dwm

Kris's build of dwm
git clone git clone https://git.krisyotam.com/krisyotam/dwm.git
Log | Files | Refs | README | LICENSE

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