aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--TODO3
-rw-r--r--doc/info/mds.texinfo614
-rw-r--r--src/mds-colour.c323
-rw-r--r--src/mds-colour.h44
5 files changed, 976 insertions, 10 deletions
diff --git a/Makefile b/Makefile
index e57cc25..da3b5ee 100644
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@ 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 mds-clipboard \
- mds-kkbd mds-vt
+ mds-kkbd mds-vt mds-colour
# Utilities that do not utilise mds-base.
TOOLS = mds-kbdc
diff --git a/TODO b/TODO
index 610f113..e292196 100644
--- a/TODO
+++ b/TODO
@@ -6,7 +6,7 @@ Missing servers:
host remote fb kbd
keytrans kkbdrate rat compositor
crtc seat dri drag
- cursorshadow kill focus colour
+ cursorshadow kill focus dither
state screensaver
Extra servers:
@@ -48,6 +48,7 @@ Need testing:
kkbd
kkbd, on a SPARC
vt
+ colour
Fast lanes
Optimise use of mutexe by replace them with rwlocks (where appropriate)
diff --git a/doc/info/mds.texinfo b/doc/info/mds.texinfo
index 2e3da3e..f6e234b 100644
--- a/doc/info/mds.texinfo
+++ b/doc/info/mds.texinfo
@@ -1286,7 +1286,7 @@ seconds. At most 1 minute.
@item --interval=SECONDS
@opindex @option{--interval}
@sgindex @code{SIGUSR2}
-Spawned servers that die twice with @var{SECONDS}
+Spawned servers that die twice within @var{SECONDS}
seconds should stop respawning until the signal
@code{SIGUSR2} is send to @command{mds-respawn}.
At most 1 minute.
@@ -1775,6 +1775,7 @@ server.
* mds-coopgamma:: The @command{mds-coopgamma} server.
* mds-dcvs:: The @command{mds-dcvs} server.
* mds-colour:: The @command{mds-colour} server.
+* mds-dither:: The @command{mds-dither} server.
* mds-retro-crt:: The @command{mds-retro-crt} server.
* mds-state:: The @command{mds-state} server.
* mds-focus:: The @command{mds-focus} server.
@@ -2357,6 +2358,7 @@ defective colour vision.
@cpindex System colours
@cpindex Colours, system
@cpindex Colours, names
+@sgindex @code{SIGUSR2}
@command{mds-colour} is a server that implements
colour names, such as system colours and generic
names, for example `red', whose exact colour can be
@@ -2370,26 +2372,43 @@ fact `red', only that it is the colour the user
wants to see when a colour is supposed to be `red'.
@command{mds-colour} will notify clients when a
colour has been reconfigured, added or removed.
+@command{mds-colour} can be notified to reload its
+settings by sending @code{SIGUSR2} to the server.
+
+
+@node mds-dither
+@section @command{mds-dither}
+
+@pgindex @command{mds-dither}
@cpindex Colour dithering
@cpindex Dithering of colours
-@command{mds-colour} is also responsible for
+@command{mds-dither} is a server responsible for
informing clients on which two colours clients
should use and how to dither them (by percent, not
-by pattern). This is useful if only 16-bit colours
+by pattern.) This is useful if only 16-bit colours
can be used, or if only 24-colour can used but
gradients between for example sRGB(255, 255, 255)
and sRGB(254, 254, 254) is to be drawn.
@cpindex Gamma correction, dithering
-@command{mds-colour} is gamma ramp-aware. For
+@command{mds-dither} is gamma ramp-aware. For
example, if for the red channel, 0 is mapped to 0, 1
is mapped to 3, 2 is mapped 2 and 3 is mapped to 1,
but 1 and 3 requires dithering, then if 3 is
-requested, @command{mds-colour} will tell the client
+requested, @command{mds-dither} will tell the client
to dither 0 and 2 with 50 %, which should generate 1,
but 1 and 3 has been swapped.
+@command{mds-dither} holds a cache of the outputs
+gamma ramps to optimise performance. It will also
+inform clients when it is time to redither colours.
+This happens the gamma ramps change substantially,
+small changes should not trigger redithering, make
+it a waste of CPU time if all clients using dithering
+would spend time figuring out whether redithering
+is required.
+
@node mds-retro-crt
@@ -4492,7 +4511,7 @@ to 2 because each subpixel has 16 bits. Allowed values
are: 1, 2, 4 and 8. These values are used so that
CPU:s with any endianness can be trivially used as the
words sizes are guaranteed to be supported in C, and
-mixed/middle-endiannes gets complicated if we go
+mixed/middle-endianness gets complicated if we go
outside this. Required if the @code{Length}-header is
used.
@@ -4651,6 +4670,15 @@ Required if supporting @code{Command: add-tray-icon}.
* get-gamma-info:: Query gamma ramp information.
* get-gamma:: Query gamma ramps.
* set-gamma:: Modify gamma ramps.
+* list-colours:: Retrieve colour table.
+* get-colour:: Query colour table.
+* set-colour:: Modify colour table.
+* colour-added:: Announce new colours.
+* colour-removed:: Announce removal of colours.
+* colour-changed:: Announce modified colours.
+* dither:: Dither colours.
+* dither-stop:: Inform the dither server that a colour is no longer being dithered.
+* redither:: Announce that redithering is required.
@end menu
@@ -4676,7 +4704,7 @@ The output name for the CRTC of interest.
@item Response:
The server will response with a @code{Command: error}
-on error, unsuccess the server will respond with a
+on error, on success the server will respond with a
message contain the headers:
@table @code
@item To
@@ -4774,7 +4802,7 @@ ramps to received. This is a signed 64-bit integer.
@item Response:
@prindex @code{error}
The server will response with a @code{Command: error}
-on error, unsuccess the server will respond with a
+on error, on success the server will respond with a
message contain the headers:
@table @code
@item Depth
@@ -5002,6 +5030,575 @@ Optional. Required if your implement support for
+@node list-colours
+@subsection @code{list-colours}
+@prindex @code{list-colours}
+
+@cpindex Colour names
+@cpindex System colours
+@cpindex Colours, system
+@cpindex Colours, names
+@table @asis
+@item Identifying header:
+@code{Command: list-colours}
+
+@item Action:
+Retrieve an exhaustive list of defined colours.
+
+@item Required header: @code{Client ID}
+Your ID, provided by the @code{ID assignment}-header
+in response to a @code{Command: assign-id}-header.
+
+@item Optional header: @code{Include values}
+@table @code
+@item yes
+Include the values of the colours in addition to the
+name of the colours.
+@item no
+Include only the names of the colours.
+@end table
+@code{no} is used if omitted.
+
+@item Response:
+The server will response with a @code{Command: error}
+on error, on success the server will respond with a
+message whose payload is a list all defined colours.
+Each line in the payload represents a colour. If values
+where not requested, each line contain, exactly, the
+name of the colour it lists. If however values are
+requested, each name will be prefixed with the number
+of bytes with which each channel is encoded, the red value,
+the green value and the blue value of the colour,
+each of these values will be suffixed with a single
+regular blank space making the format
+@code{bytes red green blue name}. Note that the name may
+contain any whitespace@footnote{Tab space is discouraged.}
+except a line feed.
+
+The payload will end with a line break unless it is
+empty. No empty lines will otherwise be included
+(unless a colours name happend to be nothing
+@footnote{You should not define colours whose name
+is of zero length or containing non-ASCII or
+non-printable characters.}.)
+
+@item Purpose:
+Enable programs to list named colours, system colours
+or otherwise.
+
+@item Compulsivity:
+@prindex @code{get-colour}
+@prindex @code{set-colour}
+Optional. Required if your implement support for
+@code{Command: get-colour} or
+@code{Command: set-colour}.
+
+@item Reference implementation:
+@pgindex @command{mds-colour}
+@command{mds-colour}
+@end table
+
+
+
+@node get-colour
+@subsection @code{get-colour}
+@prindex @code{get-colour}
+
+@cpindex Colour names
+@cpindex System colours
+@cpindex Colours, system
+@cpindex Colours, names
+@table @asis
+@item Identifying header:
+@code{Command: get-colour}
+
+@item Action:
+Query the values of a defined colour.
+
+@item Required header: @code{Client ID}
+Your ID, provided by the @code{ID assignment}-header
+in response to a @code{Command: assign-id}-header.
+
+@item Required header: @code{Name}
+The name of the colour whose values you want to
+retrieve.
+
+@item Response:
+The server will response with a @code{Command: error}
+on error, on success the server will respond with a
+message contain the headers:
+@table @code
+@item Bytes
+The number of bytes with which each channel is encoded.
+@item Red
+The value of the red channel.
+@item Green
+The value of the green channel.
+@item Blue
+The value of the blue channel.
+@end table
+
+@item Purpose:
+@cpindex Toolkits, colours
+@cpindex Colours, toolkits
+Provide a central place for retrieving system colours,
+such as text field background, for toolkits.
+
+@item Purpose:
+Provide a central place for retrieving themeable colours.
+
+@item Compulsivity:
+@prindex @code{list-colours}
+@prindex @code{set-colour}
+Optional. Required if your implement support for
+@code{Command: list-colours} or
+@code{Command: set-colour}.
+
+@item Reference implementation:
+@pgindex @command{mds-colour}
+@command{mds-colour}
+@end table
+
+
+
+@node set-colour
+@subsection @code{set-colour}
+@prindex @code{set-colour}
+
+@cpindex Colour names
+@cpindex System colours
+@cpindex Colours, system
+@cpindex Colours, names
+@table @asis
+@item Identifying header:
+@code{Command: set-colour}
+
+@item Action:
+Change the value of a defined colour, or
+remove it.
+
+@item Required header: @code{Client ID}
+Your ID, provided by the @code{ID assignment}-header
+in response to a @code{Command: assign-id}-header.
+
+@item Required header: @code{Name}
+The name of the colour you want to define, modify or undefine.
+
+@item Optional header: @code{Remove}
+@table @code
+@item yes
+Remove the colour definition.
+@item no
+Add or modify colour definition.
+@end table
+@code{no} is used if omitted.
+
+@item Conditionally required header: @code{Bytes}
+The number of bytes with which each channel is encoded.
+Required unless @code{Remove: yes} is included in the headers.
+
+@item Conditionally required header: @code{Red}
+The value of the red channel.
+Required unless @code{Remove: yes} is included in the headers.
+
+@item Conditionally required header: @code{Green}
+The value of the green channel.
+Required unless @code{Remove: yes} is included in the headers.
+
+@item Conditionally required header: @code{Blue}
+The value of the blue channel.
+Required unless @code{Remove: yes} is included in the headers.
+
+@item Purpose:
+@cpindex Toolkits, colours
+@cpindex Colours, toolkits
+Provide a central place for defining system colours,
+such as text field background, for toolkits to use.
+
+@item Purpose:
+Provide a central place for defining themeable colours.
+
+@item Compulsivity:
+Optional.
+
+@item Reference implementation:
+@pgindex @command{mds-colour}
+@command{mds-colour}
+@end table
+
+
+
+@node colour-added
+@subsection @code{colour-added}
+@prindex @code{colour-added}
+
+@cpindex Colour names
+@cpindex System colours
+@cpindex Colours, system
+@cpindex Colours, names
+@table @asis
+@item Identifying header:
+@code{Command: colour-added}
+
+@item Action:
+Announce that a new colour has been defined.
+
+@item Included header: @code{Name}
+The name of the new colour.
+
+@item Included header: @code{Bytes}
+The number of bytes with which each channel is encoded.
+
+@item Included header: @code{Red}
+The value of the colour's red channel.
+
+@item Included header: @code{Green}
+The value of the colour's green channel.
+
+@item Included header: @code{Blue}
+The value of the colour's blue channel.
+
+@item Included header: @code{Last update}
+@table @code
+@item yes
+No more updates are queued.
+@item changes
+No more additions or deletions are queued,
+but modifications are queued.
+@item no
+More additions or deletions are queued.
+@end table
+
+@item Purpose:
+@prindex @code{colour}
+Supplement @code{Command: list-colours} with
+automatic updating.
+
+@item Compulsivity:
+@prindex @code{list-colours}
+Optional. Recommended if your implement support for
+@code{Command: list-colours}.
+
+@item Reference implementation:
+@pgindex @command{mds-colour}
+@command{mds-colour}
+@end table
+
+
+
+@node colour-removed
+@subsection @code{colour-removed}
+@prindex @code{colour-removed}
+
+@cpindex Colour names
+@cpindex System colours
+@cpindex Colours, system
+@cpindex Colours, names
+@table @asis
+@item Identifying header:
+@code{Command: colour-removed}
+
+@item Action:
+Announce when colour definition is removed.
+
+@item Included header: @code{Name}
+The name of the removed colour.
+
+@item Included header: @code{Last update}
+@table @code
+@item yes
+No more updates are queued.
+@item changes
+No more additions or deletions are queued,
+but modifications are queued.
+@item no
+More additions or deletions are queued.
+@end table
+
+@item Purpose:
+@prindex @code{colour}
+Supplement @code{Command: list-colours} with
+automatic updating.
+
+@item Compulsivity:
+@prindex @code{list-colours}
+Optional. Recommended if your implement support for
+@code{Command: list-colours}.
+
+@item Reference implementation:
+@pgindex @command{mds-colour}
+@command{mds-colour}
+@end table
+
+
+
+@node colour-changed
+@subsection @code{colour-changed}
+@prindex @code{colour-changed}
+
+@cpindex Colour names
+@cpindex System colours
+@cpindex Colours, system
+@cpindex Colours, names
+@table @asis
+@item Identifying header:
+@code{Command: colour-changed}
+
+@item Action:
+Announce when a defined colour changes value.
+
+@item Included header: @code{Name}
+The name of the modified colour.
+
+@item Included header: @code{Bytes}
+The number of bytes with which each channel is encoded.
+
+@item Included header: @code{Red}
+The new value of the colour's red channel.
+
+@item Included header: @code{Green}
+The new value of the colour's green channel.
+
+@item Included header: @code{Blue}
+The new value of the colour's blue channel.
+
+@item Included header: @code{Last update}
+@table @code
+@item yes
+No more updates are queued.
+@item no
+More changes are queued.
+@end table
+
+@item Instructions:
+The server must always send additions and deletions
+of colour definitions before modifitions, when sending
+multiple update.
+
+@item Purpose:
+Provide a way to detect when a themeable colour, or
+system colour, has changed, and the program needs to
+be redrawn with new colours.
+
+@item Compulsivity:
+@prindex @code{list-colours}
+@prindex @code{get-colour}
+Optional. Recommended if your implement support for
+@code{Command: list-colours} or
+@code{Command: get-colour}.
+
+@item Reference implementation:
+@pgindex @command{mds-colour}
+@command{mds-colour}
+@end table
+
+
+
+@node dither
+@subsection @code{dither}
+@prindex @code{dither}
+
+@cpindex Colour dithering
+@cpindex Dithering of colours
+@table @asis
+@item Identifying header:
+@code{Command: dither}
+
+@item Action:
+Request output device dependent colour dithering,
+and inform the dither server that the colour is
+being dithered.
+
+@item Required header: @code{Client ID}
+Your ID, provided by the @code{ID assignment}-header
+in response to a @code{Command: assign-id}-header.
+
+@item Required header: @code{Bytes}
+The number of bytes with which each channel is encoded.
+
+@item Required header: @code{Red}
+The value of the colour's red channel.
+
+@item Required header: @code{Green}
+The value of the colour's green channel.
+
+@item Required header: @code{Blue}
+The value of the colour's blue channel.
+
+@item Response:
+The server will response with a @code{Command: error}
+on error, on success the server will respond with a
+message contain a payload describing how the colour
+should be dithered on each output. Each line on the
+payload will decribed be dithering on an output.
+No empty lines will required, however the payload
+will end with a line feed unless it is
+empty@footnote{It can only be empty if there are
+no outputs.}. Each line will contain line single
+blank space-delimited values. These values are:
+@itemize @bullet{}
+@item
+The number of bytes with which each channel is
+encoded.
+@item
+The value of the primary colour's red channel.
+@item
+The value of the primary colour's green channel.
+@item
+The value of the primary colour's blue channel.
+@item
+A floating point value describing the predominance
+of the primary colour. A period is used as
+decimal comma. This value is between 0 and 1, but
+cannot be zero. If the value is @code{1}, the
+secondary colour is identical to the primary and
+no dithering is required. As an example,
+@code{0.75} means that there should be 75% of the
+primary colour and 25% of the secondary colour.
+@item
+The value of the secondary colour's red channel.
+@item
+The value of the secondary colour's green channel.
+@item
+The value of the secondary colour's blue channel.
+@item
+The name of the CRTC for which the line describes
+the colour's dithering. Note that thes value may
+contain whitespace.
+@end itemize
+Note that the pattern to use of dithering is not
+included in the response. It is up to the client
+to select a pattern.
+
+@item Instructions:
+@prindex @code{dither-stop}
+The dither server should count how many times
+the colour's dithering has be queried, per client.
+It should be decremented by one request each time
+@code{Command: dither-stop} is received for
+the colour and client. When the counter reaches
+zero for a client, the server knows that the client
+is no longer displaying the dithered colour.
+
+@item Purpose:
+Provide dithering for low colour-depth-output,
+that is gamma correction- and output filter-aware.
+
+@item Purpose:
+Provide gamma correction- and output filter-aware
+dither for low-delta colour gradients.
+
+@item Compulsivity:
+@prindex @code{redither}
+@prindex @code{dither-stop}
+Optional. Required if your implement support for
+@code{Command: redither} or
+@code{Command: dither-stop}.
+
+@item Reference implementation:
+@pgindex @command{mds-dither}
+@command{mds-dither}
+@end table
+
+
+
+@node dither-stop
+@subsection @code{dither-stop}
+@prindex @code{dither-stop}
+
+@cpindex Colour dithering
+@cpindex Dithering of colours
+@table @asis
+@item Identifying header:
+@code{Command: dither-stop}
+
+@item Action:
+Inform the dither server that a colour is no
+longer being dithered.
+
+@item Required header: @code{Client ID}
+Your ID, provided by the @code{ID assignment}-header
+
+@item Required header: @code{Bytes}
+The number of bytes with which each channel is encoded.
+
+@item Required header: @code{Red}
+The value of the colour's red channel.
+
+@item Required header: @code{Green}
+The value of the colour's green channel.
+
+@item Required header: @code{Blue}
+The value of the colour's blue channel.
+in response to a @code{Command: assign-id}-header.
+
+@item Purpose:
+Allow dithering server to know when a client is not
+longer dithering colours, or a specific colour.
+
+@item Compulsivity:
+@prindex @code{dither}
+@prindex @code{redither}
+Optional. Required if your implement support for
+@code{Command: dither} or
+@code{Command: redither}.
+
+@item Reference implementation:
+@pgindex @command{mds-dither}
+@command{mds-dither}
+@end table
+
+
+
+@node redither
+@subsection @code{redither}
+@prindex @code{redither}
+
+@cpindex Colour dithering
+@cpindex Dithering of colours
+@table @asis
+@item Identifying header:
+@code{Command: redither}
+
+@item Action:
+Announce that the client needs to redither
+its dithered colours.
+
+@item Included header: @code{Length}
+The length of the message.
+
+@item Message:
+A line feed-terminated, line feed-separated list
+of colours that need to be dithered on the client.
+Each line will be formatted @code{Bytes Red Green Blue},
+where each these words are replaced by the values
+associated with the same headers of the same name
+in the @code{Command: dither} message that let
+the dither server know that the colour is being
+dithered.
+
+@item Purpose:
+@prindex @code{dither}
+Supplement @code{Command: dither} with automatic
+detection of when colours need to be redithered,
+without all clients needing to determine when,
+thus saving CPU time.
+
+@item Compulsivity:
+@prindex @code{dither}
+@prindex @code{dither-stop}
+Optional. Required if your implement support for
+@code{Command: dither} or
+@code{Command: dither-stop}.
+
+@item Reference implementation:
+@pgindex @command{mds-dither}
+@command{mds-dither}
+@end table
+
+
+
+
@node Screensaver Protocols
@section Screensaver Protocols
@@ -9441,6 +10038,7 @@ speed)^(1 + curve)
* Nesting Applications:: Specifications for nesting applications.
* The Real Display Server:: Identifying the real display server.
@end menu
+@c TODO list of recommended colour names
diff --git a/src/mds-colour.c b/src/mds-colour.c
new file mode 100644
index 0000000..267c0ba
--- /dev/null
+++ b/src/mds-colour.c
@@ -0,0 +1,323 @@
+/**
+ * mds — A micro-display server
+ * Copyright © 2014, 2015 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-colour.h"
+/* TODO reload settings on SIGUSR2 */
+/* TODO --save-changes */
+
+#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
+
+
+
+#define MDS_COLOUR_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 = 0,
+ .sanity_check_argc = 1,
+ .fork_for_safety = 0,
+ .danger_is_deadly = 0
+ };
+
+
+
+/**
+ * Value of the ‘Message ID’ header for the next message
+ */
+static uint32_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;
+
+/**
+ * Buffer for sending messages
+ */
+static char* send_buffer = NULL;
+
+/**
+ * The size allocated to `send_buffer` divided by `sizeof(char)`
+ */
+static size_t send_buffer_size = 0;
+
+
+
+/**
+ * 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)
+{
+ int stage = 0;
+ const char* const message =
+ "Command: intercept\n"
+ "Message ID: 0\n"
+ "Length: 62\n"
+ "\n"
+ "Command: list-colours\n"
+ "Command: get-colour\n"
+ "Command: set-colour\n";
+
+ fail_if (full_send(message, strlen(message)));
+ fail_if (server_initialised() < 0); stage++;
+ fail_if (mds_message_initialise(&received));
+
+ return 0;
+ fail:
+ xperror(*argv);
+ if (stage == 1)
+ mds_message_destroy(&received);
+ return 1;
+}
+
+
+/**
+ * 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;
+
+ fail_if (reconnect_to_display());
+ connected = 1;
+ return 0;
+ fail:
+ mds_message_destroy(&received);
+ return 1;
+}
+
+
+/**
+ * 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(uint32_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_COLOUR_VARS_VERSION);
+ buf_set_next(state_buf, int, connected);
+ buf_set_next(state_buf, uint32_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)
+{
+ /* buf_get_next(state_buf, int, MDS_COLOUR_VARS_VERSION); */
+ buf_next(state_buf, int, 1);
+ buf_get_next(state_buf, int, connected);
+ buf_get_next(state_buf, uint32_t, message_id);
+ fail_if (mds_message_unmarshal(&received, state_buf));
+ return 0;
+ fail:
+ xperror(*argv);
+ mds_message_destroy(&received);
+ return -1;
+}
+
+
+/**
+ * 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, r;
+
+ while (!reexecing && !terminating)
+ {
+ if (danger)
+ {
+ danger = 0;
+ free(send_buffer), send_buffer = NULL;
+ send_buffer_size = 0;
+ }
+
+ if (r = mds_message_read(&received, socket_fd), r == 0)
+ if (r = handle_message(), r == 0)
+ continue;
+
+ if (r == -2)
+ {
+ eprint("corrupt message received, aborting.");
+ goto done;
+ }
+ else if (errno == EINTR)
+ continue;
+ else
+ fail_if (errno != ECONNRESET);
+
+ eprint("lost connection to server.");
+ mds_message_destroy(&received);
+ mds_message_initialise(&received);
+ connected = 0;
+ fail_if (reconnect_to_display());
+ connected = 1;
+ }
+
+ rc = 0;
+ goto done;
+ fail:
+ xperror(*argv);
+ done:
+ if (rc || !reexecing)
+ mds_message_destroy(&received);
+ free(send_buffer);
+ return rc;
+}
+
+
+/**
+ * Handle the received message
+ *
+ * @return Zero on success, -1 on error
+ */
+int handle_message(void)
+{
+}
+
+
+/**
+ * Send a full message even if interrupted
+ *
+ * @param message The message to send
+ * @param length The length of the message
+ * @return Zero on success, -1 on error
+ */
+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
+ fail_if ((sent < length) && (errno != EINTR));
+ message += sent;
+ length -= sent;
+ }
+ return 0;
+ fail:
+ xperror(*argv);
+ return -1;
+}
+
+
+/**
+ * This function is called when a signal that
+ * signals that the system to dump state information
+ * and statistics has been received
+ *
+ * @param signo The signal that has been received
+ */
+void received_info(int signo)
+{
+ (void) signo;
+ iprintf("next message ID: %" PRIu32, message_id);
+ iprintf("connected: %s", connected ? "yes" : "no");
+ iprintf("send buffer size: %zu bytes", send_buffer_size);
+}
+
diff --git a/src/mds-colour.h b/src/mds-colour.h
new file mode 100644
index 0000000..f8f7d6e
--- /dev/null
+++ b/src/mds-colour.h
@@ -0,0 +1,44 @@
+/**
+ * mds — A micro-display server
+ * Copyright © 2014, 2015 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_COLOUR_H
+#define MDS_MDS_COLOUR_H
+
+
+#include "mds-base.h"
+
+
+/**
+ * Handle the received message
+ *
+ * @return Zero on success, -1 on error
+ */
+int handle_message(void);
+
+
+/**
+ * Send a full message even if interrupted
+ *
+ * @param message The message to send
+ * @param length The length of the message
+ * @return Zero on success, -1 on error
+ */
+int full_send(const char* message, size_t length);
+
+
+#endif
+