This client uses libiio to retrieve accelerometer values from the iio
subsystem on Linux (and maybe some other kernels), and automatically
rotate the output whenever orientation changed.

I tested it with a mma8453 accelerometer, but everything needed should
be available in the configuration to make it work with any other iio
device.

v2:
- Rename rotater to rotator, which is actual English.
- Add documentation for every new option, and a default value.
- Add the bare minimum of those options in the sample weston.ini.
- Fix for an inaccurate sampling frequency due to integer downcasting.
- Make the server-side a module instead of a simple function that has to be
  called by every shell.
- Remove the mostly-useless smoothing of the captured input.
- Make the protocol take an accelerometer name, to let the rotator
  match its name with the outputs using it.

Signed-off-by: Emmanuel Gil Peyrot <[email protected]>
---
 .gitignore                  |   1 +
 Makefile.am                 |  28 +++
 clients/autorotator.c       | 435 ++++++++++++++++++++++++++++++++++++++++++++
 compositor/rotator.c        | 246 +++++++++++++++++++++++++
 configure.ac                |  15 ++
 libweston/compositor.c      |   1 +
 libweston/compositor.h      |   1 +
 man/weston.ini.man          |  41 +++++
 protocol/weston-rotator.xml |  26 +++
 weston.ini.in               |   4 +
 10 files changed, 798 insertions(+)
 create mode 100644 clients/autorotator.c
 create mode 100644 compositor/rotator.c
 create mode 100644 protocol/weston-rotator.xml

diff --git a/.gitignore b/.gitignore
index 41a140b..72cea9f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -51,6 +51,7 @@ protocol/*.[ch]
 
 00*.patch
 
+weston-autorotator
 weston-calibrator
 weston-clickdot
 weston-cliptest
diff --git a/Makefile.am b/Makefile.am
index 32627f5..0e990ab 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -124,6 +124,8 @@ endif
 nodist_libweston_@LIBWESTON_MAJOR@_la_SOURCES =                                
\
        protocol/weston-screenshooter-protocol.c                        \
        protocol/weston-screenshooter-server-protocol.h                 \
+       protocol/weston-rotator-protocol.c              \
+       protocol/weston-rotator-server-protocol.h       \
        protocol/text-cursor-position-protocol.c        \
        protocol/text-cursor-position-server-protocol.h \
        protocol/text-input-unstable-v1-protocol.c                      \
@@ -610,6 +612,32 @@ nodist_weston_screenshooter_SOURCES =                      
\
 weston_screenshooter_LDADD = $(CLIENT_LIBS) libshared.la
 weston_screenshooter_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
 
+if BUILD_AUTOROTATOR
+libexec_PROGRAMS += weston-autorotator
+
+weston_autorotator_SOURCES =                           \
+       clients/autorotator.c
+nodist_weston_autorotator_SOURCES =                    \
+       protocol/weston-rotator-protocol.c              \
+       protocol/weston-rotator-client-protocol.h
+weston_autorotator_LDADD = $(CLIENT_LIBS) $(LIBIIO_LIBS) libshared.la
+weston_autorotator_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS) $(LIBIIO_CFLAGS)
+
+module_LTLIBRARIES += rotator.la
+rotator_la_LDFLAGS = -module -avoid-version
+rotator_la_LIBADD = $(COMPOSITOR_LIBS) libshared.la
+rotator_la_CFLAGS = $(AM_CFLAGS) $(COMPOSITOR_CFLAGS)
+rotator_la_SOURCES =                                   \
+       compositor/rotator.c
+
+BUILT_SOURCES +=                                       \
+       protocol/weston-rotator-protocol.c              \
+       protocol/weston-rotator-client-protocol.h
+
+EXTRA_DIST +=                                          \
+       protocol/weston-rotator.xml
+endif
+
 weston_terminal_SOURCES =                              \
        clients/terminal.c                              \
        shared/helpers.h
diff --git a/clients/autorotator.c b/clients/autorotator.c
new file mode 100644
index 0000000..89697c9
--- /dev/null
+++ b/clients/autorotator.c
@@ -0,0 +1,435 @@
+/*
+ * Copyright © 2016 Collabora, Ltd.
+ *
+ * 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 <stdint.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <wayland-client.h>
+#include "weston-rotator-client-protocol.h"
+#include "shared/config-parser.h"
+#include "shared/helpers.h"
+#include "shared/xalloc.h"
+
+#include <iio.h>
+
+#define BUFFER_SIZE 16
+
+static struct weston_rotator *rotator;
+
+#define DEFAULT_SAMPLING_FREQUENCY 100.
+
+struct config {
+       char *device_name;
+       char *channel_x_name, *channel_y_name;
+       char *sampling_frequency_name;
+       double wanted_sampling_frequency;
+       int threshold;
+       struct wl_array allowed_rotations;
+};
+
+struct accelerometer {
+       struct iio_context *context;
+       struct iio_device *device;
+       struct iio_channel *channel_x, *channel_y;
+       double sampling_frequency;
+};
+
+static const struct {
+       const char *name;
+       int token;
+} transforms[] = {
+       { "normal",     WESTON_ROTATOR_TRANSFORM_NORMAL },
+       { "90",         WESTON_ROTATOR_TRANSFORM_90 },
+       { "180",        WESTON_ROTATOR_TRANSFORM_180 },
+       { "270",        WESTON_ROTATOR_TRANSFORM_270 },
+       { "flipped",    WESTON_ROTATOR_TRANSFORM_FLIPPED },
+       { "flipped-90", WESTON_ROTATOR_TRANSFORM_FLIPPED_90 },
+       { "flipped-180", WESTON_ROTATOR_TRANSFORM_FLIPPED_180 },
+       { "flipped-270", WESTON_ROTATOR_TRANSFORM_FLIPPED_270 },
+};
+
+static bool
+parse_transform(const char *transform, int *out)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_LENGTH(transforms); i++)
+               if (strncmp(transforms[i].name, transform,
+                           strlen(transforms[i].name)) == 0) {
+                       *out = transforms[i].token;
+                       return true;
+               }
+
+       return false;
+}
+
+static struct config *
+read_configuration(const char *device_name)
+{
+       struct config *configuration;
+       const char *config_file;
+       struct weston_config *config;
+       struct weston_config_section *s;
+
+       char *allowed_rotations, *p;
+       int transform, *array_items;
+       int i;
+
+       config_file = weston_config_get_name_from_env();
+       config = weston_config_parse(config_file);
+       if (config == NULL)
+               return NULL;
+
+       s = weston_config_get_section(config, "accelerometer", "name", 
device_name);
+       if (s == NULL) {
+               weston_config_destroy(config);
+               return NULL;
+       }
+
+       configuration = zalloc(sizeof *configuration);
+       if (!configuration) {
+               weston_config_destroy(config);
+               return NULL;
+       }
+
+       weston_config_section_get_string(s, "name",
+                                        &configuration->device_name, NULL);
+       weston_config_section_get_string(s, "channel_x",
+                                        &configuration->channel_x_name, 
"accel_x");
+       weston_config_section_get_string(s, "channel_y",
+                                        &configuration->channel_y_name, 
"accel_y");
+       weston_config_section_get_string(s, "sampling_frequency_attr",
+                                        
&configuration->sampling_frequency_name,
+                                        "accel_sampling_frequency");
+       weston_config_section_get_double(s, "wanted_sampling_frequency",
+                                        
&configuration->wanted_sampling_frequency,
+                                        0.);
+       weston_config_section_get_int(s, "threshold",
+                                     &configuration->threshold, 128);
+       weston_config_section_get_string(s, "allowed_rotations",
+                                        &allowed_rotations, NULL);
+
+       weston_config_destroy(config);
+
+       wl_array_init(&configuration->allowed_rotations);
+       if (allowed_rotations) {
+               p = allowed_rotations;
+               for (i = 0; i < 4; ++i) {
+                       if (!parse_transform(p, &transform))
+                               break;
+                       array_items = 
wl_array_add(&configuration->allowed_rotations,
+                                                 sizeof(int));
+                       *array_items = transform;
+                       for (; *p != ' ' && *p != '\0'; p++);
+                       if (*p++ == '\0')
+                               break;
+               }
+               free(allowed_rotations);
+       } else {
+               array_items = wl_array_add(&configuration->allowed_rotations,
+                                          sizeof(int));
+               array_items[0] = WESTON_ROTATOR_TRANSFORM_NORMAL;
+               array_items[1] = WESTON_ROTATOR_TRANSFORM_90;
+               array_items[2] = WESTON_ROTATOR_TRANSFORM_180;
+               array_items[3] = WESTON_ROTATOR_TRANSFORM_270;
+       }
+
+       return configuration;
+}
+
+static void
+destroy_configuration(struct config *config)
+{
+       free(config->device_name);
+       free(config->channel_x_name);
+       free(config->channel_y_name);
+       free(config->sampling_frequency_name);
+       wl_array_release(&config->allowed_rotations);
+       free(config);
+}
+
+static struct accelerometer *
+initialize_iio(struct config *config)
+{
+       struct accelerometer *accel;
+       int ret;
+
+       accel = zalloc(sizeof *accel);
+       if (!accel)
+               return NULL;
+
+       accel->context = iio_create_local_context();
+       if (!accel->context)
+               goto err_context;
+
+       if (config->device_name)
+               accel->device = iio_context_find_device(accel->context,
+                                                       config->device_name);
+
+       if (!accel->device) {
+               fprintf(stderr, "couldn't find device %s\n",
+                       config->device_name);
+               goto err_device;
+       }
+
+       accel->channel_x = iio_device_find_channel(accel->device,
+                                                  config->channel_x_name,
+                                                  false);
+       if (!accel->channel_x) {
+               fprintf(stderr, "couldn't find x channel %s\n",
+                       config->channel_x_name);
+               goto err_channel;
+       }
+
+       accel->channel_y = iio_device_find_channel(accel->device,
+                                                  config->channel_y_name,
+                                                  false);
+       if (!accel->channel_y) {
+               fprintf(stderr, "couldn't find y channel %s\n",
+                       config->channel_y_name);
+               goto err_channel;
+       }
+
+       if (config->wanted_sampling_frequency) {
+               ret = iio_device_attr_write_double(accel->device,
+                                                  
config->sampling_frequency_name,
+                                                  
config->wanted_sampling_frequency);
+               if (ret < 0) {
+                       fprintf(stderr, "couldn't set sampling frequency to "
+                                       "%f\n",
+                               config->wanted_sampling_frequency);
+                       goto err_channel;
+               }
+       }
+
+       ret = iio_device_attr_read_double(accel->device,
+                                         config->sampling_frequency_name,
+                                         &accel->sampling_frequency);
+       if (ret < 0) {
+               fprintf(stderr, "couldn't retrieve sampling frequency, "
+                               "defaulting to %f\n",
+                       DEFAULT_SAMPLING_FREQUENCY);
+               accel->sampling_frequency = DEFAULT_SAMPLING_FREQUENCY;
+       }
+
+       return accel;
+
+err_channel:
+err_device:
+       iio_context_destroy(accel->context);
+err_context:
+       free(accel);
+       return NULL;
+}
+
+static void
+destroy_accelerometer(struct accelerometer *accel)
+{
+       if (accel->context)
+               iio_context_destroy(accel->context);
+       free(accel);
+}
+
+static bool
+capture_rotation(struct accelerometer *accel, int *x, int *y)
+{
+       char buf[BUFFER_SIZE];
+       ssize_t ret;
+
+       ret = iio_channel_attr_read(accel->channel_x, "raw", buf, BUFFER_SIZE);
+       if (ret < 0) {
+               iio_strerror(-ret, buf, BUFFER_SIZE);
+               fprintf(stderr, "%s\n", buf);
+               return false;
+       }
+       *x = atoi(buf);
+
+       ret = iio_channel_attr_read(accel->channel_y, "raw", buf, BUFFER_SIZE);
+       if (ret < 0) {
+               iio_strerror(-ret, buf, BUFFER_SIZE);
+               fprintf(stderr, "%s\n", buf);
+               return false;
+       }
+       *y = atoi(buf);
+       return true;
+}
+
+static int
+get_transform(int x, int y, int threshold)
+{
+       if (y > threshold && y > x)
+               return WESTON_ROTATOR_TRANSFORM_NORMAL;
+       if (x > threshold && x > y)
+               return WESTON_ROTATOR_TRANSFORM_90;
+       if (y < -threshold && y < x)
+               return WESTON_ROTATOR_TRANSFORM_180;
+       if (x < -threshold && x < y)
+               return WESTON_ROTATOR_TRANSFORM_270;
+       return -1;
+}
+
+static bool
+synchronize(struct wl_display *display, double sampling_frequency)
+{
+       if (wl_display_roundtrip(display) < 0) {
+               fprintf(stderr, "lost connection, aborting\n");
+               return false;
+       }
+       usleep(1000. * sampling_frequency);
+       return true;
+}
+
+static void
+handle_global(void *data, struct wl_registry *registry,
+              uint32_t name, const char *interface, uint32_t version)
+{
+       if (strcmp(interface, "weston_rotator") == 0) {
+               rotator = wl_registry_bind(registry, name,
+                                          &weston_rotator_interface,
+                                          1);
+       }
+}
+
+static void
+handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
+{
+       /* XXX: unimplemented */
+}
+
+static const struct wl_registry_listener registry_listener = {
+       handle_global,
+       handle_global_remove
+};
+
+int main(int argc, char *argv[])
+{
+       struct wl_display *display;
+       struct wl_registry *registry;
+       struct config *config;
+       struct accelerometer *accel;
+       const char *accelerometer_device;
+       bool ret, found;
+       int x, y;
+       int transform, previous_transform, *allowed_transform;
+
+       if (getenv("WAYLAND_SOCKET") == NULL) {
+               fprintf(stderr, "%s must be launched by Weston.\n",
+                       program_invocation_short_name);
+               return 1;
+       }
+
+       accelerometer_device = getenv("WESTON_ACCELEROMETER");
+       if (accelerometer_device == NULL) {
+               fprintf(stderr, "Weston must pass an accelerometer device.\n");
+               return 2;
+       }
+
+       config = read_configuration(accelerometer_device);
+       if (!config) {
+               fprintf(stderr, "failed to read configuration\n");
+               return 3;
+       }
+
+       display = wl_display_connect(NULL);
+       if (display == NULL) {
+               fprintf(stderr, "failed to create display: %m\n");
+               destroy_configuration(config);
+               return 4;
+       }
+
+       registry = wl_display_get_registry(display);
+       wl_registry_add_listener(registry, &registry_listener, NULL);
+       wl_display_dispatch(display);
+       wl_display_roundtrip(display);
+       if (rotator == NULL) {
+               fprintf(stderr, "display doesn't support rotator\n");
+               free(registry);
+               wl_display_disconnect(display);
+               destroy_configuration(config);
+               return 5;
+       }
+
+       accel = initialize_iio(config);
+       if (!accel) {
+               fprintf(stderr, "failed to initialize iio subsystem\n");
+               free(registry);
+               wl_display_disconnect(display);
+               destroy_configuration(config);
+               return 6;
+       }
+
+       previous_transform = WESTON_ROTATOR_TRANSFORM_NORMAL;
+       for (;;) {
+               ret = capture_rotation(accel, &x, &y);
+               if (!ret) {
+                       fprintf(stderr, "failed to capture accelerometer "
+                                       "values\n");
+                       break;
+               }
+
+               transform = get_transform(x, y, config->threshold);
+               if (transform < 0) {
+                       if (!synchronize(display, accel->sampling_frequency))
+                               return 7;
+                       continue;
+               }
+
+               found = false;
+               wl_array_for_each(allowed_transform,
+                                 &config->allowed_rotations) {
+                       if (transform == *allowed_transform) {
+                               found = true;
+                               break;
+                       }
+               }
+
+               if (!found) {
+                       if (!synchronize(display, accel->sampling_frequency))
+                               return 7;
+                       continue;
+               }
+
+               if (transform != previous_transform) {
+                       weston_rotator_rotate(rotator,
+                                             accelerometer_device,
+                                             transform);
+               }
+               previous_transform = transform;
+
+               if (!synchronize(display, accel->sampling_frequency))
+                       return 7;
+       }
+
+       wl_display_disconnect(display);
+       destroy_accelerometer(accel);
+       destroy_configuration(config);
+
+       return 0;
+}
diff --git a/compositor/rotator.c b/compositor/rotator.c
new file mode 100644
index 0000000..c823205
--- /dev/null
+++ b/compositor/rotator.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright © 2016 Collabora, Ltd.
+ *
+ * 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 <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/input-event-codes.h>
+
+#include "compositor.h"
+#include "weston-rotator-server-protocol.h"
+#include "weston.h"
+#include "shared/helpers.h"
+#include "shared/zalloc.h"
+
+struct autorotator_process {
+       char *accelerometer;
+       struct wl_client *client;
+       struct weston_process process;
+       struct wl_list link;
+};
+
+struct rotator {
+       struct weston_compositor *ec;
+       struct wl_global *global;
+       struct wl_list process_list;
+       struct wl_listener destroy_listener;
+};
+
+static void
+rotator_rotate(struct wl_client *client,
+               struct wl_resource *resource,
+               const char *accelerometer_device,
+               int32_t transform)
+{
+       struct rotator *rotator = wl_resource_get_user_data(resource);
+       int32_t current_width;
+       struct weston_output *output;
+       struct weston_mode *mode;
+
+       wl_list_for_each(output, &rotator->ec->output_list, link) {
+               if (!output->accelerometer || strcmp(accelerometer_device, 
output->accelerometer) != 0)
+                       continue;
+
+               output->transform = transform;
+               output->dirty = 1;
+
+               /* Only swap width and height when the aspect ratio changed. */
+               mode = output->current_mode;
+               if ((transform ^ output->transform) & 1) {
+                       current_width = mode->width;
+                       mode->width = mode->height;
+                       mode->height = current_width;
+                       weston_output_mode_set_native(output, mode, 
output->current_scale);
+               }
+
+               weston_output_damage(output);
+       }
+}
+
+struct weston_rotator_interface rotator_implementation = {
+       rotator_rotate
+};
+
+static void
+bind_rotator(struct wl_client *client,
+             void *data, uint32_t version, uint32_t id)
+{
+       struct rotator *rotator = data;
+       struct autorotator_process *process;
+       struct wl_resource *resource;
+       bool found;
+
+       resource = wl_resource_create(client,
+                                     &weston_rotator_interface, 1, id);
+
+       found = false;
+       wl_list_for_each(process, &rotator->process_list, link)
+               if (client == process->client)
+                       found = true;
+       if (!found) {
+               wl_resource_post_error(resource,
+                                      WL_DISPLAY_ERROR_INVALID_OBJECT,
+                                      "rotator failed: permission denied");
+               return;
+       }
+
+       wl_resource_set_implementation(resource, &rotator_implementation,
+                                      data, NULL);
+}
+
+static void
+rotator_sigchld(struct weston_process *process, int status)
+{
+       struct autorotator_process *autorotator_process =
+               container_of(process, struct autorotator_process, process);
+
+       autorotator_process->client = NULL;
+}
+
+static void
+rotator_launch_autorotator(struct rotator *rotator)
+{
+       struct autorotator_process *process;
+       char *rotator_exe;
+       int ret;
+
+       const char *old_device = getenv("WESTON_ACCELEROMETER");
+
+       ret = asprintf(&rotator_exe, "%s/%s",
+                      weston_config_get_libexec_dir(),
+                      "weston-autorotator");
+       if (ret < 0) {
+               weston_log("Could not construct rotator path.\n");
+               return;
+       }
+
+       wl_list_for_each(process, &rotator->process_list, link) {
+               setenv("WESTON_ACCELEROMETER", process->accelerometer, 1);
+               process->client = weston_client_launch(rotator->ec,
+                                                     &process->process,
+                                                     rotator_exe,
+                                                     rotator_sigchld);
+       }
+       free(rotator_exe);
+
+       if (old_device)
+               setenv("WESTON_ACCELEROMETER", old_device, 1);
+       else
+               unsetenv("WESTON_ACCELEROMETER");
+}
+
+static void
+rotator_destroy(struct wl_listener *listener, void *data)
+{
+       struct weston_output *output;
+       struct autorotator_process *process, *next;
+       struct rotator *rotator =
+               container_of(listener, struct rotator, destroy_listener);
+
+       wl_list_for_each(output, &rotator->ec->output_list, link)
+               free(output->accelerometer);
+
+       wl_list_for_each_safe(process, next, &rotator->process_list, link) {
+               free(process->accelerometer);
+               free(process);
+       }
+
+       wl_global_destroy(rotator->global);
+       free(rotator);
+}
+
+static bool
+read_configuration(struct rotator *rotator)
+{
+       const char *config_file;
+       struct weston_config *config;
+       struct weston_config_section *section = NULL;
+       struct weston_output *output;
+       struct autorotator_process *process;
+       const char *section_name;
+       char *output_name, *accelerometer_name;
+
+       config_file = weston_config_get_name_from_env();
+       config = weston_config_parse(config_file);
+       if (config == NULL)
+               return false;
+
+       while (weston_config_next_section(config, &section, &section_name)) {
+               if (strcmp(section_name, "output") == 0) {
+                       weston_config_section_get_string(section, "name", 
&output_name, NULL);
+                       if (output_name == NULL)
+                               continue;
+                       weston_config_section_get_string(section, 
"accelerometer", &accelerometer_name, NULL);
+                       wl_list_for_each(output, &rotator->ec->output_list, 
link)
+                               if (output->name && strcmp(output->name, 
output_name) == 0) {
+                                       output->accelerometer = 
accelerometer_name; //TODO: free at deletion?
+                                       break;
+                               }
+                       free(output_name);
+               } else if (strcmp(section_name, "accelerometer") == 0) {
+                       weston_config_section_get_string(section, "name", 
&accelerometer_name, NULL);
+                       if (accelerometer_name == NULL)
+                               continue;
+                       process = zalloc(sizeof *process);
+                       if (process == NULL)
+                               return false;
+                       process->accelerometer = accelerometer_name;
+                       wl_list_insert(&rotator->process_list, &process->link);
+               }
+       }
+
+       weston_config_destroy(config);
+
+       return true;
+}
+
+WL_EXPORT int
+module_init(struct weston_compositor *ec, int *argc, char *argv[])
+{
+       struct rotator *rotator;
+
+       rotator = zalloc(sizeof *rotator);
+       if (rotator == NULL)
+               return -1;
+
+       rotator->ec = ec;
+       wl_list_init(&rotator->process_list);
+
+       if (!read_configuration(rotator))
+               return -1;
+
+       rotator->global = wl_global_create(ec->wl_display,
+                                          &weston_rotator_interface, 1,
+                                          rotator, bind_rotator);
+       rotator->destroy_listener.notify = rotator_destroy;
+       wl_signal_add(&ec->destroy_signal, &rotator->destroy_listener);
+
+       rotator_launch_autorotator(rotator);
+
+       return 0;
+}
diff --git a/configure.ac b/configure.ac
index 74f931d..186fc25 100644
--- a/configure.ac
+++ b/configure.ac
@@ -379,6 +379,20 @@ if ! test "x$enable_simple_dmabuf_v4l_client" = "xno"; then
 fi
 AM_CONDITIONAL(BUILD_SIMPLE_DMABUF_V4L_CLIENT, test 
"x$enable_simple_dmabuf_v4l_client" = "xyes")
 
+AC_ARG_ENABLE(weston-autorotator,
+              AS_HELP_STRING([--disable-weston-autorotator],
+                             [do not build the autorotator client]),,
+              enable_autorotator="auto")
+if ! test "x$enable_autorotator" = "xno"; then
+  PKG_CHECK_MODULES(LIBIIO, [libiio],
+                    have_autorotator=yes, have_autorotator=no)
+  if test "x$have_autorotator" = "xno" -a "x$enable_autorotator" = "xyes"; then
+    AC_MSG_ERROR([autorotator client explicitly enabled, but libiio couldn't 
be found])
+  fi
+  enable_autorotator="$have_autorotator"
+fi
+AM_CONDITIONAL(BUILD_AUTOROTATOR, test "x$enable_autorotator" = "xyes")
+
 AC_ARG_ENABLE(clients, [  --enable-clients],, enable_clients=yes)
 AM_CONDITIONAL(BUILD_CLIENTS, test x$enable_clients = xyes)
 if test x$enable_clients = xyes; then
@@ -685,6 +699,7 @@ AC_MSG_RESULT([
        Build EGL Clients               ${have_cairo_egl}
        Build Simple Clients            ${enable_simple_clients}
        Build Simple EGL Clients        ${enable_simple_egl_clients}
+       Build Auto-rotator Client       ${enable_autorotator}
 
        Install Demo Clients            ${enable_demo_clients_install}
 
diff --git a/libweston/compositor.c b/libweston/compositor.c
index b17c76d..75c2d2f 100644
--- a/libweston/compositor.c
+++ b/libweston/compositor.c
@@ -4113,6 +4113,7 @@ weston_output_destroy(struct weston_output *output)
        wl_signal_emit(&output->destroy_signal, output);
 
        free(output->name);
+       free(output->accelerometer);
        pixman_region32_fini(&output->region);
        pixman_region32_fini(&output->previous_damage);
        output->compositor->output_id_pool &= ~(1u << output->id);
diff --git a/libweston/compositor.h b/libweston/compositor.h
index 0133084..9cf5c19 100644
--- a/libweston/compositor.h
+++ b/libweston/compositor.h
@@ -240,6 +240,7 @@ struct weston_output {
                          uint16_t *b);
 
        struct weston_timeline_object timeline;
+    char *accelerometer;
 };
 
 enum weston_pointer_motion_mask {
diff --git a/man/weston.ini.man b/man/weston.ini.man
index 7aa7810..a527707 100644
--- a/man/weston.ini.man
+++ b/man/weston.ini.man
@@ -412,6 +412,47 @@ multiheaded environment with a single compositor for 
multiple output and input
 configurations. The default seat is called "default" and will always be
 present. This seat can be constrained like any other.
 .RE
+.TP 7
+.BI "accelerometer=" device
+The name of an accelerometer corresponding to an accelerometer section, which
+will be used to make this particular output rotate.
+.RE
+.SH "ACCELEROMETER SECTION"
+There can be multiple accelerometer sections, each corresponding to one
+accelerometer device.  Each one should be listed in at least one output section
+in order to have any effect, to select which outputs it will rotate.
+.TP 7
+.BI "name=" device
+defines the device that will be used for this accelerometer.  Must be the same
+string as the accelerometer field in an output section.
+.RE
+.TP 7
+.BI "channel_x=" attribute
+sets the iio channel that will be used as the horizontal value.  By default,
+this channel is named accel_x.
+.RE
+.TP 7
+.BI "channel_y=" attribute
+sets the iio channel that will be used as the vertical value.  By default, this
+channel is named accel_y.
+.RE
+.TP 7
+.BI "sampling_frequency_attr=" attribute
+sets the iio channel that will be used to set the desired sampling frequency.
+By default, this channel is named accel_sampling_frequency.
+.RE
+.TP 7
+.BI "sampling_frequency=" number
+sets the target sampling frequency, for the sampling_frequency_attr.  If there
+is any error while setting it, the current value will be used instead.
+.RE
+.TP 7
+.BI "allowed_rotations=" list
+restricts the allowed rotation configurations, list can take up to four
+space-separated values, selected from “normal”, “90”, “180” and “270”.  Any
+value not listed in list will disallow this rotation, and the absence of this
+option will allow all four of them.
+.RE
 .SH "INPUT-METHOD SECTION"
 .TP 7
 .BI "path=" "/usr/libexec/weston-keyboard"
diff --git a/protocol/weston-rotator.xml b/protocol/weston-rotator.xml
new file mode 100644
index 0000000..37f027a
--- /dev/null
+++ b/protocol/weston-rotator.xml
@@ -0,0 +1,26 @@
+<protocol name="weston_rotator">
+
+  <interface name="weston_rotator" version="1">
+
+    <enum name="transform">
+      <description summary="copied from wl_output.transform"/>
+      <entry name="normal" value="0"/>
+      <entry name="90" value="1"/>
+      <entry name="180" value="2"/>
+      <entry name="270" value="3"/>
+      <entry name="flipped" value="4"/>
+      <entry name="flipped_90" value="5"/>
+      <entry name="flipped_180" value="6"/>
+      <entry name="flipped_270" value="7"/>
+    </enum>
+
+    <request name="rotate">
+      <arg name="accelerometer" type="string"/>
+      <arg name="transform" type="int" enum="transform"/>
+    </request>
+
+    <event name="done"/>
+
+  </interface>
+
+</protocol>
diff --git a/weston.ini.in b/weston.ini.in
index 14a4c0c..5e36e5f 100644
--- a/weston.ini.in
+++ b/weston.ini.in
@@ -46,6 +46,7 @@ path=@libexecdir@/weston-keyboard
 #mode=1680x1050
 #transform=90
 #icc_profile=/usr/share/color/icc/colord/Bluish.icc
+#accelerometer=iio:device0
 
 #[output]
 #name=VGA1
@@ -65,6 +66,9 @@ path=@libexecdir@/weston-keyboard
 #min_accel_factor = 0.16
 #max_accel_factor = 1.0
 
+#[accelerometer]
+#device=iio:device0
+
 [screen-share]
 command=@bindir@/weston --backend=rdp-backend.so --shell=fullscreen-shell.so 
--no-clients-resize
 
-- 
2.9.2

_______________________________________________
wayland-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to