--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/motif/toolkit.c Wed Dec 09 11:32:01 2020 +0100 @@ -0,0 +1,301 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 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" +#include "toolbar.h" +#include "stock.h" +#include "../common/document.h" +#include "../common/properties.h" +#include <ucx/buffer.h> + +static XtAppContext app; +static Display *display; +static Widget active_window; +static char *application_name; + +static ui_callback startup_func; +static void *startup_data; +static ui_callback open_func; +void *open_data; +static ui_callback exit_func; +void *exit_data; + +static ui_callback appclose_fnc; +static void *appclose_udata; + +static int is_toplevel_realized = 0; + +int event_pipe[2]; + + +static String fallback[] = { + //"*fontList: -dt-interface system-medium-r-normal-s*utf*:", + "*text_area*renderTable: f1", + "*f1*fontType: FONT_IS_XFT", + "*f1*fontName: Monospace", + "*f1*fontSize: 11", + "*renderTable: rt", + "*rt*fontType: FONT_IS_XFT", + "*rt*fontName: Sans", + "*rt*fontSize: 11", + NULL +}; + +void input_proc(XtPointer data, int *source, XtInputId *iid) { + void *ptr; + read(event_pipe[0], &ptr, sizeof(void*)); +} + +void ui_init(char *appname, int argc, char **argv) { + application_name = appname; + + XtToolkitInitialize(); + XtSetLanguageProc(NULL, NULL, NULL); + app = XtCreateApplicationContext(); + XtAppSetFallbackResources(app, fallback); + + display = XtOpenDisplay(app, NULL, appname, appname, NULL, 0, &argc, argv); + char **missing = NULL; + int nm = 0; + char *def = NULL; + XCreateFontSet(display, "-dt-interface system-medium-r-normal-s*utf*", &missing, &nm, &def); + + uic_docmgr_init(); + ui_toolbar_init(); + ui_stock_init(); + + uic_load_app_properties(); + + if(pipe(event_pipe)) { + fprintf(stderr, "UiError: Cannot create event pipe\n"); + exit(-1); + } + XtAppAddInput( + app, + event_pipe[0], + (XtPointer)XtInputReadMask, + input_proc, + NULL); +} + +char* ui_appname() { + return application_name; +} + +Display* ui_get_display() { + return display; +} + +void ui_onstartup(ui_callback f, void *userdata) { + startup_func = f; + startup_data = userdata; +} + +void ui_onopen(ui_callback f, void *userdata) { + open_func = f; + open_data = userdata; +} + +void ui_onexit(ui_callback f, void *userdata) { + exit_func = f; + exit_data = userdata; +} + +void ui_main() { + if(startup_func) { + startup_func(NULL, startup_data); + } + XtAppMainLoop(app); + if(exit_func) { + exit_func(NULL, exit_data); + } + uic_store_app_properties(); +} + +void ui_exit_mainloop() { + XtAppSetExitFlag(app); +} + +void ui_secondary_event_loop(int *loop) { + while(*loop && !XtAppGetExitFlag(app)) { + XEvent event; + XtAppNextEvent(app, &event); + XtDispatchEvent(&event); + } +} + +void ui_show(UiObject *obj) { + uic_check_group_widgets(obj->ctx); + XtRealizeWidget(obj->widget); + ui_window_dark_theme(XtDisplay(obj->widget), XtWindow(obj->widget)); // TODO: if +} + +// implemented in window.c +//void ui_close(UiObject *obj) + +void ui_set_enabled(UIWIDGET widget, int enabled) { + XtSetSensitive(widget, enabled); +} + +void ui_set_show_all(UIWIDGET widget, int value) { + if(!value) { + XtUnmanageChild(widget); + } +} + +void ui_set_visible(UIWIDGET widget, int visible) { + if(visible) { + XtManageChild(widget); + } else { + XtUnmanageChild(widget); + } +} + +static Boolean ui_job_finished(void *data) { + printf("WorkProc\n"); + UiJob *job = data; + + UiEvent event; + event.obj = job->obj; + event.window = job->obj->window; + event.document = job->obj->ctx->document; + event.intval = 0; + event.eventdata = NULL; + + job->finish_callback(&event, job->finish_data); + free(job); + return TRUE; +} + +static void* ui_jobthread(void *data) { + UiJob *job = data; + int result = job->job_func(job->job_data); + if(!result) { + printf("XtAppAddWorkProc\n"); + write(event_pipe[1], &job, sizeof(void*)); // hack + XtAppAddWorkProc(app, ui_job_finished, job); + + } +} + +void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd) { + UiJob *job = malloc(sizeof(UiJob)); + job->obj = obj; + job->job_func = tf; + job->job_data = td; + job->finish_callback = f; + job->finish_data = fd; + pthread_t pid; + pthread_create(&pid, NULL, ui_jobthread, job); +} + +void ui_clipboard_set(char *str) { + printf("copy: {%s}\n", str); + int length = strlen(str) + 1; + + Display *dp = XtDisplayOfObject(active_window); + Window window = XtWindowOfObject(active_window); + + XmString label = XmStringCreateLocalized("toolkit_clipboard"); + long id = 0; + + while(XmClipboardStartCopy( + dp, + window, + label, + CurrentTime, + NULL, + NULL, + &id) == ClipboardLocked); + XmStringFree(label); + + while(XmClipboardCopy( + dp, + window, + id, + "STRING", + str, + length, + 1, + NULL) == ClipboardLocked); + + while(XmClipboardEndCopy(dp, window, id) == ClipboardLocked); +} + +char* ui_clipboard_get() { + Display *dp = XtDisplayOfObject(active_window); + Window window = XtWindowOfObject(active_window); + + long id; + size_t size = 128; + char *buf = malloc(size); + + int r; + for(;;) { + r = XmClipboardRetrieve(dp, window, "STRING", buf, size, NULL, &id); + if(r == ClipboardSuccess) { + break; + } else if(r == ClipboardTruncate) { + size *= 2; + buf = realloc(buf, size); + } else if(r == ClipboardNoData) { + free(buf); + buf = NULL; + break; + } + } + + return buf; +} + +void ui_set_active_window(Widget w) { + active_window = w; +} + +Widget ui_get_active_window() { + return active_window; +} + +void ui_window_dark_theme(Display *dp, Window window) { + Atom atom = XInternAtom(dp, "_GTK_THEME_VARIANT", False); + Atom type = XInternAtom(dp, "UTF8_STRING", False); + XChangeProperty( + dp, + window, + atom, + type, + 8, + PropModeReplace, + (const unsigned char*)"dark", + 4); +}