convertablet/daemon/output_manager.c

314 lines
9.1 KiB
C

// 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 "wlr-output-management-unstable-v1.h"
static void head_handle_name(void* data,
struct zwlr_output_head_v1*,
const char* name)
{
struct convertablet_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 convertablet_wlr_state* state = data;
struct convertablet_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 convertablet_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 convertablet_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 convertablet_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 convertablet_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 convertablet_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 convertablet_wlr_state* convertablet_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 convertablet_wlr_state* state =
calloc(1, sizeof(struct convertablet_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** convertablet_wlr_get_head_names(
struct convertablet_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 convertablet_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 convertablet_wlr_head_set_transform(struct convertablet_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 convertablet_wlr_head* head;
struct convertablet_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 convertablet_wlr_state* state)
{
struct convertablet_wlr_head* head;
struct convertablet_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);
}