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.
320 lines
10 KiB
320 lines
10 KiB
#ifndef IPC_H_ |
|
#define IPC_H_ |
|
|
|
#include <stdint.h> |
|
#include <sys/epoll.h> |
|
#include <yajl/yajl_gen.h> |
|
|
|
#include "IPCClient.h" |
|
|
|
// clang-format off |
|
#define IPC_MAGIC "DWM-IPC" |
|
#define IPC_MAGIC_ARR { 'D', 'W', 'M', '-', 'I', 'P', 'C'} |
|
#define IPC_MAGIC_LEN 7 // Not including null char |
|
|
|
#define IPCCOMMAND(FUNC, ARGC, TYPES) \ |
|
{ #FUNC, {FUNC }, ARGC, (ArgType[ARGC])TYPES } |
|
// clang-format on |
|
|
|
typedef enum IPCMessageType { |
|
IPC_TYPE_RUN_COMMAND = 0, |
|
IPC_TYPE_GET_MONITORS = 1, |
|
IPC_TYPE_GET_TAGS = 2, |
|
IPC_TYPE_GET_LAYOUTS = 3, |
|
IPC_TYPE_GET_DWM_CLIENT = 4, |
|
IPC_TYPE_SUBSCRIBE = 5, |
|
IPC_TYPE_EVENT = 6 |
|
} IPCMessageType; |
|
|
|
typedef enum IPCEvent { |
|
IPC_EVENT_TAG_CHANGE = 1 << 0, |
|
IPC_EVENT_CLIENT_FOCUS_CHANGE = 1 << 1, |
|
IPC_EVENT_LAYOUT_CHANGE = 1 << 2, |
|
IPC_EVENT_MONITOR_FOCUS_CHANGE = 1 << 3, |
|
IPC_EVENT_FOCUSED_TITLE_CHANGE = 1 << 4, |
|
IPC_EVENT_FOCUSED_STATE_CHANGE = 1 << 5 |
|
} IPCEvent; |
|
|
|
typedef enum IPCSubscriptionAction { |
|
IPC_ACTION_UNSUBSCRIBE = 0, |
|
IPC_ACTION_SUBSCRIBE = 1 |
|
} IPCSubscriptionAction; |
|
|
|
/** |
|
* Every IPC packet starts with this structure |
|
*/ |
|
typedef struct dwm_ipc_header { |
|
uint8_t magic[IPC_MAGIC_LEN]; |
|
uint32_t size; |
|
uint8_t type; |
|
} __attribute((packed)) dwm_ipc_header_t; |
|
|
|
typedef enum ArgType { |
|
ARG_TYPE_NONE = 0, |
|
ARG_TYPE_UINT = 1, |
|
ARG_TYPE_SINT = 2, |
|
ARG_TYPE_FLOAT = 3, |
|
ARG_TYPE_PTR = 4, |
|
ARG_TYPE_STR = 5 |
|
} ArgType; |
|
|
|
/** |
|
* An IPCCommand function can have either of these function signatures |
|
*/ |
|
typedef union ArgFunction { |
|
void (*single_param)(const Arg *); |
|
void (*array_param)(const Arg *, int); |
|
} ArgFunction; |
|
|
|
typedef struct IPCCommand { |
|
char *name; |
|
ArgFunction func; |
|
unsigned int argc; |
|
ArgType *arg_types; |
|
} IPCCommand; |
|
|
|
typedef struct IPCParsedCommand { |
|
char *name; |
|
Arg *args; |
|
ArgType *arg_types; |
|
unsigned int argc; |
|
} IPCParsedCommand; |
|
|
|
/** |
|
* Initialize the IPC socket and the IPC module |
|
* |
|
* @param socket_path Path to create the socket at |
|
* @param epoll_fd File descriptor for epoll |
|
* @param commands Address of IPCCommands array defined in config.h |
|
* @param commands_len Length of commands[] array |
|
* |
|
* @return int The file descriptor of the socket if it was successfully created, |
|
* -1 otherwise |
|
*/ |
|
int ipc_init(const char *socket_path, const int p_epoll_fd, |
|
IPCCommand commands[], const int commands_len); |
|
|
|
/** |
|
* Uninitialize the socket and module. Free allocated memory and restore static |
|
* variables to their state before ipc_init |
|
*/ |
|
void ipc_cleanup(); |
|
|
|
/** |
|
* Get the file descriptor of the IPC socket |
|
* |
|
* @return int File descriptor of IPC socket, -1 if socket not created. |
|
*/ |
|
int ipc_get_sock_fd(); |
|
|
|
/** |
|
* Get address to IPCClient with specified file descriptor |
|
* |
|
* @param fd File descriptor of IPC Client |
|
* |
|
* @return Address to IPCClient with specified file descriptor, -1 otherwise |
|
*/ |
|
IPCClient *ipc_get_client(int fd); |
|
|
|
/** |
|
* Check if an IPC client exists with the specified file descriptor |
|
* |
|
* @param fd File descriptor |
|
* |
|
* @return int 1 if client exists, 0 otherwise |
|
*/ |
|
int ipc_is_client_registered(int fd); |
|
|
|
/** |
|
* Disconnect an IPCClient from the socket and remove the client from the list |
|
* of known connected clients |
|
* |
|
* @param c Address of IPCClient |
|
* |
|
* @return 0 if the client's file descriptor was closed successfully, the |
|
* result of executing close() on the file descriptor otherwise. |
|
*/ |
|
int ipc_drop_client(IPCClient *c); |
|
|
|
/** |
|
* Accept an IPC Client requesting to connect to the socket and add it to the |
|
* list of clients |
|
* |
|
* @return File descriptor of new client, -1 on error |
|
*/ |
|
int ipc_accept_client(); |
|
|
|
/** |
|
* Read an incoming message from an accepted IPC client |
|
* |
|
* @param c Address of IPCClient |
|
* @param msg_type Address to IPCMessageType variable which will be assigned |
|
* the message type of the received message |
|
* @param msg_size Address to uint32_t variable which will be assigned the size |
|
* of the received message |
|
* @param msg Address to char* variable which will be assigned the address of |
|
* the received message. This must be freed using free(). |
|
* |
|
* @return 0 on success, -1 on error reading message, -2 if reading the message |
|
* resulted in EAGAIN, EINTR, or EWOULDBLOCK. |
|
*/ |
|
int ipc_read_client(IPCClient *c, IPCMessageType *msg_type, uint32_t *msg_size, |
|
char **msg); |
|
|
|
/** |
|
* Write any pending buffer of the client to the client's socket |
|
* |
|
* @param c Client whose buffer to write |
|
* |
|
* @return Number of bytes written >= 0, -1 otherwise. errno will still be set |
|
* from the write operation. |
|
*/ |
|
ssize_t ipc_write_client(IPCClient *c); |
|
|
|
/** |
|
* Prepare a message in the specified client's buffer. |
|
* |
|
* @param c Client to prepare message for |
|
* @param msg_type Type of message to prepare |
|
* @param msg_size Size of the message in bytes. Should not exceed |
|
* MAX_MESSAGE_SIZE |
|
* @param msg Message to prepare (not including header). This pointer can be |
|
* freed after the function invocation. |
|
*/ |
|
void ipc_prepare_send_message(IPCClient *c, const IPCMessageType msg_type, |
|
const uint32_t msg_size, const char *msg); |
|
|
|
/** |
|
* Prepare an error message in the specified client's buffer |
|
* |
|
* @param c Client to prepare message for |
|
* @param msg_type Type of message |
|
* @param format Format string following vsprintf |
|
* @param ... Arguments for format string |
|
*/ |
|
void ipc_prepare_reply_failure(IPCClient *c, IPCMessageType msg_type, |
|
const char *format, ...); |
|
|
|
/** |
|
* Prepare a success message in the specified client's buffer |
|
* |
|
* @param c Client to prepare message for |
|
* @param msg_type Type of message |
|
*/ |
|
void ipc_prepare_reply_success(IPCClient *c, IPCMessageType msg_type); |
|
|
|
/** |
|
* Send a tag_change_event to all subscribers. Should be called only when there |
|
* has been a tag state change. |
|
* |
|
* @param mon_num The index of the monitor (Monitor.num property) |
|
* @param old_state The old tag state |
|
* @param new_state The new (now current) tag state |
|
*/ |
|
void ipc_tag_change_event(const int mon_num, TagState old_state, |
|
TagState new_state); |
|
|
|
/** |
|
* Send a client_focus_change_event to all subscribers. Should be called only |
|
* when the client focus changes. |
|
* |
|
* @param mon_num The index of the monitor (Monitor.num property) |
|
* @param old_client The old DWM client selection (Monitor.oldsel) |
|
* @param new_client The new (now current) DWM client selection |
|
*/ |
|
void ipc_client_focus_change_event(const int mon_num, Client *old_client, |
|
Client *new_client); |
|
|
|
/** |
|
* Send a layout_change_event to all subscribers. Should be called only |
|
* when there has been a layout change. |
|
* |
|
* @param mon_num The index of the monitor (Monitor.num property) |
|
* @param old_symbol The old layout symbol |
|
* @param old_layout Address to the old Layout |
|
* @param new_symbol The new (now current) layout symbol |
|
* @param new_layout Address to the new Layout |
|
*/ |
|
void ipc_layout_change_event(const int mon_num, const char *old_symbol, |
|
const Layout *old_layout, const char *new_symbol, |
|
const Layout *new_layout); |
|
|
|
/** |
|
* Send a monitor_focus_change_event to all subscribers. Should be called only |
|
* when the monitor focus changes. |
|
* |
|
* @param last_mon_num The index of the previously selected monitor |
|
* @param new_mon_num The index of the newly selected monitor |
|
*/ |
|
void ipc_monitor_focus_change_event(const int last_mon_num, |
|
const int new_mon_num); |
|
|
|
/** |
|
* Send a focused_title_change_event to all subscribers. Should only be called |
|
* if a selected client has a title change. |
|
* |
|
* @param mon_num Index of the client's monitor |
|
* @param client_id Window XID of client |
|
* @param old_name Old name of the client window |
|
* @param new_name New name of the client window |
|
*/ |
|
void ipc_focused_title_change_event(const int mon_num, const Window client_id, |
|
const char *old_name, const char *new_name); |
|
|
|
/** |
|
* Send a focused_state_change_event to all subscribers. Should only be called |
|
* if a selected client has a state change. |
|
* |
|
* @param mon_num Index of the client's monitor |
|
* @param client_id Window XID of client |
|
* @param old_state Old state of the client |
|
* @param new_state New state of the client |
|
*/ |
|
void ipc_focused_state_change_event(const int mon_num, const Window client_id, |
|
const ClientState *old_state, |
|
const ClientState *new_state); |
|
/** |
|
* Check to see if an event has occured and call the *_change_event functions |
|
* accordingly |
|
* |
|
* @param mons Address of Monitor pointing to start of linked list |
|
* @param lastselmon Address of pointer to previously selected monitor |
|
* @param selmon Address of selected Monitor |
|
*/ |
|
void ipc_send_events(Monitor *mons, Monitor **lastselmon, Monitor *selmon); |
|
|
|
/** |
|
* Handle an epoll event caused by a registered IPC client. Read, process, and |
|
* handle any received messages from clients. Write pending buffer to client if |
|
* the client is ready to receive messages. Drop clients that have sent an |
|
* EPOLLHUP. |
|
* |
|
* @param ev Associated epoll event returned by epoll_wait |
|
* @param mons Address of Monitor pointing to start of linked list |
|
* @param selmon Address of selected Monitor |
|
* @param lastselmon Address of pointer to previously selected monitor |
|
* @param tags Array of tag names |
|
* @param tags_len Length of tags array |
|
* @param layouts Array of available layouts |
|
* @param layouts_len Length of layouts array |
|
* |
|
* @return 0 if event was successfully handled, -1 on any error receiving |
|
* or handling incoming messages or unhandled epoll event. |
|
*/ |
|
int ipc_handle_client_epoll_event(struct epoll_event *ev, Monitor *mons, |
|
Monitor **lastselmon, Monitor *selmon, const int tags_len, |
|
const Layout *layouts, const int layouts_len); |
|
|
|
/** |
|
* Handle an epoll event caused by the IPC socket. This function only handles an |
|
* EPOLLIN event indicating a new client requesting to connect to the socket. |
|
* |
|
* @param ev Associated epoll event returned by epoll_wait |
|
* |
|
* @return 0, if the event was successfully handled, -1 if not an EPOLLIN event |
|
* or if a new IPC client connection request could not be accepted. |
|
*/ |
|
int ipc_handle_socket_epoll_event(struct epoll_event *ev); |
|
|
|
#endif /* IPC_H_ */ |
|
|
|
|