diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | TODO | 7 | ||||
-rw-r--r-- | doc/protocols | 100 | ||||
-rw-r--r-- | src/mds-clipboard.c | 275 | ||||
-rw-r--r-- | src/mds-clipboard.h | 44 |
5 files changed, 424 insertions, 4 deletions
@@ -12,7 +12,7 @@ include mk/config.mk LIBOBJ = linked-list client-list hash-table fd-table mds-message util # Servers and utilities. -SERVERS = mds mds-respawn mds-server mds-echo mds-registry +SERVERS = mds mds-respawn mds-server mds-echo mds-registry mds-clipboard @@ -15,7 +15,6 @@ Missing servers: inet Network enabled display server remote Bind to a remote display server fb Framebuffer presenter - clipboard Clipboard kkbd Keyboard input from kernel kbd Keyboard input rat Rat input @@ -36,6 +35,7 @@ Missing servers: stack A simple, reference implementation of a, stack window manager workspace A simple, reference implementation of a, workspaces vt VT switcher + iclipboard User-private interdisplay clipboard Missing commands: @@ -45,7 +45,10 @@ Missing commands: Need testing: registry + clipboard Fast lanes -Optimise use of mutexe with shared and exclusive locks +Optimise use of mutexe by replace them with rwlocks +Listen for `Command: reregister` +Register protocols diff --git a/doc/protocols b/doc/protocols index ee1fd18..e008c28 100644 --- a/doc/protocols +++ b/doc/protocols @@ -70,7 +70,7 @@ Command: register Required header: Client ID Your ID, provided by `ID assignment` in response to `Command: assign-id` - + Conditionally required header: Length Required if: `Action: list` Length of the message @@ -114,3 +114,101 @@ Compulsivity: highly recommended (infrastructure), programs may --------------------------------------------------------------------- +Command: clipboard + Read or manipulate a clipboard + +Required header: Level + The clipboard level, an [1, 3] integer: + 1 "primary". Text copied/pasted using + the keyboard or a menu item + 2 "secondary". Text copied/pasted using the rat + 3 "tertiary". Non-text, it is customary for this + data to begin with a line describing + the data type. + +Required header: Action + What to do with the clipboard: + add) Write the message to the clipboard + read) Read the clipboard + clear) Clear all entries on the selected level on the clipboard + set-size) Shrink/grow the clipstack + get-size) Read the size of the clipstack + In the reply, the server will send: + Size: <configured maximum size of the clipstack> + Used: <number of elements currently in the clipstack> + +Conditionally required header: Length + Required if: `Action: add` + Length of the message + +Conditionally required header: Size + Available and optional if: `Action: set-size` + The maximum number of elements in the clipstack + +Conditionally optional header: Index + Available and optional if: `Action: read` + The index of the item in the clipstack, starting at 0 + +Conditionally required header: Client ID + Your ID, provided by `ID assignment` + in response to `Command: assign-id`. + Required if: `Action: add` but not `Time to live: forever` + +Conditionally optional header: Time to live + Available and optional if: `Action: add` + The number of seconds the entry should be available + before it is removed by the server, or: + until-death: remove entry when the client closes + forever: never remove it (default) + The server will always remove the entry when: + 1) it is at the bottom of the clipstack and a new + entry is added to the clipstack + 2) `Action: clear` is issued for the clipstack + The entry will also be removed, unless + `Time to live: forever`, if the server crashes or is + reexecuted. + It is up to the implementation to choose when + the removal actually takes place. For example, + the reference implementation will pop entries + that have timed out when a new entry is added, + the reading on the clipstack is requested or the + server is reexecuted, but another implement may + choose to pop entires asynchronously using another + thread or an alarm an pop when when SIGARLM is + received. + +Purpose: Enable the user to duplicate content from one process + into another process without requiring those processes + to be aware of eathother to any extent + +Compulsivity: optional + +Reference implementation: mds-clipboard + +--------------------------------------------------------------------- + +Command: clipboard-info + The clipboard server sends out some information about + what it is doing, such as automatically removing entires + +Included header: Event + pop) An item in the clipstack has been removed + Included headers: + Level: The clipboard level that has been affected + Popped: The index of the item in the clipstack + that has been removed + Size: Configured maximum size of the clipstack + Used: Number of elements currently in the clipstack + crash) The clipboard has been reset because of a software crash + +Purpose: Enable clients to get notification about changes + to the clipboard, that cannot trivially derived + from `Command: clipboard` + +Compulsivity: optional, optional add-on to the + clipboard's functionallity + +Reference implementation: mds-clipboard + +--------------------------------------------------------------------- + diff --git a/src/mds-clipboard.c b/src/mds-clipboard.c new file mode 100644 index 0000000..1ea4ee9 --- /dev/null +++ b/src/mds-clipboard.c @@ -0,0 +1,275 @@ +/** + * mds — A micro-display server + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "mds-clipboard.h" + +#include <libmdsserver/macros.h> +#include <libmdsserver/util.h> +#include <libmdsserver/mds-message.h> + +#include <errno.h> +#include <inttypes.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#define reconnect_to_display() -1 /* TODO */ + + + +#define MDS_CLIPBOARD_VARS_VERSION 0 + + + +/** + * This variable should declared by the actual server implementation. + * It must be configured before `main` is invoked. + * + * This tells the server-base how to behave + */ +server_characteristics_t server_characteristics = + { + .require_privileges = 0, + .require_display = 1, + .require_respawn_info = 1, + .sanity_check_argc = 1 + }; + + + +/** + * Value of the ‘Message ID’ header for the next message + */ +static int32_t message_id = 1; + +/** + * Buffer for received messages + */ +static mds_message_t received; + +/** + * Whether the server is connected to the display + */ +static int connected = 1; + + + +/** + * This function will be invoked before `initialise_server` (if not re-exec:ing) + * or before `unmarshal_server` (if re-exec:ing) + * + * @return Non-zero on error + */ +int __attribute__((const)) preinitialise_server(void) +{ + return 0; +} + + +/** + * This function should initialise the server, + * and it not invoked after a re-exec. + * + * @return Non-zero on error + */ +int initialise_server(void) +{ + const char* const message = + "Command: intercept\n" + "Message ID: 0\n" + "Length: 19\n" + "\n" + "Command: clipboard\n"; + + if (full_send(message, strlen(message))) + return 1; + server_initialised(); + mds_message_initialise(&received); + return 0; +} + + +/** + * This function will be invoked after `initialise_server` (if not re-exec:ing) + * or after `unmarshal_server` (if re-exec:ing) + * + * @return Non-zero on error + */ +int postinitialise_server(void) +{ + if (connected) + return 0; + + if (reconnect_to_display()) + { + mds_message_destroy(&received); + return 1; + } + connected = 1; + return 0; +} + + +/** + * Calculate the number of bytes that will be stored by `marshal_server` + * + * On failure the program should `abort()` or exit by other means. + * However it should not be possible for this function to fail. + * + * @return The number of bytes that will be stored by `marshal_server` + */ +size_t marshal_server_size(void) +{ + return 2 * sizeof(int) + sizeof(int32_t) + mds_message_marshal_size(&received); +} + + +/** + * Marshal server implementation specific data into a buffer + * + * @param state_buf The buffer for the marshalled data + * @return Non-zero on error + */ +int marshal_server(char* state_buf) +{ + buf_set_next(state_buf, int, MDS_CLIPBOARD_VARS_VERSION); + buf_set_next(state_buf, int, connected); + buf_set_next(state_buf, int32_t, message_id); + mds_message_marshal(&received, state_buf); + + mds_message_destroy(&received); + return 0; +} + + +/** + * Unmarshal server implementation specific data and update the servers state accordingly + * + * On critical failure the program should `abort()` or exit by other means. + * That is, do not let `reexec_failure_recover` run successfully, if it unrecoverable + * error has occurred or one severe enough that it is better to simply respawn. + * + * @param state_buf The marshalled data that as not been read already + * @return Non-zero on error + */ +int unmarshal_server(char* state_buf) +{ + int r; + /* buf_get_next(state_buf, int, MDS_CLIPBOARD_VARS_VERSION); */ + buf_next(state_buf, int, 1); + buf_get_next(state_buf, int, connected); + buf_get_next(state_buf, int32_t, message_id); + r = mds_message_unmarshal(&received, state_buf); + if (r) + { + xperror(*argv); + mds_message_destroy(&received); + } + return r; +} + + +/** + * Attempt to recover from a re-exec failure that has been + * detected after the server successfully updated it execution image + * + * @return Non-zero on error + */ +int __attribute__((const)) reexec_failure_recover(void) +{ + return -1; +} + + +/** + * Perform the server's mission + * + * @return Non-zero on error + */ +int master_loop(void) +{ + int rc = 1; + + while (!reexecing && !terminating) + { + int r = mds_message_read(&received, socket_fd); + if (r == 0) + { + r = 0; /* FIXME */ + if (r == 0) + continue; + } + + if (r == -2) + { + eprint("corrupt message received, aborting."); + goto fail; + } + else if (errno == EINTR) + continue; + else if (errno != ECONNRESET) + goto pfail; + + eprint("lost connection to server."); + mds_message_destroy(&received); + mds_message_initialise(&received); + connected = 0; + if (reconnect_to_display()) + goto fail; + connected = 1; + } + + rc = 0; + goto fail; + pfail: + xperror(*argv); + fail: + if (rc || !reexecing) + mds_message_destroy(&received); + return rc; +} + + +/** + * Send a full message even if interrupted + * + * @param message The message to send + * @param length The length of the message + * @return Non-zero on success + */ +int full_send(const char* message, size_t length) +{ + size_t sent; + + while (length > 0) + { + sent = send_message(socket_fd, message, length); + if (sent > length) + { + eprint("Sent more of a message than exists in the message, aborting."); + return -1; + } + else if ((sent < length) && (errno != EINTR)) + { + xperror(*argv); + return -1; + } + message += sent; + length -= sent; + } + return 0; +} + diff --git a/src/mds-clipboard.h b/src/mds-clipboard.h new file mode 100644 index 0000000..34a12e9 --- /dev/null +++ b/src/mds-clipboard.h @@ -0,0 +1,44 @@ +/** + * mds — A micro-display server + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef MDS_MDS_ECHO_H +#define MDS_MDS_ECHO_H + + +#include "mds-base.h" + + +/** + * Echo the received message payload + * + * @return Zero on success -1 on error or interruption, + * errno will be set accordingly + */ +int echo_message(void); + +/** + * Send a full message even if interrupted + * + * @param message The message to send + * @param length The length of the message + * @return Non-zero on success + */ +int full_send(const char* message, size_t length); + + +#endif + |