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}