2023-07-13 11:53:44 +00:00
|
|
|
// This is for asprintf support.
|
|
|
|
// TODO: Don't use asprintf and remove this.
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
|
2023-07-11 15:55:43 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2023-08-27 18:39:55 +00:00
|
|
|
#include <string.h>
|
2023-07-13 11:53:44 +00:00
|
|
|
#include <unistd.h>
|
2023-07-11 15:55:43 +00:00
|
|
|
|
2023-07-11 19:02:56 +00:00
|
|
|
#include <libusb-1.0/libusb.h>
|
2023-07-11 15:55:43 +00:00
|
|
|
|
|
|
|
#include "accel_monitor.h"
|
2023-07-11 19:02:56 +00:00
|
|
|
#include "output_manager.h"
|
|
|
|
#include "usb_device_detection.h"
|
2023-08-27 18:39:55 +00:00
|
|
|
#include "device_information.h"
|
2023-07-11 15:55:43 +00:00
|
|
|
|
2023-08-27 18:39:55 +00:00
|
|
|
static struct device_information get_device_info_for_name(
|
|
|
|
char const* const device_name)
|
|
|
|
{
|
|
|
|
if (strcmp(device_name, "generic") == 0) {
|
|
|
|
fprintf(
|
|
|
|
stderr,
|
|
|
|
"WARNING: Using a 'generic' device. This may not work properly.\n");
|
|
|
|
return DEVICE_INFORMATION_GENERIC;
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t const device_info_count =
|
|
|
|
sizeof(DEVICE_INFOS) / sizeof(*DEVICE_INFOS);
|
|
|
|
for (size_t i = 0; i < device_info_count; ++i) {
|
|
|
|
struct device_information current = DEVICE_INFOS[i];
|
|
|
|
if (strcmp(current.device_name, device_name) == 0) return current;
|
|
|
|
}
|
2023-07-11 15:55:43 +00:00
|
|
|
|
2023-08-27 18:39:55 +00:00
|
|
|
fprintf(stderr, "No matching configuration for '%s'.\n", device_name);
|
2023-07-11 15:55:43 +00:00
|
|
|
|
2023-08-27 18:39:55 +00:00
|
|
|
return DEVICE_INFORMATION_GENERIC;
|
|
|
|
}
|
2023-07-11 19:02:56 +00:00
|
|
|
|
2023-07-13 11:53:44 +00:00
|
|
|
static char* get_hook_path(char const* const hook_name)
|
|
|
|
{
|
|
|
|
char* path;
|
|
|
|
char* xdg_config_dir = getenv("XDG_CONFIG_HOME");
|
|
|
|
if (xdg_config_dir)
|
2023-08-27 18:39:55 +00:00
|
|
|
asprintf(
|
|
|
|
&path, "%s/convertablet/hooks/%s-hook", xdg_config_dir, hook_name);
|
2023-07-13 11:53:44 +00:00
|
|
|
else
|
|
|
|
asprintf(&path,
|
2023-07-13 12:05:59 +00:00
|
|
|
"%s/.config/convertablet/hooks/%s-hook",
|
2023-07-13 11:53:44 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-11 15:55:43 +00:00
|
|
|
static enum accel_rotation last_accel_rotation = ACCEL_ROTATION_NO_CHANGE;
|
|
|
|
|
2023-08-27 18:39:55 +00:00
|
|
|
int main(int argc, char** argv)
|
2023-07-11 15:55:43 +00:00
|
|
|
{
|
2023-08-27 18:39:55 +00:00
|
|
|
if (argc < 2) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"No device specified! Please specify your device's name or use "
|
|
|
|
"'generic' for sane defaults.\n");
|
|
|
|
fprintf(stderr, "\tUsage: %s <device name>\n", argv[0]);
|
|
|
|
fprintf(stderr, "\t %s list-devices \n", argv[0]);
|
2023-07-11 15:55:43 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-08-27 18:39:55 +00:00
|
|
|
if (strcmp(argv[1], "list-devices") == 0) {
|
|
|
|
printf("Device names:\n");
|
|
|
|
static size_t const device_info_count =
|
|
|
|
sizeof(DEVICE_INFOS) / sizeof(*DEVICE_INFOS);
|
|
|
|
for (size_t i = 0; i < device_info_count; ++i)
|
|
|
|
printf("\t- %s\n", DEVICE_INFOS[i].device_name);
|
|
|
|
return 0;
|
|
|
|
}
|
2023-07-11 19:02:56 +00:00
|
|
|
|
2023-08-27 18:39:55 +00:00
|
|
|
struct device_information device_info = get_device_info_for_name(argv[1]);
|
2023-07-13 11:53:44 +00:00
|
|
|
|
2023-08-27 18:39:55 +00:00
|
|
|
struct accel_monitor* monitor = 0;
|
|
|
|
struct miix_wlr_state* state = 0;
|
|
|
|
if (device_info.screen_rotation_supported) {
|
|
|
|
monitor = accel_start_monitor(device_info.target_motion_sensor);
|
|
|
|
if (!monitor) {
|
|
|
|
fprintf(stderr, "Failed to start iio motion monitoring\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
state = miix_wlr_init();
|
|
|
|
if (!state) {
|
|
|
|
fprintf(stderr, "Failed to connect to wayland server.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
fprintf(stderr, "Screen rotation not supported.\n");
|
|
|
|
|
|
|
|
struct usb_detector* base_station_detector = 0;
|
|
|
|
if (device_info.basestation_detection_supported) {
|
|
|
|
base_station_detector =
|
|
|
|
create_detector(device_info.basestation_vendor_id,
|
|
|
|
device_info.basestation_product_id);
|
|
|
|
if (!base_station_detector) {
|
|
|
|
fprintf(stderr, "Failed to create basestation detector.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
base_station_detector->on_connected = &on_basestation_connected;
|
|
|
|
base_station_detector->on_disconnected = &on_basestation_disconnected;
|
|
|
|
base_station_detector->has_hotplug_callbacks = true;
|
|
|
|
} else
|
|
|
|
fprintf(stderr, "Base station detection not supported.\n");
|
|
|
|
|
|
|
|
for (;;) { // Main loop that handles the rotation detection.
|
|
|
|
// If screen rotation isn't supported, let's just do nothing.
|
|
|
|
if (!device_info.screen_rotation_supported) continue;
|
2023-07-11 15:55:43 +00:00
|
|
|
|
2023-07-11 19:16:21 +00:00
|
|
|
thrd_sleep(&(struct timespec){0, 10000000UL}, NULL);
|
2023-07-11 15:55:43 +00:00
|
|
|
if (!monitor->data_is_ready) continue;
|
|
|
|
|
2023-07-11 19:02:56 +00:00
|
|
|
if (base_station_detector && base_station_detector->is_connected) {
|
|
|
|
if (last_accel_rotation != ACCEL_ROTATION_0DEG) {
|
|
|
|
miix_wlr_head_set_transform(
|
|
|
|
state,
|
2023-08-27 18:39:55 +00:00
|
|
|
device_info.target_output,
|
|
|
|
device_info.sensor_to_output_rotation[ACCEL_ROTATION_0DEG]);
|
2023-07-11 19:02:56 +00:00
|
|
|
last_accel_rotation = ACCEL_ROTATION_0DEG;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-07-11 15:55:43 +00:00
|
|
|
enum accel_rotation rotation = accel_get_current_rotation(monitor);
|
2023-07-11 19:02:24 +00:00
|
|
|
if (rotation == ACCEL_ROTATION_NO_CHANGE ||
|
|
|
|
rotation == last_accel_rotation)
|
|
|
|
continue;
|
2023-07-11 15:55:43 +00:00
|
|
|
miix_wlr_head_set_transform(
|
2023-08-27 18:39:55 +00:00
|
|
|
state,
|
|
|
|
device_info.target_output,
|
|
|
|
device_info.sensor_to_output_rotation[rotation]);
|
2023-07-11 15:55:43 +00:00
|
|
|
last_accel_rotation = rotation;
|
|
|
|
}
|
|
|
|
|
2023-08-27 18:39:55 +00:00
|
|
|
if (device_info.screen_rotation_supported) {
|
|
|
|
accel_stop_monitor(monitor);
|
|
|
|
miix_wlr_cleanup(state);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (device_info.basestation_detection_supported)
|
|
|
|
destroy_detector(base_station_detector);
|
2023-07-11 15:55:43 +00:00
|
|
|
}
|