~emersion/public-inbox

kanshi: Expose current state via kanshictl v1 APPLIED

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
#1385766 .build.yml success
Sorry for the delay! The patch LGTM, I've pushed it. Thanks!

Might be nice to pretty-print the output in kanshictl. (For programmatic
use, it's better to use a generic varlink tool instead.)
kanshi/patches/.build.yml: SUCCESS in 18s

[Expose current state via kanshictl][0] from [Illia Ostapyshyn][1]

[0]: https://lists.sr.ht/~emersion/public-inbox/patches/56357
[1]: mailto:illia@yshyn.com

✓ #1385766 SUCCESS kanshi/patches/.build.yml https://builds.sr.ht/~emersion/job/1385766
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~emersion/public-inbox/patches/56357/mbox | git am -3
Learn more about email & git

[PATCH kanshi 1/2] ctl: Pass method to reply handler Export this patch

---
 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(&params);
		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

[PATCH kanshi 2/2] ipc: Expose state via fr.emersion.kanshi.Status Export this patch

---
 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(&params);
	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
Sorry for the delay! The patch LGTM, I've pushed it. Thanks!

Might be nice to pretty-print the output in kanshictl. (For programmatic
use, it's better to use a generic varlink tool instead.)
kanshi/patches/.build.yml: SUCCESS in 18s

[Expose current state via kanshictl][0] from [Illia Ostapyshyn][1]

[0]: https://lists.sr.ht/~emersion/public-inbox/patches/56357
[1]: mailto:illia@yshyn.com

✓ #1385766 SUCCESS kanshi/patches/.build.yml https://builds.sr.ht/~emersion/job/1385766