// This is for asprintf support. // TODO: Don't use asprintf and remove this. #define _GNU_SOURCE #include #include #include #include #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); }