1
0
mirror of https://github.com/emersion/kanshi synced 2024-09-15 00:20:36 +02:00

Add optional varlink interface.

We don't want to fallback to libwayland's defaults, so WAYLAND_DISPLAY
needs to be set in env. Since IPC in the future is going to use
XDG_RUNTIME_DIR, we also require it.

Because these functions will be used in other parts of the code as well,
we rework the build system slightly to accommodate it.

Co-authored-by: Érico Nogueira <erico.erc@gmail.com>
This commit is contained in:
Jason Francis 2021-07-07 00:13:58 -03:00 committed by Simon Ser
parent 123a2f43f3
commit afab6397ed
10 changed files with 166 additions and 6 deletions

View File

@ -3,6 +3,7 @@ packages:
- meson
- wayland
- scdoc
- libvarlink
sources:
- https://github.com/emersion/kanshi
tasks:

View File

@ -15,6 +15,7 @@ Dependencies:
* wayland-client
* scdoc (optional, for man pages)
* libvarlink (optional, for remote control functionality)
```sh
meson build

View File

@ -10,6 +10,10 @@
#include "kanshi.h"
#if KANSHI_HAS_VARLINK
#include <varlink.h>
#endif
static int set_pipe_flags(int fd) {
int flags = fcntl(fd, F_GETFL);
if (flags == -1) {
@ -45,6 +49,9 @@ static void signal_handler(int signum) {
enum readfds_type {
FD_WAYLAND,
FD_SIGNAL,
#if KANSHI_HAS_VARLINK
FD_VARLINK,
#endif
FD_COUNT,
};
@ -74,6 +81,10 @@ int kanshi_main_loop(struct kanshi_state *state) {
readfds[FD_WAYLAND].events = POLLIN;
readfds[FD_SIGNAL].fd = signal_pipefds[0];
readfds[FD_SIGNAL].events = POLLIN;
#if KANSHI_HAS_VARLINK
readfds[FD_VARLINK].fd = varlink_service_get_fd(state->service);
readfds[FD_VARLINK].events = POLLIN;
#endif
while (state->running) {
while (wl_display_prepare_read(state->display) != 0) {
@ -107,6 +118,17 @@ int kanshi_main_loop(struct kanshi_state *state) {
return EXIT_FAILURE;
}
#if KANSHI_HAS_VARLINK
if (readfds[FD_VARLINK].revents & POLLIN) {
long result = varlink_service_process_events(state->service);
if (result != 0) {
fprintf(stderr, "varlink_service_process_events failed: %s\n",
varlink_error_string(-result));
return EXIT_FAILURE;
}
}
#endif
if (readfds[FD_SIGNAL].revents & POLLIN) {
for (;;) {
int signum;

13
include/ipc.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef KANSHI_IPC_H
#define KANSHI_IPC_H
#include <stdbool.h>
#include "kanshi.h"
int kanshi_init_ipc(struct kanshi_state *state);
void kanshi_free_ipc(struct kanshi_state *state);
int get_ipc_address(char *address, size_t size);
#endif

View File

@ -43,6 +43,9 @@ struct kanshi_state {
bool running;
struct wl_display *display;
struct zwlr_output_manager_v1 *output_manager;
#if KANSHI_HAS_VARLINK
struct VarlinkService *service;
#endif
struct kanshi_config *config;
const char *config_arg;

21
ipc-addr.c Normal file
View File

@ -0,0 +1,21 @@
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include "ipc.h"
int get_ipc_address(char *address, size_t size) {
const char *wayland_display = getenv("WAYLAND_DISPLAY");
const char *xdg_runtime_dir = getenv("XDG_RUNTIME_DIR");
if (!wayland_display || !wayland_display[0]) {
fprintf(stderr, "WAYLAND_DISPLAY is not set\n");
return -1;
}
if (!xdg_runtime_dir || !xdg_runtime_dir[0]) {
fprintf(stderr, "XDG_RUNTIME_DIR is not set\n");
return -1;
}
return snprintf(address, size, "unix:%s/fr.emersion.kanshi.%s",
xdg_runtime_dir, wayland_display);
}

69
ipc.c Normal file
View File

@ -0,0 +1,69 @@
#define _POSIX_C_SOURCE 200809L
#include <limits.h>
#include <stdio.h>
#include <varlink.h>
#include "kanshi.h"
#include "ipc.h"
static void reload_config_done(void *data, struct wl_callback *callback,
uint32_t serial) {
VarlinkCall *call = data;
varlink_call_reply(call, NULL, 0);
wl_callback_destroy(callback);
}
static struct wl_callback_listener reload_config_listener = {
.done = reload_config_done
};
static long handle_reload(VarlinkService *service, VarlinkCall *call,
VarlinkObject *parameters, uint64_t flags, void *userdata) {
struct kanshi_state *state = userdata;
kanshi_reload_config(state);
// this only ensures that the server has received the configuration request,
// the server is free to wait an arbitrary amount of time before applying the configuration
// TODO: use the wlr-output-management event instead
struct wl_callback *callback = wl_display_sync(state->display);
wl_callback_add_listener(callback, &reload_config_listener, call);
return 0;
}
int kanshi_init_ipc(struct kanshi_state *state) {
VarlinkService *service;
char address[PATH_MAX];
if (get_ipc_address(address, sizeof(address)) < 0) {
return -1;
}
if (varlink_service_new(&service,
"emersion", "kanshi", KANSHI_VERSION, "https://wayland.emersion.fr/kanshi/",
address, -1) < 0) {
fprintf(stderr, "Couldn't start kanshi varlink service at %s.\n"
"Is the kanshi daemon already running?\n", address);
return -1;
}
const char *interface = "interface fr.emersion.kanshi\n"
"method Reload() -> ()";
long result = varlink_service_add_interface(service, interface,
"Reload", handle_reload, state,
NULL);
if (result != 0) {
fprintf(stderr, "varlink_service_add_interface failed: %s\n",
varlink_error_string(-result));
varlink_service_free(service);
return -1;
}
state->service = service;
return 0;
}
void kanshi_free_ipc(struct kanshi_state *state) {
if (state->service) {
varlink_service_free(state->service);
state->service = NULL;
}
}

10
main.c
View File

@ -15,6 +15,7 @@
#include "config.h"
#include "kanshi.h"
#include "parser.h"
#include "ipc.h"
#include "wlr-output-management-unstable-v1-client-protocol.h"
#define HEADS_MAX 64
@ -577,6 +578,12 @@ int main(int argc, char *argv[]) {
.config_arg = config_arg,
};
int ret = EXIT_SUCCESS;
#if KANSHI_HAS_VARLINK
if (kanshi_init_ipc(&state) != 0) {
ret = EXIT_FAILURE;
goto done;
}
#endif
wl_list_init(&state.heads);
struct wl_registry *registry = wl_display_get_registry(display);
@ -594,6 +601,9 @@ int main(int argc, char *argv[]) {
ret = kanshi_main_loop(&state);
done:
#if KANSHI_HAS_VARLINK
kanshi_free_ipc(&state);
#endif
wl_display_disconnect(display);
return ret;

View File

@ -35,18 +35,37 @@ add_project_arguments(cc.get_supported_arguments([
]), language: 'c')
wayland_client = dependency('wayland-client')
varlink = dependency('libvarlink', required: get_option('ipc'))
add_project_arguments([
'-DKANSHI_VERSION="@0@"'.format(meson.project_version()),
'-DKANSHI_HAS_VARLINK=@0@'.format(varlink.found().to_int()),
], language: 'c')
subdir('protocol')
kanshi_deps = [
wayland_client,
client_protos,
]
kanshi_srcs = [
'event-loop.c',
'main.c',
'parser.c',
'ipc-addr.c',
]
if varlink.found()
kanshi_deps += varlink
kanshi_srcs += ['ipc.c', 'ipc-addr.c']
endif
executable(
meson.project_name(),
files(
'main.c',
'parser.c',
'event-loop.c',
),
kanshi_srcs,
include_directories: include_directories('include'),
dependencies: [wayland_client, client_protos],
dependencies: kanshi_deps,
install: true,
)

View File

@ -1 +1,2 @@
option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages')
option('ipc', type: 'feature', value: 'auto', description: 'Enable remote control with varlink')