diff -r e7459e9fbed2 -r 488178e3e328 client/main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/main.c Sun Nov 30 18:15:46 2025 +0100 @@ -0,0 +1,204 @@ +/* + * 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 +#include +#include +#include + +#include +#include +#include + +#include "main.h" +#include "uiclient.h" + +/* + * debug window that is always created + */ +static UiObject *debug_window; + +/* + * test window, that is only created in testing mode + */ +static UiObject *test_window; + +static int test_mode = 0; + +static int input_fd[2]; +static int output_fd[2]; + +int main(int argc, char **argv) { + test_mode = 1; + + ui_init(NULL, argc, argv); + ui_onstartup(application_onstartup, NULL); + ui_onopen(application_onopen, NULL); + ui_onexit(application_onexit, NULL); + + int in = STDIN_FILENO; + int out = STDOUT_FILENO; + if(test_mode) { + if(pipe(input_fd)) { + perror("pipe"); + return 1; + } + if(pipe(output_fd)) { + perror("pipe"); + return 1; + } + + in = input_fd[0]; + out = output_fd[1]; + + pthread_t tid; + if(pthread_create(&tid, NULL, testwindow_read_thread, NULL)) { + perror("pthread_create"); + return 1; + } + if(pthread_detach(tid)) { + perror("pthread_detach"); + return 1; + } + } + MessageHandler *h = simple_msg_handler(in, out, client_msg_received); + client_init(h); + h->start(h); + + ui_main(); + + h->stop(h); + fprintf(stderr, "client: end"); + + return 0; +} + +void application_onstartup(UiEvent *event, void *userdata) { + // We need at least one window for the event loop to work. + // Create a debug window, that is invisible by default + debug_window = ui_simple_window("debug", NULL); + // TODO: debug UI + + if(test_mode) { + testwindow_create(); + } +} + +void application_onopen(UiEvent *event, void *userdata) { + +} + +void application_onexit(UiEvent *event, void *userdata) { + +} + +static void testwindow_close(UiEvent *event, void *userdata) { + ui_close(debug_window); + ui_app_quit(); + exit(0); +} + +static void testwindow_send(UiEvent *event, void *userdata) { + TestWindow *window = event->window; + + char *str = ui_get(window->input); + int len = strlen(str); + cxmutstr msg = cx_asprintf("%d\n%s", len, str); + write(input_fd[1], msg.ptr, msg.length); + free(msg.ptr); + + ui_set(window->input, ""); +} + +static void testwindow_clear_output(UiEvent *event, void *userdata) { + TestWindow *window = event->window; + ui_set(window->output, ""); +} + +void testwindow_create(void) { + UiObject *obj = ui_simple_window("Test", NULL); + ui_context_closefunc(obj->ctx, testwindow_close, NULL); + ui_window_size(obj, 1800, 1400); + + TestWindow *window = ui_malloc(obj->ctx, sizeof(TestWindow)); + window->input = ui_text_new(obj->ctx, NULL); + window->output = ui_text_new(obj->ctx, NULL); + obj->window = window; + + ui_hsplitpane(obj, .fill = TRUE, .initial_position = 900) { + // left + ui_vbox(obj, .fill = TRUE) { + ui_grid(obj, .margin = 10, .columnspacing = 10, .rowspacing = 10, .fill = TRUE) { + ui_llabel(obj, .label = "Input", .style = UI_LABEL_STYLE_TITLE, .hexpand = TRUE, .hfill = TRUE); + ui_newline(obj); + ui_textarea(obj, .value = window->input, .fill = TRUE); + ui_newline(obj); + ui_button(obj, .label = "Send", .onclick = testwindow_send); + } + } + + + // right + ui_vbox(obj, .fill = TRUE) { + ui_grid(obj, .margin = 10, .columnspacing = 10, .rowspacing = 10, .fill = TRUE) { + ui_llabel(obj, .label = "Output", .style = UI_LABEL_STYLE_TITLE, .hexpand = TRUE, .hfill = TRUE); + ui_newline(obj); + ui_textarea(obj, .value = window->output, .fill = TRUE); + ui_newline(obj); + ui_button(obj, .label = "Clear", .onclick = testwindow_clear_output); + } + } + } + + ui_show(obj); + + test_window = obj; +} + +static int append_log(void *data) { + char *msg = data; + TestWindow *window = test_window->window; + UiText *out = window->output; + int length = out->length(out); + out->insert(out, length, msg); + free(msg); + return 0; +} + +void* testwindow_read_thread(void *data) { + char buf[4096]; + ssize_t r; + while((r = read(output_fd[0], buf, 4096)) > 0) { + char *str = malloc(r+1); + memcpy(str, buf, r); + str[r] = 0; + ui_call_mainthread(append_log, str); + } + + return NULL; +}