main wf/howl / src / client.c
  1#include <stdio.h>
  2#include <stdlib.h>
  3#include <string.h>
  4#include <unistd.h>
  5#include <sys/socket.h>
  6#include <sys/un.h>
  7
  8#include "howl.h"
  9#include "types.h"
 10#include "ipc.h"
 11
 12struct command {
 13	const char *name;
 14	enum cmd id;
 15	int argc;
 16	bool config;
 17};
 18
 19static const struct command commands[] = {
 20	{ "move",                cmd_move,                2, false },
 21	{ "move_absolute",       cmd_move_absolute,       2, false },
 22	{ "resize",              cmd_resize,              2, false },
 23	{ "resize_absolute",     cmd_resize_absolute,     2, false },
 24	{ "teleport",            cmd_teleport,            4, false },
 25	{ "center",              cmd_center,              0, false },
 26	{ "fullscreen",          cmd_fullscreen,          0, false },
 27	{ "hide",                cmd_hide,                0, false },
 28	{ "show",                cmd_show,                0, false },
 29	{ "lower",               cmd_lower,               0, false },
 30	{ "raise",               cmd_raise,               0, false },
 31	{ "focus_prev",          cmd_focus_prev,          0, false },
 32	{ "focus_next",          cmd_focus_next,          0, false },
 33	{ "unfocus",             cmd_unfocus,             0, false },
 34	{ "close",               cmd_close,               0, false },
 35	{ "workspace",           cmd_workspace,           1, false },
 36	{ "move_workspace",      cmd_move_workspace,      1, false },
 37	{ "get_geometry",        cmd_get_geometry,        0, false },
 38	{ "get_pid",             cmd_get_pid,             0, false },
 39	{ "get_title",           cmd_get_title,           0, false },
 40	{ "get_app_id",          cmd_get_app_id,          0, false },
 41	{ "get_focus",           cmd_get_focus,           0, false },
 42	{ "get_workspace",       cmd_get_workspace,       0, false },
 43	{ "get_screen_geometry", cmd_get_screen_geometry, 0, false },
 44	{ "get_cursor_position", cmd_get_cursor_position, 0, false },
 45	{ "list_windows",        cmd_list_windows,        0, false },
 46	{ "bind",                cmd_bind,                2, false },
 47	{ "unbind",              cmd_unbind,              1, false },
 48	{ "modkey",              cmd_modkey,              1, true  },
 49	{ "inner_focus_color",   cmd_inner_focus_color,   1, true  },
 50	{ "inner_unfocus_color", cmd_inner_unfocus_color, 1, true  },
 51	{ "outer_focus_color",   cmd_outer_focus_color,   1, true  },
 52	{ "outer_unfocus_color", cmd_outer_unfocus_color, 1, true  },
 53	{ "inner_border_width",  cmd_inner_border_width,  1, true  },
 54	{ "outer_border_width",  cmd_outer_border_width,  1, true  },
 55	{ "title_format",        cmd_title_format,        1, true  },
 56	{ "set_decor",           cmd_set_decor,           1, true  },
 57	{ "quit",                cmd_quit,                0, false }
 58};
 59
 60static int
 61ipc_msg(const struct command *cmd, int argc, char **argv) {
 62	char buf[512];
 63	size_t n = 0;
 64
 65	struct sockaddr_un addr = {0};
 66	addr.sun_family = AF_UNIX;
 67	strncpy(addr.sun_path, SOCK_PATH, sizeof(addr.sun_path) - 1);
 68
 69	int fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
 70	if (fd < 0) {
 71		perror("couldn't open IPC socket");
 72		return 1;
 73	}
 74
 75	if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
 76		perror("couldn't connect to IPC socket");
 77		close(fd);
 78		return 1;
 79	}
 80
 81	if (cmd->config) {
 82		int r = snprintf(buf + n, sizeof(buf) - n, "%d %d", cmd_config, cmd->id);
 83		n += r;
 84	} else {
 85		int r = snprintf(buf + n, sizeof(buf) - n, "%d", cmd->id);
 86		n += r;
 87	}
 88
 89	for (int i = 2; i < argc; i++) {
 90		int r = snprintf(buf + n, sizeof(buf) - n, " %s", argv[i]);
 91		n += r;
 92	}
 93
 94	buf[n] = '\0';
 95	if (write(fd, buf, strlen(buf)) < 0) {
 96		perror("couldn't send IPC message");
 97		close(fd);
 98		return 1;
 99	}
100
101	char buf2[512];
102	if ((n = read(fd, buf2, sizeof(buf2) - 1)) <= 0) {
103		perror("couldn't read from IPC socket");
104		close(fd);
105		return 1;
106	}
107	buf2[n] = '\0';
108
109	char *ans;
110	long ret = strtol(buf2, &ans, 10);
111	if (ans == buf2)
112		ret = 0;
113
114	while (*ans == ' ')
115		ans++;
116
117	if (strcmp(ans, "") != 0) {
118		if (ret == 0)
119			fprintf(stderr, "%s", ans);
120		else
121			printf("%s", ans);
122	}
123	return (int)ret;
124}
125
126int
127main(int argc, char **argv) {
128	if (argc < 2) {
129		fprintf(stderr, "Usage: howlc cmd [args...]\n");
130		return 1;
131	}
132
133	for (int i = 0; i < (int)(sizeof commands / sizeof commands[0]); i++) {
134		if (strcmp(argv[1], commands[i].name) == 0) {
135			if (argc - 2 < commands[i].argc) {
136				fprintf(stderr, "Wrong number of arguments for %s (need %d)\n", commands[i].name, commands[i].argc);
137				return 1;
138			}
139			return ipc_msg(&commands[i], argc, argv);
140		}
141	}
142	
143	fprintf(stderr, "No such command: %s\n", argv[1]);
144	return 1;
145}