From bcd62aec6b74badd71c11868477eae710a7ab397 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 15 Feb 2016 12:04:14 +1000 Subject: [PATCH] resolutions: switch to using objects for resolutions Signed-off-by: Peter Hutterer --- Makefile.am | 3 +- src/ratbagd-device.c | 13 +++ src/ratbagd-profile.c | 202 ++++++++++++++++++++++++++++++--------- src/ratbagd-resolution.c | 114 ++++++++++++++++++++++ src/ratbagd.h | 20 ++++ 5 files changed, 304 insertions(+), 48 deletions(-) create mode 100644 src/ratbagd-resolution.c diff --git a/Makefile.am b/Makefile.am index 52c0acf6..a3d8270c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -81,7 +81,8 @@ ratbagd_SOURCES = \ src/ratbagd.h \ src/ratbagd.c \ src/ratbagd-device.c \ - src/ratbagd-profile.c + src/ratbagd-profile.c \ + src/ratbagd-resolution.c ratbagd_CFLAGS = \ $(AM_CFLAGS) \ diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index f049214c..7297ceb1 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -349,6 +349,7 @@ void ratbagd_device_link(struct ratbagd_device *device) struct ratbagd_device *iter; RBNode **node, *parent; int r, v; + unsigned int i; assert(device); assert(!ratbagd_device_linked(device)); @@ -398,6 +399,18 @@ void ratbagd_device_link(struct ratbagd_device *device) fprintf(stderr, "Cannot register profile interfaces for '%s': %m\n", device->name); + return; + } + + for (i = 0; i < device->n_profiles; i++) { + r = ratbagd_profile_register_resolutions(device->ctx->bus, + device, + device->profiles[i]); + if (r < 0) { + fprintf(stderr, + "Cannot register resolutions for '%s': %m\n", + device->name); + } } } diff --git a/src/ratbagd-profile.c b/src/ratbagd-profile.c index 06217a84..134f7ee4 100644 --- a/src/ratbagd-profile.c +++ b/src/ratbagd-profile.c @@ -38,8 +38,44 @@ struct ratbagd_profile { struct ratbag_profile *lib_profile; unsigned int index; char *path; + + sd_bus_slot *resolution_vtable_slot; + sd_bus_slot *resolution_enum_slot; + unsigned int n_resolutions; + struct ratbagd_resolution **resolutions; }; +static int ratbagd_profile_find_resolution(sd_bus *bus, + const char *path, + const char *interface, + void *userdata, + void **found, + sd_bus_error *error) +{ + _cleanup_(freep) char *name = NULL; + struct ratbagd_profile *profile = userdata; + unsigned int index; + int r; + + r = sd_bus_path_decode_many(path, + "/org/freedesktop/ratbag1/resolution/%/p%/r%", + NULL, + NULL, + &name); + if (r <= 0) + return r; + + r = safe_atou(name, &index); + if (r < 0) + return 0; + + if (index >= profile->n_resolutions || !profile->resolutions[index]) + return 0; + + *found = profile->resolutions[index]; + return 1; +} + static int ratbagd_profile_get_resolutions(sd_bus *bus, const char *path, const char *interface, @@ -49,60 +85,22 @@ static int ratbagd_profile_get_resolutions(sd_bus *bus, sd_bus_error *error) { struct ratbagd_profile *profile = userdata; - unsigned int i, n_resolutions; + struct ratbagd_resolution *resolution; + unsigned int i; int r; - r = sd_bus_message_open_container(reply, 'a', "a{sv}"); + r = sd_bus_message_open_container(reply, 'a', "o"); if (r < 0) return r; - n_resolutions = ratbag_profile_get_num_resolutions(profile->lib_profile); - for (i = 0; i < n_resolutions; ++i) { - struct ratbag_resolution *resolution; - bool cap_separate_xy_resolution; - unsigned int dpi_x, dpi_y, report_rate; - - resolution = ratbag_profile_get_resolution(profile->lib_profile, i); + for (i = 0; i < profile->n_resolutions; ++i) { + resolution = profile->resolutions[i]; if (!resolution) continue; - cap_separate_xy_resolution = ratbag_resolution_has_capability(resolution, - RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION); - report_rate = ratbag_resolution_get_report_rate(resolution); - if (cap_separate_xy_resolution) { - dpi_x = ratbag_resolution_get_dpi_x(resolution); - dpi_y = ratbag_resolution_get_dpi_y(resolution); - } else { - dpi_x = ratbag_resolution_get_dpi(resolution); - } - - r = sd_bus_message_open_container(reply, 'a', "{sv}"); - if (r < 0) - return r; - - if (cap_separate_xy_resolution) { - r = sd_bus_message_append(reply, "{sv}", - "dpi-x", "u", dpi_x); - if (r < 0) - return r; - - r = sd_bus_message_append(reply, "{sv}", - "dpi-y", "u", dpi_y); - if (r < 0) - return r; - } else { - r = sd_bus_message_append(reply, "{sv}", - "dpi", "u", dpi_x); - if (r < 0) - return r; - } - - r = sd_bus_message_append(reply, "{sv}", - "report-rate", "u", report_rate); - if (r < 0) - return r; - - r = sd_bus_message_close_container(reply); + r = sd_bus_message_append(reply, + "o", + ratbagd_resolution_get_path(resolution)); if (r < 0) return r; } @@ -186,7 +184,7 @@ static int ratbagd_profile_set_active(sd_bus_message *m, const sd_bus_vtable ratbagd_profile_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Index", "u", NULL, offsetof(struct ratbagd_profile, index), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("Resolutions", "aa{sv}", ratbagd_profile_get_resolutions, 0, 0), + SD_BUS_PROPERTY("Resolutions", "ao", ratbagd_profile_get_resolutions, 0, 0), SD_BUS_PROPERTY("ActiveResolution", "u", ratbagd_profile_get_active_resolution, 0, 0), SD_BUS_PROPERTY("DefaultResolution", "u", ratbagd_profile_get_default_resolution, 0, 0), SD_BUS_METHOD("SetActive", "", "u", ratbagd_profile_set_active, SD_BUS_VTABLE_UNPRIVILEGED), @@ -199,7 +197,9 @@ int ratbagd_profile_new(struct ratbagd_profile **out, unsigned int index) { _cleanup_(ratbagd_profile_freep) struct ratbagd_profile *profile = NULL; + struct ratbag_resolution *resolution; char index_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1]; + unsigned int i; int r; assert(out); @@ -220,6 +220,29 @@ int ratbagd_profile_new(struct ratbagd_profile **out, if (r < 0) return r; + profile->n_resolutions = ratbag_profile_get_num_resolutions(profile->lib_profile); + profile->resolutions = calloc(profile->n_resolutions, sizeof(*profile->resolutions)); + if (!profile->resolutions) + return -ENOMEM; + + for (i = 0; i < profile->n_resolutions; ++i) { + resolution = ratbag_profile_get_resolution(profile->lib_profile, i); + if (!resolution) + continue; + + r = ratbagd_resolution_new(&profile->resolutions[i], + device, + profile, + resolution, + i); + if (r < 0) { + errno = -r; + fprintf(stderr, + "Cannot allocate resolution for '%s': %m\n", + ratbagd_device_get_name(device)); + } + } + *out = profile; profile = NULL; return 0; @@ -250,3 +273,88 @@ bool ratbagd_profile_is_active(struct ratbagd_profile *profile) assert(profile); return ratbag_profile_is_active(profile->lib_profile) != 0; } + +unsigned int ratbagd_profile_get_index(struct ratbagd_profile *profile) +{ + assert(profile); + return profile->index; +} + +static int ratbagd_profile_list_resolutions(sd_bus *bus, + const char *path, + void *userdata, + char ***paths, + sd_bus_error *error) +{ + struct ratbagd_profile *profile = userdata; + struct ratbagd_resolution *resolution; + char **resolutions; + unsigned int i; + + resolutions = calloc(profile->n_resolutions + 1, sizeof(char *)); + if (!resolutions) + return -ENOMEM; + + for (i = 0; i < profile->n_resolutions; ++i) { + resolution = profile->resolutions[i]; + if (!resolution) + continue; + + resolutions[i] = strdup(ratbagd_resolution_get_path(resolution)); + if (!resolutions[i]) + goto error; + } + + resolutions[i] = NULL; + *paths = resolutions; + return 1; + +error: + for (i = 0; resolutions[i]; ++i) + free(resolutions[i]); + free(resolutions); + return -ENOMEM; +} + + +int ratbagd_profile_register_resolutions(struct sd_bus *bus, + struct ratbagd_device *device, + struct ratbagd_profile *profile) +{ + _cleanup_(freep) char *prefix = NULL; + char index_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1]; + int r; + + sprintf(index_buffer, "p%u", profile->index); + + /* register resolution interfaces */ + r = sd_bus_path_encode_many(&prefix, + "/org/freedesktop/ratbag1/resolution/%/%", + ratbagd_device_get_name(device), + index_buffer); + + + if (r >= 0) { + r = sd_bus_add_fallback_vtable(bus, + &profile->resolution_vtable_slot, + prefix, + "org.freedesktop.ratbag1.Resolution", + ratbagd_resolution_vtable, + ratbagd_profile_find_resolution, + profile); + if (r >= 0) + r = sd_bus_add_node_enumerator(bus, + &profile->resolution_enum_slot, + prefix, + ratbagd_profile_list_resolutions, + profile); + } + if (r < 0) { + errno = -r; + fprintf(stderr, + "Cannot register resolutions for '%s': %m\n", + ratbagd_device_get_name(device)); + } + + return 0; +} diff --git a/src/ratbagd-resolution.c b/src/ratbagd-resolution.c new file mode 100644 index 00000000..c60bad34 --- /dev/null +++ b/src/ratbagd-resolution.c @@ -0,0 +1,114 @@ +/*** + This file is part of ratbagd. + + Copyright 2016 Red Hat, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ratbagd.h" +#include "shared-macro.h" + +struct ratbagd_resolution { + struct ratbag_resolution *lib_resolution; + unsigned int index; + char *path; + unsigned int xres, yres; + unsigned int rate; + + sd_bus_slot *profile_vtable_slot; + sd_bus_slot *profile_enum_slot; +}; + +const sd_bus_vtable ratbagd_resolution_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Index", "u", NULL, offsetof(struct ratbagd_resolution, index), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("XResolution", "u", NULL, offsetof(struct ratbagd_resolution, xres), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("YResolution", "u", NULL, offsetof(struct ratbagd_resolution, yres), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ReportRate", "u", NULL, offsetof(struct ratbagd_resolution, rate), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_VTABLE_END, +}; + +int ratbagd_resolution_new(struct ratbagd_resolution **out, + struct ratbagd_device *device, + struct ratbagd_profile *profile, + struct ratbag_resolution *lib_resolution, + unsigned int index) +{ + _cleanup_(ratbagd_resolution_freep) struct ratbagd_resolution *resolution = NULL; + char profile_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1], + resolution_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1]; + int r; + + assert(out); + assert(lib_resolution); + + resolution = calloc(1, sizeof(*resolution)); + if (!resolution) + return -ENOMEM; + + resolution->lib_resolution = lib_resolution; + resolution->index = index; + resolution->xres = ratbag_resolution_get_dpi_x(lib_resolution); + resolution->yres = ratbag_resolution_get_dpi_y(lib_resolution); + resolution->rate = ratbag_resolution_get_report_rate(lib_resolution); + + sprintf(profile_buffer, "p%u", ratbagd_profile_get_index(profile)); + sprintf(resolution_buffer, "r%u", index); + r = sd_bus_path_encode_many(&resolution->path, + "/org/freedesktop/ratbag1/resolution/%/%/%", + ratbagd_device_get_name(device), + profile_buffer, + resolution_buffer); + if (r < 0) + return r; + + *out = resolution; + resolution = NULL; + return 0; +} + +const char *ratbagd_resolution_get_path(struct ratbagd_resolution *resolution) +{ + assert(resolution); + return resolution->path; +} + +struct ratbagd_resolution *ratbagd_resolution_free(struct ratbagd_resolution *resolution) +{ + if (!resolution) + return NULL; + + resolution->path = mfree(resolution->path); + + /* we cannot assume the resolution is gone, so set NULL explicitly */ + ratbag_resolution_unref(resolution->lib_resolution); + resolution->lib_resolution = NULL; + + return mfree(resolution); +} diff --git a/src/ratbagd.h b/src/ratbagd.h index e804d336..d29bf5d6 100644 --- a/src/ratbagd.h +++ b/src/ratbagd.h @@ -39,6 +39,7 @@ struct ratbagd; struct ratbagd_device; struct ratbagd_profile; +struct ratbagd_resolution; /* * Profiles @@ -54,9 +55,28 @@ struct ratbagd_profile *ratbagd_profile_free(struct ratbagd_profile *profile); const char *ratbagd_profile_get_path(struct ratbagd_profile *profile); bool ratbagd_profile_is_active(struct ratbagd_profile *profile); bool ratbagd_profile_is_default(struct ratbagd_profile *profile); +unsigned int ratbagd_profile_get_index(struct ratbagd_profile *profile); +int ratbagd_profile_register_resolutions(struct sd_bus *bus, + struct ratbagd_device *device, + struct ratbagd_profile *profile); DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_profile *, ratbagd_profile_free); +/* + * Resolutions + */ +extern const sd_bus_vtable ratbagd_resolution_vtable[]; + +int ratbagd_resolution_new(struct ratbagd_resolution **out, + struct ratbagd_device *device, + struct ratbagd_profile *profile, + struct ratbag_resolution *lib_resolution, + unsigned int index); +struct ratbagd_resolution *ratbagd_resolution_free(struct ratbagd_resolution *resolution); +const char *ratbagd_resolution_get_path(struct ratbagd_resolution *resolution); + +DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_resolution *, ratbagd_resolution_free); + /* * Devices */