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
|
- meson
|
||||||
- wayland
|
- wayland
|
||||||
- scdoc
|
- scdoc
|
||||||
|
- libvarlink
|
||||||
sources:
|
sources:
|
||||||
- https://github.com/emersion/kanshi
|
- https://github.com/emersion/kanshi
|
||||||
tasks:
|
tasks:
|
||||||
|
@ -15,6 +15,7 @@ Dependencies:
|
|||||||
|
|
||||||
* wayland-client
|
* wayland-client
|
||||||
* scdoc (optional, for man pages)
|
* scdoc (optional, for man pages)
|
||||||
|
* libvarlink (optional, for remote control functionality)
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
meson build
|
meson build
|
||||||
|
22
event-loop.c
22
event-loop.c
@ -10,6 +10,10 @@
|
|||||||
|
|
||||||
#include "kanshi.h"
|
#include "kanshi.h"
|
||||||
|
|
||||||
|
#if KANSHI_HAS_VARLINK
|
||||||
|
#include <varlink.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
static int set_pipe_flags(int fd) {
|
static int set_pipe_flags(int fd) {
|
||||||
int flags = fcntl(fd, F_GETFL);
|
int flags = fcntl(fd, F_GETFL);
|
||||||
if (flags == -1) {
|
if (flags == -1) {
|
||||||
@ -45,6 +49,9 @@ static void signal_handler(int signum) {
|
|||||||
enum readfds_type {
|
enum readfds_type {
|
||||||
FD_WAYLAND,
|
FD_WAYLAND,
|
||||||
FD_SIGNAL,
|
FD_SIGNAL,
|
||||||
|
#if KANSHI_HAS_VARLINK
|
||||||
|
FD_VARLINK,
|
||||||
|
#endif
|
||||||
FD_COUNT,
|
FD_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -74,6 +81,10 @@ int kanshi_main_loop(struct kanshi_state *state) {
|
|||||||
readfds[FD_WAYLAND].events = POLLIN;
|
readfds[FD_WAYLAND].events = POLLIN;
|
||||||
readfds[FD_SIGNAL].fd = signal_pipefds[0];
|
readfds[FD_SIGNAL].fd = signal_pipefds[0];
|
||||||
readfds[FD_SIGNAL].events = POLLIN;
|
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 (state->running) {
|
||||||
while (wl_display_prepare_read(state->display) != 0) {
|
while (wl_display_prepare_read(state->display) != 0) {
|
||||||
@ -107,6 +118,17 @@ int kanshi_main_loop(struct kanshi_state *state) {
|
|||||||
return EXIT_FAILURE;
|
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) {
|
if (readfds[FD_SIGNAL].revents & POLLIN) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int signum;
|
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;
|
bool running;
|
||||||
struct wl_display *display;
|
struct wl_display *display;
|
||||||
struct zwlr_output_manager_v1 *output_manager;
|
struct zwlr_output_manager_v1 *output_manager;
|
||||||
|
#if KANSHI_HAS_VARLINK
|
||||||
|
struct VarlinkService *service;
|
||||||
|
#endif
|
||||||
|
|
||||||
struct kanshi_config *config;
|
struct kanshi_config *config;
|
||||||
const char *config_arg;
|
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 "config.h"
|
||||||
#include "kanshi.h"
|
#include "kanshi.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "ipc.h"
|
||||||
#include "wlr-output-management-unstable-v1-client-protocol.h"
|
#include "wlr-output-management-unstable-v1-client-protocol.h"
|
||||||
|
|
||||||
#define HEADS_MAX 64
|
#define HEADS_MAX 64
|
||||||
@ -577,6 +578,12 @@ int main(int argc, char *argv[]) {
|
|||||||
.config_arg = config_arg,
|
.config_arg = config_arg,
|
||||||
};
|
};
|
||||||
int ret = EXIT_SUCCESS;
|
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);
|
wl_list_init(&state.heads);
|
||||||
|
|
||||||
struct wl_registry *registry = wl_display_get_registry(display);
|
struct wl_registry *registry = wl_display_get_registry(display);
|
||||||
@ -594,6 +601,9 @@ int main(int argc, char *argv[]) {
|
|||||||
ret = kanshi_main_loop(&state);
|
ret = kanshi_main_loop(&state);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
#if KANSHI_HAS_VARLINK
|
||||||
|
kanshi_free_ipc(&state);
|
||||||
|
#endif
|
||||||
wl_display_disconnect(display);
|
wl_display_disconnect(display);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
31
meson.build
31
meson.build
@ -35,18 +35,37 @@ add_project_arguments(cc.get_supported_arguments([
|
|||||||
]), language: 'c')
|
]), language: 'c')
|
||||||
|
|
||||||
wayland_client = dependency('wayland-client')
|
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')
|
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(
|
executable(
|
||||||
meson.project_name(),
|
meson.project_name(),
|
||||||
files(
|
kanshi_srcs,
|
||||||
'main.c',
|
|
||||||
'parser.c',
|
|
||||||
'event-loop.c',
|
|
||||||
),
|
|
||||||
include_directories: include_directories('include'),
|
include_directories: include_directories('include'),
|
||||||
dependencies: [wayland_client, client_protos],
|
dependencies: kanshi_deps,
|
||||||
install: true,
|
install: true,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1 +1,2 @@
|
|||||||
option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages')
|
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