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 { "close", cmd_close, 0, false },
34 { "workspace", cmd_workspace, 1, false },
35 { "move_workspace", cmd_move_workspace, 1, false },
36 { "get_geometry", cmd_get_geometry, 0, false },
37 { "get_pid", cmd_get_pid, 0, false },
38 { "get_title", cmd_get_title, 0, false },
39 { "get_app_id", cmd_get_app_id, 0, false },
40 { "get_focus", cmd_get_focus, 0, false },
41 { "get_workspace", cmd_get_workspace, 0, false },
42 { "get_screen_geometry", cmd_get_screen_geometry, 0, false },
43 { "get_cursor_position", cmd_get_cursor_position, 0, false },
44 { "list_windows", cmd_list_windows, 0, false },
45 { "bind", cmd_bind, 2, false },
46 { "unbind", cmd_unbind, 1, false },
47 { "modkey", cmd_modkey, 1, true },
48 { "inner_focus_color", cmd_inner_focus_color, 1, true },
49 { "inner_unfocus_color", cmd_inner_unfocus_color, 1, true },
50 { "outer_focus_color", cmd_outer_focus_color, 1, true },
51 { "outer_unfocus_color", cmd_outer_unfocus_color, 1, true },
52 { "inner_border_width", cmd_inner_border_width, 1, true },
53 { "outer_border_width", cmd_outer_border_width, 1, true },
54 { "title_format", cmd_title_format, 1, true },
55 { "set_decor", cmd_set_decor, 1, true },
56 { "quit", cmd_quit, 0, false }
57};
58
59static int
60ipc_msg(const struct command *cmd, int argc, char **argv) {
61 char buf[512];
62 size_t n = 0;
63
64 struct sockaddr_un addr = {0};
65 addr.sun_family = AF_UNIX;
66 strncpy(addr.sun_path, SOCK_PATH, sizeof(addr.sun_path) - 1);
67
68 int fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
69 if (fd < 0) {
70 perror("couldn't open IPC socket");
71 return 1;
72 }
73
74 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
75 perror("couldn't connect to IPC socket");
76 close(fd);
77 return 1;
78 }
79
80 if (cmd->config) {
81 int r = snprintf(buf + n, sizeof(buf) - n, "%d %d", cmd_config, cmd->id);
82 n += r;
83 } else {
84 int r = snprintf(buf + n, sizeof(buf) - n, "%d", cmd->id);
85 n += r;
86 }
87
88 for (int i = 2; i < argc; i++) {
89 int r = snprintf(buf + n, sizeof(buf) - n, " %s", argv[i]);
90 n += r;
91 }
92
93 buf[n] = '\0';
94 if (write(fd, buf, strlen(buf)) < 0) {
95 perror("couldn't send IPC message");
96 close(fd);
97 return 1;
98 }
99
100 char buf2[512];
101 if ((n = read(fd, buf2, sizeof(buf2) - 1)) <= 0) {
102 perror("couldn't read from IPC socket");
103 close(fd);
104 return 1;
105 }
106 buf2[n] = '\0';
107
108 char *ans;
109 long ret = strtol(buf2, &ans, 10);
110 if (ans == buf2)
111 ret = 0;
112
113 while (*ans == ' ')
114 ans++;
115
116 if (strcmp(ans, "") != 0) {
117 if (ret == 0)
118 fprintf(stderr, "%s", ans);
119 else
120 printf("%s", ans);
121 }
122 return (int)ret;
123}
124
125int
126main(int argc, char **argv) {
127 if (argc < 2) {
128 fprintf(stderr, "Usage: howlc cmd [args...]\n");
129 return 1;
130 }
131
132 for (int i = 0; i < (int)(sizeof commands / sizeof commands[0]); i++) {
133 if (strcmp(argv[1], commands[i].name) == 0) {
134 if (argc - 2 < commands[i].argc) {
135 fprintf(stderr, "Wrong number of arguments for %s (need %d)\n", commands[i].name, commands[i].argc);
136 return 1;
137 }
138 return ipc_msg(&commands[i], argc, argv);
139 }
140 }
141
142 fprintf(stderr, "No such command: %s\n", argv[1]);
143 return 1;
144}