Initial commit: Added current work

This commit is contained in:
Yuki Joou 2023-07-11 17:55:43 +02:00
commit 3fa9c8d193
10 changed files with 637 additions and 0 deletions

25
.clang-format Normal file
View file

@ -0,0 +1,25 @@
BasedOnStyle: Microsoft
UseTab: ForIndentation
TabWidth: 4
BreakBeforeBraces: Linux
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: WithoutElse
PointerAlignment: Left
AlignAfterOpenBracket: Align
BinPackArguments: false
BinPackParameters: false
AlignArrayOfStructures: Right
AlignArrayOfStructures: Right
AlignConsecutiveAssignments: Consecutive
AlignConsecutiveBitFields: Consecutive
AlignConsecutiveDeclarations: Consecutive
AlignConsecutiveMacros: Consecutive
AlignEscapedNewlines: Right
AlignOperands: AlignAfterOperator
AlignTrailingComments: true
ColumnLimit: 80

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
protocol/*.c
protocol/*.h
protocol/*.xml
*~
miix-wlr

162
accel_monitor.c Normal file
View file

@ -0,0 +1,162 @@
#include "accel_monitor.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char* sensor_get_axis_path(char const* const base, char axis)
{
// TODO: Be smarter about the buffer size
char buffer[128];
snprintf(buffer, sizeof(buffer), "%s/in_accel_%c_raw", base, axis);
return strdup(buffer);
}
static int monitor_thread(void* data)
{
struct accel_monitor* monitor = data;
while (!monitor->monitoring_thread_is_ready)
;
char* x_axis_path = sensor_get_axis_path(monitor->sysfs_device_path, 'x');
FILE* x_axis_fp = fopen(x_axis_path, "r");
free(x_axis_path);
char* y_axis_path = sensor_get_axis_path(monitor->sysfs_device_path, 'y');
FILE* y_axis_fp = fopen(y_axis_path, "r");
free(y_axis_path);
char* z_axis_path = sensor_get_axis_path(monitor->sysfs_device_path, 'z');
FILE* z_axis_fp = fopen(z_axis_path, "r");
free(z_axis_path);
while (!monitor->monitoring_thread_should_exit) {
fseek(x_axis_fp, 0, SEEK_SET);
fseek(y_axis_fp, 0, SEEK_SET);
fseek(z_axis_fp, 0, SEEK_SET);
int16_t x_axis;
int16_t y_axis;
int16_t z_axis;
fscanf(x_axis_fp, "%hd\n", &x_axis);
fscanf(y_axis_fp, "%hd\n", &y_axis);
fscanf(z_axis_fp, "%hd\n", &z_axis);
if (mtx_lock(&monitor->current_data_lock) != thrd_success) {
fprintf(stderr,
"Can't lock data from data monitoring thread. Something is "
"going wrong. Giving up on monitoring sensor data.\n");
break;
}
monitor->current_data.x = x_axis;
monitor->current_data.y = y_axis;
monitor->current_data.z = z_axis;
if (mtx_unlock(&monitor->current_data_lock) != thrd_success) {
fprintf(stderr,
"Can't unlock data from data monitoring thread. Something "
"is going wrong. Giving up on monitoring sensor data.\n");
break;
}
monitor->data_is_ready = true;
}
fclose(x_axis_fp);
fclose(y_axis_fp);
fclose(z_axis_fp);
return 0;
}
struct accel_monitor* accel_start_monitor(
char const* const sysfs_device_path)
{
mtx_t current_data_lock;
if (mtx_init(&current_data_lock, mtx_plain) != thrd_success) return 0;
if (mtx_lock(&current_data_lock) != thrd_success) return 0;
struct accel_monitor* monitor = calloc(1, sizeof(struct accel_monitor));
monitor->monitoring_thread_is_ready = false;
monitor->data_is_ready = false;
thrd_t monitoring_thread;
if (thrd_create(&monitoring_thread, &monitor_thread, monitor) !=
thrd_success) {
free(monitor);
return 0;
}
monitor->sysfs_device_path = sysfs_device_path;
monitor->monitoring_thread = monitoring_thread;
monitor->current_data_lock = current_data_lock;
monitor->current_data.x = 0;
monitor->current_data.y = 0;
monitor->current_data.z = 0;
monitor->monitoring_thread_should_exit = false;
if (mtx_unlock(&monitor->current_data_lock) != thrd_success)
fprintf(stderr,
"Unable to unlock the data after initialisation. We are in UB "
"territory. Something must've went very wrong\n");
monitor->monitoring_thread_is_ready = true;
return monitor;
}
static bool axis_is_near_0(int16_t axis)
{
return (axis > -500) && (axis < 500);
}
static bool axis_is_mostly_positive(int16_t axis)
{
return axis >= 500;
}
static bool axis_is_mostly_negative(int16_t axis)
{
return axis <= -500;
}
enum accel_rotation accel_get_current_rotation(
struct accel_monitor* monitor)
{
if (mtx_lock(&monitor->current_data_lock) != thrd_success)
return ACCEL_ROTATION_NO_CHANGE;
struct accel_data data = monitor->current_data;
if (mtx_unlock(&monitor->current_data_lock) != thrd_success)
fprintf(stderr, "Can't unlock data, this is going to cause issues.\n");
if (axis_is_near_0(data.x)) {
if (axis_is_mostly_positive(data.y)) return ACCEL_ROTATION_0DEG;
if (axis_is_mostly_negative(data.y)) return ACCEL_ROTATION_180DEG;
}
if (axis_is_mostly_positive(data.x)) return ACCEL_ROTATION_90DEG;
if (axis_is_mostly_negative(data.x)) return ACCEL_ROTATION_270DEG;
return ACCEL_ROTATION_NO_CHANGE;
}
void accel_stop_monitor(struct accel_monitor* monitor)
{
monitor->monitoring_thread_should_exit = true;
if (thrd_join(monitor->monitoring_thread, NULL) != thrd_success)
fprintf(stderr,
"Can't join monitoring thread. The program may not exit "
"cleanly.\n");
mtx_destroy(&monitor->current_data_lock);
free(monitor);
}

36
accel_monitor.h Normal file
View file

@ -0,0 +1,36 @@
#pragma once
#include <stdatomic.h>
#include <stdint.h>
#include <threads.h>
struct accel_data {
int16_t x;
int16_t y;
int16_t z;
};
enum accel_rotation : uint8_t {
ACCEL_ROTATION_0DEG = 0,
ACCEL_ROTATION_90DEG,
ACCEL_ROTATION_180DEG,
ACCEL_ROTATION_270DEG,
ACCEL_ROTATION_NO_CHANGE,
};
struct accel_monitor {
atomic_bool monitoring_thread_should_exit;
atomic_bool monitoring_thread_is_ready;
thrd_t monitoring_thread;
char const* sysfs_device_path;
mtx_t current_data_lock;
struct accel_data current_data;
atomic_bool data_is_ready;
};
struct accel_monitor* accel_start_monitor(
char const* const sysfs_device_path);
enum accel_rotation accel_get_current_rotation(struct accel_monitor*);
void accel_stop_monitor(struct accel_monitor*);

10
build.sh Executable file
View file

@ -0,0 +1,10 @@
#!/bin/sh
set -ex;
SOURCES="main.c output_manager.c accel_monitor.c"
CFLAGS="-std=c2x -Wall -Wextra -pedantic $CFLAGS"
LIBS="-lwayland-client protocol/wlr-output-management-unstable-v1.c"
OUTPUT=miix-wlr
clang $CFLAGS $LIBS $SOURCES -o $OUTPUT

45
main.c Normal file
View file

@ -0,0 +1,45 @@
#include <stdio.h>
#include <stdlib.h>
#include "output_manager.h"
#include "accel_monitor.h"
static enum wl_output_transform const SENSOR_TO_OUTPUT_ROTATION[] = {
[ACCEL_ROTATION_0DEG] = WL_OUTPUT_TRANSFORM_270,
[ACCEL_ROTATION_90DEG] = WL_OUTPUT_TRANSFORM_NORMAL,
[ACCEL_ROTATION_180DEG] = WL_OUTPUT_TRANSFORM_90,
[ACCEL_ROTATION_270DEG] = WL_OUTPUT_TRANSFORM_180,
};
static char const* const DEFAULT_OUTPUT = "DSI-1";
static char const* const DEFAULT_MOTION_SENSOR =
"/sys/bus/iio/devices/iio:device0";
static enum accel_rotation last_accel_rotation = ACCEL_ROTATION_NO_CHANGE;
int main(int, char**)
{
struct accel_monitor* monitor =
accel_start_monitor(DEFAULT_MOTION_SENSOR);
if (!monitor) {
fprintf(stderr, "Failed to start iio motion monitoring\n");
return -1;
}
struct miix_wlr_state* state = miix_wlr_init();
for (;;) {
if (!monitor->data_is_ready) continue;
enum accel_rotation rotation = accel_get_current_rotation(monitor);
if (rotation == ACCEL_ROTATION_NO_CHANGE || rotation == last_accel_rotation) continue;
miix_wlr_head_set_transform(
state, DEFAULT_OUTPUT, SENSOR_TO_OUTPUT_ROTATION[rotation]);
last_accel_rotation = rotation;
}
accel_stop_monitor(monitor);
miix_wlr_cleanup(state);
}

311
output_manager.c Normal file
View file

@ -0,0 +1,311 @@
// NOTE: Most of this code was stolen from wlr-randr, available at
// https://git.sr.ht/~emersion/wlr-randr/tree/master/item/main.c
#include "output_manager.h"
#include <wayland-client.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "protocol/wlr-output-management-unstable-v1.h"
static void head_handle_name(void* data,
struct zwlr_output_head_v1*,
const char* name)
{
struct miix_wlr_head* head = data;
head->name = strdup(name);
}
static void head_handle_description(void*,
struct zwlr_output_head_v1*,
const char*)
{
// NO-OP
}
static void head_handle_physical_size(void*,
struct zwlr_output_head_v1*,
int32_t,
int32_t)
{
// NO-OP
}
static void head_handle_mode(void*,
struct zwlr_output_head_v1*,
struct zwlr_output_mode_v1*)
{
// NO-OP
}
static void head_handle_enabled(void*, struct zwlr_output_head_v1*, int32_t)
{
// NO-OP
}
static void head_handle_current_mode(void*,
struct zwlr_output_head_v1*,
struct zwlr_output_mode_v1*)
{
// NO-OP
}
static void head_handle_position(void*,
struct zwlr_output_head_v1*,
int32_t,
int32_t)
{
// NO-OP
}
static void head_handle_transform(void*, struct zwlr_output_head_v1*, int32_t)
{
// NO-OP
}
static void head_handle_scale(void*, struct zwlr_output_head_v1*, wl_fixed_t)
{
// NO-OP
}
static void head_handle_finished(void*, struct zwlr_output_head_v1*)
{
// NO-OP
}
static void head_handle_make(void*, struct zwlr_output_head_v1*, const char*)
{
// NO-OP
}
static void head_handle_model(void*, struct zwlr_output_head_v1*, const char*)
{
// NO-OP
}
static void head_handle_serial_number(void*,
struct zwlr_output_head_v1*,
const char*)
{
// NO-OP
}
static void head_handle_adaptive_sync(void*,
struct zwlr_output_head_v1*,
uint32_t)
{
// NO-OP
}
static const struct zwlr_output_head_v1_listener head_listener = {
.name = head_handle_name,
.description = head_handle_description,
.physical_size = head_handle_physical_size,
.mode = head_handle_mode,
.enabled = head_handle_enabled,
.current_mode = head_handle_current_mode,
.position = head_handle_position,
.transform = head_handle_transform,
.scale = head_handle_scale,
.finished = head_handle_finished,
.make = head_handle_make,
.model = head_handle_model,
.serial_number = head_handle_serial_number,
.adaptive_sync = head_handle_adaptive_sync,
};
static void output_manager_handle_head(void* data,
struct zwlr_output_manager_v1*,
struct zwlr_output_head_v1* wlr_head)
{
struct miix_wlr_state* state = data;
struct miix_wlr_head* head = calloc(1, sizeof(*head));
head->wlr_head = wlr_head;
wl_list_insert(state->heads.prev, &head->link);
zwlr_output_head_v1_add_listener(wlr_head, &head_listener, head);
}
static void output_manager_handle_done(void* data,
struct zwlr_output_manager_v1*,
uint32_t serial)
{
struct miix_wlr_state* state = data;
state->serial = serial;
}
static void output_manager_handle_finished(void*,
struct zwlr_output_manager_v1*)
{
// NO-OP
}
static const struct zwlr_output_manager_v1_listener output_manager_listener = {
.head = output_manager_handle_head,
.done = output_manager_handle_done,
.finished = output_manager_handle_finished,
};
static void registry_handle_global(void* data,
struct wl_registry* registry,
uint32_t name,
const char* interface,
uint32_t)
{
struct miix_wlr_state* state = data;
if (strcmp(interface, zwlr_output_manager_v1_interface.name) == 0) {
// TODO: Don't always bind version 4?
state->output_manager = wl_registry_bind(
registry, name, &zwlr_output_manager_v1_interface, 4);
zwlr_output_manager_v1_add_listener(
state->output_manager, &output_manager_listener, state);
}
}
static void registry_handle_global_remove(void*, struct wl_registry*, uint32_t)
{
// NO-OP
}
static void config_handle_succeeded(void* data,
struct zwlr_output_configuration_v1* config)
{
struct miix_wlr_state* state = data;
state->is_working = false;
zwlr_output_configuration_v1_destroy(config);
printf("Applied configuration successfully!\n");
}
static void config_handle_failed(void* data,
struct zwlr_output_configuration_v1* config)
{
struct miix_wlr_state* state = data;
state->is_working = false;
zwlr_output_configuration_v1_destroy(config);
fprintf(stderr, "Failed to apply configuration\n");
}
static void config_handle_cancelled(void* data,
struct zwlr_output_configuration_v1* config)
{
struct miix_wlr_state* state = data;
state->is_working = false;
zwlr_output_configuration_v1_destroy(config);
fprintf(stderr, "Configuration cancelled\n");
}
static const struct zwlr_output_configuration_v1_listener config_listener = {
.succeeded = config_handle_succeeded,
.failed = config_handle_failed,
.cancelled = config_handle_cancelled,
};
struct miix_wlr_state* miix_wlr_init()
{
struct wl_display* display = wl_display_connect(NULL);
if (!display) {
fprintf(stderr, "Couldn't connect to display\n");
return 0;
}
struct wl_registry* registry = wl_display_get_registry(display);
if (!registry) {
fprintf(stderr, "Couldn't get display registry\n");
return 0;
}
struct miix_wlr_state* state = calloc(1, sizeof(struct miix_wlr_state));
state->is_working = false;
state->display = display;
wl_list_init(&state->heads);
static const struct wl_registry_listener registry_listener = {
.global = registry_handle_global,
.global_remove = registry_handle_global_remove,
};
wl_registry_add_listener(registry, &registry_listener, state);
wl_display_dispatch(display);
wl_display_roundtrip(display);
wl_registry_destroy(registry);
if (!state->output_manager) {
fprintf(stderr,
"Couldn't get output manager. Does your compositor support "
"wlr-outpput-management-unstable-v1?\n");
return 0;
}
return state;
}
char** miix_wlr_get_head_names(struct miix_wlr_state const* state)
{
int head_count = wl_list_length(&state->heads);
char** head_name_list = calloc(head_count + 1, sizeof(char*));
size_t head_index = 0;
struct miix_wlr_head *head, *tmp_head;
wl_list_for_each_safe(head, tmp_head, &state->heads, link)
{
head_name_list[head_index] = head->name;
++head_index;
}
head_name_list[head_index] = 0;
return head_name_list;
}
void miix_wlr_head_set_transform(struct miix_wlr_state* state,
char const* const head_name,
enum wl_output_transform transform)
{
struct zwlr_output_configuration_v1* output_config =
zwlr_output_manager_v1_create_configuration(state->output_manager,
state->serial);
zwlr_output_configuration_v1_add_listener(
output_config, &config_listener, state);
struct miix_wlr_head* head;
struct miix_wlr_head* tmp_head;
wl_list_for_each_safe(head, tmp_head, &state->heads, link)
{
if (strcmp(head->name, head_name) != 0) continue;
printf("Found head %s\n", head->name);
struct zwlr_output_configuration_head_v1* config_head =
zwlr_output_configuration_v1_enable_head(output_config,
head->wlr_head);
state->is_working = true;
zwlr_output_configuration_head_v1_set_transform(config_head, transform);
zwlr_output_configuration_v1_apply(output_config);
}
while (state->is_working && wl_display_dispatch(state->display) > 0)
;
}
void miix_wlr_cleanup(struct miix_wlr_state* state)
{
struct miix_wlr_head* head;
struct miix_wlr_head* tmp_head;
wl_list_for_each_safe(head, tmp_head, &state->heads, link)
{
zwlr_output_head_v1_destroy(head->wlr_head);
free(head->name);
free(head);
}
zwlr_output_manager_v1_destroy(state->output_manager);
wl_display_disconnect(state->display);
}

32
output_manager.h Normal file
View file

@ -0,0 +1,32 @@
#pragma once
#include <stdbool.h>
#include <wayland-client.h>
#include "protocol/wlr-output-management-unstable-v1.h"
struct miix_wlr_head {
struct zwlr_output_head_v1* wlr_head;
char* name;
struct wl_list link;
};
struct miix_wlr_state {
bool is_working;
struct zwlr_output_manager_v1* output_manager;
struct wl_display* display;
uint32_t serial;
struct wl_list heads; // struct miix_wlr_head
};
struct miix_wlr_state* miix_wlr_init();
char** miix_wlr_get_head_names(struct miix_wlr_state const*);
void miix_wlr_head_set_transform(struct miix_wlr_state*,
char const* const head_name,
enum wl_output_transform);
void miix_wlr_cleanup(struct miix_wlr_state*);

6
protocol/codegen.sh Executable file
View file

@ -0,0 +1,6 @@
#!/bin/sh
PROTO_NAME=wlr-output-management-unstable-v1
wayland-scanner private-code $PROTO_NAME.xml $PROTO_NAME.c
wayland-scanner client-header $PROTO_NAME.xml $PROTO_NAME.h

5
protocol/download_protocols.sh Executable file
View file

@ -0,0 +1,5 @@
#!/bin/sh
URL="https://gitlab.freedesktop.org/wlroots/wlr-protocols/-/raw/master/unstable/wlr-output-management-unstable-v1.xml"
curl $URL > wlr-output-management-unstable-v1.xml