/* See LICENSE file for copyright and license details. */ #ifndef LIBAXL_H #define LIBAXL_H #include #include #if defined(__GNUC__) # define _LIBAXL_GCC_ONLY(...) __VA_ARGS__ #else # define _LIBAXL_GCC_ONLY(...) #endif #include "libaxl-types.h" #include "libaxl-consts.h" #include "libaxl-atoms.h" #include "libaxl-events.h" #include "libaxl-errors.h" #include "libaxl-requests.h" #include "libaxl-replies.h" #include "libaxl-display-info.h" /** * The major version number of the highest version of X protocol * of the library supports (the lowest version is 11.0). If you * are using dynamic linking, you make also want to use the * libaxl_protocol_major() function. */ #define LIBAXL_PROTOCOL_MAJOR 11 /** * The minor version number of the highest version of X protocol * of the library supports (the lowest version is 11.0). If you * are using dynamic linking, you make also want to use the * libaxl_protocol_minor() function. */ #define LIBAXL_PROTOCOL_MINOR 0 /** * The version number of the highest version of X protocol of * the library supports, as one integer where the major number * is multiped by 100000, (the lowest version is 11.0, which is * encoded as 1100000). If you are using dynamic linking, you * make also want to use the libaxl_protocol_version() function. */ #define LIBAXL_PROTOCOL_VERSION ((LIBAXL_PROTOCOL_MAJOR) * 100000 + (LIBAXL_PROTOCOL_MINOR)) /* libaxl error codes */ #define LIBAXL_ERROR_SYSTEM -1 /* use `errno` */ #define LIBAXL_ERROR_NO_DISPLAY_SERVER_SPECIFIED -2 #define LIBAXL_ERROR_INVALID_DISPLAY_NAME_NO_DISPLAY_INDEX -3 #define LIBAXL_ERROR_INVALID_DISPLAY_NAME_DISPLAY_INDEX_OUT_OF_DOMAIN -4 #define LIBAXL_ERROR_INVALID_DISPLAY_NAME_INVALID_SCREEN_INDEX -5 #define LIBAXL_ERROR_INVALID_DISPLAY_NAME_SCREEN_INDEX_OUT_OF_DOMAIN -6 #define LIBAXL_ERROR_INVALID_REQUEST_OPCODE -7 #define LIBAXL_ERROR_INVALID_FORMAT_NUMBER -8 #define LIBAXL_ERROR_MALFORMATTED_REQUEST -9 #define LIBAXL_ERROR_CONNECTION_CLOSED -10 #define LIBAXL_ERROR_INVALID_REPLY_OPCODE -11 #define LIBAXL_ERROR_INVALID_HANDSHAKE_RESPONSE -12 #define LIBAXL_ERROR_OUT_OF_RESOURCE_IDS -13 #define LIBAXL_HANDSHAKE_FAILED 0 #define LIBAXL_HANDSHAKE_SUCCESS 1 #define LIBAXL_HANDSHAKE_AUTHENTICATE 2 /* * The largest possible return of the libaxl_get_decnet_object() * function, plus 1 for the terminal NUL byte */ #define LIBAXL_DECNET_OBJECT_MAX (5 + 3 * sizeof(int) - sizeof(int) / 2) union libaxl_input { /* TODO doc, man */ uint8_t type; union libaxl_error error; /* if .type = LIBAXL_ERROR */ union libaxl_reply reply; /* if .type = LIBAXL_REPLY */ union libaxl_event event; /* otherwise (.type = event type) */ }; /** * Opaque structure for connection to the X display server */ typedef struct libaxl_connection LIBAXL_CONNECTION; /** * Opaque structure that wraps LIBAXL_CONNECTION with * private data for the thread, all threads running at * the same time shall access the display server * via a unique LIBAXL_CONTEXT */ typedef struct libaxl_context LIBAXL_CONTEXT; /** * Returns the major version number of the highest version of * X protocol of the library supports (the lowest version is * 11.0). If you are using static linking, you make also want * to use the LIBAXL_PROTOCOL_MAJOR constant. * * @return The major version number of highest support version of the protocol */ int libaxl_protocol_version_major(void); /** * Returns the minor version number of the highest version of * X protocol of the library supports (the lowest version is * 11.0). If you are using static linking, you make also want * to use the LIBAXL_PROTOCOL_MINOR constant. * * @return The minor version number of highest support version of the protocol */ int libaxl_protocol_version_minor(void); /** * Returns the minor version number of the highest version of * X protocol of the library supports (the lowest version is 11.0, * which is encoded as 1100000). If you are using static linking, * you make also want to use the LIBAXL_PROTOCOL_VERSION constant. * * @return The version number of highest support version of the protocol, * encoded as a sum of the major number multipled by 100000 (1e5) * and the minor number, e.g. 1100000 for 11.0 (X11) */ int libaxl_protocol_version(void); /** * Get the file description used for a connection to * the X display server * * @param conn The connection to the display server * @return The number of the file descriptor that holds * the connection to the display server */ _LIBAXL_GCC_ONLY(__attribute__((__nonnull__, __warn_unused_result__))) int libaxl_fileno(LIBAXL_CONNECTION *); /* TODO man */ /** * Get information about a connection and the display * and display server it is connected to * * This information is sent to the client during the * connection handshake, and is never updated hence * * @param conn The connection to the display server * @param version Should be `LIBAXL_DISPLAY_INFO_VERSION`; used to * identify if old fields that have been replaces * must allocated and filled in with information * from the new fields that the application does ' not know about * @return Information about the display, the display * server, and the connection; `NULL` on error * * On failure, no error is returned, but the error * is always LIBAXL_ERROR_SYSTEM */ _LIBAXL_GCC_ONLY(__attribute__((__nonnull__, __warn_unused_result__))) const struct libaxl_display_info *libaxl_info(LIBAXL_CONNECTION *, int); /* TODO man */ /** * Get the next element in a `struct libaxl_depth *` * * Usage example for iterating of all elements in * `screen->allowed_depths` where `screen` is a * `struct libaxl_screen *`: * * struct libaxl_depth *depth; * size_t i = 0; * for (depth = screen->allowed_depths; i < screen->number_of_allowed_depths; depth = libaxl_next_depth(depth)) { * ... do something with `depth` or `break` if `i` is of a desired value (index) ... * } * * @param depth The element before the element to return * @return The element after `depth` */ inline const struct libaxl_depth * libaxl_next_depth(const struct libaxl_depth *depth) /* TODO man */ { return (const struct libaxl_depth *)(uintptr_t)&depth->visuals[depth->number_of_visuals]; } /** * Get the next element in a `struct libaxl_screen *` * * Usage example for iterating of all elements in `info->screens` * where `info` is a `struct libaxl_display_info *`: * * struct libaxl_screen *screen; * size_t i = 0; * for (screen = info->screens; i < info->nscreens; screen = libaxl_next_screen(screen)) { * ... do something with `screen` or `break` if `i` is of a desired value (index) ... * } * * @param screen The element before the element to return * @return The element after `screen` */ inline const struct libaxl_screen * libaxl_next_screen(const struct libaxl_screen *screen) /* TODO man */ { uint8_t n = screen->number_of_allowed_depths; const struct libaxl_depth *depth = screen->allowed_depths; while (n--) depth = libaxl_next_depth(depth); return (const struct libaxl_screen *)(uintptr_t)depth; } /** * Create context, for a thread, to use when accessing * the display server * * @param conn The connection to the display server * @return The context, NULL on failure (can only be out of memory) */ _LIBAXL_GCC_ONLY(__attribute__((__nonnull__, __malloc__, __warn_unused_result__))) LIBAXL_CONTEXT *libaxl_context_create(LIBAXL_CONNECTION *); /* TODO man */ /** * Deallocate a context * * @param ctx The context to deallocate */ void libaxl_context_free(LIBAXL_CONTEXT *); /* TODO man */ /** * Generate a resource ID * * The generated resource ID can be deallocated * with the libaxl_deallocate_id() function * * @param ctx The thread's context for the connection * @return The generated resource ID, 0 on failure * * On failure, no error is returned, but the error * is always LIBAXL_ERROR_OUT_OF_RESOURCE_IDS */ _LIBAXL_GCC_ONLY(__attribute__((__nonnull__, __warn_unused_result__))) libaxl_id_t libaxl_generate_id(LIBAXL_CONTEXT *); /* TODO man */ /** * Deallocate a resource ID so that it can be reused later * * @param ctx The thread's context for the connection * @param id The generated resource ID to deallocate * @return 0 on success, a negative libaxl error code on failure */ _LIBAXL_GCC_ONLY(__attribute__((__nonnull__))) int libaxl_deallocate_id(LIBAXL_CONTEXT *, libaxl_id_t); /* TODO man, implement */ /** * Parse a display name string * * The format for the display name string shall be either * * [/][]:[.] * * or for the "unix" protocol * * [.] * * @param name The display name string, $DISPLAY will be used if NULL or empty * @param hostp Output parameter for the host of or (if the protocol is "unix") path * to the display, remember to free after successful completion * @param protocolp Output parameter for the network protocol used to access the display, * remember to free after successful completion * @param displayp Output parameter for the display's index (0 if the protocol is "unix") * @param screenp Output parameter for the screen's index * @return 0 on success, a negative libaxl error code on failure */ _LIBAXL_GCC_ONLY(__attribute__((__nonnull__(2, 3, 4, 5)))) int libaxl_parse_display(const char *, char **, char **, int *, int *); /* TODO man */ /** * Get the TCP port that is used for a display * * @param display The display's number, the function will assume that it is a valid number * @return The TCP port used for the display */ _LIBAXL_GCC_ONLY(__attribute__((__warn_unused_result__))) inline uint16_t libaxl_get_tcp_port(int display) /* TODO man */ { return (uint16_t)(display + 6000); } /** * Get the DECnet object name that is used for a display * * @param buf Buffer that the object name shall be written to, it is recommended * that is size, if static, is LIBAXL_DECNET_OBJECT_MAX (which is * always sufficient), otherwise it should be at least the return value * of this function (for the same last argument but with NULL and 0 * as the first two arguments) plus 1 * @param size The size of the buffer in the `buf` argument * @param display The display's number * @return The length of the object name, will not exceed LIBAXL_DECNET_OBJECT_MAX * less 1; an additional uncounted NUL byte will be written to the buffer * if it is large enough; or -1 on failure (specifically snprintf(3), which * the function calls, by fail with EOVERFLOW if the `size` argument is * greater than {INT_MAX}) */ int libaxl_get_decnet_object(char *, size_t, int); /* TODO man */ /** * This function is to be called once and only once, excluding any * failure that does not set `errno` to EINPROGRESS and excluding * any call for which the display server respond that the handshake * failed or requires authentication, immediately after connecting * to the socket for the display * * The libaxl_receive_handshake() shall be called immediately after * calling this function * * @param ctx The thread's context for the connection to the display to send the handshake over * @param auth_name The protocol name of the authorisation the client expects the server to use; * valid authorisation mechanisms are not part of the core X protocol * @param auth_name_len The length of `auth_name`, 0 if `auth_name` is NULL * @param auth_data The authorisation data, which is specific to the choosen authorisation mechanism * @param auth_data_len The length of `auth_data`, 0 if `auth_data` is NULL * @param flags Flags to use for the 4th parameter when calling send(3) * @return 0 on success, a negative libaxl error code on failure * * If the function returns LIBAXL_ERROR_SYSTEM and sets `errno` * to EINPROGRESS, the message has been saved (possibly partially * sent) and pending to be sent by calling libaxl_flush(). */ _LIBAXL_GCC_ONLY(__attribute__((__nonnull__(1)))) int libaxl_send_handshake(LIBAXL_CONTEXT *restrict, const char *, size_t, const char *, size_t, int); /* TODO man */ /** * Send a request to the display server * * May deadlock if called from an asynchronously called signal handler * * @param ctx The thread's context for the connection to the display to send the request over * @param request The request to send, the function will not edit the content * @param flags Flags to use for the 4th parameter when calling send(3) * @param seqnump Output parameter for the request's sequence number * @return 0 on success, a negative libaxl error code on failure * * If the function returns LIBAXL_ERROR_SYSTEM and sets `errno` * to EINPROGRESS, the message has been saved (possibly partially * sent) and pending to be sent by calling libaxl_flush(). In this * case (and on success), `*seqnump` will be set. * * If the function returns LIBAXL_ERROR_SYSTEM and sets `errno` * to EALREADY, libaxl_flush() must first be called, either because * the previous call to this function returned LIBAXL_ERROR_SYSTEM * and set `errno` to EINPROGRESS, or such happened in another * thread. */ _LIBAXL_GCC_ONLY(__attribute__((__nonnull__))) int libaxl_send_request(LIBAXL_CONTEXT *restrict, union libaxl_request_const_ptr, int, uint16_t *restrict); /* TODO man */ /** * Send any pending messages to the display server * * @param conn The connection to the display server to flush * @param flags Flags to use for the 4th parameter when calling send(3) * @return 0 on success, a negative libaxl error code on failure * * If the function returns LIBAXL_ERROR_SYSTEM and sets `errno` * to EINPROGRESS, call the function again. Note well, the * EINPROGRESS error is caused by some other error, which could * be EAGAIN (otherwise its probably EINTR). On success, there * is nothing more to flush. */ _LIBAXL_GCC_ONLY(__attribute__((__nonnull__))) int libaxl_flush(LIBAXL_CONNECTION *restrict, int); /* TODO man */ /** * Receive the server's part of the handshake, this function * shall be called once immediately after each successful call * to the libaxl_send_handshake() function or successful call * to the libaxl_flush() function due to EINPROGRESS failure * of call to the libaxl_send_handshake() function * * @param ctx The thread's context for the connection to the display server * @param majorp Output parameter for the major version number for a version * of the X protocol that the display server supports, which is * not necessarily the version that the library uses. Will only * be set if the function returns LIBAXL_HANDSHAKE_FAILED or * LIBAXL_HANDSHAKE_SUCCESS. * @param minorp Output parameter for the minor version number for a version * of the X protocol that the display server supports, which is * not necessarily the version that the library uses. Will only * be set if the function returns LIBAXL_HANDSHAKE_FAILED or * LIBAXL_HANDSHAKE_SUCCESS. * @param reasonp Output parameter for the reason the handshake or authorisation * failed. Will be set to NULL unless the function returns * LIBAXL_HANDSHAKE_FAILED or LIBAXL_HANDSHAKE_AUTHENTICATE. * Remember to free after successful completion (non-negative return) * @param flags Flags to use for the 4th parameter when calling recv(3) * @return 0 on success, a negative libaxl error code on failure * * Behaviour is unspecified if SO_PEEK_OFF is active on the * connection to the display server or if the MSG_PEEK flag * is used */ _LIBAXL_GCC_ONLY(__attribute__((__nonnull__(1)))) int libaxl_receive_handshake(LIBAXL_CONTEXT *restrict, int *restrict, int *restrict, char **restrict, int); /* TODO man */ /** * Receive the next pending message from the display server * * Be aware: order of replies and events is not guaranteed, * and events caused by a request are sent before replies * and errors, however when multiple events are generated, * by some action, they are send in an uninterrupted sequence * (no other event, error, or reply is send between those event). * This means that it is important to check the returned * sequence number. * * @param ctx The thread's context for the connection to the display server * @param msgp Output parameter for the received message; the message will * be vaild until the next time this function is called with the * same `ctx` parameter or until the libaxl_context_free() function * is called with the same `ctx` paramter (whichever comes first) * @param flags Flags to use for the 4th parameter when calling recv(3) * @return 0 on success, a negative libaxl error code on failure * * Behaviour is unspecified if SO_PEEK_OFF is active on the * connection to the display server or if the MSG_PEEK flag * is used */ _LIBAXL_GCC_ONLY(__attribute__((__nonnull__))) int libaxl_receive(LIBAXL_CONTEXT *restrict, union libaxl_input *restrict, int); /* TODO man */ #endif