Another copy of my dotfiles. Because I don't completely trust GitHub.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

319 lines
10 KiB

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