mirror of
https://github.com/emersion/kanshi
synced 2024-09-18 09:51: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:
parent
123a2f43f3
commit
afab6397ed
@ -3,6 +3,7 @@ packages:
|
||||
- meson
|
||||
- wayland
|
||||
- scdoc
|
||||
- libvarlink
|
||||
sources:
|
||||
- https://github.com/emersion/kanshi
|
||||
tasks:
|
||||
|
@ -15,6 +15,7 @@ Dependencies:
|
||||
|
||||
* wayland-client
|
||||
* scdoc (optional, for man pages)
|
||||
* libvarlink (optional, for remote control functionality)
|
||||
|
||||
```sh
|
||||
meson build
|
||||
|
22
event-loop.c
22
event-loop.c
@ -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
13
include/ipc.h
Normal 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
|
@ -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
21
ipc-addr.c
Normal 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
69
ipc.c
Normal 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
10
main.c
@ -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;
|
||||
|
31
meson.build
31
meson.build
@ -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,
|
||||
)
|
||||
|
||||
|
@ -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')
|
||||
|
Loading…
Reference in New Issue
Block a user