This patch series adds a new status command to kanshictl, which prints
out the current kanshi state to the standart output as a JSON string.
The feature is motivated by the idea of coupling power management to
the current kanshi profile via external programs (github#54 [1]).
However, kanshi is currently missing a posibility to query the current
profile.
The output is currently limited to {current,pending}_profile. If more
use cases arise in the future, the command can be extended to expose
more fields of the kanshi_state structure.
[1] https://github.com/emersion/kanshi/issues/54
Illia Ostapyshyn (2):
ctl: Pass method to reply handler
ipc: Expose state via fr.emersion.kanshi.Status
ctl.c | 34 +++++++++++++++++++++++++++-------
ipc.c | 31 +++++++++++++++++++++++++++++++
2 files changed, 58 insertions(+), 7 deletions(-)
--
2.47.0
---
ctl.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/ctl.c b/ctl.c
index e5ca870..ee06728 100644
--- a/ctl.c
+++ b/ctl.c
@@ -89,9 +89,10 @@ int main(int argc, char *argv[]) {
const char *command = argv[1];
long ret;
+ char *method = NULL;
+ VarlinkObject *params = NULL;
if (strcmp(command, "reload") == 0) {
- ret = varlink_connection_call(connection,
- "fr.emersion.kanshi.Reload", NULL, 0, handle_call_done, NULL);
+ method = "fr.emersion.kanshi.Reload";
} else if (strcmp(command, "switch") == 0) {
if (argc < 3) {
usage();
@@ -99,17 +100,20 @@ int main(int argc, char *argv[]) {
}
const char *profile = argv[2];
- VarlinkObject *params = NULL;
varlink_object_new(¶ms);
varlink_object_set_string(params, "profile", profile);
- ret = varlink_connection_call(connection,
- "fr.emersion.kanshi.Switch", params, 0, handle_call_done, NULL);
- varlink_object_unref(params);
+ method = "fr.emersion.kanshi.Switch";
} else {
fprintf(stderr, "invalid command: %s\n", argv[1]);
usage();
return EXIT_FAILURE;
}
+
+ ret = varlink_connection_call(connection, method, params, 0,
+ handle_call_done, method);
+ if (params)
+ varlink_object_unref(params);
+
if (ret != 0) {
fprintf(stderr, "varlink_connection_call failed: %s\n",
varlink_error_string(-ret));
--
2.47.0
---
ctl.c | 18 +++++++++++++++++-
ipc.c | 31 +++++++++++++++++++++++++++++++
2 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/ctl.c b/ctl.c
index ee06728..e0bb3b3 100644
--- a/ctl.c
+++ b/ctl.c
@@ -14,11 +14,13 @@ static void usage(void) {
"\n"
"Commands:\n"
" reload Reload the configuration file\n"
- " switch <profile> Switch to another profile\n");
+ " switch <profile> Switch to another profile\n"
+ " status Output current state as JSON\n");
}
static long handle_call_done(VarlinkConnection *connection, const char *error,
VarlinkObject *parameters, uint64_t flags, void *userdata) {
+ char *method = userdata;
if (error != NULL) {
if (strcmp(error, "fr.emersion.kanshi.ProfileNotFound") == 0) {
fprintf(stderr, "Profile not found\n");
@@ -31,6 +33,18 @@ static long handle_call_done(VarlinkConnection *connection, const char *error,
}
exit(EXIT_FAILURE);
}
+
+ if (strcmp(method, "fr.emersion.kanshi.Status") == 0) {
+ char *json = NULL;
+ long ret = varlink_object_to_json(parameters, &json);
+ if (ret < 0) {
+ fprintf(stderr, "varlink_object_to_json failed: %s\n", varlink_error_string(ret));
+ exit(EXIT_FAILURE);
+ }
+ puts(json);
+ free(json);
+ }
+
return varlink_connection_close(connection);
}
@@ -93,6 +107,8 @@ int main(int argc, char *argv[]) {
VarlinkObject *params = NULL;
if (strcmp(command, "reload") == 0) {
method = "fr.emersion.kanshi.Reload";
+ } else if (strcmp(command, "status") == 0) {
+ method = "fr.emersion.kanshi.Status";
} else if (strcmp(command, "switch") == 0) {
if (argc < 3) {
usage();
diff --git a/ipc.c b/ipc.c
index fe61f63..960184d 100644
--- a/ipc.c
+++ b/ipc.c
@@ -28,6 +28,35 @@ static void apply_profile_done(void *data, bool success) {
}
}
+static long handle_status(VarlinkService *service, VarlinkCall *call,
+ VarlinkObject *parameters, uint64_t flags, void *userdata) {
+ struct kanshi_state *state = userdata;
+ VarlinkObject *params = NULL;
+ long ret = varlink_object_new(¶ms);
+ if (ret < 0)
+ return ret;
+
+ if (state->current_profile) {
+ ret = varlink_object_set_string(params, "current_profile",
+ state->current_profile->name);
+ if (ret < 0)
+ goto out_free;
+ }
+
+ if (state->pending_profile) {
+ ret = varlink_object_set_string(params, "pending_profile",
+ state->pending_profile->name);
+ if (ret < 0)
+ goto out_free;
+ }
+
+ ret = varlink_call_reply(call, params, 0);
+
+out_free:
+ varlink_object_unref(params);
+ return ret;
+}
+
static long handle_reload(VarlinkService *service, VarlinkCall *call,
VarlinkObject *parameters, uint64_t flags, void *userdata) {
struct kanshi_state *state = userdata;
@@ -104,6 +133,7 @@ int kanshi_init_ipc(struct kanshi_state *state, int listen_fd) {
const char *interface = "interface fr.emersion.kanshi\n"
"method Reload() -> ()\n"
"method Switch(profile: string) -> ()\n"
+ "method Status() -> (current_profile: ?string, pending_profile: ?string)\n"
"error ProfileNotFound()\n"
"error ProfileNotMatched()\n"
"error ProfileNotApplied()\n";
@@ -111,6 +141,7 @@ int kanshi_init_ipc(struct kanshi_state *state, int listen_fd) {
long result = varlink_service_add_interface(service, interface,
"Reload", handle_reload, state,
"Switch", handle_switch, state,
+ "Status", handle_status, state,
NULL);
if (result != 0) {
fprintf(stderr, "varlink_service_add_interface failed: %s\n",
--
2.47.0