convertablet/main.c

148 lines
3.7 KiB
C

// This is for asprintf support.
// TODO: Don't use asprintf and remove this.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libusb-1.0/libusb.h>
#include "accel_monitor.h"
#include "output_manager.h"
#include "usb_device_detection.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 uint16_t const BASESTATION_VENDOR_ID = 0x048d;
static uint16_t const BASESTATION_PRODUCT_ID = 0x8911;
static char* get_hook_path(char const* const hook_name)
{
char* path;
char* xdg_config_dir = getenv("XDG_CONFIG_HOME");
if (xdg_config_dir)
asprintf(&path, "%s/convertablet/hooks/%s-hook", xdg_config_dir, hook_name);
else
asprintf(&path,
"%s/.config/convertablet/hooks/%s-hook",
getenv("HOME"),
hook_name);
return path;
}
static void on_basestation_connected()
{
printf("Basestation connected\n");
char* hook_path = get_hook_path("basestation-connected");
if (access(hook_path, X_OK) != 0) {
fprintf(stderr, "Couldn't read or execute hook at %s\n", hook_path);
free(hook_path);
return;
}
pid_t pid = fork();
if (pid < 0) {
// Error
fprintf(stderr, "Unable to run hook script!\n");
perror("fork");
} else if (pid == 0) {
// In the child
char* argv[] = {hook_path, 0};
execve(hook_path, argv, environ);
exit(-1);
} else {
free(hook_path);
}
}
static void on_basestation_disconnected()
{
printf("Basestation disconnected\n");
char* hook_path = get_hook_path("basestation-disconnected");
if (access(hook_path, X_OK) != 0) {
// Hook is innaccessible
fprintf(stderr, "Couldn't read or execute hook at %s\n", hook_path);
free(hook_path);
return;
}
pid_t pid = fork();
if (pid < 0) {
// Error
fprintf(stderr, "Unable to run hook script!\n");
perror("fork");
} else if (pid == 0) {
// In the child
char* argv[] = {hook_path, 0};
execve(hook_path, argv, environ);
exit(-1);
} else {
free(hook_path);
}
}
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 usb_detector* base_station_detector =
create_detector(BASESTATION_VENDOR_ID, BASESTATION_PRODUCT_ID);
base_station_detector->on_connected = &on_basestation_connected;
base_station_detector->on_disconnected = &on_basestation_disconnected;
base_station_detector->has_hotplug_callbacks = true;
struct miix_wlr_state* state = miix_wlr_init();
for (;;) {
thrd_sleep(&(struct timespec){0, 10000000UL}, NULL);
if (!monitor->data_is_ready) continue;
if (base_station_detector && base_station_detector->is_connected) {
if (last_accel_rotation != ACCEL_ROTATION_0DEG) {
miix_wlr_head_set_transform(
state,
DEFAULT_OUTPUT,
SENSOR_TO_OUTPUT_ROTATION[ACCEL_ROTATION_0DEG]);
last_accel_rotation = ACCEL_ROTATION_0DEG;
}
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);
destroy_detector(base_station_detector);
miix_wlr_cleanup(state);
}