Compare commits

...

5 commits

Author SHA1 Message Date
e1ed4a7198 daemon: Added support for 'google-caroline' 2023-08-27 21:19:06 +02:00
e48e5a52cf daemon/main: Formating fixup 2023-08-27 21:19:06 +02:00
6b45fb4430 README: Improved README's structure
This commit also adds information about device compatibility!
2023-08-27 21:19:06 +02:00
42e24e5843 daemon: Added support for multiple device configurations 2023-08-27 21:19:06 +02:00
a584f6f358 format: Fixed clang-format to not mess up arrays 2023-08-27 21:19:06 +02:00
4 changed files with 191 additions and 37 deletions

View file

@ -12,8 +12,6 @@ BinPackArguments: false
BinPackParameters: false
AlignArrayOfStructures: Right
AlignArrayOfStructures: Right
AlignConsecutiveAssignments: Consecutive
AlignConsecutiveBitFields: Consecutive
AlignConsecutiveDeclarations: Consecutive

View file

@ -5,9 +5,9 @@ Support for tablet-laptop convertible on wlroots-based compositors.
This project includes both a daemon for handling screen rotation and docking,
and some configuration for other software
## Installation
## Daemon
### Daemon
### Installation
1. Get the code
@ -33,12 +33,19 @@ cd ../
4. Run it to try it out
```
./convertablet
./convertablet generic
```
This will run the daemon in 'generic' mode. This assumes "sane defaults" for
your display's name and motion sensor. It's likely your device isn't using
those.
You can check the list of supported devices with `./convertablet list-devices`,
and load that specific device's config with `./convertablet <device name here>`.
5. Copy it to /usr/local/bin & make it run at startup
### Daemon configuration
### Configuration
You can create scripts at $HOME/.config/convertablet/hooks that will trigger on
events
@ -46,6 +53,24 @@ events
- Basestation disconnected: basestation-disconnected-hook
- Basestation connected: basestation-connected-hook
### Configurations
### Device compatibility
| Product name | Device name | Notes |
|---------------------------------------|-------------------------|----------------------------------------------|
| Lenovo Miix 320-10icr | `lenovo-miix-320-10icr` | |
| Samsung Chromebook Pro XE510C24-K01US | `google-caroline` | Thanks to nothingneko/@jaiden@ordinary.cafe! |
## Using fcitx hooks
If you're using fcitx to get fancy input methods working, on-screen keyboards
will not work, because on wayland, only one program can detect input begining
events. To work around this issue, you can use the `fcitx5-hooks` module I wrote
to run a script when an input field is focused/unfocused. See instructions in
[fcitx5-hooks/](./fcitx5-hooks/).
## 3rd party programs Configurations
Still a work in progress...
In the meantime, you can find some example hooks for the convertablet daemon and
waybar in [configs/](./configs/).

View file

@ -0,0 +1,71 @@
#pragma once
#include <stdint.h>
struct device_information {
char const* const device_name;
bool screen_rotation_supported;
char const* const target_output;
char const* const target_motion_sensor;
enum wl_output_transform const sensor_to_output_rotation[4];
bool basestation_detection_supported;
uint16_t const basestation_vendor_id;
uint16_t const basestation_product_id;
};
static struct device_information DEVICE_INFORMATION_GENERIC = {
.device_name = "generic",
.screen_rotation_supported = true,
.target_output = "eDP-1",
.target_motion_sensor = "/sys/bus/iio/devices/iio:device0",
.sensor_to_output_rotation =
{
[ACCEL_ROTATION_0DEG] = WL_OUTPUT_TRANSFORM_NORMAL,
[ACCEL_ROTATION_90DEG] = WL_OUTPUT_TRANSFORM_90,
[ACCEL_ROTATION_180DEG] = WL_OUTPUT_TRANSFORM_180,
[ACCEL_ROTATION_270DEG] = WL_OUTPUT_TRANSFORM_270,
},
.basestation_detection_supported = false,
.basestation_vendor_id = 0,
.basestation_product_id = 0,
};
static struct device_information DEVICE_INFOS[] = {
{
// Lenovo Miix 320-10icr
// https://support.lenovo.com/us/en/solutions/pd104871-product-overview-miix-320-10icr
.device_name = "lenovo-miix-320-10icr",
.screen_rotation_supported = true,
.target_output = "DSI-1",
.target_motion_sensor = "/sys/bus/iio/devices/iio:device0",
.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,
},
.basestation_detection_supported = true,
.basestation_vendor_id = 0x048d,
.basestation_product_id = 0x8911,
},
{
// Samsung Chromebook Pro
// https://www.samsung.com/us/computing/chromebooks/12-14/samsung-chromebook-pro-xe510c24-k01us/
.device_name = "google-caroline",
.screen_rotation_supported = true,
.target_output = "eDP-1",
.target_motion_sensor = "/sys/bus/iio/devices/iio:device1",
.sensor_to_output_rotation =
{
[ACCEL_ROTATION_0DEG] = WL_OUTPUT_TRANSFORM_NORAML,
[ACCEL_ROTATION_90DEG] = WL_OUTPUT_TRANSFORM_270,
[ACCEL_ROTATION_180DEG] = WL_OUTPUT_TRANSFORM_180,
[ACCEL_ROTATION_270DEG] = WL_OUTPUT_TRANSFORM_90,
},
.basestation_detection_supported = false,
.basestation_vendor_id = 0,
.basestation_product_id = 0,
},
};

View file

@ -4,34 +4,48 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libusb-1.0/libusb.h>
#include "accel_monitor.h"
#include "device_information.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 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 char const* const DEFAULT_OUTPUT = "DSI-1";
static char const* const DEFAULT_MOTION_SENSOR =
"/sys/bus/iio/devices/iio:device0";
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;
}
static uint16_t const BASESTATION_VENDOR_ID = 0x048d;
static uint16_t const BASESTATION_PRODUCT_ID = 0x8911;
fprintf(stderr,
"No matching configuration for '%s'. Using the generic "
"configuration.\n",
device_name);
return DEVICE_INFORMATION_GENERIC;
}
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);
asprintf(
&path, "%s/convertablet/hooks/%s-hook", xdg_config_dir, hook_name);
else
asprintf(&path,
"%s/.config/convertablet/hooks/%s-hook",
@ -99,25 +113,65 @@ static void on_basestation_disconnected()
static enum accel_rotation last_accel_rotation = ACCEL_ROTATION_NO_CHANGE;
int main(int, char**)
int main(int argc, char** argv)
{
struct accel_monitor* monitor = accel_start_monitor(DEFAULT_MOTION_SENSOR);
if (!monitor) {
fprintf(stderr, "Failed to start iio motion monitoring\n");
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]);
return -1;
}
struct usb_detector* base_station_detector =
create_detector(BASESTATION_VENDOR_ID, BASESTATION_PRODUCT_ID);
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;
}
base_station_detector->on_connected = &on_basestation_connected;
base_station_detector->on_disconnected = &on_basestation_disconnected;
base_station_detector->has_hotplug_callbacks = true;
struct device_information device_info = get_device_info_for_name(argv[1]);
struct miix_wlr_state* state = miix_wlr_init();
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;
for (;;) {
thrd_sleep(&(struct timespec){0, 10000000UL}, NULL);
if (!monitor->data_is_ready) continue;
@ -125,8 +179,8 @@ int main(int, char**)
if (last_accel_rotation != ACCEL_ROTATION_0DEG) {
miix_wlr_head_set_transform(
state,
DEFAULT_OUTPUT,
SENSOR_TO_OUTPUT_ROTATION[ACCEL_ROTATION_0DEG]);
device_info.target_output,
device_info.sensor_to_output_rotation[ACCEL_ROTATION_0DEG]);
last_accel_rotation = ACCEL_ROTATION_0DEG;
}
continue;
@ -137,11 +191,17 @@ int main(int, char**)
rotation == last_accel_rotation)
continue;
miix_wlr_head_set_transform(
state, DEFAULT_OUTPUT, SENSOR_TO_OUTPUT_ROTATION[rotation]);
state,
device_info.target_output,
device_info.sensor_to_output_rotation[rotation]);
last_accel_rotation = rotation;
}
accel_stop_monitor(monitor);
destroy_detector(base_station_detector);
miix_wlr_cleanup(state);
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);
}