implement window (Server)

Wed, 10 Dec 2025 19:04:46 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 10 Dec 2025 19:04:46 +0100
changeset 982
9102a53c5385
parent 981
1d47e71f26b6
child 983
1d7d24147961

implement window (Server)

application/main.c file | annotate | diff | comparison | revisions
client/uiclient.c file | annotate | diff | comparison | revisions
ui/common/message.c file | annotate | diff | comparison | revisions
ui/common/message.h 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/server/window.c file | annotate | diff | comparison | revisions
ui/server/window.h file | annotate | diff | comparison | revisions
--- a/application/main.c	Mon Dec 08 18:11:54 2025 +0100
+++ b/application/main.c	Wed Dec 10 19:04:46 2025 +0100
@@ -1290,8 +1290,16 @@
 
 #ifdef UI_SERVER
 
-void main(int argc, char **argv) {
-    
+void application_startup(UiEvent *event, void *userdata) {
+    UiObject *obj = ui_window("Test", NULL);
+    ui_show(obj);
+}
+
+int main(int argc, char **argv) {
+    ui_init(NULL, 0, NULL);
+    ui_onstartup(application_startup, NULL);
+    ui_main();
+    return 0;
 }
 
 
--- a/client/uiclient.c	Mon Dec 08 18:11:54 2025 +0100
+++ b/client/uiclient.c	Wed Dec 10 19:04:46 2025 +0100
@@ -175,15 +175,23 @@
 }
 
 int msg_simple_window(UiObject *parent, const CxJsonValue *value) {
+    cxmutstr obj_id = jsonobj_getstring(value, "obj_id");
     cxmutstr id = jsonobj_getstring(value, "id");
     cxmutstr title = jsonobj_getstring(value, "title");
     
-    if(!id.ptr) {
+    if(!obj_id.ptr) {
+        return 1;
+    }
+    if(!id) {
         return 1;
     }
     
     UiObject *obj = ui_simple_window(title.ptr, NULL);
-    client_add_obj_mapping(obj, id);
+    client_add_obj_mapping(obj, obj_id);
+    
+    if(obj->widget) {
+        client_reg_widget(obj, id, obj->widget);
+    }
     
     return client_handle_children(obj, value);
 }
--- a/ui/common/message.c	Mon Dec 08 18:11:54 2025 +0100
+++ b/ui/common/message.c	Wed Dec 10 19:04:46 2025 +0100
@@ -34,6 +34,10 @@
 
 #include "message.h"
 
+int uic_message_send_(UiMessageHandler *handler, cxstring msg) {
+    return handler->send(handler, msg);
+}
+
 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;
@@ -79,6 +83,9 @@
 int uic_simple_msg_handler_send(UiMessageHandler *handler, cxstring msg) {
     UiSimpleMessageHandler *sh = (UiSimpleMessageHandler*)handler;
     pthread_mutex_lock(&sh->queue_lock);
+    char header[32];
+    snprintf(header, 32, "%zu\n", msg.length);
+    cxBufferPutString(sh->outbuf, header);
     cxBufferWrite(msg.ptr, 1, msg.length, sh->outbuf);
     pthread_cond_signal(&sh->available);
     pthread_mutex_unlock(&sh->queue_lock);
--- a/ui/common/message.h	Mon Dec 08 18:11:54 2025 +0100
+++ b/ui/common/message.h	Wed Dec 10 19:04:46 2025 +0100
@@ -71,6 +71,9 @@
     int stop;
 } UiSimpleMessageHandler;
 
+int uic_message_send_(UiMessageHandler *handler, cxstring msg);
+#define uic_message_send(handler, msg) uic_message_send_(handler, cx_strcast(msg))
+
 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);
--- a/ui/server/objs.mk	Mon Dec 08 18:11:54 2025 +0100
+++ b/ui/server/objs.mk	Wed Dec 10 19:04:46 2025 +0100
@@ -31,6 +31,7 @@
 
 SERVEROBJ = toolkit.o
 SERVEROBJ += widget.o
+SERVEROBJ += window.o
 SERVEROBJ += image.o
 
 TOOLKITOBJS += $(SERVEROBJ:%=$(SERVER_OBJPRE)%)
--- a/ui/server/toolkit.c	Mon Dec 08 18:11:54 2025 +0100
+++ b/ui/server/toolkit.c	Wed Dec 10 19:04:46 2025 +0100
@@ -37,6 +37,9 @@
 #include "../common/threadpool.h"
 #include "../common/app.h"
 
+#include <cx/hash_map.h>
+#include <cx/printf.h>
+
 static const char *ui_app_name;
 
 static UiMessageHandler *message_handler;
@@ -46,10 +49,15 @@
 
 static UiQueue *event_queue;
 
+static CxMap *srv_obj_map;
+static uint64_t srv_obj_id_counter = 0;
+
 void ui_init(const char *appname, int argc, char **argv) {
     ui_app_name = appname;
     
     message_handler = uic_simple_msg_handler(STDIN_FILENO, STDOUT_FILENO, ui_server_message_received);
+    
+    srv_obj_map = cxHashMapCreateSimple(CX_STORE_POINTERS);
 }
 
 const char* ui_appname() {
@@ -66,6 +74,8 @@
 }
 
 void ui_main(void) {
+    uic_simple_msg_handler_start(message_handler);
+    uic_application_startup(NULL);
     event_queue = ui_queue_create();
     UiServerEvent *event = NULL;
     while((event = ui_queue_get_wait(event_queue)) != NULL) {
@@ -96,3 +106,41 @@
     c->data = td;
     ui_queue_put(event_queue, c);
 }
+
+void ui_show(UiObject *obj) {
+    if(!obj->widget->sent) {
+        cxmutstr msg = obj->widget->serialize(obj->widget);
+        obj->widget->sent = TRUE;
+        uic_message_send(message_handler, msg);
+        free(msg.ptr);
+    }
+    cxmutstr msg = cx_asprintf("{\"type\":\"show\", \"obj\":\"%s\"}", obj->widget->obj->id.ptr);
+    obj->widget->visible = TRUE;
+    uic_message_send(message_handler, msg);
+    free(msg.ptr);
+}
+
+UiSrvObj* ui_create_server_object(UiContext *ctx) {
+    const CxAllocator *a = ctx->allocator;
+    UiSrvObj *obj = cxZalloc(a, sizeof(UiSrvObj));
+    
+    char id[32];
+    snprintf(id, 32, "%" PRIu64, srv_obj_id_counter++);
+    obj->id = cx_strdup_a(a, id);
+    obj->ctx = ctx;
+    
+    obj->widgets = cxHashMapCreate(a, CX_STORE_POINTERS, 64);
+    
+    return obj;
+}
+
+void ui_reg_widget(UiWidget *widget) {
+    UiSrvObj *obj = widget->obj;
+    
+    char id[32];
+    snprintf(id, 32, "%" PRIu64, obj->widget_id_counter++);
+    
+    widget->id = cx_strdup_a(widget->obj->ctx->allocator, cx_str(id));
+    cxMapPut(obj->widgets, id, widget);
+}
+
--- a/ui/server/toolkit.h	Mon Dec 08 18:11:54 2025 +0100
+++ b/ui/server/toolkit.h	Wed Dec 10 19:04:46 2025 +0100
@@ -62,7 +62,11 @@
 };
 
 struct UiSrvObj {
+    UiContext *ctx;
     cxmutstr id;
+    
+    CxMap *widgets;
+    uint64_t widget_id_counter;
 };
 
 struct UiWidget {
@@ -75,11 +79,15 @@
     cxmutstr args;
     UiBool visible;
     UiBool enabled;
-    ui_serialize_func *serialize;
+    UiBool sent;
+    ui_serialize_func serialize;
 };
 
 void ui_server_message_received(cxstring msg);
 
+UiSrvObj* ui_create_server_object(UiContext *ctx);
+void ui_reg_widget(UiWidget *widget);
+
 
 #ifdef	__cplusplus
 }
--- a/ui/server/window.c	Mon Dec 08 18:11:54 2025 +0100
+++ b/ui/server/window.c	Wed Dec 10 19:04:46 2025 +0100
@@ -28,3 +28,76 @@
 
 #include "window.h"
 
+#include "../common/object.h"
+
+#include <cx/buffer.h>
+
+static UiObject* create_window(const char *title, UiBool simple, UiBool sidebar, UiBool splitview) {
+    UiObject *obj = uic_object_new_toplevel();
+    const CxAllocator *a = obj->ctx->allocator;
+    
+    UiWindow *window = cxZalloc(a, sizeof(UiWindow));
+    window->widget.obj = ui_create_server_object(obj->ctx);
+    window->widget.children = cxLinkedListCreate(a, NULL, CX_STORE_POINTERS);
+    window->widget.serialize = (ui_serialize_func)ui_window_serialize;
+    window->title = cx_strdup_a(a, title);
+    
+    obj->widget = (UiWidget*)window;
+    ui_reg_widget(obj->widget);
+    
+    return obj;
+}
+
+UiObject *ui_window(const char *title, void *window_data) {
+    return create_window(title, FALSE, FALSE, FALSE);
+}
+
+UiObject *ui_sidebar_window(const char *title, void *window_data) {
+    return create_window(title, FALSE, TRUE, FALSE);
+}
+
+UiObject *ui_splitview_window(const char *title, UiBool sidebar) {
+    return create_window(title, FALSE, sidebar, TRUE);
+}
+
+UiObject *ui_simple_window(const char *title, void *window_data) {
+    return create_window(title, TRUE, FALSE, FALSE);
+}
+
+
+cxmutstr ui_window_serialize(UiWindow *w) {
+    CxBuffer buf;
+    cxBufferInit(&buf, NULL, 1024, NULL, CX_BUFFER_AUTO_EXTEND | CX_BUFFER_FREE_CONTENTS);
+    
+    cxBufferPutString(&buf, "{\"type\":");
+    switch(w->type) {
+        case UI_WINDOW_MAIN: cxBufferPutString(&buf, "\"window\""); break;
+        case UI_WINDOW_SIMPLE: cxBufferPutString(&buf, "\"simple_window\""); break;
+        case UI_WINDOW_SIDEBAR: cxBufferPutString(&buf, "\"sidebar_window\""); break;
+        case UI_WINDOW_SPLITVIEW: cxBufferPutString(&buf, "\"splitview_window\""); break;
+    }
+    
+    cxmutstr obj_id = w->widget.obj->id;
+    cxmutstr id = w->widget.id;
+    
+    cxBufferPutString(&buf, " obj_id=\"");
+    cxBufferWrite(obj_id.ptr, 1, obj_id.length, &buf);
+    cxBufferPutString(&buf, "\"");
+    
+    cxBufferPutString(&buf, " id=\"");
+    cxBufferWrite(id.ptr, 1, id.length, &buf);
+    cxBufferPutString(&buf, "\"");
+    
+    if(w->title.ptr) {
+        cxBufferPutString(&buf, " title=\"");
+        cxBufferWrite(w->title.ptr, 1, w->title.length, &buf);
+        cxBufferPutString(&buf, "\"");
+    }
+    
+    
+    cxBufferPutString(&buf, "}\n");
+    
+    return cx_mutstrn(buf.space, buf.size);
+}
+
+
--- a/ui/server/window.h	Mon Dec 08 18:11:54 2025 +0100
+++ b/ui/server/window.h	Wed Dec 10 19:04:46 2025 +0100
@@ -36,8 +36,21 @@
 extern "C" {
 #endif
 
+enum UiWindowType {
+    UI_WINDOW_MAIN = 0,
+    UI_WINDOW_SIMPLE,
+    UI_WINDOW_SIDEBAR,
+    UI_WINDOW_SPLITVIEW
+};
+typedef enum UiWindowType UiWindowType;
 
+typedef struct UiWindow {
+    UiWidget widget;
+    UiWindowType type;
+    cxmutstr title;
+} UiWindow;
 
+cxmutstr ui_window_serialize(UiWindow *w);
 
 #ifdef __cplusplus
 }

mercurial