ipc.h (10392B)
1 #ifndef IPC_H_ 2 #define IPC_H_ 3 4 #include <stdint.h> 5 #include <sys/epoll.h> 6 #include <yajl/yajl_gen.h> 7 8 #include "IPCClient.h" 9 10 // clang-format off 11 #define IPC_MAGIC "DWM-IPC" 12 #define IPC_MAGIC_ARR { 'D', 'W', 'M', '-', 'I', 'P', 'C'} 13 #define IPC_MAGIC_LEN 7 // Not including null char 14 15 #define IPCCOMMAND(FUNC, ARGC, TYPES) \ 16 { #FUNC, {FUNC }, ARGC, (ArgType[ARGC])TYPES } 17 // clang-format on 18 19 typedef enum IPCMessageType { 20 IPC_TYPE_RUN_COMMAND = 0, 21 IPC_TYPE_GET_MONITORS = 1, 22 IPC_TYPE_GET_TAGS = 2, 23 IPC_TYPE_GET_LAYOUTS = 3, 24 IPC_TYPE_GET_DWM_CLIENT = 4, 25 IPC_TYPE_SUBSCRIBE = 5, 26 IPC_TYPE_EVENT = 6 27 } IPCMessageType; 28 29 typedef enum IPCEvent { 30 IPC_EVENT_TAG_CHANGE = 1 << 0, 31 IPC_EVENT_CLIENT_FOCUS_CHANGE = 1 << 1, 32 IPC_EVENT_LAYOUT_CHANGE = 1 << 2, 33 IPC_EVENT_MONITOR_FOCUS_CHANGE = 1 << 3, 34 IPC_EVENT_FOCUSED_TITLE_CHANGE = 1 << 4, 35 IPC_EVENT_FOCUSED_STATE_CHANGE = 1 << 5 36 } IPCEvent; 37 38 typedef enum IPCSubscriptionAction { 39 IPC_ACTION_UNSUBSCRIBE = 0, 40 IPC_ACTION_SUBSCRIBE = 1 41 } IPCSubscriptionAction; 42 43 /** 44 * Every IPC packet starts with this structure 45 */ 46 typedef struct dwm_ipc_header { 47 uint8_t magic[IPC_MAGIC_LEN]; 48 uint32_t size; 49 uint8_t type; 50 } __attribute((packed)) dwm_ipc_header_t; 51 52 typedef enum ArgType { 53 ARG_TYPE_NONE = 0, 54 ARG_TYPE_UINT = 1, 55 ARG_TYPE_SINT = 2, 56 ARG_TYPE_FLOAT = 3, 57 ARG_TYPE_PTR = 4, 58 ARG_TYPE_STR = 5 59 } ArgType; 60 61 /** 62 * An IPCCommand function can have either of these function signatures 63 */ 64 typedef union ArgFunction { 65 void (*single_param)(const Arg *); 66 void (*array_param)(const Arg *, int); 67 } ArgFunction; 68 69 typedef struct IPCCommand { 70 char *name; 71 ArgFunction func; 72 unsigned int argc; 73 ArgType *arg_types; 74 } IPCCommand; 75 76 typedef struct IPCParsedCommand { 77 char *name; 78 Arg *args; 79 ArgType *arg_types; 80 unsigned int argc; 81 } IPCParsedCommand; 82 83 /** 84 * Initialize the IPC socket and the IPC module 85 * 86 * @param socket_path Path to create the socket at 87 * @param epoll_fd File descriptor for epoll 88 * @param commands Address of IPCCommands array defined in config.h 89 * @param commands_len Length of commands[] array 90 * 91 * @return int The file descriptor of the socket if it was successfully created, 92 * -1 otherwise 93 */ 94 int ipc_init(const char *socket_path, const int p_epoll_fd, 95 IPCCommand commands[], const int commands_len); 96 97 /** 98 * Uninitialize the socket and module. Free allocated memory and restore static 99 * variables to their state before ipc_init 100 */ 101 void ipc_cleanup(); 102 103 /** 104 * Get the file descriptor of the IPC socket 105 * 106 * @return int File descriptor of IPC socket, -1 if socket not created. 107 */ 108 int ipc_get_sock_fd(); 109 110 /** 111 * Get address to IPCClient with specified file descriptor 112 * 113 * @param fd File descriptor of IPC Client 114 * 115 * @return Address to IPCClient with specified file descriptor, -1 otherwise 116 */ 117 IPCClient *ipc_get_client(int fd); 118 119 /** 120 * Check if an IPC client exists with the specified file descriptor 121 * 122 * @param fd File descriptor 123 * 124 * @return int 1 if client exists, 0 otherwise 125 */ 126 int ipc_is_client_registered(int fd); 127 128 /** 129 * Disconnect an IPCClient from the socket and remove the client from the list 130 * of known connected clients 131 * 132 * @param c Address of IPCClient 133 * 134 * @return 0 if the client's file descriptor was closed successfully, the 135 * result of executing close() on the file descriptor otherwise. 136 */ 137 int ipc_drop_client(IPCClient *c); 138 139 /** 140 * Accept an IPC Client requesting to connect to the socket and add it to the 141 * list of clients 142 * 143 * @return File descriptor of new client, -1 on error 144 */ 145 int ipc_accept_client(); 146 147 /** 148 * Read an incoming message from an accepted IPC client 149 * 150 * @param c Address of IPCClient 151 * @param msg_type Address to IPCMessageType variable which will be assigned 152 * the message type of the received message 153 * @param msg_size Address to uint32_t variable which will be assigned the size 154 * of the received message 155 * @param msg Address to char* variable which will be assigned the address of 156 * the received message. This must be freed using free(). 157 * 158 * @return 0 on success, -1 on error reading message, -2 if reading the message 159 * resulted in EAGAIN, EINTR, or EWOULDBLOCK. 160 */ 161 int ipc_read_client(IPCClient *c, IPCMessageType *msg_type, uint32_t *msg_size, 162 char **msg); 163 164 /** 165 * Write any pending buffer of the client to the client's socket 166 * 167 * @param c Client whose buffer to write 168 * 169 * @return Number of bytes written >= 0, -1 otherwise. errno will still be set 170 * from the write operation. 171 */ 172 ssize_t ipc_write_client(IPCClient *c); 173 174 /** 175 * Prepare a message in the specified client's buffer. 176 * 177 * @param c Client to prepare message for 178 * @param msg_type Type of message to prepare 179 * @param msg_size Size of the message in bytes. Should not exceed 180 * MAX_MESSAGE_SIZE 181 * @param msg Message to prepare (not including header). This pointer can be 182 * freed after the function invocation. 183 */ 184 void ipc_prepare_send_message(IPCClient *c, const IPCMessageType msg_type, 185 const uint32_t msg_size, const char *msg); 186 187 /** 188 * Prepare an error message in the specified client's buffer 189 * 190 * @param c Client to prepare message for 191 * @param msg_type Type of message 192 * @param format Format string following vsprintf 193 * @param ... Arguments for format string 194 */ 195 void ipc_prepare_reply_failure(IPCClient *c, IPCMessageType msg_type, 196 const char *format, ...); 197 198 /** 199 * Prepare a success message in the specified client's buffer 200 * 201 * @param c Client to prepare message for 202 * @param msg_type Type of message 203 */ 204 void ipc_prepare_reply_success(IPCClient *c, IPCMessageType msg_type); 205 206 /** 207 * Send a tag_change_event to all subscribers. Should be called only when there 208 * has been a tag state change. 209 * 210 * @param mon_num The index of the monitor (Monitor.num property) 211 * @param old_state The old tag state 212 * @param new_state The new (now current) tag state 213 */ 214 void ipc_tag_change_event(const int mon_num, TagState old_state, 215 TagState new_state); 216 217 /** 218 * Send a client_focus_change_event to all subscribers. Should be called only 219 * when the client focus changes. 220 * 221 * @param mon_num The index of the monitor (Monitor.num property) 222 * @param old_client The old DWM client selection (Monitor.oldsel) 223 * @param new_client The new (now current) DWM client selection 224 */ 225 void ipc_client_focus_change_event(const int mon_num, Client *old_client, 226 Client *new_client); 227 228 /** 229 * Send a layout_change_event to all subscribers. Should be called only 230 * when there has been a layout change. 231 * 232 * @param mon_num The index of the monitor (Monitor.num property) 233 * @param old_symbol The old layout symbol 234 * @param old_layout Address to the old Layout 235 * @param new_symbol The new (now current) layout symbol 236 * @param new_layout Address to the new Layout 237 */ 238 void ipc_layout_change_event(const int mon_num, const char *old_symbol, 239 const Layout *old_layout, const char *new_symbol, 240 const Layout *new_layout); 241 242 /** 243 * Send a monitor_focus_change_event to all subscribers. Should be called only 244 * when the monitor focus changes. 245 * 246 * @param last_mon_num The index of the previously selected monitor 247 * @param new_mon_num The index of the newly selected monitor 248 */ 249 void ipc_monitor_focus_change_event(const int last_mon_num, 250 const int new_mon_num); 251 252 /** 253 * Send a focused_title_change_event to all subscribers. Should only be called 254 * if a selected client has a title change. 255 * 256 * @param mon_num Index of the client's monitor 257 * @param client_id Window XID of client 258 * @param old_name Old name of the client window 259 * @param new_name New name of the client window 260 */ 261 void ipc_focused_title_change_event(const int mon_num, const Window client_id, 262 const char *old_name, const char *new_name); 263 264 /** 265 * Send a focused_state_change_event to all subscribers. Should only be called 266 * if a selected client has a state change. 267 * 268 * @param mon_num Index of the client's monitor 269 * @param client_id Window XID of client 270 * @param old_state Old state of the client 271 * @param new_state New state of the client 272 */ 273 void ipc_focused_state_change_event(const int mon_num, const Window client_id, 274 const ClientState *old_state, 275 const ClientState *new_state); 276 /** 277 * Check to see if an event has occured and call the *_change_event functions 278 * accordingly 279 * 280 * @param mons Address of Monitor pointing to start of linked list 281 * @param lastselmon Address of pointer to previously selected monitor 282 * @param selmon Address of selected Monitor 283 */ 284 void ipc_send_events(Monitor *mons, Monitor **lastselmon, Monitor *selmon); 285 286 /** 287 * Handle an epoll event caused by a registered IPC client. Read, process, and 288 * handle any received messages from clients. Write pending buffer to client if 289 * the client is ready to receive messages. Drop clients that have sent an 290 * EPOLLHUP. 291 * 292 * @param ev Associated epoll event returned by epoll_wait 293 * @param mons Address of Monitor pointing to start of linked list 294 * @param selmon Address of selected Monitor 295 * @param lastselmon Address of pointer to previously selected monitor 296 * @param tags Array of tag names 297 * @param tags_len Length of tags array 298 * @param layouts Array of available layouts 299 * @param layouts_len Length of layouts array 300 * 301 * @return 0 if event was successfully handled, -1 on any error receiving 302 * or handling incoming messages or unhandled epoll event. 303 */ 304 int ipc_handle_client_epoll_event(struct epoll_event *ev, Monitor *mons, 305 Monitor **lastselmon, Monitor *selmon, const int tags_len, 306 const Layout *layouts, const int layouts_len); 307 308 /** 309 * Handle an epoll event caused by the IPC socket. This function only handles an 310 * EPOLLIN event indicating a new client requesting to connect to the socket. 311 * 312 * @param ev Associated epoll event returned by epoll_wait 313 * 314 * @return 0, if the event was successfully handled, -1 if not an EPOLLIN event 315 * or if a new IPC client connection request could not be accepted. 316 */ 317 int ipc_handle_socket_epoll_event(struct epoll_event *ev); 318 319 #endif /* IPC_H_ */ 320