move message handler to ui common

Sun, 30 Nov 2025 21:12:00 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 30 Nov 2025 21:12:00 +0100
changeset 944
cc23aad6335e
parent 943
9b5948aa5b90
child 945
6055c7c677cf

move message handler to ui common

client/Makefile file | annotate | diff | comparison | revisions
client/main.c file | annotate | diff | comparison | revisions
client/main.h file | annotate | diff | comparison | revisions
client/message.c file | annotate | diff | comparison | revisions
client/message.h file | annotate | diff | comparison | revisions
client/uiclient.c file | annotate | diff | comparison | revisions
client/uiclient.h file | annotate | diff | comparison | revisions
configure file | annotate | diff | comparison | revisions
make/configure.vm file | annotate | diff | comparison | revisions
make/project.xml file | annotate | diff | comparison | revisions
make/toolchain.sh file | annotate | diff | comparison | revisions
make/uwproj.xsd file | annotate | diff | comparison | revisions
ui/common/message.c file | annotate | diff | comparison | revisions
ui/common/message.h file | annotate | diff | comparison | revisions
ui/common/objs.mk file | annotate | diff | comparison | revisions
ui/server/Makefile file | annotate | diff | comparison | revisions
ui/server/objs.mk file | annotate | diff | comparison | revisions
ui/server/toolkit.c file | annotate | diff | comparison | revisions
ui/server/toolkit.h file | annotate | diff | comparison | revisions
ui/ui/toolkit.h file | annotate | diff | comparison | revisions
ui/ui/widget.h file | annotate | diff | comparison | revisions
--- a/client/Makefile	Sun Nov 30 18:17:49 2025 +0100
+++ b/client/Makefile	Sun Nov 30 21:12:00 2025 +0100
@@ -32,7 +32,6 @@
 CFLAGS += -I../ui/ -I../ucx
 
 APP_BIN_OBJ = ../build/client/main$(OBJ_EXT)
-APP_BIN_OBJ += ../build/client/message$(OBJ_EXT)
 APP_BIN_OBJ += ../build/client/uiclient$(OBJ_EXT)
 APP_BIN_OBJ += ../build/client/args$(OBJ_EXT)
 
--- a/client/main.c	Sun Nov 30 18:17:49 2025 +0100
+++ b/client/main.c	Sun Nov 30 21:12:00 2025 +0100
@@ -86,7 +86,7 @@
             return 1;
         }
     }
-    MessageHandler *h = simple_msg_handler(in, out, client_msg_received);
+    UiMessageHandler *h = uic_simple_msg_handler(in, out, client_msg_received);
     client_init(h);
     h->start(h);
     
--- a/client/main.h	Sun Nov 30 18:17:49 2025 +0100
+++ b/client/main.h	Sun Nov 30 21:12:00 2025 +0100
@@ -31,7 +31,7 @@
 
 #include <ui/ui.h>
 
-#include "message.h"
+#include "../ui/common/message.h"
 
 #ifdef __cplusplus
 extern "C" {
--- a/client/message.c	Sun Nov 30 18:17:49 2025 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,174 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2025 Olaf Wintermann. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *   1. Redistributions of source code must retain the above copyright
- *      notice, this list of conditions and the following disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above copyright
- *      notice, this list of conditions and the following disclaimer in the
- *      documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "message.h"
-
-MessageHandler* simple_msg_handler(int in, int out, msg_received_callback callback) {
-    SimpleMessageHandler *handler = malloc(sizeof(SimpleMessageHandler));
-    handler->handler.start = simple_msg_handler_start;
-    handler->handler.stop = simple_msg_handler_stop;
-    handler->handler.send = simple_msg_handler_send;
-    handler->handler.callback = callback;
-    handler->in = in;
-    handler->out = out;
-    handler->outbuf = cxBufferCreate(NULL, 4096, NULL, CX_BUFFER_FREE_CONTENTS | CX_BUFFER_AUTO_EXTEND);
-    handler->stop = 0;
-    pthread_mutex_init(&handler->queue_lock, NULL);
-    pthread_mutex_init(&handler->avlbl_lock, NULL);
-    pthread_cond_init(&handler->available, NULL);  
-    return (MessageHandler*)handler;
-}
-
-int simple_msg_handler_start(MessageHandler *handler) {
-    SimpleMessageHandler *sh = (SimpleMessageHandler*)handler;
-    if(pthread_create(&sh->in_thread, NULL, simple_msg_handler_in_thread, sh)) {
-        return 1;
-    }
-    if(pthread_create(&sh->out_thread, NULL, simple_msg_handler_out_thread, sh)) {
-        return 1;
-    }
-    return 0;
-}
-
-int simple_msg_handler_stop(MessageHandler *handler) {
-    SimpleMessageHandler *sh = (SimpleMessageHandler*)handler;
-    pthread_mutex_lock(&sh->queue_lock);
-    sh->stop = 0;
-    pthread_cond_signal(&sh->available);
-    pthread_mutex_unlock(&sh->queue_lock);
-    close(sh->in);
-    sh->in = -1;
-    
-    pthread_join(sh->in_thread, NULL);
-    pthread_join(sh->out_thread, NULL);
-    
-    return 0;
-}
-
-int simple_msg_handler_send(MessageHandler *handler, cxstring msg) {
-    SimpleMessageHandler *sh = (SimpleMessageHandler*)handler;
-    pthread_mutex_lock(&sh->queue_lock);
-    cxBufferWrite(msg.ptr, 1, msg.length, sh->outbuf);
-    pthread_cond_signal(&sh->available);
-    pthread_mutex_unlock(&sh->queue_lock);
-    return 0;
-}
-
-#define HEADERBUF_SIZE 64
-
-void* simple_msg_handler_in_thread(void *data) {
-    SimpleMessageHandler *handler = data;
-    
-    char *msg = NULL;
-    size_t msg_size = 0;
-    size_t msg_pos = 0; // currently received message length
-    
-    char headerbuf[HEADERBUF_SIZE];
-    size_t headerpos = 0;
-    
-    char buf[2048];
-    ssize_t r;
-    while((r = read(handler->in, buf, 2024)) > 0) {
-        char *buffer = buf;
-        size_t available = r;
-        
-        while(available > 0) {
-            if(msg) {
-                // read message
-                size_t need = msg_size - msg_pos;
-                size_t cplen = r > need ? need : available;
-                memcpy(msg+msg_pos, buffer, cplen);
-                buffer += cplen;
-                available -= cplen;
-                msg_pos += cplen;
-                if(msg_pos == msg_size) {
-                    // message complete
-                    //fprintf(stderr, "send: %.*s\n", (int)msg_size, msg);
-                    if(handler->handler.callback) {
-                        handler->handler.callback(cx_mutstrn(msg, msg_size));
-                    }
-                    msg = NULL;
-                    msg_size = 0;
-                    msg_pos = 0;
-                }
-            } else {
-                size_t header_max = HEADERBUF_SIZE - headerpos - 1;
-                if(header_max > available) {
-                    header_max = available;
-                }
-                // search for line break
-                int i;
-                int header_complete = 0;
-                for(i=0;i<header_max;i++) {
-                    if(buffer[i] == '\n') {
-                        header_complete = 1;
-                        break;
-                    }
-                }
-                i++;
-                memcpy(headerbuf+headerpos, buffer, i);
-                headerpos += i;
-                buffer += i;
-                available -= i;
-                
-                if(header_complete) {
-                    headerbuf[headerpos-1] = 0; // terminate buffer
-                    char *end;
-                    long length = strtol(headerbuf, &end, 10);
-                    if(*end == '\0') {
-                        //fprintf(stderr, "header: %d\n", (int)length);
-                        msg = malloc(length);
-                        msg_size = length;
-                        headerpos = 0;
-                    } else {
-                        fprintf(stderr, "Error: invalid message {%s}\n", headerbuf);
-                    }
-                } else if(headerpos+1 >= HEADERBUF_SIZE) {
-                    fprintf(stderr, "Error: message header too big\n");
-                    exit(-1);
-                }
-            }
-        }
-        
-        
-    }
-    perror("error");
-    fprintf(stderr, "stop simple_msg_handler_in_thread\n");
-    
-    return NULL;
-}
-
-void* simple_msg_handler_out_thread(void *data) {
-    SimpleMessageHandler *handler = data;
-    
-    return NULL;
-}
--- a/client/message.h	Sun Nov 30 18:17:49 2025 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2025 Olaf Wintermann. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *   1. Redistributions of source code must retain the above copyright
- *      notice, this list of conditions and the following disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above copyright
- *      notice, this list of conditions and the following disclaimer in the
- *      documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef CLIENT_MESSAGE_H
-#define CLIENT_MESSAGE_H
-
-#include <cx/string.h>
-#include <cx/json.h>
-#include <cx/buffer.h>
-
-#include <pthread.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct MessageHandler MessageHandler;
-
-typedef void(*msg_received_callback)(cxmutstr msg);
-
-struct MessageHandler {
-    int (*start)(MessageHandler *handler);
-    int (*stop)(MessageHandler *handler);
-    int (*send)(MessageHandler *handler, cxstring msg);
-    
-    msg_received_callback callback;
-};
-
-typedef struct SimpleMessageHandler {
-    MessageHandler handler;
-    int in;
-    int out;
-    pthread_t in_thread;
-    pthread_t out_thread;
-    pthread_mutex_t queue_lock;
-    pthread_mutex_t avlbl_lock;
-    pthread_cond_t  available;
-    CxBuffer *outbuf;
-    int stop;
-} SimpleMessageHandler;
-
-MessageHandler* simple_msg_handler(int in, int out, msg_received_callback callback);
-int simple_msg_handler_start(MessageHandler *handler);
-int simple_msg_handler_stop(MessageHandler *handler);
-int simple_msg_handler_send(MessageHandler *handler, cxstring msg);
-
-void* simple_msg_handler_in_thread(void *data);
-void* simple_msg_handler_out_thread(void *data);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* CLIENT_MESSAGE_H */
-
--- a/client/uiclient.c	Sun Nov 30 18:17:49 2025 +0100
+++ b/client/uiclient.c	Sun Nov 30 21:12:00 2025 +0100
@@ -33,12 +33,12 @@
 
 #include "../ui/common/args.h"
 
-static MessageHandler *io;
+static UiMessageHandler *io;
 
 static CxMap *msg_types;
 static CxMap *objects;
 
-void client_init(MessageHandler *handler) {
+void client_init(UiMessageHandler *handler) {
     io = handler;
     
     msg_types = cxHashMapCreateSimple(CX_STORE_POINTERS);
--- a/client/uiclient.h	Sun Nov 30 18:17:49 2025 +0100
+++ b/client/uiclient.h	Sun Nov 30 21:12:00 2025 +0100
@@ -34,7 +34,7 @@
 #include <cx/json.h>
 #include <cx/map.h>
 
-#include "message.h"
+#include "../ui/common/message.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -46,7 +46,7 @@
     
 typedef int (*json_msg_handler)(UiObject *parent, const CxJsonValue *value);
     
-void client_init(MessageHandler *handler);
+void client_init(UiMessageHandler *handler);
     
 void client_msg_received(cxmutstr msg);
 
--- a/configure	Sun Nov 30 18:17:49 2025 +0100
+++ b/configure	Sun Nov 30 21:12:00 2025 +0100
@@ -85,39 +85,21 @@
 printhelp()
 {
     echo "Usage: $0 [OPTIONS]..."
-    cat << __EOF__
-Installation directories:
-  --prefix=PREFIX         path prefix for architecture-independent files
-                          [$prefix]
-  --exec-prefix=EPREFIX   path prefix for architecture-dependent files
-                          [PREFIX]
-
-  --bindir=DIR            user executables [EPREFIX/bin]
-  --sbindir=DIR           system admin executables [EPREFIX/sbin]
-  --libexecdir=DIR        program executables [EPREFIX/libexec]
-  --sysconfdir=DIR        system configuration files [PREFIX/etc]
-  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
-  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
-  --runstatedir=DIR       run-time variable data [LOCALSTATEDIR/run]
-  --libdir=DIR            object code libraries [EPREFIX/lib]
-  --includedir=DIR        C header files [PREFIX/include]
-  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
-  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
-  --infodir=DIR           info documentation [DATAROOTDIR/info]
-  --mandir=DIR            man documentation [DATAROOTDIR/man]
-  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+    echo 'Configuration:'
+    cat << '__EOF__'
 
 Build Types:
   --debug                 add extra compile flags for debug builds
   --release               add extra compile flags for release builds
 
 Options:
-  --toolkit=(libadwaita|gtk4|gtk3|gtk2|gtk2legacy|qt5|qt4|cocoa|motif)
+  --toolkit=(libadwaita|gtk4|gtk3|gtk2|gtk2legacy|qt5|qt4|cocoa|motif|server)
 
 Optional Features:
   --enable-client
 
 __EOF__
+    abort_configure
 }
 
 # create temporary directory
@@ -133,26 +115,7 @@
 touch "$TEMP_DIR/options"
 touch "$TEMP_DIR/features"
 
-# define standard variables
-# also define standard prefix (this is where we will search for config.site)
-prefix=/usr
-exec_prefix=
-bindir=
-sbindir=
-libdir=
-libexecdir=
-datarootdir=
-datadir=
-sysconfdir=
-sharedstatedir=
-localstatedir=
-runstatedir=
-includedir=
-infodir=
-localedir=
-mandir=
-
-# custom variables
+# config variables
 
 # features
 
@@ -163,32 +126,30 @@
 for ARG in "$@"
 do
     case "$ARG" in
-        "--prefix="*)         prefix=${ARG#--prefix=} ;;
-        "--exec-prefix="*)    exec_prefix=${ARG#--exec-prefix=} ;;
-        "--bindir="*)         bindir=${ARG#----bindir=} ;;
-        "--sbindir="*)        sbindir=${ARG#--sbindir=} ;;
-        "--libdir="*)         libdir=${ARG#--libdir=} ;;
-        "--libexecdir="*)     libexecdir=${ARG#--libexecdir=} ;;
-        "--datarootdir="*)    datarootdir=${ARG#--datarootdir=} ;;
-        "--datadir="*)        datadir=${ARG#--datadir=} ;;
-        "--sysconfdir="*)     sysconfdir=${ARG#--sysconfdir=} ;;
-        "--sharedstatedir="*) sharedstatedir=${ARG#--sharedstatedir=} ;;
-        "--localstatedir="*)  localstatedir=${ARG#--localstatedir=} ;;
-        "--includedir="*)     includedir=${ARG#--includedir=} ;;
-        "--infodir="*)        infodir=${ARG#--infodir=} ;;
-        "--mandir"*)          mandir=${ARG#--mandir} ;;
-        "--localedir"*)       localedir=${ARG#--localedir} ;;
-        "--help"*)            printhelp; abort_configure ;;
-        "--debug")            BUILD_TYPE="debug" ;;
-        "--release")          BUILD_TYPE="release" ;;
+        "--help"*) printhelp ;;
+        "--debug") BUILD_TYPE="debug" ;;
+        "--release") BUILD_TYPE="release" ;;
         "--toolkit="*) OPT_TOOLKIT=${ARG#--toolkit=} ;;
-        "--toolkit")  echo "option '$ARG' needs a value:"; echo "  $ARG=(libadwaita|gtk4|gtk3|gtk2|gtk2legacy|qt5|qt4|cocoa|motif)"; abort_configure ;;
+        "--toolkit") echo "option '$ARG' needs a value:"; echo "  $ARG=(libadwaita|gtk4|gtk3|gtk2|gtk2legacy|qt5|qt4|cocoa|motif|server)"; abort_configure ;;
         "--enable-client") FEATURE_CLIENT=on ;;
         "--disable-client") unset FEATURE_CLIENT ;;
         "-"*) echo "unknown option: $ARG"; abort_configure ;;
     esac
 done
 
+# toolchain detection utilities
+. make/toolchain.sh
+
+# check languages
+lang_c=
+lang_cpp=
+if detect_cpp_compiler ; then
+    lang_cpp=1
+fi
+if detect_c_compiler ; then
+    lang_c=1
+fi
+
 
 
 # set defaults for dir variables
@@ -199,67 +160,76 @@
 : ${libexecdir:='${exec_prefix}/libexec'}
 : ${datarootdir:='${prefix}/share'}
 : ${datadir:='${datarootdir}'}
-: ${sysconfdir:='${prefix}/etc'}
 : ${sharedstatedir:='${prefix}/com'}
-: ${localstatedir:='${prefix}/var'}
-: ${runstatedir:='${localstatedir}/run'}
+if [ -z "$sysconfdir" ]; then
+    if [ "$prefix" = '/usr' ]; then
+        sysconfdir='/etc'
+    else
+        sysconfdir='${prefix}/etc'
+    fi
+fi
+if [ -z "$localstatedir" ]; then
+    if [ "$prefix" = '/usr' ]; then
+        localstatedir='/var'
+    else
+        localstatedir='${prefix}/var'
+    fi
+fi
+if [ -z "$runstatedir" ]; then
+    if [ "$prefix" = '/usr' ]; then
+        runstatedir='/var/run'
+    else
+        runstatedir='${prefix}/var'
+    fi
+fi
 : ${includedir:='${prefix}/include'}
 : ${infodir:='${datarootdir}/info'}
 : ${mandir:='${datarootdir}/man'}
 : ${localedir:='${datarootdir}/locale'}
 
-# remember the above values and compare them later
-orig_bindir="$bindir"
-orig_sbindir="$sbindir"
-orig_libdir="$libdir"
-orig_libexecdir="$libexecdir"
-orig_datarootdir="$datarootdir"
-orig_datadir="$datadir"
-orig_sysconfdir="$sysconfdir"
-orig_sharedstatedir="$sharedstatedir"
-orig_localstatedir="$localstatedir"
-orig_runstatedir="$runstatedir"
-orig_includedir="$includedir"
-orig_infodir="$infodir"
-orig_mandir="$mandir"
-orig_localedir="$localedir"
 
 # check if a config.site exists and load it
+CONFIG_SITE_OK=0
 if [ -n "$CONFIG_SITE" ]; then
     # CONFIG_SITE may contain space separated file names
     for cs in $CONFIG_SITE; do
         printf "loading defaults from $cs... "
-        . "$cs"
-        echo ok
+        if [ -f "$cs" ]; then
+            . "$cs"
+            echo ok
+            CONFIG_SITE_OK=1
+            break
+        else
+            echo "not found"
+        fi
     done
 elif [ -f "$prefix/share/config.site" ]; then
     printf "loading site defaults... "
     . "$prefix/share/config.site"
     echo ok
+    CONFIG_SITE_OK=1
 elif [ -f "$prefix/etc/config.site" ]; then
     printf "loading site defaults... "
     . "$prefix/etc/config.site"
     echo ok
-else
+    CONFIG_SITE_OK=1
+fi
+
+if [ $CONFIG_SITE_OK -eq 0 ]; then
     # try to detect the correct libdir on our own, except it was changed by the user
-    if test "$libdir" = '${exec_prefix}/lib'; then
-        if [ "$OS" = "SunOS" ]; then
-            test -d "${exec_prefix}/lib/amd64" && libdir='${exec_prefix}/lib/amd64'
-        else
-            # check if the standard libdir even exists
-            if test -d "${exec_prefix}/lib" ; then
-                :
+    if [ "$libdir" = '${exec_prefix}/lib' ] ; then
+        if [ "$TOOLCHAIN_WSIZE" = "64" ] ; then
+            if [ "$OS" = "SunOS" ]; then
+                [ -d "${exec_prefix}/lib/64" ] && libdir='${exec_prefix}/lib/64'
             else
-                # if it does not, maybe a lib32 exists
-                test -d "${exec_prefix}/lib32" && libdir='${exec_prefix}/lib32'
+                [ -d "${exec_prefix}/lib64" ] && libdir='${exec_prefix}/lib64'
             fi
-            # now check if there is a special 64bit libdir that we should use
-            for i in x86_64 ppc64 s390x aarch64 aarch64_be arm64 ; do
-                if [ $ARCH = $i ]; then
-                    test -d "${exec_prefix}/lib64" && libdir='${exec_prefix}/lib64'
-                    break
-                fi
-            done
+        elif [ "$TOOLCHAIN_WSIZE" = "32" ] ; then
+            if [ "$OS" = "SunOS" ]; then
+                [ -d "${exec_prefix}/lib/32" ] && libdir='${exec_prefix}/lib/32'
+            else
+                [ -d "${exec_prefix}/lib32" ] && libdir='${exec_prefix}/lib32'
+            fi
         fi
     fi
 fi
@@ -267,40 +237,14 @@
 
 # generate vars.mk
 cat > "$TEMP_DIR/vars.mk" << __EOF__
-prefix=$prefix
-exec_prefix=$exec_prefix
-bindir=$bindir
-sbindir=$sbindir
-libdir=$libdir
-libexecdir=$libexecdir
-datarootdir=$datarootdir
-datadir=$datadir
-sysconfdir=$sysconfdir
-sharedstatedir=$sharedstatedir
-localstatedir=$localstatedir
-runstatedir=$runstatedir
-includedir=$includedir
-infodir=$infodir
-mandir=$mandir
-localedir=$localedir
 __EOF__
 
-# toolchain detection utilities
-. make/toolchain.sh
 
 #
 # DEPENDENCIES
 #
 
-# check languages
-lang_c=
-lang_cpp=
-if detect_cpp_compiler ; then
-    lang_cpp=1
-fi
-if detect_c_compiler ; then
-    lang_c=1
-fi
+
 
 # create buffer for make variables required by dependencies
 echo > "$TEMP_DIR/make.mk"
@@ -326,6 +270,22 @@
     fi
 }
 
+dependency_error_server()
+{
+    print_check_msg "$dep_checked_server" "checking for server... "
+    # dependency server
+    while true
+    do
+        TEMP_CFLAGS="$TEMP_CFLAGS -DUI_SERVER -DUI_WEBVIEW"
+        print_check_msg "$dep_checked_server" "yes\n"
+        dep_checked_server=1
+        return 1
+    done
+
+    print_check_msg "$dep_checked_server" "no\n"
+    dep_checked_server=1
+    return 0
+}
 dependency_error_gtk2legacy()
 {
     print_check_msg "$dep_checked_gtk2legacy" "checking for gtk2legacy... "
@@ -364,7 +324,7 @@
         if [ -z "$PKG_CONFIG" ]; then
             break
         fi
-        if which qmake-qt5 > /dev/null ; then
+        if which qmake-qt5 > /dev/null 2>&1 ; then
             :
         else
             break
@@ -399,7 +359,7 @@
         if [ -z "$PKG_CONFIG" ]; then
             break
         fi
-        if pkg-config --atleast-version=2.20 gtk+-2.0 > /dev/null ; then
+        if pkg-config --atleast-version=2.20 gtk+-2.0 > /dev/null 2>&1 ; then
             :
         else
             break
@@ -944,6 +904,20 @@
 __EOF__
     return 0
 }
+checkopt_toolkit_server()
+{
+    VERR=0
+    if dependency_error_server ; then
+        VERR=1
+    fi
+    if [ $VERR -ne 0 ]; then
+        return 1
+    fi
+    cat >> "$TEMP_DIR/make.mk" << __EOF__
+TOOLKIT = server
+__EOF__
+    return 0
+}
 
 #
 # TARGETS
@@ -1090,10 +1064,18 @@
             ERROR=1
             DEPENDENCIES_FAILED="option 'toolkit' $DEPENDENCIES_FAILED"
         fi
+    elif [ "$OPT_TOOLKIT" = "server" ]; then
+        echo "  toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options
+        if checkopt_toolkit_server ; then
+            :
+        else
+            ERROR=1
+            DEPENDENCIES_FAILED="option 'toolkit' $DEPENDENCIES_FAILED"
+        fi
     else
         echo
         echo "Invalid option value - usage:"
-        echo "  --toolkit=(libadwaita|gtk4|gtk3|gtk2|gtk2legacy|qt5|qt4|cocoa|motif)"
+        echo "  --toolkit=(libadwaita|gtk4|gtk3|gtk2|gtk2legacy|qt5|qt4|cocoa|motif|server)"
         abort_configure
     fi
 fi
@@ -1153,7 +1135,7 @@
 
 echo "configure finished"
 echo
-echo "Toolchain"
+echo "Toolchain:"
 echo "  name:           $TOOLCHAIN_NAME"
 if [ -n "$TOOLCHAIN_CC" ]; then
     echo "  cc:             $TOOLCHAIN_CC"
@@ -1168,60 +1150,17 @@
     echo "  default C std:  $TOOLCHAIN_CSTD"
 fi
 echo
-echo "Build Config:"
-echo "  prefix:         $prefix"
-echo "  exec_prefix:    $exec_prefix"
-if [ "$orig_bindir" != "$bindir" ]; then
-    echo "  bindir:      $bindir"
-fi
-if [ "$orig_sbindir" != "$sbindir" ]; then
-    echo "  sbindir:     $sbindir"
-fi
-if [ "$orig_libdir" != "$libdir" ]; then
-    echo "  libdir:         $libdir"
-fi
-if [ "$orig_libexecdir" != "$libexecdir" ]; then
-    echo "  libexecdir:     $libexecdir"
-fi
-if [ "$orig_datarootdir" != "$datarootdir" ]; then
-    echo "  datarootdir:    $datarootdir"
-fi
-if [ "$orig_datadir" != "$datadir" ]; then
-    echo "  datadir:        $datadir"
-fi
-if [ "$orig_sysconfdir" != "$sysconfdir" ]; then
-    echo "  sysconfdir:     $sysconfdir"
-fi
-if [ "$orig_sharedstatedir" != "$sharedstatedir" ]; then
-    echo "  sharedstatedir: $sharedstatedir"
-fi
-if [ "$orig_localstatedir" != "$localstatedir" ]; then
-    echo "  localstatedir:  $localstatedir"
-fi
-if [ "$orig_runstatedir" != "$runstatedir" ]; then
-    echo "  runstatedir:    $runstatedir"
-fi
-if [ "$orig_includedir" != "$includedir" ]; then
-    echo "  includedir:     $includedir"
-fi
-if [ "$orig_infodir" != "$infodir" ]; then
-    echo "  infodir:        $infodir"
-fi
-if [ "$orig_mandir" != "$mandir" ]; then
-    echo "  mandir:         $mandir"
-fi
-if [ "$orig_localedir" != "$localedir" ]; then
-    echo "  localedir:      $localedir"
-fi
+echo "Config:"
 echo
 echo "Options:"
 cat "$TEMP_DIR/options"
 echo
 echo "Features:"
+printf '  %-16s' 'client:'
 if [ -n "$FEATURE_CLIENT" ]; then
-echo "  client: on"
+    echo 'on'
 else
-echo "  client: off"
+    echo 'off'
 fi
 echo
 
--- a/make/configure.vm	Sun Nov 30 18:17:49 2025 +0100
+++ b/make/configure.vm	Sun Nov 30 21:12:00 2025 +0100
@@ -86,27 +86,30 @@
 printhelp()
 {
     echo "Usage: $0 [OPTIONS]..."
-    cat << __EOF__
-Installation directories:
-  --prefix=PREFIX         path prefix for architecture-independent files
-                          [${D}prefix]
-  --exec-prefix=EPREFIX   path prefix for architecture-dependent files
-                          [PREFIX]
-
-  --bindir=DIR            user executables [EPREFIX/bin]
-  --sbindir=DIR           system admin executables [EPREFIX/sbin]
-  --libexecdir=DIR        program executables [EPREFIX/libexec]
-  --sysconfdir=DIR        system configuration files [PREFIX/etc]
-  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
-  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
-  --runstatedir=DIR       run-time variable data [LOCALSTATEDIR/run]
-  --libdir=DIR            object code libraries [EPREFIX/lib]
-  --includedir=DIR        C header files [PREFIX/include]
-  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
-  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
-  --infodir=DIR           info documentation [DATAROOTDIR/info]
-  --mandir=DIR            man documentation [DATAROOTDIR/man]
-  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+    echo 'Configuration:'
+#foreach( $cfg in $config )
+if true \
+#if( $cfg.platform )
+    && isplatform "${cfg.platform}" \
+#end
+#foreach( $np in $cfg.notList )
+      && notisplatform "${np}" \
+#end
+      ; then
+    :
+    #foreach( $var in $cfg.vars )
+    #if( $var.overridable )
+    if test -z "${D}${var.varName}__described__"; then
+        ${var.varName}__described__=1
+        cat << '__EOF__'
+${var.helpText}
+__EOF__
+    fi
+    #end
+    #end
+fi
+#end
+    cat << '__EOF__'
 
 Build Types:
   --debug                 add extra compile flags for debug builds
@@ -115,7 +118,7 @@
 
 Options:
 #foreach( $opt in $options )
-  --${opt.argument}=${opt.valuesString}
+${opt.helpText}
 #end
 #end
 #if( $features.size() > 0 )
@@ -127,6 +130,7 @@
 #end
 
 __EOF__
+    abort_configure
 }
 
 # create temporary directory
@@ -142,26 +146,7 @@
 touch "$TEMP_DIR/options"
 touch "$TEMP_DIR/features"
 
-# define standard variables
-# also define standard prefix (this is where we will search for config.site)
-prefix=/usr
-exec_prefix=
-bindir=
-sbindir=
-libdir=
-libexecdir=
-datarootdir=
-datadir=
-sysconfdir=
-sharedstatedir=
-localstatedir=
-runstatedir=
-includedir=
-infodir=
-localedir=
-mandir=
-
-# custom variables
+# config variables
 #foreach( $cfg in $config )
 if true \
 #if( $cfg.platform )
@@ -171,12 +156,16 @@
       && notisplatform "${np}" \
 #end
       ; then
+    :
     #foreach( $var in $cfg.vars )
-    #if( $var.exec )
-    ${var.varName}=`${var.value}`
-    #else
-    ${var.varName}="${var.value}"
-    #end
+    if test -z "${D}${var.varName}__initialized__"; then
+        ${var.varName}__initialized__=1
+        #if( $var.exec )
+        ${var.varName}=`${var.value}`
+        #else
+        ${var.varName}='${var.value}'
+        #end
+    fi
     #end
 fi
 #end
@@ -195,27 +184,17 @@
 for ARG in "$@"
 do
     case "$ARG" in
-        "--prefix="*)         prefix=${D}{ARG#--prefix=} ;;
-        "--exec-prefix="*)    exec_prefix=${D}{ARG#--exec-prefix=} ;;
-        "--bindir="*)         bindir=${D}{ARG#----bindir=} ;;
-        "--sbindir="*)        sbindir=${D}{ARG#--sbindir=} ;;
-        "--libdir="*)         libdir=${D}{ARG#--libdir=} ;;
-        "--libexecdir="*)     libexecdir=${D}{ARG#--libexecdir=} ;;
-        "--datarootdir="*)    datarootdir=${D}{ARG#--datarootdir=} ;;
-        "--datadir="*)        datadir=${D}{ARG#--datadir=} ;;
-        "--sysconfdir="*)     sysconfdir=${D}{ARG#--sysconfdir=} ;;
-        "--sharedstatedir="*) sharedstatedir=${D}{ARG#--sharedstatedir=} ;;
-        "--localstatedir="*)  localstatedir=${D}{ARG#--localstatedir=} ;;
-        "--includedir="*)     includedir=${D}{ARG#--includedir=} ;;
-        "--infodir="*)        infodir=${D}{ARG#--infodir=} ;;
-        "--mandir"*)          mandir=${D}{ARG#--mandir} ;;
-        "--localedir"*)       localedir=${D}{ARG#--localedir} ;;
-        "--help"*)            printhelp; abort_configure ;;
-        "--debug")            BUILD_TYPE="debug" ;;
-        "--release")          BUILD_TYPE="release" ;;
+    #foreach( $var in $vars )
+    #if ($var.overridable)
+        "--${var.arg}="*) ${var.varName}=${D}{ARG#--${var.arg}=} ;;
+    #end
+    #end
+        "--help"*) printhelp ;;
+        "--debug") BUILD_TYPE="debug" ;;
+        "--release") BUILD_TYPE="release" ;;
     #foreach( $opt in $options )
-        "--${opt.argument}="*) ${opt.varName}=${D}{ARG#--${opt.argument}=} ;;
-        "--${opt.argument}")  echo "option '$ARG' needs a value:"; echo "  $ARG=${opt.valuesString}"; abort_configure ;;
+        "--${opt.arg}="*) ${opt.varName}=${D}{ARG#--${opt.arg}=} ;;
+        "--${opt.arg}") echo "option '$ARG' needs a value:"; echo "  $ARG=${opt.valuesString}"; abort_configure ;;
     #end
     #foreach( $feature in $features )
         "--enable-${feature.arg}") ${feature.varName}=on ;;
@@ -225,6 +204,18 @@
     esac
 done
 
+# toolchain detection utilities
+. make/toolchain.sh
+
+# check languages
+lang_c=
+lang_cpp=
+#foreach( $lang in $languages )
+if detect_${lang}_compiler ; then
+    lang_${lang}=1
+fi
+#end
+
 ## Begin unparsed content. **
 #[[
 
@@ -236,67 +227,76 @@
 : ${libexecdir:='${exec_prefix}/libexec'}
 : ${datarootdir:='${prefix}/share'}
 : ${datadir:='${datarootdir}'}
-: ${sysconfdir:='${prefix}/etc'}
 : ${sharedstatedir:='${prefix}/com'}
-: ${localstatedir:='${prefix}/var'}
-: ${runstatedir:='${localstatedir}/run'}
+if [ -z "$sysconfdir" ]; then
+    if [ "$prefix" = '/usr' ]; then
+        sysconfdir='/etc'
+    else
+        sysconfdir='${prefix}/etc'
+    fi
+fi
+if [ -z "$localstatedir" ]; then
+    if [ "$prefix" = '/usr' ]; then
+        localstatedir='/var'
+    else
+        localstatedir='${prefix}/var'
+    fi
+fi
+if [ -z "$runstatedir" ]; then
+    if [ "$prefix" = '/usr' ]; then
+        runstatedir='/var/run'
+    else
+        runstatedir='${prefix}/var'
+    fi
+fi
 : ${includedir:='${prefix}/include'}
 : ${infodir:='${datarootdir}/info'}
 : ${mandir:='${datarootdir}/man'}
 : ${localedir:='${datarootdir}/locale'}
 
-# remember the above values and compare them later
-orig_bindir="$bindir"
-orig_sbindir="$sbindir"
-orig_libdir="$libdir"
-orig_libexecdir="$libexecdir"
-orig_datarootdir="$datarootdir"
-orig_datadir="$datadir"
-orig_sysconfdir="$sysconfdir"
-orig_sharedstatedir="$sharedstatedir"
-orig_localstatedir="$localstatedir"
-orig_runstatedir="$runstatedir"
-orig_includedir="$includedir"
-orig_infodir="$infodir"
-orig_mandir="$mandir"
-orig_localedir="$localedir"
 
 # check if a config.site exists and load it
+CONFIG_SITE_OK=0
 if [ -n "$CONFIG_SITE" ]; then
     # CONFIG_SITE may contain space separated file names
     for cs in $CONFIG_SITE; do
         printf "loading defaults from $cs... "
-        . "$cs"
-        echo ok
+        if [ -f "$cs" ]; then
+            . "$cs"
+            echo ok
+            CONFIG_SITE_OK=1
+            break
+        else
+            echo "not found"
+        fi
     done
 elif [ -f "$prefix/share/config.site" ]; then
     printf "loading site defaults... "
     . "$prefix/share/config.site"
     echo ok
+    CONFIG_SITE_OK=1
 elif [ -f "$prefix/etc/config.site" ]; then
     printf "loading site defaults... "
     . "$prefix/etc/config.site"
     echo ok
-else
+    CONFIG_SITE_OK=1
+fi
+
+if [ $CONFIG_SITE_OK -eq 0 ]; then
     # try to detect the correct libdir on our own, except it was changed by the user
-    if test "$libdir" = '${exec_prefix}/lib'; then
-        if [ "$OS" = "SunOS" ]; then
-            test -d "${exec_prefix}/lib/amd64" && libdir='${exec_prefix}/lib/amd64'
-        else
-            # check if the standard libdir even exists
-            if test -d "${exec_prefix}/lib" ; then
-                :
+    if [ "$libdir" = '${exec_prefix}/lib' ] ; then
+        if [ "$TOOLCHAIN_WSIZE" = "64" ] ; then
+            if [ "$OS" = "SunOS" ]; then
+                [ -d "${exec_prefix}/lib/64" ] && libdir='${exec_prefix}/lib/64'
             else
-                # if it does not, maybe a lib32 exists
-                test -d "${exec_prefix}/lib32" && libdir='${exec_prefix}/lib32'
+                [ -d "${exec_prefix}/lib64" ] && libdir='${exec_prefix}/lib64'
             fi
-            # now check if there is a special 64bit libdir that we should use
-            for i in x86_64 ppc64 s390x aarch64 aarch64_be arm64 ; do
-                if [ $ARCH = $i ]; then
-                    test -d "${exec_prefix}/lib64" && libdir='${exec_prefix}/lib64'
-                    break
-                fi
-            done
+        elif [ "$TOOLCHAIN_WSIZE" = "32" ] ; then
+            if [ "$OS" = "SunOS" ]; then
+                [ -d "${exec_prefix}/lib/32" ] && libdir='${exec_prefix}/lib/32'
+            else
+                [ -d "${exec_prefix}/lib32" ] && libdir='${exec_prefix}/lib32'
+            fi
         fi
     fi
 fi
@@ -305,42 +305,17 @@
 
 # generate vars.mk
 cat > "$TEMP_DIR/vars.mk" << __EOF__
-prefix=$prefix
-exec_prefix=$exec_prefix
-bindir=$bindir
-sbindir=$sbindir
-libdir=$libdir
-libexecdir=$libexecdir
-datarootdir=$datarootdir
-datadir=$datadir
-sysconfdir=$sysconfdir
-sharedstatedir=$sharedstatedir
-localstatedir=$localstatedir
-runstatedir=$runstatedir
-includedir=$includedir
-infodir=$infodir
-mandir=$mandir
-localedir=$localedir
 #foreach( $var in $vars )
 ${var.varName}=${D}${var.varName}
 #end
 __EOF__
 
-# toolchain detection utilities
-. make/toolchain.sh
 
 #
 # DEPENDENCIES
 #
 
-# check languages
-lang_c=
-lang_cpp=
-#foreach( $lang in $languages )
-if detect_${lang}_compiler ; then
-    lang_${lang}=1
-fi
-#end
+
 
 # create buffer for make variables required by dependencies
 echo > "$TEMP_DIR/make.mk"
@@ -400,7 +375,7 @@
         fi
         #end
         #foreach( $test in $sub.tests )
-        if $test > /dev/null ; then
+        if $test > /dev/null 2>&1 ; then
             :
         else
             break
@@ -502,7 +477,6 @@
 
         #foreach( $flags in $dependency.flags )
         #if( $flags.exec )
-        $flags.value > /dev/null
         if tmp_flags=`$flags.value` ; then
             TEMP_$flags.varName="$TEMP_$flags.varName $tmp_flags"
         else
@@ -652,9 +626,9 @@
 #end
 
 #foreach( $opt in $target.options )
-# Option: --${opt.argument}
+# Option: --${opt.arg}
 if [ -z "${D}${opt.varName}" ]; then
-    echo "auto-detecting option '${opt.argument}'"
+    echo "auto-detecting option '${opt.arg}'"
     SAVED_ERROR="$ERROR"
     SAVED_DEPENDENCIES_FAILED="$DEPENDENCIES_FAILED"
     ERROR=1
@@ -665,7 +639,7 @@
         if isplatform "$optdef.platform"; then
         #end
         if $optdef.func ; then
-            echo "  ${opt.argument}: ${optdef.valueName}" >> "$TEMP_DIR/options"
+            echo "  ${opt.arg}: ${optdef.valueName}" >> "$TEMP_DIR/options"
             ERROR=0
             break
         fi
@@ -677,28 +651,28 @@
     done
     if [ $ERROR -ne 0 ]; then
         SAVED_ERROR=1
-        SAVED_DEPENDENCIES_FAILED="option '${opt.argument}' $SAVED_DEPENDENCIES_FAILED"
+        SAVED_DEPENDENCIES_FAILED="option '${opt.arg}' $SAVED_DEPENDENCIES_FAILED"
     fi
     ERROR="$SAVED_ERROR"
     DEPENDENCIES_FAILED="$SAVED_DEPENDENCIES_FAILED"
 else
-    echo "checking option ${opt.argument} = ${D}${opt.varName}"
+    echo "checking option ${opt.arg} = ${D}${opt.varName}"
     if false; then
         false
     #foreach( $optval in $opt.values )
     elif [ "${D}${opt.varName}" = "${optval.value}" ]; then
-        echo "  ${opt.argument}: ${D}${opt.varName}" >> $TEMP_DIR/options
+        echo "  ${opt.arg}: ${D}${opt.varName}" >> $TEMP_DIR/options
         if $optval.func ; then
             :
         else
             ERROR=1
-            DEPENDENCIES_FAILED="option '${opt.argument}' $DEPENDENCIES_FAILED"
+            DEPENDENCIES_FAILED="option '${opt.arg}' $DEPENDENCIES_FAILED"
         fi
     #end
     else
         echo
         echo "Invalid option value - usage:"
-        echo "  --${opt.argument}=${opt.valuesString}"
+        echo "  --${opt.arg}=${opt.valuesString}"
         abort_configure
     fi
 fi
@@ -726,7 +700,7 @@
 
 echo "configure finished"
 echo
-echo "Toolchain"
+echo "Toolchain:"
 echo "  name:           $TOOLCHAIN_NAME"
 if [ -n "$TOOLCHAIN_CC" ]; then
     echo "  cc:             $TOOLCHAIN_CC"
@@ -741,51 +715,13 @@
     echo "  default C std:  $TOOLCHAIN_CSTD"
 fi
 echo
-echo "Build Config:"
-echo "  prefix:         $prefix"
-echo "  exec_prefix:    $exec_prefix"
-if [ "$orig_bindir" != "$bindir" ]; then
-    echo "  bindir:      $bindir"
-fi
-if [ "$orig_sbindir" != "$sbindir" ]; then
-    echo "  sbindir:     $sbindir"
-fi
-if [ "$orig_libdir" != "$libdir" ]; then
-    echo "  libdir:         $libdir"
-fi
-if [ "$orig_libexecdir" != "$libexecdir" ]; then
-    echo "  libexecdir:     $libexecdir"
-fi
-if [ "$orig_datarootdir" != "$datarootdir" ]; then
-    echo "  datarootdir:    $datarootdir"
-fi
-if [ "$orig_datadir" != "$datadir" ]; then
-    echo "  datadir:        $datadir"
-fi
-if [ "$orig_sysconfdir" != "$sysconfdir" ]; then
-    echo "  sysconfdir:     $sysconfdir"
-fi
-if [ "$orig_sharedstatedir" != "$sharedstatedir" ]; then
-    echo "  sharedstatedir: $sharedstatedir"
-fi
-if [ "$orig_localstatedir" != "$localstatedir" ]; then
-    echo "  localstatedir:  $localstatedir"
-fi
-if [ "$orig_runstatedir" != "$runstatedir" ]; then
-    echo "  runstatedir:    $runstatedir"
-fi
-if [ "$orig_includedir" != "$includedir" ]; then
-    echo "  includedir:     $includedir"
-fi
-if [ "$orig_infodir" != "$infodir" ]; then
-    echo "  infodir:        $infodir"
-fi
-if [ "$orig_mandir" != "$mandir" ]; then
-    echo "  mandir:         $mandir"
-fi
-if [ "$orig_localedir" != "$localedir" ]; then
-    echo "  localedir:      $localedir"
-fi
+echo "Config:"
+#foreach( $var in $vars )
+#if ($var.overridable)
+    printf '  %-16s' '${var.arg}:'
+    echo "${D}${var.varName}"
+#end
+#end
 #if ( $options.size() > 0 )
 echo
 echo "Options:"
@@ -795,10 +731,11 @@
 echo
 echo "Features:"
 #foreach( $feature in $features )
+printf '  %-16s' '$feature.name:'
 if [ -n "${D}${feature.varName}" ]; then
-echo "  $feature.name: on"
+    echo 'on'
 else
-echo "  $feature.name: off"
+    echo 'off'
 fi
 #end
 #end
--- a/make/project.xml	Sun Nov 30 18:17:49 2025 +0100
+++ b/make/project.xml	Sun Nov 30 21:12:00 2025 +0100
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project version="0.3" xmlns="http://unixwork.de/uwproj">
+<project version="0.4" xmlns="http://unixwork.de/uwproj">
 	<dependency>
 		<lang>c</lang>
 		<make>LD = \$(CC)</make>
@@ -96,6 +96,10 @@
 		<!-- webview unsupported -->
 	</dependency>
 	
+	<dependency name="server">
+		<cflags>-DUI_SERVER -DUI_WEBVIEW</cflags>
+	</dependency>
+	
 	<dependency platform="macos">
 		<make>OBJ_EXT = .o</make>
 		<make>LIB_EXT = .a</make>
@@ -165,6 +169,10 @@
 				<dependencies>motif</dependencies>
 				<make>TOOLKIT = motif</make>
 			</value>
+			<value str="server">
+				<dependencies>server</dependencies>
+				<make>TOOLKIT = server</make>
+			</value>
 			<default value="winui" platform="windows" />
 			<default value="cocoa" platform="macos" />
 			<default value="gtk4" />
--- a/make/toolchain.sh	Sun Nov 30 18:17:49 2025 +0100
+++ b/make/toolchain.sh	Sun Nov 30 21:12:00 2025 +0100
@@ -24,8 +24,9 @@
 
 check_c_compiler()
 {
-  command -v "$1" >/dev/null 2>&1
-  if [ $? -ne 0 ] ; then
+  if command -v "$1" >/dev/null 2>&1 ; then
+    :
+  else
     return 1
   fi
   cat > "$TEMP_DIR/test.c" << __EOF__
@@ -56,8 +57,9 @@
 
 check_cpp_compiler()
 {
-  command -v "$1" >/dev/null 2>&1
-  if [ $? -ne 0 ] ; then
+  if command -v "$1" >/dev/null 2>&1 ; then
+    :
+  else
     return 1
   fi
   cat > "$TEMP_DIR/test.cpp" << __EOF__
--- a/make/uwproj.xsd	Sun Nov 30 18:17:49 2025 +0100
+++ b/make/uwproj.xsd	Sun Nov 30 21:12:00 2025 +0100
@@ -3,7 +3,7 @@
            xmlns="http://unixwork.de/uwproj"
            targetNamespace="http://unixwork.de/uwproj"
            elementFormDefault="qualified"
-           version="0.3"
+           version="0.4"
 >
     <xs:element name="project" type="ProjectType"/>
 
@@ -29,23 +29,61 @@
             <xs:documentation>
                 <p>
                     The configuration section.
-                    Consists of an arbitrary number of <code>var</code> elements.
+                    Consists of an arbitrary number of <code>var</code> elements and pre-defined elements for
+                    standard installation directories. If you want to use standard installation directories, you
+                    must list the wanted variables here.
                 </p>
                 <p>
                     The optional <code>platform</code> attribute may specify a <em>single</em> platform identifier and
                     the optional <code>not</code> attribute may specify a comma-separated list of platform identifiers.
                     The configure script shall skip this config declaration if the detected platform is not matching
                     the filter specification of these attributes.
+                    When multiple config sections have a matching filter, and declare the same variables, the settings
+                    of the first matching config section will be used for the affected variables.
                 </p>
             </xs:documentation>
         </xs:annotation>
         <xs:sequence>
+            <xs:element name="prefix" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="exec-prefix" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="bindir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="sbindir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="libdir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="libexecdir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="datarootdir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="datadir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="sysconfdir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="sharedstatedir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="localstatedir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="runstatedir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="includedir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="infodir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="localedir" type="StandardConfigVarType" minOccurs="0"/>
+            <xs:element name="mandir" type="StandardConfigVarType" minOccurs="0"/>
             <xs:element name="var" type="ConfigVarType" minOccurs="0" maxOccurs="unbounded"/>
         </xs:sequence>
         <xs:attribute name="platform" type="xs:string"/>
         <xs:attribute name="not" type="xs:string"/>
     </xs:complexType>
 
+    <xs:complexType name="StandardConfigVarType">
+        <xs:annotation>
+            <xs:documentation>
+                The definition of a standard configuration variable.
+                <p>
+                    You may customize the value and the help text,
+                    but the variable name and the option name are pre-defined.
+                </p>
+            </xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="option-help" type="xs:string"/>
+                <xs:attribute name="exec" type="xs:boolean" default="false"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
     <xs:complexType name="ConfigVarType">
         <xs:annotation>
             <xs:documentation>
@@ -55,14 +93,23 @@
                     written to the resulting config file (in contrast to make variables, which are only
                     written to the config file).
                     The <code>name</code> attribute is mandatory, the value is defined by the text body of the element.
-                    The optional Boolean <code>exec</code> attribute (false by default) controls, whether the entire
-                    definition is automatically executed under command substitution.
+                    The optional Boolean <code>exec</code> attribute (false by default) controls, whether value denotes
+                    a command which shall be executed at configuration time to produce the value.
+                    With <code>option</code> and <code>option-help</code> you can control how the variable can be
+                    overridden on the command line. When you don't specify either of those attributes, no command
+                    line option will be generated. When you provide a <code>option-help</code>, but do not specify the
+                    <code>option</code> name, a name is generated.
+                    You can use the string <code>%default</code> in your help text when you want to show the default
+                    value in the text. When <code>exec</code> is used, the default will not be resolved in the help
+                    text and instead the command is shown (to avoid breaking the formatting).
                 </p>
             </xs:documentation>
         </xs:annotation>
         <xs:simpleContent>
             <xs:extension base="xs:string">
                 <xs:attribute name="name" type="xs:string" use="required"/>
+                <xs:attribute name="option" type="xs:string"/>
+                <xs:attribute name="option-help" type="xs:string"/>
                 <xs:attribute name="exec" type="xs:boolean" default="false"/>
             </xs:extension>
         </xs:simpleContent>
@@ -228,7 +275,9 @@
             <xs:documentation>
                 Declares a configuration option.
                 The option argument name is specified with the <code>arg</code> attribute.
-                Then, the children of this element specify possible <code>values</code> by defining the conditions
+                Optionally, a description for the help text of the resulting configure script can be specified by
+                a <code>desc</code> element.
+                Then, the next children of this element specify possible <code>values</code> by defining the conditions
                 (in terms of dependencies) and effects (in terms of defines and make variables) of each value.
                 Finally, a set of <code>default</code>s is specified which supposed to automagically select the most
                 appropriate value for a specific platform under the available dependencies (in case the option is not
@@ -236,6 +285,7 @@
             </xs:documentation>
         </xs:annotation>
         <xs:sequence>
+            <xs:element name="desc" type="xs:string" minOccurs="0"/>
             <xs:element name="value" type="OptionValueType" minOccurs="0" maxOccurs="unbounded"/>
             <xs:element name="default" type="OptionDefaultType" minOccurs="0" maxOccurs="unbounded"/>
         </xs:sequence>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/common/message.c	Sun Nov 30 21:12:00 2025 +0100
@@ -0,0 +1,174 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "message.h"
+
+UiMessageHandler* uic_simple_msg_handler(int in, int out, msg_received_callback callback) {
+    UiSimpleMessageHandler *handler = malloc(sizeof(UiSimpleMessageHandler));
+    handler->handler.start = uic_simple_msg_handler_start;
+    handler->handler.stop = uic_simple_msg_handler_stop;
+    handler->handler.send = uic_simple_msg_handler_send;
+    handler->handler.callback = callback;
+    handler->in = in;
+    handler->out = out;
+    handler->outbuf = cxBufferCreate(NULL, 4096, NULL, CX_BUFFER_FREE_CONTENTS | CX_BUFFER_AUTO_EXTEND);
+    handler->stop = 0;
+    pthread_mutex_init(&handler->queue_lock, NULL);
+    pthread_mutex_init(&handler->avlbl_lock, NULL);
+    pthread_cond_init(&handler->available, NULL);  
+    return (UiMessageHandler*)handler;
+}
+
+int uic_simple_msg_handler_start(UiMessageHandler *handler) {
+    UiSimpleMessageHandler *sh = (UiSimpleMessageHandler*)handler;
+    if(pthread_create(&sh->in_thread, NULL, uic_simple_msg_handler_in_thread, sh)) {
+        return 1;
+    }
+    if(pthread_create(&sh->out_thread, NULL, uic_simple_msg_handler_out_thread, sh)) {
+        return 1;
+    }
+    return 0;
+}
+
+int uic_simple_msg_handler_stop(UiMessageHandler *handler) {
+    UiSimpleMessageHandler *sh = (UiSimpleMessageHandler*)handler;
+    pthread_mutex_lock(&sh->queue_lock);
+    sh->stop = 0;
+    pthread_cond_signal(&sh->available);
+    pthread_mutex_unlock(&sh->queue_lock);
+    close(sh->in);
+    sh->in = -1;
+    
+    pthread_join(sh->in_thread, NULL);
+    pthread_join(sh->out_thread, NULL);
+    
+    return 0;
+}
+
+int uic_simple_msg_handler_send(UiMessageHandler *handler, cxstring msg) {
+    UiSimpleMessageHandler *sh = (UiSimpleMessageHandler*)handler;
+    pthread_mutex_lock(&sh->queue_lock);
+    cxBufferWrite(msg.ptr, 1, msg.length, sh->outbuf);
+    pthread_cond_signal(&sh->available);
+    pthread_mutex_unlock(&sh->queue_lock);
+    return 0;
+}
+
+#define HEADERBUF_SIZE 64
+
+void* uic_simple_msg_handler_in_thread(void *data) {
+    UiSimpleMessageHandler *handler = data;
+    
+    char *msg = NULL;
+    size_t msg_size = 0;
+    size_t msg_pos = 0; // currently received message length
+    
+    char headerbuf[HEADERBUF_SIZE];
+    size_t headerpos = 0;
+    
+    char buf[2048];
+    ssize_t r;
+    while((r = read(handler->in, buf, 2024)) > 0) {
+        char *buffer = buf;
+        size_t available = r;
+        
+        while(available > 0) {
+            if(msg) {
+                // read message
+                size_t need = msg_size - msg_pos;
+                size_t cplen = r > need ? need : available;
+                memcpy(msg+msg_pos, buffer, cplen);
+                buffer += cplen;
+                available -= cplen;
+                msg_pos += cplen;
+                if(msg_pos == msg_size) {
+                    // message complete
+                    //fprintf(stderr, "send: %.*s\n", (int)msg_size, msg);
+                    if(handler->handler.callback) {
+                        handler->handler.callback(cx_mutstrn(msg, msg_size));
+                    }
+                    msg = NULL;
+                    msg_size = 0;
+                    msg_pos = 0;
+                }
+            } else {
+                size_t header_max = HEADERBUF_SIZE - headerpos - 1;
+                if(header_max > available) {
+                    header_max = available;
+                }
+                // search for line break
+                int i;
+                int header_complete = 0;
+                for(i=0;i<header_max;i++) {
+                    if(buffer[i] == '\n') {
+                        header_complete = 1;
+                        break;
+                    }
+                }
+                i++;
+                memcpy(headerbuf+headerpos, buffer, i);
+                headerpos += i;
+                buffer += i;
+                available -= i;
+                
+                if(header_complete) {
+                    headerbuf[headerpos-1] = 0; // terminate buffer
+                    char *end;
+                    long length = strtol(headerbuf, &end, 10);
+                    if(*end == '\0') {
+                        //fprintf(stderr, "header: %d\n", (int)length);
+                        msg = malloc(length);
+                        msg_size = length;
+                        headerpos = 0;
+                    } else {
+                        fprintf(stderr, "Error: invalid message {%s}\n", headerbuf);
+                    }
+                } else if(headerpos+1 >= HEADERBUF_SIZE) {
+                    fprintf(stderr, "Error: message header too big\n");
+                    exit(-1);
+                }
+            }
+        }
+        
+        
+    }
+    perror("error");
+    fprintf(stderr, "stop simple_msg_handler_in_thread\n");
+    
+    return NULL;
+}
+
+void* uic_simple_msg_handler_out_thread(void *data) {
+    UiSimpleMessageHandler *handler = data;
+    
+    return NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/common/message.h	Sun Nov 30 21:12:00 2025 +0100
@@ -0,0 +1,83 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UIC_MESSAGE_H
+#define UIC_MESSAGE_H
+
+#include <cx/string.h>
+#include <cx/json.h>
+#include <cx/buffer.h>
+
+#include <pthread.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct UiMessageHandler UiMessageHandler;
+
+typedef void(*msg_received_callback)(cxmutstr msg);
+
+struct UiMessageHandler {
+    int (*start)(UiMessageHandler *handler);
+    int (*stop)(UiMessageHandler *handler);
+    int (*send)(UiMessageHandler *handler, cxstring msg);
+    
+    msg_received_callback callback;
+};
+
+typedef struct UiSimpleMessageHandler {
+    UiMessageHandler handler;
+    int in;
+    int out;
+    pthread_t in_thread;
+    pthread_t out_thread;
+    pthread_mutex_t queue_lock;
+    pthread_mutex_t avlbl_lock;
+    pthread_cond_t  available;
+    CxBuffer *outbuf;
+    int stop;
+} UiSimpleMessageHandler;
+
+UiMessageHandler* uic_simple_msg_handler(int in, int out, msg_received_callback callback);
+int uic_simple_msg_handler_start(UiMessageHandler *handler);
+int uic_simple_msg_handler_stop(UiMessageHandler *handler);
+int uic_simple_msg_handler_send(UiMessageHandler *handler, cxstring msg);
+
+void* uic_simple_msg_handler_in_thread(void *data);
+void* uic_simple_msg_handler_out_thread(void *data);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UIC_MESSAGE_H */
+
--- a/ui/common/objs.mk	Sun Nov 30 18:17:49 2025 +0100
+++ b/ui/common/objs.mk	Sun Nov 30 21:12:00 2025 +0100
@@ -43,6 +43,7 @@
 COMMON_OBJ += args$(OBJ_EXT)
 COMMON_OBJ += wrapper$(OBJ_EXT)
 COMMON_OBJ += utils$(OBJ_EXT)
+COMMON_OBJ += message$(OBJ_EXT)
 
 TOOLKITOBJS += $(COMMON_OBJ:%=$(COMMON_OBJPRE)uic_%)
 TOOLKITSOURCE += $(COMMON_OBJ:%$(OBJ_EXT)=common/%.c)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/server/Makefile	Sun Nov 30 21:12:00 2025 +0100
@@ -0,0 +1,36 @@
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright 2012 Olaf Wintermann. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+#   1. Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#   2. Redistributions in binary form must reproduce the above copyright
+#      notice, this list of conditions and the following disclaimer in the
+#      documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+$(SERVER_OBJPRE)%.o: server/%.c
+	$(CC) -o $@ -c -I../ucx $(CFLAGS) $(SHLIB_CFLAGS) $(TK_CFLAGS) $<
+
+$(UI_LIB): $(OBJ)
+	$(AR) $(ARFLAGS) $(UI_LIB) $(OBJ)	
+
+$(UI_SHLIB): $(OBJ)
+	$(CC) -o $(UI_SHLIB) $(LDFLAGS) $(SHLIB_LDFLAGS) $(TK_LDFLAGS) $(OBJ) -L../build/lib -lucx
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/server/objs.mk	Sun Nov 30 21:12:00 2025 +0100
@@ -0,0 +1,35 @@
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright 2012 Olaf Wintermann. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+#   1. Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#   2. Redistributions in binary form must reproduce the above copyright
+#      notice, this list of conditions and the following disclaimer in the
+#      documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+SERVER_SRC_DIR = ui/server/
+SERVER_OBJPRE = $(OBJ_DIR)$(SERVER_SRC_DIR)
+
+SERVEROBJ = toolkit.o
+
+TOOLKITOBJS += $(SERVEROBJ:%=$(SERVER_OBJPRE)%)
+TOOLKITSOURCE += $(SERVEROBJ:%.o=SERVER/%.c)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/server/toolkit.c	Sun Nov 30 21:12:00 2025 +0100
@@ -0,0 +1,36 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include "toolkit.h"
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/server/toolkit.h	Sun Nov 30 21:12:00 2025 +0100
@@ -0,0 +1,48 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TOOLKIT_H
+#define	TOOLKIT_H
+
+#include <inttypes.h>
+#include "../ui/toolkit.h"
+#include "../common/context.h"
+#include "../common/object.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* TOOLKIT_H */
+
--- a/ui/ui/toolkit.h	Sun Nov 30 18:17:49 2025 +0100
+++ b/ui/ui/toolkit.h	Sun Nov 30 21:12:00 2025 +0100
@@ -146,6 +146,12 @@
 #endif
 
 
+#elif UI_SERVER
+
+#define UIWIDGET void*
+#define UIWINDOW void*
+#define UIMENU   void*
+
 #endif
 
 #ifndef TRUE
--- a/ui/ui/widget.h	Sun Nov 30 18:17:49 2025 +0100
+++ b/ui/ui/widget.h	Sun Nov 30 21:12:00 2025 +0100
@@ -64,6 +64,8 @@
 typedef UIWIDGET(*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata);
 #elif defined(UI_WIN32)
 typedef UIWIDGET(*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata);
+#elif defined(UI_SERVER)
+typedef UIWIDGET(*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata);
 #endif
 UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs *args);
 

mercurial