]> git.sur5r.net Git - i3/i3/blob - i3-msg/main.c
Add i3-msg, a sample implementation and hopefully useful utility
[i3/i3] / i3-msg / main.c
1 /*
2  * vim:ts=8:expandtab
3  *
4  * i3 - an improved dynamic tiling window manager
5  *
6  * © 2009 Michael Stapelberg and contributors
7  *
8  * See file LICENSE for license information.
9  *
10  * i3-msg/main.c: Utility which sends messages to a running i3-instance using
11  * IPC via UNIX domain sockets.
12  *
13  * This serves as an example for how to send your own messages to i3.
14  * Additionally, it’s even useful sometimes :-).
15  *
16  */
17 #include <ev.h>
18 #include <stdio.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <sys/un.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <err.h>
27 #include <stdint.h>
28 #include <getopt.h>
29
30 static void ipc_send_message(int sockfd, uint32_t message_size,
31                              uint32_t message_type, uint8_t *payload) {
32         int buffer_size = strlen("i3-ipc") + sizeof(uint32_t) + sizeof(uint32_t) + message_size;
33         char msg[buffer_size];
34         char *walk = msg;
35
36         strcpy(walk, "i3-ipc");
37         walk += strlen("i3-ipc");
38         memcpy(walk, &message_size, sizeof(uint32_t));
39         walk += sizeof(uint32_t);
40         memcpy(walk, &message_type, sizeof(uint32_t));
41         walk += sizeof(uint32_t);
42         memcpy(walk, payload, message_size);
43
44         int sent_bytes = 0;
45         int bytes_to_go = buffer_size;
46         while (sent_bytes < bytes_to_go) {
47                 int n = write(sockfd, msg + sent_bytes, bytes_to_go);
48                 if (n == -1)
49                         err(EXIT_FAILURE, "write() failed");
50
51                 sent_bytes += n;
52                 bytes_to_go -= n;
53         }
54 }
55
56 int main(int argc, char *argv[]) {
57         char *socket_path = "/tmp/i3-ipc.sock";
58         int o, option_index = 0;
59
60         static struct option long_options[] = {
61                 {"socket", required_argument, 0, 's'},
62                 {"type", required_argument, 0, 't'},
63                 {"version", no_argument, 0, 'v'},
64                 {"help", no_argument, 0, 'h'},
65                 {0, 0, 0, 0}
66         };
67
68         char *options_string = "s:t:vh";
69
70         while ((o = getopt_long(argc, argv, options_string, long_options, &option_index)) != -1) {
71                 if (o == 's') {
72                         socket_path = strdup(optarg);
73                         break;
74                 } else if (o == 't') {
75                         printf("currently only commands are implemented\n");
76                 } else if (o == 'v') {
77                         printf("i3-msg " I3_VERSION);
78                         return 0;
79                 } else if (o == 'h') {
80                         printf("i3-msg " I3_VERSION);
81                         printf("i3-msg [-s <socket>] [-t <type>] <message>\n");
82                         return 0;
83                 }
84         }
85
86         if (optind >= argc) {
87                 fprintf(stderr, "Error: missing message\n");
88                 fprintf(stderr, "i3-msg [-s <socket>] [-t <type>] <message>\n");
89                 return 1;
90         }
91
92         int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);
93         struct sockaddr_un addr;
94         memset(&addr, 0, sizeof(struct sockaddr_un));
95         addr.sun_family = AF_LOCAL;
96         strcpy(addr.sun_path, socket_path);
97         if (connect(sockfd, &addr, sizeof(struct sockaddr_un)) < 0)
98                 err(-1, "Could not connect to i3");
99
100         ipc_send_message(sockfd, strlen(argv[optind]), 0, (uint8_t*)argv[optind]);
101
102         close(sockfd);
103
104         return 0;
105 }