From 3f0b41ec3c264c95d8f721a702e63131a471cafa Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Thu, 24 Sep 2015 16:45:22 +0200 Subject: [PATCH 001/137] Initialize ratbagd repository Initial commit for the ratbagd project, a dbus daemon to manage libratbag devices and proxy user accesses. Signed-off-by: David Herrmann --- README | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 README diff --git a/README b/README new file mode 100644 index 00000000..e69de29b From aa052ae0054ee3d3766671c3ce61d1699df3abe6 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Thu, 24 Sep 2015 17:05:57 +0200 Subject: [PATCH 002/137] Import initial components This adds two new components: 1) ratbagd The ratbagd daemon is a very basic dbus daemon that provides an org.freedesktop.DBus.ObjectManager based enumeration and modification API for libratbag devices. So far, all it does is enumerate input devices on the bus. However, this will be extended to advertise full libratbag hierarchies on the bus and allow clients to modify properties via DBus. So far, it is root-only, but the DBus policy can be losened and PolKit support can be added. 2) ratbagctl A very basic command-line tool to manage ratbagd. It's basically a command-line interface for the DBus API of ratbagd. So far, it has no hookup for anything. This will be added once ratbagd gains further DBus APIs. Signed-off-by: David Herrmann --- .gitignore | 29 ++ Makefile.am | 93 +++++++ autogen.sh | 48 ++++ configure.ac | 151 +++++++++++ src/org.freedesktop.ratbag1.conf | 14 + src/ratbagctl.c | 213 +++++++++++++++ src/ratbagd-device.c | 288 ++++++++++++++++++++ src/ratbagd.c | 303 +++++++++++++++++++++ src/ratbagd.h | 71 +++++ src/shared-macro.h | 165 ++++++++++++ src/shared-rbtree.c | 450 +++++++++++++++++++++++++++++++ src/shared-rbtree.h | 99 +++++++ 12 files changed, 1924 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile.am create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 src/org.freedesktop.ratbag1.conf create mode 100644 src/ratbagctl.c create mode 100644 src/ratbagd-device.c create mode 100644 src/ratbagd.c create mode 100644 src/ratbagd.h create mode 100644 src/shared-macro.h create mode 100644 src/shared-rbtree.c create mode 100644 src/shared-rbtree.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..7f44e8b2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +*.a +*.la +*.lo +*.log +*.o +*.stamp +*.swp +*.trs +*~ +.config.args +.deps/ +.dirstamp +.libs/ +/*.tar.xz +Makefile +Makefile.in +autom4te.cache/ +aclocal.m4 +build-aux/ +config.h +config.h.in +config.log +config.status +configure +libtool +m4/ +ratbagctl +ratbagd +stamp-* diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..e721ab8e --- /dev/null +++ b/Makefile.am @@ -0,0 +1,93 @@ +# ------------------------------------------------------------------------------ +# main + +ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} +AM_MAKEFLAGS = --no-print-directory +AUTOMAKE_OPTIONS = color-tests parallel-tests + +GCC_COLORS ?= 'ooh, shiny!' +export GCC_COLORS + +SUBDIRS = . + +# remove targets if the command fails +.DELETE_ON_ERROR: + +# keep intermediate files +.SECONDARY: + +# Keep the test-suite.log +.PRECIOUS: $(TEST_SUITE_LOG) Makefile + +CLEANFILES = $(BUILT_SOURCES) +DISTCLEANFILES = +EXTRA_DIST = +BUILT_SOURCES = +lib_LTLIBRARIES = +noinst_LTLIBRARIES = +bin_PROGRAMS = +noinst_PROGRAMS = + +AM_CPPFLAGS = \ + -include $(top_builddir)/config.h \ + -I $(top_srcdir)/src \ + -I $(top_builddir)/src \ + $(OUR_CPPFLAGS) + +AM_CFLAGS = $(OUR_CFLAGS) +AM_LDFLAGS = $(OUR_LDFLAGS) + +# ------------------------------------------------------------------------------ +# libshared + +noinst_LTLIBRARIES += \ + libshared.la + +libshared_la_SOURCES = \ + src/shared-macro.h \ + src/shared-rbtree.h \ + src/shared-rbtree.c + +libshared_la_CFLAGS = \ + $(AM_CFLAGS) + +libshared_la_LIBADD = \ + -lm + +# ------------------------------------------------------------------------------ +# ratbagctl + +bin_PROGRAMS += \ + ratbagctl + +ratbagctl_SOURCES = \ + src/ratbagctl.c + +ratbagctl_CFLAGS = \ + $(AM_CFLAGS) \ + $(LIBSYSTEMD_CFLAGS) + +ratbagctl_LDADD = \ + libshared.la \ + $(LIBSYSTEMD_LIBS) + +# ------------------------------------------------------------------------------ +# ratbagd + +bin_PROGRAMS += \ + ratbagd + +ratbagd_SOURCES = \ + src/ratbagd.h \ + src/ratbagd.c \ + src/ratbagd-device.c + +ratbagd_CFLAGS = \ + $(AM_CFLAGS) \ + $(UDEV_CFLAGS) \ + $(LIBSYSTEMD_CFLAGS) + +ratbagd_LDADD = \ + libshared.la \ + $(UDEV_LIBS) \ + $(LIBSYSTEMD_LIBS) diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 00000000..dbb5141d --- /dev/null +++ b/autogen.sh @@ -0,0 +1,48 @@ +#!/bin/sh +# +# autogen.sh: prepare build system +# Run this script to prepare the build-system for your local checkout. It +# requires the usual autotools dependencies to be installed. +# +# Prepare build system, but don't configure: +# $ ./autogen.sh +# +# Prepare build system and run ./configure with debugging enabled: +# $ ./autogen.sh c +# +# Prepare build system and run ./configure with llvm over gcc: +# $ ./autogen.sh l +# +# You can put additional arguments to ./configure into ".config.args". They +# will be appended to the arguments used by this script. +# + +set -e + +oldpwd=$(pwd) +topdir=$(dirname $0) +cd $topdir + +autoreconf --force --install --symlink + +if [ -f "$topdir/.config.args" ]; then + args="$args $(cat $topdir/.config.args)" +fi + +cd $oldpwd + +if [ "x$1" = "xc" ]; then + $topdir/configure --enable-debug $args + make clean +elif [ "x$1" = "xl" ]; then + $topdir/configure CC=clang $args + make clean +else + echo + echo "----------------------------------------------------------------" + echo "Initialized build system. For a common configuration please run:" + echo "----------------------------------------------------------------" + echo + echo "$topdir/configure $args" + echo +fi diff --git a/configure.ac b/configure.ac new file mode 100644 index 00000000..2d40488d --- /dev/null +++ b/configure.ac @@ -0,0 +1,151 @@ +# ------------------------------------------------------------------------------ +# main + +AC_PREREQ([2.64]) + +AC_INIT([ratbagd], + [1], + [http://www.github.com/libratbag/ratbagd], + [ratbagd], + [http://www.github.com/libratbag/ratbagd]) + +AC_CONFIG_SRCDIR([src/ratbagd.h]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_AUX_DIR([build-aux]) + +AC_USE_SYSTEM_EXTENSIONS +AC_SYS_LARGEFILE +AM_MAINTAINER_MODE([enable]) +AM_INIT_AUTOMAKE([foreign 1.11 -Wall -Wno-portability silent-rules tar-pax no-dist-gzip dist-xz subdir-objects parallel-tests]) +AM_SILENT_RULES([yes]) +AC_CANONICAL_HOST +AC_DEFINE_UNQUOTED([CANONICAL_HOST], "$host", [Canonical host string.]) + +LT_PREREQ(2.2) +LT_INIT([disable-static]) + +AC_PROG_MKDIR_P +AC_PROG_LN_S +AC_PROG_SED +AC_PROG_GREP +AC_PROG_AWK +AC_PROG_CC_C99 + +AC_PATH_PROG([M4], [m4]) +AC_PATH_PROG([XSLTPROC], [xsltproc]) + +AS_IF([! ln --relative --help > /dev/null 2>&1], [AC_MSG_ERROR([*** ln doesn't support --relative ***])]) + +# ------------------------------------------------------------------------------ +# arguments + +AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug], [enable debug options])) + +# ------------------------------------------------------------------------------ +# toolchain + +CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\ + -pipe \ + -Wall \ + -Wextra \ + -Wno-inline \ + -Wundef \ + "-Wformat=2 -Wformat-security -Wformat-nonliteral" \ + -Wlogical-op \ + -Wsign-compare \ + -Wmissing-include-dirs \ + -Wold-style-definition \ + -Wpointer-arith \ + -Winit-self \ + -Wdeclaration-after-statement \ + -Wfloat-equal \ + -Wsuggest-attribute=noreturn \ + -Wmissing-prototypes \ + -Wstrict-prototypes \ + -Wredundant-decls \ + -Wmissing-declarations \ + -Wmissing-noreturn \ + -Wendif-labels \ + -Wstrict-aliasing=2 \ + -Wwrite-strings \ + -Wno-long-long \ + -Wno-overlength-strings \ + -Wno-unused-parameter \ + -Wno-missing-field-initializers \ + -Wno-unused-result \ + -Werror=overflow \ + -Wdate-time \ + -Wnested-externs \ + -ffast-math \ + -fno-common \ + -fdiagnostics-show-option \ + -fno-strict-aliasing \ + -fvisibility=hidden \ + -ffunction-sections \ + -fdata-sections \ + -fstack-protector \ + -fstack-protector-strong \ + -fPIE \ + --param=ssp-buffer-size=4]) + +AS_CASE([$CC], [*clang*], + [CC_CHECK_FLAGS_APPEND([with_cppflags], [CPPFLAGS], [ \ + -Wno-typedef-redefinition \ + -Wno-gnu-variable-sized-type-not-at-end \ + ])]) + +CC_CHECK_FLAGS_APPEND([with_ldflags], [LDFLAGS], [\ + -Wl,--as-needed \ + -Wl,--no-undefined \ + -Wl,--gc-sections \ + -Wl,-z,relro \ + -Wl,-z,now \ + -pie]) + +AS_IF([test "x$enable_debug" = "xyes"], + [ + CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [ \ + -g \ + -O0 \ + -ftrapv]) + ], [ + CC_CHECK_FLAGS_APPEND([with_cppflags], [CPPFLAGS], [\ + -Wp,-D_FORTIFY_SOURCE=2]) + ]) + +AC_SUBST([OUR_CFLAGS], "$with_cflags") +AC_SUBST([OUR_CPPFLAGS], "$with_cppflags") +AC_SUBST([OUR_LDFLAGS], "$with_ldflags") + +# ------------------------------------------------------------------------------ +# system features + +# This makes sure pkg.m4 is available. +m4_pattern_forbid([^_?PKG_[A-Z_]+$],[*** pkg.m4 missing, please install pkg-config]) + +# ------------------------------------------------------------------------------ +# dependencies + +PKG_CHECK_MODULES([UDEV], [libudev]) +PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd >= 225]) + +# ------------------------------------------------------------------------------ +# report + +AC_CONFIG_FILES([Makefile]) + +AC_OUTPUT +AC_MSG_RESULT([ + $PACKAGE_NAME $VERSION + debug: ${enable_debug} + + prefix: ${prefix} + exec_prefix: ${exec_prefix} + includedir: ${includedir} + libdir: ${libdir} + + CFLAGS: ${OUR_CFLAGS} ${CFLAGS} + CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS} + LDFLAGS: ${OUR_LDFLAGS} ${LDFLAGS} +]) diff --git a/src/org.freedesktop.ratbag1.conf b/src/org.freedesktop.ratbag1.conf new file mode 100644 index 00000000..cd7b8843 --- /dev/null +++ b/src/org.freedesktop.ratbag1.conf @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/src/ratbagctl.c b/src/ratbagctl.c new file mode 100644 index 00000000..929c174c --- /dev/null +++ b/src/ratbagctl.c @@ -0,0 +1,213 @@ +/*** + This file is part of ratbagd. + + Copyright 2015 David Herrmann + + 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 "shared-macro.h" + +struct ratbagctl { + int unused; +}; + +static int verb_help(struct ratbagctl *ctl, int argc, char **argv); + +static struct ratbagctl *ratbagctl_free(struct ratbagctl *ctl) +{ + if (!ctl) + return NULL; + + free(ctl); + + return NULL; +} + +static int ratbagctl_new(struct ratbagctl **out) +{ + struct ratbagctl *ctl; + + ctl = calloc(1, sizeof(*ctl)); + if (!ctl) + return -ENOMEM; + + *out = ctl; + return 0; +} + +static int verb_list(struct ratbagctl *ctl, int argc, char **argv) +{ + return 0; +} + +static const struct { + const char *verb; + const char *help; + int (*dispatch) (struct ratbagctl *ctl, int argc, char **argv); + void (*long_help) (void); +} verbs[] = { + { "list", "List available configurable mice", verb_list, NULL }, + { "help", "Show help for a command", verb_help, NULL }, + {}, +}; + +static void help(void) +{ + unsigned int i; + + printf("%s [OPTIONS..] COMMAND [OPTIONS..]\n\n" + "Query or modify configurable mice.\n\n" + "Commands:\n", + program_invocation_short_name); + + for (i = 0; i < ELEMENTSOF(verbs); ++i) { + if (verbs[i].help != NULL) + printf(" %-12s %s\n", verbs[i].verb, verbs[i].help); + } +} + +static int verb_help(struct ratbagctl *ctl, int argc, char **argv) +{ + static const struct option options[] = { + {}, + }; + const char *verb; + unsigned int i; + int c; + + while ((c = getopt_long(argc, argv, "+", options, NULL)) >= 0) { + switch (c) { + default: + return -EINVAL; + } + } + + verb = argv[optind]; + if (!verb) { + help(); + return 1; + } else { + for (i = 0; i < ELEMENTSOF(verbs); ++i) { + if (!streq_ptr(verb, verbs[i].verb)) + continue; + + if (verbs[i].long_help) + verbs[i].long_help(); + else + printf("%s: No help available for '%s'\n", + program_invocation_short_name, verb); + + return 1; + } + } + + fprintf(stderr, "%s: Unknown verb '%s'\n", program_invocation_short_name, verb); + return 1; +} + +static void version(void) +{ + printf("%s\n", VERSION); +} + +static int ratbagctl_dispatch(struct ratbagctl *ctl, int argc, char **argv) +{ + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + {}, + }; + char *fake[] = { (char*)verbs[0].verb, NULL }; + const char *verb; + unsigned int i; + int c; + + /* '+' makes getopt_long() stop at the first non-argument */ + while ((c = getopt_long(argc, argv, "+hV", options, NULL)) >= 0) { + switch (c) { + case 'h': + help(); + return 1; + case 'V': + version(); + return 1; + default: + return -EINVAL; + } + } + + verb = argv[optind]; + if (!verb) { + assert(argc - optind == 0); + + argc = ELEMENTSOF(fake) - 1; + argv = fake; + verb = fake[0]; + optind = 0; + + assert(verb); + } + + for (i = 0; i < ELEMENTSOF(verbs); ++i) { + if (!streq_ptr(verb, verbs[i].verb)) + continue; + + argc -= optind; + argv += optind; + optind = 0; + + return verbs[i].dispatch(ctl, argc, argv); + } + + fprintf(stderr, "%s: Missing or unknown command\n", + program_invocation_short_name); + + return -EINVAL; +} + +int main(int argc, char **argv) +{ + struct ratbagctl *ctl = NULL; + int r; + + r = ratbagctl_new(&ctl); + if (r < 0) + goto exit; + + r = ratbagctl_dispatch(ctl, argc, argv); + +exit: + ratbagctl_free(ctl); + + if (r < 0) { + errno = -r; + fprintf(stderr, "%s: Failed: %m\n", + program_invocation_short_name); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c new file mode 100644 index 00000000..8c54951f --- /dev/null +++ b/src/ratbagd-device.c @@ -0,0 +1,288 @@ +/*** + This file is part of ratbagd. + + Copyright 2015 David Herrmann + + 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 "ratbagd.h" +#include "shared-macro.h" +#include "shared-rbtree.h" + +struct ratbagd_device { + struct ratbagd *ctx; + RBNode node; + char *name; +}; + +#define ratbagd_device_from_node(_ptr) \ + rbnode_of((_ptr), struct ratbagd_device, node) + +static int ratbagd_device_find(sd_bus *bus, + const char *path, + const char *interface, + void *userdata, + void **found, + sd_bus_error *error) +{ + _cleanup_(freep) char *name = NULL; + struct ratbagd *ctx = userdata; + struct ratbagd_device *device; + int r; + + /* decodes the suffix into @name, returns 1 if valid */ + r = sd_bus_path_decode(path, "/org/freedesktop/ratbag1/device", &name); + if (r <= 0) + return r; + + device = ratbagd_find_device(ctx, name); + if (!device) + return 0; + + *found = device; + return 1; +} + +static int ratbagd_device_list(sd_bus *bus, + const char *path, + void *userdata, + char ***nodes, + sd_bus_error *error) +{ + struct ratbagd *ctx = userdata; + struct ratbagd_device *device; + char **devices, **pos; + RBNode *node; + int r; + + devices = calloc(ctx->n_devices + 1, sizeof(char *)); + if (!devices) + return -ENOMEM; + + pos = devices; + + for (node = rbtree_first(&ctx->device_map); + node; + node = rbnode_next(node)) { + device = ratbagd_device_from_node(node); + + r = sd_bus_path_encode("/org/freedesktop/ratbag1/device", + device->name, + pos++); + if (r < 0) + goto error; + } + + *pos = NULL; + + *nodes = devices; + return 1; + +error: + for (pos = devices; *pos; ++pos) + free(*pos); + free(devices); + return r; +} + +static const sd_bus_vtable ratbagd_device_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_VTABLE_END, +}; + +int ratbagd_device_new(struct ratbagd_device **out, + struct ratbagd *ctx, + const char *name) +{ + _cleanup_(ratbagd_device_freep) struct ratbagd_device *device = NULL; + + assert(out); + assert(ctx); + assert(name); + + device = calloc(1, sizeof(*device)); + if (!device) + return -ENOMEM; + + device->ctx = ctx; + rbnode_init(&device->node); + + device->name = strdup(name); + if (!device->name) + return -ENOMEM; + + *out = device; + device = NULL; + return 0; +} + +struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device) +{ + if (!device) + return NULL; + + assert(!ratbagd_device_linked(device)); + + device->name = mfree(device->name); + return mfree(device); +} + +bool ratbagd_device_linked(struct ratbagd_device *device) +{ + return device && rbnode_linked(&device->node); +} + +void ratbagd_device_link(struct ratbagd_device *device) +{ + _cleanup_(freep) char *path = NULL; + struct ratbagd_device *iter; + RBNode **node, *parent; + int r, v; + + assert(device); + assert(!ratbagd_device_linked(device)); + + /* find place to link it to */ + parent = NULL; + node = &device->ctx->device_map.root; + while (*node) { + parent = *node; + iter = ratbagd_device_from_node(parent); + v = strcmp(device->name, iter->name); + + /* if there's a duplicate, the caller screwed up */ + assert(v != 0); + + if (v < 0) + node = &parent->left; + else /* if (v > 0) */ + node = &parent->right; + } + + /* link into context */ + rbtree_add(&device->ctx->device_map, parent, node, &device->node); + ++device->ctx->n_devices; + + /* send out object-manager notification */ + r = sd_bus_path_encode("/org/freedesktop/ratbag1/device", + device->name, + &path); + if (r >= 0) + r = sd_bus_emit_object_added(device->ctx->bus, path); + if (r < 0) { + errno = -r; + fprintf(stderr, + "Cannot send device notification for '%s': %m\n", + device->name); + } +} + +void ratbagd_device_unlink(struct ratbagd_device *device) +{ + _cleanup_(freep) char *path = NULL; + int r; + + if (!ratbagd_device_linked(device)) + return; + + /* send out object-manager notification */ + r = sd_bus_path_encode("/org/freedesktop/ratbag1/device", + device->name, + &path); + if (r >= 0) + r = sd_bus_emit_object_removed(device->ctx->bus, path); + if (r < 0) { + errno = -r; + fprintf(stderr, + "Cannot send device notification for '%s': %m\n", + device->name); + } + + /* unlink from context */ + --device->ctx->n_devices; + rbtree_remove(&device->ctx->device_map, &device->node); + rbnode_init(&device->node); +} + +int ratbagd_init_device(struct ratbagd *ctx) +{ + int r; + + assert(ctx); + + /* + * Called by the context initializer after the context was prepared but + * not run, yet. No need to cleanup anything if an error is returned, + * as long it is teared down automatically on destruction. + */ + + r = sd_bus_add_fallback_vtable(ctx->bus, + NULL, + "/org/freedesktop/ratbag1/device", + "org.freedesktop.ratbag1.Device", + ratbagd_device_vtable, + ratbagd_device_find, + ctx); + if (r < 0) + return r; + + r = sd_bus_add_node_enumerator(ctx->bus, + NULL, + "/org/freedesktop/ratbag1/device", + ratbagd_device_list, + ctx); + if (r < 0) + return r; + + return 0; +} + +struct ratbagd_device *ratbagd_find_device(struct ratbagd *ctx, + const char *name) +{ + struct ratbagd_device *device; + RBNode *node; + int v; + + assert(ctx); + assert(name); + + node = ctx->device_map.root; + while (node) { + device = ratbagd_device_from_node(node); + v = strcmp(name, device->name); + if (!v) + return device; + else if (v < 0) + node = node->left; + else /* if (v > 0) */ + node = node->right; + } + + return NULL; +} diff --git a/src/ratbagd.c b/src/ratbagd.c new file mode 100644 index 00000000..86c8cb88 --- /dev/null +++ b/src/ratbagd.c @@ -0,0 +1,303 @@ +/*** + This file is part of ratbagd. + + Copyright 2015 David Herrmann + + 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 "ratbagd.h" +#include "shared-macro.h" + +static void ratbagd_process_device(struct ratbagd *ctx, + struct udev_device *udevice) +{ + struct ratbagd_device *device; + const char *name; + int r; + + /* + * TODO: So far we just enumerate udev input devices and add a new + * ratbag device for each one we find. That's a bit easy. We + * should really try to create a libratbag device for the udev + * device and only add devices that are actually accepted. + * Furthermore, the libratbag object should really be kept as + * context in ratbagd_device. + * + * TODO: libratbag should provide some mechanism to allow + * device-grouping, just like libinput does. If multiple input + * devices belong to the same virtual device, we should not add + * it multiple times. Instead, libratbag should group them and + * provide *us* a unique name that identifies the group, rather + * than taking a random input-device as tag. + */ + + name = udev_device_get_sysname(udevice); + if (!name) + return; + + device = ratbagd_find_device(ctx, name); + + if (streq_ptr("remove", udev_device_get_action(udevice))) { + /* device was removed, unlink it and destroy our context */ + if (device) { + ratbagd_device_unlink(device); + ratbagd_device_free(device); + } + } else if (device) { + /* device already known, refresh our view of the device */ + } else { + /* device unknown, create new one and link it */ + r = ratbagd_device_new(&device, ctx, name); + if (r < 0) { + fprintf(stderr, "Cannot track device '%s'\n", name); + return; + } + + ratbagd_device_link(device); + } +} + +static int ratbagd_monitor_event(sd_event_source *source, + int fd, + uint32_t mask, + void *userdata) +{ + struct ratbagd *ctx = userdata; + struct udev_device *udevice; + + udevice = udev_monitor_receive_device(ctx->monitor); + if (!udevice) + return 0; + + ratbagd_process_device(ctx, udevice); + udev_device_unref(udevice); + + return 0; +} + +static struct ratbagd *ratbagd_free(struct ratbagd *ctx) +{ + if (!ctx) + return NULL; + + ctx->bus = sd_bus_flush_close_unref(ctx->bus); + ctx->monitor_source = sd_event_source_unref(ctx->monitor_source); + ctx->monitor = udev_monitor_unref(ctx->monitor); + ctx->event = sd_event_unref(ctx->event); + + assert(!ctx->device_map.root); + + return mfree(ctx); +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd *, ratbagd_free); + +static int ratbagd_init_monitor(struct ratbagd *ctx) +{ + struct udev *udev; + int r; + + udev = udev_new(); + if (!udev) + return -ENOMEM; + + ctx->monitor = udev_monitor_new_from_netlink(udev, "udev"); + + /* we don't need the context to stay around; drop it */ + udev_unref(udev); + + if (!ctx->monitor) + return -ENOMEM; + + r = udev_monitor_filter_add_match_subsystem_devtype(ctx->monitor, + "input", + NULL); + if (r < 0) + return r; + + r = udev_monitor_enable_receiving(ctx->monitor); + if (r < 0) + return r; + + r = sd_event_add_io(ctx->event, + &ctx->monitor_source, + udev_monitor_get_fd(ctx->monitor), + EPOLLIN, + ratbagd_monitor_event, + ctx); + if (r < 0) + return r; + + return 0; +} + +static int ratbagd_new(struct ratbagd **out) +{ + _cleanup_(ratbagd_freep) struct ratbagd *ctx = NULL; + int r; + + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) + return -ENOMEM; + + r = sd_event_default(&ctx->event); + if (r < 0) + return r; + + r = sd_event_set_watchdog(ctx->event, true); + if (r < 0) + return r; + + r = ratbagd_init_monitor(ctx); + if (r < 0) + return r; + + r = sd_bus_open_system(&ctx->bus); + if (r < 0) + return r; + + r = sd_bus_add_object_manager(ctx->bus, + NULL, + "/org/freedesktop/ratbag1"); + if (r < 0) + return r; + + r = ratbagd_init_device(ctx); + if (r < 0) + return r; + + r = sd_bus_request_name(ctx->bus, "org.freedesktop.ratbag1", 0); + if (r < 0) + return r; + + r = sd_bus_attach_event(ctx->bus, ctx->event, 0); + if (r < 0) + return r; + + *out = ctx; + ctx = NULL; + return 0; +} + +static int ratbagd_run_enumerate(struct ratbagd *ctx) +{ + struct udev_list_entry *list, *iter; + struct udev_enumerate *e; + struct udev *udev; + int r; + + udev = udev_monitor_get_udev(ctx->monitor); + + e = udev_enumerate_new(udev); + if (!e) + return -ENOMEM; + + r = udev_enumerate_add_match_subsystem(e, "input"); + if (r < 0) + goto exit; + + r = udev_enumerate_add_match_is_initialized(e); + if (r < 0) + goto exit; + + r = udev_enumerate_scan_devices(e); + if (r < 0) + goto exit; + + list = udev_enumerate_get_list_entry(e); + udev_list_entry_foreach(iter, list) { + struct udev_device *udevice; + const char *p; + + p = udev_list_entry_get_name(iter); + udevice = udev_device_new_from_syspath(udev, p); + if (udevice) + ratbagd_process_device(ctx, udevice); + udev_device_unref(udevice); + } + + r = 0; + +exit: + udev_enumerate_unref(e); + return r; +} + +static int ratbagd_run(struct ratbagd *ctx) +{ + int r; + + /* + * TODO: We should support exit-on-idle and bus-activation. Note that + * we don't store any state on our own, hence, all we have to do + * is to make sure we advertise device add/remove events via the + * bus (in case there is a listener). + * To track such events, we should store devices we already + * advertised in /run/ratbagd/devices/ and read it out on + * activation. + * Note that this feature requires udev-activation, which might + * not be possible, yet. + */ + + r = ratbagd_run_enumerate(ctx); + if (r < 0) + return r; + + return sd_event_loop(ctx->event); +} + +int main(int argc, char *argv[]) +{ + struct ratbagd *ctx = NULL; + int r; + + if (argc != 1) { + fprintf(stderr, "%s: This program takes no arguments\n", + program_invocation_short_name); + r = -EINVAL; + goto exit; + } + + r = ratbagd_new(&ctx); + if (r < 0) + goto exit; + + r = ratbagd_run(ctx); + +exit: + ratbagd_free(ctx); + + if (r < 0) { + errno = -r; + fprintf(stderr, "%s: Failed: %m\n", + program_invocation_short_name); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/src/ratbagd.h b/src/ratbagd.h new file mode 100644 index 00000000..84235f09 --- /dev/null +++ b/src/ratbagd.h @@ -0,0 +1,71 @@ +#pragma once + +/*** + This file is part of ratbagd. + + Copyright 2015 David Herrmann + + 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 "shared-macro.h" +#include "shared-rbtree.h" + +struct ratbagd; +struct ratbagd_device; + +/* + * Devices + */ + +int ratbagd_device_new(struct ratbagd_device **out, + struct ratbagd *ctx, + const char *name); +struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device); +bool ratbagd_device_linked(struct ratbagd_device *device); +void ratbagd_device_link(struct ratbagd_device *device); +void ratbagd_device_unlink(struct ratbagd_device *device); + +DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_device *, ratbagd_device_free); + +/* + * Context + */ + +struct ratbagd { + sd_event *event; + struct udev_monitor *monitor; + sd_event_source *monitor_source; + sd_bus *bus; + + RBTree device_map; + size_t n_devices; +}; + +int ratbagd_init_device(struct ratbagd *ctx); +struct ratbagd_device *ratbagd_find_device(struct ratbagd *ctx, + const char *name); diff --git a/src/shared-macro.h b/src/shared-macro.h new file mode 100644 index 00000000..c542b75f --- /dev/null +++ b/src/shared-macro.h @@ -0,0 +1,165 @@ +#pragma once + +/*** + This file is part of ratbagd. + + Copyright 2015 David Herrmann + + 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 + +/* + * We require: + * sizeof(void*) == sizeof(long) + * sizeof(long) == 4 || sizeof(long) == 8 + * sizeof(int) == 4 + * The linux kernel requires the same from the toolchain, so this should work + * just fine. + */ +#if __SIZEOF_POINTER__ != __SIZEOF_LONG__ +# error "sizeof(void*) != sizeof(long)" +#elif __SIZEOF_LONG__ != 4 && __SIZEOF_LONG__ != 8 +# error "sizeof(long) != 4 && sizeof(long) != 8" +#elif __SIZEOF_INT__ != 4 +# error "sizeof(int) != 4" +#endif + +/* + * Shortcuts for gcc attributes. See GCC manual for details. + */ +#define _alignas_(_x) __attribute__((aligned(__alignof(_x)))) +#define _alloc_(...) __attribute__((alloc_size(__VA_ARGS__))) +#define _cleanup_(_x) __attribute__((cleanup(_x))) +#define _const_ __attribute__((const)) +#define _deprecated_ __attribute__((deprecated)) +#define _hidden_ __attribute__((visibility("hidden"))) +#define _likely_(_x) (__builtin_expect(!!(_x), 1)) +#define _malloc_ __attribute__((malloc)) +#define _packed_ __attribute__((packed)) +#define _printf_(_a, _b) __attribute__((format (printf, _a, _b))) +#define _public_ __attribute__((visibility("default"))) +#define _pure_ __attribute__((pure)) +#define _sentinel_ __attribute__((sentinel)) +#define _unlikely_(_x) (__builtin_expect(!!(_x), 0)) +#define _unused_ __attribute__((unused)) +#define _weak_ __attribute__((weak)) +#define _weakref_(_x) __attribute__((weakref(#_x))) + +/* + * DEFINE_TRIVIAL_CLEANUP_FUNC() - define helper suitable for _cleanup_() + * @_type: type of object to cleanup + * @_func: function to call on cleanup + */ +#define DEFINE_TRIVIAL_CLEANUP_FUNC(_type, _func) \ + static inline void _func##p(_type *_p) \ + { \ + if (*_p) \ + _func(*_p); \ + } \ + struct __useless_struct_to_allow_trailing_semicolon__ + +/* + * ELEMENTSOF() - number of array elements + * @_array: C array + * + * This calculates the number of elements (compared to the byte size) of + * the given C array. This returns (void) if the passed argument is not + * actually a valid C array (decided at compile time). + */ +#define ELEMENTSOF(_array) \ + __extension__ (__builtin_choose_expr( \ + !__builtin_types_compatible_p(typeof(_array), \ + typeof(&*(_array))), \ + sizeof(_array) / sizeof((_array)[0]), \ + (void)0)) + +/* + * negative_errno() - return negative errno + * + * This helper should be used to shut up gcc if you know 'errno' is + * negative. Instead of "return -errno;", use "return negative_errno();" + * It will suppress bogus gcc warnings in case it assumes 'errno' might + * be 0 and thus the caller's error-handling might not be triggered. + */ +static inline int negative_errno(void) +{ + return (errno <= 0) ? -EINVAL : -errno; +} + +/* + * mfree() - free memory + * @mem: memory to free + * + * This is basically the same as free(), but returns NULL. This makes free() + * follow the same style as all our other destructors. + */ +static inline void *mfree(void *mem) +{ + free(mem); + return NULL; +} + +/* + * Miscellaneous cleanup helpers + * All these helpers are suitable for use with _cleanup_(). They call the helper + * they're named after on the variable marked for cleanup. + */ +static inline void freep(void *p) +{ + free(*(void**)p); +} + +/* + * streq() - test whether two strings are equal + * @_a: string A + * @_b: string B + */ +#define streq(_a, _b) (!strcmp((_a), (_b))) + +/* + * streq_ptr() - test whether two strings are equal, considering NULL valid + * @a: string A or NULL + * @b: string B or NULL + */ +static inline bool streq_ptr(const char *a, const char *b) +{ + return (a && b) ? streq(a, b) : (!a && !b); +} + +/* + * now() - returns current time in nano-seconds + * @clock: clock to use + */ +static inline uint64_t now(clockid_t clock) +{ + struct timespec spec = {}; + clock_gettime(clock, &spec); + return spec.tv_sec * 1000ULL * 1000ULL * 1000ULL + spec.tv_nsec; +} diff --git a/src/shared-rbtree.c b/src/shared-rbtree.c new file mode 100644 index 00000000..53866241 --- /dev/null +++ b/src/shared-rbtree.c @@ -0,0 +1,450 @@ +/*** + This file is part of rbtree. + + Copyright 2015 David Herrmann + + Based on the rbtree implementation of the linux-kernel: + Copyright 1999 Andrea Arcangeli + + rbtree is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + rbtree is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with rbtree; If not, see . +***/ + +/* + * Open Red-Black-Tree Implementation + * You're highly recommended to read a paper on rb-trees before reading this + * code. The reader is expected to be familiar with the different cases that + * might occur during insertion and removal of elements. The comments in this + * file do not contain a full prove for correctness. + */ + +#include "shared-rbtree.h" + +RBNode *rbnode_leftmost(RBNode *n) { + if (n) + while (n->left) + n = n->left; + return n; +} + +RBNode *rbnode_rightmost(RBNode *n) { + if (n) + while (n->right) + n = n->right; + return n; +} + +RBNode *rbtree_first(RBTree *t) { + return rbnode_leftmost(t->root); +} + +RBNode *rbtree_last(RBTree *t) { + return rbnode_rightmost(t->root); +} + +RBNode *rbnode_next(RBNode *n) { + RBNode *p; + + if (!rbnode_linked(n)) + return NULL; + + if (n->right) + return rbnode_leftmost(n->right); + + while ((p = rbnode_parent(n)) && n == p->right) + n = p; + + return p; +} + +RBNode *rbnode_prev(RBNode *n) { + RBNode *p; + + if (!rbnode_linked(n)) + return NULL; + + if (n->left) + return rbnode_rightmost(n->left); + + while ((p = rbnode_parent(n)) && n == p->left) + n = p; + + return p; +} + +static inline void rbnode_reparent(RBNode *n, RBNode *p, unsigned long c) { + /* change color and/or parent of a node */ + rbtree_assert(!((unsigned long)p & 1)); + rbtree_assert(c < 2); + n->__parent_and_color = (RBNode*)((unsigned long)p | c); +} + +static inline void rbtree_reparent(RBTree *t, RBNode *p, RBNode *old, RBNode *new) { + /* change previous parent/root from old to new node */ + if (p) { + if (p->left == old) + p->left = new; + else + p->right = new; + } else { + t->root = new; + } +} + +static inline RBNode *rbtree_paint_one(RBTree *t, RBNode *n) { + RBNode *p, *g, *gg, *u, *x; + + /* + * Paint a single node according to RB-Tree rules. The node must + * already be linked into the tree and painted red. + * We repaint the node or rotate the tree, if required. In case a + * recursive repaint is required, the next node to be re-painted + * is returned. + * p: parent + * g: grandparent + * gg: grandgrandparent + * u: uncle + * x: temporary + */ + + /* node is red, so we can access the parent directly */ + p = n->__parent_and_color; + + if (!p) { + /* Case 1: + * We reached the root. Mark it black and be done. As all + * leaf-paths share the root, the ratio of black nodes on each + * path stays the same. */ + rbnode_reparent(n, p, RBNODE_BLACK); + n = NULL; + } else if (rbnode_black(p)) { + /* Case 2: + * The parent is already black. As our node is red, we did not + * change the number of black nodes on any path, nor do we have + * multiple consecutive red nodes. */ + n = NULL; + } else if (p == p->__parent_and_color->left) { /* parent is red, so grandparent exists */ + g = p->__parent_and_color; + gg = rbnode_parent(g); + u = g->right; + + if (u && rbnode_red(u)) { + /* Case 3: + * Parent and uncle are both red. We know the + * grandparent must be black then. Repaint parent and + * uncle black, the grandparent red and recurse into + * the grandparent. */ + rbnode_reparent(p, g, RBNODE_BLACK); + rbnode_reparent(u, g, RBNODE_BLACK); + rbnode_reparent(g, gg, RBNODE_RED); + n = g; + } else { + /* parent is red, uncle is black */ + + if (n == p->right) { + /* Case 4: + * We're the right child. Rotate on parent to + * become left child, so we can handle it the + * same as case 5. */ + x = n->left; + p->right = n->left; + n->left = p; + if (x) + rbnode_reparent(x, p, RBNODE_BLACK); + rbnode_reparent(p, n, RBNODE_RED); + p = n; + } + + /* 'n' is invalid from here on! */ + n = NULL; + + /* Case 5: + * We're the red left child or a red parent, black + * grandparent and uncle. Rotate on grandparent and + * switch color with parent. Number of black nodes on + * each path stays the same, but we got rid of the + * double red path. As the grandparent is still black, + * we're done. */ + x = p->right; + g->left = x; + p->right = g; + if (x) + rbnode_reparent(x, g, RBNODE_BLACK); + rbnode_reparent(p, gg, RBNODE_BLACK); + rbnode_reparent(g, p, RBNODE_RED); + rbtree_reparent(t, gg, g, p); + } + } else /* if (p == p->__parent_and_color->left) */ { /* same as above, but mirrored */ + g = p->__parent_and_color; + gg = rbnode_parent(g); + u = g->left; + + if (u && rbnode_red(u)) { + rbnode_reparent(p, g, RBNODE_BLACK); + rbnode_reparent(u, g, RBNODE_BLACK); + rbnode_reparent(g, gg, RBNODE_RED); + n = g; + } else { + if (n == p->left) { + x = n->right; + p->left = n->right; + n->right = p; + if (x) + rbnode_reparent(x, p, RBNODE_BLACK); + rbnode_reparent(p, n, RBNODE_RED); + p = n; + } + + n = NULL; + + x = p->left; + g->right = x; + p->left = g; + if (x) + rbnode_reparent(x, g, RBNODE_BLACK); + rbnode_reparent(p, gg, RBNODE_BLACK); + rbnode_reparent(g, p, RBNODE_RED); + rbtree_reparent(t, gg, g, p); + } + } + + return n; +} + +static inline void rbtree_paint(RBTree *t, RBNode *n) { + while (n) + n = rbtree_paint_one(t, n); +} + +void rbtree_add(RBTree *t, RBNode *p, RBNode **l, RBNode *n) { + n->__parent_and_color = p; + n->left = n->right = NULL; + *l = n; + + rbtree_paint(t, n); +} + +static inline RBNode *rbtree_rebalance_one(RBTree *t, RBNode *p, RBNode *n) { + RBNode *s, *x, *y, *g; + + /* + * Rebalance tree after a node was removed. This happens only if you + * remove a black node and one path is now left with an unbalanced + * number or black nodes. + * This function assumes all paths through p and n have one black node + * less than all other paths. If recursive fixup is required, the + * current node is returned. + */ + + if (n == p->left) { + s = p->right; + if (rbnode_red(s)) { + /* Case 3: + * We have a red node as sibling. Rotate it onto our + * side so we can later on turn it black. This way, we + * gain the additional black node in our path. */ + g = rbnode_parent(p); + x = s->left; + p->right = x; + s->left = p; + rbnode_reparent(x, p, RBNODE_BLACK); + rbnode_reparent(s, g, rbnode_color(p)); + rbnode_reparent(p, s, RBNODE_RED); + rbtree_reparent(t, g, p, s); + s = x; + } + + x = s->right; + if (!x || rbnode_black(x)) { + y = s->left; + if (!y || rbnode_black(y)) { + /* Case 4: + * Our sibling is black and has only black + * children. Flip it red and turn parent black. + * This way we gained a black node in our path, + * or we fix it recursively one layer up, which + * will rotate the red sibling as parent. */ + rbnode_reparent(s, p, RBNODE_RED); + if (rbnode_black(p)) + return p; + + rbnode_reparent(p, rbnode_parent(p), RBNODE_BLACK); + return NULL; + } + + /* Case 5: + * Left child of our sibling is red, right one is black. + * Rotate on parent so the right child of our sibling is + * now red, and we can fall through to case 6. */ + x = y->right; + s->left = y->right; + y->right = s; + p->right = y; + if (x) + rbnode_reparent(x, s, RBNODE_BLACK); + x = s; + s = y; + } + + /* Case 6: + * The right child of our sibling is red. Rotate left and flip + * colors, which gains us an additional black node in our path, + * that was previously on our sibling. */ + g = rbnode_parent(p); + y = s->left; + p->right = y; + s->left = p; + rbnode_reparent(x, s, RBNODE_BLACK); + if (y) + rbnode_reparent(y, p, rbnode_color(y)); + rbnode_reparent(s, g, rbnode_color(p)); + rbnode_reparent(p, s, RBNODE_BLACK); + rbtree_reparent(t, g, p, s); + } else /* if (!n || n == p->right) */ { /* same as above, but mirrored */ + s = p->left; + if (rbnode_red(s)) { + g = rbnode_parent(p); + x = s->right; + p->left = x; + s->right = p; + rbnode_reparent(x, p, RBNODE_BLACK); + rbnode_reparent(s, g, RBNODE_BLACK); + rbnode_reparent(p, s, RBNODE_RED); + rbtree_reparent(t, g, p, s); + s = x; + } + + x = s->left; + if (!x || rbnode_black(x)) { + y = s->right; + if (!y || rbnode_black(y)) { + rbnode_reparent(s, p, RBNODE_RED); + if (rbnode_black(p)) + return p; + + rbnode_reparent(p, rbnode_parent(p), RBNODE_BLACK); + return NULL; + } + + x = y->left; + s->right = y->left; + y->left = s; + p->left = y; + if (x) + rbnode_reparent(x, s, RBNODE_BLACK); + x = s; + s = y; + } + + g = rbnode_parent(p); + y = s->right; + p->left = y; + s->right = p; + rbnode_reparent(x, s, RBNODE_BLACK); + if (y) + rbnode_reparent(y, p, rbnode_color(y)); + rbnode_reparent(s, g, rbnode_color(p)); + rbnode_reparent(p, s, RBNODE_BLACK); + rbtree_reparent(t, g, p, s); + } + + return NULL; +} + +static inline void rbtree_rebalance(RBTree *t, RBNode *p) { + RBNode *n = NULL; + + while (p) { + n = rbtree_rebalance_one(t, p, n); + p = n ? rbnode_parent(n) : NULL; + } +} + +void rbtree_remove(RBTree *t, RBNode *n) { + RBNode *p, *s, *gc, *x, *next = NULL; + unsigned long c; + + /* + * To remove an interior node from a binary tree, we simply find its + * successor, swap both nodes and then remove the node. Therefore, the + * only interesting case is were the node to be removed has at most one + * child. + * p: parent + * s: successor + * gc: grand-...-child + * x: temporary + * next: next node to rebalance on + */ + + if (!n->left) { + /* Case 1: + * We have at most one child, which must be red. We're + * guaranteed to be black then. Replace our node with the child + * (in case it exists), but turn it black. + * If no child exists, we need to rebalance, in case we were + * black as our path now lost a black node. */ + p = rbnode_parent(n); + c = rbnode_color(n); + rbtree_reparent(t, p, n, n->right); + if (n->right) + rbnode_reparent(n->right, p, c); + else + next = (c == RBNODE_BLACK) ? p : NULL; + } else if (!n->right) { + /* case 1 mirrored (but n->left guaranteed non-NULL) */ + p = rbnode_parent(n); + c = rbnode_color(n); + rbnode_reparent(n->left, p, c); + rbtree_reparent(t, p, n, n->left); + } else { + /* Case 2: + * We're an interior node. Find our successor and swap it with + * our node. Then remove our node. For performance reasons we + * don't perform the full swap, but skip links that are about to + * be removed, anyway. */ + s = n->right; + if (!s->left) { + /* right child is next, no need to touch grandchild */ + p = s; + gc = s->right; + } else { + /* find successor and swap partially */ + s = rbnode_leftmost(s); + p = rbnode_parent(s); + + gc = s->right; + p->left = s->right; + s->right = n->right; + rbnode_reparent(n->right, s, rbnode_color(n->right)); + } + + /* node is partially swapped, now remove as in case 1 */ + + s->left = n->left; + rbnode_reparent(n->left, s, rbnode_color(n->left)); + + x = rbnode_parent(n); + c = rbnode_color(n); + rbtree_reparent(t, x, n, s); + if (gc) { + rbnode_reparent(s, x, c); + rbnode_reparent(gc, p, RBNODE_BLACK); + } else { + next = rbnode_black(s) ? p : NULL; + rbnode_reparent(s, x, c); + } + } + + if (next) + rbtree_rebalance(t, next); +} diff --git a/src/shared-rbtree.h b/src/shared-rbtree.h new file mode 100644 index 00000000..ffb0296d --- /dev/null +++ b/src/shared-rbtree.h @@ -0,0 +1,99 @@ +#pragma once + +/*** + This file is part of rbtree. + + Copyright 2015 David Herrmann + + rbtree is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + rbtree is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with rbtree; If not, see . +***/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef RBTREE_DEBUG +# include +# define rbtree_assert(_x) assert(_x) +#else +# define rbtree_assert(_x) +#endif + +typedef struct RBTree RBTree; +typedef struct RBNode RBNode; + +enum { + RBNODE_RED = 0, + RBNODE_BLACK = 1, +}; + +struct RBTree { + RBNode *root; +}; + +struct RBNode { + RBNode *__parent_and_color; + RBNode *left; + RBNode *right; +}; + +#define rbnode_of(_ptr, _type, _member) \ + __extension__ ({ \ + const typeof( ((_type*)0)->_member ) *__ptr = (_ptr); \ + __ptr ? (_type*)( (char*)__ptr - offsetof(_type, _member) ) : NULL; \ + }) + +#define RBNODE_INIT(var) ((RBNode){ .__parent_and_color = (&var) }) + +static inline RBNode *rbnode_init(RBNode *n) { + *n = RBNODE_INIT(*n); + return n; +} + +static inline RBNode *rbnode_parent(RBNode *n) { + return (RBNode*)((unsigned long)n->__parent_and_color & ~1UL); +} + +static inline int rbnode_linked(RBNode *n) { + return n && n->__parent_and_color != n; +} + +static inline unsigned long rbnode_color(RBNode *n) { + return (unsigned long)n->__parent_and_color & 1UL; +} + +static inline int rbnode_red(RBNode *n) { + return rbnode_color(n) == RBNODE_RED; +} + +static inline int rbnode_black(RBNode *n) { + return rbnode_color(n) == RBNODE_BLACK; +} + +RBNode *rbnode_leftmost(RBNode *n); +RBNode *rbnode_rightmost(RBNode *n); + +RBNode *rbtree_first(RBTree *t); +RBNode *rbtree_last(RBTree *t); +RBNode *rbnode_next(RBNode *n); +RBNode *rbnode_prev(RBNode *n); + +void rbtree_add(RBTree *t, RBNode *p, RBNode **l, RBNode *n); +void rbtree_remove(RBTree *t, RBNode *n); + +#ifdef __cplusplus +} +#endif From c22d51e439f6ea907b3f9db9e0b3e452c8a9ac8d Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 25 Sep 2015 12:35:43 +0200 Subject: [PATCH 003/137] build: be more consistent in variable names Rename UDEV_* to LIBUDEV_* to be more consistent regarding other pkg-build dependencies. Signed-off-by: David Herrmann --- Makefile.am | 4 ++-- configure.ac | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index e721ab8e..8f6daf87 100644 --- a/Makefile.am +++ b/Makefile.am @@ -84,10 +84,10 @@ ratbagd_SOURCES = \ ratbagd_CFLAGS = \ $(AM_CFLAGS) \ - $(UDEV_CFLAGS) \ + $(LIBUDEV_CFLAGS) \ $(LIBSYSTEMD_CFLAGS) ratbagd_LDADD = \ libshared.la \ - $(UDEV_LIBS) \ + $(LIBUDEV_LIBS) \ $(LIBSYSTEMD_LIBS) diff --git a/configure.ac b/configure.ac index 2d40488d..c7d00191 100644 --- a/configure.ac +++ b/configure.ac @@ -127,7 +127,7 @@ m4_pattern_forbid([^_?PKG_[A-Z_]+$],[*** pkg.m4 missing, please install pkg-conf # ------------------------------------------------------------------------------ # dependencies -PKG_CHECK_MODULES([UDEV], [libudev]) +PKG_CHECK_MODULES([LIBUDEV], [libudev]) PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd >= 225]) # ------------------------------------------------------------------------------ From c4afc3d5c0a392cc04ce162fa5992f17c7ea7da3 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 25 Sep 2015 12:49:44 +0200 Subject: [PATCH 004/137] shared: add safe_close() Add safe_close() helper that makes close(2) a bit nicer to use. This also introduces PROTECT_ERRNO, which makes sure a function does not clutter errno if called. Signed-off-by: David Herrmann --- src/shared-macro.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/shared-macro.h b/src/shared-macro.h index c542b75f..56fa7d10 100644 --- a/src/shared-macro.h +++ b/src/shared-macro.h @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -34,6 +35,7 @@ #include #include #include +#include /* * We require: @@ -72,6 +74,15 @@ #define _weak_ __attribute__((weak)) #define _weakref_(_x) __attribute__((weakref(#_x))) +/* + * PROTECT_ERRNO: make sure a function protects errno + */ +static inline void reset_errno(int *saved_errno) +{ + errno = *saved_errno; +} +#define PROTECT_ERRNO _cleanup_(reset_errno) _unused_ int saved_errno = errno + /* * DEFINE_TRIVIAL_CLEANUP_FUNC() - define helper suitable for _cleanup_() * @_type: type of object to cleanup @@ -126,6 +137,22 @@ static inline void *mfree(void *mem) return NULL; } +/* + * safe_close() - safe variant of close(2) + * @fd: fd to close + * + * This is the same as close(2), but allows passing negative FDs, which makes + * it a no-op. Furthermore, this always returns -1. + */ +static inline int safe_close(int fd) +{ + if (fd >= 0) { + PROTECT_ERRNO; + close(fd); + } + return -1; +} + /* * Miscellaneous cleanup helpers * All these helpers are suitable for use with _cleanup_(). They call the helper @@ -136,6 +163,11 @@ static inline void freep(void *p) free(*(void**)p); } +static inline void safe_closep(int *fd) +{ + safe_close(*fd); +} + /* * streq() - test whether two strings are equal * @_a: string A From 8ca0c11154075267f817085455d5699580e4ed21 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 25 Sep 2015 12:51:11 +0200 Subject: [PATCH 005/137] ratbagd: keep libratbag context around Make sure the ratbagd context has a reference to a valid libratbag context at all times. We need this to access libratbag devices, so lets reference on in our own context. This also adds a dependency for libratbag via autotools. Signed-off-by: David Herrmann --- Makefile.am | 6 ++++-- configure.ac | 1 + src/ratbagd.c | 24 ++++++++++++++++++++++++ src/ratbagd.h | 2 ++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 8f6daf87..bf8b1b53 100644 --- a/Makefile.am +++ b/Makefile.am @@ -85,9 +85,11 @@ ratbagd_SOURCES = \ ratbagd_CFLAGS = \ $(AM_CFLAGS) \ $(LIBUDEV_CFLAGS) \ - $(LIBSYSTEMD_CFLAGS) + $(LIBSYSTEMD_CFLAGS) \ + $(LIBRATBAG_CFLAGS) ratbagd_LDADD = \ libshared.la \ $(LIBUDEV_LIBS) \ - $(LIBSYSTEMD_LIBS) + $(LIBSYSTEMD_LIBS) \ + $(LIBRATBAG_LIBS) diff --git a/configure.ac b/configure.ac index c7d00191..01362d9f 100644 --- a/configure.ac +++ b/configure.ac @@ -129,6 +129,7 @@ m4_pattern_forbid([^_?PKG_[A-Z_]+$],[*** pkg.m4 missing, please install pkg-conf PKG_CHECK_MODULES([LIBUDEV], [libudev]) PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd >= 225]) +PKG_CHECK_MODULES([LIBRATBAG], [libratbag]) # ------------------------------------------------------------------------------ # report diff --git a/src/ratbagd.c b/src/ratbagd.c index 86c8cb88..69e423a4 100644 --- a/src/ratbagd.c +++ b/src/ratbagd.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -100,6 +101,23 @@ static int ratbagd_monitor_event(sd_event_source *source, return 0; } +static int ratbagd_lib_open_restricted(const char *path, + int flags, + void *userdata) +{ + return open(path, flags, 0); +} + +static void ratbagd_lib_close_restricted(int fd, void *userdata) +{ + safe_close(fd); +} + +static const struct ratbag_interface ratbagd_lib_interface = { + .open_restricted = ratbagd_lib_open_restricted, + .close_restricted = ratbagd_lib_close_restricted, +}; + static struct ratbagd *ratbagd_free(struct ratbagd *ctx) { if (!ctx) @@ -108,9 +126,11 @@ static struct ratbagd *ratbagd_free(struct ratbagd *ctx) ctx->bus = sd_bus_flush_close_unref(ctx->bus); ctx->monitor_source = sd_event_source_unref(ctx->monitor_source); ctx->monitor = udev_monitor_unref(ctx->monitor); + ctx->lib_ctx = ratbag_unref(ctx->lib_ctx); ctx->event = sd_event_unref(ctx->event); assert(!ctx->device_map.root); + assert(!ctx->lib_ctx); /* ratbag returns non-NULL if still pinned */ return mfree(ctx); } @@ -173,6 +193,10 @@ static int ratbagd_new(struct ratbagd **out) if (r < 0) return r; + ctx->lib_ctx = ratbag_create_context(&ratbagd_lib_interface, ctx); + if (!ctx->lib_ctx) + return -ENOMEM; + r = ratbagd_init_monitor(ctx); if (r < 0) return r; diff --git a/src/ratbagd.h b/src/ratbagd.h index 84235f09..bed93389 100644 --- a/src/ratbagd.h +++ b/src/ratbagd.h @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -58,6 +59,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_device *, ratbagd_device_free); struct ratbagd { sd_event *event; + struct ratbag *lib_ctx; struct udev_monitor *monitor; sd_event_source *monitor_source; sd_bus *bus; From 17d66153b061ef8e587fc9e1e96f34d8fc4ce986 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 25 Sep 2015 15:57:14 +0200 Subject: [PATCH 006/137] ratbagd: ignore anything but event devices We are only interested in evdev, so ignore anything but input-event devices. Signed-off-by: David Herrmann --- src/ratbagd.c | 2 +- src/shared-macro.h | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/ratbagd.c b/src/ratbagd.c index 69e423a4..e9efc681 100644 --- a/src/ratbagd.c +++ b/src/ratbagd.c @@ -58,7 +58,7 @@ static void ratbagd_process_device(struct ratbagd *ctx, */ name = udev_device_get_sysname(udevice); - if (!name) + if (!name || !startswith(name, "event")) return; device = ratbagd_find_device(ctx, name); diff --git a/src/shared-macro.h b/src/shared-macro.h index 56fa7d10..05ec2f3b 100644 --- a/src/shared-macro.h +++ b/src/shared-macro.h @@ -185,6 +185,25 @@ static inline bool streq_ptr(const char *a, const char *b) return (a && b) ? streq(a, b) : (!a && !b); } +/* + * startswith() - test prefix of a string + * @s: string to test + * @prefix: prefix to test for + * + * This returns a pointer to the first character in @s that follows @prefix. If + * @s does not start with @prefix, NULL is returned. + */ +static inline char *startswith(const char *s, const char *prefix) +{ + size_t l; + + l = strlen(prefix); + if (strncmp(s, prefix, l) == 0) + return (char*) s + l; + + return NULL; +} + /* * now() - returns current time in nano-seconds * @clock: clock to use From bea8e89cc7dd63c7188631d0a3c42ae3c523da2e Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 25 Sep 2015 16:05:26 +0200 Subject: [PATCH 007/137] ratbagd: create libratbag_device contexts Make sure to create libratbag_device contexts for each device we add. If libratbag returns NULL, we just ignore the devices. Otherwise, we keep the context around and manage the device. Signed-off-by: David Herrmann --- src/ratbagd-device.c | 10 +++++++++- src/ratbagd.c | 19 +++++++++++-------- src/ratbagd.h | 3 ++- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 8c54951f..b63552d1 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -38,6 +39,7 @@ struct ratbagd_device { struct ratbagd *ctx; RBNode node; char *name; + struct ratbag_device *lib_device; }; #define ratbagd_device_from_node(_ptr) \ @@ -117,7 +119,8 @@ static const sd_bus_vtable ratbagd_device_vtable[] = { int ratbagd_device_new(struct ratbagd_device **out, struct ratbagd *ctx, - const char *name) + const char *name, + struct ratbag_device *lib_device) { _cleanup_(ratbagd_device_freep) struct ratbagd_device *device = NULL; @@ -131,6 +134,7 @@ int ratbagd_device_new(struct ratbagd_device **out, device->ctx = ctx; rbnode_init(&device->node); + device->lib_device = ratbag_device_ref(lib_device); device->name = strdup(name); if (!device->name) @@ -148,7 +152,11 @@ struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device) assert(!ratbagd_device_linked(device)); + device->lib_device = ratbag_device_unref(device->lib_device); device->name = mfree(device->name); + + assert(!device->lib_device); /* ratbag yields !NULL if still pinned */ + return mfree(device); } diff --git a/src/ratbagd.c b/src/ratbagd.c index e9efc681..437d98ce 100644 --- a/src/ratbagd.c +++ b/src/ratbagd.c @@ -37,18 +37,12 @@ static void ratbagd_process_device(struct ratbagd *ctx, struct udev_device *udevice) { + struct ratbag_device *lib_device; struct ratbagd_device *device; const char *name; int r; /* - * TODO: So far we just enumerate udev input devices and add a new - * ratbag device for each one we find. That's a bit easy. We - * should really try to create a libratbag device for the udev - * device and only add devices that are actually accepted. - * Furthermore, the libratbag object should really be kept as - * context in ratbagd_device. - * * TODO: libratbag should provide some mechanism to allow * device-grouping, just like libinput does. If multiple input * devices belong to the same virtual device, we should not add @@ -73,7 +67,16 @@ static void ratbagd_process_device(struct ratbagd *ctx, /* device already known, refresh our view of the device */ } else { /* device unknown, create new one and link it */ - r = ratbagd_device_new(&device, ctx, name); + lib_device = ratbag_device_new_from_udev_device(ctx->lib_ctx, + udevice); + if (!lib_device) + return; /* unsupported device */ + + r = ratbagd_device_new(&device, ctx, name, lib_device); + + /* the ratbagd_device takes its own reference, drop ours */ + ratbag_device_unref(lib_device); + if (r < 0) { fprintf(stderr, "Cannot track device '%s'\n", name); return; diff --git a/src/ratbagd.h b/src/ratbagd.h index bed93389..687e1aad 100644 --- a/src/ratbagd.h +++ b/src/ratbagd.h @@ -45,7 +45,8 @@ struct ratbagd_device; int ratbagd_device_new(struct ratbagd_device **out, struct ratbagd *ctx, - const char *name); + const char *name, + struct ratbag_device *lib_device); struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device); bool ratbagd_device_linked(struct ratbagd_device *device); void ratbagd_device_link(struct ratbagd_device *device); From e4617108117eaa5e7bf16d1007bf6ac2bc03bfd5 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 25 Sep 2015 16:27:45 +0200 Subject: [PATCH 008/137] ratbagd: add basic device properties Add two device properties: - Id: Returns the string ID to identify the device - Description: Returns the ratbag-device name Signed-off-by: David Herrmann --- src/ratbagd-device.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index b63552d1..44b83aca 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -112,8 +112,28 @@ error: return r; } +static int ratbagd_device_get_description(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_device *device = userdata; + const char *description; + + description = ratbag_device_get_name(device->lib_device); + if (!description) + return -ENODATA; + + return sd_bus_message_append(reply, "s", description); +} + static const sd_bus_vtable ratbagd_device_vtable[] = { SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct ratbagd_device, name), SD_BUS_VTABLE_UNPRIVILEGED | SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Description", "s", ratbagd_device_get_description, 0, SD_BUS_VTABLE_UNPRIVILEGED | SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_VTABLE_END, }; From c0799b0c1dac9e9d67324664f27eebafc7602e23 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sat, 26 Sep 2015 17:59:58 +0200 Subject: [PATCH 009/137] ratbagd: drop UNPRIVILEGED from properties This does not work, we cannot flag properties as UNPRIVILEGED. Drop it. Lets figure out later what exactly we want as privilege level to enumerate and query device properties. Signed-off-by: David Herrmann --- src/ratbagd-device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 44b83aca..952cad19 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -132,8 +132,8 @@ static int ratbagd_device_get_description(sd_bus *bus, static const sd_bus_vtable ratbagd_device_vtable[] = { SD_BUS_VTABLE_START(0), - SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct ratbagd_device, name), SD_BUS_VTABLE_UNPRIVILEGED | SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("Description", "s", ratbagd_device_get_description, 0, SD_BUS_VTABLE_UNPRIVILEGED | SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct ratbagd_device, name), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Description", "s", ratbagd_device_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_VTABLE_END, }; From b1851ada931ef2b7a56a4557fef47721adb17e51 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sat, 26 Sep 2015 18:02:00 +0200 Subject: [PATCH 010/137] ratbagd: split dbus handling from object handling Make sure our dbus callbacks to not contain any logic themselves. They should be simple wrappers around our internal object handling. This also makes use of the new sd-bus pat helpers, to-be-released with systemd-v227 next week. Signed-off-by: David Herrmann --- configure.ac | 2 +- src/ratbagd-device.c | 96 ++++++++++++++++++++++++-------------------- src/ratbagd.c | 2 +- src/ratbagd.h | 6 ++- 4 files changed, 58 insertions(+), 48 deletions(-) diff --git a/configure.ac b/configure.ac index 01362d9f..cb647f0d 100644 --- a/configure.ac +++ b/configure.ac @@ -128,7 +128,7 @@ m4_pattern_forbid([^_?PKG_[A-Z_]+$],[*** pkg.m4 missing, please install pkg-conf # dependencies PKG_CHECK_MODULES([LIBUDEV], [libudev]) -PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd >= 225]) +PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd >= 227]) PKG_CHECK_MODULES([LIBRATBAG], [libratbag]) # ------------------------------------------------------------------------------ diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 952cad19..30d4fb71 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -45,7 +45,7 @@ struct ratbagd_device { #define ratbagd_device_from_node(_ptr) \ rbnode_of((_ptr), struct ratbagd_device, node) -static int ratbagd_device_find(sd_bus *bus, +static int ratbagd_find_device(sd_bus *bus, const char *path, const char *interface, void *userdata, @@ -57,12 +57,13 @@ static int ratbagd_device_find(sd_bus *bus, struct ratbagd_device *device; int r; - /* decodes the suffix into @name, returns 1 if valid */ - r = sd_bus_path_decode(path, "/org/freedesktop/ratbag1/device", &name); + r = sd_bus_path_decode_many(path, + "/org/freedesktop/ratbag1/device/%", + &name); if (r <= 0) return r; - device = ratbagd_find_device(ctx, name); + device = ratbagd_device_lookup(ctx, name); if (!device) return 0; @@ -70,46 +71,17 @@ static int ratbagd_device_find(sd_bus *bus, return 1; } -static int ratbagd_device_list(sd_bus *bus, - const char *path, - void *userdata, - char ***nodes, - sd_bus_error *error) +static int ratbagd_list_devices(sd_bus *bus, + const char *path, + void *userdata, + char ***paths, + sd_bus_error *error) { struct ratbagd *ctx = userdata; - struct ratbagd_device *device; - char **devices, **pos; - RBNode *node; int r; - devices = calloc(ctx->n_devices + 1, sizeof(char *)); - if (!devices) - return -ENOMEM; - - pos = devices; - - for (node = rbtree_first(&ctx->device_map); - node; - node = rbnode_next(node)) { - device = ratbagd_device_from_node(node); - - r = sd_bus_path_encode("/org/freedesktop/ratbag1/device", - device->name, - pos++); - if (r < 0) - goto error; - } - - *pos = NULL; - - *nodes = devices; - return 1; - -error: - for (pos = devices; *pos; ++pos) - free(*pos); - free(devices); - return r; + r = ratbagd_device_list(ctx, paths); + return r < 0 ? r : 1; } static int ratbagd_device_get_description(sd_bus *bus, @@ -274,7 +246,7 @@ int ratbagd_init_device(struct ratbagd *ctx) "/org/freedesktop/ratbag1/device", "org.freedesktop.ratbag1.Device", ratbagd_device_vtable, - ratbagd_device_find, + ratbagd_find_device, ctx); if (r < 0) return r; @@ -282,7 +254,7 @@ int ratbagd_init_device(struct ratbagd *ctx) r = sd_bus_add_node_enumerator(ctx->bus, NULL, "/org/freedesktop/ratbag1/device", - ratbagd_device_list, + ratbagd_list_devices, ctx); if (r < 0) return r; @@ -290,8 +262,8 @@ int ratbagd_init_device(struct ratbagd *ctx) return 0; } -struct ratbagd_device *ratbagd_find_device(struct ratbagd *ctx, - const char *name) +struct ratbagd_device *ratbagd_device_lookup(struct ratbagd *ctx, + const char *name) { struct ratbagd_device *device; RBNode *node; @@ -314,3 +286,39 @@ struct ratbagd_device *ratbagd_find_device(struct ratbagd *ctx, return NULL; } + +int ratbagd_device_list(struct ratbagd *ctx, char ***paths) +{ + struct ratbagd_device *device; + char **devices, **pos; + RBNode *node; + int r; + + devices = calloc(ctx->n_devices + 1, sizeof(char *)); + if (!devices) + return -ENOMEM; + + pos = devices; + + for (node = rbtree_first(&ctx->device_map); + node; + node = rbnode_next(node)) { + device = ratbagd_device_from_node(node); + + r = sd_bus_path_encode_many(pos++, + "/org/freedesktop/ratbag1/device/%", + device->name); + if (r < 0) + goto error; + } + + *pos = NULL; + *paths = devices; + return 1; + +error: + for (pos = devices; *pos; ++pos) + free(*pos); + free(devices); + return r; +} diff --git a/src/ratbagd.c b/src/ratbagd.c index 437d98ce..584ad2ab 100644 --- a/src/ratbagd.c +++ b/src/ratbagd.c @@ -55,7 +55,7 @@ static void ratbagd_process_device(struct ratbagd *ctx, if (!name || !startswith(name, "event")) return; - device = ratbagd_find_device(ctx, name); + device = ratbagd_device_lookup(ctx, name); if (streq_ptr("remove", udev_device_get_action(udevice))) { /* device was removed, unlink it and destroy our context */ diff --git a/src/ratbagd.h b/src/ratbagd.h index 687e1aad..83bcacb9 100644 --- a/src/ratbagd.h +++ b/src/ratbagd.h @@ -54,6 +54,10 @@ void ratbagd_device_unlink(struct ratbagd_device *device); DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_device *, ratbagd_device_free); +struct ratbagd_device *ratbagd_device_lookup(struct ratbagd *ctx, + const char *name); +int ratbagd_device_list(struct ratbagd *ctx, char ***paths); + /* * Context */ @@ -70,5 +74,3 @@ struct ratbagd { }; int ratbagd_init_device(struct ratbagd *ctx); -struct ratbagd_device *ratbagd_find_device(struct ratbagd *ctx, - const char *name); From dbc8a37b56b2f5e43bcccf9f706942eced7bafd8 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sat, 26 Sep 2015 18:07:18 +0200 Subject: [PATCH 011/137] ratbagd: move dbus device management Make sure the device management (lookup and enumeration and registration) is done from the parent, not the child. Hence, move it into ratbagd.c over ratbagd-device. Signed-off-by: David Herrmann --- src/ratbagd-device.c | 74 +------------------------------------------- src/ratbagd.c | 55 +++++++++++++++++++++++++++++++- src/ratbagd.h | 4 +-- 3 files changed, 57 insertions(+), 76 deletions(-) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 30d4fb71..cae64b62 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -45,45 +45,6 @@ struct ratbagd_device { #define ratbagd_device_from_node(_ptr) \ rbnode_of((_ptr), struct ratbagd_device, node) -static int ratbagd_find_device(sd_bus *bus, - const char *path, - const char *interface, - void *userdata, - void **found, - sd_bus_error *error) -{ - _cleanup_(freep) char *name = NULL; - struct ratbagd *ctx = userdata; - struct ratbagd_device *device; - int r; - - r = sd_bus_path_decode_many(path, - "/org/freedesktop/ratbag1/device/%", - &name); - if (r <= 0) - return r; - - device = ratbagd_device_lookup(ctx, name); - if (!device) - return 0; - - *found = device; - return 1; -} - -static int ratbagd_list_devices(sd_bus *bus, - const char *path, - void *userdata, - char ***paths, - sd_bus_error *error) -{ - struct ratbagd *ctx = userdata; - int r; - - r = ratbagd_device_list(ctx, paths); - return r < 0 ? r : 1; -} - static int ratbagd_device_get_description(sd_bus *bus, const char *path, const char *interface, @@ -102,7 +63,7 @@ static int ratbagd_device_get_description(sd_bus *bus, return sd_bus_message_append(reply, "s", description); } -static const sd_bus_vtable ratbagd_device_vtable[] = { +const sd_bus_vtable ratbagd_device_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct ratbagd_device, name), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Description", "s", ratbagd_device_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST), @@ -229,39 +190,6 @@ void ratbagd_device_unlink(struct ratbagd_device *device) rbnode_init(&device->node); } -int ratbagd_init_device(struct ratbagd *ctx) -{ - int r; - - assert(ctx); - - /* - * Called by the context initializer after the context was prepared but - * not run, yet. No need to cleanup anything if an error is returned, - * as long it is teared down automatically on destruction. - */ - - r = sd_bus_add_fallback_vtable(ctx->bus, - NULL, - "/org/freedesktop/ratbag1/device", - "org.freedesktop.ratbag1.Device", - ratbagd_device_vtable, - ratbagd_find_device, - ctx); - if (r < 0) - return r; - - r = sd_bus_add_node_enumerator(ctx->bus, - NULL, - "/org/freedesktop/ratbag1/device", - ratbagd_list_devices, - ctx); - if (r < 0) - return r; - - return 0; -} - struct ratbagd_device *ratbagd_device_lookup(struct ratbagd *ctx, const char *name) { diff --git a/src/ratbagd.c b/src/ratbagd.c index 584ad2ab..960b926d 100644 --- a/src/ratbagd.c +++ b/src/ratbagd.c @@ -34,6 +34,45 @@ #include "ratbagd.h" #include "shared-macro.h" +static int ratbagd_find_device(sd_bus *bus, + const char *path, + const char *interface, + void *userdata, + void **found, + sd_bus_error *error) +{ + _cleanup_(freep) char *name = NULL; + struct ratbagd *ctx = userdata; + struct ratbagd_device *device; + int r; + + r = sd_bus_path_decode_many(path, + "/org/freedesktop/ratbag1/device/%", + &name); + if (r <= 0) + return r; + + device = ratbagd_device_lookup(ctx, name); + if (!device) + return 0; + + *found = device; + return 1; +} + +static int ratbagd_list_devices(sd_bus *bus, + const char *path, + void *userdata, + char ***paths, + sd_bus_error *error) +{ + struct ratbagd *ctx = userdata; + int r; + + r = ratbagd_device_list(ctx, paths); + return r < 0 ? r : 1; +} + static void ratbagd_process_device(struct ratbagd *ctx, struct udev_device *udevice) { @@ -214,7 +253,21 @@ static int ratbagd_new(struct ratbagd **out) if (r < 0) return r; - r = ratbagd_init_device(ctx); + r = sd_bus_add_fallback_vtable(ctx->bus, + NULL, + "/org/freedesktop/ratbag1/device", + "org.freedesktop.ratbag1.Device", + ratbagd_device_vtable, + ratbagd_find_device, + ctx); + if (r < 0) + return r; + + r = sd_bus_add_node_enumerator(ctx->bus, + NULL, + "/org/freedesktop/ratbag1/device", + ratbagd_list_devices, + ctx); if (r < 0) return r; diff --git a/src/ratbagd.h b/src/ratbagd.h index 83bcacb9..d86c1fe0 100644 --- a/src/ratbagd.h +++ b/src/ratbagd.h @@ -43,6 +43,8 @@ struct ratbagd_device; * Devices */ +extern const sd_bus_vtable ratbagd_device_vtable[]; + int ratbagd_device_new(struct ratbagd_device **out, struct ratbagd *ctx, const char *name, @@ -72,5 +74,3 @@ struct ratbagd { RBTree device_map; size_t n_devices; }; - -int ratbagd_init_device(struct ratbagd *ctx); From 1a8037cd6c5cf610d14e04e5a4b47833e863b363 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sat, 26 Sep 2015 18:53:55 +0200 Subject: [PATCH 012/137] ratbagd: expose profiles on the bus Profiles are static children of devices. Expose them as 2nd-level objects underneath their parent devices on the bus. Signed-off-by: David Herrmann --- Makefile.am | 3 +- src/ratbagd-device.c | 131 +++++++++++++++++++++++++++++++++++++++++- src/ratbagd-profile.c | 79 +++++++++++++++++++++++++ src/ratbagd.h | 14 +++++ src/shared-macro.h | 42 ++++++++++++++ 5 files changed, 267 insertions(+), 2 deletions(-) create mode 100644 src/ratbagd-profile.c diff --git a/Makefile.am b/Makefile.am index bf8b1b53..52c0acf6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -80,7 +80,8 @@ bin_PROGRAMS += \ ratbagd_SOURCES = \ src/ratbagd.h \ src/ratbagd.c \ - src/ratbagd-device.c + src/ratbagd-device.c \ + src/ratbagd-profile.c ratbagd_CFLAGS = \ $(AM_CFLAGS) \ diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index cae64b62..f82dcf33 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -40,11 +40,83 @@ struct ratbagd_device { RBNode node; char *name; struct ratbag_device *lib_device; + + sd_bus_slot *profile_vtable_slot; + sd_bus_slot *profile_enum_slot; + unsigned int n_profiles; + struct ratbagd_profile **profiles; }; #define ratbagd_device_from_node(_ptr) \ rbnode_of((_ptr), struct ratbagd_device, node) +static int ratbagd_device_find_profile(sd_bus *bus, + const char *path, + const char *interface, + void *userdata, + void **found, + sd_bus_error *error) +{ + _cleanup_(freep) char *name = NULL; + struct ratbagd_device *device = userdata; + unsigned int index; + int r; + + r = sd_bus_path_decode_many(path, + "/org/freedesktop/ratbag1/device/%/profile/%", + NULL, + &name); + if (r <= 0) + return r; + + r = safe_atou(name, &index); + if (r < 0) + return 0; + + if (index >= device->n_profiles) + return 0; + + *found = device->profiles[index]; + return 1; +} + +static int ratbagd_device_list_profiles(sd_bus *bus, + const char *path, + void *userdata, + char ***paths, + sd_bus_error *error) +{ + struct ratbagd_device *device = userdata; + char index_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1]; + char **profiles; + unsigned int i; + int r; + + profiles = calloc(device->n_profiles + 1, sizeof(char *)); + if (!profiles) + return -ENOMEM; + + for (i = 0; i < device->n_profiles; ++i) { + sprintf(index_buffer, "%u", i); + r = sd_bus_path_encode_many(&profiles[i], + "/org/freedesktop/ratbag1/device/%/profile/%", + device->name, + index_buffer); + if (r < 0) + goto error; + } + + profiles[i] = NULL; + *paths = profiles; + return 1; + +error: + for (i = 0; profiles[i]; ++i) + free(profiles[i]); + free(profiles); + return r; +} + static int ratbagd_device_get_description(sd_bus *bus, const char *path, const char *interface, @@ -76,6 +148,9 @@ int ratbagd_device_new(struct ratbagd_device **out, struct ratbag_device *lib_device) { _cleanup_(ratbagd_device_freep) struct ratbagd_device *device = NULL; + struct ratbag_profile *profile; + unsigned int i; + int r; assert(out); assert(ctx); @@ -93,6 +168,25 @@ int ratbagd_device_new(struct ratbagd_device **out, if (!device->name) return -ENOMEM; + device->n_profiles = ratbag_device_get_num_profiles(device->lib_device); + device->profiles = calloc(device->n_profiles, sizeof(*device->profiles)); + if (!device->profiles) + return -ENOMEM; + + for (i = 0; i < device->n_profiles; ++i) { + profile = ratbag_device_get_profile(device->lib_device, i); + if (!profile) + continue; + + r = ratbagd_profile_new(&device->profiles[i], profile, i); + if (r < 0) { + errno = -r; + fprintf(stderr, + "Cannot allocate profile for '%s': %m\n", + device->name); + } + } + *out = device; device = NULL; return 0; @@ -100,11 +194,17 @@ int ratbagd_device_new(struct ratbagd_device **out, struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device) { + unsigned int i; + if (!device) return NULL; assert(!ratbagd_device_linked(device)); + for (i = 0; i < device->n_profiles; ++i) + device->profiles[i] = ratbagd_profile_free(device->profiles[i]); + + device->profiles = mfree(device->profiles); device->lib_device = ratbag_device_unref(device->lib_device); device->name = mfree(device->name); @@ -120,7 +220,7 @@ bool ratbagd_device_linked(struct ratbagd_device *device) void ratbagd_device_link(struct ratbagd_device *device) { - _cleanup_(freep) char *path = NULL; + _cleanup_(freep) char *path = NULL, *prefix = NULL; struct ratbagd_device *iter; RBNode **node, *parent; int r, v; @@ -161,6 +261,32 @@ void ratbagd_device_link(struct ratbagd_device *device) "Cannot send device notification for '%s': %m\n", device->name); } + + /* register profile interfaces */ + r = sd_bus_path_encode_many(&prefix, + "/org/freedesktop/ratbag1/device/%/profile", + device->name); + if (r >= 0) { + r = sd_bus_add_fallback_vtable(device->ctx->bus, + &device->profile_vtable_slot, + prefix, + "org.freedesktop.ratbag1.Profile", + ratbagd_profile_vtable, + ratbagd_device_find_profile, + device); + if (r >= 0) + r = sd_bus_add_node_enumerator(device->ctx->bus, + &device->profile_enum_slot, + prefix, + ratbagd_device_list_profiles, + device); + } + if (r < 0) { + errno = -r; + fprintf(stderr, + "Cannot register profile interfaces for '%s': %m\n", + device->name); + } } void ratbagd_device_unlink(struct ratbagd_device *device) @@ -171,6 +297,9 @@ void ratbagd_device_unlink(struct ratbagd_device *device) if (!ratbagd_device_linked(device)) return; + device->profile_enum_slot = sd_bus_slot_unref(device->profile_enum_slot); + device->profile_vtable_slot = sd_bus_slot_unref(device->profile_vtable_slot); + /* send out object-manager notification */ r = sd_bus_path_encode("/org/freedesktop/ratbag1/device", device->name, diff --git a/src/ratbagd-profile.c b/src/ratbagd-profile.c new file mode 100644 index 00000000..ad7a9d24 --- /dev/null +++ b/src/ratbagd-profile.c @@ -0,0 +1,79 @@ +/*** + This file is part of ratbagd. + + Copyright 2015 David Herrmann + + 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_profile { + struct ratbag_profile *lib_profile; + unsigned int index; +}; + +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_VTABLE_END, +}; + +int ratbagd_profile_new(struct ratbagd_profile **out, + struct ratbag_profile *lib_profile, + unsigned int index) +{ + _cleanup_(ratbagd_profile_freep) struct ratbagd_profile *profile = NULL; + + assert(out); + assert(lib_profile); + + profile = calloc(1, sizeof(*profile)); + if (!profile) + return -ENOMEM; + + profile->lib_profile = lib_profile; + profile->index = index; + + *out = profile; + profile = NULL; + return 0; +} + +struct ratbagd_profile *ratbagd_profile_free(struct ratbagd_profile *profile) +{ + if (!profile) + return NULL; + + /* we cannot assume the profile is gone, so set NULL explicitly */ + ratbag_profile_unref(profile->lib_profile); + profile->lib_profile = NULL; + + return mfree(profile); +} diff --git a/src/ratbagd.h b/src/ratbagd.h index d86c1fe0..8a58898c 100644 --- a/src/ratbagd.h +++ b/src/ratbagd.h @@ -38,6 +38,20 @@ struct ratbagd; struct ratbagd_device; +struct ratbagd_profile; + +/* + * Profiles + */ + +extern const sd_bus_vtable ratbagd_profile_vtable[]; + +int ratbagd_profile_new(struct ratbagd_profile **out, + struct ratbag_profile *lib_profile, + unsigned int index); +struct ratbagd_profile *ratbagd_profile_free(struct ratbagd_profile *profile); + +DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_profile *, ratbagd_profile_free); /* * Devices diff --git a/src/shared-macro.h b/src/shared-macro.h index 05ec2f3b..748d4292 100644 --- a/src/shared-macro.h +++ b/src/shared-macro.h @@ -74,6 +74,18 @@ #define _weak_ __attribute__((weak)) #define _weakref_(_x) __attribute__((weakref(#_x))) +/* + * DECIMAL_TOKEN_MAX() - calculate maximum length of the decimal representation + * of an integer + * @_type: type of integer + */ +#define DECIMAL_TOKEN_MAX(_type) \ + (1 + (sizeof(_type) <= 1 ? 3 : \ + sizeof(_type) <= 2 ? 5 : \ + sizeof(_type) <= 4 ? 10 : \ + sizeof(_type) <= 8 ? 20 : \ + sizeof(int[-2 * (sizeof(_type) > 8)]))) + /* * PROTECT_ERRNO: make sure a function protects errno */ @@ -204,6 +216,36 @@ static inline char *startswith(const char *s, const char *prefix) return NULL; } +/* + * safe_atou() - safe variant of strtoul() + * @s: string to parse + * @ret_u: output storage for parsed integer + * + * This is a sane and safe variant of strtoul(), which rejects any invalid + * input, or trailing garbage. + * + * Return: 0 on success, negative error code on failure. + */ +static inline int safe_atou(const char *s, unsigned int *ret_u) +{ + char *x = NULL; + unsigned long l; + + assert(s); + assert(ret_u); + + errno = 0; + l = strtoul(s, &x, 0); + if (!x || x == s || *x || errno) + return errno > 0 ? -errno : -EINVAL; + + if ((unsigned long)(unsigned int)l != l) + return -ERANGE; + + *ret_u = (unsigned int)l; + return 0; +} + /* * now() - returns current time in nano-seconds * @clock: clock to use From 7e4d757bdfe129b1d8587903603cd40d0f771889 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 13:09:45 +0200 Subject: [PATCH 013/137] ratbagd: cache device path Cache device path in device->path and avoid re-calculating it all the time. Signed-off-by: David Herrmann --- src/ratbagd-device.c | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index f82dcf33..aa2f8f65 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -39,6 +39,7 @@ struct ratbagd_device { struct ratbagd *ctx; RBNode node; char *name; + char *path; struct ratbag_device *lib_device; sd_bus_slot *profile_vtable_slot; @@ -168,6 +169,12 @@ int ratbagd_device_new(struct ratbagd_device **out, if (!device->name) return -ENOMEM; + r = sd_bus_path_encode("/org/freedesktop/ratbag1/device", + device->name, + &device->path); + if (r < 0) + return r; + device->n_profiles = ratbag_device_get_num_profiles(device->lib_device); device->profiles = calloc(device->n_profiles, sizeof(*device->profiles)); if (!device->profiles) @@ -206,6 +213,7 @@ struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device) device->profiles = mfree(device->profiles); device->lib_device = ratbag_device_unref(device->lib_device); + device->path = mfree(device->path); device->name = mfree(device->name); assert(!device->lib_device); /* ratbag yields !NULL if still pinned */ @@ -220,7 +228,7 @@ bool ratbagd_device_linked(struct ratbagd_device *device) void ratbagd_device_link(struct ratbagd_device *device) { - _cleanup_(freep) char *path = NULL, *prefix = NULL; + _cleanup_(freep) char *prefix = NULL; struct ratbagd_device *iter; RBNode **node, *parent; int r, v; @@ -250,11 +258,7 @@ void ratbagd_device_link(struct ratbagd_device *device) ++device->ctx->n_devices; /* send out object-manager notification */ - r = sd_bus_path_encode("/org/freedesktop/ratbag1/device", - device->name, - &path); - if (r >= 0) - r = sd_bus_emit_object_added(device->ctx->bus, path); + r = sd_bus_emit_object_added(device->ctx->bus, device->path); if (r < 0) { errno = -r; fprintf(stderr, @@ -263,9 +267,7 @@ void ratbagd_device_link(struct ratbagd_device *device) } /* register profile interfaces */ - r = sd_bus_path_encode_many(&prefix, - "/org/freedesktop/ratbag1/device/%/profile", - device->name); + r = asprintf(&prefix, "%s/profile", device->path); if (r >= 0) { r = sd_bus_add_fallback_vtable(device->ctx->bus, &device->profile_vtable_slot, @@ -291,7 +293,6 @@ void ratbagd_device_link(struct ratbagd_device *device) void ratbagd_device_unlink(struct ratbagd_device *device) { - _cleanup_(freep) char *path = NULL; int r; if (!ratbagd_device_linked(device)) @@ -301,11 +302,7 @@ void ratbagd_device_unlink(struct ratbagd_device *device) device->profile_vtable_slot = sd_bus_slot_unref(device->profile_vtable_slot); /* send out object-manager notification */ - r = sd_bus_path_encode("/org/freedesktop/ratbag1/device", - device->name, - &path); - if (r >= 0) - r = sd_bus_emit_object_removed(device->ctx->bus, path); + r = sd_bus_emit_object_removed(device->ctx->bus, device->path); if (r < 0) { errno = -r; fprintf(stderr, @@ -349,7 +346,6 @@ int ratbagd_device_list(struct ratbagd *ctx, char ***paths) struct ratbagd_device *device; char **devices, **pos; RBNode *node; - int r; devices = calloc(ctx->n_devices + 1, sizeof(char *)); if (!devices) @@ -361,12 +357,10 @@ int ratbagd_device_list(struct ratbagd *ctx, char ***paths) node; node = rbnode_next(node)) { device = ratbagd_device_from_node(node); - - r = sd_bus_path_encode_many(pos++, - "/org/freedesktop/ratbag1/device/%", - device->name); - if (r < 0) + *pos = strdup(device->path); + if (!*pos) goto error; + ++pos; } *pos = NULL; @@ -377,5 +371,5 @@ error: for (pos = devices; *pos; ++pos) free(*pos); free(devices); - return r; + return -ENOMEM; } From 9ac799bc956aa47803dceeb596d47238fbeb3d41 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 13:21:27 +0200 Subject: [PATCH 014/137] ratbagd: add ratbagd_device_get_path() Add helper to retrieve the device path from outside of ratbagd-device.c. This will be needed for the non-object-manager based enumerators and signals introduced to org.freedesktop.ratbag1.Manager. Signed-off-by: David Herrmann --- src/ratbagd-device.c | 6 ++++++ src/ratbagd.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index aa2f8f65..7feb49fe 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -221,6 +221,12 @@ struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device) return mfree(device); } +const char *ratbagd_device_get_path(struct ratbagd_device *device) +{ + assert(device); + return device->path; +} + bool ratbagd_device_linked(struct ratbagd_device *device) { return device && rbnode_linked(&device->node); diff --git a/src/ratbagd.h b/src/ratbagd.h index 8a58898c..4075717f 100644 --- a/src/ratbagd.h +++ b/src/ratbagd.h @@ -64,6 +64,8 @@ int ratbagd_device_new(struct ratbagd_device **out, const char *name, struct ratbag_device *lib_device); struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device); +const char *ratbagd_device_get_path(struct ratbagd_device *device); + bool ratbagd_device_linked(struct ratbagd_device *device); void ratbagd_device_link(struct ratbagd_device *device); void ratbagd_device_unlink(struct ratbagd_device *device); From 65463b6efb2840b22281b565235785dc770002ca Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 13:22:13 +0200 Subject: [PATCH 015/137] ratbagd: add device iterator Add iterators for ratbagd_device objects. Signed-off-by: David Herrmann --- src/ratbagd-device.c | 26 +++++++++++++++++++++----- src/ratbagd.h | 7 +++++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 7feb49fe..20865c8d 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -347,11 +347,30 @@ struct ratbagd_device *ratbagd_device_lookup(struct ratbagd *ctx, return NULL; } +struct ratbagd_device *ratbagd_device_first(struct ratbagd *ctx) +{ + struct RBNode *node; + + assert(ctx); + + node = rbtree_first(&ctx->device_map); + return node ? ratbagd_device_from_node(node) : NULL; +} + +struct ratbagd_device *ratbagd_device_next(struct ratbagd_device *device) +{ + struct RBNode *node; + + assert(device); + + node = rbnode_next(&device->node); + return node ? ratbagd_device_from_node(node) : NULL; +} + int ratbagd_device_list(struct ratbagd *ctx, char ***paths) { struct ratbagd_device *device; char **devices, **pos; - RBNode *node; devices = calloc(ctx->n_devices + 1, sizeof(char *)); if (!devices) @@ -359,10 +378,7 @@ int ratbagd_device_list(struct ratbagd *ctx, char ***paths) pos = devices; - for (node = rbtree_first(&ctx->device_map); - node; - node = rbnode_next(node)) { - device = ratbagd_device_from_node(node); + RATBAGD_DEVICE_FOREACH(device, ctx) { *pos = strdup(device->path); if (!*pos) goto error; diff --git a/src/ratbagd.h b/src/ratbagd.h index 4075717f..43a7ac93 100644 --- a/src/ratbagd.h +++ b/src/ratbagd.h @@ -74,8 +74,15 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_device *, ratbagd_device_free); struct ratbagd_device *ratbagd_device_lookup(struct ratbagd *ctx, const char *name); +struct ratbagd_device *ratbagd_device_first(struct ratbagd *ctx); +struct ratbagd_device *ratbagd_device_next(struct ratbagd_device *device); int ratbagd_device_list(struct ratbagd *ctx, char ***paths); +#define RATBAGD_DEVICE_FOREACH(_device, _ctx) \ + for ((_device) = ratbagd_device_first(_ctx); \ + (_device); \ + (_device) = ratbagd_device_next(_device)) + /* * Context */ From e926212554336fbd1d1bbde765f3b8ba29596a57 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 13:25:05 +0200 Subject: [PATCH 016/137] ratbagd: remove ratbagd_device_list() This is no longer needed. Use the device-iterator in ratbagd.c directly and then drop ratbagd_device_list(). Signed-off-by: David Herrmann --- src/ratbagd-device.c | 29 ----------------------------- src/ratbagd.c | 27 ++++++++++++++++++++++++--- src/ratbagd.h | 1 - 3 files changed, 24 insertions(+), 33 deletions(-) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 20865c8d..07685a61 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -366,32 +366,3 @@ struct ratbagd_device *ratbagd_device_next(struct ratbagd_device *device) node = rbnode_next(&device->node); return node ? ratbagd_device_from_node(node) : NULL; } - -int ratbagd_device_list(struct ratbagd *ctx, char ***paths) -{ - struct ratbagd_device *device; - char **devices, **pos; - - devices = calloc(ctx->n_devices + 1, sizeof(char *)); - if (!devices) - return -ENOMEM; - - pos = devices; - - RATBAGD_DEVICE_FOREACH(device, ctx) { - *pos = strdup(device->path); - if (!*pos) - goto error; - ++pos; - } - - *pos = NULL; - *paths = devices; - return 1; - -error: - for (pos = devices; *pos; ++pos) - free(*pos); - free(devices); - return -ENOMEM; -} diff --git a/src/ratbagd.c b/src/ratbagd.c index 960b926d..29ca73c3 100644 --- a/src/ratbagd.c +++ b/src/ratbagd.c @@ -67,10 +67,31 @@ static int ratbagd_list_devices(sd_bus *bus, sd_bus_error *error) { struct ratbagd *ctx = userdata; - int r; + struct ratbagd_device *device; + char **devices, **pos; - r = ratbagd_device_list(ctx, paths); - return r < 0 ? r : 1; + devices = calloc(ctx->n_devices + 1, sizeof(char *)); + if (!devices) + return -ENOMEM; + + pos = devices; + + RATBAGD_DEVICE_FOREACH(device, ctx) { + *pos = strdup(ratbagd_device_get_path(device)); + if (!*pos) + goto error; + ++pos; + } + + *pos = NULL; + *paths = devices; + return 1; + +error: + for (pos = devices; *pos; ++pos) + free(*pos); + free(devices); + return -ENOMEM; } static void ratbagd_process_device(struct ratbagd *ctx, diff --git a/src/ratbagd.h b/src/ratbagd.h index 43a7ac93..50e96d85 100644 --- a/src/ratbagd.h +++ b/src/ratbagd.h @@ -76,7 +76,6 @@ struct ratbagd_device *ratbagd_device_lookup(struct ratbagd *ctx, const char *name); struct ratbagd_device *ratbagd_device_first(struct ratbagd *ctx); struct ratbagd_device *ratbagd_device_next(struct ratbagd_device *device); -int ratbagd_device_list(struct ratbagd *ctx, char ***paths); #define RATBAGD_DEVICE_FOREACH(_device, _ctx) \ for ((_device) = ratbagd_device_first(_ctx); \ From eca2203603acfabb187ada88d3cf598bd8d413d9 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 14:09:23 +0200 Subject: [PATCH 017/137] ratbagd: add manager interface Instead of relying on the cricket ObjectManager interface, use our own manager interface. This gets rid of ridiculous recursive behavior of the ObjectManager interface and instead allows us to control the behavior. Signed-off-by: David Herrmann --- src/ratbagd-device.c | 20 ---------------- src/ratbagd.c | 56 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 23 deletions(-) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 07685a61..5427651e 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -263,15 +263,6 @@ void ratbagd_device_link(struct ratbagd_device *device) rbtree_add(&device->ctx->device_map, parent, node, &device->node); ++device->ctx->n_devices; - /* send out object-manager notification */ - r = sd_bus_emit_object_added(device->ctx->bus, device->path); - if (r < 0) { - errno = -r; - fprintf(stderr, - "Cannot send device notification for '%s': %m\n", - device->name); - } - /* register profile interfaces */ r = asprintf(&prefix, "%s/profile", device->path); if (r >= 0) { @@ -299,23 +290,12 @@ void ratbagd_device_link(struct ratbagd_device *device) void ratbagd_device_unlink(struct ratbagd_device *device) { - int r; - if (!ratbagd_device_linked(device)) return; device->profile_enum_slot = sd_bus_slot_unref(device->profile_enum_slot); device->profile_vtable_slot = sd_bus_slot_unref(device->profile_vtable_slot); - /* send out object-manager notification */ - r = sd_bus_emit_object_removed(device->ctx->bus, device->path); - if (r < 0) { - errno = -r; - fprintf(stderr, - "Cannot send device notification for '%s': %m\n", - device->name); - } - /* unlink from context */ --device->ctx->n_devices; rbtree_remove(&device->ctx->device_map, &device->node); diff --git a/src/ratbagd.c b/src/ratbagd.c index 29ca73c3..6619e35f 100644 --- a/src/ratbagd.c +++ b/src/ratbagd.c @@ -94,6 +94,41 @@ error: return -ENOMEM; } +static int ratbagd_get_devices(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd *ctx = userdata; + struct ratbagd_device *device; + int r; + + r = sd_bus_message_open_container(reply, 'a', "o"); + if (r < 0) + return r; + + RATBAGD_DEVICE_FOREACH(device, ctx) { + r = sd_bus_message_append(reply, + "o", + ratbagd_device_get_path(device)); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +static const sd_bus_vtable ratbagd_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Devices", "ao", ratbagd_get_devices, 0, 0), + SD_BUS_SIGNAL("DeviceNew", "o", 0), + SD_BUS_SIGNAL("DeviceRemoved", "o", 0), + SD_BUS_VTABLE_END, +}; + static void ratbagd_process_device(struct ratbagd *ctx, struct udev_device *udevice) { @@ -120,6 +155,12 @@ static void ratbagd_process_device(struct ratbagd *ctx, if (streq_ptr("remove", udev_device_get_action(udevice))) { /* device was removed, unlink it and destroy our context */ if (device) { + (void) sd_bus_emit_signal(ctx->bus, + "/org/freedesktop/ratbag1", + "org.freedesktop.ratbag1.Manager", + "DeviceRemoved", + "o", + ratbagd_device_get_path(device)); ratbagd_device_unlink(device); ratbagd_device_free(device); } @@ -143,6 +184,12 @@ static void ratbagd_process_device(struct ratbagd *ctx, } ratbagd_device_link(device); + (void) sd_bus_emit_signal(ctx->bus, + "/org/freedesktop/ratbag1", + "org.freedesktop.ratbag1.Manager", + "DeviceNew", + "o", + ratbagd_device_get_path(device)); } } @@ -268,9 +315,12 @@ static int ratbagd_new(struct ratbagd **out) if (r < 0) return r; - r = sd_bus_add_object_manager(ctx->bus, - NULL, - "/org/freedesktop/ratbag1"); + r = sd_bus_add_object_vtable(ctx->bus, + NULL, + "/org/freedesktop/ratbag1", + "org.freedesktop.ratbag1.Manager", + ratbagd_vtable, + ctx); if (r < 0) return r; From cba28a97a0f1bc6d434c7658ebc22f9e8d545b8d Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 16:20:42 +0200 Subject: [PATCH 018/137] ratbagd: add ratbagd_device_get_name() New helper to return the name of a device. This will be required to build hierarchical paths in the sub-classes, like profiles. Signed-off-by: David Herrmann --- src/ratbagd-device.c | 6 ++++++ src/ratbagd.h | 1 + 2 files changed, 7 insertions(+) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 5427651e..6961c269 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -221,6 +221,12 @@ struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device) return mfree(device); } +const char *ratbagd_device_get_name(struct ratbagd_device *device) +{ + assert(device); + return device->name; +} + const char *ratbagd_device_get_path(struct ratbagd_device *device) { assert(device); diff --git a/src/ratbagd.h b/src/ratbagd.h index 50e96d85..6492b2fc 100644 --- a/src/ratbagd.h +++ b/src/ratbagd.h @@ -64,6 +64,7 @@ int ratbagd_device_new(struct ratbagd_device **out, const char *name, struct ratbag_device *lib_device); struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device); +const char *ratbagd_device_get_name(struct ratbagd_device *device); const char *ratbagd_device_get_path(struct ratbagd_device *device); bool ratbagd_device_linked(struct ratbagd_device *device); From 260df588566471f3e3e14ebc586fb71b213ee3fa Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 16:17:02 +0200 Subject: [PATCH 019/137] ratbagd: profile profile accessors Provide two new profile accessors that return the path and index of a profile. This also requires us to cache the dbus path in the profile itself. Signed-off-by: David Herrmann --- src/ratbagd-device.c | 5 ++++- src/ratbagd-profile.c | 26 ++++++++++++++++++++++++++ src/ratbagd.h | 3 +++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 6961c269..99e16362 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -185,7 +185,10 @@ int ratbagd_device_new(struct ratbagd_device **out, if (!profile) continue; - r = ratbagd_profile_new(&device->profiles[i], profile, i); + r = ratbagd_profile_new(&device->profiles[i], + device, + profile, + i); if (r < 0) { errno = -r; fprintf(stderr, diff --git a/src/ratbagd-profile.c b/src/ratbagd-profile.c index ad7a9d24..69b5370c 100644 --- a/src/ratbagd-profile.c +++ b/src/ratbagd-profile.c @@ -37,6 +37,7 @@ struct ratbagd_profile { struct ratbag_profile *lib_profile; unsigned int index; + char *path; }; const sd_bus_vtable ratbagd_profile_vtable[] = { @@ -46,10 +47,13 @@ const sd_bus_vtable ratbagd_profile_vtable[] = { }; int ratbagd_profile_new(struct ratbagd_profile **out, + struct ratbagd_device *device, struct ratbag_profile *lib_profile, unsigned int index) { _cleanup_(ratbagd_profile_freep) struct ratbagd_profile *profile = NULL; + char index_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1]; + int r; assert(out); assert(lib_profile); @@ -61,6 +65,14 @@ int ratbagd_profile_new(struct ratbagd_profile **out, profile->lib_profile = lib_profile; profile->index = index; + sprintf(index_buffer, "%u", index); + r = sd_bus_path_encode_many(&profile->path, + "/org/freedesktop/ratbag1/profile/%/%", + ratbagd_device_get_name(device), + index_buffer); + if (r < 0) + return r; + *out = profile; profile = NULL; return 0; @@ -71,9 +83,23 @@ struct ratbagd_profile *ratbagd_profile_free(struct ratbagd_profile *profile) if (!profile) return NULL; + profile->path = mfree(profile->path); + /* we cannot assume the profile is gone, so set NULL explicitly */ ratbag_profile_unref(profile->lib_profile); profile->lib_profile = NULL; return mfree(profile); } + +const char *ratbagd_profile_get_path(struct ratbagd_profile *profile) +{ + assert(profile); + return profile->path; +} + +bool ratbagd_profile_is_active(struct ratbagd_profile *profile) +{ + assert(profile); + return ratbag_profile_is_active(profile->lib_profile) != 0; +} diff --git a/src/ratbagd.h b/src/ratbagd.h index 6492b2fc..4039cad6 100644 --- a/src/ratbagd.h +++ b/src/ratbagd.h @@ -47,9 +47,12 @@ struct ratbagd_profile; extern const sd_bus_vtable ratbagd_profile_vtable[]; int ratbagd_profile_new(struct ratbagd_profile **out, + struct ratbagd_device *device, struct ratbag_profile *lib_profile, unsigned int index); 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); DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_profile *, ratbagd_profile_free); From 2780e6f3d753a51b3112f22227fa7f138277de78 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 16:18:33 +0200 Subject: [PATCH 020/137] ratbagd: simplify profile DBus paths Refrain from hierarchical paths and instead use object prefixes with unique paths each. This avoids several nasty DBus-enforced behaviors regarding deep hierarchies. Furthermore, it keeps the names shorter, which is always a nice side-effect. Signed-off-by: David Herrmann --- src/ratbagd-device.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 99e16362..4756c265 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -64,7 +64,7 @@ static int ratbagd_device_find_profile(sd_bus *bus, int r; r = sd_bus_path_decode_many(path, - "/org/freedesktop/ratbag1/device/%/profile/%", + "/org/freedesktop/ratbag1/profile/%/%", NULL, &name); if (r <= 0) @@ -88,22 +88,21 @@ static int ratbagd_device_list_profiles(sd_bus *bus, sd_bus_error *error) { struct ratbagd_device *device = userdata; - char index_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1]; + struct ratbagd_profile *profile; char **profiles; unsigned int i; - int r; profiles = calloc(device->n_profiles + 1, sizeof(char *)); if (!profiles) return -ENOMEM; for (i = 0; i < device->n_profiles; ++i) { - sprintf(index_buffer, "%u", i); - r = sd_bus_path_encode_many(&profiles[i], - "/org/freedesktop/ratbag1/device/%/profile/%", - device->name, - index_buffer); - if (r < 0) + profile = device->profiles[i]; + if (!profile) + continue; + + profiles[i] = strdup(ratbagd_profile_get_path(profile)); + if (!profiles[i]) goto error; } @@ -115,7 +114,7 @@ error: for (i = 0; profiles[i]; ++i) free(profiles[i]); free(profiles); - return r; + return -ENOMEM; } static int ratbagd_device_get_description(sd_bus *bus, @@ -273,7 +272,9 @@ void ratbagd_device_link(struct ratbagd_device *device) ++device->ctx->n_devices; /* register profile interfaces */ - r = asprintf(&prefix, "%s/profile", device->path); + r = sd_bus_path_encode_many(&prefix, + "/org/freedesktop/ratbag1/profile/%", + device->name); if (r >= 0) { r = sd_bus_add_fallback_vtable(device->ctx->bus, &device->profile_vtable_slot, From dc37d3bf624b439911a100ec3c6ecdb9fddadd68 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 16:21:35 +0200 Subject: [PATCH 021/137] ratbagd: ignore NULL profiles Never return information about non-existant profiles. Just skip NULL profiles silently, when iterating. Signed-off-by: David Herrmann --- src/ratbagd-device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 4756c265..b9c8eb2a 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -74,7 +74,7 @@ static int ratbagd_device_find_profile(sd_bus *bus, if (r < 0) return 0; - if (index >= device->n_profiles) + if (index >= device->n_profiles || !device->profiles[index]) return 0; *found = device->profiles[index]; From 0a9c2824ba8ae7d733ee2e27bf3012f03459c221 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 16:22:05 +0200 Subject: [PATCH 022/137] ratbagd: expose profile information Expose a list of profiles, including a tag for the active profile, from within each ratbagd device via DBus. Signed-off-by: David Herrmann --- src/ratbagd-device.c | 60 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index b9c8eb2a..167f93b2 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -135,10 +135,70 @@ static int ratbagd_device_get_description(sd_bus *bus, return sd_bus_message_append(reply, "s", description); } +static int ratbagd_device_get_profiles(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_device *device = userdata; + struct ratbagd_profile *profile; + unsigned int i; + int r; + + r = sd_bus_message_open_container(reply, 'a', "o"); + if (r < 0) + return r; + + for (i = 0; i < device->n_profiles; ++i) { + profile = device->profiles[i]; + if (!profile) + continue; + + r = sd_bus_message_append(reply, + "o", + ratbagd_profile_get_path(profile)); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +static int ratbagd_device_get_active_profile(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_device *device = userdata; + struct ratbagd_profile *profile; + unsigned int i; + + for (i = 0; i < device->n_profiles; ++i) { + profile = device->profiles[i]; + if (!profile) + continue; + if (!ratbagd_profile_is_active(profile)) + continue; + + return sd_bus_message_append(reply, "o", + ratbagd_profile_get_path(profile)); + } + + return -ENODATA; +} + const sd_bus_vtable ratbagd_device_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct ratbagd_device, name), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Description", "s", ratbagd_device_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Profiles", "ao", ratbagd_device_get_profiles, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ActiveProfile", "o", ratbagd_device_get_active_profile, 0, 0), SD_BUS_VTABLE_END, }; From ff8f391e9197c24aa21be8483ea3cdba0ed50464 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 16:22:53 +0200 Subject: [PATCH 023/137] ratbagctl: implement list-devices and show-device Two new verbs for ratbagctl: - list-devices: list all available devices - show-device: show detailed information about a single device Signed-off-by: David Herrmann --- src/ratbagctl.c | 333 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 327 insertions(+), 6 deletions(-) diff --git a/src/ratbagctl.c b/src/ratbagctl.c index 929c174c..5e775416 100644 --- a/src/ratbagctl.c +++ b/src/ratbagctl.c @@ -28,48 +28,369 @@ #include #include #include +#include #include "shared-macro.h" struct ratbagctl { - int unused; + sd_bus *bus; }; static int verb_help(struct ratbagctl *ctl, int argc, char **argv); +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message *, sd_bus_message_unref); + static struct ratbagctl *ratbagctl_free(struct ratbagctl *ctl) { if (!ctl) return NULL; - free(ctl); + ctl->bus = sd_bus_unref(ctl->bus); - return NULL; + return mfree(ctl); } +DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagctl *, ratbagctl_free); + static int ratbagctl_new(struct ratbagctl **out) { - struct ratbagctl *ctl; + _cleanup_(ratbagctl_freep) struct ratbagctl *ctl = NULL; + int r; ctl = calloc(1, sizeof(*ctl)); if (!ctl) return -ENOMEM; + r = sd_bus_open_system(&ctl->bus); + if (r < 0) + return r; + *out = ctl; + ctl = NULL; return 0; } -static int verb_list(struct ratbagctl *ctl, int argc, char **argv) +static int list_devices_show(struct ratbagctl *ctl, const char *path) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + const char *prop_id = NULL, *prop_description = NULL; + int r; + + r = sd_bus_call_method(ctl->bus, + "org.freedesktop.ratbag1", + path, + "org.freedesktop.DBus.Properties", + "GetAll", + &error, + &reply, + "s", + "org.freedesktop.ratbag1.Device"); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(reply, 'a', "{sv}"); + if (r < 0) + return r; + + while ((r = sd_bus_message_enter_container(reply, 'e', "sv")) > 0) { + const char *property; + + r = sd_bus_message_read_basic(reply, 's', &property); + if (r < 0) + return r; + + if (!strcmp(property, "Id")) { + r = sd_bus_message_read(reply, "v", "s", + &prop_id); + } else if (!strcmp(property, "Description")) { + r = sd_bus_message_read(reply, "v", "s", + &prop_description); + } else { + r = sd_bus_message_skip(reply, "v"); + } + if (r < 0) + return r; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return r; + } + if (r < 0) + return r; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return r; + + printf("%10s %-32s\n", prop_id, prop_description); return 0; } +static int list_devices_all(struct ratbagctl *ctl) +{ + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + unsigned int k = 0; + const char *path; + int r; + + r = sd_bus_call_method(ctl->bus, + "org.freedesktop.ratbag1", + "/org/freedesktop/ratbag1", + "org.freedesktop.DBus.Properties", + "Get", + &error, + &reply, + "ss", + "org.freedesktop.ratbag1.Manager", + "Devices"); + if (r < 0) + goto exit; + + r = sd_bus_message_enter_container(reply, 'v', "ao"); + if (r < 0) + goto exit; + + r = sd_bus_message_enter_container(reply, 'a', "o"); + if (r < 0) + goto exit; + + printf("%10s %-32s\n", "DEVICE", "DESCRIPTION"); + + while ((r = sd_bus_message_read_basic(reply, 'o', &path)) > 0) { + r = list_devices_show(ctl, path); + if (r < 0) + goto exit; + + ++k; + } + if (r < 0) + goto exit; + + printf("\n%u device%s listed.\n", k, k > 1 ? "s" : ""); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto exit; + + r = sd_bus_message_exit_container(reply); +exit: + if (r < 0) + fprintf(stderr, "Cannot list devices: %s\n", + error.message ? : "Parser error"); + return r; +} + +static int verb_list_devices(struct ratbagctl *ctl, int argc, char **argv) +{ + static const struct option options[] = { + {}, + }; + int c; + + while ((c = getopt_long(argc, argv, "+", options, NULL)) >= 0) { + switch (c) { + default: + return -EINVAL; + } + } + + if (argv[optind]) { + fprintf(stderr, "Command does not take arguments\n"); + return -EINVAL; + } + + return list_devices_all(ctl); +} + +static int show_device_get_profile_index(struct ratbagctl *ctl, + const char *path, + unsigned int *out_index) +{ + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + int r; + + r = sd_bus_call_method(ctl->bus, + "org.freedesktop.ratbag1", + path, + "org.freedesktop.DBus.Properties", + "Get", + &error, + &reply, + "ss", + "org.freedesktop.ratbag1.Profile", + "Index"); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(reply, 'v', "u"); + if (r < 0) + return r; + + r = sd_bus_message_read_basic(reply, 'u', out_index); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return r; + + return 0; +} + +static int show_device_print(struct ratbagctl *ctl, const char *device) +{ + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + unsigned int prop_min_index = 0, prop_max_index = 0; + unsigned int prop_active_profile = 0; + const char *prop_id = NULL, *prop_description = NULL; + _cleanup_(freep) char *path = NULL; + int r; + + r = sd_bus_path_encode_many(&path, + "/org/freedesktop/ratbag1/device/%", + device); + if (r < 0) + goto exit; + + r = sd_bus_call_method(ctl->bus, + "org.freedesktop.ratbag1", + path, + "org.freedesktop.DBus.Properties", + "GetAll", + &error, + &reply, + "s", + "org.freedesktop.ratbag1.Device"); + if (r < 0) + goto exit; + + r = sd_bus_message_enter_container(reply, 'a', "{sv}"); + if (r < 0) + goto exit; + + while ((r = sd_bus_message_enter_container(reply, 'e', "sv")) > 0) { + const char *property, *profile; + + r = sd_bus_message_read_basic(reply, 's', &property); + if (r < 0) + goto exit; + + if (!strcmp(property, "Id")) { + r = sd_bus_message_read(reply, "v", "s", + &prop_id); + } else if (!strcmp(property, "Description")) { + r = sd_bus_message_read(reply, "v", "s", + &prop_description); + } else if (!strcmp(property, "Profiles")) { + r = sd_bus_message_enter_container(reply, 'v', "ao"); + if (r < 0) + goto exit; + + r = sd_bus_message_enter_container(reply, 'a', "o"); + if (r < 0) + goto exit; + + while ((r = sd_bus_message_read_basic(reply, + 'o', + &profile)) > 0) { + unsigned int index; + + r = show_device_get_profile_index(ctl, + profile, + &index); + if (r < 0) + goto exit; + + if (index < prop_min_index) + prop_min_index = index; + if (index >= prop_max_index) + prop_max_index = index + 1; + } + if (r < 0) + goto exit; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto exit; + + r = sd_bus_message_exit_container(reply); + } else if (!strcmp(property, "ActiveProfile")) { + r = sd_bus_message_read(reply, "v", "o", &profile); + if (r < 0) + goto exit; + + r = show_device_get_profile_index(ctl, + profile, + &prop_active_profile); + } else { + r = sd_bus_message_skip(reply, "v"); + } + if (r < 0) + goto exit; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto exit; + } + if (r < 0) + goto exit; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto exit; + + printf("%s - %s\n", prop_id, prop_description); + if (prop_min_index == prop_max_index) + printf("\t Profiles:\n"); + else if (prop_min_index + 1 == prop_max_index) + printf("\t Profiles: %u\n", prop_min_index); + else + printf("\t Profiles: %u - %u\n", + prop_min_index, prop_max_index - 1); + printf("\t Active Profile: %u\n", prop_active_profile); + +exit: + if (r < 0) + fprintf(stderr, "Cannot show device: %s\n", + error.message ? : "Parser error"); + return r; +} + +static int verb_show_device(struct ratbagctl *ctl, int argc, char **argv) +{ + static const struct option options[] = { + {}, + }; + const char *device; + int c; + + while ((c = getopt_long(argc, argv, "+", options, NULL)) >= 0) { + switch (c) { + default: + return -EINVAL; + } + } + + device = argv[optind]; + if (!device) { + fprintf(stderr, "No device specified\n"); + return -EINVAL; + } + + return show_device_print(ctl, device); +} + static const struct { const char *verb; const char *help; int (*dispatch) (struct ratbagctl *ctl, int argc, char **argv); void (*long_help) (void); } verbs[] = { - { "list", "List available configurable mice", verb_list, NULL }, + { "list-devices", "List available configurable mice", verb_list_devices, NULL }, + { "show-device", "Show device information", verb_show_device, NULL }, { "help", "Show help for a command", verb_help, NULL }, {}, }; From e189dc3b1f7fe9afddae0b232fc1b78df9e65435 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 16:33:30 +0200 Subject: [PATCH 024/137] ratbagd: never return ENODATA for Get() We should always provide valid data if requested via Get(). Unfortunately, DBus still does not include 'maybe' types, so we just return something that is clearly invalid data. Signed-off-by: David Herrmann --- src/ratbagctl.c | 14 ++++++++++++-- src/ratbagd-device.c | 3 ++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/ratbagctl.c b/src/ratbagctl.c index 5e775416..3fd3c3b2 100644 --- a/src/ratbagctl.c +++ b/src/ratbagctl.c @@ -211,6 +211,11 @@ static int show_device_get_profile_index(struct ratbagctl *ctl, _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; int r; + if (streq(path, "/")) { + *out_index = -1; + return 0; + } + r = sd_bus_call_method(ctl->bus, "org.freedesktop.ratbag1", path, @@ -244,7 +249,7 @@ static int show_device_print(struct ratbagctl *ctl, const char *device) _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; unsigned int prop_min_index = 0, prop_max_index = 0; - unsigned int prop_active_profile = 0; + unsigned int prop_active_profile = -1; const char *prop_id = NULL, *prop_description = NULL; _cleanup_(freep) char *path = NULL; int r; @@ -343,6 +348,7 @@ static int show_device_print(struct ratbagctl *ctl, const char *device) goto exit; printf("%s - %s\n", prop_id, prop_description); + if (prop_min_index == prop_max_index) printf("\t Profiles:\n"); else if (prop_min_index + 1 == prop_max_index) @@ -350,7 +356,11 @@ static int show_device_print(struct ratbagctl *ctl, const char *device) else printf("\t Profiles: %u - %u\n", prop_min_index, prop_max_index - 1); - printf("\t Active Profile: %u\n", prop_active_profile); + + if (prop_active_profile == (unsigned int)-1) + printf("\t Active Profile: (unknown)\n"); + else + printf("\t Active Profile: %u\n", prop_active_profile); exit: if (r < 0) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 167f93b2..0702e312 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -190,7 +190,8 @@ static int ratbagd_device_get_active_profile(sd_bus *bus, ratbagd_profile_get_path(profile)); } - return -ENODATA; + /* Eww, we want 'maybe' types here! */ + return sd_bus_message_append(reply, "o", "/"); } const sd_bus_vtable ratbagd_device_vtable[] = { From c24ca68d633ed69718c9ab4e8b91c23300c28a02 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 16:34:32 +0200 Subject: [PATCH 025/137] ratbagd: expose 'DefaultProfile' Add a new property that exposes the default profile. Signed-off-by: David Herrmann --- src/ratbagd-device.c | 28 ++++++++++++++++++++++++++++ src/ratbagd-profile.c | 6 ++++++ src/ratbagd.h | 1 + 3 files changed, 35 insertions(+) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 0702e312..0f8a4420 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -194,12 +194,40 @@ static int ratbagd_device_get_active_profile(sd_bus *bus, return sd_bus_message_append(reply, "o", "/"); } +static int ratbagd_device_get_default_profile(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_device *device = userdata; + struct ratbagd_profile *profile; + unsigned int i; + + for (i = 0; i < device->n_profiles; ++i) { + profile = device->profiles[i]; + if (!profile) + continue; + if (!ratbagd_profile_is_default(profile)) + continue; + + return sd_bus_message_append(reply, "o", + ratbagd_profile_get_path(profile)); + } + + /* Eww, we want 'maybe' types here! */ + return sd_bus_message_append(reply, "o", "/"); +} + const sd_bus_vtable ratbagd_device_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct ratbagd_device, name), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Description", "s", ratbagd_device_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Profiles", "ao", ratbagd_device_get_profiles, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ActiveProfile", "o", ratbagd_device_get_active_profile, 0, 0), + SD_BUS_PROPERTY("DefaultProfile", "o", ratbagd_device_get_default_profile, 0, 0), SD_BUS_VTABLE_END, }; diff --git a/src/ratbagd-profile.c b/src/ratbagd-profile.c index 69b5370c..7b557b27 100644 --- a/src/ratbagd-profile.c +++ b/src/ratbagd-profile.c @@ -103,3 +103,9 @@ bool ratbagd_profile_is_active(struct ratbagd_profile *profile) assert(profile); return ratbag_profile_is_active(profile->lib_profile) != 0; } + +bool ratbagd_profile_is_default(struct ratbagd_profile *profile) +{ + assert(profile); + return ratbag_profile_is_default(profile->lib_profile) != 0; +} diff --git a/src/ratbagd.h b/src/ratbagd.h index 4039cad6..e804d336 100644 --- a/src/ratbagd.h +++ b/src/ratbagd.h @@ -53,6 +53,7 @@ int ratbagd_profile_new(struct ratbagd_profile **out, 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); DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_profile *, ratbagd_profile_free); From eeb8788413800b3cd669c409ae59ffbb3f738949 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 16:35:00 +0200 Subject: [PATCH 026/137] ratbagctl: print the default profile Include the default profile in 'show-device' output. Signed-off-by: David Herrmann --- src/ratbagctl.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/ratbagctl.c b/src/ratbagctl.c index 3fd3c3b2..29db8c1e 100644 --- a/src/ratbagctl.c +++ b/src/ratbagctl.c @@ -249,7 +249,7 @@ static int show_device_print(struct ratbagctl *ctl, const char *device) _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; unsigned int prop_min_index = 0, prop_max_index = 0; - unsigned int prop_active_profile = -1; + unsigned int prop_active_profile = -1, prop_default_profile = -1; const char *prop_id = NULL, *prop_description = NULL; _cleanup_(freep) char *path = NULL; int r; @@ -330,6 +330,14 @@ static int show_device_print(struct ratbagctl *ctl, const char *device) r = show_device_get_profile_index(ctl, profile, &prop_active_profile); + } else if (!strcmp(property, "DefaultProfile")) { + r = sd_bus_message_read(reply, "v", "o", &profile); + if (r < 0) + goto exit; + + r = show_device_get_profile_index(ctl, + profile, + &prop_default_profile); } else { r = sd_bus_message_skip(reply, "v"); } @@ -362,6 +370,11 @@ static int show_device_print(struct ratbagctl *ctl, const char *device) else printf("\t Active Profile: %u\n", prop_active_profile); + if (prop_default_profile == (unsigned int)-1) + printf("\tDefault Profile: (unknown)\n"); + else + printf("\tDefault Profile: %u\n", prop_default_profile); + exit: if (r < 0) fprintf(stderr, "Cannot show device: %s\n", From 1a677c0b1dd436b02c8d67e609e29d277a3a9763 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 18:53:54 +0200 Subject: [PATCH 027/137] ratbagd: add DBus methods to retrieve object paths Add two new helpers to query ratbagd for the object-paths of a specific object: GetDeviceByName: Return device given a device name GetProfileByIndex: Return a profile given a profile index Signed-off-by: David Herrmann --- src/ratbagd-device.c | 22 ++++++++++++++++++++++ src/ratbagd.c | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 0f8a4420..703d50cd 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -221,6 +221,27 @@ static int ratbagd_device_get_default_profile(sd_bus *bus, return sd_bus_message_append(reply, "o", "/"); } +static int ratbagd_device_get_profile_by_index(sd_bus_message *m, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_device *device = userdata; + struct ratbagd_profile *profile; + unsigned int index; + int r; + + r = sd_bus_message_read(m, "u", &index); + if (r < 0) + return r; + + if (index >= device->n_profiles || !device->profiles[index]) + return -ENXIO; + + profile = device->profiles[index]; + return sd_bus_reply_method_return(m, "o", + ratbagd_profile_get_path(profile)); +} + const sd_bus_vtable ratbagd_device_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct ratbagd_device, name), SD_BUS_VTABLE_PROPERTY_CONST), @@ -228,6 +249,7 @@ const sd_bus_vtable ratbagd_device_vtable[] = { SD_BUS_PROPERTY("Profiles", "ao", ratbagd_device_get_profiles, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ActiveProfile", "o", ratbagd_device_get_active_profile, 0, 0), SD_BUS_PROPERTY("DefaultProfile", "o", ratbagd_device_get_default_profile, 0, 0), + SD_BUS_METHOD("GetProfileByIndex", "u", "o", ratbagd_device_get_profile_by_index, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END, }; diff --git a/src/ratbagd.c b/src/ratbagd.c index 6619e35f..4013c50a 100644 --- a/src/ratbagd.c +++ b/src/ratbagd.c @@ -121,11 +121,33 @@ static int ratbagd_get_devices(sd_bus *bus, return sd_bus_message_close_container(reply); } +static int ratbagd_get_device_by_name(sd_bus_message *m, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd *ctx = userdata; + struct ratbagd_device *device; + const char *name; + int r; + + r = sd_bus_message_read(m, "s", &name); + if (r < 0) + return r; + + device = ratbagd_device_lookup(ctx, name); + if (!device) + return -ENXIO; + + return sd_bus_reply_method_return(m, "o", + ratbagd_device_get_path(device)); +} + static const sd_bus_vtable ratbagd_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Devices", "ao", ratbagd_get_devices, 0, 0), SD_BUS_SIGNAL("DeviceNew", "o", 0), SD_BUS_SIGNAL("DeviceRemoved", "o", 0), + SD_BUS_METHOD("GetDeviceByName", "s", "o", ratbagd_get_device_by_name, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END, }; From 765fd1565a65fe31a6f7cb520eb98f71d7e3f214 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 18:55:03 +0200 Subject: [PATCH 028/137] ratbagd: expose resolutions on the bus Add a new property to profiles that exposes resolutions on the bus. We simply expose a dictionary entry for each resolution, hence, we can easily extend it in the future. However, we avoid the full overhead of real dbus objects, as there is no real need for it. Signed-off-by: David Herrmann --- src/ratbagd-profile.c | 131 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/src/ratbagd-profile.c b/src/ratbagd-profile.c index 7b557b27..4688f967 100644 --- a/src/ratbagd-profile.c +++ b/src/ratbagd-profile.c @@ -40,9 +40,140 @@ struct ratbagd_profile { char *path; }; +static int ratbagd_profile_get_resolutions(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_profile *profile = userdata; + unsigned int i, n_resolutions; + int r; + + r = sd_bus_message_open_container(reply, 'a', "a{sv}"); + 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); + 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); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +static int ratbagd_profile_get_active_resolution(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_profile *profile = userdata; + unsigned int i, n_resolutions, k = 0; + + n_resolutions = ratbag_profile_get_num_resolutions(profile->lib_profile); + for (i = 0; i < n_resolutions; ++i) { + struct ratbag_resolution *resolution; + + resolution = ratbag_profile_get_resolution(profile->lib_profile, i); + if (!resolution) + continue; + if (!ratbag_resolution_is_active(resolution)) { + ++k; + continue; + } + + return sd_bus_message_append(reply, "u", k); + } + + return sd_bus_message_append(reply, "u", (unsigned int)-1); +} + +static int ratbagd_profile_get_default_resolution(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_profile *profile = userdata; + unsigned int i, n_resolutions, k = 0; + + n_resolutions = ratbag_profile_get_num_resolutions(profile->lib_profile); + for (i = 0; i < n_resolutions; ++i) { + struct ratbag_resolution *resolution; + + resolution = ratbag_profile_get_resolution(profile->lib_profile, i); + if (!resolution) + continue; + if (!ratbag_resolution_is_default(resolution)) { + ++k; + continue; + } + + return sd_bus_message_append(reply, "u", k); + } + + return sd_bus_message_append(reply, "u", (unsigned int)-1); +} + 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("ActiveResolution", "u", ratbagd_profile_get_active_resolution, 0, 0), + SD_BUS_PROPERTY("DefaultResolution", "u", ratbagd_profile_get_default_resolution, 0, 0), SD_BUS_VTABLE_END, }; From fbffe241e61bffcdb3a49847792628670dce0a8f Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 18:56:25 +0200 Subject: [PATCH 029/137] ratbagctl: add show-profile verb New verb: show-profile This simply prints a profile of a given device by querying ratbagd for all information on the selected profile. Signed-off-by: David Herrmann --- src/ratbagctl.c | 357 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 357 insertions(+) diff --git a/src/ratbagctl.c b/src/ratbagctl.c index 29db8c1e..44f856bb 100644 --- a/src/ratbagctl.c +++ b/src/ratbagctl.c @@ -406,6 +406,362 @@ static int verb_show_device(struct ratbagctl *ctl, int argc, char **argv) return show_device_print(ctl, device); } +static int get_profile_path(struct ratbagctl *ctl, + const char *device_name, + const char *profile_name, + char **out_path, + sd_bus_error *error) +{ + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply2 = NULL; + const char *device_path = NULL, *profile_path = NULL; + unsigned int profile_index; + char *path; + int r; + + if (device_name) { + r = sd_bus_call_method(ctl->bus, + "org.freedesktop.ratbag1", + "/org/freedesktop/ratbag1", + "org.freedesktop.ratbag1.Manager", + "GetDeviceByName", + error, + &reply, + "s", + device_name); + if (r < 0) + return r; + + r = sd_bus_message_read(reply, "o", &device_path); + if (r < 0) + return r; + } else { + r = sd_bus_call_method(ctl->bus, + "org.freedesktop.ratbag1", + "/org/freedesktop/ratbag1", + "org.freedesktop.DBus.Properties", + "Get", + error, + &reply, + "ss", + "org.freedesktop.ratbag1.Manager", + "Devices"); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(reply, 'v', "ao"); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(reply, 'a', "o"); + if (r < 0) + return r; + + while ((r = sd_bus_message_read_basic(reply, 'o', &path)) > 0) { + if (!device_path) + device_path = path; + } + if (r < 0) + return r; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return r; + + if (!device_path) + return -ENXIO; + } + + assert(device_path); + + if (profile_name) { + r = safe_atou(profile_name, &profile_index); + if (r < 0) + return -ENXIO; + + r = sd_bus_call_method(ctl->bus, + "org.freedesktop.ratbag1", + device_path, + "org.freedesktop.ratbag1.Device", + "GetProfileByIndex", + error, + &reply2, + "u", + profile_index); + if (r < 0) + return r; + + r = sd_bus_message_read(reply2, "o", &profile_path); + if (r < 0) + return r; + } else { + r = sd_bus_call_method(ctl->bus, + "org.freedesktop.ratbag1", + device_path, + "org.freedesktop.DBus.Properties", + "Get", + error, + &reply2, + "ss", + "org.freedesktop.ratbag1.Device", + "ActiveProfile"); + if (r < 0) + return r; + + r = sd_bus_message_read(reply2, "v", "o", &profile_path); + if (r < 0) + return r; + + if (streq(profile_path, "/")) { + reply2 = sd_bus_message_unref(reply2); + + r = sd_bus_call_method(ctl->bus, + "org.freedesktop.ratbag1", + device_path, + "org.freedesktop.DBus.Properties", + "Get", + error, + &reply2, + "ss", + "org.freedesktop.ratbag1.Device", + "DefaultProfile"); + if (r < 0) + return r; + + r = sd_bus_message_read(reply2, "v", "o", &profile_path); + if (r < 0) + return r; + + if (streq(profile_path, "/")) + return -ENXIO; + } + } + + assert(profile_path); + + path = strdup(profile_path); + if (!path) + return -ENOMEM; + + *out_path = path; + return 0; +} + +static int show_profile_print_resolutions(struct ratbagctl *ctl, + sd_bus_message *m, + unsigned int active_resolution, + unsigned int default_resolution) +{ + unsigned int k = 0; + int r; + + r = sd_bus_message_enter_container(m, 'v', "aa{sv}"); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(m, 'a', "a{sv}"); + if (r < 0) + return r; + + while ((r = sd_bus_message_enter_container(m, 'a', "{sv}")) > 0) { + unsigned int dpi = -1, dpi_x = -1, dpi_y = -1; + unsigned int report_rate = -1; + const char *key; + + while ((r = sd_bus_message_enter_container(m, 'e', "sv")) > 0) { + r = sd_bus_message_read_basic(m, 's', &key); + if (r < 0) + return r; + + if (!strcmp(key, "dpi")) { + r = sd_bus_message_read(m, "v", "u", &dpi); + } else if (!strcmp(key, "dpi-x")) { + r = sd_bus_message_read(m, "v", "u", &dpi_x); + } else if (!strcmp(key, "dpi-y")) { + r = sd_bus_message_read(m, "v", "u", &dpi_y); + } else if (!strcmp(key, "report-rate")) { + r = sd_bus_message_read(m, "v", "u", &report_rate); + } else { + r = sd_bus_message_skip(m, "v"); + } + if (r < 0) + return r; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + } + if (r < 0) + return r; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + if (dpi != (unsigned int)-1) { + dpi_x = dpi; + dpi_y = dpi; + } + + if (dpi_x != (unsigned int)-1 && + dpi_y != (unsigned int)-1 && + report_rate != (unsigned int)-1) { + printf("%s%5u x %-5u dpi @ %5u Hz%s%s\n", + (k != 0) ? "\t\t\t " : "", + dpi_x, dpi_y, report_rate, + (k == active_resolution) ? " (active)" : "", + (k == default_resolution) ? " (default)" : ""); + } + + ++k; + } + if (r < 0) + return r; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + if (k == 0) + printf("\n"); + + return 0; +} + +static int show_profile_print(struct ratbagctl *ctl, + const char *device, + const char *profile) +{ + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(freep) char *path = NULL; + unsigned int prop_index = -1, prop_active_resolution = -1; + unsigned int prop_default_resolution = -1; + int r; + + r = get_profile_path(ctl, device, profile, &path, &error); + if (r < 0) + goto exit; + + r = sd_bus_call_method(ctl->bus, + "org.freedesktop.ratbag1", + path, + "org.freedesktop.DBus.Properties", + "GetAll", + &error, + &reply, + "s", + "org.freedesktop.ratbag1.Profile"); + if (r < 0) + goto exit; + + r = sd_bus_message_enter_container(reply, 'a', "{sv}"); + if (r < 0) + goto exit; + + while ((r = sd_bus_message_enter_container(reply, 'e', "sv")) > 0) { + const char *property; + + r = sd_bus_message_read_basic(reply, 's', &property); + if (r < 0) + goto exit; + + if (!strcmp(property, "Index")) { + r = sd_bus_message_read(reply, "v", "u", + &prop_index); + } else if (!strcmp(property, "ActiveResolution")) { + r = sd_bus_message_read(reply, "v", "u", + &prop_active_resolution); + } else if (!strcmp(property, "DefaultResolution")) { + r = sd_bus_message_read(reply, "v", "u", + &prop_default_resolution); + } else { + r = sd_bus_message_skip(reply, "v"); + } + if (r < 0) + goto exit; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto exit; + } + if (r < 0) + goto exit; + + r = sd_bus_message_rewind(reply, 0); + if (r < 0) + goto exit; + + printf("profile-%u\n", prop_index); + + printf("\t Index: %u\n", prop_index); + + printf("\t Resolutions: "); + while ((r = sd_bus_message_enter_container(reply, 'e', "sv")) > 0) { + const char *property; + + r = sd_bus_message_read_basic(reply, 's', &property); + if (r < 0) + goto exit; + + if (!strcmp(property, "Resolutions")) { + r = show_profile_print_resolutions(ctl, + reply, + prop_active_resolution, + prop_default_resolution); + } else { + r = sd_bus_message_skip(reply, "v"); + } + if (r < 0) + goto exit; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto exit; + } + if (r < 0) + goto exit; + + r = sd_bus_message_exit_container(reply); +exit: + if (r < 0) + fprintf(stderr, "Cannot show device: %s\n", + error.message ? : "Parser error"); + return r; +} + +static int verb_show_profile(struct ratbagctl *ctl, int argc, char **argv) +{ + static const struct option options[] = { + { "device", required_argument, NULL, 'd' }, + {}, + }; + const char *device = NULL, *profile = NULL; + int c; + + while ((c = getopt_long(argc, argv, "+d:", options, NULL)) >= 0) { + switch (c) { + case 'd': + device = optarg; + break; + default: + return -EINVAL; + } + } + + profile = argv[optind]; + + return show_profile_print(ctl, device, profile); +} + static const struct { const char *verb; const char *help; @@ -414,6 +770,7 @@ static const struct { } verbs[] = { { "list-devices", "List available configurable mice", verb_list_devices, NULL }, { "show-device", "Show device information", verb_show_device, NULL }, + { "show-profile", "Show profile information", verb_show_profile, NULL }, { "help", "Show help for a command", verb_help, NULL }, {}, }; From 85a045c5384d17c978af92ec47f722e3f4ab0e4a Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 18:57:42 +0200 Subject: [PATCH 030/137] ratbagctl: move get_profile_path() Move get_profile_path() up to make it available to other verbs as well. Signed-off-by: David Herrmann --- src/ratbagctl.c | 290 ++++++++++++++++++++++++------------------------ 1 file changed, 145 insertions(+), 145 deletions(-) diff --git a/src/ratbagctl.c b/src/ratbagctl.c index 44f856bb..05dfbd5f 100644 --- a/src/ratbagctl.c +++ b/src/ratbagctl.c @@ -69,6 +69,151 @@ static int ratbagctl_new(struct ratbagctl **out) return 0; } +static int get_profile_path(struct ratbagctl *ctl, + const char *device_name, + const char *profile_name, + char **out_path, + sd_bus_error *error) +{ + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply2 = NULL; + const char *device_path = NULL, *profile_path = NULL; + unsigned int profile_index; + char *path; + int r; + + if (device_name) { + r = sd_bus_call_method(ctl->bus, + "org.freedesktop.ratbag1", + "/org/freedesktop/ratbag1", + "org.freedesktop.ratbag1.Manager", + "GetDeviceByName", + error, + &reply, + "s", + device_name); + if (r < 0) + return r; + + r = sd_bus_message_read(reply, "o", &device_path); + if (r < 0) + return r; + } else { + r = sd_bus_call_method(ctl->bus, + "org.freedesktop.ratbag1", + "/org/freedesktop/ratbag1", + "org.freedesktop.DBus.Properties", + "Get", + error, + &reply, + "ss", + "org.freedesktop.ratbag1.Manager", + "Devices"); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(reply, 'v', "ao"); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(reply, 'a', "o"); + if (r < 0) + return r; + + while ((r = sd_bus_message_read_basic(reply, 'o', &path)) > 0) { + if (!device_path) + device_path = path; + } + if (r < 0) + return r; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return r; + + if (!device_path) + return -ENXIO; + } + + assert(device_path); + + if (profile_name) { + r = safe_atou(profile_name, &profile_index); + if (r < 0) + return -ENXIO; + + r = sd_bus_call_method(ctl->bus, + "org.freedesktop.ratbag1", + device_path, + "org.freedesktop.ratbag1.Device", + "GetProfileByIndex", + error, + &reply2, + "u", + profile_index); + if (r < 0) + return r; + + r = sd_bus_message_read(reply2, "o", &profile_path); + if (r < 0) + return r; + } else { + r = sd_bus_call_method(ctl->bus, + "org.freedesktop.ratbag1", + device_path, + "org.freedesktop.DBus.Properties", + "Get", + error, + &reply2, + "ss", + "org.freedesktop.ratbag1.Device", + "ActiveProfile"); + if (r < 0) + return r; + + r = sd_bus_message_read(reply2, "v", "o", &profile_path); + if (r < 0) + return r; + + if (streq(profile_path, "/")) { + reply2 = sd_bus_message_unref(reply2); + + r = sd_bus_call_method(ctl->bus, + "org.freedesktop.ratbag1", + device_path, + "org.freedesktop.DBus.Properties", + "Get", + error, + &reply2, + "ss", + "org.freedesktop.ratbag1.Device", + "DefaultProfile"); + if (r < 0) + return r; + + r = sd_bus_message_read(reply2, "v", "o", &profile_path); + if (r < 0) + return r; + + if (streq(profile_path, "/")) + return -ENXIO; + } + } + + assert(profile_path); + + path = strdup(profile_path); + if (!path) + return -ENOMEM; + + *out_path = path; + return 0; +} + static int list_devices_show(struct ratbagctl *ctl, const char *path) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -406,151 +551,6 @@ static int verb_show_device(struct ratbagctl *ctl, int argc, char **argv) return show_device_print(ctl, device); } -static int get_profile_path(struct ratbagctl *ctl, - const char *device_name, - const char *profile_name, - char **out_path, - sd_bus_error *error) -{ - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply2 = NULL; - const char *device_path = NULL, *profile_path = NULL; - unsigned int profile_index; - char *path; - int r; - - if (device_name) { - r = sd_bus_call_method(ctl->bus, - "org.freedesktop.ratbag1", - "/org/freedesktop/ratbag1", - "org.freedesktop.ratbag1.Manager", - "GetDeviceByName", - error, - &reply, - "s", - device_name); - if (r < 0) - return r; - - r = sd_bus_message_read(reply, "o", &device_path); - if (r < 0) - return r; - } else { - r = sd_bus_call_method(ctl->bus, - "org.freedesktop.ratbag1", - "/org/freedesktop/ratbag1", - "org.freedesktop.DBus.Properties", - "Get", - error, - &reply, - "ss", - "org.freedesktop.ratbag1.Manager", - "Devices"); - if (r < 0) - return r; - - r = sd_bus_message_enter_container(reply, 'v', "ao"); - if (r < 0) - return r; - - r = sd_bus_message_enter_container(reply, 'a', "o"); - if (r < 0) - return r; - - while ((r = sd_bus_message_read_basic(reply, 'o', &path)) > 0) { - if (!device_path) - device_path = path; - } - if (r < 0) - return r; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - return r; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - return r; - - if (!device_path) - return -ENXIO; - } - - assert(device_path); - - if (profile_name) { - r = safe_atou(profile_name, &profile_index); - if (r < 0) - return -ENXIO; - - r = sd_bus_call_method(ctl->bus, - "org.freedesktop.ratbag1", - device_path, - "org.freedesktop.ratbag1.Device", - "GetProfileByIndex", - error, - &reply2, - "u", - profile_index); - if (r < 0) - return r; - - r = sd_bus_message_read(reply2, "o", &profile_path); - if (r < 0) - return r; - } else { - r = sd_bus_call_method(ctl->bus, - "org.freedesktop.ratbag1", - device_path, - "org.freedesktop.DBus.Properties", - "Get", - error, - &reply2, - "ss", - "org.freedesktop.ratbag1.Device", - "ActiveProfile"); - if (r < 0) - return r; - - r = sd_bus_message_read(reply2, "v", "o", &profile_path); - if (r < 0) - return r; - - if (streq(profile_path, "/")) { - reply2 = sd_bus_message_unref(reply2); - - r = sd_bus_call_method(ctl->bus, - "org.freedesktop.ratbag1", - device_path, - "org.freedesktop.DBus.Properties", - "Get", - error, - &reply2, - "ss", - "org.freedesktop.ratbag1.Device", - "DefaultProfile"); - if (r < 0) - return r; - - r = sd_bus_message_read(reply2, "v", "o", &profile_path); - if (r < 0) - return r; - - if (streq(profile_path, "/")) - return -ENXIO; - } - } - - assert(profile_path); - - path = strdup(profile_path); - if (!path) - return -ENOMEM; - - *out_path = path; - return 0; -} - static int show_profile_print_resolutions(struct ratbagctl *ctl, sd_bus_message *m, unsigned int active_resolution, From acb0118897b009a039db62198d144423e8e68f93 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 19:00:27 +0200 Subject: [PATCH 031/137] ratbagctl: split get_profile_path() Split get_profile_path() and provide an helper for get_device_path() on its own. Signed-off-by: David Herrmann --- src/ratbagctl.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/ratbagctl.c b/src/ratbagctl.c index 05dfbd5f..a0da4b17 100644 --- a/src/ratbagctl.c +++ b/src/ratbagctl.c @@ -69,16 +69,13 @@ static int ratbagctl_new(struct ratbagctl **out) return 0; } -static int get_profile_path(struct ratbagctl *ctl, - const char *device_name, - const char *profile_name, - char **out_path, - sd_bus_error *error) +static int get_device_path(struct ratbagctl *ctl, + const char *device_name, + char **out_path, + sd_bus_error *error) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply2 = NULL; - const char *device_path = NULL, *profile_path = NULL; - unsigned int profile_index; + const char *device_path = NULL; char *path; int r; @@ -141,6 +138,32 @@ static int get_profile_path(struct ratbagctl *ctl, assert(device_path); + path = strdup(device_path); + if (!path) + return -ENOMEM; + + *out_path = path; + return 0; +} + +static int get_profile_path(struct ratbagctl *ctl, + const char *device_name, + const char *profile_name, + char **out_path, + sd_bus_error *error) +{ + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply2 = NULL; + _cleanup_(freep) char *device_path = NULL; + const char *profile_path = NULL; + unsigned int profile_index; + char *path; + int r; + + r = get_device_path(ctl, device_name, &device_path, error); + if (r < 0) + return r; + if (profile_name) { r = safe_atou(profile_name, &profile_index); if (r < 0) From 958e86f67eda36a31e193eefc42324a69e0df1d5 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 29 Sep 2015 19:02:12 +0200 Subject: [PATCH 032/137] ratbagctl: pick default device if none given for show-device Lets use the new get_device_path() helper to allow calling show-device without any argument. This follows what show-profile does already. Signed-off-by: David Herrmann --- src/ratbagctl.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/ratbagctl.c b/src/ratbagctl.c index a0da4b17..febca74d 100644 --- a/src/ratbagctl.c +++ b/src/ratbagctl.c @@ -422,9 +422,7 @@ static int show_device_print(struct ratbagctl *ctl, const char *device) _cleanup_(freep) char *path = NULL; int r; - r = sd_bus_path_encode_many(&path, - "/org/freedesktop/ratbag1/device/%", - device); + r = get_device_path(ctl, device, &path, &error); if (r < 0) goto exit; @@ -566,10 +564,6 @@ static int verb_show_device(struct ratbagctl *ctl, int argc, char **argv) } device = argv[optind]; - if (!device) { - fprintf(stderr, "No device specified\n"); - return -EINVAL; - } return show_device_print(ctl, device); } From 17f0fc41d1934a0cf70fb589e70961ebb208630e Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 14 Oct 2015 11:34:27 -0400 Subject: [PATCH 033/137] Add Readme and the policy file required Or running ratbagd (as root) raises a "Permission denied". Signed-off-by: Benjamin Tissoires --- README | 0 README.md | 24 ++++++++++++++++++++++++ dbus/org.freedesktop.ratbag1.conf | 14 ++++++++++++++ 3 files changed, 38 insertions(+) delete mode 100644 README create mode 100644 README.md create mode 100644 dbus/org.freedesktop.ratbag1.conf diff --git a/README b/README deleted file mode 100644 index e69de29b..00000000 diff --git a/README.md b/README.md new file mode 100644 index 00000000..680167b4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +ratbagd +======= + +ratbagd is a system daemon to introspect and modify configurable mice. + +Running ratbagd +--------------- + +To be able to run ratbagd, you need to add a policy file to your dbus +environment: + + sudo cp dbus/org.freedesktop.ratbag1.conf /etc/dbus-1/system.d/org.freedesktop.ratbag1.conf + +License +------- + +libratbag is licensed under the MIT license. + +> 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: [...] diff --git a/dbus/org.freedesktop.ratbag1.conf b/dbus/org.freedesktop.ratbag1.conf new file mode 100644 index 00000000..cd7b8843 --- /dev/null +++ b/dbus/org.freedesktop.ratbag1.conf @@ -0,0 +1,14 @@ + + + + + + + + + + + + From 91a4a325ae7787c5df077c24fc0c7bc0df6d3c05 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 20 Nov 2015 09:05:00 +1000 Subject: [PATCH 034/137] Add missing attributes.m4 Signed-off-by: Peter Hutterer --- .gitignore | 3 +- m4/attributes.m4 | 292 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 m4/attributes.m4 diff --git a/.gitignore b/.gitignore index 7f44e8b2..59d03d4e 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,8 @@ config.log config.status configure libtool -m4/ +*.m4 +!m4/attributes.m4 ratbagctl ratbagd stamp-* diff --git a/m4/attributes.m4 b/m4/attributes.m4 new file mode 100644 index 00000000..db5df250 --- /dev/null +++ b/m4/attributes.m4 @@ -0,0 +1,292 @@ +dnl Macros to check the presence of generic (non-typed) symbols. +dnl Copyright (c) 2006-2008 Diego Pettenò +dnl Copyright (c) 2006-2008 xine project +dnl Copyright (c) 2012 Lucas De Marchi +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +dnl 02110-1301, USA. +dnl +dnl As a special exception, the copyright owners of the +dnl macro gives unlimited permission to copy, distribute and modify the +dnl configure scripts that are the output of Autoconf when processing the +dnl Macro. You need not follow the terms of the GNU General Public +dnl License when using or distributing such scripts, even though portions +dnl of the text of the Macro appear in them. The GNU General Public +dnl License (GPL) does govern all other use of the material that +dnl constitutes the Autoconf Macro. +dnl +dnl This special exception to the GPL applies to versions of the +dnl Autoconf Macro released by this project. When you make and +dnl distribute a modified version of the Autoconf Macro, you may extend +dnl this special exception to the GPL to apply to your modified version as +dnl well. + +dnl Check if FLAG in ENV-VAR is supported by compiler and append it +dnl to WHERE-TO-APPEND variable. Note that we invert -Wno-* checks to +dnl -W* as gcc cannot test for negated warnings. If a C snippet is passed, +dnl use it, otherwise use a simple main() definition that just returns 0. +dnl CC_CHECK_FLAG_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG], [C-SNIPPET]) + +AC_DEFUN([CC_CHECK_FLAG_APPEND], [ + AC_CACHE_CHECK([if $CC supports flag $3 in envvar $2], + AS_TR_SH([cc_cv_$2_$3]), + [eval "AS_TR_SH([cc_save_$2])='${$2}'" + eval "AS_TR_SH([$2])='-Werror `echo "$3" | sed 's/^-Wno-/-W/'`'" + AC_LINK_IFELSE([AC_LANG_SOURCE(ifelse([$4], [], + [int main(void) { return 0; } ], + [$4]))], + [eval "AS_TR_SH([cc_cv_$2_$3])='yes'"], + [eval "AS_TR_SH([cc_cv_$2_$3])='no'"]) + eval "AS_TR_SH([$2])='$cc_save_$2'"]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_$2_$3])[ = xyes], + [eval "$1='${$1} $3'"]) +]) + +dnl CC_CHECK_FLAGS_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG1 FLAG2], [C-SNIPPET]) +AC_DEFUN([CC_CHECK_FLAGS_APPEND], [ + for flag in [$3]; do + CC_CHECK_FLAG_APPEND([$1], [$2], $flag, [$4]) + done +]) + +dnl Check if the flag is supported by linker (cacheable) +dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) + +AC_DEFUN([CC_CHECK_LDFLAGS], [ + AC_CACHE_CHECK([if $CC supports $1 flag], + AS_TR_SH([cc_cv_ldflags_$1]), + [ac_save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $1" + AC_LINK_IFELSE([int main() { return 1; }], + [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_ldflags_$1])="]) + LDFLAGS="$ac_save_LDFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes], + [$2], [$3]) +]) + +dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for +dnl the current linker to avoid undefined references in a shared object. +AC_DEFUN([CC_NOUNDEFINED], [ + dnl We check $host for which systems to enable this for. + AC_REQUIRE([AC_CANONICAL_HOST]) + + case $host in + dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads + dnl are requested, as different implementations are present; to avoid problems + dnl use -Wl,-z,defs only for those platform not behaving this way. + *-freebsd* | *-openbsd*) ;; + *) + dnl First of all check for the --no-undefined variant of GNU ld. This allows + dnl for a much more readable command line, so that people can understand what + dnl it does without going to look for what the heck -z defs does. + for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do + CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"]) + break + done + ;; + esac + + AC_SUBST([LDFLAGS_NOUNDEFINED]) +]) + +dnl Check for a -Werror flag or equivalent. -Werror is the GCC +dnl and ICC flag that tells the compiler to treat all the warnings +dnl as fatal. We usually need this option to make sure that some +dnl constructs (like attributes) are not simply ignored. +dnl +dnl Other compilers don't support -Werror per se, but they support +dnl an equivalent flag: +dnl - Sun Studio compiler supports -errwarn=%all +AC_DEFUN([CC_CHECK_WERROR], [ + AC_CACHE_CHECK( + [for $CC way to treat warnings as errors], + [cc_cv_werror], + [CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror], + [CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])]) + ]) +]) + +AC_DEFUN([CC_CHECK_ATTRIBUTE], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))], + AS_TR_SH([cc_cv_attribute_$1]), + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])], + [eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_attribute_$1])='no'"]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes], + [AC_DEFINE( + AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1, + [Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))] + ) + $4], + [$5]) +]) + +AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [ + CC_CHECK_ATTRIBUTE( + [constructor],, + [void __attribute__((constructor)) ctor() { int a; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_FORMAT], [ + CC_CHECK_ATTRIBUTE( + [format], [format(printf, n, n)], + [void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [ + CC_CHECK_ATTRIBUTE( + [format_arg], [format_arg(printf)], + [char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [ + CC_CHECK_ATTRIBUTE( + [visibility_$1], [visibility("$1")], + [void __attribute__((visibility("$1"))) $1_function() { }], + [$2], [$3]) +]) + +AC_DEFUN([CC_ATTRIBUTE_NONNULL], [ + CC_CHECK_ATTRIBUTE( + [nonnull], [nonnull()], + [void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_UNUSED], [ + CC_CHECK_ATTRIBUTE( + [unused], , + [void some_function(void *foo, __attribute__((unused)) void *bar);], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [ + CC_CHECK_ATTRIBUTE( + [sentinel], , + [void some_function(void *foo, ...) __attribute__((sentinel));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [ + CC_CHECK_ATTRIBUTE( + [deprecated], , + [void some_function(void *foo, ...) __attribute__((deprecated));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_ALIAS], [ + CC_CHECK_ATTRIBUTE( + [alias], [weak, alias], + [void other_function(void *foo) { } + void some_function(void *foo) __attribute__((weak, alias("other_function")));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_MALLOC], [ + CC_CHECK_ATTRIBUTE( + [malloc], , + [void * __attribute__((malloc)) my_alloc(int n);], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_PACKED], [ + CC_CHECK_ATTRIBUTE( + [packed], , + [struct astructure { char a; int b; long c; void *d; } __attribute__((packed));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_CONST], [ + CC_CHECK_ATTRIBUTE( + [const], , + [int __attribute__((const)) twopow(int n) { return 1 << n; } ], + [$1], [$2]) +]) + +AC_DEFUN([CC_FLAG_VISIBILITY], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if $CC supports -fvisibility=hidden], + [cc_cv_flag_visibility], + [cc_flag_visibility_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden], + cc_cv_flag_visibility='yes', + cc_cv_flag_visibility='no') + CFLAGS="$cc_flag_visibility_save_CFLAGS"]) + + AS_IF([test "x$cc_cv_flag_visibility" = "xyes"], + [AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1, + [Define this if the compiler supports the -fvisibility flag]) + $1], + [$2]) +]) + +AC_DEFUN([CC_FUNC_EXPECT], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if compiler has __builtin_expect function], + [cc_cv_func_expect], + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + AC_COMPILE_IFELSE([AC_LANG_SOURCE( + [int some_function() { + int a = 3; + return (int)__builtin_expect(a, 3); + }])], + [cc_cv_func_expect=yes], + [cc_cv_func_expect=no]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([test "x$cc_cv_func_expect" = "xyes"], + [AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1, + [Define this if the compiler supports __builtin_expect() function]) + $1], + [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported], + [cc_cv_attribute_aligned], + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + for cc_attribute_align_try in 64 32 16 8 4 2; do + AC_COMPILE_IFELSE([AC_LANG_SOURCE([ + int main() { + static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0; + return c; + }])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break]) + done + CFLAGS="$ac_save_CFLAGS" + ]) + + if test "x$cc_cv_attribute_aligned" != "x"; then + AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned], + [Define the highest alignment supported]) + fi +]) From 5ffed21e0eee947a0308c8f1c53e0cf71023f68a Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 11 Feb 2016 17:16:58 +1000 Subject: [PATCH 035/137] Remove cleanup func define for sd_bus_message_unref Added to systemd in 4afd3348c7506dd1d36305b7bcb9feb8952b9d6b --- src/ratbagctl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ratbagctl.c b/src/ratbagctl.c index febca74d..327e7a83 100644 --- a/src/ratbagctl.c +++ b/src/ratbagctl.c @@ -37,8 +37,6 @@ struct ratbagctl { static int verb_help(struct ratbagctl *ctl, int argc, char **argv); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message *, sd_bus_message_unref); - static struct ratbagctl *ratbagctl_free(struct ratbagctl *ctl) { if (!ctl) From d049c13062b80065ff982cd4e21d215b33b77b33 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 11 Feb 2016 17:21:18 +1000 Subject: [PATCH 036/137] device: drop default profile fetching, removed from libratbag Signed-off-by: Peter Hutterer --- src/ratbagd-device.c | 28 ---------------------------- src/ratbagd-profile.c | 6 ------ 2 files changed, 34 deletions(-) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 703d50cd..a31c8fef 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -194,33 +194,6 @@ static int ratbagd_device_get_active_profile(sd_bus *bus, return sd_bus_message_append(reply, "o", "/"); } -static int ratbagd_device_get_default_profile(sd_bus *bus, - const char *path, - const char *interface, - const char *property, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error) -{ - struct ratbagd_device *device = userdata; - struct ratbagd_profile *profile; - unsigned int i; - - for (i = 0; i < device->n_profiles; ++i) { - profile = device->profiles[i]; - if (!profile) - continue; - if (!ratbagd_profile_is_default(profile)) - continue; - - return sd_bus_message_append(reply, "o", - ratbagd_profile_get_path(profile)); - } - - /* Eww, we want 'maybe' types here! */ - return sd_bus_message_append(reply, "o", "/"); -} - static int ratbagd_device_get_profile_by_index(sd_bus_message *m, void *userdata, sd_bus_error *error) @@ -248,7 +221,6 @@ const sd_bus_vtable ratbagd_device_vtable[] = { SD_BUS_PROPERTY("Description", "s", ratbagd_device_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Profiles", "ao", ratbagd_device_get_profiles, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ActiveProfile", "o", ratbagd_device_get_active_profile, 0, 0), - SD_BUS_PROPERTY("DefaultProfile", "o", ratbagd_device_get_default_profile, 0, 0), SD_BUS_METHOD("GetProfileByIndex", "u", "o", ratbagd_device_get_profile_by_index, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END, }; diff --git a/src/ratbagd-profile.c b/src/ratbagd-profile.c index 4688f967..f92836cf 100644 --- a/src/ratbagd-profile.c +++ b/src/ratbagd-profile.c @@ -234,9 +234,3 @@ bool ratbagd_profile_is_active(struct ratbagd_profile *profile) assert(profile); return ratbag_profile_is_active(profile->lib_profile) != 0; } - -bool ratbagd_profile_is_default(struct ratbagd_profile *profile) -{ - assert(profile); - return ratbag_profile_is_default(profile->lib_profile) != 0; -} From 3262def07c642e31843f5427393865dd8ffa1fc9 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 12 Feb 2016 16:15:43 +1000 Subject: [PATCH 037/137] device: add support for get-svg Signed-off-by: Peter Hutterer --- src/ratbagd-device.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index a31c8fef..2c6299ee 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -135,6 +135,25 @@ static int ratbagd_device_get_description(sd_bus *bus, return sd_bus_message_append(reply, "s", description); } +static int ratbagd_device_get_svg(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_device *device = userdata; + const char *svg; + + svg = ratbag_device_get_svg_name(device->lib_device); + if (!svg) + return -ENODATA; + + return sd_bus_message_append(reply, "s", svg); +} + + static int ratbagd_device_get_profiles(sd_bus *bus, const char *path, const char *interface, @@ -219,6 +238,7 @@ const sd_bus_vtable ratbagd_device_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct ratbagd_device, name), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Description", "s", ratbagd_device_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Svg", "s", ratbagd_device_get_svg, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Profiles", "ao", ratbagd_device_get_profiles, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ActiveProfile", "o", ratbagd_device_get_active_profile, 0, 0), SD_BUS_METHOD("GetProfileByIndex", "u", "o", ratbagd_device_get_profile_by_index, SD_BUS_VTABLE_UNPRIVILEGED), From c70b53a162354e5bfef4052269c41b04ec1df187 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 12 Feb 2016 16:15:53 +1000 Subject: [PATCH 038/137] profile: add support for setting the active profile Signed-off-by: Peter Hutterer --- src/ratbagd-profile.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/ratbagd-profile.c b/src/ratbagd-profile.c index f92836cf..59c688a7 100644 --- a/src/ratbagd-profile.c +++ b/src/ratbagd-profile.c @@ -168,12 +168,28 @@ static int ratbagd_profile_get_default_resolution(sd_bus *bus, return sd_bus_message_append(reply, "u", (unsigned int)-1); } +static int ratbagd_profile_set_active(sd_bus_message *m, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_profile *profile = userdata; + int r; + + r = sd_bus_message_read(m, ""); + if (r < 0) + return r; + + return sd_bus_reply_method_return(m, "u", + ratbag_profile_set_active(profile->lib_profile)); +} + 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("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), SD_BUS_VTABLE_END, }; From c4e4330bd1d97f9c7c14f55344704cdf1d5fcaaa Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 15 Feb 2016 12:31:55 +1000 Subject: [PATCH 039/137] profile: prefix the profile object path with a 'p' sd_bus_encode_many() escaps elements starting with a digit so our 0 profile has an object path of /.../_30. This is quite confusing during debugging. Signed-off-by: Peter Hutterer --- src/ratbagd-device.c | 2 +- src/ratbagd-profile.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 2c6299ee..f049214c 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -64,7 +64,7 @@ static int ratbagd_device_find_profile(sd_bus *bus, int r; r = sd_bus_path_decode_many(path, - "/org/freedesktop/ratbag1/profile/%/%", + "/org/freedesktop/ratbag1/profile/%/p%", NULL, &name); if (r <= 0) diff --git a/src/ratbagd-profile.c b/src/ratbagd-profile.c index 59c688a7..06217a84 100644 --- a/src/ratbagd-profile.c +++ b/src/ratbagd-profile.c @@ -212,7 +212,7 @@ int ratbagd_profile_new(struct ratbagd_profile **out, profile->lib_profile = lib_profile; profile->index = index; - sprintf(index_buffer, "%u", index); + sprintf(index_buffer, "p%u", index); r = sd_bus_path_encode_many(&profile->path, "/org/freedesktop/ratbag1/profile/%/%", ratbagd_device_get_name(device), From bcd62aec6b74badd71c11868477eae710a7ab397 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 15 Feb 2016 12:04:14 +1000 Subject: [PATCH 040/137] 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 */ From f2a55bca55c5ef1d13db244c8be06641ad6192da Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 15 Feb 2016 14:54:20 +1000 Subject: [PATCH 041/137] profile: add GetResolutionByIndex Signed-off-by: Peter Hutterer --- src/ratbagd-profile.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/ratbagd-profile.c b/src/ratbagd-profile.c index 134f7ee4..740e24c2 100644 --- a/src/ratbagd-profile.c +++ b/src/ratbagd-profile.c @@ -181,6 +181,27 @@ static int ratbagd_profile_set_active(sd_bus_message *m, ratbag_profile_set_active(profile->lib_profile)); } +static int ratbagd_profile_get_resolution_by_index(sd_bus_message *m, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_profile *profile = userdata; + struct ratbagd_resolution *resolution; + unsigned int index; + int r; + + r = sd_bus_message_read(m, "u", &index); + if (r < 0) + return r; + + if (index >= profile->n_resolutions || !profile->resolutions[index]) + return 0; + + resolution = profile->resolutions[index]; + return sd_bus_reply_method_return(m, "o", + ratbagd_resolution_get_path(resolution)); +} + 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), @@ -188,6 +209,7 @@ const sd_bus_vtable ratbagd_profile_vtable[] = { 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), + SD_BUS_METHOD("GetResolutionByIndex", "u", "o", ratbagd_profile_get_resolution_by_index, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END, }; From e199278d6ff38fa9d13e5ca0f4056774c31b8e1b Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 15 Feb 2016 15:04:14 +1000 Subject: [PATCH 042/137] profile: switch DefaultResolution/ActiveResolution over to an object path Signed-off-by: Peter Hutterer --- src/ratbagd-profile.c | 44 ++++++++++++++++++---------------------- src/ratbagd-resolution.c | 12 +++++++++++ src/ratbagd.h | 2 ++ 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/ratbagd-profile.c b/src/ratbagd-profile.c index 740e24c2..1bbd3039 100644 --- a/src/ratbagd-profile.c +++ b/src/ratbagd-profile.c @@ -117,24 +117,22 @@ static int ratbagd_profile_get_active_resolution(sd_bus *bus, sd_bus_error *error) { struct ratbagd_profile *profile = userdata; - unsigned int i, n_resolutions, k = 0; + struct ratbagd_resolution *resolution; + unsigned int i; - n_resolutions = ratbag_profile_get_num_resolutions(profile->lib_profile); - for (i = 0; i < n_resolutions; ++i) { - struct ratbag_resolution *resolution; - - resolution = ratbag_profile_get_resolution(profile->lib_profile, i); + for (i = 0; i < profile->n_resolutions; ++i) { + resolution = profile->resolutions[i]; if (!resolution) continue; - if (!ratbag_resolution_is_active(resolution)) { - ++k; + if (!ratbagd_resolution_is_active(resolution)) continue; - } - return sd_bus_message_append(reply, "u", k); + return sd_bus_message_append(reply, "o", + ratbagd_resolution_get_path(resolution)); } - return sd_bus_message_append(reply, "u", (unsigned int)-1); + /* Eww, we want 'maybe' types here! */ + return sd_bus_message_append(reply, "o", "/"); } static int ratbagd_profile_get_default_resolution(sd_bus *bus, @@ -146,24 +144,22 @@ static int ratbagd_profile_get_default_resolution(sd_bus *bus, sd_bus_error *error) { struct ratbagd_profile *profile = userdata; - unsigned int i, n_resolutions, k = 0; + struct ratbagd_resolution *resolution; + unsigned int i; - n_resolutions = ratbag_profile_get_num_resolutions(profile->lib_profile); - for (i = 0; i < n_resolutions; ++i) { - struct ratbag_resolution *resolution; - - resolution = ratbag_profile_get_resolution(profile->lib_profile, i); + for (i = 0; i < profile->n_resolutions; ++i) { + resolution = profile->resolutions[i]; if (!resolution) continue; - if (!ratbag_resolution_is_default(resolution)) { - ++k; + if (!ratbagd_resolution_is_default(resolution)) continue; - } - return sd_bus_message_append(reply, "u", k); + return sd_bus_message_append(reply, "o", + ratbagd_resolution_get_path(resolution)); } - return sd_bus_message_append(reply, "u", (unsigned int)-1); + /* Eww, we want 'maybe' types here! */ + return sd_bus_message_append(reply, "o", "/"); } static int ratbagd_profile_set_active(sd_bus_message *m, @@ -206,8 +202,8 @@ 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", "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_PROPERTY("ActiveResolution", "o", ratbagd_profile_get_active_resolution, 0, 0), + SD_BUS_PROPERTY("DefaultResolution", "o", ratbagd_profile_get_default_resolution, 0, 0), SD_BUS_METHOD("SetActive", "", "u", ratbagd_profile_set_active, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("GetResolutionByIndex", "u", "o", ratbagd_profile_get_resolution_by_index, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END, diff --git a/src/ratbagd-resolution.c b/src/ratbagd-resolution.c index c60bad34..0dc9b4e5 100644 --- a/src/ratbagd-resolution.c +++ b/src/ratbagd-resolution.c @@ -112,3 +112,15 @@ struct ratbagd_resolution *ratbagd_resolution_free(struct ratbagd_resolution *re return mfree(resolution); } + +bool ratbagd_resolution_is_active(struct ratbagd_resolution *resolution) +{ + assert(resolution); + return ratbag_resolution_is_active(resolution->lib_resolution) != 0; +} + +bool ratbagd_resolution_is_default(struct ratbagd_resolution *resolution) +{ + assert(resolution); + return ratbag_resolution_is_default(resolution->lib_resolution) != 0; +} diff --git a/src/ratbagd.h b/src/ratbagd.h index d29bf5d6..c4ccb08b 100644 --- a/src/ratbagd.h +++ b/src/ratbagd.h @@ -74,6 +74,8 @@ int ratbagd_resolution_new(struct ratbagd_resolution **out, unsigned int index); struct ratbagd_resolution *ratbagd_resolution_free(struct ratbagd_resolution *resolution); const char *ratbagd_resolution_get_path(struct ratbagd_resolution *resolution); +bool ratbagd_resolution_is_active(struct ratbagd_resolution *resolution); +bool ratbagd_resolution_is_default(struct ratbagd_resolution *resolution); DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_resolution *, ratbagd_resolution_free); From 7aca92f2b3baf3bc3239d87e29d209959a568448 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 16 Feb 2016 07:48:16 +1000 Subject: [PATCH 043/137] resolution: add support for setting resolutions and report rate Signed-off-by: Peter Hutterer --- src/ratbagd-resolution.c | 46 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/src/ratbagd-resolution.c b/src/ratbagd-resolution.c index 0dc9b4e5..bd54e6ed 100644 --- a/src/ratbagd-resolution.c +++ b/src/ratbagd-resolution.c @@ -45,12 +45,52 @@ struct ratbagd_resolution { sd_bus_slot *profile_enum_slot; }; +static int ratbagd_resolution_set_report_rate(sd_bus_message *m, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_resolution *resolution = userdata; + unsigned int rate; + int r; + + r = sd_bus_message_read(m, "u", &rate); + if (r < 0) + return r; + + /* basic sanity check */ + if (rate > 5000 || rate % 100) + return 0; + + r = ratbag_resolution_set_report_rate(resolution->lib_resolution, + rate); + return sd_bus_reply_method_return(m, "u", r); +} + +static int ratbagd_resolution_set_resolution(sd_bus_message *m, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_resolution *resolution = userdata; + unsigned int xres, yres; + int r; + + r = sd_bus_message_read(m, "uu", &xres, &yres); + if (r < 0) + return r; + + r = ratbag_resolution_set_dpi_xy(resolution->lib_resolution, + xres, yres); + return sd_bus_reply_method_return(m, "u", r); +} + 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_PROPERTY("XResolution", "u", NULL, offsetof(struct ratbagd_resolution, xres), 0), + SD_BUS_PROPERTY("YResolution", "u", NULL, offsetof(struct ratbagd_resolution, yres), 0), + SD_BUS_PROPERTY("ReportRate", "u", NULL, offsetof(struct ratbagd_resolution, rate), 0), + SD_BUS_METHOD("SetReportRate", "u", "u", ratbagd_resolution_set_report_rate, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetResolution", "uu", "u", ratbagd_resolution_set_resolution, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END, }; From c04f1b57aa89e80931e9483c4e9b7089dc938018 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 16 Feb 2016 16:51:23 +1000 Subject: [PATCH 044/137] device: switch active profile over to return an index only Returning the object path makes it harder for the client to identify which object is the active one. A simple index into the devices array is easier to handle. Note: another approach was to have an IsActive property on the profile directly. This would require updating all properties when the active profile is changed, it's simpler to just have one index. Signed-off-by: Peter Hutterer --- src/ratbagd-device.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 7297ceb1..25f0d33c 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -205,12 +205,12 @@ static int ratbagd_device_get_active_profile(sd_bus *bus, if (!ratbagd_profile_is_active(profile)) continue; - return sd_bus_message_append(reply, "o", - ratbagd_profile_get_path(profile)); + return sd_bus_message_append(reply, "u", i); } - /* Eww, we want 'maybe' types here! */ - return sd_bus_message_append(reply, "o", "/"); + fprintf(stderr, "Unable to find active profile for %s\n", + device->name); + return sd_bus_message_append(reply, "u", 0); } static int ratbagd_device_get_profile_by_index(sd_bus_message *m, @@ -240,7 +240,7 @@ const sd_bus_vtable ratbagd_device_vtable[] = { SD_BUS_PROPERTY("Description", "s", ratbagd_device_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Svg", "s", ratbagd_device_get_svg, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Profiles", "ao", ratbagd_device_get_profiles, 0, SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("ActiveProfile", "o", ratbagd_device_get_active_profile, 0, 0), + SD_BUS_PROPERTY("ActiveProfile", "u", ratbagd_device_get_active_profile, 0, 0), SD_BUS_METHOD("GetProfileByIndex", "u", "o", ratbagd_device_get_profile_by_index, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END, }; From 80ed6d1399c4a57d8cb8f35e278eff53c7ceb8e3 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 16 Feb 2016 16:59:28 +1000 Subject: [PATCH 045/137] resolution: switch to an index for ActiveResolution/DefaultResolution Signed-off-by: Peter Hutterer --- src/ratbagd-profile.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/ratbagd-profile.c b/src/ratbagd-profile.c index 1bbd3039..81c8ad5f 100644 --- a/src/ratbagd-profile.c +++ b/src/ratbagd-profile.c @@ -35,6 +35,7 @@ #include "shared-macro.h" struct ratbagd_profile { + struct ratbagd_device *device; struct ratbag_profile *lib_profile; unsigned int index; char *path; @@ -127,12 +128,12 @@ static int ratbagd_profile_get_active_resolution(sd_bus *bus, if (!ratbagd_resolution_is_active(resolution)) continue; - return sd_bus_message_append(reply, "o", - ratbagd_resolution_get_path(resolution)); + return sd_bus_message_append(reply, "u", i); } - /* Eww, we want 'maybe' types here! */ - return sd_bus_message_append(reply, "o", "/"); + fprintf(stderr, "Unable to find active resolution for %s\n", + ratbagd_device_get_name(profile->device)); + return sd_bus_message_append(reply, "u", 0); } static int ratbagd_profile_get_default_resolution(sd_bus *bus, @@ -154,12 +155,12 @@ static int ratbagd_profile_get_default_resolution(sd_bus *bus, if (!ratbagd_resolution_is_default(resolution)) continue; - return sd_bus_message_append(reply, "o", - ratbagd_resolution_get_path(resolution)); + return sd_bus_message_append(reply, "u", i); } - /* Eww, we want 'maybe' types here! */ - return sd_bus_message_append(reply, "o", "/"); + fprintf(stderr, "Unable to find default resolution for %s\n", + ratbagd_device_get_name(profile->device)); + return sd_bus_message_append(reply, "u", 0); } static int ratbagd_profile_set_active(sd_bus_message *m, @@ -202,8 +203,8 @@ 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", "ao", ratbagd_profile_get_resolutions, 0, 0), - SD_BUS_PROPERTY("ActiveResolution", "o", ratbagd_profile_get_active_resolution, 0, 0), - SD_BUS_PROPERTY("DefaultResolution", "o", ratbagd_profile_get_default_resolution, 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), SD_BUS_METHOD("GetResolutionByIndex", "u", "o", ratbagd_profile_get_resolution_by_index, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END, @@ -227,6 +228,7 @@ int ratbagd_profile_new(struct ratbagd_profile **out, if (!profile) return -ENOMEM; + profile->device = device; profile->lib_profile = lib_profile; profile->index = index; From 262dd532e6b47cb5bc14b0019f527903ff112ead Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 17 Feb 2016 10:33:20 +1000 Subject: [PATCH 046/137] Add a log_verbose logging function for debug output Signed-off-by: Peter Hutterer --- src/ratbagd-device.c | 6 ++++++ src/ratbagd.c | 27 ++++++++++++++++++++++----- src/ratbagd.h | 3 +++ 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 25f0d33c..592e6ca2 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -277,11 +277,17 @@ int ratbagd_device_new(struct ratbagd_device **out, if (r < 0) return r; + device->n_profiles = ratbag_device_get_num_profiles(device->lib_device); device->profiles = calloc(device->n_profiles, sizeof(*device->profiles)); if (!device->profiles) return -ENOMEM; + log_verbose("%s: \"%s\", %d profiles\n", + name, + ratbag_device_get_name(lib_device), + device->n_profiles); + for (i = 0; i < device->n_profiles; ++i) { profile = ratbag_device_get_profile(device->lib_device, i); if (!profile) diff --git a/src/ratbagd.c b/src/ratbagd.c index 4013c50a..dbf5040b 100644 --- a/src/ratbagd.c +++ b/src/ratbagd.c @@ -34,6 +34,19 @@ #include "ratbagd.h" #include "shared-macro.h" +static bool verbose = false; + +void log_verbose(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + + if (verbose) + vprintf(fmt, args); + va_end(args); +} + static int ratbagd_find_device(sd_bus *bus, const char *path, const char *interface, @@ -449,11 +462,15 @@ int main(int argc, char *argv[]) struct ratbagd *ctx = NULL; int r; - if (argc != 1) { - fprintf(stderr, "%s: This program takes no arguments\n", - program_invocation_short_name); - r = -EINVAL; - goto exit; + if (argc > 1) { + if (streq(argv[1], "--verbose")) { + verbose = true; + } else { + fprintf(stderr, "Usage: %s [--verbose]\n", + program_invocation_short_name); + r = -EINVAL; + goto exit; + } } r = ratbagd_new(&ctx); diff --git a/src/ratbagd.h b/src/ratbagd.h index c4ccb08b..296866c2 100644 --- a/src/ratbagd.h +++ b/src/ratbagd.h @@ -41,6 +41,9 @@ struct ratbagd_device; struct ratbagd_profile; struct ratbagd_resolution; + +void log_verbose(const char *fmt, ...) _printf_(1, 2); + /* * Profiles */ From 420a05cabfd0e7bf520e9fd802c4219e2dbdeb3d Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 17 Feb 2016 15:23:30 +0100 Subject: [PATCH 047/137] README: Add instructions to have libsystemd >= 227 Works on F23. There are few dependencies pulled by configure that I did not put there. Signed-off-by: Benjamin Tissoires Signed-off-by: Peter Hutterer --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index 680167b4..bd386d0b 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,35 @@ environment: sudo cp dbus/org.freedesktop.ratbag1.conf /etc/dbus-1/system.d/org.freedesktop.ratbag1.conf +Compiling ratbagd +----------------- + +ratbagd needs systemd >= 227. If you are running Fedora 23, you might find the +following instruction valuable: + +Download systemd v229 (master caused troubles with gcrypt and gpg-error last +time I tried). + + $ git clone --branch v229 https://github.com/systemd/systemd + + +Configure it with: + + $ ./autogen.sh && ./configure --prefix=/opt/systemd \ + --libdir=/opt/systemd/lib \ + --disable-gcrypt \ + --without-bashcompletiondir \ + --with-rootprefix=/opt/systemd \ + --with-sysvinit-path=/opt/systemd/etc \ + --with-sysvrcnd-path=/opt/systemd/etc/rc.d + +Then run make and make install. + +In ratbagd, you will need to add the newly installed libsystemd in the +pkg_config path: + + $ PKG_CONFIG_PATH=/opt/systemd/lib/pkgconfig ./configure + License ------- From e0cb0c70e16927ad24bfd30a31d5b3cfbb1d236a Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 18 Feb 2016 09:11:57 +1000 Subject: [PATCH 048/137] README: fix typo, this is ratbagd, not libratbag Signed-off-by: Peter Hutterer --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bd386d0b..489568f6 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ pkg_config path: License ------- -libratbag is licensed under the MIT license. +ratbagd is licensed under the MIT license. > Permission is hereby granted, free of charge, to any person obtaining a > copy of this software and associated documentation files (the "Software"), From 61abdb57a72904b489be560262041279092893e6 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 18 Feb 2016 11:10:51 +1000 Subject: [PATCH 049/137] device: export all capabilities as dbus properties Signed-off-by: Peter Hutterer --- src/ratbagd-device.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 592e6ca2..69a1fa88 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -46,6 +46,14 @@ struct ratbagd_device { sd_bus_slot *profile_enum_slot; unsigned int n_profiles; struct ratbagd_profile **profiles; + + struct { + bool switchable_resolution; + bool switchable_profile; + bool button_keys; + bool button_macros; + bool default_profile; + } capabilities; }; #define ratbagd_device_from_node(_ptr) \ @@ -237,6 +245,21 @@ static int ratbagd_device_get_profile_by_index(sd_bus_message *m, const sd_bus_vtable ratbagd_device_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct ratbagd_device, name), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CapSwitchableResolution", "b", NULL, + offsetof(struct ratbagd_device, capabilities.switchable_resolution), + SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CapSwitchableProfile", "b", NULL, + offsetof(struct ratbagd_device, capabilities.switchable_profile), + SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CapButtonKeys", "b", NULL, + offsetof(struct ratbagd_device, capabilities.button_keys), + SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CapButtonMacros", "b", NULL, + offsetof(struct ratbagd_device, capabilities.button_macros), + SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CapDefaultProfile", "b", NULL, + offsetof(struct ratbagd_device, capabilities.default_profile), + SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Description", "s", ratbagd_device_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Svg", "s", ratbagd_device_get_svg, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Profiles", "ao", ratbagd_device_get_profiles, 0, SD_BUS_VTABLE_PROPERTY_CONST), @@ -305,6 +328,23 @@ int ratbagd_device_new(struct ratbagd_device **out, } } + + device->capabilities.switchable_resolution = + ratbag_device_has_capability(lib_device, + RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION); + device->capabilities.switchable_profile = + ratbag_device_has_capability(lib_device, + RATBAG_DEVICE_CAP_SWITCHABLE_PROFILE); + device->capabilities.button_keys = + ratbag_device_has_capability(lib_device, + RATBAG_DEVICE_CAP_BUTTON_MACROS); + device->capabilities.button_macros = + ratbag_device_has_capability(lib_device, + RATBAG_DEVICE_CAP_BUTTON_MACROS); + device->capabilities.default_profile = + ratbag_device_has_capability(lib_device, + RATBAG_DEVICE_CAP_DEFAULT_PROFILE); + *out = device; device = NULL; return 0; From 9af58224faa2f0ba6a0051b987d1864b2d5e94c0 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 18 Feb 2016 11:14:13 +1000 Subject: [PATCH 050/137] resolution: export capabilities as dbus properties Signed-off-by: Peter Hutterer --- src/ratbagd-resolution.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/ratbagd-resolution.c b/src/ratbagd-resolution.c index bd54e6ed..a04e8936 100644 --- a/src/ratbagd-resolution.c +++ b/src/ratbagd-resolution.c @@ -43,6 +43,11 @@ struct ratbagd_resolution { sd_bus_slot *profile_vtable_slot; sd_bus_slot *profile_enum_slot; + + struct { + bool individual_report_rate; + bool separate_xy_res; + } capabilities; }; static int ratbagd_resolution_set_report_rate(sd_bus_message *m, @@ -86,6 +91,12 @@ static int ratbagd_resolution_set_resolution(sd_bus_message *m, 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("CapIndividualReportRate", "b", NULL, + offsetof(struct ratbagd_resolution, capabilities.individual_report_rate), + SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CapSeparateXYResolution", "b", NULL, + offsetof(struct ratbagd_resolution, capabilities.separate_xy_res), + SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("XResolution", "u", NULL, offsetof(struct ratbagd_resolution, xres), 0), SD_BUS_PROPERTY("YResolution", "u", NULL, offsetof(struct ratbagd_resolution, yres), 0), SD_BUS_PROPERTY("ReportRate", "u", NULL, offsetof(struct ratbagd_resolution, rate), 0), @@ -117,6 +128,12 @@ int ratbagd_resolution_new(struct ratbagd_resolution **out, 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); + resolution->capabilities.individual_report_rate = + ratbag_resolution_has_capability(lib_resolution, + RATBAG_RESOLUTION_CAP_INDIVIDUAL_REPORT_RATE); + resolution->capabilities.separate_xy_res = + ratbag_resolution_has_capability(lib_resolution, + RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION); sprintf(profile_buffer, "p%u", ratbagd_profile_get_index(profile)); sprintf(resolution_buffer, "r%u", index); From 7a498310e2c3a638007115e330fb6385821addc7 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 18 Feb 2016 15:14:15 +1000 Subject: [PATCH 051/137] resolution: remove unused variables Copy/paste leftover from the profile. Signed-off-by: Peter Hutterer --- src/ratbagd-resolution.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ratbagd-resolution.c b/src/ratbagd-resolution.c index a04e8936..33608a7a 100644 --- a/src/ratbagd-resolution.c +++ b/src/ratbagd-resolution.c @@ -41,9 +41,6 @@ struct ratbagd_resolution { unsigned int xres, yres; unsigned int rate; - sd_bus_slot *profile_vtable_slot; - sd_bus_slot *profile_enum_slot; - struct { bool individual_report_rate; bool separate_xy_res; From 12f013681a1341cdb58797e3b485351d47052c8d Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 18 Feb 2016 15:53:25 +1000 Subject: [PATCH 052/137] Add rudimentary for buttons This just exports the button index so far and makes sure we can write clients that deal with button objects instead of making stuff up to test for buttons. Signed-off-by: Peter Hutterer --- Makefile.am | 1 + src/ratbagd-button.c | 104 +++++++++++++++++++++++++++++++ src/ratbagd-device.c | 10 +++ src/ratbagd-profile.c | 138 ++++++++++++++++++++++++++++++++++++++++++ src/ratbagd.h | 21 ++++++- 5 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 src/ratbagd-button.c diff --git a/Makefile.am b/Makefile.am index a3d8270c..b99755c3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -80,6 +80,7 @@ bin_PROGRAMS += \ ratbagd_SOURCES = \ src/ratbagd.h \ src/ratbagd.c \ + src/ratbagd-button.c \ src/ratbagd-device.c \ src/ratbagd-profile.c \ src/ratbagd-resolution.c diff --git a/src/ratbagd-button.c b/src/ratbagd-button.c new file mode 100644 index 00000000..3bb2117f --- /dev/null +++ b/src/ratbagd-button.c @@ -0,0 +1,104 @@ +/*** + 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_button { + struct ratbag_button *lib_button; + unsigned int index; + char *path; +}; + +const sd_bus_vtable ratbagd_button_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Index", "u", NULL, offsetof(struct ratbagd_button, index), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_VTABLE_END, +}; + +int ratbagd_button_new(struct ratbagd_button **out, + struct ratbagd_device *device, + struct ratbagd_profile *profile, + struct ratbag_button *lib_button, + unsigned int index) +{ + _cleanup_(ratbagd_button_freep) struct ratbagd_button *button = NULL; + char profile_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1], + button_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1]; + int r; + + assert(out); + assert(lib_button); + + button = calloc(1, sizeof(*button)); + if (!button) + return -ENOMEM; + + button->lib_button = lib_button; + button->index = index; + + sprintf(profile_buffer, "p%u", ratbagd_profile_get_index(profile)); + sprintf(button_buffer, "b%u", index); + r = sd_bus_path_encode_many(&button->path, + "/org/freedesktop/ratbag1/button/%/%/%", + ratbagd_device_get_name(device), + profile_buffer, + button_buffer); + if (r < 0) + return r; + + *out = button; + button = NULL; + return 0; +} + +const char *ratbagd_button_get_path(struct ratbagd_button *button) +{ + assert(button); + return button->path; +} + +struct ratbagd_button *ratbagd_button_free(struct ratbagd_button *button) +{ + if (!button) + return NULL; + + button->path = mfree(button->path); + + /* we cannot assume the button is gone, so set NULL explicitly */ + ratbag_button_unref(button->lib_button); + button->lib_button = NULL; + + return mfree(button); +} + diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 69a1fa88..45c17d99 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -384,6 +384,12 @@ const char *ratbagd_device_get_path(struct ratbagd_device *device) return device->path; } +unsigned int ratbagd_device_get_num_buttons(struct ratbagd_device *device) +{ + assert(device); + return ratbag_device_get_num_buttons(device->lib_device); +} + bool ratbagd_device_linked(struct ratbagd_device *device) { return device && rbnode_linked(&device->node); @@ -457,6 +463,10 @@ void ratbagd_device_link(struct ratbagd_device *device) "Cannot register resolutions for '%s': %m\n", device->name); } + + r = ratbagd_profile_register_buttons(device->ctx->bus, + device, + device->profiles[i]); } } diff --git a/src/ratbagd-profile.c b/src/ratbagd-profile.c index 81c8ad5f..0aa43622 100644 --- a/src/ratbagd-profile.c +++ b/src/ratbagd-profile.c @@ -44,6 +44,11 @@ struct ratbagd_profile { sd_bus_slot *resolution_enum_slot; unsigned int n_resolutions; struct ratbagd_resolution **resolutions; + + sd_bus_slot *button_vtable_slot; + sd_bus_slot *button_enum_slot; + unsigned int n_buttons; + struct ratbagd_button **buttons; }; static int ratbagd_profile_find_resolution(sd_bus *bus, @@ -163,6 +168,37 @@ static int ratbagd_profile_get_default_resolution(sd_bus *bus, return sd_bus_message_append(reply, "u", 0); } +static int ratbagd_profile_find_button(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/button/%/p%/b%", + NULL, + NULL, + &name); + if (r <= 0) + return r; + + r = safe_atou(name, &index); + if (r < 0) + return 0; + + if (index >= profile->n_buttons || !profile->buttons[index]) + return 0; + + *found = profile->buttons[index]; + return 1; +} + static int ratbagd_profile_set_active(sd_bus_message *m, void *userdata, sd_bus_error *error) @@ -217,6 +253,7 @@ int ratbagd_profile_new(struct ratbagd_profile **out, { _cleanup_(ratbagd_profile_freep) struct ratbagd_profile *profile = NULL; struct ratbag_resolution *resolution; + struct ratbag_button *button; char index_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1]; unsigned int i; int r; @@ -245,6 +282,11 @@ int ratbagd_profile_new(struct ratbagd_profile **out, if (!profile->resolutions) return -ENOMEM; + profile->n_buttons = ratbagd_device_get_num_buttons(device); + profile->buttons = calloc(profile->n_buttons, sizeof(*profile->buttons)); + if (!profile->buttons) + return -ENOMEM; + for (i = 0; i < profile->n_resolutions; ++i) { resolution = ratbag_profile_get_resolution(profile->lib_profile, i); if (!resolution) @@ -263,6 +305,24 @@ int ratbagd_profile_new(struct ratbagd_profile **out, } } + for (i = 0; i < profile->n_buttons; ++i) { + button = ratbag_profile_get_button(profile->lib_profile, i); + if (!button) + continue; + + r = ratbagd_button_new(&profile->buttons[i], + device, + profile, + button, + i); + if (r < 0) { + errno = -r; + fprintf(stderr, + "Cannot allocate button for '%s': %m\n", + ratbagd_device_get_name(device)); + } + } + *out = profile; profile = NULL; return 0; @@ -378,3 +438,81 @@ int ratbagd_profile_register_resolutions(struct sd_bus *bus, return 0; } + +static int ratbagd_profile_list_buttons(sd_bus *bus, + const char *path, + void *userdata, + char ***paths, + sd_bus_error *error) +{ + struct ratbagd_profile *profile = userdata; + struct ratbagd_button *button; + char **buttons; + unsigned int i; + + buttons = calloc(profile->n_buttons + 1, sizeof(char *)); + if (!buttons) + return -ENOMEM; + + for (i = 0; i < profile->n_buttons; ++i) { + button = profile->buttons[i]; + if (!button) + continue; + + buttons[i] = strdup(ratbagd_button_get_path(button)); + if (!buttons[i]) + goto error; + } + + buttons[i] = NULL; + *paths = buttons; + return 1; + +error: + for (i = 0; buttons[i]; ++i) + free(buttons[i]); + free(buttons); + return -ENOMEM; +} + +int ratbagd_profile_register_buttons(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/button/%/%", + ratbagd_device_get_name(device), + index_buffer); + + + if (r >= 0) { + r = sd_bus_add_fallback_vtable(bus, + &profile->button_vtable_slot, + prefix, + "org.freedesktop.ratbag1.Button", + ratbagd_button_vtable, + ratbagd_profile_find_button, + profile); + if (r >= 0) + r = sd_bus_add_node_enumerator(bus, + &profile->button_enum_slot, + prefix, + ratbagd_profile_list_buttons, + profile); + } + if (r < 0) { + errno = -r; + fprintf(stderr, + "Cannot register buttons for '%s': %m\n", + ratbagd_device_get_name(device)); + } + + return 0; +} diff --git a/src/ratbagd.h b/src/ratbagd.h index 296866c2..442f2e6f 100644 --- a/src/ratbagd.h +++ b/src/ratbagd.h @@ -40,7 +40,7 @@ struct ratbagd; struct ratbagd_device; struct ratbagd_profile; struct ratbagd_resolution; - +struct ratbagd_button; void log_verbose(const char *fmt, ...) _printf_(1, 2); @@ -62,6 +62,9 @@ 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); +int ratbagd_profile_register_buttons(struct sd_bus *bus, + struct ratbagd_device *device, + struct ratbagd_profile *profile); DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_profile *, ratbagd_profile_free); @@ -82,6 +85,21 @@ bool ratbagd_resolution_is_default(struct ratbagd_resolution *resolution); DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_resolution *, ratbagd_resolution_free); +/* + * Buttons + */ +extern const sd_bus_vtable ratbagd_button_vtable[]; + +int ratbagd_button_new(struct ratbagd_button **out, + struct ratbagd_device *device, + struct ratbagd_profile *profile, + struct ratbag_button *lib_button, + unsigned int index); +struct ratbagd_button *ratbagd_button_free(struct ratbagd_button *button); +const char *ratbagd_button_get_path(struct ratbagd_button *button); + +DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_button *, ratbagd_button_free); + /* * Devices */ @@ -95,6 +113,7 @@ int ratbagd_device_new(struct ratbagd_device **out, struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device); const char *ratbagd_device_get_name(struct ratbagd_device *device); const char *ratbagd_device_get_path(struct ratbagd_device *device); +unsigned int ratbagd_device_get_num_buttons(struct ratbagd_device *device); bool ratbagd_device_linked(struct ratbagd_device *device); void ratbagd_device_link(struct ratbagd_device *device); From 555d00c9a8c5116de46fdb90195f6eec4a6c3edd Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 19 Feb 2016 13:55:09 +1000 Subject: [PATCH 053/137] ratbagd: if --verbose is specified, set libratbag to verbose too Signed-off-by: Peter Hutterer --- src/ratbagd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ratbagd.c b/src/ratbagd.c index dbf5040b..4fef42c9 100644 --- a/src/ratbagd.c +++ b/src/ratbagd.c @@ -342,6 +342,10 @@ static int ratbagd_new(struct ratbagd **out) if (!ctx->lib_ctx) return -ENOMEM; + if (verbose) + ratbag_log_set_priority(ctx->lib_ctx, + RATBAG_LOG_PRIORITY_DEBUG); + r = ratbagd_init_monitor(ctx); if (r < 0) return r; From ce3038fd8e35dc85b6cd7c0b9061c4d57df10bf0 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 19 Feb 2016 13:56:43 +1000 Subject: [PATCH 054/137] Use streq over strcmp Signed-off-by: Peter Hutterer --- src/ratbagctl.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/ratbagctl.c b/src/ratbagctl.c index 327e7a83..444e7fdc 100644 --- a/src/ratbagctl.c +++ b/src/ratbagctl.c @@ -265,10 +265,10 @@ static int list_devices_show(struct ratbagctl *ctl, const char *path) if (r < 0) return r; - if (!strcmp(property, "Id")) { + if (streq(property, "Id")) { r = sd_bus_message_read(reply, "v", "s", &prop_id); - } else if (!strcmp(property, "Description")) { + } else if (streq(property, "Description")) { r = sd_bus_message_read(reply, "v", "s", &prop_description); } else { @@ -447,13 +447,13 @@ static int show_device_print(struct ratbagctl *ctl, const char *device) if (r < 0) goto exit; - if (!strcmp(property, "Id")) { + if (streq(property, "Id")) { r = sd_bus_message_read(reply, "v", "s", &prop_id); - } else if (!strcmp(property, "Description")) { + } else if (streq(property, "Description")) { r = sd_bus_message_read(reply, "v", "s", &prop_description); - } else if (!strcmp(property, "Profiles")) { + } else if (streq(property, "Profiles")) { r = sd_bus_message_enter_container(reply, 'v', "ao"); if (r < 0) goto exit; @@ -486,7 +486,7 @@ static int show_device_print(struct ratbagctl *ctl, const char *device) goto exit; r = sd_bus_message_exit_container(reply); - } else if (!strcmp(property, "ActiveProfile")) { + } else if (streq(property, "ActiveProfile")) { r = sd_bus_message_read(reply, "v", "o", &profile); if (r < 0) goto exit; @@ -494,7 +494,7 @@ static int show_device_print(struct ratbagctl *ctl, const char *device) r = show_device_get_profile_index(ctl, profile, &prop_active_profile); - } else if (!strcmp(property, "DefaultProfile")) { + } else if (streq(property, "DefaultProfile")) { r = sd_bus_message_read(reply, "v", "o", &profile); if (r < 0) goto exit; @@ -592,13 +592,13 @@ static int show_profile_print_resolutions(struct ratbagctl *ctl, if (r < 0) return r; - if (!strcmp(key, "dpi")) { + if (streq(key, "dpi")) { r = sd_bus_message_read(m, "v", "u", &dpi); - } else if (!strcmp(key, "dpi-x")) { + } else if (streq(key, "dpi-x")) { r = sd_bus_message_read(m, "v", "u", &dpi_x); - } else if (!strcmp(key, "dpi-y")) { + } else if (streq(key, "dpi-y")) { r = sd_bus_message_read(m, "v", "u", &dpi_y); - } else if (!strcmp(key, "report-rate")) { + } else if (streq(key, "report-rate")) { r = sd_bus_message_read(m, "v", "u", &report_rate); } else { r = sd_bus_message_skip(m, "v"); @@ -689,13 +689,13 @@ static int show_profile_print(struct ratbagctl *ctl, if (r < 0) goto exit; - if (!strcmp(property, "Index")) { + if (streq(property, "Index")) { r = sd_bus_message_read(reply, "v", "u", &prop_index); - } else if (!strcmp(property, "ActiveResolution")) { + } else if (streq(property, "ActiveResolution")) { r = sd_bus_message_read(reply, "v", "u", &prop_active_resolution); - } else if (!strcmp(property, "DefaultResolution")) { + } else if (streq(property, "DefaultResolution")) { r = sd_bus_message_read(reply, "v", "u", &prop_default_resolution); } else { @@ -727,7 +727,7 @@ static int show_profile_print(struct ratbagctl *ctl, if (r < 0) goto exit; - if (!strcmp(property, "Resolutions")) { + if (streq(property, "Resolutions")) { r = show_profile_print_resolutions(ctl, reply, prop_active_resolution, From 2138ab05e55ccea02e52a88fdcf9f65e8287b148 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 19 Feb 2016 14:06:04 +1000 Subject: [PATCH 055/137] Replace fprintfs with a new log_error helper Signed-off-by: Peter Hutterer --- src/ratbagd-device.c | 18 +++++++----------- src/ratbagd-profile.c | 28 ++++++++++++---------------- src/ratbagd.c | 15 ++++++++++++--- src/ratbagd.h | 1 + 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 45c17d99..8fb36684 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -216,8 +216,7 @@ static int ratbagd_device_get_active_profile(sd_bus *bus, return sd_bus_message_append(reply, "u", i); } - fprintf(stderr, "Unable to find active profile for %s\n", - device->name); + log_error("Unable to find active profile for %s\n", device->name); return sd_bus_message_append(reply, "u", 0); } @@ -322,9 +321,8 @@ int ratbagd_device_new(struct ratbagd_device **out, i); if (r < 0) { errno = -r; - fprintf(stderr, - "Cannot allocate profile for '%s': %m\n", - device->name); + log_error("Cannot allocate profile for '%s': %m\n", + device->name); } } @@ -448,9 +446,8 @@ void ratbagd_device_link(struct ratbagd_device *device) } if (r < 0) { errno = -r; - fprintf(stderr, - "Cannot register profile interfaces for '%s': %m\n", - device->name); + log_error("Cannot register profile interfaces for '%s': %m\n", + device->name); return; } @@ -459,9 +456,8 @@ void ratbagd_device_link(struct ratbagd_device *device) device, device->profiles[i]); if (r < 0) { - fprintf(stderr, - "Cannot register resolutions for '%s': %m\n", - device->name); + log_error("Cannot register resolutions for '%s': %m\n", + device->name); } r = ratbagd_profile_register_buttons(device->ctx->bus, diff --git a/src/ratbagd-profile.c b/src/ratbagd-profile.c index 0aa43622..3e463b14 100644 --- a/src/ratbagd-profile.c +++ b/src/ratbagd-profile.c @@ -136,8 +136,8 @@ static int ratbagd_profile_get_active_resolution(sd_bus *bus, return sd_bus_message_append(reply, "u", i); } - fprintf(stderr, "Unable to find active resolution for %s\n", - ratbagd_device_get_name(profile->device)); + log_error("Unable to find active resolution for %s\n", + ratbagd_device_get_name(profile->device)); return sd_bus_message_append(reply, "u", 0); } @@ -163,8 +163,8 @@ static int ratbagd_profile_get_default_resolution(sd_bus *bus, return sd_bus_message_append(reply, "u", i); } - fprintf(stderr, "Unable to find default resolution for %s\n", - ratbagd_device_get_name(profile->device)); + log_error("Unable to find default resolution for %s\n", + ratbagd_device_get_name(profile->device)); return sd_bus_message_append(reply, "u", 0); } @@ -299,9 +299,8 @@ int ratbagd_profile_new(struct ratbagd_profile **out, i); if (r < 0) { errno = -r; - fprintf(stderr, - "Cannot allocate resolution for '%s': %m\n", - ratbagd_device_get_name(device)); + log_error("Cannot allocate resolution for '%s': %m\n", + ratbagd_device_get_name(device)); } } @@ -317,9 +316,8 @@ int ratbagd_profile_new(struct ratbagd_profile **out, i); if (r < 0) { errno = -r; - fprintf(stderr, - "Cannot allocate button for '%s': %m\n", - ratbagd_device_get_name(device)); + log_error("Cannot allocate button for '%s': %m\n", + ratbagd_device_get_name(device)); } } @@ -431,9 +429,8 @@ int ratbagd_profile_register_resolutions(struct sd_bus *bus, } if (r < 0) { errno = -r; - fprintf(stderr, - "Cannot register resolutions for '%s': %m\n", - ratbagd_device_get_name(device)); + log_error("Cannot register resolutions for '%s': %m\n", + ratbagd_device_get_name(device)); } return 0; @@ -509,9 +506,8 @@ int ratbagd_profile_register_buttons(struct sd_bus *bus, } if (r < 0) { errno = -r; - fprintf(stderr, - "Cannot register buttons for '%s': %m\n", - ratbagd_device_get_name(device)); + log_error("Cannot register buttons for '%s': %m\n", + ratbagd_device_get_name(device)); } return 0; diff --git a/src/ratbagd.c b/src/ratbagd.c index 4fef42c9..ca5347ef 100644 --- a/src/ratbagd.c +++ b/src/ratbagd.c @@ -47,6 +47,16 @@ void log_verbose(const char *fmt, ...) va_end(args); } +void log_error(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + fprintf(stderr, "%s error: ", program_invocation_short_name); + vfprintf(stderr, fmt, args); + va_end(args); +} + static int ratbagd_find_device(sd_bus *bus, const char *path, const char *interface, @@ -214,7 +224,7 @@ static void ratbagd_process_device(struct ratbagd *ctx, ratbag_device_unref(lib_device); if (r < 0) { - fprintf(stderr, "Cannot track device '%s'\n", name); + log_error("Cannot track device '%s'\n", name); return; } @@ -488,8 +498,7 @@ exit: if (r < 0) { errno = -r; - fprintf(stderr, "%s: Failed: %m\n", - program_invocation_short_name); + log_error("Failed: %m\n"); return EXIT_FAILURE; } diff --git a/src/ratbagd.h b/src/ratbagd.h index 442f2e6f..01477f4f 100644 --- a/src/ratbagd.h +++ b/src/ratbagd.h @@ -43,6 +43,7 @@ struct ratbagd_resolution; struct ratbagd_button; void log_verbose(const char *fmt, ...) _printf_(1, 2); +void log_error(const char *fmt, ...) _printf_(1, 2); /* * Profiles From c6627d62668f4dee7d1a95d23d71a4eefb9bb45e Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 19 Feb 2016 14:16:08 +1000 Subject: [PATCH 056/137] device: if we can't fetch the description or svg, return an empty string Less exception handling needed on the client side. Signed-off-by: Peter Hutterer --- src/ratbagd-device.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 8fb36684..2f4dc3af 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -137,8 +137,11 @@ static int ratbagd_device_get_description(sd_bus *bus, const char *description; description = ratbag_device_get_name(device->lib_device); - if (!description) - return -ENODATA; + if (!description) { + log_error("Unable to fetch description for %s\n", + ratbagd_device_get_name(device)); + description = ""; + } return sd_bus_message_append(reply, "s", description); } @@ -155,8 +158,11 @@ static int ratbagd_device_get_svg(sd_bus *bus, const char *svg; svg = ratbag_device_get_svg_name(device->lib_device); - if (!svg) - return -ENODATA; + if (!svg) { + log_error("Unable to fetch SVG for %s\n", + ratbagd_device_get_name(device)); + svg = ""; + } return sd_bus_message_append(reply, "s", svg); } From d1ea517f9a381d3196fa9a2ef197ad44fb6b0027 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 19 Feb 2016 14:17:42 +1000 Subject: [PATCH 057/137] ratbagctl: drop DefaultProfile parsing Dropped in d049c13062b8006 Signed-off-by: Peter Hutterer --- src/ratbagctl.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/ratbagctl.c b/src/ratbagctl.c index 444e7fdc..49460f2e 100644 --- a/src/ratbagctl.c +++ b/src/ratbagctl.c @@ -415,7 +415,7 @@ static int show_device_print(struct ratbagctl *ctl, const char *device) _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; unsigned int prop_min_index = 0, prop_max_index = 0; - unsigned int prop_active_profile = -1, prop_default_profile = -1; + unsigned int prop_active_profile = -1; const char *prop_id = NULL, *prop_description = NULL; _cleanup_(freep) char *path = NULL; int r; @@ -494,14 +494,6 @@ static int show_device_print(struct ratbagctl *ctl, const char *device) r = show_device_get_profile_index(ctl, profile, &prop_active_profile); - } else if (streq(property, "DefaultProfile")) { - r = sd_bus_message_read(reply, "v", "o", &profile); - if (r < 0) - goto exit; - - r = show_device_get_profile_index(ctl, - profile, - &prop_default_profile); } else { r = sd_bus_message_skip(reply, "v"); } @@ -534,11 +526,6 @@ static int show_device_print(struct ratbagctl *ctl, const char *device) else printf("\t Active Profile: %u\n", prop_active_profile); - if (prop_default_profile == (unsigned int)-1) - printf("\tDefault Profile: (unknown)\n"); - else - printf("\tDefault Profile: %u\n", prop_default_profile); - exit: if (r < 0) fprintf(stderr, "Cannot show device: %s\n", From e8d164515006738f00e0f87bf35b5bfde6b80605 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 19 Feb 2016 14:18:14 +1000 Subject: [PATCH 058/137] ratbagctl: Switch ActiveProfile parsing to an integer Fallout from c04f1b57aa89e Signed-off-by: Peter Hutterer --- src/ratbagctl.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/ratbagctl.c b/src/ratbagctl.c index 49460f2e..c294c391 100644 --- a/src/ratbagctl.c +++ b/src/ratbagctl.c @@ -487,13 +487,9 @@ static int show_device_print(struct ratbagctl *ctl, const char *device) r = sd_bus_message_exit_container(reply); } else if (streq(property, "ActiveProfile")) { - r = sd_bus_message_read(reply, "v", "o", &profile); + r = sd_bus_message_read(reply, "v", "u", &prop_active_profile); if (r < 0) goto exit; - - r = show_device_get_profile_index(ctl, - profile, - &prop_active_profile); } else { r = sd_bus_message_skip(reply, "v"); } From 5fe39f94ab267a85920bf7a33e6a4676f30311dc Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 19 Feb 2016 15:07:15 +1000 Subject: [PATCH 059/137] ratbagctl: fix show-profile to handle the resolution objects Signed-off-by: Peter Hutterer --- src/ratbagctl.c | 146 ++++++++++++++++++++++++++++-------------------- 1 file changed, 84 insertions(+), 62 deletions(-) diff --git a/src/ratbagctl.c b/src/ratbagctl.c index c294c391..f80aefff 100644 --- a/src/ratbagctl.c +++ b/src/ratbagctl.c @@ -416,7 +416,7 @@ static int show_device_print(struct ratbagctl *ctl, const char *device) _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; unsigned int prop_min_index = 0, prop_max_index = 0; unsigned int prop_active_profile = -1; - const char *prop_id = NULL, *prop_description = NULL; + const char *prop_id = NULL, *prop_description = NULL, *prop_svg = NULL; _cleanup_(freep) char *path = NULL; int r; @@ -453,6 +453,8 @@ static int show_device_print(struct ratbagctl *ctl, const char *device) } else if (streq(property, "Description")) { r = sd_bus_message_read(reply, "v", "s", &prop_description); + } else if (streq(property, "Svg")) { + r = sd_bus_message_read(reply, "v", "s", &prop_svg); } else if (streq(property, "Profiles")) { r = sd_bus_message_enter_container(reply, 'v', "ao"); if (r < 0) @@ -508,6 +510,7 @@ static int show_device_print(struct ratbagctl *ctl, const char *device) goto exit; printf("%s - %s\n", prop_id, prop_description); + printf("\t Svg: %s\n", strlen(prop_svg) > 0 ? prop_svg : ""); if (prop_min_index == prop_max_index) printf("\t Profiles:\n"); @@ -549,76 +552,99 @@ static int verb_show_device(struct ratbagctl *ctl, int argc, char **argv) return show_device_print(ctl, device); } +static int show_profile_print_resolution(struct ratbagctl *ctl, const char *path) +{ + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + unsigned int prop_index = -1, + prop_report_rate = -1, + prop_xres = -1, + prop_yres = -1; + int r; + + r = sd_bus_call_method(ctl->bus, + "org.freedesktop.ratbag1", + path, + "org.freedesktop.DBus.Properties", + "GetAll", + &error, + &reply, + "s", + "org.freedesktop.ratbag1.Resolution"); + if (r < 0) + goto exit; + + r = sd_bus_message_enter_container(reply, 'a', "{sv}"); + if (r < 0) + goto exit; + + while ((r = sd_bus_message_enter_container(reply, 'e', "sv")) > 0) { + const char *property; + + r = sd_bus_message_read_basic(reply, 's', &property); + if (r < 0) + goto exit; + + if (streq(property, "Index")) { + r = sd_bus_message_read(reply, "v", "u", + &prop_index); + } else if (streq(property, "ReportRate")) { + r = sd_bus_message_read(reply, "v", "u", + &prop_report_rate); + } else if (streq(property, "XResolution")) { + r = sd_bus_message_read(reply, "v", "u", &prop_xres); + } else if (streq(property, "YResolution")) { + r = sd_bus_message_read(reply, "v", "u", &prop_yres); + } else { + r = sd_bus_message_skip(reply, "v"); + } + if (r < 0) + goto exit; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto exit; + } + if (r < 0) + goto exit; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto exit; + + printf("resolution-%u\n", prop_index); + + printf("\t Index: %u\n", prop_index); + printf("\t Report Rate: %uHz\n", prop_report_rate); + printf("\t Resolution: %ux%udpi\n", prop_xres, prop_yres); + + printf("\n"); + +exit: + if (r < 0) + fprintf(stderr, "Cannot show resolution: %s\n", + error.message ? : "Parser error"); + return r; +} + static int show_profile_print_resolutions(struct ratbagctl *ctl, sd_bus_message *m, unsigned int active_resolution, unsigned int default_resolution) { - unsigned int k = 0; + const char *resolution; int r; - r = sd_bus_message_enter_container(m, 'v', "aa{sv}"); + r = sd_bus_message_enter_container(m, 'v', "ao"); if (r < 0) return r; - r = sd_bus_message_enter_container(m, 'a', "a{sv}"); + r = sd_bus_message_enter_container(m, 'a', "o"); if (r < 0) return r; - while ((r = sd_bus_message_enter_container(m, 'a', "{sv}")) > 0) { - unsigned int dpi = -1, dpi_x = -1, dpi_y = -1; - unsigned int report_rate = -1; - const char *key; - - while ((r = sd_bus_message_enter_container(m, 'e', "sv")) > 0) { - r = sd_bus_message_read_basic(m, 's', &key); - if (r < 0) - return r; - - if (streq(key, "dpi")) { - r = sd_bus_message_read(m, "v", "u", &dpi); - } else if (streq(key, "dpi-x")) { - r = sd_bus_message_read(m, "v", "u", &dpi_x); - } else if (streq(key, "dpi-y")) { - r = sd_bus_message_read(m, "v", "u", &dpi_y); - } else if (streq(key, "report-rate")) { - r = sd_bus_message_read(m, "v", "u", &report_rate); - } else { - r = sd_bus_message_skip(m, "v"); - } - if (r < 0) - return r; - - r = sd_bus_message_exit_container(m); - if (r < 0) - return r; - } - if (r < 0) - return r; - - r = sd_bus_message_exit_container(m); - if (r < 0) - return r; - - if (dpi != (unsigned int)-1) { - dpi_x = dpi; - dpi_y = dpi; - } - - if (dpi_x != (unsigned int)-1 && - dpi_y != (unsigned int)-1 && - report_rate != (unsigned int)-1) { - printf("%s%5u x %-5u dpi @ %5u Hz%s%s\n", - (k != 0) ? "\t\t\t " : "", - dpi_x, dpi_y, report_rate, - (k == active_resolution) ? " (active)" : "", - (k == default_resolution) ? " (default)" : ""); - } - - ++k; - } - if (r < 0) - return r; + while ((r = sd_bus_message_read_basic(m, 'o', &resolution)) > 0) + show_profile_print_resolution(ctl, resolution); r = sd_bus_message_exit_container(m); if (r < 0) @@ -628,9 +654,6 @@ static int show_profile_print_resolutions(struct ratbagctl *ctl, if (r < 0) return r; - if (k == 0) - printf("\n"); - return 0; } @@ -702,7 +725,6 @@ static int show_profile_print(struct ratbagctl *ctl, printf("\t Index: %u\n", prop_index); - printf("\t Resolutions: "); while ((r = sd_bus_message_enter_container(reply, 'e', "sv")) > 0) { const char *property; From 124385fc315889076825dd5ed607934a36eec43d Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 19 Feb 2016 15:18:44 +1000 Subject: [PATCH 060/137] ratbagctl: print all properties Signed-off-by: Peter Hutterer --- src/ratbagctl.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/src/ratbagctl.c b/src/ratbagctl.c index f80aefff..2e83ee30 100644 --- a/src/ratbagctl.c +++ b/src/ratbagctl.c @@ -505,13 +505,42 @@ static int show_device_print(struct ratbagctl *ctl, const char *device) if (r < 0) goto exit; - r = sd_bus_message_exit_container(reply); + r = sd_bus_message_rewind(reply, 0); if (r < 0) goto exit; printf("%s - %s\n", prop_id, prop_description); printf("\t Svg: %s\n", strlen(prop_svg) > 0 ? prop_svg : ""); + while ((r = sd_bus_message_enter_container(reply, 'e', "sv")) > 0) { + const char *property; + + r = sd_bus_message_read_basic(reply, 's', &property); + if (r < 0) + goto exit; + + if (startswith(property, "Cap")) { + bool has_cap; + r = sd_bus_message_read(reply, "v", "b", &has_cap); + + printf("%23s: %s\n", property, has_cap ? "yes" : "no"); + } else { + r = sd_bus_message_skip(reply, "v"); + } + if (r < 0) + goto exit; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto exit; + } + if (r < 0) + goto exit; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto exit; + if (prop_min_index == prop_max_index) printf("\t Profiles:\n"); else if (prop_min_index + 1 == prop_max_index) @@ -608,7 +637,7 @@ static int show_profile_print_resolution(struct ratbagctl *ctl, const char *path if (r < 0) goto exit; - r = sd_bus_message_exit_container(reply); + r = sd_bus_message_rewind(reply, 0); if (r < 0) goto exit; @@ -618,6 +647,35 @@ static int show_profile_print_resolution(struct ratbagctl *ctl, const char *path printf("\t Report Rate: %uHz\n", prop_report_rate); printf("\t Resolution: %ux%udpi\n", prop_xres, prop_yres); + while ((r = sd_bus_message_enter_container(reply, 'e', "sv")) > 0) { + const char *property; + + r = sd_bus_message_read_basic(reply, 's', &property); + if (r < 0) + goto exit; + + if (startswith(property, "Cap")) { + bool has_cap; + r = sd_bus_message_read(reply, "v", "b", &has_cap); + + printf("%24s: %s\n", property, has_cap ? "yes" : "no"); + } else { + r = sd_bus_message_skip(reply, "v"); + } + if (r < 0) + goto exit; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto exit; + } + if (r < 0) + goto exit; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto exit; + printf("\n"); exit: From 4c66d7f5ba54a691f91db40acdf4facc47ec568c Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 22 Feb 2016 09:42:47 +1000 Subject: [PATCH 061/137] dbus: allow normal users to talk to ratbagd Signed-off-by: Peter Hutterer --- dbus/org.freedesktop.ratbag1.conf | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dbus/org.freedesktop.ratbag1.conf b/dbus/org.freedesktop.ratbag1.conf index cd7b8843..f4edc1e1 100644 --- a/dbus/org.freedesktop.ratbag1.conf +++ b/dbus/org.freedesktop.ratbag1.conf @@ -11,4 +11,10 @@ + + + + + + From 2fad2e3ccd4dc023b27cd1437215c238be4f7608 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 22 Feb 2016 13:29:02 +1000 Subject: [PATCH 062/137] resolution: mark the dpi/rate as changable And make sure we actually save the new value too Signed-off-by: Peter Hutterer --- src/ratbagd-resolution.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/ratbagd-resolution.c b/src/ratbagd-resolution.c index 33608a7a..45472421 100644 --- a/src/ratbagd-resolution.c +++ b/src/ratbagd-resolution.c @@ -65,6 +65,9 @@ static int ratbagd_resolution_set_report_rate(sd_bus_message *m, r = ratbag_resolution_set_report_rate(resolution->lib_resolution, rate); + if (r == 0) { + resolution->rate = rate; + } return sd_bus_reply_method_return(m, "u", r); } @@ -82,6 +85,10 @@ static int ratbagd_resolution_set_resolution(sd_bus_message *m, r = ratbag_resolution_set_dpi_xy(resolution->lib_resolution, xres, yres); + if (r == 0) { + resolution->xres = xres; + resolution->yres = yres; + } return sd_bus_reply_method_return(m, "u", r); } @@ -94,9 +101,9 @@ const sd_bus_vtable ratbagd_resolution_vtable[] = { SD_BUS_PROPERTY("CapSeparateXYResolution", "b", NULL, offsetof(struct ratbagd_resolution, capabilities.separate_xy_res), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("XResolution", "u", NULL, offsetof(struct ratbagd_resolution, xres), 0), - SD_BUS_PROPERTY("YResolution", "u", NULL, offsetof(struct ratbagd_resolution, yres), 0), - SD_BUS_PROPERTY("ReportRate", "u", NULL, offsetof(struct ratbagd_resolution, rate), 0), + SD_BUS_PROPERTY("XResolution", "u", NULL, offsetof(struct ratbagd_resolution, xres), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("YResolution", "u", NULL, offsetof(struct ratbagd_resolution, yres), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("ReportRate", "u", NULL, offsetof(struct ratbagd_resolution, rate), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_METHOD("SetReportRate", "u", "u", ratbagd_resolution_set_report_rate, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetResolution", "uu", "u", ratbagd_resolution_set_resolution, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END, From 8e8d827e0077eee4a8f0f2abd7345e6737e1360a Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 23 Feb 2016 14:37:29 +1000 Subject: [PATCH 063/137] Export button mappings over dbus Signed-off-by: Peter Hutterer --- src/ratbagctl.c | 172 ++++++++++++++++ src/ratbagd-button.c | 445 ++++++++++++++++++++++++++++++++++++++++++ src/ratbagd-profile.c | 36 +++- 3 files changed, 652 insertions(+), 1 deletion(-) diff --git a/src/ratbagctl.c b/src/ratbagctl.c index 2e83ee30..b06be8a8 100644 --- a/src/ratbagctl.c +++ b/src/ratbagctl.c @@ -715,6 +715,176 @@ static int show_profile_print_resolutions(struct ratbagctl *ctl, return 0; } +static int show_profile_print_button(struct ratbagctl *ctl, const char *path) +{ + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + unsigned int prop_index = -1, + prop_btnmap = -1; + unsigned int prop_keymap[20] = {0}; + const char *prop_type, + *prop_action_type, + *prop_special; + const char *prop_action_types[20] = {0}; + unsigned int idx = 0; + unsigned int modmap = 0; + int r; + + r = sd_bus_call_method(ctl->bus, + "org.freedesktop.ratbag1", + path, + "org.freedesktop.DBus.Properties", + "GetAll", + &error, + &reply, + "s", + "org.freedesktop.ratbag1.Button"); + if (r < 0) + goto exit; + + r = sd_bus_message_enter_container(reply, 'a', "{sv}"); + if (r < 0) + goto exit; + + while ((r = sd_bus_message_enter_container(reply, 'e', "sv")) > 0) { + const char *property; + + r = sd_bus_message_read_basic(reply, 's', &property); + if (r < 0) + goto exit; + + if (streq(property, "Index")) { + r = sd_bus_message_read(reply, "v", "u", + &prop_index); + } else if (streq(property, "Type")) { + r = sd_bus_message_read(reply, "v", "s", + &prop_type); + } else if (streq(property, "ButtonMapping")) { + r = sd_bus_message_read(reply, "v", "u", + &prop_btnmap); + } else if (streq(property, "SpecialMapping")) { + r = sd_bus_message_read(reply, "v", "s", + &prop_special); + } else if (streq(property, "KeyMapping")) { + r = sd_bus_message_enter_container(reply, 'v', "au"); + if (r < 0) + goto exit; + + r = sd_bus_message_enter_container(reply, 'a', "u"); + if (r < 0) + goto exit; + + idx = 0; + while ((r = sd_bus_message_read_basic(reply, 'u', + &prop_keymap[idx++])) > 0) + ; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto exit; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto exit; + } else if (streq(property, "ActionType")) { + r = sd_bus_message_read(reply, "v", "s", + &prop_action_type); + } else if (streq(property, "ActionTypes")) { + r = sd_bus_message_enter_container(reply, 'v', "as"); + if (r < 0) + goto exit; + + r = sd_bus_message_enter_container(reply, 'a', "s"); + if (r < 0) + goto exit; + + idx = 0; + while ((r = sd_bus_message_read_basic(reply, 's', + &prop_action_types[idx++])) > 0) + ; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto exit; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto exit; + } else { + r = sd_bus_message_skip(reply, "v"); + } + if (r < 0) + goto exit; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto exit; + } + if (r < 0) + goto exit; + + r = sd_bus_message_rewind(reply, 0); + if (r < 0) + goto exit; + + printf("button-%u\n", prop_index); + + printf("\t Index: %u\n", prop_index); + printf("\t Type: %s\n", prop_type); + printf("\t Action type: %s\n", prop_action_type); + idx = 0; + printf("\t Action types: "); + while ((prop_action_type = prop_action_types[idx++]) != NULL) + printf("%s ", prop_action_type); + printf("\n"); + printf("\t Special mapping: %s\n", prop_special); + printf("\t Button mapping: %d\n", prop_btnmap); + + printf("\t Key mapping: %d (", prop_keymap[0]); + idx = 1; + if (prop_keymap[1] == 0) { + printf("no modifiers"); + } else { + printf("modifiers "); + while ((modmap = prop_keymap[idx++]) != 0) + printf("%d ", modmap); + } + printf(")\n"); +exit: + if (r < 0) + fprintf(stderr, "Cannot show button: %s\n", + error.message ? : "Parser error"); + return r; +} + +static int show_profile_print_buttons(struct ratbagctl *ctl, + sd_bus_message *m) +{ + const char *button; + int r; + + r = sd_bus_message_enter_container(m, 'v', "ao"); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(m, 'a', "o"); + if (r < 0) + return r; + + while ((r = sd_bus_message_read_basic(m, 'o', &button)) > 0) + show_profile_print_button(ctl, button); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + return 0; +} + static int show_profile_print(struct ratbagctl *ctl, const char *device, const char *profile) @@ -795,6 +965,8 @@ static int show_profile_print(struct ratbagctl *ctl, reply, prop_active_resolution, prop_default_resolution); + } else if (streq(property, "Buttons")) { + r = show_profile_print_buttons(ctl, reply); } else { r = sd_bus_message_skip(reply, "v"); } diff --git a/src/ratbagd-button.c b/src/ratbagd-button.c index 3bb2117f..735d7ee0 100644 --- a/src/ratbagd-button.c +++ b/src/ratbagd-button.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "ratbagd.h" #include "shared-macro.h" @@ -40,9 +41,453 @@ struct ratbagd_button { char *path; }; +static int ratbagd_button_get_type(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_button *button = userdata; + const char *type = NULL; + enum ratbag_button_type t; + + t = ratbag_button_get_type(button->lib_button); + + switch(t) { + default: + log_error("Unknown button type %d\n", t); + /* fallthrough */ + case RATBAG_BUTTON_TYPE_UNKNOWN: + type = "unknown"; + break; + case RATBAG_BUTTON_TYPE_LEFT: + type = "left"; + break; + case RATBAG_BUTTON_TYPE_MIDDLE: + type = "middle"; + break; + case RATBAG_BUTTON_TYPE_RIGHT: + type = "right"; + break; + case RATBAG_BUTTON_TYPE_THUMB: + type = "thumb"; + break; + case RATBAG_BUTTON_TYPE_THUMB2: + type = "thumb2"; + break; + case RATBAG_BUTTON_TYPE_THUMB3: + type = "thumb3"; + break; + case RATBAG_BUTTON_TYPE_THUMB4: + type = "thumb4"; + break; + case RATBAG_BUTTON_TYPE_WHEEL_LEFT: + type = "wheel_left"; + break; + case RATBAG_BUTTON_TYPE_WHEEL_RIGHT: + type = "wheel_right"; + break; + case RATBAG_BUTTON_TYPE_WHEEL_CLICK: + type = "wheel_click"; + break; + case RATBAG_BUTTON_TYPE_WHEEL_UP: + type = "wheel_up"; + break; + case RATBAG_BUTTON_TYPE_WHEEL_DOWN: + type = "wheel_down"; + break; + case RATBAG_BUTTON_TYPE_WHEEL_RATCHET_MODE_SHIFT: + type = "wheel_ratchet_mode_shift"; + break; + case RATBAG_BUTTON_TYPE_EXTRA: + type = "extra"; + break; + case RATBAG_BUTTON_TYPE_SIDE: + type = "side"; + break; + case RATBAG_BUTTON_TYPE_PINKIE: + type = "pinkie"; + break; + case RATBAG_BUTTON_TYPE_PINKIE2: + type = "pinkie2"; + break; + case RATBAG_BUTTON_TYPE_RESOLUTION_CYCLE_UP: + type = "resolution_cycle_up"; + break; + case RATBAG_BUTTON_TYPE_RESOLUTION_UP: + type = "resolution_up"; + break; + case RATBAG_BUTTON_TYPE_RESOLUTION_DOWN: + type = "resolution_down"; + break; + case RATBAG_BUTTON_TYPE_PROFILE_CYCLE_UP: + type = "profile_cycle_up"; + break; + case RATBAG_BUTTON_TYPE_PROFILE_UP: + type = "profile_up"; + break; + case RATBAG_BUTTON_TYPE_PROFILE_DOWN: + type = "profile_down"; + break; + } + + return sd_bus_message_append(reply, "s", type); +} + +static int ratbagd_button_get_button(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_button *button = userdata; + unsigned int b; + + b = ratbag_button_get_button(button->lib_button); + + return sd_bus_message_append(reply, "u", b); +} + +static int ratbagd_button_set_button(sd_bus_message *m, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_button *button = userdata; + unsigned int map; + int r; + + r = sd_bus_message_read(m, "u", &map); + if (r < 0) + return r; + + if (map == 0 || map > 30) + return 0; + + r = ratbag_button_set_button(button->lib_button, map); + + return sd_bus_reply_method_return(m, "u", r); +} + +static int ratbagd_button_get_special(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_button *button = userdata; + const char *type; + enum ratbag_button_action_special special; + + special = ratbag_button_get_special(button->lib_button); + + switch(special) { + default: + log_error("Unknown special type %d\n", special); + case RATBAG_BUTTON_ACTION_SPECIAL_UNKNOWN: + type = "unknown"; + break; + case RATBAG_BUTTON_ACTION_SPECIAL_INVALID: + type = "n/a"; + break; + case RATBAG_BUTTON_ACTION_SPECIAL_DOUBLECLICK: + type = "doubleclick"; + break; + case RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_LEFT: + type = "wheel-left"; + break; + case RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_RIGHT: + type = "wheel-right"; + break; + case RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_UP: + type = "wheel-up"; + break; + case RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_DOWN: + type = "wheel-down"; + break; + case RATBAG_BUTTON_ACTION_SPECIAL_RATCHET_MODE_SWITCH: + type = "ratchet-mode-switch"; + break; + case RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_UP: + type = "resolution-cycle-up"; + break; + case RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_UP: + type = "resolution-up"; + break; + case RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_DOWN: + type = "resolution-down"; + break; + case RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_ALTERNATE: + type = "resolution-alternate"; + break; + case RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_DEFAULT: + type = "resolution-default"; + break; + case RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP: + type = "profile-cycle-up"; + break; + case RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_UP: + type = "profile-up"; + break; + case RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_DOWN: + type = "profile-down"; + break; + case RATBAG_BUTTON_ACTION_SPECIAL_SECOND_MODE: + type = "second-mode"; + break; + case RATBAG_BUTTON_ACTION_SPECIAL_BATTERY_LEVEL: + type = "battery-level"; + break; + } + + return sd_bus_message_append(reply, "s", type); +} + +static int ratbagd_button_set_special(sd_bus_message *m, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_button *button = userdata; + const char *s; + enum ratbag_button_action_special special; + int r; + + r = sd_bus_message_read(m, "s", &s); + if (r < 0) + return r; + + if (streq(s, "doubleclick")) + special = RATBAG_BUTTON_ACTION_SPECIAL_DOUBLECLICK; + else if (streq(s, "wheel-left")) + special = RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_LEFT; + else if (streq(s, "wheel-right")) + special = RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_RIGHT; + else if (streq(s, "wheel-up")) + special = RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_UP; + else if (streq(s, "wheel-down")) + special = RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_DOWN; + else if (streq(s, "ratchet-mode-switch")) + special = RATBAG_BUTTON_ACTION_SPECIAL_RATCHET_MODE_SWITCH; + else if (streq(s, "resolution-cycle-up")) + special = RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_UP; + else if (streq(s, "resolution-up")) + special = RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_UP; + else if (streq(s, "resolution-down")) + special = RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_DOWN; + else if (streq(s, "resolution-alternate")) + special = RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_ALTERNATE; + else if (streq(s, "resolution-default")) + special = RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_DEFAULT; + else if (streq(s, "profile-cycle-up")) + special = RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP; + else if (streq(s, "profile-up")) + special = RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_UP; + else if (streq(s, "profile-down")) + special = RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_DOWN; + else if (streq(s, "second-mode")) + special = RATBAG_BUTTON_ACTION_SPECIAL_SECOND_MODE; + else if (streq(s, "battery-level")) + special = RATBAG_BUTTON_ACTION_SPECIAL_BATTERY_LEVEL; + else { + log_error("Unknown button special action %s\n", s); + return 0; + } + + r = ratbag_button_set_special(button->lib_button, special); + + return sd_bus_reply_method_return(m, "u", r); +} + +static int ratbagd_button_get_key(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_button *button = userdata; + unsigned int key; + unsigned int modifiers[10] = {0}; + size_t nmodifiers = ELEMENTSOF(modifiers); + size_t i; + int r; + + /* Return an array with the first element the key, the rest + are modifiers (or 0 if unset). If no key is set, the array is + just [0] */ + + r = sd_bus_message_open_container(reply, 'a', "u"); + if (r < 0) + return r; + + key = ratbag_button_get_key(button->lib_button, + modifiers, + &nmodifiers); + + r = sd_bus_message_append(reply, "u", key); + if (r < 0) + return r; + + if (key == 0) + nmodifiers = 0; + + for (i = 0; i < nmodifiers; i++) { + r = sd_bus_message_append(reply, "u", modifiers[0]); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +static int ratbagd_button_set_key(sd_bus_message *m, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_button *button = userdata; + unsigned int key; + size_t nmodifiers = 10; + unsigned int modifiers[nmodifiers]; + int r; + + /* Expect an array with the first element the key, the rest + are modifiers (or 0 if unset). */ + + r = sd_bus_message_enter_container(m, 'a', "u"); + if (r < 0) + return r; + + r = sd_bus_message_read(m, "u", &key); + if (r < 0) + return r; + + nmodifiers = 0; + while ((r = sd_bus_message_read_basic(m, 'u', + &modifiers[nmodifiers++])) > 0) + ; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + r = ratbag_button_set_key(button->lib_button, key, modifiers, nmodifiers); + + return sd_bus_reply_method_return(m, "u", r); +} + +static int ratbagd_button_get_action_type(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_button *button = userdata; + const char *type; + + switch (ratbag_button_get_action_type(button->lib_button)) { + case RATBAG_BUTTON_ACTION_TYPE_NONE: + type = "none"; + break; + case RATBAG_BUTTON_ACTION_TYPE_BUTTON: + type = "button"; + break; + case RATBAG_BUTTON_ACTION_TYPE_KEY: + type = "key"; + break; + case RATBAG_BUTTON_ACTION_TYPE_SPECIAL: + type = "special"; + break; + case RATBAG_BUTTON_ACTION_TYPE_MACRO: + type = "macro"; + break; + case RATBAG_BUTTON_ACTION_TYPE_UNKNOWN: + type = "unknown"; + break; + } + + return sd_bus_message_append(reply, "s", type); +} + +static int ratbagd_button_get_action_types(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_button *button = userdata; + const char *types[5] = {NULL}; + const char **t; + int idx = 0; + int r; + + r = sd_bus_message_open_container(reply, 'a', "s"); + if (r < 0) + return r; + + if (ratbag_button_has_action_type(button->lib_button, + RATBAG_BUTTON_ACTION_TYPE_BUTTON)) + types[idx++] = "button"; + if (ratbag_button_has_action_type(button->lib_button, + RATBAG_BUTTON_ACTION_TYPE_KEY)) + types[idx++] = "key"; + if (ratbag_button_has_action_type(button->lib_button, + RATBAG_BUTTON_ACTION_TYPE_SPECIAL)) + types[idx++] = "special"; + if (ratbag_button_has_action_type(button->lib_button, + RATBAG_BUTTON_ACTION_TYPE_MACRO)) + types[idx++] = "macro"; + + t = types; + while (*t) { + r = sd_bus_message_append(reply, "s", *t); + if (r < 0) + return r; + t++; + } + + return sd_bus_message_close_container(reply); +} + +static int ratbagd_button_disable(sd_bus_message *m, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_button *button = userdata; + int r; + + r = sd_bus_message_read(m, ""); + if (r < 0) + return r; + + r = ratbag_button_disable(button->lib_button); + + return sd_bus_reply_method_return(m, "u", r); +} + const sd_bus_vtable ratbagd_button_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Index", "u", NULL, offsetof(struct ratbagd_button, index), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Type", "s", ratbagd_button_get_type, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ButtonMapping", "u", ratbagd_button_get_button, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("SpecialMapping", "s", ratbagd_button_get_special, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("KeyMapping", "au", ratbagd_button_get_key, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("ActionType", "s", ratbagd_button_get_action_type, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("ActionTypes", "as", ratbagd_button_get_action_types, 0, SD_BUS_VTABLE_PROPERTY_CONST), + + SD_BUS_METHOD("SetButtonMapping", "u", "u", ratbagd_button_set_button, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetSpecialMapping", "s", "u", ratbagd_button_set_special, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetKeyMapping", "au", "u", ratbagd_button_set_key, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("Disable", "", "u", ratbagd_button_disable, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END, }; diff --git a/src/ratbagd-profile.c b/src/ratbagd-profile.c index 3e463b14..77de4746 100644 --- a/src/ratbagd-profile.c +++ b/src/ratbagd-profile.c @@ -114,6 +114,39 @@ static int ratbagd_profile_get_resolutions(sd_bus *bus, return sd_bus_message_close_container(reply); } +static int ratbagd_profile_get_buttons(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_profile *profile = userdata; + struct ratbagd_button *button; + unsigned int i; + int r; + + r = sd_bus_message_open_container(reply, 'a', "o"); + if (r < 0) + return r; + + for (i = 0; i < profile->n_buttons; ++i) { + button = profile->buttons[i]; + if (!button) + continue; + + r = sd_bus_message_append(reply, + "o", + ratbagd_button_get_path(button)); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + + static int ratbagd_profile_get_active_resolution(sd_bus *bus, const char *path, const char *interface, @@ -239,6 +272,7 @@ 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", "ao", ratbagd_profile_get_resolutions, 0, 0), + SD_BUS_PROPERTY("Buttons", "ao", ratbagd_profile_get_buttons, 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), @@ -482,7 +516,7 @@ int ratbagd_profile_register_buttons(struct sd_bus *bus, sprintf(index_buffer, "p%u", profile->index); - /* register resolution interfaces */ + /* register button interfaces */ r = sd_bus_path_encode_many(&prefix, "/org/freedesktop/ratbag1/button/%/%", ratbagd_device_get_name(device), From 8a8379c7eb18640d44e733afe1de55a93acba82a Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 25 Feb 2016 15:23:58 +1000 Subject: [PATCH 064/137] button: return -1 for invalid special values Otherwise it looks like the function doesn't exist Signed-off-by: Peter Hutterer --- src/ratbagd-button.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ratbagd-button.c b/src/ratbagd-button.c index 735d7ee0..59b1c2ca 100644 --- a/src/ratbagd-button.c +++ b/src/ratbagd-button.c @@ -295,7 +295,7 @@ static int ratbagd_button_set_special(sd_bus_message *m, special = RATBAG_BUTTON_ACTION_SPECIAL_BATTERY_LEVEL; else { log_error("Unknown button special action %s\n", s); - return 0; + return sd_bus_reply_method_return(m, "u", -1); } r = ratbag_button_set_special(button->lib_button, special); From 184e2b646ca65df15a18285d2cde0c7d91e1266e Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 29 Feb 2016 09:14:22 +1000 Subject: [PATCH 065/137] Add a systemd service file We don't have dbus-activation yet, so just define it as a normal dbus service for now. Signed-off-by: Peter Hutterer --- .gitignore | 1 + Makefile.am | 9 +++++++++ configure.ac | 10 ++++++++++ ratbagd.service.in | 10 ++++++++++ 4 files changed, 30 insertions(+) create mode 100644 ratbagd.service.in diff --git a/.gitignore b/.gitignore index 59d03d4e..5a957412 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ libtool ratbagctl ratbagd stamp-* +ratbagd.service diff --git a/Makefile.am b/Makefile.am index b99755c3..faaa1d2b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -96,3 +96,12 @@ ratbagd_LDADD = \ $(LIBUDEV_LIBS) \ $(LIBSYSTEMD_LIBS) \ $(LIBRATBAG_LIBS) + +unitdir = $(SYSTEMD_UNIT_DIR) +unit_DATA = ratbagd.service + +$(unit_DATA): $(unit_DATA).in + $(AM_V_GEN)$(SED) -e 's|__BIN_PREFIX__|$(bindir)|g' < $< > $@ + +EXTRA_DIST += ratbagd.service.in +BUILT_SOURCES += ratbagd.service diff --git a/configure.ac b/configure.ac index cb647f0d..f017d8bf 100644 --- a/configure.ac +++ b/configure.ac @@ -131,6 +131,16 @@ PKG_CHECK_MODULES([LIBUDEV], [libudev]) PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd >= 227]) PKG_CHECK_MODULES([LIBRATBAG], [libratbag]) +# ------------------------------------------------------------------------------ +# options +AC_ARG_WITH([systemd-unit-dir], + AS_HELP_STRING([--with-systemd-unit-dir=DIR], + [systemd unit directory [[default=$libdir/systemd/system]]]), + [unitdir="$withval"], + [unitdir="$libdir/systemd/system"]) +SYSTEMD_UNIT_DIR=${unitdir} +AC_SUBST(SYSTEMD_UNIT_DIR) + # ------------------------------------------------------------------------------ # report diff --git a/ratbagd.service.in b/ratbagd.service.in new file mode 100644 index 00000000..053bc77f --- /dev/null +++ b/ratbagd.service.in @@ -0,0 +1,10 @@ +[Unit] +Description=Daemon to introspect and modify configuable mice + +[Service] +Type=dbus +BusName=org.freedesktop.ratbag1 +ExecStart=__BIN_PREFIX__/ratbagd + +[Install] +WantedBy=multi-user.target From c54b382775a1282ddd4200c7701029a41c7599b7 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 29 Feb 2016 09:59:51 +1000 Subject: [PATCH 066/137] Require libratbag 0.2 Signed-off-by: Peter Hutterer --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f017d8bf..af76d290 100644 --- a/configure.ac +++ b/configure.ac @@ -129,7 +129,7 @@ m4_pattern_forbid([^_?PKG_[A-Z_]+$],[*** pkg.m4 missing, please install pkg-conf PKG_CHECK_MODULES([LIBUDEV], [libudev]) PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd >= 227]) -PKG_CHECK_MODULES([LIBRATBAG], [libratbag]) +PKG_CHECK_MODULES([LIBRATBAG], [libratbag >= 0.2]) # ------------------------------------------------------------------------------ # options From d6116e00bced2c77da2fd5bbd997f36d001714ba Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 29 Feb 2016 10:07:52 +1000 Subject: [PATCH 067/137] ratbagd 0.0.1 This reverts the version number but ratbagd is nowhere near stable (because libratbag itself isn't stable yet) and the dbus API can change at any time. I'm not committing to keeping the current dbus API around for backwards compatibility reasons. Signed-off-by: Peter Hutterer --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index af76d290..005cd7af 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ AC_PREREQ([2.64]) AC_INIT([ratbagd], - [1], + [0.0.1], [http://www.github.com/libratbag/ratbagd], [ratbagd], [http://www.github.com/libratbag/ratbagd]) From 6c285fa2a1930e4e7e8449d1556a8367540122d3 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 29 Feb 2016 13:55:58 +1000 Subject: [PATCH 068/137] button: emit property change events when we update a button Signed-off-by: Peter Hutterer --- src/ratbagd-button.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/ratbagd-button.c b/src/ratbagd-button.c index 59b1c2ca..84a16223 100644 --- a/src/ratbagd-button.c +++ b/src/ratbagd-button.c @@ -169,6 +169,15 @@ static int ratbagd_button_set_button(sd_bus_message *m, r = ratbag_button_set_button(button->lib_button, map); + if (r == 0) { + sd_bus *bus = sd_bus_message_get_bus(m); + sd_bus_emit_properties_changed(bus, + button->path, + "org.freedesktop.ratbag1.Button", + "ButtonMapping", + NULL); + } + return sd_bus_reply_method_return(m, "u", r); } @@ -300,6 +309,15 @@ static int ratbagd_button_set_special(sd_bus_message *m, r = ratbag_button_set_special(button->lib_button, special); + if (r == 0) { + sd_bus *bus = sd_bus_message_get_bus(m); + sd_bus_emit_properties_changed(bus, + button->path, + "org.freedesktop.ratbag1.Button", + "SpecialMapping", + NULL); + } + return sd_bus_reply_method_return(m, "u", r); } From 9c33eede5c792edecf33125b0531a5118ce06910 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 3 Mar 2016 10:17:31 +1000 Subject: [PATCH 069/137] Add a COPYING file Signed-off-by: Peter Hutterer --- COPYING | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 COPYING diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..6f3e9ba2 --- /dev/null +++ b/COPYING @@ -0,0 +1,21 @@ +Copyright © 2015 David Herrmann +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. From a8600faeb3f3adf3fc65ddb697e1995e985c07ae Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 3 Mar 2016 15:10:11 +1000 Subject: [PATCH 070/137] button: use dash, not underscore, for button type names Signed-off-by: Peter Hutterer --- src/ratbagd-button.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/ratbagd-button.c b/src/ratbagd-button.c index 84a16223..6561f4ae 100644 --- a/src/ratbagd-button.c +++ b/src/ratbagd-button.c @@ -84,22 +84,22 @@ static int ratbagd_button_get_type(sd_bus *bus, type = "thumb4"; break; case RATBAG_BUTTON_TYPE_WHEEL_LEFT: - type = "wheel_left"; + type = "wheel-left"; break; case RATBAG_BUTTON_TYPE_WHEEL_RIGHT: - type = "wheel_right"; + type = "wheel-right"; break; case RATBAG_BUTTON_TYPE_WHEEL_CLICK: - type = "wheel_click"; + type = "wheel-click"; break; case RATBAG_BUTTON_TYPE_WHEEL_UP: - type = "wheel_up"; + type = "wheel-up"; break; case RATBAG_BUTTON_TYPE_WHEEL_DOWN: - type = "wheel_down"; + type = "wheel-down"; break; case RATBAG_BUTTON_TYPE_WHEEL_RATCHET_MODE_SHIFT: - type = "wheel_ratchet_mode_shift"; + type = "wheel-ratchet_mode_shift"; break; case RATBAG_BUTTON_TYPE_EXTRA: type = "extra"; @@ -114,22 +114,22 @@ static int ratbagd_button_get_type(sd_bus *bus, type = "pinkie2"; break; case RATBAG_BUTTON_TYPE_RESOLUTION_CYCLE_UP: - type = "resolution_cycle_up"; + type = "resolution-cycle-up"; break; case RATBAG_BUTTON_TYPE_RESOLUTION_UP: - type = "resolution_up"; + type = "resolution-up"; break; case RATBAG_BUTTON_TYPE_RESOLUTION_DOWN: - type = "resolution_down"; + type = "resolution-down"; break; case RATBAG_BUTTON_TYPE_PROFILE_CYCLE_UP: - type = "profile_cycle_up"; + type = "profile-cycle-up"; break; case RATBAG_BUTTON_TYPE_PROFILE_UP: - type = "profile_up"; + type = "profile-up"; break; case RATBAG_BUTTON_TYPE_PROFILE_DOWN: - type = "profile_down"; + type = "profile-down"; break; } From eac1e91638c83ba1ec757c22ce4769ce51f43075 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 3 Mar 2016 10:10:38 +1000 Subject: [PATCH 071/137] Add a python module to talk to ratbagd Signed-off-by: Peter Hutterer --- .gitignore | 2 +- Makefile.am | 5 + configure.ac | 1 + python/ratbagd/__init__.py | 334 +++++++++++++++++++++++++++++++++++++ 4 files changed, 341 insertions(+), 1 deletion(-) create mode 100644 python/ratbagd/__init__.py diff --git a/.gitignore b/.gitignore index 5a957412..17d95834 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,6 @@ libtool *.m4 !m4/attributes.m4 ratbagctl -ratbagd +./ratbagd stamp-* ratbagd.service diff --git a/Makefile.am b/Makefile.am index faaa1d2b..af747773 100644 --- a/Makefile.am +++ b/Makefile.am @@ -105,3 +105,8 @@ $(unit_DATA): $(unit_DATA).in EXTRA_DIST += ratbagd.service.in BUILT_SOURCES += ratbagd.service + +# ------------------------------------------------------------------------------ +# python module +dist_pkgpython_DATA = \ + python/ratbagd/__init__.py diff --git a/configure.ac b/configure.ac index 005cd7af..25efbfad 100644 --- a/configure.ac +++ b/configure.ac @@ -34,6 +34,7 @@ AC_PROG_CC_C99 AC_PATH_PROG([M4], [m4]) AC_PATH_PROG([XSLTPROC], [xsltproc]) +AM_PATH_PYTHON AS_IF([! ln --relative --help > /dev/null 2>&1], [AC_MSG_ERROR([*** ln doesn't support --relative ***])]) diff --git a/python/ratbagd/__init__.py b/python/ratbagd/__init__.py new file mode 100644 index 00000000..23dd72e4 --- /dev/null +++ b/python/ratbagd/__init__.py @@ -0,0 +1,334 @@ +# vim: set expandtab shiftwidth=4 tabstop=4: +# +# 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. + +from gi.repository import GLib +from gi.repository import Gio + +class RatbagdDBusUnavailable(BaseException): + """ + Signals DBus is unavailable or the ratbagd daemon is not available. + """ + pass + +class _RatbagdDBus(object): + def __init__(self, interface, object_path): + self._dbus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None) + self._proxy = Gio.DBusProxy.new_sync(self._dbus, + Gio.DBusProxyFlags.NONE, + None, + 'org.freedesktop.ratbag1', + object_path, + 'org.freedesktop.ratbag1.{}'.format(interface), + None) + if self._proxy.get_name_owner() == None: + raise RatbagdDBusUnavailable() + + def dbus_property(self, property): + p = self._proxy.get_cached_property(property) + if p != None: + return p.unpack() + return p + + def dbus_call(self, method, type, *value): + val = GLib.Variant("({})".format(type), value ) + self._proxy.call_sync(method, val, Gio.DBusCallFlags.NO_AUTO_START, 500, None) + +class Ratbagd(_RatbagdDBus): + """ + The ratbagd top-level object. Provides a list of devices available + through ratbagd, actual interaction with the devices is via the + RatbagdDevice, RatbagdProfile and RatbagdResolution objects. + """ + def __init__(self): + _RatbagdDBus.__init__(self, "Manager", '/org/freedesktop/ratbag1') + self._devices = [] + result = self.dbus_property("Devices") + if result != None: + self._devices = [RatbagdDevice(objpath) for objpath in result] + + @property + def devices(self): + """ + A list of RatbagdDevice objects supported by ratbagd. + """ + return self._devices + +class RatbagdDevice(_RatbagdDBus): + """ + Represents a ratbagd device. + """ + def __init__(self, object_path): + _RatbagdDBus.__init__(self, "Device", object_path) + self._devnode = self.dbus_property("Id") + self._description = self.dbus_property("Description") + self._svg = self.dbus_property("Svg") + + self._profiles = [] + self._active_profile = -1 + result = self.dbus_property("Profiles") + if result != None: + self._profiles = [RatbagdProfile(objpath) for objpath in result] + self._active_profile = self.dbus_property("ActiveProfile") + + caps = [ "switchable-resolution", + "switchable-profile", + "button-keys", + "button-macros", + "default-profile"] + self._caps = [] + for c in caps: + cname = "Cap" + "".join([n.capitalize() for n in c.split("-")]) + if self.dbus_property(cname): + self._caps.append(c) + + @property + def profiles(self): + """ + A list of RatbagdProfile objects provided by this device. + """ + return self._profiles + + @property + def description(self): + """ + The device name, usually provided by the kernel. + """ + return self._description + + @property + def svg(self): + """ + The SVG file name. This function returns the file name only, not the + absolute path to the file. + """ + return self._svg + + @property + def id(self): + """ + A unique identifier for this device. + """ + return self._devnode + + @property + def active_profile(self): + """ + The currently active profile. This function returns a RatbagdProfile + or None if no active profile was found. + """ + if self._active_profile == -1: + return None + return self._profiles[self._active_profile] + + @property + def capabilities(self): + """ + Return the capabilities of this device as a list of identifier strings. + Capabilities not present on the device are not in the list. Thus use + if "capability" is in deivce.caps: + do something + + Capabilities supported: "switchable-resolution", + "switchable-profile", "button-keys", "button-macros", + "default-profile" + """ + return self._caps + + def __eq__(self, other): + return other and self._objpath == other._objpath + +class RatbagdProfile(_RatbagdDBus): + """ + Represents a ratbagd profile + """ + def __init__(self, object_path): + _RatbagdDBus.__init__(self, "Profile", object_path) + self._objpath = object_path + self._index = self.dbus_property("Index") + + self._resolutions = [] + self._active_resolution_idx = -1 + self._default_resolution_idx = -1 + self._buttons = [] + + result = self.dbus_property("Resolutions") + if result != None: + self._resolutions = [RatbagdResolution(objpath) for objpath in result] + self._active_resolution_idx = self.dbus_property("ActiveResolution") + self._default_resolution_idx = self.dbus_property("DefaultResolution") + + result = self.dbus_property("Buttons") + if result != None: + self._buttons = [RatbagdButton(objpath) for objpath in result] + + @property + def index(self): + return self._index + + @property + def resolutions(self): + """ + A list of RatbagdResolution objects with this profile's resolutions. + """ + return self._resolutions + + @property + def active_resolution(self): + """ + The currently active resolution. This function returns a + RatbagdResolution object or None. + """ + if self._active_resolution_idx == -1: + return None + return self._resolutions[self._active_resolution_idx] + + @property + def default_resolution(self): + """ + The default resolution. This function returns a RatbagdResolution + object or None. + """ + if self._default_resolution_idx == -1: + return None + return self._resolutions[self._default_resolution_idx] + + @property + def buttons(self): + """ + A list of RatbagdButton objects with this profile's button + mappings. Note that the list of buttons differs between profiles but + the number of buttons is identical across profiles. + """ + return self._buttons + + def __eq__(self, other): + return self._objpath == other._objpath + +class RatbagdResolution(_RatbagdDBus): + """ + Represents a ratbagd resolution. + """ + def __init__(self, object_path): + _RatbagdDBus.__init__(self, "Resolution", object_path) + self._index = self.dbus_property("Index") + self._xres = self.dbus_property("XResolution") + self._yres = self.dbus_property("YResolution") + self._rate = self.dbus_property("ReportRate") + self._objpath = object_path + + caps = [ "individual-report-rate", + "separate-xy-resolution" ] + self._caps = [] + for c in caps: + cname = "Cap" + "".join([n.capitalize() for n in c.split("-")]) + if self.dbus_property(cname): + self._caps.append(c) + + @property + def resolution(self): + """Returns the tuple (xres, yres) with each resolution in DPI""" + return (self._xres, self._yres) + + @resolution.setter + def resolution(self, res): + return self.dbus_call("SetResolution", "uu", *res) + + @property + def report_rate(self): + """ + Returns the report rate in Hz. + """ + return self._rate + + @report_rate.setter + def report_rate(self, rate): + return self.dbus_call("SetReportRate", "u", rate) + + @property + def capabilities(self): + """ + Return the capabilities of this device as a list of identifier strings. + Capabilities not present on the device are not in the list. Thus use + if "capability" is in resolution.caps: + do something + + Capabilities supported: "individual-report-rate", + "separate-xy-resolution" + """ + return self._caps + + def __eq__(self, other): + return self._objpath == other._objpath + +class RatbagdButton(_RatbagdDBus): + """ + Represents a ratbagd button. + """ + def __init__(self, object_path): + _RatbagdDBus.__init__(self, "Button", object_path) + self._index = self.dbus_property("Index") + self._button = self.dbus_property("ButtonMapping") + + @property + def index(self): + return self._index + + @property + def button_type(self): + return self.dbus_property("Type") + + @property + def action_type(self): + return self.dbus_property("ActionType") + + @property + def special(self): + self._special = self.dbus_property("SpecialMapping") + return self._special + + @special.setter + def special(self, special): + return self.dbus_call("SetSpecialMapping", "s", special) + + @property + def key(self): + self._key = self.dbus_property("KeyMapping") + return self._key + + @key.setter + def key(self, key, modifiers): + return self.dbus_call("SetKeyMapping", "au", [key].append(modifiers)) + + @property + def button(self): + self._button = self.dbus_property("ButtonMapping") + return self._button + + @button.setter + def button(self, button): + return self.dbus_call("SetButtonMapping", "u", button) + + def disable(self): + return self.dbus_call("Disable", "") From 0528981a0a193ed2d0990c6d856341b849cbf897 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 3 Mar 2016 20:13:00 +1000 Subject: [PATCH 072/137] Replace ratbagctl with a python version It's a lot easier to interact with ratbagd from a python script than it is with C code. Plus this means we test the bindings whenever we use ratbagctl. Signed-off-by: Peter Hutterer --- .gitignore | 1 + Makefile.am | 23 +- python/ratbagctl.py | 184 +++++++ src/ratbagctl.c | 1164 ------------------------------------------- 4 files changed, 191 insertions(+), 1181 deletions(-) create mode 100755 python/ratbagctl.py delete mode 100644 src/ratbagctl.c diff --git a/.gitignore b/.gitignore index 17d95834..74154a6a 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ ratbagctl ./ratbagd stamp-* ratbagd.service +ratbagctl diff --git a/Makefile.am b/Makefile.am index af747773..542cf943 100644 --- a/Makefile.am +++ b/Makefile.am @@ -54,23 +54,6 @@ libshared_la_CFLAGS = \ libshared_la_LIBADD = \ -lm -# ------------------------------------------------------------------------------ -# ratbagctl - -bin_PROGRAMS += \ - ratbagctl - -ratbagctl_SOURCES = \ - src/ratbagctl.c - -ratbagctl_CFLAGS = \ - $(AM_CFLAGS) \ - $(LIBSYSTEMD_CFLAGS) - -ratbagctl_LDADD = \ - libshared.la \ - $(LIBSYSTEMD_LIBS) - # ------------------------------------------------------------------------------ # ratbagd @@ -110,3 +93,9 @@ BUILT_SOURCES += ratbagd.service # python module dist_pkgpython_DATA = \ python/ratbagd/__init__.py + +bin_SCRIPTS = \ + python/ratbagctl + +python/ratbagctl: python/ratbagctl.py + $(AM_V_GEN)$(SED) -e "s/__VERSION__/$(PACKAGE_VERSION)/" < $^ > $@ diff --git a/python/ratbagctl.py b/python/ratbagctl.py new file mode 100755 index 00000000..c86b70a9 --- /dev/null +++ b/python/ratbagctl.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python +# +# vim: set expandtab shiftwidth=4 tabstop=4: +# +# 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. + +from __future__ import print_function + +from ratbagd import * + +import sys +import argparse + +def list_devices(r, args): + for d in r.devices: + print("{:10s} {:32s}".format(d.id + ":", d.description)) + +def find_device(r, args): + dev = None + for d in r.devices: + if d.id == args.device: + dev = d + break; + if dev is None: + print("Unable to find device {}".format(args.device)) + sys.exit(1) + return dev + +def find_profile(r, args): + d = find_device(r, args) + try: + p = d.profiles[args.profile] + except IndexError: + print("Invalid profile index {}".format(args.profile)) + sys.exit(1) + return p, d + +def find_resolution(r, args): + p, d = find_profile(r, args) + try: + r = p.resolutions[args.resolution] + except IndexError: + print("Invalid resolution index {}".format(args.resolution)) + sys.exit(1) + return r, p, d + +def find_button(r, args): + p, d = find_profile(r, args) + try: + b = p.buttons[args.button] + except IndexError: + print("Invalid button index {}".format(args.button)) + sys.exit(1) + return b, p, d + +def show_device(r, args): + d = find_device(r, args) + + print("{} - {}".format(d.id, d.description)) + print(" SVG: {}".format(d.svg)) + print(" Capabilities: {}".format(", ".join(d.capabilities))) + print("Number of Profiles: {}".format(len(d.profiles))) + active = -1 + for i, p in enumerate(d.profiles): + if p == d.active_profile: + active = i + break + print(" Active Profile: {}".format(active)) + +def show_profile(r, args): + p, d = find_profile(r, args) + + print("Profile {} on {} ({})".format(args.profile, d.id, d.description)) + print(" Number of Buttons: {}".format(len(p.buttons))) + print("Number of Resolutions: {}".format(len(p.resolutions))) + active, default = -1, -1 + for i, r in enumerate(p.resolutions): + if p.active_resolution == r: + active = i + if p.default_resolution == r: + default = i + + print(" Active Resolution: {}".format(active)) + print(" Default Resolution: {}".format(default)) + +def show_resolution(r, args): + r, p, d = find_resolution(r, args) + + print("Resolution {} on Profile {} on {} ({})".format(args.resolution, + args.profile, + d.id, + d.description)) + print(" Report Rate: {}Hz".format(r.report_rate)) + if "separate-xy-resolution" in r.capabilities: + print(" Resolution: {}x{}dpi".format(r.resolution)) + else: + print(" Resolution: {}dpi".format(r.resolution[0])) + + print(" Capabilities: {}".format(", ".join(r.capabilities))) + +def show_button(r, args): + b, p, d = find_button(r, args) + + print("Button {} on Profile {} on {} ({})".format(args.button, + args.profile, + d.id, + d.description)) + + print(" Type: {}".format(b.button_type)) + print(" Action Type: {}".format(b.action_type)) + + if b.action_type == "button": + print(" Button Mapping: {}".format(b.button)) + elif b.action_type == "key": + print(" Key Mapping: {}".format(b.key)) + elif b.action_type == "special": + print("Special Mapping: {}".format(b.special)) + +def make_parser(): + parser = argparse.ArgumentParser(description="Inspect and modify configurable mice") + parser.add_argument("-V", "--version", action="version", version="__VERSION__") + subs = parser.add_subparsers(title="COMMANDS", help=None) + + list = subs.add_parser("list-devices", help="List available configurable mice") + list.set_defaults(func=list_devices) + + show = subs.add_parser("show-device", help="Show device information") + show.add_argument("device", metavar="event0", help="The device node") + show.set_defaults(func=show_device) + + profile = subs.add_parser("show-profile", help="Show profile information") + profile.add_argument("device", metavar="event0", help="The device node") + profile.add_argument("profile", metavar="0", help="The profile index", type=int) + profile.set_defaults(func=show_profile) + + resolution = subs.add_parser("show-resolution", help="Show resolution information") + resolution.add_argument("device", metavar="event0", help="The device node") + resolution.add_argument("profile", metavar="0", help="The profile index", type=int) + resolution.add_argument("resolution", metavar="0", help="The resolution index", type=int) + resolution.set_defaults(func=show_resolution) + + button = subs.add_parser("show-button", help="Show button information") + button.add_argument("device", metavar="event0", help="The device node") + button.add_argument("profile", metavar="0", help="The profile index", type=int) + button.add_argument("button", metavar="0", help="The button index", type=int) + button.set_defaults(func=show_button) + + return parser + +def main(argv): + cmd = make_parser().parse_args(argv) + + try: + r = Ratbagd() + if not r.devices: + print("No devices available.") + except RatbagdDBusUnavailable: + print("Unable to connect to ratbagd over dbus") + + cmd.func(r, cmd) + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/src/ratbagctl.c b/src/ratbagctl.c deleted file mode 100644 index b06be8a8..00000000 --- a/src/ratbagctl.c +++ /dev/null @@ -1,1164 +0,0 @@ -/*** - This file is part of ratbagd. - - Copyright 2015 David Herrmann - - 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 "shared-macro.h" - -struct ratbagctl { - sd_bus *bus; -}; - -static int verb_help(struct ratbagctl *ctl, int argc, char **argv); - -static struct ratbagctl *ratbagctl_free(struct ratbagctl *ctl) -{ - if (!ctl) - return NULL; - - ctl->bus = sd_bus_unref(ctl->bus); - - return mfree(ctl); -} - -DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagctl *, ratbagctl_free); - -static int ratbagctl_new(struct ratbagctl **out) -{ - _cleanup_(ratbagctl_freep) struct ratbagctl *ctl = NULL; - int r; - - ctl = calloc(1, sizeof(*ctl)); - if (!ctl) - return -ENOMEM; - - r = sd_bus_open_system(&ctl->bus); - if (r < 0) - return r; - - *out = ctl; - ctl = NULL; - return 0; -} - -static int get_device_path(struct ratbagctl *ctl, - const char *device_name, - char **out_path, - sd_bus_error *error) -{ - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - const char *device_path = NULL; - char *path; - int r; - - if (device_name) { - r = sd_bus_call_method(ctl->bus, - "org.freedesktop.ratbag1", - "/org/freedesktop/ratbag1", - "org.freedesktop.ratbag1.Manager", - "GetDeviceByName", - error, - &reply, - "s", - device_name); - if (r < 0) - return r; - - r = sd_bus_message_read(reply, "o", &device_path); - if (r < 0) - return r; - } else { - r = sd_bus_call_method(ctl->bus, - "org.freedesktop.ratbag1", - "/org/freedesktop/ratbag1", - "org.freedesktop.DBus.Properties", - "Get", - error, - &reply, - "ss", - "org.freedesktop.ratbag1.Manager", - "Devices"); - if (r < 0) - return r; - - r = sd_bus_message_enter_container(reply, 'v', "ao"); - if (r < 0) - return r; - - r = sd_bus_message_enter_container(reply, 'a', "o"); - if (r < 0) - return r; - - while ((r = sd_bus_message_read_basic(reply, 'o', &path)) > 0) { - if (!device_path) - device_path = path; - } - if (r < 0) - return r; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - return r; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - return r; - - if (!device_path) - return -ENXIO; - } - - assert(device_path); - - path = strdup(device_path); - if (!path) - return -ENOMEM; - - *out_path = path; - return 0; -} - -static int get_profile_path(struct ratbagctl *ctl, - const char *device_name, - const char *profile_name, - char **out_path, - sd_bus_error *error) -{ - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply2 = NULL; - _cleanup_(freep) char *device_path = NULL; - const char *profile_path = NULL; - unsigned int profile_index; - char *path; - int r; - - r = get_device_path(ctl, device_name, &device_path, error); - if (r < 0) - return r; - - if (profile_name) { - r = safe_atou(profile_name, &profile_index); - if (r < 0) - return -ENXIO; - - r = sd_bus_call_method(ctl->bus, - "org.freedesktop.ratbag1", - device_path, - "org.freedesktop.ratbag1.Device", - "GetProfileByIndex", - error, - &reply2, - "u", - profile_index); - if (r < 0) - return r; - - r = sd_bus_message_read(reply2, "o", &profile_path); - if (r < 0) - return r; - } else { - r = sd_bus_call_method(ctl->bus, - "org.freedesktop.ratbag1", - device_path, - "org.freedesktop.DBus.Properties", - "Get", - error, - &reply2, - "ss", - "org.freedesktop.ratbag1.Device", - "ActiveProfile"); - if (r < 0) - return r; - - r = sd_bus_message_read(reply2, "v", "o", &profile_path); - if (r < 0) - return r; - - if (streq(profile_path, "/")) { - reply2 = sd_bus_message_unref(reply2); - - r = sd_bus_call_method(ctl->bus, - "org.freedesktop.ratbag1", - device_path, - "org.freedesktop.DBus.Properties", - "Get", - error, - &reply2, - "ss", - "org.freedesktop.ratbag1.Device", - "DefaultProfile"); - if (r < 0) - return r; - - r = sd_bus_message_read(reply2, "v", "o", &profile_path); - if (r < 0) - return r; - - if (streq(profile_path, "/")) - return -ENXIO; - } - } - - assert(profile_path); - - path = strdup(profile_path); - if (!path) - return -ENOMEM; - - *out_path = path; - return 0; -} - -static int list_devices_show(struct ratbagctl *ctl, const char *path) -{ - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - const char *prop_id = NULL, *prop_description = NULL; - int r; - - r = sd_bus_call_method(ctl->bus, - "org.freedesktop.ratbag1", - path, - "org.freedesktop.DBus.Properties", - "GetAll", - &error, - &reply, - "s", - "org.freedesktop.ratbag1.Device"); - if (r < 0) - return r; - - r = sd_bus_message_enter_container(reply, 'a', "{sv}"); - if (r < 0) - return r; - - while ((r = sd_bus_message_enter_container(reply, 'e', "sv")) > 0) { - const char *property; - - r = sd_bus_message_read_basic(reply, 's', &property); - if (r < 0) - return r; - - if (streq(property, "Id")) { - r = sd_bus_message_read(reply, "v", "s", - &prop_id); - } else if (streq(property, "Description")) { - r = sd_bus_message_read(reply, "v", "s", - &prop_description); - } else { - r = sd_bus_message_skip(reply, "v"); - } - if (r < 0) - return r; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - return r; - } - if (r < 0) - return r; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - return r; - - printf("%10s %-32s\n", prop_id, prop_description); - return 0; -} - -static int list_devices_all(struct ratbagctl *ctl) -{ - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - unsigned int k = 0; - const char *path; - int r; - - r = sd_bus_call_method(ctl->bus, - "org.freedesktop.ratbag1", - "/org/freedesktop/ratbag1", - "org.freedesktop.DBus.Properties", - "Get", - &error, - &reply, - "ss", - "org.freedesktop.ratbag1.Manager", - "Devices"); - if (r < 0) - goto exit; - - r = sd_bus_message_enter_container(reply, 'v', "ao"); - if (r < 0) - goto exit; - - r = sd_bus_message_enter_container(reply, 'a', "o"); - if (r < 0) - goto exit; - - printf("%10s %-32s\n", "DEVICE", "DESCRIPTION"); - - while ((r = sd_bus_message_read_basic(reply, 'o', &path)) > 0) { - r = list_devices_show(ctl, path); - if (r < 0) - goto exit; - - ++k; - } - if (r < 0) - goto exit; - - printf("\n%u device%s listed.\n", k, k > 1 ? "s" : ""); - - r = sd_bus_message_exit_container(reply); - if (r < 0) - goto exit; - - r = sd_bus_message_exit_container(reply); -exit: - if (r < 0) - fprintf(stderr, "Cannot list devices: %s\n", - error.message ? : "Parser error"); - return r; -} - -static int verb_list_devices(struct ratbagctl *ctl, int argc, char **argv) -{ - static const struct option options[] = { - {}, - }; - int c; - - while ((c = getopt_long(argc, argv, "+", options, NULL)) >= 0) { - switch (c) { - default: - return -EINVAL; - } - } - - if (argv[optind]) { - fprintf(stderr, "Command does not take arguments\n"); - return -EINVAL; - } - - return list_devices_all(ctl); -} - -static int show_device_get_profile_index(struct ratbagctl *ctl, - const char *path, - unsigned int *out_index) -{ - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - int r; - - if (streq(path, "/")) { - *out_index = -1; - return 0; - } - - r = sd_bus_call_method(ctl->bus, - "org.freedesktop.ratbag1", - path, - "org.freedesktop.DBus.Properties", - "Get", - &error, - &reply, - "ss", - "org.freedesktop.ratbag1.Profile", - "Index"); - if (r < 0) - return r; - - r = sd_bus_message_enter_container(reply, 'v', "u"); - if (r < 0) - return r; - - r = sd_bus_message_read_basic(reply, 'u', out_index); - if (r < 0) - return r; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - return r; - - return 0; -} - -static int show_device_print(struct ratbagctl *ctl, const char *device) -{ - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - unsigned int prop_min_index = 0, prop_max_index = 0; - unsigned int prop_active_profile = -1; - const char *prop_id = NULL, *prop_description = NULL, *prop_svg = NULL; - _cleanup_(freep) char *path = NULL; - int r; - - r = get_device_path(ctl, device, &path, &error); - if (r < 0) - goto exit; - - r = sd_bus_call_method(ctl->bus, - "org.freedesktop.ratbag1", - path, - "org.freedesktop.DBus.Properties", - "GetAll", - &error, - &reply, - "s", - "org.freedesktop.ratbag1.Device"); - if (r < 0) - goto exit; - - r = sd_bus_message_enter_container(reply, 'a', "{sv}"); - if (r < 0) - goto exit; - - while ((r = sd_bus_message_enter_container(reply, 'e', "sv")) > 0) { - const char *property, *profile; - - r = sd_bus_message_read_basic(reply, 's', &property); - if (r < 0) - goto exit; - - if (streq(property, "Id")) { - r = sd_bus_message_read(reply, "v", "s", - &prop_id); - } else if (streq(property, "Description")) { - r = sd_bus_message_read(reply, "v", "s", - &prop_description); - } else if (streq(property, "Svg")) { - r = sd_bus_message_read(reply, "v", "s", &prop_svg); - } else if (streq(property, "Profiles")) { - r = sd_bus_message_enter_container(reply, 'v', "ao"); - if (r < 0) - goto exit; - - r = sd_bus_message_enter_container(reply, 'a', "o"); - if (r < 0) - goto exit; - - while ((r = sd_bus_message_read_basic(reply, - 'o', - &profile)) > 0) { - unsigned int index; - - r = show_device_get_profile_index(ctl, - profile, - &index); - if (r < 0) - goto exit; - - if (index < prop_min_index) - prop_min_index = index; - if (index >= prop_max_index) - prop_max_index = index + 1; - } - if (r < 0) - goto exit; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - goto exit; - - r = sd_bus_message_exit_container(reply); - } else if (streq(property, "ActiveProfile")) { - r = sd_bus_message_read(reply, "v", "u", &prop_active_profile); - if (r < 0) - goto exit; - } else { - r = sd_bus_message_skip(reply, "v"); - } - if (r < 0) - goto exit; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - goto exit; - } - if (r < 0) - goto exit; - - r = sd_bus_message_rewind(reply, 0); - if (r < 0) - goto exit; - - printf("%s - %s\n", prop_id, prop_description); - printf("\t Svg: %s\n", strlen(prop_svg) > 0 ? prop_svg : ""); - - while ((r = sd_bus_message_enter_container(reply, 'e', "sv")) > 0) { - const char *property; - - r = sd_bus_message_read_basic(reply, 's', &property); - if (r < 0) - goto exit; - - if (startswith(property, "Cap")) { - bool has_cap; - r = sd_bus_message_read(reply, "v", "b", &has_cap); - - printf("%23s: %s\n", property, has_cap ? "yes" : "no"); - } else { - r = sd_bus_message_skip(reply, "v"); - } - if (r < 0) - goto exit; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - goto exit; - } - if (r < 0) - goto exit; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - goto exit; - - if (prop_min_index == prop_max_index) - printf("\t Profiles:\n"); - else if (prop_min_index + 1 == prop_max_index) - printf("\t Profiles: %u\n", prop_min_index); - else - printf("\t Profiles: %u - %u\n", - prop_min_index, prop_max_index - 1); - - if (prop_active_profile == (unsigned int)-1) - printf("\t Active Profile: (unknown)\n"); - else - printf("\t Active Profile: %u\n", prop_active_profile); - -exit: - if (r < 0) - fprintf(stderr, "Cannot show device: %s\n", - error.message ? : "Parser error"); - return r; -} - -static int verb_show_device(struct ratbagctl *ctl, int argc, char **argv) -{ - static const struct option options[] = { - {}, - }; - const char *device; - int c; - - while ((c = getopt_long(argc, argv, "+", options, NULL)) >= 0) { - switch (c) { - default: - return -EINVAL; - } - } - - device = argv[optind]; - - return show_device_print(ctl, device); -} - -static int show_profile_print_resolution(struct ratbagctl *ctl, const char *path) -{ - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - unsigned int prop_index = -1, - prop_report_rate = -1, - prop_xres = -1, - prop_yres = -1; - int r; - - r = sd_bus_call_method(ctl->bus, - "org.freedesktop.ratbag1", - path, - "org.freedesktop.DBus.Properties", - "GetAll", - &error, - &reply, - "s", - "org.freedesktop.ratbag1.Resolution"); - if (r < 0) - goto exit; - - r = sd_bus_message_enter_container(reply, 'a', "{sv}"); - if (r < 0) - goto exit; - - while ((r = sd_bus_message_enter_container(reply, 'e', "sv")) > 0) { - const char *property; - - r = sd_bus_message_read_basic(reply, 's', &property); - if (r < 0) - goto exit; - - if (streq(property, "Index")) { - r = sd_bus_message_read(reply, "v", "u", - &prop_index); - } else if (streq(property, "ReportRate")) { - r = sd_bus_message_read(reply, "v", "u", - &prop_report_rate); - } else if (streq(property, "XResolution")) { - r = sd_bus_message_read(reply, "v", "u", &prop_xres); - } else if (streq(property, "YResolution")) { - r = sd_bus_message_read(reply, "v", "u", &prop_yres); - } else { - r = sd_bus_message_skip(reply, "v"); - } - if (r < 0) - goto exit; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - goto exit; - } - if (r < 0) - goto exit; - - r = sd_bus_message_rewind(reply, 0); - if (r < 0) - goto exit; - - printf("resolution-%u\n", prop_index); - - printf("\t Index: %u\n", prop_index); - printf("\t Report Rate: %uHz\n", prop_report_rate); - printf("\t Resolution: %ux%udpi\n", prop_xres, prop_yres); - - while ((r = sd_bus_message_enter_container(reply, 'e', "sv")) > 0) { - const char *property; - - r = sd_bus_message_read_basic(reply, 's', &property); - if (r < 0) - goto exit; - - if (startswith(property, "Cap")) { - bool has_cap; - r = sd_bus_message_read(reply, "v", "b", &has_cap); - - printf("%24s: %s\n", property, has_cap ? "yes" : "no"); - } else { - r = sd_bus_message_skip(reply, "v"); - } - if (r < 0) - goto exit; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - goto exit; - } - if (r < 0) - goto exit; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - goto exit; - - printf("\n"); - -exit: - if (r < 0) - fprintf(stderr, "Cannot show resolution: %s\n", - error.message ? : "Parser error"); - return r; -} - -static int show_profile_print_resolutions(struct ratbagctl *ctl, - sd_bus_message *m, - unsigned int active_resolution, - unsigned int default_resolution) -{ - const char *resolution; - int r; - - r = sd_bus_message_enter_container(m, 'v', "ao"); - if (r < 0) - return r; - - r = sd_bus_message_enter_container(m, 'a', "o"); - if (r < 0) - return r; - - while ((r = sd_bus_message_read_basic(m, 'o', &resolution)) > 0) - show_profile_print_resolution(ctl, resolution); - - r = sd_bus_message_exit_container(m); - if (r < 0) - return r; - - r = sd_bus_message_exit_container(m); - if (r < 0) - return r; - - return 0; -} - -static int show_profile_print_button(struct ratbagctl *ctl, const char *path) -{ - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - unsigned int prop_index = -1, - prop_btnmap = -1; - unsigned int prop_keymap[20] = {0}; - const char *prop_type, - *prop_action_type, - *prop_special; - const char *prop_action_types[20] = {0}; - unsigned int idx = 0; - unsigned int modmap = 0; - int r; - - r = sd_bus_call_method(ctl->bus, - "org.freedesktop.ratbag1", - path, - "org.freedesktop.DBus.Properties", - "GetAll", - &error, - &reply, - "s", - "org.freedesktop.ratbag1.Button"); - if (r < 0) - goto exit; - - r = sd_bus_message_enter_container(reply, 'a', "{sv}"); - if (r < 0) - goto exit; - - while ((r = sd_bus_message_enter_container(reply, 'e', "sv")) > 0) { - const char *property; - - r = sd_bus_message_read_basic(reply, 's', &property); - if (r < 0) - goto exit; - - if (streq(property, "Index")) { - r = sd_bus_message_read(reply, "v", "u", - &prop_index); - } else if (streq(property, "Type")) { - r = sd_bus_message_read(reply, "v", "s", - &prop_type); - } else if (streq(property, "ButtonMapping")) { - r = sd_bus_message_read(reply, "v", "u", - &prop_btnmap); - } else if (streq(property, "SpecialMapping")) { - r = sd_bus_message_read(reply, "v", "s", - &prop_special); - } else if (streq(property, "KeyMapping")) { - r = sd_bus_message_enter_container(reply, 'v', "au"); - if (r < 0) - goto exit; - - r = sd_bus_message_enter_container(reply, 'a', "u"); - if (r < 0) - goto exit; - - idx = 0; - while ((r = sd_bus_message_read_basic(reply, 'u', - &prop_keymap[idx++])) > 0) - ; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - goto exit; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - goto exit; - } else if (streq(property, "ActionType")) { - r = sd_bus_message_read(reply, "v", "s", - &prop_action_type); - } else if (streq(property, "ActionTypes")) { - r = sd_bus_message_enter_container(reply, 'v', "as"); - if (r < 0) - goto exit; - - r = sd_bus_message_enter_container(reply, 'a', "s"); - if (r < 0) - goto exit; - - idx = 0; - while ((r = sd_bus_message_read_basic(reply, 's', - &prop_action_types[idx++])) > 0) - ; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - goto exit; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - goto exit; - } else { - r = sd_bus_message_skip(reply, "v"); - } - if (r < 0) - goto exit; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - goto exit; - } - if (r < 0) - goto exit; - - r = sd_bus_message_rewind(reply, 0); - if (r < 0) - goto exit; - - printf("button-%u\n", prop_index); - - printf("\t Index: %u\n", prop_index); - printf("\t Type: %s\n", prop_type); - printf("\t Action type: %s\n", prop_action_type); - idx = 0; - printf("\t Action types: "); - while ((prop_action_type = prop_action_types[idx++]) != NULL) - printf("%s ", prop_action_type); - printf("\n"); - printf("\t Special mapping: %s\n", prop_special); - printf("\t Button mapping: %d\n", prop_btnmap); - - printf("\t Key mapping: %d (", prop_keymap[0]); - idx = 1; - if (prop_keymap[1] == 0) { - printf("no modifiers"); - } else { - printf("modifiers "); - while ((modmap = prop_keymap[idx++]) != 0) - printf("%d ", modmap); - } - printf(")\n"); -exit: - if (r < 0) - fprintf(stderr, "Cannot show button: %s\n", - error.message ? : "Parser error"); - return r; -} - -static int show_profile_print_buttons(struct ratbagctl *ctl, - sd_bus_message *m) -{ - const char *button; - int r; - - r = sd_bus_message_enter_container(m, 'v', "ao"); - if (r < 0) - return r; - - r = sd_bus_message_enter_container(m, 'a', "o"); - if (r < 0) - return r; - - while ((r = sd_bus_message_read_basic(m, 'o', &button)) > 0) - show_profile_print_button(ctl, button); - - r = sd_bus_message_exit_container(m); - if (r < 0) - return r; - - r = sd_bus_message_exit_container(m); - if (r < 0) - return r; - - return 0; -} - -static int show_profile_print(struct ratbagctl *ctl, - const char *device, - const char *profile) -{ - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - _cleanup_(freep) char *path = NULL; - unsigned int prop_index = -1, prop_active_resolution = -1; - unsigned int prop_default_resolution = -1; - int r; - - r = get_profile_path(ctl, device, profile, &path, &error); - if (r < 0) - goto exit; - - r = sd_bus_call_method(ctl->bus, - "org.freedesktop.ratbag1", - path, - "org.freedesktop.DBus.Properties", - "GetAll", - &error, - &reply, - "s", - "org.freedesktop.ratbag1.Profile"); - if (r < 0) - goto exit; - - r = sd_bus_message_enter_container(reply, 'a', "{sv}"); - if (r < 0) - goto exit; - - while ((r = sd_bus_message_enter_container(reply, 'e', "sv")) > 0) { - const char *property; - - r = sd_bus_message_read_basic(reply, 's', &property); - if (r < 0) - goto exit; - - if (streq(property, "Index")) { - r = sd_bus_message_read(reply, "v", "u", - &prop_index); - } else if (streq(property, "ActiveResolution")) { - r = sd_bus_message_read(reply, "v", "u", - &prop_active_resolution); - } else if (streq(property, "DefaultResolution")) { - r = sd_bus_message_read(reply, "v", "u", - &prop_default_resolution); - } else { - r = sd_bus_message_skip(reply, "v"); - } - if (r < 0) - goto exit; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - goto exit; - } - if (r < 0) - goto exit; - - r = sd_bus_message_rewind(reply, 0); - if (r < 0) - goto exit; - - printf("profile-%u\n", prop_index); - - printf("\t Index: %u\n", prop_index); - - while ((r = sd_bus_message_enter_container(reply, 'e', "sv")) > 0) { - const char *property; - - r = sd_bus_message_read_basic(reply, 's', &property); - if (r < 0) - goto exit; - - if (streq(property, "Resolutions")) { - r = show_profile_print_resolutions(ctl, - reply, - prop_active_resolution, - prop_default_resolution); - } else if (streq(property, "Buttons")) { - r = show_profile_print_buttons(ctl, reply); - } else { - r = sd_bus_message_skip(reply, "v"); - } - if (r < 0) - goto exit; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - goto exit; - } - if (r < 0) - goto exit; - - r = sd_bus_message_exit_container(reply); -exit: - if (r < 0) - fprintf(stderr, "Cannot show device: %s\n", - error.message ? : "Parser error"); - return r; -} - -static int verb_show_profile(struct ratbagctl *ctl, int argc, char **argv) -{ - static const struct option options[] = { - { "device", required_argument, NULL, 'd' }, - {}, - }; - const char *device = NULL, *profile = NULL; - int c; - - while ((c = getopt_long(argc, argv, "+d:", options, NULL)) >= 0) { - switch (c) { - case 'd': - device = optarg; - break; - default: - return -EINVAL; - } - } - - profile = argv[optind]; - - return show_profile_print(ctl, device, profile); -} - -static const struct { - const char *verb; - const char *help; - int (*dispatch) (struct ratbagctl *ctl, int argc, char **argv); - void (*long_help) (void); -} verbs[] = { - { "list-devices", "List available configurable mice", verb_list_devices, NULL }, - { "show-device", "Show device information", verb_show_device, NULL }, - { "show-profile", "Show profile information", verb_show_profile, NULL }, - { "help", "Show help for a command", verb_help, NULL }, - {}, -}; - -static void help(void) -{ - unsigned int i; - - printf("%s [OPTIONS..] COMMAND [OPTIONS..]\n\n" - "Query or modify configurable mice.\n\n" - "Commands:\n", - program_invocation_short_name); - - for (i = 0; i < ELEMENTSOF(verbs); ++i) { - if (verbs[i].help != NULL) - printf(" %-12s %s\n", verbs[i].verb, verbs[i].help); - } -} - -static int verb_help(struct ratbagctl *ctl, int argc, char **argv) -{ - static const struct option options[] = { - {}, - }; - const char *verb; - unsigned int i; - int c; - - while ((c = getopt_long(argc, argv, "+", options, NULL)) >= 0) { - switch (c) { - default: - return -EINVAL; - } - } - - verb = argv[optind]; - if (!verb) { - help(); - return 1; - } else { - for (i = 0; i < ELEMENTSOF(verbs); ++i) { - if (!streq_ptr(verb, verbs[i].verb)) - continue; - - if (verbs[i].long_help) - verbs[i].long_help(); - else - printf("%s: No help available for '%s'\n", - program_invocation_short_name, verb); - - return 1; - } - } - - fprintf(stderr, "%s: Unknown verb '%s'\n", program_invocation_short_name, verb); - return 1; -} - -static void version(void) -{ - printf("%s\n", VERSION); -} - -static int ratbagctl_dispatch(struct ratbagctl *ctl, int argc, char **argv) -{ - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, - {}, - }; - char *fake[] = { (char*)verbs[0].verb, NULL }; - const char *verb; - unsigned int i; - int c; - - /* '+' makes getopt_long() stop at the first non-argument */ - while ((c = getopt_long(argc, argv, "+hV", options, NULL)) >= 0) { - switch (c) { - case 'h': - help(); - return 1; - case 'V': - version(); - return 1; - default: - return -EINVAL; - } - } - - verb = argv[optind]; - if (!verb) { - assert(argc - optind == 0); - - argc = ELEMENTSOF(fake) - 1; - argv = fake; - verb = fake[0]; - optind = 0; - - assert(verb); - } - - for (i = 0; i < ELEMENTSOF(verbs); ++i) { - if (!streq_ptr(verb, verbs[i].verb)) - continue; - - argc -= optind; - argv += optind; - optind = 0; - - return verbs[i].dispatch(ctl, argc, argv); - } - - fprintf(stderr, "%s: Missing or unknown command\n", - program_invocation_short_name); - - return -EINVAL; -} - -int main(int argc, char **argv) -{ - struct ratbagctl *ctl = NULL; - int r; - - r = ratbagctl_new(&ctl); - if (r < 0) - goto exit; - - r = ratbagctl_dispatch(ctl, argc, argv); - -exit: - ratbagctl_free(ctl); - - if (r < 0) { - errno = -r; - fprintf(stderr, "%s: Failed: %m\n", - program_invocation_short_name); - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} From 212ab08c15d6256f8533998f10d2b3442dd70ec8 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 4 Mar 2016 08:30:10 +1000 Subject: [PATCH 073/137] device: export the full path to the SVG as well Exporting just the filename requires the caller to know where that file sits. That's useful for things like e.g. icons where callers may several sets to chose from but here most callers will just use the default svg provided by libratbag. Export that, so that we don't have build-time dependencies in the callers just for that single path. Signed-off-by: Peter Hutterer --- configure.ac | 3 +++ python/ratbagd/__init__.py | 9 +++++++++ src/ratbagd-device.c | 26 ++++++++++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/configure.ac b/configure.ac index 25efbfad..a3147d95 100644 --- a/configure.ac +++ b/configure.ac @@ -132,6 +132,9 @@ PKG_CHECK_MODULES([LIBUDEV], [libudev]) PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd >= 227]) PKG_CHECK_MODULES([LIBRATBAG], [libratbag >= 0.2]) +libratbag_data_dir=`$PKG_CONFIG --variable pkgdatadir libratbag` +AC_DEFINE_UNQUOTED([LIBRATBAG_DATA_DIR], ["$libratbag_data_dir"], [Directory for libratbag's SVG files]) + # ------------------------------------------------------------------------------ # options AC_ARG_WITH([systemd-unit-dir], diff --git a/python/ratbagd/__init__.py b/python/ratbagd/__init__.py index 23dd72e4..a3c6271b 100644 --- a/python/ratbagd/__init__.py +++ b/python/ratbagd/__init__.py @@ -84,6 +84,7 @@ class RatbagdDevice(_RatbagdDBus): self._devnode = self.dbus_property("Id") self._description = self.dbus_property("Description") self._svg = self.dbus_property("Svg") + self._svg_path = self.dbus_property("SvgPath") self._profiles = [] self._active_profile = -1 @@ -125,6 +126,14 @@ class RatbagdDevice(_RatbagdDBus): """ return self._svg + @property + def svg_path(self): + """ + The absolute SVG path. This function returns the full path to the + svg file. + """ + return self._svg_path + @property def id(self): """ diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 2f4dc3af..3fee6209 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -167,6 +168,30 @@ static int ratbagd_device_get_svg(sd_bus *bus, return sd_bus_message_append(reply, "s", svg); } +static int ratbagd_device_get_svg_path(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_device *device = userdata; + char svg_path[PATH_MAX] = {0}; + const char *svg; + + svg = ratbag_device_get_svg_name(device->lib_device); + if (!svg) { + log_error("Unable to fetch SVG for %s\n", + ratbagd_device_get_name(device)); + goto out; + } + + sprintf(svg_path, "%s/%s", LIBRATBAG_DATA_DIR, svg); + +out: + return sd_bus_message_append(reply, "s", svg_path); +} static int ratbagd_device_get_profiles(sd_bus *bus, const char *path, @@ -267,6 +292,7 @@ const sd_bus_vtable ratbagd_device_vtable[] = { SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Description", "s", ratbagd_device_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Svg", "s", ratbagd_device_get_svg, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SvgPath", "s", ratbagd_device_get_svg_path, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Profiles", "ao", ratbagd_device_get_profiles, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ActiveProfile", "u", ratbagd_device_get_active_profile, 0, 0), SD_BUS_METHOD("GetProfileByIndex", "u", "o", ratbagd_device_get_profile_by_index, SD_BUS_VTABLE_UNPRIVILEGED), From 654956baa6990270cd0449e28f8af2acd034935c Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 4 Mar 2016 14:19:03 +1000 Subject: [PATCH 074/137] Fix distcheck Signed-off-by: Peter Hutterer --- Makefile.am | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile.am b/Makefile.am index 542cf943..4f0e327c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -98,4 +98,8 @@ bin_SCRIPTS = \ python/ratbagctl python/ratbagctl: python/ratbagctl.py + $(AM_V_GEN)$(MKDIR_P) python $(AM_V_GEN)$(SED) -e "s/__VERSION__/$(PACKAGE_VERSION)/" < $^ > $@ + +EXTRA_DIST += python/ratbagctl.py +BUILT_SOURCES += python/ratbagctl From aceef4d0d049addfc71ee0c92205f436604546f0 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 4 Mar 2016 14:27:18 +1000 Subject: [PATCH 075/137] ratbagd 0.0.2 Signed-off-by: Peter Hutterer --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index a3147d95..6a05dbc2 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ AC_PREREQ([2.64]) AC_INIT([ratbagd], - [0.0.1], + [0.0.2], [http://www.github.com/libratbag/ratbagd], [ratbagd], [http://www.github.com/libratbag/ratbagd]) From 5e2d7de6c2b68ddc812f236c229dfebe1652bb2d Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 9 Mar 2016 13:04:22 +1000 Subject: [PATCH 076/137] configure.ac: remove a couple of unused items This configure.ac is largely a copy from systemd so it included things that we don't use locally. - we don't use grep, awk or ln - AC_SYS_LARGEFILE and AC_CANONICAL_HOST are unecessary - pkg.m4 - if that's missing you don't have pkgconfig installed. stop trying to build things then :) Signed-off-by: Peter Hutterer --- configure.ac | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/configure.ac b/configure.ac index 6a05dbc2..fdc25805 100644 --- a/configure.ac +++ b/configure.ac @@ -15,11 +15,9 @@ AC_CONFIG_HEADERS([config.h]) AC_CONFIG_AUX_DIR([build-aux]) AC_USE_SYSTEM_EXTENSIONS -AC_SYS_LARGEFILE AM_MAINTAINER_MODE([enable]) AM_INIT_AUTOMAKE([foreign 1.11 -Wall -Wno-portability silent-rules tar-pax no-dist-gzip dist-xz subdir-objects parallel-tests]) AM_SILENT_RULES([yes]) -AC_CANONICAL_HOST AC_DEFINE_UNQUOTED([CANONICAL_HOST], "$host", [Canonical host string.]) LT_PREREQ(2.2) @@ -28,16 +26,12 @@ LT_INIT([disable-static]) AC_PROG_MKDIR_P AC_PROG_LN_S AC_PROG_SED -AC_PROG_GREP -AC_PROG_AWK AC_PROG_CC_C99 AC_PATH_PROG([M4], [m4]) AC_PATH_PROG([XSLTPROC], [xsltproc]) AM_PATH_PYTHON -AS_IF([! ln --relative --help > /dev/null 2>&1], [AC_MSG_ERROR([*** ln doesn't support --relative ***])]) - # ------------------------------------------------------------------------------ # arguments @@ -119,12 +113,6 @@ AC_SUBST([OUR_CFLAGS], "$with_cflags") AC_SUBST([OUR_CPPFLAGS], "$with_cppflags") AC_SUBST([OUR_LDFLAGS], "$with_ldflags") -# ------------------------------------------------------------------------------ -# system features - -# This makes sure pkg.m4 is available. -m4_pattern_forbid([^_?PKG_[A-Z_]+$],[*** pkg.m4 missing, please install pkg-config]) - # ------------------------------------------------------------------------------ # dependencies From 70222b3033c9704eebaf905e8096bda92ebdcf0e Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 9 Mar 2016 13:10:14 +1000 Subject: [PATCH 077/137] Use PKG_CHECK_VAR to check for the pkgdatadir Signed-off-by: Peter Hutterer --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index fdc25805..fd8f8c0f 100644 --- a/configure.ac +++ b/configure.ac @@ -120,8 +120,8 @@ PKG_CHECK_MODULES([LIBUDEV], [libudev]) PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd >= 227]) PKG_CHECK_MODULES([LIBRATBAG], [libratbag >= 0.2]) -libratbag_data_dir=`$PKG_CONFIG --variable pkgdatadir libratbag` -AC_DEFINE_UNQUOTED([LIBRATBAG_DATA_DIR], ["$libratbag_data_dir"], [Directory for libratbag's SVG files]) +PKG_CHECK_VAR([libratbag_data_dir], [libratbag], [pkgdatadir], + [AC_DEFINE_UNQUOTED([LIBRATBAG_DATA_DIR], ["$libratbag_data_dir"], [Directory for libratbag's SVG files])]) # ------------------------------------------------------------------------------ # options From 9f9383e6ffb830bb9b0c95692273820eb785bdbc Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 9 Mar 2016 13:25:44 +1000 Subject: [PATCH 078/137] profile: free the buttons/resolutions on profile cleanup Signed-off-by: Peter Hutterer --- src/ratbagd-profile.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/ratbagd-profile.c b/src/ratbagd-profile.c index 77de4746..880fda81 100644 --- a/src/ratbagd-profile.c +++ b/src/ratbagd-profile.c @@ -362,9 +362,24 @@ int ratbagd_profile_new(struct ratbagd_profile **out, struct ratbagd_profile *ratbagd_profile_free(struct ratbagd_profile *profile) { + unsigned int i; + if (!profile) return NULL; + profile->resolution_vtable_slot = sd_bus_slot_unref(profile->resolution_vtable_slot); + profile->resolution_enum_slot = sd_bus_slot_unref(profile->resolution_enum_slot); + profile->button_vtable_slot = sd_bus_slot_unref(profile->button_vtable_slot); + profile->button_enum_slot = sd_bus_slot_unref(profile->button_enum_slot); + + for (i = 0; i< profile->n_buttons; ++i) + ratbagd_button_free(profile->buttons[i]); + for (i = 0; i< profile->n_resolutions; ++i) + ratbagd_resolution_free(profile->resolutions[i]); + + mfree(profile->buttons); + mfree(profile->resolutions); + profile->path = mfree(profile->path); /* we cannot assume the profile is gone, so set NULL explicitly */ From 819c70fa9ad12ff895dd8bb4a10cfc1df9e7c140 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 9 Mar 2016 13:41:04 +1000 Subject: [PATCH 079/137] systemd: restart on abort Now that we clean up properly, the most common crash should be fixed. Restart on abort by default so ideally all we need to do is restart piper or whatever consumes the API. Signed-off-by: Peter Hutterer --- ratbagd.service.in | 1 + 1 file changed, 1 insertion(+) diff --git a/ratbagd.service.in b/ratbagd.service.in index 053bc77f..db07f0aa 100644 --- a/ratbagd.service.in +++ b/ratbagd.service.in @@ -5,6 +5,7 @@ Description=Daemon to introspect and modify configuable mice Type=dbus BusName=org.freedesktop.ratbag1 ExecStart=__BIN_PREFIX__/ratbagd +Restart=on-abort [Install] WantedBy=multi-user.target From a066203b4a9eb6c83ca07a34ed46f30d18456fbc Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 9 Mar 2016 14:08:20 +1000 Subject: [PATCH 080/137] systemd: fix typo in service file Signed-off-by: Peter Hutterer --- ratbagd.service.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ratbagd.service.in b/ratbagd.service.in index db07f0aa..ef9b7342 100644 --- a/ratbagd.service.in +++ b/ratbagd.service.in @@ -1,5 +1,5 @@ [Unit] -Description=Daemon to introspect and modify configuable mice +Description=Daemon to introspect and modify configurable mice [Service] Type=dbus From b164fa622f951deebd6d85a8026cbccabed9a7ed Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 9 Mar 2016 14:37:49 +1000 Subject: [PATCH 081/137] Change to a dbus-activated service We don't shut down once activated but that doesn't mean we need to run when never requested. Signed-off-by: Peter Hutterer Reviewed-by: David Herrmann --- .gitignore | 1 + Makefile.am | 10 ++++++++-- configure.ac | 8 ++++++++ dbus/org.freedesktop.ratbag1.service.in | 5 +++++ ratbagd.service.in | 2 +- 5 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 dbus/org.freedesktop.ratbag1.service.in diff --git a/.gitignore b/.gitignore index 74154a6a..a6ef9a28 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,4 @@ ratbagctl stamp-* ratbagd.service ratbagctl +org.freedesktop.ratbag1.service diff --git a/Makefile.am b/Makefile.am index 4f0e327c..89307737 100644 --- a/Makefile.am +++ b/Makefile.am @@ -86,8 +86,14 @@ unit_DATA = ratbagd.service $(unit_DATA): $(unit_DATA).in $(AM_V_GEN)$(SED) -e 's|__BIN_PREFIX__|$(bindir)|g' < $< > $@ -EXTRA_DIST += ratbagd.service.in -BUILT_SOURCES += ratbagd.service +dbusdir = $(DBUS_SYSTEM_SERVICES_DIR) +dbus_DATA = dbus/org.freedesktop.ratbag1.service + +$(dbus_DATA): $(dbus_DATA).in + $(AM_V_GEN)$(SED) -e 's|__BIN_PREFIX__|$(bindir)|g' < $< > $@ + +EXTRA_DIST += ratbagd.service.in dbus/org.freedesktop.ratbag1.service.in +BUILT_SOURCES += ratbagd.service dbus/org.freedesktop.ratbag1.service # ------------------------------------------------------------------------------ # python module diff --git a/configure.ac b/configure.ac index fd8f8c0f..08ff8e16 100644 --- a/configure.ac +++ b/configure.ac @@ -133,6 +133,14 @@ AC_ARG_WITH([systemd-unit-dir], SYSTEMD_UNIT_DIR=${unitdir} AC_SUBST(SYSTEMD_UNIT_DIR) +AC_ARG_WITH([dbus-root-dir], + AS_HELP_STRING([--with-dbus-root-dir=DIR], + [dbus service directory [[default=$datadir/dbus-1]]]), + [unitdir="$withval"], + [unitdir="$datadir/dbus-1"]) +DBUS_SYSTEM_SERVICES_DIR="${datadir}/system-services" +AC_SUBST(DBUS_SYSTEM_SERVICES_DIR) + # ------------------------------------------------------------------------------ # report diff --git a/dbus/org.freedesktop.ratbag1.service.in b/dbus/org.freedesktop.ratbag1.service.in new file mode 100644 index 00000000..712bbfb2 --- /dev/null +++ b/dbus/org.freedesktop.ratbag1.service.in @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=org.freedesktop.ratbag1 +Exec=__BIN_PREFIX__/ratbagd +User=root +SystemdService=dbus-org.freedesktop.ratbag1.service diff --git a/ratbagd.service.in b/ratbagd.service.in index ef9b7342..600ab8c0 100644 --- a/ratbagd.service.in +++ b/ratbagd.service.in @@ -8,4 +8,4 @@ ExecStart=__BIN_PREFIX__/ratbagd Restart=on-abort [Install] -WantedBy=multi-user.target +Alias=dbus-org.freedesktop.ratbag1.service From fa0d57dd47bc6e635e1776085281dc8c3e960642 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Mar 2016 07:14:44 +1000 Subject: [PATCH 082/137] Install the dbus config as well Signed-off-by: Peter Hutterer --- Makefile.am | 14 ++++++++++---- configure.ac | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index 89307737..c9431370 100644 --- a/Makefile.am +++ b/Makefile.am @@ -86,13 +86,19 @@ unit_DATA = ratbagd.service $(unit_DATA): $(unit_DATA).in $(AM_V_GEN)$(SED) -e 's|__BIN_PREFIX__|$(bindir)|g' < $< > $@ -dbusdir = $(DBUS_SYSTEM_SERVICES_DIR) -dbus_DATA = dbus/org.freedesktop.ratbag1.service +dbusservicedir = $(DBUS_SYSTEM_SERVICES_DIR) +dbusservice_DATA = dbus/org.freedesktop.ratbag1.service -$(dbus_DATA): $(dbus_DATA).in +$(dbusservice_DATA): $(dbusservice_DATA).in $(AM_V_GEN)$(SED) -e 's|__BIN_PREFIX__|$(bindir)|g' < $< > $@ -EXTRA_DIST += ratbagd.service.in dbus/org.freedesktop.ratbag1.service.in +dbusconfigdir = $(DBUS_SYSTEM_CONFIG_DIR) +dbusconfig_DATA = dbus/org.freedesktop.ratbag1.conf + +EXTRA_DIST += \ + ratbagd.service.in \ + dbus/org.freedesktop.ratbag1.service.in \ + dbus/org.freedesktop.ratbag1.conf BUILT_SOURCES += ratbagd.service dbus/org.freedesktop.ratbag1.service # ------------------------------------------------------------------------------ diff --git a/configure.ac b/configure.ac index 08ff8e16..16a86eea 100644 --- a/configure.ac +++ b/configure.ac @@ -139,6 +139,7 @@ AC_ARG_WITH([dbus-root-dir], [unitdir="$withval"], [unitdir="$datadir/dbus-1"]) DBUS_SYSTEM_SERVICES_DIR="${datadir}/system-services" +DBUS_SYSTEM_CONFIG_DIR="${datadir}/system.d" AC_SUBST(DBUS_SYSTEM_SERVICES_DIR) # ------------------------------------------------------------------------------ From de83186c3ca3a759cfb29eb6a5328d66ce800e03 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Mar 2016 07:16:28 +1000 Subject: [PATCH 083/137] Create the dbus directory in $builddir Signed-off-by: Peter Hutterer --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index c9431370..2b589515 100644 --- a/Makefile.am +++ b/Makefile.am @@ -90,6 +90,7 @@ dbusservicedir = $(DBUS_SYSTEM_SERVICES_DIR) dbusservice_DATA = dbus/org.freedesktop.ratbag1.service $(dbusservice_DATA): $(dbusservice_DATA).in + $(AM_V_GEN)$(MKDIR_P) dbus $(AM_V_GEN)$(SED) -e 's|__BIN_PREFIX__|$(bindir)|g' < $< > $@ dbusconfigdir = $(DBUS_SYSTEM_CONFIG_DIR) From f385622ec6aa0290add3e35a87a9967fa2680f46 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Mar 2016 07:23:01 +1000 Subject: [PATCH 084/137] Makefile: add a comment marker for the dbus/systemd config files Signed-off-by: Peter Hutterer --- Makefile.am | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile.am b/Makefile.am index 2b589515..64b80b85 100644 --- a/Makefile.am +++ b/Makefile.am @@ -80,6 +80,9 @@ ratbagd_LDADD = \ $(LIBSYSTEMD_LIBS) \ $(LIBRATBAG_LIBS) +# ------------------------------------------------------------------------------ +# DBus and systemd configuration files + unitdir = $(SYSTEMD_UNIT_DIR) unit_DATA = ratbagd.service From 2e93ac07f6ba49a4f041c0705514c33255b4dcc9 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Mar 2016 10:26:51 +1000 Subject: [PATCH 085/137] Update gitignore for a few things Signed-off-by: Peter Hutterer --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index a6ef9a28..5c5c81e2 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,9 @@ libtool ratbagctl ./ratbagd stamp-* +ratbagd ratbagd.service ratbagctl org.freedesktop.ratbag1.service +tags +__pycache__ From 20b9339620e37843999259b63eabd8775a6fd77c Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Mar 2016 10:38:19 +1000 Subject: [PATCH 086/137] README: update install instructions for dbus Signed-off-by: Peter Hutterer --- README.md | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 489568f6..3fa02fdf 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,27 @@ ratbagd is a system daemon to introspect and modify configurable mice. Running ratbagd --------------- -To be able to run ratbagd, you need to add a policy file to your dbus -environment: +ratbagd is intended to run as dbus-activated systemd service. This requires +installation of the following files: sudo cp dbus/org.freedesktop.ratbag1.conf /etc/dbus-1/system.d/org.freedesktop.ratbag1.conf + sudo cp dbus/org.freedesktop.ratbag1.service /etc/dbus-1/systemd-services/org.freedesktop.ratbag1.conf + sudo cp ratbagd.service /etc/systemd/system/ratbagd.service + +The files are installed into the prefix by make install, see also the +configure switches ---with-systemd-uint-dir and --with-dbus-root-dir. +Developers are encouraged to simply symlink to the files in the git +repository. + +For the files to take effect, you should run + sudo systemctl daemon-reload + sudo systemctl reload dbus.service + +And finally, to enable the service: + sudo systemctl enable ratbagd.service + +This places the required symlink into the systemd directory so that dbus +activation is possible. Compiling ratbagd ----------------- From 815a81a6108c4f80d5a68b8ea3dc69c82ce4b0f7 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Mar 2016 10:54:04 +1000 Subject: [PATCH 087/137] Spice up the README a bit Signed-off-by: Peter Hutterer --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 3fa02fdf..d7f1f751 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,16 @@ ratbagd ratbagd is a system daemon to introspect and modify configurable mice. +ratbagd uses libratbag to access mice and exports the features over a DBus +API to unprivileged proceses. ratbagd needs permissions to access device +nodes (primarily /dev/hidraw nodes) and usually needs to run as root. + +ratbagd is a relatively thin wrapper arond libratbag. If a device is not +detected or does not function as expected, the issue is usually in +libratbag. libratbag can be found at + https://github.com/libratbag/libratbag + + Running ratbagd --------------- From 8517e103b0a22811c03718d5a7a5301686f8e0fc Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Mar 2016 10:23:36 +1000 Subject: [PATCH 088/137] ratbagd 0.1 Signed-off-by: Peter Hutterer --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 16a86eea..452fd4d2 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ AC_PREREQ([2.64]) AC_INIT([ratbagd], - [0.0.2], + [0.1], [http://www.github.com/libratbag/ratbagd], [ratbagd], [http://www.github.com/libratbag/ratbagd]) From 346631cd75138df053cf79192841d9777a6b89c4 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Mar 2016 13:03:56 +1000 Subject: [PATCH 089/137] Skip the manual NULL assignment after unref libratbag guarantees that unref() always returns NULL Signed-off-by: Peter Hutterer --- src/ratbagd-button.c | 5 +---- src/ratbagd-profile.c | 5 +---- src/ratbagd-resolution.c | 5 +---- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/ratbagd-button.c b/src/ratbagd-button.c index 6561f4ae..b4060d73 100644 --- a/src/ratbagd-button.c +++ b/src/ratbagd-button.c @@ -557,10 +557,7 @@ struct ratbagd_button *ratbagd_button_free(struct ratbagd_button *button) return NULL; button->path = mfree(button->path); - - /* we cannot assume the button is gone, so set NULL explicitly */ - ratbag_button_unref(button->lib_button); - button->lib_button = NULL; + button->lib_button = ratbag_button_unref(button->lib_button); return mfree(button); } diff --git a/src/ratbagd-profile.c b/src/ratbagd-profile.c index 880fda81..fc93ede4 100644 --- a/src/ratbagd-profile.c +++ b/src/ratbagd-profile.c @@ -381,10 +381,7 @@ struct ratbagd_profile *ratbagd_profile_free(struct ratbagd_profile *profile) mfree(profile->resolutions); profile->path = mfree(profile->path); - - /* we cannot assume the profile is gone, so set NULL explicitly */ - ratbag_profile_unref(profile->lib_profile); - profile->lib_profile = NULL; + profile->lib_profile = ratbag_profile_unref(profile->lib_profile); return mfree(profile); } diff --git a/src/ratbagd-resolution.c b/src/ratbagd-resolution.c index 45472421..cecadabe 100644 --- a/src/ratbagd-resolution.c +++ b/src/ratbagd-resolution.c @@ -166,10 +166,7 @@ struct ratbagd_resolution *ratbagd_resolution_free(struct ratbagd_resolution *re 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; + resolution->lib_resolution = ratbag_resolution_unref(resolution->lib_resolution); return mfree(resolution); } From 99011fd3bf710a14ab540beec6e78c61a0638161 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 11 Mar 2016 09:16:48 +1000 Subject: [PATCH 090/137] configure.ac: fix dbus install directories Signed-off-by: Peter Hutterer --- configure.ac | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 452fd4d2..88785e78 100644 --- a/configure.ac +++ b/configure.ac @@ -136,10 +136,10 @@ AC_SUBST(SYSTEMD_UNIT_DIR) AC_ARG_WITH([dbus-root-dir], AS_HELP_STRING([--with-dbus-root-dir=DIR], [dbus service directory [[default=$datadir/dbus-1]]]), - [unitdir="$withval"], - [unitdir="$datadir/dbus-1"]) -DBUS_SYSTEM_SERVICES_DIR="${datadir}/system-services" -DBUS_SYSTEM_CONFIG_DIR="${datadir}/system.d" + [dbusrootdir="$withval"], + [dbusrootdir="$datadir/dbus-1"]) +DBUS_SYSTEM_SERVICES_DIR="${dbusrootdir}/system-services" +DBUS_SYSTEM_CONFIG_DIR="${dbusrootdir}/system.d" AC_SUBST(DBUS_SYSTEM_SERVICES_DIR) # ------------------------------------------------------------------------------ From 1824b977f7142e92fce00cab98908181b23cf58a Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 11 Mar 2016 09:17:34 +1000 Subject: [PATCH 091/137] Fix typo in README Signed-off-by: Peter Hutterer --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d7f1f751..c299a31f 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ installation of the following files: sudo cp ratbagd.service /etc/systemd/system/ratbagd.service The files are installed into the prefix by make install, see also the -configure switches ---with-systemd-uint-dir and --with-dbus-root-dir. +configure switches ---with-systemd-unit-dir and --with-dbus-root-dir. Developers are encouraged to simply symlink to the files in the git repository. From 2bbcc51a8b8383bfd36742fecd18b445baca6ae6 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 11 Mar 2016 10:40:01 +1000 Subject: [PATCH 092/137] ratbagd 0.1.1 Signed-off-by: Peter Hutterer --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 88785e78..69a97822 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ AC_PREREQ([2.64]) AC_INIT([ratbagd], - [0.1], + [0.1.1], [http://www.github.com/libratbag/ratbagd], [ratbagd], [http://www.github.com/libratbag/ratbagd]) From 5cc234e27e71a08d06bf39623311dfb710c98eb9 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 11 Mar 2016 11:27:16 +1000 Subject: [PATCH 093/137] configure.ac: add missing AC_SUBST for the dbus config dir Signed-off-by: Peter Hutterer --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 69a97822..f81308aa 100644 --- a/configure.ac +++ b/configure.ac @@ -141,6 +141,7 @@ AC_ARG_WITH([dbus-root-dir], DBUS_SYSTEM_SERVICES_DIR="${dbusrootdir}/system-services" DBUS_SYSTEM_CONFIG_DIR="${dbusrootdir}/system.d" AC_SUBST(DBUS_SYSTEM_SERVICES_DIR) +AC_SUBST(DBUS_SYSTEM_CONFIG_DIR) # ------------------------------------------------------------------------------ # report From 97eee9e0c5b37ee1d9687f3ed5b8cc50a3355297 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 11 Mar 2016 12:02:17 +1000 Subject: [PATCH 094/137] ratbagd 0.1.2 Signed-off-by: Peter Hutterer --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f81308aa..554201be 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ AC_PREREQ([2.64]) AC_INIT([ratbagd], - [0.1.1], + [0.1.2], [http://www.github.com/libratbag/ratbagd], [ratbagd], [http://www.github.com/libratbag/ratbagd]) From 917308d24dd7c6481a16f742857337e4d4619a13 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 14 Mar 2016 17:02:17 +1000 Subject: [PATCH 095/137] Document the DBus interface in the README Signed-off-by: Peter Hutterer --- README.md | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/README.md b/README.md index c299a31f..830df8fb 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,82 @@ detected or does not function as expected, the issue is usually in libratbag. libratbag can be found at https://github.com/libratbag/libratbag +The DBus-Interface +------------------ + +Note: **the DBus interface is subject to change** + +Interfaces: +- org.freedesktop.ratbag1.Manager +- org.freedesktop.ratbag1.Device +- org.freedesktop.ratbag1.Profile +- org.freedesktop.ratbag1.Resolution +- org.freedesktop.ratbag1.Button + +The **org.freedesktop.ratbag1.Manager** interface provides: +- Properties: + - Devices -> array of object paths with interface Device +- Signals: + - DeviceNew -> new device available, carries object path + - DeviceRemoved -> device removed, carries object path +- Methods: + - GetDeviceByName(string) -> returns object path + +The **org.freedesktop.ratbag1.Device** interface provides: +- Properties: + - Id -> unique ID of this device + - CapSwitchableResolution, CapSwitchableProfile, CapButtonKeys, + CapButtonMacros, CapDefaultProfile -> booleans to signal capabilities + - Description -> device name + - Svg -> device SVG name (file only) + - SvgPath -> device SVG name (full absolute path) + - Profiles -> array of object paths with interface Profile + - ActiveProfile -> index of the currently active profile in Profiles +- Methods: + - GetProfileByIndex(uint) -> returns the object path for the given index + +The **org.freedesktop.ratbag1.Profile** interface provides: +- Properties: + - Index -> index of the profile + - Resolutions -> array of object paths with interface Resolution + - Buttons -> array of object paths with interface Button + - ActiveResolution -> index of the currently active resolution in Resolutions + - DefaultResolution -> index of the default resolution in Resolutions +- Methods: + - SetActive(void) -> set this profile to be the active profile + - GetResolutionByIndex(uint) -> returns the object path for the given index + +The **org.freedesktop.ratbag1.Resolution** interface provides: +- Properties: + - Index -> index of the resolution + - CapIndividualReportRate, CapSeparateXYResolution -> booleans to signal + capabilities + - XResolution -> uint for the x resolution assigned to this entry + - YResolution -> uint for the y resolution assigned to this entry + - ReportRate -> uint for the report rate in Hz assigned to this entry +- Methods: + - SetResolution(uint, uint) -> x/y resolution to assign + - SetReportRate(uint) -> uint for the report rate to assign + +The **org.freedesktop.ratbag1.Button** interface provides: +- Properties: + - Index -> index of the button + - Type -> string describing the button type + - ButtonMapping -> uint of the current button mapping (if mapping to button) + - SpecialMapping -> string of the current special mapping (if mapped to special) + - KeyMapping -> array of uints, first entry is the keycode, other entries, if any, are modifiers (if mapped to key) + - ActionType -> string describing the action type of the button ("none", "button", "key", "special", "macro", "unknown"). This decides which *Mapping property has a value + - ActionTypes -> array of strings, possible values for ActionType +- Methods: + - SetButtonMapping(uint) -> set the button mapping to the given button + - SetSpecialMapping(string) -> set the button mapping to the given special entry + - SetKeyMapping(uint[]) -> set the key mapping, first entry is the keycode, other entries, if any, are modifier keycodes + - Disable(void) -> disable this button + +For easier debugging, objects paths are constructed from the device. e.g. +`/org/freedesktop/ratbag/button/event5/p0/b10` is the button interface for +button 10 on profile 0 on event5. The naming is subject to change. Do not +rely on a constructed object path in your application. Running ratbagd --------------- From 7c622ecc58c81ba8cac5914374af1fdd2f52c5a5 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 15 Mar 2016 10:18:23 +1000 Subject: [PATCH 096/137] Adjust for new libratbag 0.4 API Signed-off-by: Peter Hutterer --- configure.ac | 2 +- src/ratbagd.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 554201be..b95e005e 100644 --- a/configure.ac +++ b/configure.ac @@ -118,7 +118,7 @@ AC_SUBST([OUR_LDFLAGS], "$with_ldflags") PKG_CHECK_MODULES([LIBUDEV], [libudev]) PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd >= 227]) -PKG_CHECK_MODULES([LIBRATBAG], [libratbag >= 0.2]) +PKG_CHECK_MODULES([LIBRATBAG], [libratbag >= 0.4]) PKG_CHECK_VAR([libratbag_data_dir], [libratbag], [pkgdatadir], [AC_DEFINE_UNQUOTED([LIBRATBAG_DATA_DIR], ["$libratbag_data_dir"], [Directory for libratbag's SVG files])]) diff --git a/src/ratbagd.c b/src/ratbagd.c index ca5347ef..172dda8c 100644 --- a/src/ratbagd.c +++ b/src/ratbagd.c @@ -212,10 +212,13 @@ static void ratbagd_process_device(struct ratbagd *ctx, } else if (device) { /* device already known, refresh our view of the device */ } else { + enum ratbag_error_code error; + /* device unknown, create new one and link it */ - lib_device = ratbag_device_new_from_udev_device(ctx->lib_ctx, - udevice); - if (!lib_device) + error = ratbag_device_new_from_udev_device(ctx->lib_ctx, + udevice, + &lib_device); + if (error != RATBAG_SUCCESS) return; /* unsupported device */ r = ratbagd_device_new(&device, ctx, name, lib_device); From 0ebbccc6cffd64226cf584f775a14cf13022e010 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 15 Mar 2016 12:21:30 +1000 Subject: [PATCH 097/137] ratbagctl: fix error when printing separate x/y resolutions Signed-off-by: Peter Hutterer --- python/ratbagctl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ratbagctl.py b/python/ratbagctl.py index c86b70a9..a8f2c45e 100755 --- a/python/ratbagctl.py +++ b/python/ratbagctl.py @@ -113,7 +113,7 @@ def show_resolution(r, args): d.description)) print(" Report Rate: {}Hz".format(r.report_rate)) if "separate-xy-resolution" in r.capabilities: - print(" Resolution: {}x{}dpi".format(r.resolution)) + print(" Resolution: {}x{}dpi".format(*r.resolution)) else: print(" Resolution: {}dpi".format(r.resolution[0])) From ca2f32ea58b4a7f1276032fed3ff1526bc705797 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 15 Mar 2016 11:21:09 +1000 Subject: [PATCH 098/137] device: switch the capabilities to an enum Strings can suffer from locale issues, the official recommendation for DBus APIs is to use enums here. Signed-off-by: Peter Hutterer --- README.md | 3 +- python/ratbagctl.py | 10 ++++- python/ratbagd/__init__.py | 25 ++++------- src/ratbagd-device.c | 90 +++++++++++++++++++++----------------- 4 files changed, 69 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 830df8fb..4f5ff694 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,7 @@ The **org.freedesktop.ratbag1.Manager** interface provides: The **org.freedesktop.ratbag1.Device** interface provides: - Properties: - Id -> unique ID of this device - - CapSwitchableResolution, CapSwitchableProfile, CapButtonKeys, - CapButtonMacros, CapDefaultProfile -> booleans to signal capabilities + - Capabilities -> array of uints with the capabilities enum from libratbag - Description -> device name - Svg -> device SVG name (file only) - SvgPath -> device SVG name (full absolute path) diff --git a/python/ratbagctl.py b/python/ratbagctl.py index a8f2c45e..69a939fd 100755 --- a/python/ratbagctl.py +++ b/python/ratbagctl.py @@ -77,9 +77,17 @@ def find_button(r, args): def show_device(r, args): d = find_device(r, args) + + caps = { RatbagdDevice.CAP_SWITCHABLE_RESOLUTION : "switchable-resolution", + RatbagdDevice.CAP_SWITCHABLE_PROFILE : "switchable-profile", + RatbagdDevice.CAP_BUTTON_KEY : "button-keys", + RatbagdDevice.CAP_BUTTON_MACROS : "button-macros", + RatbagdDevice.CAP_DEFAULT_PROFILE : "default-profile" } + capabilities = [caps[c] for c in d.capabilities] + print("{} - {}".format(d.id, d.description)) print(" SVG: {}".format(d.svg)) - print(" Capabilities: {}".format(", ".join(d.capabilities))) + print(" Capabilities: {}".format(", ".join(capabilities))) print("Number of Profiles: {}".format(len(d.profiles))) active = -1 for i, p in enumerate(d.profiles): diff --git a/python/ratbagd/__init__.py b/python/ratbagd/__init__.py index a3c6271b..726cfebb 100644 --- a/python/ratbagd/__init__.py +++ b/python/ratbagd/__init__.py @@ -76,6 +76,12 @@ class Ratbagd(_RatbagdDBus): return self._devices class RatbagdDevice(_RatbagdDBus): + CAP_SWITCHABLE_RESOLUTION = 1 + CAP_SWITCHABLE_PROFILE = 2 + CAP_BUTTON_KEY = 3 + CAP_BUTTON_MACROS = 4 + CAP_DEFAULT_PROFILE = 5 + """ Represents a ratbagd device. """ @@ -93,16 +99,7 @@ class RatbagdDevice(_RatbagdDBus): self._profiles = [RatbagdProfile(objpath) for objpath in result] self._active_profile = self.dbus_property("ActiveProfile") - caps = [ "switchable-resolution", - "switchable-profile", - "button-keys", - "button-macros", - "default-profile"] - self._caps = [] - for c in caps: - cname = "Cap" + "".join([n.capitalize() for n in c.split("-")]) - if self.dbus_property(cname): - self._caps.append(c) + self._caps = self.dbus_property("Capabilities") @property def profiles(self): @@ -154,14 +151,10 @@ class RatbagdDevice(_RatbagdDBus): @property def capabilities(self): """ - Return the capabilities of this device as a list of identifier strings. + Return the capabilities of this device as an array. Capabilities not present on the device are not in the list. Thus use - if "capability" is in deivce.caps: + if "capability" is in device.caps: do something - - Capabilities supported: "switchable-resolution", - "switchable-profile", "button-keys", "button-macros", - "default-profile" """ return self._caps diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 3fee6209..05b98bf7 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -47,14 +47,6 @@ struct ratbagd_device { sd_bus_slot *profile_enum_slot; unsigned int n_profiles; struct ratbagd_profile **profiles; - - struct { - bool switchable_resolution; - bool switchable_profile; - bool button_keys; - bool button_macros; - bool default_profile; - } capabilities; }; #define ratbagd_device_from_node(_ptr) \ @@ -272,24 +264,59 @@ static int ratbagd_device_get_profile_by_index(sd_bus_message *m, ratbagd_profile_get_path(profile)); } +static int +ratbagd_device_get_capabilities(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_device *device = userdata; + struct ratbag_device *lib_device = device->lib_device; + enum ratbag_device_capability cap; + int r; + + r = sd_bus_message_open_container(reply, 'a', "u"); + if (r < 0) + return r; + + cap = RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION; + if (ratbag_device_has_capability(lib_device, cap)) { + r = sd_bus_message_append(reply, "u", cap); + if (r < 0) + return r; + } + + cap = RATBAG_DEVICE_CAP_SWITCHABLE_PROFILE; + if (ratbag_device_has_capability(lib_device, cap)) { + r = sd_bus_message_append(reply, "u", cap); + if (r < 0) + return r; + } + + cap = RATBAG_DEVICE_CAP_BUTTON_MACROS; + if (ratbag_device_has_capability(lib_device, cap)) { + r = sd_bus_message_append(reply, "u", cap); + if (r < 0) + return r; + } + + cap = RATBAG_DEVICE_CAP_DEFAULT_PROFILE; + if (ratbag_device_has_capability(lib_device, cap)) { + r = sd_bus_message_append(reply, "u", cap); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + const sd_bus_vtable ratbagd_device_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct ratbagd_device, name), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("CapSwitchableResolution", "b", NULL, - offsetof(struct ratbagd_device, capabilities.switchable_resolution), - SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("CapSwitchableProfile", "b", NULL, - offsetof(struct ratbagd_device, capabilities.switchable_profile), - SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("CapButtonKeys", "b", NULL, - offsetof(struct ratbagd_device, capabilities.button_keys), - SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("CapButtonMacros", "b", NULL, - offsetof(struct ratbagd_device, capabilities.button_macros), - SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("CapDefaultProfile", "b", NULL, - offsetof(struct ratbagd_device, capabilities.default_profile), - SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Capabilities", "au", ratbagd_device_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Description", "s", ratbagd_device_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Svg", "s", ratbagd_device_get_svg, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SvgPath", "s", ratbagd_device_get_svg_path, 0, SD_BUS_VTABLE_PROPERTY_CONST), @@ -358,23 +385,6 @@ int ratbagd_device_new(struct ratbagd_device **out, } } - - device->capabilities.switchable_resolution = - ratbag_device_has_capability(lib_device, - RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION); - device->capabilities.switchable_profile = - ratbag_device_has_capability(lib_device, - RATBAG_DEVICE_CAP_SWITCHABLE_PROFILE); - device->capabilities.button_keys = - ratbag_device_has_capability(lib_device, - RATBAG_DEVICE_CAP_BUTTON_MACROS); - device->capabilities.button_macros = - ratbag_device_has_capability(lib_device, - RATBAG_DEVICE_CAP_BUTTON_MACROS); - device->capabilities.default_profile = - ratbag_device_has_capability(lib_device, - RATBAG_DEVICE_CAP_DEFAULT_PROFILE); - *out = device; device = NULL; return 0; From 00f488dc13301b0af532bc3de3f783cbd7f48191 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 15 Mar 2016 11:21:09 +1000 Subject: [PATCH 099/137] resolution: switch the capabilities to an enum Strings can suffer from locale issues, the official recommendation for DBus APIs is to use enums here. Signed-off-by: Peter Hutterer --- README.md | 3 +-- python/ratbagctl.py | 8 ++++-- python/ratbagd/__init__.py | 21 ++++++--------- src/ratbagd-resolution.c | 53 ++++++++++++++++++++++++++------------ 4 files changed, 51 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 4f5ff694..56550c0d 100644 --- a/README.md +++ b/README.md @@ -59,8 +59,7 @@ The **org.freedesktop.ratbag1.Profile** interface provides: The **org.freedesktop.ratbag1.Resolution** interface provides: - Properties: - Index -> index of the resolution - - CapIndividualReportRate, CapSeparateXYResolution -> booleans to signal - capabilities + - Capabilities -> array of uints with the capabilities enum from libratbag - XResolution -> uint for the x resolution assigned to this entry - YResolution -> uint for the y resolution assigned to this entry - ReportRate -> uint for the report rate in Hz assigned to this entry diff --git a/python/ratbagctl.py b/python/ratbagctl.py index 69a939fd..8adc9f9b 100755 --- a/python/ratbagctl.py +++ b/python/ratbagctl.py @@ -120,12 +120,16 @@ def show_resolution(r, args): d.id, d.description)) print(" Report Rate: {}Hz".format(r.report_rate)) - if "separate-xy-resolution" in r.capabilities: + if RatbagdResolution.CAP_SEPARATE_XY_RESOLUTION in r.capabilities: print(" Resolution: {}x{}dpi".format(*r.resolution)) else: print(" Resolution: {}dpi".format(r.resolution[0])) - print(" Capabilities: {}".format(", ".join(r.capabilities))) + + caps = { RatbagdResolution.CAP_INDIVIDUAL_REPORT_RATE : "individual-report-rate", + RatbagdResolution.CAP_SEPARATE_XY_RESOLUTION : "separate-xy-resolution" } + capabilities = [caps[c] for c in r.capabilities] + print(" Capabilities: {}".format(", ".join(capabilities))) def show_button(r, args): b, p, d = find_button(r, args) diff --git a/python/ratbagd/__init__.py b/python/ratbagd/__init__.py index 726cfebb..2c4dabbf 100644 --- a/python/ratbagd/__init__.py +++ b/python/ratbagd/__init__.py @@ -153,7 +153,8 @@ class RatbagdDevice(_RatbagdDBus): """ Return the capabilities of this device as an array. Capabilities not present on the device are not in the list. Thus use - if "capability" is in device.caps: + e.g. + if RatbagdDevice.CAP_SWITCHABLE_RESOLUTION is in device.caps: do something """ return self._caps @@ -229,6 +230,8 @@ class RatbagdProfile(_RatbagdDBus): return self._objpath == other._objpath class RatbagdResolution(_RatbagdDBus): + CAP_INDIVIDUAL_REPORT_RATE = 1 + CAP_SEPARATE_XY_RESOLUTION = 2 """ Represents a ratbagd resolution. """ @@ -240,13 +243,7 @@ class RatbagdResolution(_RatbagdDBus): self._rate = self.dbus_property("ReportRate") self._objpath = object_path - caps = [ "individual-report-rate", - "separate-xy-resolution" ] - self._caps = [] - for c in caps: - cname = "Cap" + "".join([n.capitalize() for n in c.split("-")]) - if self.dbus_property(cname): - self._caps.append(c) + self._caps = self.dbus_property("Capabilities") @property def resolution(self): @@ -271,13 +268,11 @@ class RatbagdResolution(_RatbagdDBus): @property def capabilities(self): """ - Return the capabilities of this device as a list of identifier strings. + Return the capabilities of this device as a list. Capabilities not present on the device are not in the list. Thus use - if "capability" is in resolution.caps: + e.g. + if RatbagdResolution.CAP_SEPARATE_XY_RESOLUTION is in resolution.caps: do something - - Capabilities supported: "individual-report-rate", - "separate-xy-resolution" """ return self._caps diff --git a/src/ratbagd-resolution.c b/src/ratbagd-resolution.c index cecadabe..356d974c 100644 --- a/src/ratbagd-resolution.c +++ b/src/ratbagd-resolution.c @@ -40,11 +40,6 @@ struct ratbagd_resolution { char *path; unsigned int xres, yres; unsigned int rate; - - struct { - bool individual_report_rate; - bool separate_xy_res; - } capabilities; }; static int ratbagd_resolution_set_report_rate(sd_bus_message *m, @@ -92,15 +87,45 @@ static int ratbagd_resolution_set_resolution(sd_bus_message *m, return sd_bus_reply_method_return(m, "u", r); } +static int +ratbagd_resolution_get_capabilities(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_resolution *resolution = userdata; + struct ratbag_resolution *lib_resolution = resolution->lib_resolution; + enum ratbag_device_capability cap; + int r; + + r = sd_bus_message_open_container(reply, 'a', "u"); + if (r < 0) + return r; + + cap = RATBAG_RESOLUTION_CAP_INDIVIDUAL_REPORT_RATE; + if (ratbag_resolution_has_capability(lib_resolution, cap)) { + r = sd_bus_message_append(reply, "u", cap); + if (r < 0) + return r; + } + + cap = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION; + if (ratbag_resolution_has_capability(lib_resolution, cap)) { + r = sd_bus_message_append(reply, "u", cap); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + 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("CapIndividualReportRate", "b", NULL, - offsetof(struct ratbagd_resolution, capabilities.individual_report_rate), - SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("CapSeparateXYResolution", "b", NULL, - offsetof(struct ratbagd_resolution, capabilities.separate_xy_res), - SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Capabilities", "au", ratbagd_resolution_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("XResolution", "u", NULL, offsetof(struct ratbagd_resolution, xres), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("YResolution", "u", NULL, offsetof(struct ratbagd_resolution, yres), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("ReportRate", "u", NULL, offsetof(struct ratbagd_resolution, rate), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), @@ -132,12 +157,6 @@ int ratbagd_resolution_new(struct ratbagd_resolution **out, 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); - resolution->capabilities.individual_report_rate = - ratbag_resolution_has_capability(lib_resolution, - RATBAG_RESOLUTION_CAP_INDIVIDUAL_REPORT_RATE); - resolution->capabilities.separate_xy_res = - ratbag_resolution_has_capability(lib_resolution, - RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION); sprintf(profile_buffer, "p%u", ratbagd_profile_get_index(profile)); sprintf(resolution_buffer, "r%u", index); From ff3730f3fba7dc9e4660fe841097d4f1fe1793e8 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 15 Mar 2016 13:21:56 +1000 Subject: [PATCH 100/137] device: use "Name" instead of "Description" This is the terminology used in libratbag as well (and everywhere else where we deal with input devices). Signed-off-by: Peter Hutterer --- python/ratbagctl.py | 10 +++++----- python/ratbagd/__init__.py | 6 +++--- src/ratbagd-device.c | 16 ++++++++-------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/python/ratbagctl.py b/python/ratbagctl.py index 8adc9f9b..37e5827c 100755 --- a/python/ratbagctl.py +++ b/python/ratbagctl.py @@ -34,7 +34,7 @@ import argparse def list_devices(r, args): for d in r.devices: - print("{:10s} {:32s}".format(d.id + ":", d.description)) + print("{:10s} {:32s}".format(d.id + ":", d.name)) def find_device(r, args): dev = None @@ -85,7 +85,7 @@ def show_device(r, args): RatbagdDevice.CAP_DEFAULT_PROFILE : "default-profile" } capabilities = [caps[c] for c in d.capabilities] - print("{} - {}".format(d.id, d.description)) + print("{} - {}".format(d.id, d.name)) print(" SVG: {}".format(d.svg)) print(" Capabilities: {}".format(", ".join(capabilities))) print("Number of Profiles: {}".format(len(d.profiles))) @@ -99,7 +99,7 @@ def show_device(r, args): def show_profile(r, args): p, d = find_profile(r, args) - print("Profile {} on {} ({})".format(args.profile, d.id, d.description)) + print("Profile {} on {} ({})".format(args.profile, d.id, d.name)) print(" Number of Buttons: {}".format(len(p.buttons))) print("Number of Resolutions: {}".format(len(p.resolutions))) active, default = -1, -1 @@ -118,7 +118,7 @@ def show_resolution(r, args): print("Resolution {} on Profile {} on {} ({})".format(args.resolution, args.profile, d.id, - d.description)) + d.name)) print(" Report Rate: {}Hz".format(r.report_rate)) if RatbagdResolution.CAP_SEPARATE_XY_RESOLUTION in r.capabilities: print(" Resolution: {}x{}dpi".format(*r.resolution)) @@ -137,7 +137,7 @@ def show_button(r, args): print("Button {} on Profile {} on {} ({})".format(args.button, args.profile, d.id, - d.description)) + d.name)) print(" Type: {}".format(b.button_type)) print(" Action Type: {}".format(b.action_type)) diff --git a/python/ratbagd/__init__.py b/python/ratbagd/__init__.py index 2c4dabbf..3df5766f 100644 --- a/python/ratbagd/__init__.py +++ b/python/ratbagd/__init__.py @@ -88,7 +88,7 @@ class RatbagdDevice(_RatbagdDBus): def __init__(self, object_path): _RatbagdDBus.__init__(self, "Device", object_path) self._devnode = self.dbus_property("Id") - self._description = self.dbus_property("Description") + self._name = self.dbus_property("Name") self._svg = self.dbus_property("Svg") self._svg_path = self.dbus_property("SvgPath") @@ -109,11 +109,11 @@ class RatbagdDevice(_RatbagdDBus): return self._profiles @property - def description(self): + def name(self): """ The device name, usually provided by the kernel. """ - return self._description + return self._name @property def svg(self): diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 05b98bf7..7006137d 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -118,7 +118,7 @@ error: return -ENOMEM; } -static int ratbagd_device_get_description(sd_bus *bus, +static int ratbagd_device_get_device_name(sd_bus *bus, const char *path, const char *interface, const char *property, @@ -127,16 +127,16 @@ static int ratbagd_device_get_description(sd_bus *bus, sd_bus_error *error) { struct ratbagd_device *device = userdata; - const char *description; + const char *name; - description = ratbag_device_get_name(device->lib_device); - if (!description) { - log_error("Unable to fetch description for %s\n", + name = ratbag_device_get_name(device->lib_device); + if (!name) { + log_error("Unable to fetch name for %s\n", ratbagd_device_get_name(device)); - description = ""; + name = ""; } - return sd_bus_message_append(reply, "s", description); + return sd_bus_message_append(reply, "s", name); } static int ratbagd_device_get_svg(sd_bus *bus, @@ -317,7 +317,7 @@ const sd_bus_vtable ratbagd_device_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct ratbagd_device, name), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Capabilities", "au", ratbagd_device_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("Description", "s", ratbagd_device_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Name", "s", ratbagd_device_get_device_name, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Svg", "s", ratbagd_device_get_svg, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SvgPath", "s", ratbagd_device_get_svg_path, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Profiles", "ao", ratbagd_device_get_profiles, 0, SD_BUS_VTABLE_PROPERTY_CONST), From 638b505ade92f00e4a780ea3fe0b6cf702bac8b2 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 15 Mar 2016 13:36:53 +1000 Subject: [PATCH 101/137] manager: drop GetDeviceById We don't really expect more than 2-3 devices even on a test box. This function serves little purpose, we can easily require a caller to just get all devices (usually just one anyway) and then go from there. Signed-off-by: Peter Hutterer --- README.md | 2 -- src/ratbagd.c | 22 ---------------------- 2 files changed, 24 deletions(-) diff --git a/README.md b/README.md index 56550c0d..4c582017 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,6 @@ The **org.freedesktop.ratbag1.Manager** interface provides: - Signals: - DeviceNew -> new device available, carries object path - DeviceRemoved -> device removed, carries object path -- Methods: - - GetDeviceByName(string) -> returns object path The **org.freedesktop.ratbag1.Device** interface provides: - Properties: diff --git a/src/ratbagd.c b/src/ratbagd.c index 172dda8c..233ec4f3 100644 --- a/src/ratbagd.c +++ b/src/ratbagd.c @@ -144,33 +144,11 @@ static int ratbagd_get_devices(sd_bus *bus, return sd_bus_message_close_container(reply); } -static int ratbagd_get_device_by_name(sd_bus_message *m, - void *userdata, - sd_bus_error *error) -{ - struct ratbagd *ctx = userdata; - struct ratbagd_device *device; - const char *name; - int r; - - r = sd_bus_message_read(m, "s", &name); - if (r < 0) - return r; - - device = ratbagd_device_lookup(ctx, name); - if (!device) - return -ENXIO; - - return sd_bus_reply_method_return(m, "o", - ratbagd_device_get_path(device)); -} - static const sd_bus_vtable ratbagd_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Devices", "ao", ratbagd_get_devices, 0, 0), SD_BUS_SIGNAL("DeviceNew", "o", 0), SD_BUS_SIGNAL("DeviceRemoved", "o", 0), - SD_BUS_METHOD("GetDeviceByName", "s", "o", ratbagd_get_device_by_name, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END, }; From a658b117a799aba4f86da82e2ad1510a319b602d Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 15 Mar 2016 14:40:44 +1000 Subject: [PATCH 102/137] device: add support for QUERY_CONFIGURATION device capability Signed-off-by: Peter Hutterer --- src/ratbagd-device.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 7006137d..b76ef7da 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -310,6 +310,13 @@ ratbagd_device_get_capabilities(sd_bus *bus, return r; } + cap = RATBAG_DEVICE_CAP_QUERY_CONFIGURATION; + if (ratbag_device_has_capability(lib_device, cap)) { + r = sd_bus_message_append(reply, "u", cap); + if (r < 0) + return r; + } + return sd_bus_message_close_container(reply); } From d874a2e5f14a8f5a8636dda92a94699e87506e98 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 16 Mar 2016 10:12:09 +1000 Subject: [PATCH 103/137] ratbagd 0.2 Signed-off-by: Peter Hutterer --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index b95e005e..25de2919 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ AC_PREREQ([2.64]) AC_INIT([ratbagd], - [0.1.2], + [0.2], [http://www.github.com/libratbag/ratbagd], [ratbagd], [http://www.github.com/libratbag/ratbagd]) From fc874c02497b221086b54553b84e6c85b0e36a18 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Sun, 18 Sep 2016 23:30:46 +0200 Subject: [PATCH 104/137] Add manpages for ratbagctl and ratbagd Signed-off-by: Stephen Kitt --- Makefile.am | 6 ++++ doc/ratbagctl.1 | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ doc/ratbagd.8 | 19 +++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 doc/ratbagctl.1 create mode 100644 doc/ratbagd.8 diff --git a/Makefile.am b/Makefile.am index 64b80b85..218aac46 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,6 +27,8 @@ lib_LTLIBRARIES = noinst_LTLIBRARIES = bin_PROGRAMS = noinst_PROGRAMS = +dist_man1_MANS = +dist_man8_MANS = AM_CPPFLAGS = \ -include $(top_builddir)/config.h \ @@ -80,6 +82,8 @@ ratbagd_LDADD = \ $(LIBSYSTEMD_LIBS) \ $(LIBRATBAG_LIBS) +dist_man8_MANS += doc/ratbagd.8 + # ------------------------------------------------------------------------------ # DBus and systemd configuration files @@ -119,3 +123,5 @@ python/ratbagctl: python/ratbagctl.py EXTRA_DIST += python/ratbagctl.py BUILT_SOURCES += python/ratbagctl + +dist_man1_MANS += doc/ratbagctl.1 diff --git a/doc/ratbagctl.1 b/doc/ratbagctl.1 new file mode 100644 index 00000000..90d1bc37 --- /dev/null +++ b/doc/ratbagctl.1 @@ -0,0 +1,75 @@ +.TH ratbagctl 1 "Apr 13, 2016" ratbagctl +.SH NAME +ratbagctl \- inspect and modify configurable mice +.SH SYNOPSIS +.B ratbagctl +.RB [ \-h ] +.RB [ \-V ] +.br +.B ratbagctl list-devices +.br +.B ratbagctl show-device +.RI < device > +.br +.B ratbagctl show-profile +.RI < device "> <" profile > +.br +.B ratbagctl show-resolution +.RI < device "> <" profile "> <" resolution > +.br +.B ratbagctl show-button +.RI < device "> <" profile "> <" button > +.SH DESCRIPTION +.SS Common options +.TP +.BR \-h +displays a short help message (it can be used with any form of the +.B ratbagctl +command). +.TP +.BR \-V +displays the version of +.B ratbagctl +and exits. +.SS Listing devices +.TP +.B list-devices +lists all identified devices on the system. +.SS Displaying a device +.TP +.BR show-device " <" \fIdevice\fP > +displays the device information for the given +.I device +(as identified by +.BR list-devices ). +.SS Displaying profiles +.TP +.IR \fBshow-profile\fP " <" device "> <" profile > +displays the profile information for the given +.I device +and +.IR "profile index" . +.SS Displaying resolution information +.TP +.IR \fBshow-resolution\fP " <" device "> <" profile "> <" resolution > +displays the resolution information for the given +.IR device , +.IR "profile index" , +and +.IR "resolution index" . +.SS Displaying button information +.TP +.IR \fBshow-button\fP " <" device "> <" profile "> <" button > +displays the resolution information for the given +.IR device , +.IR "profile index" , +and +.IR "button index" . +.SH SEE ALSO +.BR ratbagd (8) +.SH AUTHORS +.B ratbagctl +was written by David Herrmann, Peter Hutterer and Benjamin Tissoires. +.PP +This manual page was written by Stephen Kitt for +the Debian GNU/Linux system (but may be used by others). diff --git a/doc/ratbagd.8 b/doc/ratbagd.8 new file mode 100644 index 00000000..fcbad3e9 --- /dev/null +++ b/doc/ratbagd.8 @@ -0,0 +1,19 @@ +.TH ratbagd 8 "Apr 13, 2016" ratbagd +.SH NAME +ratbagd \- system daemon to introspect and modify configurable mice +.SH SYNOPSIS +.B ratbagd +.RB [ \-\-verbose ] +.SH DESCRIPTION +.B ratbagd +starts the daemon. It shouldn't be invoked directly; +.B ratbagd +is normally started through DBus activation. +.SH SEE ALSO +.BR ratbagctl (1) +.SH AUTHORS +.B ratbagd +was written by David Herrmann, Peter Hutterer and Benjamin Tissoires. +.PP +This manual page was written by Stephen Kitt for +the Debian GNU/Linux system (but may be used by others). From 9601ba132307b4c879eb7be7a4dddcde6f98b716 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Wed, 29 Mar 2017 23:30:23 +0200 Subject: [PATCH 105/137] python: catch more DBus exceptions Gio.bus_get_sync may return None when the DBus service is not available (see libratbag/piper#2). In addition to this, the service may time out when it is being started in which case Gio.DBusProxy.new_sync will raise a GLib.Gerror. This commit checks for both scenarios and raises a RatbagdDBusUnavailable exception when either one of them occurs. This will in turn be caught in for example Piper to properly deal with this. --- python/ratbagd/__init__.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/python/ratbagd/__init__.py b/python/ratbagd/__init__.py index 3df5766f..6fa70c18 100644 --- a/python/ratbagd/__init__.py +++ b/python/ratbagd/__init__.py @@ -35,13 +35,20 @@ class RatbagdDBusUnavailable(BaseException): class _RatbagdDBus(object): def __init__(self, interface, object_path): self._dbus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None) - self._proxy = Gio.DBusProxy.new_sync(self._dbus, - Gio.DBusProxyFlags.NONE, - None, - 'org.freedesktop.ratbag1', - object_path, - 'org.freedesktop.ratbag1.{}'.format(interface), - None) + if self._dbus is None: + raise RatbagdDBusUnavailable() + + try: + self._proxy = Gio.DBusProxy.new_sync(self._dbus, + Gio.DBusProxyFlags.NONE, + None, + 'org.freedesktop.ratbag1', + object_path, + 'org.freedesktop.ratbag1.{}'.format(interface), + None) + except GLib.GError: + raise RatbagdDBusUnavailable() + if self._proxy.get_name_owner() == None: raise RatbagdDBusUnavailable() @@ -60,6 +67,8 @@ class Ratbagd(_RatbagdDBus): The ratbagd top-level object. Provides a list of devices available through ratbagd, actual interaction with the devices is via the RatbagdDevice, RatbagdProfile and RatbagdResolution objects. + + Throws RatbagdDBusUnavailable when the DBus service is not available. """ def __init__(self): _RatbagdDBus.__init__(self, "Manager", '/org/freedesktop/ratbag1') From 617cd628eabbb95f44b90010fbeb6a615923d6fc Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Thu, 30 Mar 2017 10:42:55 +0200 Subject: [PATCH 106/137] python: replace == None with is None == checks for value equivalence, but in this case what we really want is address equivalence. Hence we use is. --- python/ratbagd/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ratbagd/__init__.py b/python/ratbagd/__init__.py index 6fa70c18..2e8a4cfc 100644 --- a/python/ratbagd/__init__.py +++ b/python/ratbagd/__init__.py @@ -49,7 +49,7 @@ class _RatbagdDBus(object): except GLib.GError: raise RatbagdDBusUnavailable() - if self._proxy.get_name_owner() == None: + if self._proxy.get_name_owner() is None: raise RatbagdDBusUnavailable() def dbus_property(self, property): From d358d7433b2d48982919c3a621d949caa4cca1c7 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 6 Apr 2017 16:49:55 +1000 Subject: [PATCH 107/137] Include config.h before anything else Signed-off-by: Peter Hutterer --- src/ratbagd-button.c | 2 ++ src/ratbagd-device.c | 2 ++ src/ratbagd-profile.c | 2 ++ src/ratbagd-resolution.c | 2 ++ src/ratbagd.c | 2 ++ src/ratbagd.h | 2 ++ src/shared-macro.h | 2 ++ src/shared-rbtree.c | 2 ++ src/shared-rbtree.h | 2 ++ 9 files changed, 18 insertions(+) diff --git a/src/ratbagd-button.c b/src/ratbagd-button.c index b4060d73..bdf78d5e 100644 --- a/src/ratbagd-button.c +++ b/src/ratbagd-button.c @@ -23,6 +23,8 @@ DEALINGS IN THE SOFTWARE. ***/ +#include "config.h" + #include #include #include diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index b76ef7da..94998a2c 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -23,6 +23,8 @@ DEALINGS IN THE SOFTWARE. ***/ +#include "config.h" + #include #include #include diff --git a/src/ratbagd-profile.c b/src/ratbagd-profile.c index fc93ede4..b945afb5 100644 --- a/src/ratbagd-profile.c +++ b/src/ratbagd-profile.c @@ -23,6 +23,8 @@ DEALINGS IN THE SOFTWARE. ***/ +#include "config.h" + #include #include #include diff --git a/src/ratbagd-resolution.c b/src/ratbagd-resolution.c index 356d974c..7af846c1 100644 --- a/src/ratbagd-resolution.c +++ b/src/ratbagd-resolution.c @@ -23,6 +23,8 @@ DEALINGS IN THE SOFTWARE. ***/ +#include "config.h" + #include #include #include diff --git a/src/ratbagd.c b/src/ratbagd.c index 233ec4f3..112b89ab 100644 --- a/src/ratbagd.c +++ b/src/ratbagd.c @@ -23,6 +23,8 @@ DEALINGS IN THE SOFTWARE. ***/ +#include "config.h" + #include #include #include diff --git a/src/ratbagd.h b/src/ratbagd.h index 01477f4f..32e27b8c 100644 --- a/src/ratbagd.h +++ b/src/ratbagd.h @@ -25,6 +25,8 @@ DEALINGS IN THE SOFTWARE. ***/ +#include "config.h" + #include #include #include diff --git a/src/shared-macro.h b/src/shared-macro.h index 748d4292..490f20fc 100644 --- a/src/shared-macro.h +++ b/src/shared-macro.h @@ -25,6 +25,8 @@ DEALINGS IN THE SOFTWARE. ***/ +#include "config.h" + #include #include #include diff --git a/src/shared-rbtree.c b/src/shared-rbtree.c index 53866241..5afe643c 100644 --- a/src/shared-rbtree.c +++ b/src/shared-rbtree.c @@ -28,6 +28,8 @@ * file do not contain a full prove for correctness. */ +#include "config.h" + #include "shared-rbtree.h" RBNode *rbnode_leftmost(RBNode *n) { diff --git a/src/shared-rbtree.h b/src/shared-rbtree.h index ffb0296d..9b5cd95b 100644 --- a/src/shared-rbtree.h +++ b/src/shared-rbtree.h @@ -19,6 +19,8 @@ along with rbtree; If not, see . ***/ +#include "config.h" + #ifdef __cplusplus extern "C" { #endif From 70a33ec78d5b92ce33d874038b82b101b0fa68ce Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 6 Apr 2017 17:09:18 +1000 Subject: [PATCH 108/137] Drop AM_MAINTAINER_MODE This isn't useful Signed-off-by: Peter Hutterer --- configure.ac | 1 - 1 file changed, 1 deletion(-) diff --git a/configure.ac b/configure.ac index 25de2919..d538d14b 100644 --- a/configure.ac +++ b/configure.ac @@ -15,7 +15,6 @@ AC_CONFIG_HEADERS([config.h]) AC_CONFIG_AUX_DIR([build-aux]) AC_USE_SYSTEM_EXTENSIONS -AM_MAINTAINER_MODE([enable]) AM_INIT_AUTOMAKE([foreign 1.11 -Wall -Wno-portability silent-rules tar-pax no-dist-gzip dist-xz subdir-objects parallel-tests]) AM_SILENT_RULES([yes]) AC_DEFINE_UNQUOTED([CANONICAL_HOST], "$host", [Canonical host string.]) From 25a92e61efb418b3b3ef516c44b368ec9228fe61 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 6 Apr 2017 17:09:48 +1000 Subject: [PATCH 109/137] configure.ac: drop xslt check Some leftover from the triassic period or so Signed-off-by: Peter Hutterer --- configure.ac | 1 - 1 file changed, 1 deletion(-) diff --git a/configure.ac b/configure.ac index d538d14b..26bed2db 100644 --- a/configure.ac +++ b/configure.ac @@ -28,7 +28,6 @@ AC_PROG_SED AC_PROG_CC_C99 AC_PATH_PROG([M4], [m4]) -AC_PATH_PROG([XSLTPROC], [xsltproc]) AM_PATH_PYTHON # ------------------------------------------------------------------------------ From 53ff42ea55213212c2d106d93a11ab12a2820936 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 24 Apr 2017 15:12:21 +1000 Subject: [PATCH 110/137] README: remove the compilation instructions for systemd By now you should have 229. And replace the instructions with actual ratbagd build instructions. Signed-off-by: Peter Hutterer --- README.md | 29 +++++------------------------ 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 4c582017..d6c98a8c 100644 --- a/README.md +++ b/README.md @@ -113,31 +113,12 @@ activation is possible. Compiling ratbagd ----------------- -ratbagd needs systemd >= 227. If you are running Fedora 23, you might find the -following instruction valuable: + ./autogen.sh && ./configure --prefix=/usr/ --libdir=/usr/lib64 + make + sudo make install -Download systemd v229 (master caused troubles with gcrypt and gpg-error last -time I tried). - - $ git clone --branch v229 https://github.com/systemd/systemd - - -Configure it with: - - $ ./autogen.sh && ./configure --prefix=/opt/systemd \ - --libdir=/opt/systemd/lib \ - --disable-gcrypt \ - --without-bashcompletiondir \ - --with-rootprefix=/opt/systemd \ - --with-sysvinit-path=/opt/systemd/etc \ - --with-sysvrcnd-path=/opt/systemd/etc/rc.d - -Then run make and make install. - -In ratbagd, you will need to add the newly installed libsystemd in the -pkg_config path: - - $ PKG_CONFIG_PATH=/opt/systemd/lib/pkgconfig ./configure +Depending on your distribution, you can omit the --libdir argument. Fedora +and related require it, Debian and related do not. License ------- From 894435371626aedf13d11c5149bc82e682d9bdc9 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 24 Apr 2017 15:07:10 +1000 Subject: [PATCH 111/137] Update for new caps in libratbag 0.6 Signed-off-by: Peter Hutterer --- configure.ac | 2 +- python/ratbagctl.py | 5 ++++- python/ratbagd/__init__.py | 7 +++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 26bed2db..b29fab10 100644 --- a/configure.ac +++ b/configure.ac @@ -116,7 +116,7 @@ AC_SUBST([OUR_LDFLAGS], "$with_ldflags") PKG_CHECK_MODULES([LIBUDEV], [libudev]) PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd >= 227]) -PKG_CHECK_MODULES([LIBRATBAG], [libratbag >= 0.4]) +PKG_CHECK_MODULES([LIBRATBAG], [libratbag >= 0.6]) PKG_CHECK_VAR([libratbag_data_dir], [libratbag], [pkgdatadir], [AC_DEFINE_UNQUOTED([LIBRATBAG_DATA_DIR], ["$libratbag_data_dir"], [Directory for libratbag's SVG files])]) diff --git a/python/ratbagctl.py b/python/ratbagctl.py index 37e5827c..78e6857e 100755 --- a/python/ratbagctl.py +++ b/python/ratbagctl.py @@ -82,7 +82,10 @@ def show_device(r, args): RatbagdDevice.CAP_SWITCHABLE_PROFILE : "switchable-profile", RatbagdDevice.CAP_BUTTON_KEY : "button-keys", RatbagdDevice.CAP_BUTTON_MACROS : "button-macros", - RatbagdDevice.CAP_DEFAULT_PROFILE : "default-profile" } + RatbagdDevice.CAP_DEFAULT_PROFILE : "default-profile", + RatbagdDevice.CAP_QUERY_CONFIGURATION : "query-configuration", + RatbagdDevice.CAP_DISABLE_PROFILE : "disable-profile", + RatbagdDevice.CAP_LED : "led" } capabilities = [caps[c] for c in d.capabilities] print("{} - {}".format(d.id, d.name)) diff --git a/python/ratbagd/__init__.py b/python/ratbagd/__init__.py index 2e8a4cfc..4217e56b 100644 --- a/python/ratbagd/__init__.py +++ b/python/ratbagd/__init__.py @@ -88,8 +88,11 @@ class RatbagdDevice(_RatbagdDBus): CAP_SWITCHABLE_RESOLUTION = 1 CAP_SWITCHABLE_PROFILE = 2 CAP_BUTTON_KEY = 3 - CAP_BUTTON_MACROS = 4 - CAP_DEFAULT_PROFILE = 5 + CAP_LED = 4 + CAP_BUTTON_MACROS = 5 + CAP_DEFAULT_PROFILE = 6 + CAP_QUERY_CONFIGURATION = 7 + CAP_DISABLE_PROFILE = 8 """ Represents a ratbagd device. From f5270e153963f7828d14f7c65c88510b194abe9a Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 6 Apr 2017 17:28:47 +1000 Subject: [PATCH 112/137] Change the sed replacement for meson's benefit No functional changes Signed-off-by: Peter Hutterer --- Makefile.am | 6 +++--- dbus/org.freedesktop.ratbag1.service.in | 2 +- python/ratbagctl.py | 2 +- ratbagd.service.in | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile.am b/Makefile.am index 218aac46..a3bf3967 100644 --- a/Makefile.am +++ b/Makefile.am @@ -91,14 +91,14 @@ unitdir = $(SYSTEMD_UNIT_DIR) unit_DATA = ratbagd.service $(unit_DATA): $(unit_DATA).in - $(AM_V_GEN)$(SED) -e 's|__BIN_PREFIX__|$(bindir)|g' < $< > $@ + $(AM_V_GEN)$(SED) -e 's|@bindir@|$(bindir)|g' < $< > $@ dbusservicedir = $(DBUS_SYSTEM_SERVICES_DIR) dbusservice_DATA = dbus/org.freedesktop.ratbag1.service $(dbusservice_DATA): $(dbusservice_DATA).in $(AM_V_GEN)$(MKDIR_P) dbus - $(AM_V_GEN)$(SED) -e 's|__BIN_PREFIX__|$(bindir)|g' < $< > $@ + $(AM_V_GEN)$(SED) -e 's|@bindir@|$(bindir)|g' < $< > $@ dbusconfigdir = $(DBUS_SYSTEM_CONFIG_DIR) dbusconfig_DATA = dbus/org.freedesktop.ratbag1.conf @@ -119,7 +119,7 @@ bin_SCRIPTS = \ python/ratbagctl: python/ratbagctl.py $(AM_V_GEN)$(MKDIR_P) python - $(AM_V_GEN)$(SED) -e "s/__VERSION__/$(PACKAGE_VERSION)/" < $^ > $@ + $(AM_V_GEN)$(SED) -e "s/@version@/$(PACKAGE_VERSION)/" < $^ > $@ EXTRA_DIST += python/ratbagctl.py BUILT_SOURCES += python/ratbagctl diff --git a/dbus/org.freedesktop.ratbag1.service.in b/dbus/org.freedesktop.ratbag1.service.in index 712bbfb2..8cad1c6f 100644 --- a/dbus/org.freedesktop.ratbag1.service.in +++ b/dbus/org.freedesktop.ratbag1.service.in @@ -1,5 +1,5 @@ [D-BUS Service] Name=org.freedesktop.ratbag1 -Exec=__BIN_PREFIX__/ratbagd +Exec=@bindir@/ratbagd User=root SystemdService=dbus-org.freedesktop.ratbag1.service diff --git a/python/ratbagctl.py b/python/ratbagctl.py index 78e6857e..3c672236 100755 --- a/python/ratbagctl.py +++ b/python/ratbagctl.py @@ -154,7 +154,7 @@ def show_button(r, args): def make_parser(): parser = argparse.ArgumentParser(description="Inspect and modify configurable mice") - parser.add_argument("-V", "--version", action="version", version="__VERSION__") + parser.add_argument("-V", "--version", action="version", version="@version@") subs = parser.add_subparsers(title="COMMANDS", help=None) list = subs.add_parser("list-devices", help="List available configurable mice") diff --git a/ratbagd.service.in b/ratbagd.service.in index 600ab8c0..e6f6eb9f 100644 --- a/ratbagd.service.in +++ b/ratbagd.service.in @@ -4,7 +4,7 @@ Description=Daemon to introspect and modify configurable mice [Service] Type=dbus BusName=org.freedesktop.ratbag1 -ExecStart=__BIN_PREFIX__/ratbagd +ExecStart=@bindir@/ratbagd Restart=on-abort [Install] From 8f7bf150df7687bf23f0c2fda0b8dfb6c03432ea Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 24 Apr 2017 13:42:29 +1000 Subject: [PATCH 113/137] Use automake to generate ratbagctl All we do is a single sed, we can leave that to automake. Signed-off-by: Peter Hutterer --- Makefile.am | 14 +++----------- configure.ac | 3 ++- python/{ratbagctl.py => ratbagctl.in} | 0 3 files changed, 5 insertions(+), 12 deletions(-) rename python/{ratbagctl.py => ratbagctl.in} (100%) mode change 100755 => 100644 diff --git a/Makefile.am b/Makefile.am index a3bf3967..1885de16 100644 --- a/Makefile.am +++ b/Makefile.am @@ -111,17 +111,9 @@ BUILT_SOURCES += ratbagd.service dbus/org.freedesktop.ratbag1.service # ------------------------------------------------------------------------------ # python module -dist_pkgpython_DATA = \ - python/ratbagd/__init__.py +dist_pkgpython_DATA = python/ratbagd/__init__.py +bin_SCRIPTS = python/ratbagctl -bin_SCRIPTS = \ - python/ratbagctl - -python/ratbagctl: python/ratbagctl.py - $(AM_V_GEN)$(MKDIR_P) python - $(AM_V_GEN)$(SED) -e "s/@version@/$(PACKAGE_VERSION)/" < $^ > $@ - -EXTRA_DIST += python/ratbagctl.py -BUILT_SOURCES += python/ratbagctl +EXTRA_DIST += python/ratbagctl.in dist_man1_MANS += doc/ratbagctl.1 diff --git a/configure.ac b/configure.ac index b29fab10..2409f931 100644 --- a/configure.ac +++ b/configure.ac @@ -144,7 +144,8 @@ AC_SUBST(DBUS_SYSTEM_CONFIG_DIR) # ------------------------------------------------------------------------------ # report -AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([Makefile + python/ratbagctl]) AC_OUTPUT AC_MSG_RESULT([ diff --git a/python/ratbagctl.py b/python/ratbagctl.in old mode 100755 new mode 100644 similarity index 100% rename from python/ratbagctl.py rename to python/ratbagctl.in From 9624d1bdcd5bf27193715f3cdded96161a36972e Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 6 Apr 2017 17:06:57 +1000 Subject: [PATCH 114/137] Add meson build file Signed-off-by: Peter Hutterer --- meson.build | 165 ++++++++++++++++++++++++++++++++++++++++++++ meson_options.txt | 9 +++ python/ratbagctl.in | 0 3 files changed, 174 insertions(+) create mode 100644 meson.build create mode 100644 meson_options.txt mode change 100644 => 100755 python/ratbagctl.in diff --git a/meson.build b/meson.build new file mode 100644 index 00000000..26db64e4 --- /dev/null +++ b/meson.build @@ -0,0 +1,165 @@ +project('ratbagd', 'c', + version : '0.2', + license : 'MIT/Expat', + meson_version : '>= 0.40.0', + default_options : [ 'c_std=gnu99' ]) + +ratbagd_version = meson.project_version().split('.') + +# Compiler setup +cc = meson.get_compiler('c') +cflags = [ + '-pipe', + '-Wall', + '-Wextra', + '-Wno-inline', + '-Wundef', + '-Wformat=2', + '-Wformat-security', + '-Wformat-nonliteral', + '-Wlogical-op', + '-Wsign-compare', + '-Wmissing-include-dirs', + '-Wold-style-definition', + '-Wpointer-arith', + '-Winit-self', + '-Wdeclaration-after-statement', + '-Wfloat-equal', + '-Wsuggest-attribute=noreturn', + '-Wmissing-prototypes', + '-Wstrict-prototypes', + '-Wredundant-decls', + '-Wmissing-declarations', + '-Wmissing-noreturn', + '-Wendif-labels', + '-Wstrict-aliasing=2', + '-Wwrite-strings', + '-Wno-long-long', + '-Wno-overlength-strings', + '-Wno-unused-parameter', + '-Wno-missing-field-initializers', + '-Wno-unused-result', + '-Werror=overflow', + '-Wdate-time', + '-Wnested-externs', + '-ffast-math', + '-fno-common', + '-fdiagnostics-show-option', + '-fno-strict-aliasing', + '-fvisibility=hidden', + '-ffunction-sections', + '-fdata-sections', + '-fstack-protector', + '-fstack-protector-strong', + '-fPIE', + '--param=ssp-buffer-size=4' +] +add_project_arguments(cflags, language: 'c') +add_project_arguments('-D_GNU_SOURCE', language : 'c') + +# Initialize config.h, to be added to in the various options below, config.h +# is generated at the end of this file +config_h = configuration_data() + +# dependencies +pkgconfig = import('pkgconfig') +dep_udev = dependency('libudev') +dep_systemd = dependency('libsystemd', version : '>=227') +dep_libratbag = dependency('libratbag', version : '>= 0.6') +dep_lm = cc.find_library('m') + +libratbag_data_dir = dep_libratbag.get_pkgconfig_variable('pkgdatadir') +config_h.set_quoted('LIBRATBAG_DATA_DIR', libratbag_data_dir) + +#### libshared.a #### +src_libshared = [ + 'src/shared-macro.h', + 'src/shared-rbtree.h', + 'src/shared-rbtree.c', +] + +deps_libshared = [ + dep_lm, +] + +lib_libshared = static_library('shared', + src_libshared, + dependencies : deps_libshared +) +dep_libshared = declare_dependency(link_with: lib_libshared) + +#### ratbagd #### +src_ratbagd = [ + 'src/ratbagd.h', + 'src/ratbagd.c', + 'src/ratbagd-button.c', + 'src/ratbagd-device.c', + 'src/ratbagd-profile.c', + 'src/ratbagd-resolution.c' +] + +deps_ratbagd = [ + dep_udev, + dep_systemd, + dep_libratbag, + dep_libshared, +] + +executable('ratbagd', + src_ratbagd, + dependencies : deps_ratbagd, + include_directories : include_directories('src'), + install : true, +) + +install_man('doc/ratbagd.8') + +#### unit file #### +unitdir = get_option('systemd-unit-dir') +if unitdir == '' + unitdir = get_option('libdir') + '/systemd/system' +endif + +config_bindir = configuration_data() +config_bindir.set('bindir', get_option('bindir')) + +install_data('ratbagd.service.in', + configuration : config_bindir, + install_dir : unitdir) + +dbusdir = get_option('dbus-root-dir') +if dbusdir == '' + dbusdir = get_option('datadir') + '/dbus-1' +endif + +install_data('dbus/org.freedesktop.ratbag1.service.in', + configuration : config_bindir, + install_dir : dbusdir + '/system-services') +install_data('dbus/org.freedesktop.ratbag1.conf', + configuration : config_bindir, + install_dir : dbusdir + '/system.d') + +#### python bindings #### + +py3_mod = import('python3') +py3 = py3_mod.find_python() +py3_dep = dependency('python3', required : true) + +pysrc_ratbagd = [ 'python/ratbagd/__init__.py' ] + +py3_purelib = py3_mod.sysconfig_path('purelib') + +install_data(pysrc_ratbagd, + install_dir : py3_purelib + '/ratbagd') + +config_ratbagctl = configuration_data() +config_ratbagctl.set('version', meson.project_version()) +configure_file(input : 'python/ratbagctl.in', + output : 'ratbagctl', + configuration : config_ratbagctl, + install_dir : get_option('bindir')) + +install_man('doc/ratbagctl.1') + +#### output files #### +configure_file(output: 'config.h', install: false, configuration: config_h) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 00000000..e7431145 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,9 @@ +option('systemd-unit-dir', + type : 'string', + default : '', + description : 'systemd unit directory [default=$libdir/systemd/system]') + +option('dbus-root-dir', + type : 'string', + default : '', + description : 'dbus service directory [default=$datadir/dbus-1]') diff --git a/python/ratbagctl.in b/python/ratbagctl.in old mode 100644 new mode 100755 From fa12517fb2f622062ef616a657db53b7f7c6ec64 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 24 Apr 2017 15:14:06 +1000 Subject: [PATCH 115/137] Drop autotools Signed-off-by: Peter Hutterer --- .gitignore | 24 ---- Makefile.am | 119 ------------------- README.md | 22 +++- autogen.sh | 48 -------- configure.ac | 163 -------------------------- m4/attributes.m4 | 292 ----------------------------------------------- 6 files changed, 17 insertions(+), 651 deletions(-) delete mode 100644 Makefile.am delete mode 100755 autogen.sh delete mode 100644 configure.ac delete mode 100644 m4/attributes.m4 diff --git a/.gitignore b/.gitignore index 5c5c81e2..a4eed7cd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,36 +1,12 @@ *.a -*.la -*.lo *.log *.o *.stamp *.swp *.trs *~ -.config.args -.deps/ .dirstamp .libs/ /*.tar.xz -Makefile -Makefile.in -autom4te.cache/ -aclocal.m4 -build-aux/ -config.h -config.h.in -config.log -config.status -configure -libtool -*.m4 -!m4/attributes.m4 -ratbagctl -./ratbagd -stamp-* -ratbagd -ratbagd.service -ratbagctl -org.freedesktop.ratbag1.service tags __pycache__ diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 1885de16..00000000 --- a/Makefile.am +++ /dev/null @@ -1,119 +0,0 @@ -# ------------------------------------------------------------------------------ -# main - -ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} -AM_MAKEFLAGS = --no-print-directory -AUTOMAKE_OPTIONS = color-tests parallel-tests - -GCC_COLORS ?= 'ooh, shiny!' -export GCC_COLORS - -SUBDIRS = . - -# remove targets if the command fails -.DELETE_ON_ERROR: - -# keep intermediate files -.SECONDARY: - -# Keep the test-suite.log -.PRECIOUS: $(TEST_SUITE_LOG) Makefile - -CLEANFILES = $(BUILT_SOURCES) -DISTCLEANFILES = -EXTRA_DIST = -BUILT_SOURCES = -lib_LTLIBRARIES = -noinst_LTLIBRARIES = -bin_PROGRAMS = -noinst_PROGRAMS = -dist_man1_MANS = -dist_man8_MANS = - -AM_CPPFLAGS = \ - -include $(top_builddir)/config.h \ - -I $(top_srcdir)/src \ - -I $(top_builddir)/src \ - $(OUR_CPPFLAGS) - -AM_CFLAGS = $(OUR_CFLAGS) -AM_LDFLAGS = $(OUR_LDFLAGS) - -# ------------------------------------------------------------------------------ -# libshared - -noinst_LTLIBRARIES += \ - libshared.la - -libshared_la_SOURCES = \ - src/shared-macro.h \ - src/shared-rbtree.h \ - src/shared-rbtree.c - -libshared_la_CFLAGS = \ - $(AM_CFLAGS) - -libshared_la_LIBADD = \ - -lm - -# ------------------------------------------------------------------------------ -# ratbagd - -bin_PROGRAMS += \ - ratbagd - -ratbagd_SOURCES = \ - src/ratbagd.h \ - src/ratbagd.c \ - src/ratbagd-button.c \ - src/ratbagd-device.c \ - src/ratbagd-profile.c \ - src/ratbagd-resolution.c - -ratbagd_CFLAGS = \ - $(AM_CFLAGS) \ - $(LIBUDEV_CFLAGS) \ - $(LIBSYSTEMD_CFLAGS) \ - $(LIBRATBAG_CFLAGS) - -ratbagd_LDADD = \ - libshared.la \ - $(LIBUDEV_LIBS) \ - $(LIBSYSTEMD_LIBS) \ - $(LIBRATBAG_LIBS) - -dist_man8_MANS += doc/ratbagd.8 - -# ------------------------------------------------------------------------------ -# DBus and systemd configuration files - -unitdir = $(SYSTEMD_UNIT_DIR) -unit_DATA = ratbagd.service - -$(unit_DATA): $(unit_DATA).in - $(AM_V_GEN)$(SED) -e 's|@bindir@|$(bindir)|g' < $< > $@ - -dbusservicedir = $(DBUS_SYSTEM_SERVICES_DIR) -dbusservice_DATA = dbus/org.freedesktop.ratbag1.service - -$(dbusservice_DATA): $(dbusservice_DATA).in - $(AM_V_GEN)$(MKDIR_P) dbus - $(AM_V_GEN)$(SED) -e 's|@bindir@|$(bindir)|g' < $< > $@ - -dbusconfigdir = $(DBUS_SYSTEM_CONFIG_DIR) -dbusconfig_DATA = dbus/org.freedesktop.ratbag1.conf - -EXTRA_DIST += \ - ratbagd.service.in \ - dbus/org.freedesktop.ratbag1.service.in \ - dbus/org.freedesktop.ratbag1.conf -BUILT_SOURCES += ratbagd.service dbus/org.freedesktop.ratbag1.service - -# ------------------------------------------------------------------------------ -# python module -dist_pkgpython_DATA = python/ratbagd/__init__.py -bin_SCRIPTS = python/ratbagctl - -EXTRA_DIST += python/ratbagctl.in - -dist_man1_MANS += doc/ratbagctl.1 diff --git a/README.md b/README.md index d6c98a8c..74e3e459 100644 --- a/README.md +++ b/README.md @@ -113,12 +113,24 @@ activation is possible. Compiling ratbagd ----------------- - ./autogen.sh && ./configure --prefix=/usr/ --libdir=/usr/lib64 - make - sudo make install +ratbagd uses the meson build system (see http://mesonbuild.com) which in +turn uses ninja to invoke the compiler (`ninja` may be `ninja-build` on your +distribution). From a fresh git checkout, run the following commands to init +the repository: -Depending on your distribution, you can omit the --libdir argument. Fedora -and related require it, Debian and related do not. + meson builddir --prefix=/usr/ + +And to build or re-build after code-changes, run: + + ninja -C builddir + sudo ninja -C builddir install + +Note: 'builddir' is the build output directory and can be changed to any +other directory name. To set configure-time options, use e.g. + + mesonconf builddir -Denable-documentation=no + +Run 'mesonconf builddir' to list the options. License ------- diff --git a/autogen.sh b/autogen.sh deleted file mode 100755 index dbb5141d..00000000 --- a/autogen.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh -# -# autogen.sh: prepare build system -# Run this script to prepare the build-system for your local checkout. It -# requires the usual autotools dependencies to be installed. -# -# Prepare build system, but don't configure: -# $ ./autogen.sh -# -# Prepare build system and run ./configure with debugging enabled: -# $ ./autogen.sh c -# -# Prepare build system and run ./configure with llvm over gcc: -# $ ./autogen.sh l -# -# You can put additional arguments to ./configure into ".config.args". They -# will be appended to the arguments used by this script. -# - -set -e - -oldpwd=$(pwd) -topdir=$(dirname $0) -cd $topdir - -autoreconf --force --install --symlink - -if [ -f "$topdir/.config.args" ]; then - args="$args $(cat $topdir/.config.args)" -fi - -cd $oldpwd - -if [ "x$1" = "xc" ]; then - $topdir/configure --enable-debug $args - make clean -elif [ "x$1" = "xl" ]; then - $topdir/configure CC=clang $args - make clean -else - echo - echo "----------------------------------------------------------------" - echo "Initialized build system. For a common configuration please run:" - echo "----------------------------------------------------------------" - echo - echo "$topdir/configure $args" - echo -fi diff --git a/configure.ac b/configure.ac deleted file mode 100644 index 2409f931..00000000 --- a/configure.ac +++ /dev/null @@ -1,163 +0,0 @@ -# ------------------------------------------------------------------------------ -# main - -AC_PREREQ([2.64]) - -AC_INIT([ratbagd], - [0.2], - [http://www.github.com/libratbag/ratbagd], - [ratbagd], - [http://www.github.com/libratbag/ratbagd]) - -AC_CONFIG_SRCDIR([src/ratbagd.h]) -AC_CONFIG_MACRO_DIR([m4]) -AC_CONFIG_HEADERS([config.h]) -AC_CONFIG_AUX_DIR([build-aux]) - -AC_USE_SYSTEM_EXTENSIONS -AM_INIT_AUTOMAKE([foreign 1.11 -Wall -Wno-portability silent-rules tar-pax no-dist-gzip dist-xz subdir-objects parallel-tests]) -AM_SILENT_RULES([yes]) -AC_DEFINE_UNQUOTED([CANONICAL_HOST], "$host", [Canonical host string.]) - -LT_PREREQ(2.2) -LT_INIT([disable-static]) - -AC_PROG_MKDIR_P -AC_PROG_LN_S -AC_PROG_SED -AC_PROG_CC_C99 - -AC_PATH_PROG([M4], [m4]) -AM_PATH_PYTHON - -# ------------------------------------------------------------------------------ -# arguments - -AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug], [enable debug options])) - -# ------------------------------------------------------------------------------ -# toolchain - -CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\ - -pipe \ - -Wall \ - -Wextra \ - -Wno-inline \ - -Wundef \ - "-Wformat=2 -Wformat-security -Wformat-nonliteral" \ - -Wlogical-op \ - -Wsign-compare \ - -Wmissing-include-dirs \ - -Wold-style-definition \ - -Wpointer-arith \ - -Winit-self \ - -Wdeclaration-after-statement \ - -Wfloat-equal \ - -Wsuggest-attribute=noreturn \ - -Wmissing-prototypes \ - -Wstrict-prototypes \ - -Wredundant-decls \ - -Wmissing-declarations \ - -Wmissing-noreturn \ - -Wendif-labels \ - -Wstrict-aliasing=2 \ - -Wwrite-strings \ - -Wno-long-long \ - -Wno-overlength-strings \ - -Wno-unused-parameter \ - -Wno-missing-field-initializers \ - -Wno-unused-result \ - -Werror=overflow \ - -Wdate-time \ - -Wnested-externs \ - -ffast-math \ - -fno-common \ - -fdiagnostics-show-option \ - -fno-strict-aliasing \ - -fvisibility=hidden \ - -ffunction-sections \ - -fdata-sections \ - -fstack-protector \ - -fstack-protector-strong \ - -fPIE \ - --param=ssp-buffer-size=4]) - -AS_CASE([$CC], [*clang*], - [CC_CHECK_FLAGS_APPEND([with_cppflags], [CPPFLAGS], [ \ - -Wno-typedef-redefinition \ - -Wno-gnu-variable-sized-type-not-at-end \ - ])]) - -CC_CHECK_FLAGS_APPEND([with_ldflags], [LDFLAGS], [\ - -Wl,--as-needed \ - -Wl,--no-undefined \ - -Wl,--gc-sections \ - -Wl,-z,relro \ - -Wl,-z,now \ - -pie]) - -AS_IF([test "x$enable_debug" = "xyes"], - [ - CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [ \ - -g \ - -O0 \ - -ftrapv]) - ], [ - CC_CHECK_FLAGS_APPEND([with_cppflags], [CPPFLAGS], [\ - -Wp,-D_FORTIFY_SOURCE=2]) - ]) - -AC_SUBST([OUR_CFLAGS], "$with_cflags") -AC_SUBST([OUR_CPPFLAGS], "$with_cppflags") -AC_SUBST([OUR_LDFLAGS], "$with_ldflags") - -# ------------------------------------------------------------------------------ -# dependencies - -PKG_CHECK_MODULES([LIBUDEV], [libudev]) -PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd >= 227]) -PKG_CHECK_MODULES([LIBRATBAG], [libratbag >= 0.6]) - -PKG_CHECK_VAR([libratbag_data_dir], [libratbag], [pkgdatadir], - [AC_DEFINE_UNQUOTED([LIBRATBAG_DATA_DIR], ["$libratbag_data_dir"], [Directory for libratbag's SVG files])]) - -# ------------------------------------------------------------------------------ -# options -AC_ARG_WITH([systemd-unit-dir], - AS_HELP_STRING([--with-systemd-unit-dir=DIR], - [systemd unit directory [[default=$libdir/systemd/system]]]), - [unitdir="$withval"], - [unitdir="$libdir/systemd/system"]) -SYSTEMD_UNIT_DIR=${unitdir} -AC_SUBST(SYSTEMD_UNIT_DIR) - -AC_ARG_WITH([dbus-root-dir], - AS_HELP_STRING([--with-dbus-root-dir=DIR], - [dbus service directory [[default=$datadir/dbus-1]]]), - [dbusrootdir="$withval"], - [dbusrootdir="$datadir/dbus-1"]) -DBUS_SYSTEM_SERVICES_DIR="${dbusrootdir}/system-services" -DBUS_SYSTEM_CONFIG_DIR="${dbusrootdir}/system.d" -AC_SUBST(DBUS_SYSTEM_SERVICES_DIR) -AC_SUBST(DBUS_SYSTEM_CONFIG_DIR) - -# ------------------------------------------------------------------------------ -# report - -AC_CONFIG_FILES([Makefile - python/ratbagctl]) - -AC_OUTPUT -AC_MSG_RESULT([ - $PACKAGE_NAME $VERSION - debug: ${enable_debug} - - prefix: ${prefix} - exec_prefix: ${exec_prefix} - includedir: ${includedir} - libdir: ${libdir} - - CFLAGS: ${OUR_CFLAGS} ${CFLAGS} - CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS} - LDFLAGS: ${OUR_LDFLAGS} ${LDFLAGS} -]) diff --git a/m4/attributes.m4 b/m4/attributes.m4 deleted file mode 100644 index db5df250..00000000 --- a/m4/attributes.m4 +++ /dev/null @@ -1,292 +0,0 @@ -dnl Macros to check the presence of generic (non-typed) symbols. -dnl Copyright (c) 2006-2008 Diego Pettenò -dnl Copyright (c) 2006-2008 xine project -dnl Copyright (c) 2012 Lucas De Marchi -dnl -dnl This program is free software; you can redistribute it and/or modify -dnl it under the terms of the GNU General Public License as published by -dnl the Free Software Foundation; either version 2, or (at your option) -dnl any later version. -dnl -dnl This program is distributed in the hope that it will be useful, -dnl but WITHOUT ANY WARRANTY; without even the implied warranty of -dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -dnl GNU General Public License for more details. -dnl -dnl You should have received a copy of the GNU General Public License -dnl along with this program; if not, write to the Free Software -dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -dnl 02110-1301, USA. -dnl -dnl As a special exception, the copyright owners of the -dnl macro gives unlimited permission to copy, distribute and modify the -dnl configure scripts that are the output of Autoconf when processing the -dnl Macro. You need not follow the terms of the GNU General Public -dnl License when using or distributing such scripts, even though portions -dnl of the text of the Macro appear in them. The GNU General Public -dnl License (GPL) does govern all other use of the material that -dnl constitutes the Autoconf Macro. -dnl -dnl This special exception to the GPL applies to versions of the -dnl Autoconf Macro released by this project. When you make and -dnl distribute a modified version of the Autoconf Macro, you may extend -dnl this special exception to the GPL to apply to your modified version as -dnl well. - -dnl Check if FLAG in ENV-VAR is supported by compiler and append it -dnl to WHERE-TO-APPEND variable. Note that we invert -Wno-* checks to -dnl -W* as gcc cannot test for negated warnings. If a C snippet is passed, -dnl use it, otherwise use a simple main() definition that just returns 0. -dnl CC_CHECK_FLAG_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG], [C-SNIPPET]) - -AC_DEFUN([CC_CHECK_FLAG_APPEND], [ - AC_CACHE_CHECK([if $CC supports flag $3 in envvar $2], - AS_TR_SH([cc_cv_$2_$3]), - [eval "AS_TR_SH([cc_save_$2])='${$2}'" - eval "AS_TR_SH([$2])='-Werror `echo "$3" | sed 's/^-Wno-/-W/'`'" - AC_LINK_IFELSE([AC_LANG_SOURCE(ifelse([$4], [], - [int main(void) { return 0; } ], - [$4]))], - [eval "AS_TR_SH([cc_cv_$2_$3])='yes'"], - [eval "AS_TR_SH([cc_cv_$2_$3])='no'"]) - eval "AS_TR_SH([$2])='$cc_save_$2'"]) - - AS_IF([eval test x$]AS_TR_SH([cc_cv_$2_$3])[ = xyes], - [eval "$1='${$1} $3'"]) -]) - -dnl CC_CHECK_FLAGS_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG1 FLAG2], [C-SNIPPET]) -AC_DEFUN([CC_CHECK_FLAGS_APPEND], [ - for flag in [$3]; do - CC_CHECK_FLAG_APPEND([$1], [$2], $flag, [$4]) - done -]) - -dnl Check if the flag is supported by linker (cacheable) -dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) - -AC_DEFUN([CC_CHECK_LDFLAGS], [ - AC_CACHE_CHECK([if $CC supports $1 flag], - AS_TR_SH([cc_cv_ldflags_$1]), - [ac_save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS $1" - AC_LINK_IFELSE([int main() { return 1; }], - [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"], - [eval "AS_TR_SH([cc_cv_ldflags_$1])="]) - LDFLAGS="$ac_save_LDFLAGS" - ]) - - AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes], - [$2], [$3]) -]) - -dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for -dnl the current linker to avoid undefined references in a shared object. -AC_DEFUN([CC_NOUNDEFINED], [ - dnl We check $host for which systems to enable this for. - AC_REQUIRE([AC_CANONICAL_HOST]) - - case $host in - dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads - dnl are requested, as different implementations are present; to avoid problems - dnl use -Wl,-z,defs only for those platform not behaving this way. - *-freebsd* | *-openbsd*) ;; - *) - dnl First of all check for the --no-undefined variant of GNU ld. This allows - dnl for a much more readable command line, so that people can understand what - dnl it does without going to look for what the heck -z defs does. - for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do - CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"]) - break - done - ;; - esac - - AC_SUBST([LDFLAGS_NOUNDEFINED]) -]) - -dnl Check for a -Werror flag or equivalent. -Werror is the GCC -dnl and ICC flag that tells the compiler to treat all the warnings -dnl as fatal. We usually need this option to make sure that some -dnl constructs (like attributes) are not simply ignored. -dnl -dnl Other compilers don't support -Werror per se, but they support -dnl an equivalent flag: -dnl - Sun Studio compiler supports -errwarn=%all -AC_DEFUN([CC_CHECK_WERROR], [ - AC_CACHE_CHECK( - [for $CC way to treat warnings as errors], - [cc_cv_werror], - [CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror], - [CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])]) - ]) -]) - -AC_DEFUN([CC_CHECK_ATTRIBUTE], [ - AC_REQUIRE([CC_CHECK_WERROR]) - AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))], - AS_TR_SH([cc_cv_attribute_$1]), - [ac_save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $cc_cv_werror" - AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])], - [eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"], - [eval "AS_TR_SH([cc_cv_attribute_$1])='no'"]) - CFLAGS="$ac_save_CFLAGS" - ]) - - AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes], - [AC_DEFINE( - AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1, - [Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))] - ) - $4], - [$5]) -]) - -AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [ - CC_CHECK_ATTRIBUTE( - [constructor],, - [void __attribute__((constructor)) ctor() { int a; }], - [$1], [$2]) -]) - -AC_DEFUN([CC_ATTRIBUTE_FORMAT], [ - CC_CHECK_ATTRIBUTE( - [format], [format(printf, n, n)], - [void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }], - [$1], [$2]) -]) - -AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [ - CC_CHECK_ATTRIBUTE( - [format_arg], [format_arg(printf)], - [char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }], - [$1], [$2]) -]) - -AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [ - CC_CHECK_ATTRIBUTE( - [visibility_$1], [visibility("$1")], - [void __attribute__((visibility("$1"))) $1_function() { }], - [$2], [$3]) -]) - -AC_DEFUN([CC_ATTRIBUTE_NONNULL], [ - CC_CHECK_ATTRIBUTE( - [nonnull], [nonnull()], - [void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }], - [$1], [$2]) -]) - -AC_DEFUN([CC_ATTRIBUTE_UNUSED], [ - CC_CHECK_ATTRIBUTE( - [unused], , - [void some_function(void *foo, __attribute__((unused)) void *bar);], - [$1], [$2]) -]) - -AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [ - CC_CHECK_ATTRIBUTE( - [sentinel], , - [void some_function(void *foo, ...) __attribute__((sentinel));], - [$1], [$2]) -]) - -AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [ - CC_CHECK_ATTRIBUTE( - [deprecated], , - [void some_function(void *foo, ...) __attribute__((deprecated));], - [$1], [$2]) -]) - -AC_DEFUN([CC_ATTRIBUTE_ALIAS], [ - CC_CHECK_ATTRIBUTE( - [alias], [weak, alias], - [void other_function(void *foo) { } - void some_function(void *foo) __attribute__((weak, alias("other_function")));], - [$1], [$2]) -]) - -AC_DEFUN([CC_ATTRIBUTE_MALLOC], [ - CC_CHECK_ATTRIBUTE( - [malloc], , - [void * __attribute__((malloc)) my_alloc(int n);], - [$1], [$2]) -]) - -AC_DEFUN([CC_ATTRIBUTE_PACKED], [ - CC_CHECK_ATTRIBUTE( - [packed], , - [struct astructure { char a; int b; long c; void *d; } __attribute__((packed));], - [$1], [$2]) -]) - -AC_DEFUN([CC_ATTRIBUTE_CONST], [ - CC_CHECK_ATTRIBUTE( - [const], , - [int __attribute__((const)) twopow(int n) { return 1 << n; } ], - [$1], [$2]) -]) - -AC_DEFUN([CC_FLAG_VISIBILITY], [ - AC_REQUIRE([CC_CHECK_WERROR]) - AC_CACHE_CHECK([if $CC supports -fvisibility=hidden], - [cc_cv_flag_visibility], - [cc_flag_visibility_save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $cc_cv_werror" - CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden], - cc_cv_flag_visibility='yes', - cc_cv_flag_visibility='no') - CFLAGS="$cc_flag_visibility_save_CFLAGS"]) - - AS_IF([test "x$cc_cv_flag_visibility" = "xyes"], - [AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1, - [Define this if the compiler supports the -fvisibility flag]) - $1], - [$2]) -]) - -AC_DEFUN([CC_FUNC_EXPECT], [ - AC_REQUIRE([CC_CHECK_WERROR]) - AC_CACHE_CHECK([if compiler has __builtin_expect function], - [cc_cv_func_expect], - [ac_save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $cc_cv_werror" - AC_COMPILE_IFELSE([AC_LANG_SOURCE( - [int some_function() { - int a = 3; - return (int)__builtin_expect(a, 3); - }])], - [cc_cv_func_expect=yes], - [cc_cv_func_expect=no]) - CFLAGS="$ac_save_CFLAGS" - ]) - - AS_IF([test "x$cc_cv_func_expect" = "xyes"], - [AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1, - [Define this if the compiler supports __builtin_expect() function]) - $1], - [$2]) -]) - -AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [ - AC_REQUIRE([CC_CHECK_WERROR]) - AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported], - [cc_cv_attribute_aligned], - [ac_save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $cc_cv_werror" - for cc_attribute_align_try in 64 32 16 8 4 2; do - AC_COMPILE_IFELSE([AC_LANG_SOURCE([ - int main() { - static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0; - return c; - }])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break]) - done - CFLAGS="$ac_save_CFLAGS" - ]) - - if test "x$cc_cv_attribute_aligned" != "x"; then - AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned], - [Define the highest alignment supported]) - fi -]) From 44471d3c42ef05b7a2b36860e6ccf53fe0af8d04 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 2 May 2017 10:10:20 +1000 Subject: [PATCH 116/137] meson: use warning_level=2 instead of manual -Wall -Wextra Signed-off-by: Peter Hutterer --- meson.build | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 26db64e4..e2abdac9 100644 --- a/meson.build +++ b/meson.build @@ -2,7 +2,7 @@ project('ratbagd', 'c', version : '0.2', license : 'MIT/Expat', meson_version : '>= 0.40.0', - default_options : [ 'c_std=gnu99' ]) + default_options : [ 'c_std=gnu99', 'warning_level=2' ]) ratbagd_version = meson.project_version().split('.') @@ -10,8 +10,6 @@ ratbagd_version = meson.project_version().split('.') cc = meson.get_compiler('c') cflags = [ '-pipe', - '-Wall', - '-Wextra', '-Wno-inline', '-Wundef', '-Wformat=2', From 28956126ec742cdd66b8c17e9b35ed9340598765 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Mon, 8 May 2017 10:23:21 +0200 Subject: [PATCH 117/137] meson: correctly install service files https://github.com/libratbag/ratbagd/issues/18 --- meson.build | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index e2abdac9..aa098889 100644 --- a/meson.build +++ b/meson.build @@ -119,20 +119,22 @@ if unitdir == '' endif config_bindir = configuration_data() -config_bindir.set('bindir', get_option('bindir')) +config_bindir.set('bindir', join_paths(get_option('prefix'), get_option('bindir'))) -install_data('ratbagd.service.in', - configuration : config_bindir, - install_dir : unitdir) +configure_file(input : 'ratbagd.service.in', + output : 'ratbagd.service', + configuration : config_bindir, + install_dir : unitdir) dbusdir = get_option('dbus-root-dir') if dbusdir == '' dbusdir = get_option('datadir') + '/dbus-1' endif -install_data('dbus/org.freedesktop.ratbag1.service.in', - configuration : config_bindir, - install_dir : dbusdir + '/system-services') +configure_file(input : 'dbus/org.freedesktop.ratbag1.service.in', + output : 'org.freedesktop.ratbag1.service', + configuration : config_bindir, + install_dir : dbusdir + '/system-services') install_data('dbus/org.freedesktop.ratbag1.conf', configuration : config_bindir, install_dir : dbusdir + '/system.d') From a2b858008f5ae0c6343eaf2b3422cd1eadc47789 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Mon, 8 May 2017 10:30:31 +0200 Subject: [PATCH 118/137] meson: use join_paths with dbusdir for consistency --- meson.build | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index aa098889..45738e85 100644 --- a/meson.build +++ b/meson.build @@ -128,16 +128,16 @@ configure_file(input : 'ratbagd.service.in', dbusdir = get_option('dbus-root-dir') if dbusdir == '' - dbusdir = get_option('datadir') + '/dbus-1' + dbusdir = join_paths(get_option('datadir'), 'dbus-1') endif configure_file(input : 'dbus/org.freedesktop.ratbag1.service.in', output : 'org.freedesktop.ratbag1.service', configuration : config_bindir, - install_dir : dbusdir + '/system-services') + install_dir : join_paths(dbusdir, 'system-services')) install_data('dbus/org.freedesktop.ratbag1.conf', configuration : config_bindir, - install_dir : dbusdir + '/system.d') + install_dir : join_paths(dbusdir, 'system.d')) #### python bindings #### From 57ffc9c5d3e2ec3cd823b7a096735033ce512079 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 5 May 2017 14:17:43 +1000 Subject: [PATCH 119/137] meson: drop a bunch of compiler flags These all affect the final executable and should be under the control of the distro. Signed-off-by: Peter Hutterer --- meson.build | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/meson.build b/meson.build index 45738e85..5d2097ea 100644 --- a/meson.build +++ b/meson.build @@ -9,7 +9,6 @@ ratbagd_version = meson.project_version().split('.') # Compiler setup cc = meson.get_compiler('c') cflags = [ - '-pipe', '-Wno-inline', '-Wundef', '-Wformat=2', @@ -40,17 +39,6 @@ cflags = [ '-Werror=overflow', '-Wdate-time', '-Wnested-externs', - '-ffast-math', - '-fno-common', - '-fdiagnostics-show-option', - '-fno-strict-aliasing', - '-fvisibility=hidden', - '-ffunction-sections', - '-fdata-sections', - '-fstack-protector', - '-fstack-protector-strong', - '-fPIE', - '--param=ssp-buffer-size=4' ] add_project_arguments(cflags, language: 'c') add_project_arguments('-D_GNU_SOURCE', language : 'c') From 2750f8c49b26c6cca452d5dda5f3f7739de76b3a Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 5 May 2017 14:19:57 +1000 Subject: [PATCH 120/137] Mark the unknown button type as explicit fallthrough Signed-off-by: Peter Hutterer --- src/ratbagd-button.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ratbagd-button.c b/src/ratbagd-button.c index bdf78d5e..4956fc42 100644 --- a/src/ratbagd-button.c +++ b/src/ratbagd-button.c @@ -200,6 +200,7 @@ static int ratbagd_button_get_special(sd_bus *bus, switch(special) { default: log_error("Unknown special type %d\n", special); + /* fallthrough */ case RATBAG_BUTTON_ACTION_SPECIAL_UNKNOWN: type = "unknown"; break; From 190e78c79c16216d6314e30f25363e84111aa344 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Mon, 8 May 2017 10:37:48 +0200 Subject: [PATCH 121/137] README: small documentation fixes --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 74e3e459..0ca16f0b 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ The **org.freedesktop.ratbag1.Button** interface provides: - ButtonMapping -> uint of the current button mapping (if mapping to button) - SpecialMapping -> string of the current special mapping (if mapped to special) - KeyMapping -> array of uints, first entry is the keycode, other entries, if any, are modifiers (if mapped to key) - - ActionType -> string describing the action type of the button ("none", "button", "key", "special", "macro", "unknown"). This decides which *Mapping property has a value + - ActionType -> string describing the action type of the button ("none", "button", "key", "special", "macro", "unknown"). This decides which \*Mapping property has a value - ActionTypes -> array of strings, possible values for ActionType - Methods: - SetButtonMapping(uint) -> set the button mapping to the given button @@ -92,19 +92,21 @@ ratbagd is intended to run as dbus-activated systemd service. This requires installation of the following files: sudo cp dbus/org.freedesktop.ratbag1.conf /etc/dbus-1/system.d/org.freedesktop.ratbag1.conf - sudo cp dbus/org.freedesktop.ratbag1.service /etc/dbus-1/systemd-services/org.freedesktop.ratbag1.conf + sudo cp dbus/org.freedesktop.ratbag1.service /etc/dbus-1/system-services/org.freedesktop.ratbag1.conf sudo cp ratbagd.service /etc/systemd/system/ratbagd.service The files are installed into the prefix by make install, see also the -configure switches ---with-systemd-unit-dir and --with-dbus-root-dir. +configure switches `--with-systemd-unit-dir` and `--with-dbus-root-dir`. Developers are encouraged to simply symlink to the files in the git repository. For the files to take effect, you should run + sudo systemctl daemon-reload sudo systemctl reload dbus.service And finally, to enable the service: + sudo systemctl enable ratbagd.service This places the required symlink into the systemd directory so that dbus @@ -125,12 +127,12 @@ And to build or re-build after code-changes, run: ninja -C builddir sudo ninja -C builddir install -Note: 'builddir' is the build output directory and can be changed to any +Note: `builddir` is the build output directory and can be changed to any other directory name. To set configure-time options, use e.g. mesonconf builddir -Denable-documentation=no -Run 'mesonconf builddir' to list the options. +Run `mesonconf builddir` to list the options. License ------- From 3a764b6aae3cffdd096cdaa6759d056fae3557a1 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Tue, 9 May 2017 14:14:58 +0200 Subject: [PATCH 122/137] README: replace configure switches with mesonconf switches --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0ca16f0b..65d03e9c 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ installation of the following files: sudo cp ratbagd.service /etc/systemd/system/ratbagd.service The files are installed into the prefix by make install, see also the -configure switches `--with-systemd-unit-dir` and `--with-dbus-root-dir`. +configure-time options `-Dsystemd-unit-dir` and `-Ddbus-root-dir`. Developers are encouraged to simply symlink to the files in the git repository. From 4dc15451b773a3910101a24a4ab44e53bb1a2059 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Tue, 9 May 2017 14:30:09 +0200 Subject: [PATCH 123/137] README: s/make install/ninja install/ --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 65d03e9c..52f8f139 100644 --- a/README.md +++ b/README.md @@ -95,10 +95,10 @@ installation of the following files: sudo cp dbus/org.freedesktop.ratbag1.service /etc/dbus-1/system-services/org.freedesktop.ratbag1.conf sudo cp ratbagd.service /etc/systemd/system/ratbagd.service -The files are installed into the prefix by make install, see also the -configure-time options `-Dsystemd-unit-dir` and `-Ddbus-root-dir`. -Developers are encouraged to simply symlink to the files in the git -repository. +The files are installed into the prefix by `ninja install`, see also the +configure-time options `-Dsystemd-unit-dir` and `-Ddbus-root-dir` (see +"Compiling ratbagd" below). Developers are encouraged to simply symlink to the +files in the git repository. For the files to take effect, you should run From 178b08cd0a587f4afbca2cfff14c6f2830f7fdca Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 12 May 2017 16:35:41 +0200 Subject: [PATCH 124/137] ratbagd 0.3 Signed-off-by: Benjamin Tissoires --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 5d2097ea..7c223482 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('ratbagd', 'c', - version : '0.2', + version : '0.3', license : 'MIT/Expat', meson_version : '>= 0.40.0', default_options : [ 'c_std=gnu99', 'warning_level=2' ]) From 2722e008e040491e8fef09ab9444ec70160b8b36 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Mon, 15 May 2017 09:48:07 +0200 Subject: [PATCH 125/137] profile: add signal for active profile changes This implements a signal that is fired whenever the active profile changes. For now the signal is only fired when the profile changes through the setter, ratbagd_profile_set_active, as profile changes may not always be hooked up in the hardware. Fixes #7. --- README.md | 2 ++ src/ratbagd-profile.c | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/README.md b/README.md index 52f8f139..4b6fba78 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,8 @@ The **org.freedesktop.ratbag1.Profile** interface provides: - Methods: - SetActive(void) -> set this profile to be the active profile - GetResolutionByIndex(uint) -> returns the object path for the given index +- Signals: + - ActiveProfileChanged -> active profile changed, carries index of the currently active profile The **org.freedesktop.ratbag1.Resolution** interface provides: - Properties: diff --git a/src/ratbagd-profile.c b/src/ratbagd-profile.c index b945afb5..e36e94b9 100644 --- a/src/ratbagd-profile.c +++ b/src/ratbagd-profile.c @@ -245,6 +245,13 @@ static int ratbagd_profile_set_active(sd_bus_message *m, if (r < 0) return r; + (void) sd_bus_emit_signal(sd_bus_message_get_bus(m), + "/org/freedesktop/ratbag1", + "/org.freedesktop.ratbag1.Profile", + "ActiveProfileChanged", + "u", + profile->index); + return sd_bus_reply_method_return(m, "u", ratbag_profile_set_active(profile->lib_profile)); } @@ -279,6 +286,7 @@ const sd_bus_vtable ratbagd_profile_vtable[] = { 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), SD_BUS_METHOD("GetResolutionByIndex", "u", "o", ratbagd_profile_get_resolution_by_index, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_SIGNAL("ActiveProfileChanged", "u", 0), SD_BUS_VTABLE_END, }; From b1feabaf64265f1f3a027e7b966c4decd0c9d052 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Mon, 15 May 2017 10:07:01 +0200 Subject: [PATCH 126/137] resolution: add signal for active resolution changes This implements a signal that is fired whenever the active resolution changes. For now the signal is only fired when the resolution changes through the setter, ratbagd_resolution_set_resolution, as profile changes may not always be hooked up in the hardware. Reference #8. --- README.md | 2 ++ src/ratbagd-resolution.c | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/README.md b/README.md index 4b6fba78..8a03a435 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,8 @@ The **org.freedesktop.ratbag1.Resolution** interface provides: - Methods: - SetResolution(uint, uint) -> x/y resolution to assign - SetReportRate(uint) -> uint for the report rate to assign +- Signals: + - ActiveResolutionChanged -> active resolution changed, carries index of the currently active resolution The **org.freedesktop.ratbag1.Button** interface provides: - Properties: diff --git a/src/ratbagd-resolution.c b/src/ratbagd-resolution.c index 7af846c1..cc8b9c51 100644 --- a/src/ratbagd-resolution.c +++ b/src/ratbagd-resolution.c @@ -86,6 +86,14 @@ static int ratbagd_resolution_set_resolution(sd_bus_message *m, resolution->xres = xres; resolution->yres = yres; } + + (void) sd_bus_emit_signal(sd_bus_message_get_bus(m), + "/org/freedesktop/ratbag1", + "/org.freedesktop.ratbag1.Resolution", + "ActiveResolutionChanged", + "u", + resolution->index); + return sd_bus_reply_method_return(m, "u", r); } @@ -133,6 +141,7 @@ const sd_bus_vtable ratbagd_resolution_vtable[] = { SD_BUS_PROPERTY("ReportRate", "u", NULL, offsetof(struct ratbagd_resolution, rate), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_METHOD("SetReportRate", "u", "u", ratbagd_resolution_set_report_rate, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetResolution", "uu", "u", ratbagd_resolution_set_resolution, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_SIGNAL("ActiveResolutionChanged", "u", 0), SD_BUS_VTABLE_END, }; From 299c49c2918bd10a094094e55b8a310aaa93a396 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Tue, 16 May 2017 15:01:14 +0200 Subject: [PATCH 127/137] README: remove ambiguity in signal descriptions --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8a03a435..e7d0a75a 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ The **org.freedesktop.ratbag1.Profile** interface provides: - SetActive(void) -> set this profile to be the active profile - GetResolutionByIndex(uint) -> returns the object path for the given index - Signals: - - ActiveProfileChanged -> active profile changed, carries index of the currently active profile + - ActiveProfileChanged -> active profile changed, carries index of the new active profile The **org.freedesktop.ratbag1.Resolution** interface provides: - Properties: @@ -67,7 +67,7 @@ The **org.freedesktop.ratbag1.Resolution** interface provides: - SetResolution(uint, uint) -> x/y resolution to assign - SetReportRate(uint) -> uint for the report rate to assign - Signals: - - ActiveResolutionChanged -> active resolution changed, carries index of the currently active resolution + - ActiveResolutionChanged -> active resolution changed, carries index of the new active resolution The **org.freedesktop.ratbag1.Button** interface provides: - Properties: From dd71c23a047c796ee3a90a048eea644ce40c3a30 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Wed, 17 May 2017 11:11:23 +0200 Subject: [PATCH 128/137] resolution: add set_default method Fixes #8. --- README.md | 2 ++ src/ratbagd-resolution.c | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/README.md b/README.md index e7d0a75a..d722886c 100644 --- a/README.md +++ b/README.md @@ -66,8 +66,10 @@ The **org.freedesktop.ratbag1.Resolution** interface provides: - Methods: - SetResolution(uint, uint) -> x/y resolution to assign - SetReportRate(uint) -> uint for the report rate to assign + - SetDefault -> set this resolution to be the default - Signals: - ActiveResolutionChanged -> active resolution changed, carries index of the new active resolution + - DefaultResolutionChanged -> default resolution changed, carries index of the new default resolution The **org.freedesktop.ratbag1.Button** interface provides: - Properties: diff --git a/src/ratbagd-resolution.c b/src/ratbagd-resolution.c index cc8b9c51..b2ea9af6 100644 --- a/src/ratbagd-resolution.c +++ b/src/ratbagd-resolution.c @@ -97,6 +97,25 @@ static int ratbagd_resolution_set_resolution(sd_bus_message *m, return sd_bus_reply_method_return(m, "u", r); } +static int ratbagd_resolution_set_default(sd_bus_message *m, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_resolution *resolution = userdata; + int r; + + r = ratbag_resolution_set_default(resolution->lib_resolution); + + (void) sd_bus_emit_signal(sd_bus_message_get_bus(m), + "/org/freedesktop/ratbag1", + "/org.freedesktop.ratbag1.Resolution", + "DefaultResolutionChanged", + "u", + resolution->index); + + return sd_bus_reply_method_return(m, "u", r); +} + static int ratbagd_resolution_get_capabilities(sd_bus *bus, const char *path, @@ -141,7 +160,9 @@ const sd_bus_vtable ratbagd_resolution_vtable[] = { SD_BUS_PROPERTY("ReportRate", "u", NULL, offsetof(struct ratbagd_resolution, rate), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_METHOD("SetReportRate", "u", "u", ratbagd_resolution_set_report_rate, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetResolution", "uu", "u", ratbagd_resolution_set_resolution, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetDefault", "", "u", ratbagd_resolution_set_default, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_SIGNAL("ActiveResolutionChanged", "u", 0), + SD_BUS_SIGNAL("DefaultResolutionChanged", "u", 0), SD_BUS_VTABLE_END, }; From ad88f755a438739423529600d038e154f9f10e63 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 22 May 2017 08:50:06 +1000 Subject: [PATCH 129/137] shared: relicense rbtree to MIT To avoid having multiple licenses within a project as small as ratbagd, and to avoid having to deal with any fallout from mixing MIT and LGPL. Pre-approved by David Herrmann who wrote that code, see https://github.com/libratbag/ratbagd/issues/23#issuecomment-302741861 Fixes https://github.com/libratbag/ratbagd/issues/23 Signed-off-by: Peter Hutterer --- src/shared-rbtree.c | 31 +++++++++++++++++-------------- src/shared-rbtree.h | 28 +++++++++++++++++----------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/src/shared-rbtree.c b/src/shared-rbtree.c index 5afe643c..ca144284 100644 --- a/src/shared-rbtree.c +++ b/src/shared-rbtree.c @@ -1,23 +1,26 @@ /*** - This file is part of rbtree. + This file is part of ratbagd. Copyright 2015 David Herrmann - Based on the rbtree implementation of the linux-kernel: - Copyright 1999 Andrea Arcangeli + 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: - rbtree is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. - rbtree is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with rbtree; If not, see . + 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. ***/ /* diff --git a/src/shared-rbtree.h b/src/shared-rbtree.h index 9b5cd95b..6ffba442 100644 --- a/src/shared-rbtree.h +++ b/src/shared-rbtree.h @@ -1,22 +1,28 @@ #pragma once /*** - This file is part of rbtree. + This file is part of ratbagd. Copyright 2015 David Herrmann - rbtree is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. + 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: - rbtree is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. - You should have received a copy of the GNU Lesser General Public License - along with rbtree; If not, see . + 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 "config.h" From 932cf905ef9765051ce22b153a846154442b4078 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 6 Jun 2017 16:04:39 +0200 Subject: [PATCH 130/137] ratbagd 0.4 - changed licence of rb-tree to have a consistent MIT licence - new signal for active resolution changes Signed-off-by: Benjamin Tissoires --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 7c223482..de036e1b 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('ratbagd', 'c', - version : '0.3', + version : '0.4', license : 'MIT/Expat', meson_version : '>= 0.40.0', default_options : [ 'c_std=gnu99', 'warning_level=2' ]) From 9cf6100e00c0a242c83ae16facf4d573026bd4e7 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 7 Jun 2017 11:00:38 +1000 Subject: [PATCH 131/137] python: switch ratbagctl shebang to python3 Signed-off-by: Peter Hutterer --- python/ratbagctl.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ratbagctl.in b/python/ratbagctl.in index 3c672236..53cd55a7 100755 --- a/python/ratbagctl.in +++ b/python/ratbagctl.in @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # vim: set expandtab shiftwidth=4 tabstop=4: # From 97a37d21e12d6777a90c28af3fccf739ff5b3d56 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 8 Jun 2017 10:10:49 +1000 Subject: [PATCH 132/137] Drop the python bindings, move them into ratbagctl The python bindings were mostly boilerplate and a 1:1 mapping of the dbus interface anyway. Packaging them for distributions is difficult, so given how little benefit they provide, let's just stop shipping them. Those who need those bindings (like piper) can either make their own or copy them. Signed-off-by: Peter Hutterer --- meson.build | 17 +- python/ratbagctl.in | 199 ------------------ .../ratbagd/__init__.py => tools/ratbagctl.in | 172 +++++++++++++++ 3 files changed, 174 insertions(+), 214 deletions(-) delete mode 100755 python/ratbagctl.in rename python/ratbagd/__init__.py => tools/ratbagctl.in (63%) mode change 100644 => 100755 diff --git a/meson.build b/meson.build index de036e1b..63176cb3 100644 --- a/meson.build +++ b/meson.build @@ -127,26 +127,13 @@ install_data('dbus/org.freedesktop.ratbag1.conf', configuration : config_bindir, install_dir : join_paths(dbusdir, 'system.d')) -#### python bindings #### - -py3_mod = import('python3') -py3 = py3_mod.find_python() -py3_dep = dependency('python3', required : true) - -pysrc_ratbagd = [ 'python/ratbagd/__init__.py' ] - -py3_purelib = py3_mod.sysconfig_path('purelib') - -install_data(pysrc_ratbagd, - install_dir : py3_purelib + '/ratbagd') - +#### tools #### config_ratbagctl = configuration_data() config_ratbagctl.set('version', meson.project_version()) -configure_file(input : 'python/ratbagctl.in', +configure_file(input : 'tools/ratbagctl.in', output : 'ratbagctl', configuration : config_ratbagctl, install_dir : get_option('bindir')) - install_man('doc/ratbagctl.1') #### output files #### diff --git a/python/ratbagctl.in b/python/ratbagctl.in deleted file mode 100755 index 53cd55a7..00000000 --- a/python/ratbagctl.in +++ /dev/null @@ -1,199 +0,0 @@ -#!/usr/bin/env python3 -# -# vim: set expandtab shiftwidth=4 tabstop=4: -# -# 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. - -from __future__ import print_function - -from ratbagd import * - -import sys -import argparse - -def list_devices(r, args): - for d in r.devices: - print("{:10s} {:32s}".format(d.id + ":", d.name)) - -def find_device(r, args): - dev = None - for d in r.devices: - if d.id == args.device: - dev = d - break; - if dev is None: - print("Unable to find device {}".format(args.device)) - sys.exit(1) - return dev - -def find_profile(r, args): - d = find_device(r, args) - try: - p = d.profiles[args.profile] - except IndexError: - print("Invalid profile index {}".format(args.profile)) - sys.exit(1) - return p, d - -def find_resolution(r, args): - p, d = find_profile(r, args) - try: - r = p.resolutions[args.resolution] - except IndexError: - print("Invalid resolution index {}".format(args.resolution)) - sys.exit(1) - return r, p, d - -def find_button(r, args): - p, d = find_profile(r, args) - try: - b = p.buttons[args.button] - except IndexError: - print("Invalid button index {}".format(args.button)) - sys.exit(1) - return b, p, d - -def show_device(r, args): - d = find_device(r, args) - - - caps = { RatbagdDevice.CAP_SWITCHABLE_RESOLUTION : "switchable-resolution", - RatbagdDevice.CAP_SWITCHABLE_PROFILE : "switchable-profile", - RatbagdDevice.CAP_BUTTON_KEY : "button-keys", - RatbagdDevice.CAP_BUTTON_MACROS : "button-macros", - RatbagdDevice.CAP_DEFAULT_PROFILE : "default-profile", - RatbagdDevice.CAP_QUERY_CONFIGURATION : "query-configuration", - RatbagdDevice.CAP_DISABLE_PROFILE : "disable-profile", - RatbagdDevice.CAP_LED : "led" } - capabilities = [caps[c] for c in d.capabilities] - - print("{} - {}".format(d.id, d.name)) - print(" SVG: {}".format(d.svg)) - print(" Capabilities: {}".format(", ".join(capabilities))) - print("Number of Profiles: {}".format(len(d.profiles))) - active = -1 - for i, p in enumerate(d.profiles): - if p == d.active_profile: - active = i - break - print(" Active Profile: {}".format(active)) - -def show_profile(r, args): - p, d = find_profile(r, args) - - print("Profile {} on {} ({})".format(args.profile, d.id, d.name)) - print(" Number of Buttons: {}".format(len(p.buttons))) - print("Number of Resolutions: {}".format(len(p.resolutions))) - active, default = -1, -1 - for i, r in enumerate(p.resolutions): - if p.active_resolution == r: - active = i - if p.default_resolution == r: - default = i - - print(" Active Resolution: {}".format(active)) - print(" Default Resolution: {}".format(default)) - -def show_resolution(r, args): - r, p, d = find_resolution(r, args) - - print("Resolution {} on Profile {} on {} ({})".format(args.resolution, - args.profile, - d.id, - d.name)) - print(" Report Rate: {}Hz".format(r.report_rate)) - if RatbagdResolution.CAP_SEPARATE_XY_RESOLUTION in r.capabilities: - print(" Resolution: {}x{}dpi".format(*r.resolution)) - else: - print(" Resolution: {}dpi".format(r.resolution[0])) - - - caps = { RatbagdResolution.CAP_INDIVIDUAL_REPORT_RATE : "individual-report-rate", - RatbagdResolution.CAP_SEPARATE_XY_RESOLUTION : "separate-xy-resolution" } - capabilities = [caps[c] for c in r.capabilities] - print(" Capabilities: {}".format(", ".join(capabilities))) - -def show_button(r, args): - b, p, d = find_button(r, args) - - print("Button {} on Profile {} on {} ({})".format(args.button, - args.profile, - d.id, - d.name)) - - print(" Type: {}".format(b.button_type)) - print(" Action Type: {}".format(b.action_type)) - - if b.action_type == "button": - print(" Button Mapping: {}".format(b.button)) - elif b.action_type == "key": - print(" Key Mapping: {}".format(b.key)) - elif b.action_type == "special": - print("Special Mapping: {}".format(b.special)) - -def make_parser(): - parser = argparse.ArgumentParser(description="Inspect and modify configurable mice") - parser.add_argument("-V", "--version", action="version", version="@version@") - subs = parser.add_subparsers(title="COMMANDS", help=None) - - list = subs.add_parser("list-devices", help="List available configurable mice") - list.set_defaults(func=list_devices) - - show = subs.add_parser("show-device", help="Show device information") - show.add_argument("device", metavar="event0", help="The device node") - show.set_defaults(func=show_device) - - profile = subs.add_parser("show-profile", help="Show profile information") - profile.add_argument("device", metavar="event0", help="The device node") - profile.add_argument("profile", metavar="0", help="The profile index", type=int) - profile.set_defaults(func=show_profile) - - resolution = subs.add_parser("show-resolution", help="Show resolution information") - resolution.add_argument("device", metavar="event0", help="The device node") - resolution.add_argument("profile", metavar="0", help="The profile index", type=int) - resolution.add_argument("resolution", metavar="0", help="The resolution index", type=int) - resolution.set_defaults(func=show_resolution) - - button = subs.add_parser("show-button", help="Show button information") - button.add_argument("device", metavar="event0", help="The device node") - button.add_argument("profile", metavar="0", help="The profile index", type=int) - button.add_argument("button", metavar="0", help="The button index", type=int) - button.set_defaults(func=show_button) - - return parser - -def main(argv): - cmd = make_parser().parse_args(argv) - - try: - r = Ratbagd() - if not r.devices: - print("No devices available.") - except RatbagdDBusUnavailable: - print("Unable to connect to ratbagd over dbus") - - cmd.func(r, cmd) - -if __name__ == "__main__": - main(sys.argv[1:]) diff --git a/python/ratbagd/__init__.py b/tools/ratbagctl.in old mode 100644 new mode 100755 similarity index 63% rename from python/ratbagd/__init__.py rename to tools/ratbagctl.in index 4217e56b..3836e7c5 --- a/python/ratbagd/__init__.py +++ b/tools/ratbagctl.in @@ -1,3 +1,5 @@ +#!/usr/bin/env python3 +# # vim: set expandtab shiftwidth=4 tabstop=4: # # This file is part of ratbagd. @@ -23,9 +25,13 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. +from __future__ import print_function from gi.repository import GLib from gi.repository import Gio +import sys +import argparse + class RatbagdDBusUnavailable(BaseException): """ Signals DBus is unavailable or the ratbagd daemon is not available. @@ -341,3 +347,169 @@ class RatbagdButton(_RatbagdDBus): def disable(self): return self.dbus_call("Disable", "") + +def list_devices(r, args): + for d in r.devices: + print("{:10s} {:32s}".format(d.id + ":", d.name)) + +def find_device(r, args): + dev = None + for d in r.devices: + if d.id == args.device: + dev = d + break; + if dev is None: + print("Unable to find device {}".format(args.device)) + sys.exit(1) + return dev + +def find_profile(r, args): + d = find_device(r, args) + try: + p = d.profiles[args.profile] + except IndexError: + print("Invalid profile index {}".format(args.profile)) + sys.exit(1) + return p, d + +def find_resolution(r, args): + p, d = find_profile(r, args) + try: + r = p.resolutions[args.resolution] + except IndexError: + print("Invalid resolution index {}".format(args.resolution)) + sys.exit(1) + return r, p, d + +def find_button(r, args): + p, d = find_profile(r, args) + try: + b = p.buttons[args.button] + except IndexError: + print("Invalid button index {}".format(args.button)) + sys.exit(1) + return b, p, d + +def show_device(r, args): + d = find_device(r, args) + + + caps = { RatbagdDevice.CAP_SWITCHABLE_RESOLUTION : "switchable-resolution", + RatbagdDevice.CAP_SWITCHABLE_PROFILE : "switchable-profile", + RatbagdDevice.CAP_BUTTON_KEY : "button-keys", + RatbagdDevice.CAP_BUTTON_MACROS : "button-macros", + RatbagdDevice.CAP_DEFAULT_PROFILE : "default-profile", + RatbagdDevice.CAP_QUERY_CONFIGURATION : "query-configuration", + RatbagdDevice.CAP_DISABLE_PROFILE : "disable-profile", + RatbagdDevice.CAP_LED : "led" } + capabilities = [caps[c] for c in d.capabilities] + + print("{} - {}".format(d.id, d.name)) + print(" SVG: {}".format(d.svg)) + print(" Capabilities: {}".format(", ".join(capabilities))) + print("Number of Profiles: {}".format(len(d.profiles))) + active = -1 + for i, p in enumerate(d.profiles): + if p == d.active_profile: + active = i + break + print(" Active Profile: {}".format(active)) + +def show_profile(r, args): + p, d = find_profile(r, args) + + print("Profile {} on {} ({})".format(args.profile, d.id, d.name)) + print(" Number of Buttons: {}".format(len(p.buttons))) + print("Number of Resolutions: {}".format(len(p.resolutions))) + active, default = -1, -1 + for i, r in enumerate(p.resolutions): + if p.active_resolution == r: + active = i + if p.default_resolution == r: + default = i + + print(" Active Resolution: {}".format(active)) + print(" Default Resolution: {}".format(default)) + +def show_resolution(r, args): + r, p, d = find_resolution(r, args) + + print("Resolution {} on Profile {} on {} ({})".format(args.resolution, + args.profile, + d.id, + d.name)) + print(" Report Rate: {}Hz".format(r.report_rate)) + if RatbagdResolution.CAP_SEPARATE_XY_RESOLUTION in r.capabilities: + print(" Resolution: {}x{}dpi".format(*r.resolution)) + else: + print(" Resolution: {}dpi".format(r.resolution[0])) + + + caps = { RatbagdResolution.CAP_INDIVIDUAL_REPORT_RATE : "individual-report-rate", + RatbagdResolution.CAP_SEPARATE_XY_RESOLUTION : "separate-xy-resolution" } + capabilities = [caps[c] for c in r.capabilities] + print(" Capabilities: {}".format(", ".join(capabilities))) + +def show_button(r, args): + b, p, d = find_button(r, args) + + print("Button {} on Profile {} on {} ({})".format(args.button, + args.profile, + d.id, + d.name)) + + print(" Type: {}".format(b.button_type)) + print(" Action Type: {}".format(b.action_type)) + + if b.action_type == "button": + print(" Button Mapping: {}".format(b.button)) + elif b.action_type == "key": + print(" Key Mapping: {}".format(b.key)) + elif b.action_type == "special": + print("Special Mapping: {}".format(b.special)) + +def make_parser(): + parser = argparse.ArgumentParser(description="Inspect and modify configurable mice") + parser.add_argument("-V", "--version", action="version", version="@version@") + subs = parser.add_subparsers(title="COMMANDS", help=None) + + list = subs.add_parser("list-devices", help="List available configurable mice") + list.set_defaults(func=list_devices) + + show = subs.add_parser("show-device", help="Show device information") + show.add_argument("device", metavar="event0", help="The device node") + show.set_defaults(func=show_device) + + profile = subs.add_parser("show-profile", help="Show profile information") + profile.add_argument("device", metavar="event0", help="The device node") + profile.add_argument("profile", metavar="0", help="The profile index", type=int) + profile.set_defaults(func=show_profile) + + resolution = subs.add_parser("show-resolution", help="Show resolution information") + resolution.add_argument("device", metavar="event0", help="The device node") + resolution.add_argument("profile", metavar="0", help="The profile index", type=int) + resolution.add_argument("resolution", metavar="0", help="The resolution index", type=int) + resolution.set_defaults(func=show_resolution) + + button = subs.add_parser("show-button", help="Show button information") + button.add_argument("device", metavar="event0", help="The device node") + button.add_argument("profile", metavar="0", help="The profile index", type=int) + button.add_argument("button", metavar="0", help="The button index", type=int) + button.set_defaults(func=show_button) + + return parser + +def main(argv): + cmd = make_parser().parse_args(argv) + + try: + r = Ratbagd() + if not r.devices: + print("No devices available.") + except RatbagdDBusUnavailable: + print("Unable to connect to ratbagd over dbus") + + cmd.func(r, cmd) + +if __name__ == "__main__": + main(sys.argv[1:]) From 90d2a48cfba3d7ee409f265d0c00326b2c831464 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 8 Jun 2017 10:17:10 +1000 Subject: [PATCH 133/137] ratbagctl: default to list-devices without argv Signed-off-by: Peter Hutterer --- tools/ratbagctl.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/ratbagctl.in b/tools/ratbagctl.in index 3836e7c5..d409c254 100755 --- a/tools/ratbagctl.in +++ b/tools/ratbagctl.in @@ -500,6 +500,8 @@ def make_parser(): return parser def main(argv): + if not argv: + argv = ["list-devices"] cmd = make_parser().parse_args(argv) try: From 2b5b0b17720a1f29070d30ba431b07791e74946d Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Thu, 8 Jun 2017 12:22:34 +0200 Subject: [PATCH 134/137] Fix boolean instruction for Meson https://github.com/libratbag/libratbag/issues/175 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d722886c..831cfb97 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ And to build or re-build after code-changes, run: Note: `builddir` is the build output directory and can be changed to any other directory name. To set configure-time options, use e.g. - mesonconf builddir -Denable-documentation=no + mesonconf builddir -Denable-documentation=false Run `mesonconf builddir` to list the options. From 22135f31d5bcb3f429fcf06600d5f97615590140 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Mon, 12 Jun 2017 10:10:49 +0200 Subject: [PATCH 135/137] ratbagd-device: update for new capabilities in libratbag Fixes #29. --- src/ratbagd-device.c | 54 +++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 33 deletions(-) diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 94998a2c..096aead1 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -278,45 +278,33 @@ ratbagd_device_get_capabilities(sd_bus *bus, struct ratbagd_device *device = userdata; struct ratbag_device *lib_device = device->lib_device; enum ratbag_device_capability cap; + enum ratbag_device_capability caps[] = { + RATBAG_DEVICE_CAP_QUERY_CONFIGURATION, + RATBAG_DEVICE_CAP_RESOLUTION, + RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION, + RATBAG_DEVICE_CAP_PROFILE, + RATBAG_DEVICE_CAP_SWITCHABLE_PROFILE, + RATBAG_DEVICE_CAP_DISABLE_PROFILE, + RATBAG_DEVICE_CAP_DEFAULT_PROFILE, + RATBAG_DEVICE_CAP_BUTTON, + RATBAG_DEVICE_CAP_BUTTON_KEY, + RATBAG_DEVICE_CAP_BUTTON_MACROS, + RATBAG_DEVICE_CAP_LED, + }; int r; + size_t i; r = sd_bus_message_open_container(reply, 'a', "u"); if (r < 0) return r; - cap = RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION; - if (ratbag_device_has_capability(lib_device, cap)) { - r = sd_bus_message_append(reply, "u", cap); - if (r < 0) - return r; - } - - cap = RATBAG_DEVICE_CAP_SWITCHABLE_PROFILE; - if (ratbag_device_has_capability(lib_device, cap)) { - r = sd_bus_message_append(reply, "u", cap); - if (r < 0) - return r; - } - - cap = RATBAG_DEVICE_CAP_BUTTON_MACROS; - if (ratbag_device_has_capability(lib_device, cap)) { - r = sd_bus_message_append(reply, "u", cap); - if (r < 0) - return r; - } - - cap = RATBAG_DEVICE_CAP_DEFAULT_PROFILE; - if (ratbag_device_has_capability(lib_device, cap)) { - r = sd_bus_message_append(reply, "u", cap); - if (r < 0) - return r; - } - - cap = RATBAG_DEVICE_CAP_QUERY_CONFIGURATION; - if (ratbag_device_has_capability(lib_device, cap)) { - r = sd_bus_message_append(reply, "u", cap); - if (r < 0) - return r; + for (i = 0; i < ELEMENTSOF(caps); i++) { + cap = caps[i]; + if (ratbag_device_has_capability(lib_device, cap)) { + r = sd_bus_message_append(reply, "u", cap); + if (r < 0) + return r; + } } return sd_bus_message_close_container(reply); From c0c4ba156a4bc9081d6e796081afaf13364f4353 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Wed, 14 Jun 2017 09:35:27 +0200 Subject: [PATCH 136/137] README: fix install instructions The instructions still referred to in-source builds. Meson instead uses an out of tree build directory, hence we update the paths to point to the build directory. Fixes #32. --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 831cfb97..3ddb81ec 100644 --- a/README.md +++ b/README.md @@ -98,13 +98,14 @@ ratbagd is intended to run as dbus-activated systemd service. This requires installation of the following files: sudo cp dbus/org.freedesktop.ratbag1.conf /etc/dbus-1/system.d/org.freedesktop.ratbag1.conf - sudo cp dbus/org.freedesktop.ratbag1.service /etc/dbus-1/system-services/org.freedesktop.ratbag1.conf - sudo cp ratbagd.service /etc/systemd/system/ratbagd.service + sudo cp builddir/org.freedesktop.ratbag1.service /etc/dbus-1/system-services/org.freedesktop.ratbag1.conf + sudo cp builddir/ratbagd.service /etc/systemd/system/ratbagd.service The files are installed into the prefix by `ninja install`, see also the configure-time options `-Dsystemd-unit-dir` and `-Ddbus-root-dir` (see "Compiling ratbagd" below). Developers are encouraged to simply symlink to the -files in the git repository. +files in the git repository. If you used any other build directory than +`builddir`, adjust accordingly. For the files to take effect, you should run From 5dcdc3c652a93712f5b7ecde093c87bfa47343e0 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Mon, 26 Jun 2017 00:29:10 +0200 Subject: [PATCH 137/137] Add an API for LEDs --- README.md | 16 +++ meson.build | 1 + src/ratbagd-device.c | 18 +++ src/ratbagd-led.c | 271 ++++++++++++++++++++++++++++++++++++++++++ src/ratbagd-profile.c | 174 ++++++++++++++++++++++++++- src/ratbagd.h | 20 ++++ 6 files changed, 498 insertions(+), 2 deletions(-) create mode 100644 src/ratbagd-led.c diff --git a/README.md b/README.md index 3ddb81ec..d9f54dae 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Interfaces: - org.freedesktop.ratbag1.Profile - org.freedesktop.ratbag1.Resolution - org.freedesktop.ratbag1.Button +- org.freedesktop.ratbag1.Led The **org.freedesktop.ratbag1.Manager** interface provides: - Properties: @@ -48,6 +49,7 @@ The **org.freedesktop.ratbag1.Profile** interface provides: - Index -> index of the profile - Resolutions -> array of object paths with interface Resolution - Buttons -> array of object paths with interface Button + - Leds -> array of object paths with interface Led - ActiveResolution -> index of the currently active resolution in Resolutions - DefaultResolution -> index of the default resolution in Resolutions - Methods: @@ -86,6 +88,20 @@ The **org.freedesktop.ratbag1.Button** interface provides: - SetKeyMapping(uint[]) -> set the key mapping, first entry is the keycode, other entries, if any, are modifier keycodes - Disable(void) -> disable this button +The **org.freedesktop.ratbag1.Led** interface provides: +- Properties: + - Index -> index of the LED + - Mode -> uint mapping to the mode enum from libratbag + - Type -> string describing the LED type + - Color -> uint triplet (RGB) of the LED's color + - EffectRate -> the effect rate in Hz, possible values are in the range 100 - 20000 + - Brightness -> the brightness of the LED, possible values are in the range 0 - 255 +- Methods: + - SetMode(uint) -> set the mode to the given mode enum value from libratbag + - SetColor((uuu)) -> set the color to the given uint triplet (RGB) + - SetEffectRate(uint) -> set the effect rate in Hz, possible values are in the range 100 - 20000 + - SetBrightness(int) -> set the brightness, possible values are in the range 0 - 255 + For easier debugging, objects paths are constructed from the device. e.g. `/org/freedesktop/ratbag/button/event5/p0/b10` is the button interface for button 10 on profile 0 on event5. The naming is subject to change. Do not diff --git a/meson.build b/meson.build index 63176cb3..44f9d30c 100644 --- a/meson.build +++ b/meson.build @@ -78,6 +78,7 @@ dep_libshared = declare_dependency(link_with: lib_libshared) src_ratbagd = [ 'src/ratbagd.h', 'src/ratbagd.c', + 'src/ratbagd-led.c', 'src/ratbagd-button.c', 'src/ratbagd-device.c', 'src/ratbagd-profile.c', diff --git a/src/ratbagd-device.c b/src/ratbagd-device.c index 096aead1..3191604c 100644 --- a/src/ratbagd-device.c +++ b/src/ratbagd-device.c @@ -427,6 +427,12 @@ unsigned int ratbagd_device_get_num_buttons(struct ratbagd_device *device) return ratbag_device_get_num_buttons(device->lib_device); } +unsigned int ratbagd_device_get_num_leds(struct ratbagd_device *device) +{ + assert(device); + return ratbag_device_get_num_leds(device->lib_device); +} + bool ratbagd_device_linked(struct ratbagd_device *device) { return device && rbnode_linked(&device->node); @@ -502,6 +508,18 @@ void ratbagd_device_link(struct ratbagd_device *device) r = ratbagd_profile_register_buttons(device->ctx->bus, device, device->profiles[i]); + if (r < 0) { + log_error("Cannot register buttons for '%s': %m\n", + device->name); + } + + r = ratbagd_profile_register_leds(device->ctx->bus, + device, + device->profiles[i]); + if (r < 0) { + log_error("Cannot register leds for '%s': %m\n", + device->name); + } } } diff --git a/src/ratbagd-led.c b/src/ratbagd-led.c new file mode 100644 index 00000000..c0c958e6 --- /dev/null +++ b/src/ratbagd-led.c @@ -0,0 +1,271 @@ +/*** + This file is part of ratbagd. + + Copyright 2017 Jente Hidskes . + + 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 "config.h" + +#include +#include +#include +#include +#include "ratbagd.h" +#include "shared-macro.h" + +struct ratbagd_led { + struct ratbag_led *lib_led; + unsigned int index; + char *path; +}; + +static int ratbagd_led_get_mode(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_led *led = userdata; + enum ratbag_led_mode mode; + + mode = ratbag_led_get_mode(led->lib_led); + return sd_bus_message_append(reply, "u", mode); +} + +static int ratbagd_led_set_mode(sd_bus_message *m, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_led *led = userdata; + enum ratbag_led_mode mode; + int r; + + r = sd_bus_message_read(m, "u", &mode); + if (r < 0) + return r; + + r = ratbag_led_set_mode(led->lib_led, mode); + return sd_bus_reply_method_return(m, "u", r); +} + +static int ratbagd_led_get_type(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_led *led = userdata; + const char *type = NULL; + enum ratbag_led_type t; + + t = ratbag_led_get_type(led->lib_led); + + switch(t) { + default: + log_error("Unknown led type %d\n", t); + /* fallthrough */ + case RATBAG_LED_TYPE_UNKNOWN: + type = "unknown"; + break; + case RATBAG_LED_TYPE_LOGO: + type = "logo"; + break; + case RATBAG_LED_TYPE_SIDE: + type = "side"; + break; + } + + return sd_bus_message_append(reply, "s", type); +} + +static int ratbagd_led_get_color(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_led *led = userdata; + struct ratbag_color c; + + c = ratbag_led_get_color(led->lib_led); + return sd_bus_message_append(reply, "(uuu)", c.red, c.green, c.blue); +} + +static int ratbagd_led_set_color(sd_bus_message *m, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_led *led = userdata; + struct ratbag_color c; + int r; + + r = sd_bus_message_read(m, "(uuu)", &c.red, &c.green, &c.blue); + if (r < 0) + return r; + + r = ratbag_led_set_color(led->lib_led, c); + return sd_bus_reply_method_return(m, "u", r); +} + +static int ratbagd_led_get_effect_rate(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_led *led = userdata; + int rate; + + rate = ratbag_led_get_effect_rate(led->lib_led); + return sd_bus_message_append(reply, "i", rate); +} + +static int ratbagd_led_set_effect_rate(sd_bus_message *m, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_led *led = userdata; + unsigned int rate; + int r; + + r = sd_bus_message_read(m, "u", &rate); + if (r < 0) + return r; + + if (rate < 100 || rate > 20000) + return 0; + + r = ratbag_led_set_effect_rate(led->lib_led, rate); + return sd_bus_reply_method_return(m, "u", r); +} + +static int ratbagd_led_get_brightness(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_led *led = userdata; + unsigned int brightness; + + brightness = ratbag_led_get_brightness(led->lib_led); + return sd_bus_message_append(reply, "u", brightness); +} + +static int ratbagd_led_set_brightness(sd_bus_message *m, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_led *led = userdata; + unsigned int brightness; + int r; + + r = sd_bus_message_read(m, "u", &brightness); + if (r < 0) + return r; + + if (brightness > 255) + return 0; + + r = ratbag_led_set_brightness(led->lib_led, brightness); + return sd_bus_reply_method_return(m, "u", r); +} + +const sd_bus_vtable ratbagd_led_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Index", "u", NULL, offsetof(struct ratbagd_led, index), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Mode", "u", ratbagd_led_get_mode, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Type", "s", ratbagd_led_get_type, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Color", "(uuu)", ratbagd_led_get_color, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("EffectRate", "i", ratbagd_led_get_effect_rate, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Brightness", "u", ratbagd_led_get_brightness, 0, SD_BUS_VTABLE_PROPERTY_CONST), + + SD_BUS_METHOD("SetMode", "u", "u", ratbagd_led_set_mode, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetColor", "(uuu)", "u", ratbagd_led_set_color, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetEffectRate", "u", "u", ratbagd_led_set_effect_rate, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetBrightness", "u", "u", ratbagd_led_set_brightness, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_VTABLE_END, +}; + +int ratbagd_led_new(struct ratbagd_led **out, + struct ratbagd_device *device, + struct ratbagd_profile *profile, + struct ratbag_led *lib_led, + unsigned int index) +{ + _cleanup_(ratbagd_led_freep) struct ratbagd_led *led = NULL; + char profile_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1], + led_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1]; + int r; + + assert(out); + assert(lib_led); + + led = calloc(1, sizeof(*led)); + if (!led) + return -ENOMEM; + + led->lib_led = lib_led; + led->index = index; + + sprintf(profile_buffer, "p%u", ratbagd_profile_get_index(profile)); + sprintf(led_buffer, "b%u", index); + r = sd_bus_path_encode_many(&led->path, + "/org/freedesktop/ratbag1/led/%/%/%", + ratbagd_device_get_name(device), + profile_buffer, + led_buffer); + if (r < 0) + return r; + + *out = led; + led = NULL; + return 0; +} + +const char *ratbagd_led_get_path(struct ratbagd_led *led) +{ + assert(led); + return led->path; +} + +struct ratbagd_led *ratbagd_led_free(struct ratbagd_led *led) +{ + if (!led) + return NULL; + + led->path = mfree(led->path); + led->lib_led = ratbag_led_unref(led->lib_led); + + return mfree(led); +} + diff --git a/src/ratbagd-profile.c b/src/ratbagd-profile.c index e36e94b9..45c6fd35 100644 --- a/src/ratbagd-profile.c +++ b/src/ratbagd-profile.c @@ -51,6 +51,11 @@ struct ratbagd_profile { sd_bus_slot *button_enum_slot; unsigned int n_buttons; struct ratbagd_button **buttons; + + sd_bus_slot *led_vtable_slot; + sd_bus_slot *led_enum_slot; + unsigned int n_leds; + struct ratbagd_led **leds; }; static int ratbagd_profile_find_resolution(sd_bus *bus, @@ -148,6 +153,37 @@ static int ratbagd_profile_get_buttons(sd_bus *bus, return sd_bus_message_close_container(reply); } +static int ratbagd_profile_get_leds(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) +{ + struct ratbagd_profile *profile = userdata; + struct ratbagd_led *led; + unsigned int i; + int r; + + r = sd_bus_message_open_container(reply, 'a', "o"); + if (r < 0) + return r; + + for (i = 0; i < profile->n_leds; ++i) { + led = profile->leds[i]; + if (!led) + continue; + + r = sd_bus_message_append(reply, + "o", + ratbagd_led_get_path(led)); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} static int ratbagd_profile_get_active_resolution(sd_bus *bus, const char *path, @@ -234,6 +270,37 @@ static int ratbagd_profile_find_button(sd_bus *bus, return 1; } +static int ratbagd_profile_find_led(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/led/%/p%/b%", + NULL, + NULL, + &name); + if (r <= 0) + return r; + + r = safe_atou(name, &index); + if (r < 0) + return 0; + + if (index >= profile->n_leds || !profile->leds[index]) + return 0; + + *found = profile->leds[index]; + return 1; +} + static int ratbagd_profile_set_active(sd_bus_message *m, void *userdata, sd_bus_error *error) @@ -282,6 +349,7 @@ const sd_bus_vtable ratbagd_profile_vtable[] = { SD_BUS_PROPERTY("Index", "u", NULL, offsetof(struct ratbagd_profile, index), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Resolutions", "ao", ratbagd_profile_get_resolutions, 0, 0), SD_BUS_PROPERTY("Buttons", "ao", ratbagd_profile_get_buttons, 0, 0), + SD_BUS_PROPERTY("Leds", "ao", ratbagd_profile_get_leds, 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), @@ -298,6 +366,7 @@ int ratbagd_profile_new(struct ratbagd_profile **out, _cleanup_(ratbagd_profile_freep) struct ratbagd_profile *profile = NULL; struct ratbag_resolution *resolution; struct ratbag_button *button; + struct ratbag_led *led; char index_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1]; unsigned int i; int r; @@ -331,6 +400,11 @@ int ratbagd_profile_new(struct ratbagd_profile **out, if (!profile->buttons) return -ENOMEM; + profile->n_leds = ratbagd_device_get_num_leds(device); + profile->leds = calloc(profile->n_leds, sizeof(*profile->leds)); + if (!profile->leds) + return -ENOMEM; + for (i = 0; i < profile->n_resolutions; ++i) { resolution = ratbag_profile_get_resolution(profile->lib_profile, i); if (!resolution) @@ -365,6 +439,23 @@ int ratbagd_profile_new(struct ratbagd_profile **out, } } + for (i = 0; i < profile->n_leds; ++i) { + led = ratbag_profile_get_led(profile->lib_profile, i); + if (!led) + continue; + + r = ratbagd_led_new(&profile->leds[i], + device, + profile, + led, + i); + if (r < 0) { + errno = -r; + log_error("Cannot allocate led for '%s': %m\n", + ratbagd_device_get_name(device)); + } + } + *out = profile; profile = NULL; return 0; @@ -381,12 +472,17 @@ struct ratbagd_profile *ratbagd_profile_free(struct ratbagd_profile *profile) profile->resolution_enum_slot = sd_bus_slot_unref(profile->resolution_enum_slot); profile->button_vtable_slot = sd_bus_slot_unref(profile->button_vtable_slot); profile->button_enum_slot = sd_bus_slot_unref(profile->button_enum_slot); + profile->led_vtable_slot = sd_bus_slot_unref(profile->led_vtable_slot); + profile->led_enum_slot = sd_bus_slot_unref(profile->led_enum_slot); + for (i = 0; i< profile->n_leds; ++i) + ratbagd_led_free(profile->leds[i]); for (i = 0; i< profile->n_buttons; ++i) ratbagd_button_free(profile->buttons[i]); for (i = 0; i< profile->n_resolutions; ++i) ratbagd_resolution_free(profile->resolutions[i]); + mfree(profile->leds); mfree(profile->buttons); mfree(profile->resolutions); @@ -467,7 +563,6 @@ int ratbagd_profile_register_resolutions(struct sd_bus *bus, ratbagd_device_get_name(device), index_buffer); - if (r >= 0) { r = sd_bus_add_fallback_vtable(bus, &profile->resolution_vtable_slot, @@ -544,7 +639,6 @@ int ratbagd_profile_register_buttons(struct sd_bus *bus, ratbagd_device_get_name(device), index_buffer); - if (r >= 0) { r = sd_bus_add_fallback_vtable(bus, &profile->button_vtable_slot, @@ -568,3 +662,79 @@ int ratbagd_profile_register_buttons(struct sd_bus *bus, return 0; } + +static int ratbagd_profile_list_leds(sd_bus *bus, + const char *path, + void *userdata, + char ***paths, + sd_bus_error *error) +{ + struct ratbagd_profile *profile = userdata; + struct ratbagd_led *led; + char **leds; + unsigned int i; + + leds = calloc(profile->n_leds + 1, sizeof(char *)); + if (!leds) + return -ENOMEM; + + for (i = 0; i < profile->n_leds; ++i) { + led = profile->leds[i]; + if (!led) + continue; + + leds[i] = strdup(ratbagd_led_get_path(led)); + if (!leds[i]) + goto error; + } + + leds[i] = NULL; + *paths = leds; + return 1; + +error: + for (i = 0; leds[i]; ++i) + free(leds[i]); + free(leds); + return -ENOMEM; +} + +int ratbagd_profile_register_leds(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 led interfaces */ + r = sd_bus_path_encode_many(&prefix, + "/org/freedesktop/ratbag1/led/%/%", + ratbagd_device_get_name(device), + index_buffer); + + if (r >= 0) { + r = sd_bus_add_fallback_vtable(bus, + &profile->led_vtable_slot, + prefix, + "org.freedesktop.ratbag1.Led", + ratbagd_led_vtable, + ratbagd_profile_find_led, + profile); + if (r >= 0) + r = sd_bus_add_node_enumerator(bus, + &profile->led_enum_slot, + prefix, + ratbagd_profile_list_leds, + profile); + } + if (r < 0) { + errno = -r; + log_error("Cannot register leds for '%s': %m\n", + ratbagd_device_get_name(device)); + } + + return 0; +} diff --git a/src/ratbagd.h b/src/ratbagd.h index 32e27b8c..7a70f2af 100644 --- a/src/ratbagd.h +++ b/src/ratbagd.h @@ -43,6 +43,7 @@ struct ratbagd_device; struct ratbagd_profile; struct ratbagd_resolution; struct ratbagd_button; +struct ratbagd_led; void log_verbose(const char *fmt, ...) _printf_(1, 2); void log_error(const char *fmt, ...) _printf_(1, 2); @@ -68,6 +69,9 @@ int ratbagd_profile_register_resolutions(struct sd_bus *bus, int ratbagd_profile_register_buttons(struct sd_bus *bus, struct ratbagd_device *device, struct ratbagd_profile *profile); +int ratbagd_profile_register_leds(struct sd_bus *bus, + struct ratbagd_device *device, + struct ratbagd_profile *profile); DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_profile *, ratbagd_profile_free); @@ -103,6 +107,21 @@ const char *ratbagd_button_get_path(struct ratbagd_button *button); DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_button *, ratbagd_button_free); +/* + * Leds + */ +extern const sd_bus_vtable ratbagd_led_vtable[]; + +int ratbagd_led_new(struct ratbagd_led **out, + struct ratbagd_device *device, + struct ratbagd_profile *profile, + struct ratbag_led *lib_led, + unsigned int index); +struct ratbagd_led *ratbagd_led_free(struct ratbagd_led *led); +const char *ratbagd_led_get_path(struct ratbagd_led *led); + +DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_led *, ratbagd_led_free); + /* * Devices */ @@ -117,6 +136,7 @@ struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device); const char *ratbagd_device_get_name(struct ratbagd_device *device); const char *ratbagd_device_get_path(struct ratbagd_device *device); unsigned int ratbagd_device_get_num_buttons(struct ratbagd_device *device); +unsigned int ratbagd_device_get_num_leds(struct ratbagd_device *device); bool ratbagd_device_linked(struct ratbagd_device *device); void ratbagd_device_link(struct ratbagd_device *device);