aboutsummaryrefslogtreecommitdiff
path: root/include/ipc.h
blob: 8ea9fd2e49f94da1a43168df9db5970c7592bb36 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
 * vim:ts=4:sw=4:expandtab
 *
 * i3 - an improved dynamic tiling window manager
 * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
 *
 * ipc.c: UNIX domain socket IPC (initialization, client handling, protocol).
 *
 */
#pragma once

#include <config.h>

#include <ev.h>
#include <stdbool.h>
#include <yajl/yajl_gen.h>
#include <yajl/yajl_parse.h>

#include "data.h"
#include "tree.h"
#include "configuration.h"

#include "i3/ipc.h"

extern char *current_socketpath;

typedef struct ipc_client {
    int fd;

    /* The events which this client wants to receive */
    int num_events;
    char **events;

    /* For clients which subscribe to the tick event: whether the first tick
     * event has been sent by i3. */
    bool first_tick_sent;

    struct ev_io *read_callback;
    struct ev_io *write_callback;
    struct ev_timer *timeout;
    uint8_t *buffer;
    size_t buffer_size;

    TAILQ_ENTRY(ipc_client)
    clients;
} ipc_client;

/*
 * Callback type for the different message types.
 *
 * message is the raw packet, as received from the UNIX domain socket. size
 * is the remaining size of bytes for this packet.
 *
 * message_size is the size of the message as the sender specified it.
 * message_type is the type of the message as the sender specified it.
 *
 */
typedef void (*handler_t)(ipc_client *, uint8_t *, int, uint32_t, uint32_t);

/* Macro to declare a callback */
#define IPC_HANDLER(name)                                           \
    static void handle_##name(ipc_client *client, uint8_t *message, \
                              int size, uint32_t message_size,      \
                              uint32_t message_type)

/**
 * Handler for activity on the listening socket, meaning that a new client
 * has just connected and we should accept() him. Sets up the event handler
 * for activity on the new connection and inserts the file descriptor into
 * the list of clients.
 *
 */
void ipc_new_client(EV_P_ struct ev_io *w, int revents);

/**
 * ipc_new_client_on_fd() only sets up the event handler
 * for activity on the new connection and inserts the file descriptor into
 * the list of clients.
 *
 * This variant is useful for the inherited IPC connection when restarting.
 *
 */
ipc_client *ipc_new_client_on_fd(EV_P_ int fd);

/**
 * Creates the UNIX domain socket at the given path, sets it to non-blocking
 * mode, bind()s and listen()s on it.
 *
 */
int ipc_create_socket(const char *filename);

/**
 * Sends the specified event to all IPC clients which are currently connected
 * and subscribed to this kind of event.
 *
 */
void ipc_send_event(const char *event, uint32_t message_type, const char *payload);

/**
 * Calls to ipc_shutdown() should provide a reason for the shutdown.
 */
typedef enum {
    SHUTDOWN_REASON_RESTART,
    SHUTDOWN_REASON_EXIT
} shutdown_reason_t;

/**
 * Calls shutdown() on each socket and closes it. This function is to be called
 * when exiting or restarting only!
 *
 * exempt_fd is never closed. Set to -1 to close all fds.
 *
 */
void ipc_shutdown(shutdown_reason_t reason, int exempt_fd);

void dump_node(yajl_gen gen, Con *con, bool inplace_restart);

/**
 * Generates a json workspace event. Returns a dynamically allocated yajl
 * generator. Free with yajl_gen_free().
 */
yajl_gen ipc_marshal_workspace_event(const char *change, Con *current, Con *old);

/**
 * For the workspace events we send, along with the usual "change" field, also
 * the workspace container in "current". For focus events, we send the
 * previously focused workspace in "old".
 */
void ipc_send_workspace_event(const char *change, Con *current, Con *old);

/**
 * For the window events we send, along the usual "change" field,
 * also the window container, in "container".
 */
void ipc_send_window_event(const char *property, Con *con);

/**
 * For the barconfig update events, we send the serialized barconfig.
 */
void ipc_send_barconfig_update_event(Barconfig *barconfig);

/**
 * For the binding events, we send the serialized binding struct.
 */
void ipc_send_binding_event(const char *event_type, Binding *bind);

/**
 * Set the maximum duration that we allow for a connection with an unwriteable
 * socket.
 */
void ipc_set_kill_timeout(ev_tstamp new);

/**
 * Sends a restart reply to the IPC client on the specified fd.
 */
void ipc_confirm_restart(ipc_client *client);