UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2024 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <unistd.h> 32 #include <pthread.h> 33 34 #include "toolkit.h" 35 #include "toolbar.h" 36 #include "container.h" 37 #include "stock.h" 38 #include "../common/menu.h" 39 #include "../common/toolbar.h" 40 #include "../common/document.h" 41 #include "../common/properties.h" 42 #include <cx/buffer.h> 43 44 #include <X11/Intrinsic.h> 45 #include <Xm/CutPaste.h> 46 47 static XtAppContext app; 48 static Display *display; 49 static Widget active_window; 50 static const char *application_name; 51 52 static ui_callback startup_func; 53 static void *startup_data; 54 static ui_callback open_func; 55 void *open_data; 56 static ui_callback exit_func; 57 void *exit_data; 58 59 static ui_callback appclose_fnc; 60 static void *appclose_udata; 61 62 static int is_toplevel_realized = 0; 63 64 int event_pipe[2]; 65 66 67 static String fallback[] = { 68 //"*fontList: -dt-interface system-medium-r-normal-s*utf*:", 69 "*renderTable: rt", 70 "*rt*fontType: FONT_IS_XFT", 71 "*rt*fontName: Sans", 72 "*rt*fontSize: 11", 73 74 "*progresss_spinner*renderTable*fontType: FONT_IS_FONT", 75 "*progresss_spinner*renderTable*fontName: Cursor", 76 77 "*window_frame.shadowType: SHADOW_ETCHED_OUT", 78 "*window_frame.shadowThickness: 1", 79 "*togglebutton.shadowThickness: 1", 80 "*togglebutton.highlightThickness: 2", 81 82 "*ui_test.background: red", 83 NULL 84 }; 85 86 void input_proc(XtPointer data, int *source, XtInputId *iid) { 87 void *ptr; 88 read(event_pipe[0], &ptr, sizeof(void*)); 89 } 90 91 void ui_init(const char *appname, int argc, char **argv) { 92 application_name = appname; 93 uic_init_global_context(); 94 95 XtToolkitInitialize(); 96 XtSetLanguageProc(NULL, NULL, NULL); 97 app = XtCreateApplicationContext(); 98 XtAppSetFallbackResources(app, fallback); 99 100 display = XtOpenDisplay(app, NULL, appname, appname, NULL, 0, &argc, argv); 101 102 uic_docmgr_init(); 103 uic_menu_init(); 104 uic_toolbar_init(); 105 uic_load_app_properties(); 106 107 if(pipe(event_pipe)) { 108 fprintf(stderr, "UiError: Cannot create event pipe\n"); 109 exit(-1); 110 } 111 XtAppAddInput( 112 app, 113 event_pipe[0], 114 (XtPointer)XtInputReadMask, 115 input_proc, 116 NULL); 117 } 118 119 const char* ui_appname() { 120 return application_name; 121 } 122 123 Display* ui_motif_get_display() { 124 return display; 125 } 126 127 void ui_onstartup(ui_callback f, void *userdata) { 128 startup_func = f; 129 startup_data = userdata; 130 } 131 132 void ui_onopen(ui_callback f, void *userdata) { 133 open_func = f; 134 open_data = userdata; 135 } 136 137 void ui_onexit(ui_callback f, void *userdata) { 138 exit_func = f; 139 exit_data = userdata; 140 } 141 142 void ui_main() { 143 if(startup_func) { 144 startup_func(NULL, startup_data); 145 } 146 XtAppMainLoop(app); 147 if(exit_func) { 148 exit_func(NULL, exit_data); 149 } 150 uic_store_app_properties(); 151 } 152 153 void ui_exit_mainloop() { 154 XtAppSetExitFlag(app); 155 } 156 157 void ui_secondary_event_loop(int *loop) { 158 while(*loop && !XtAppGetExitFlag(app)) { 159 XEvent event; 160 XtAppNextEvent(app, &event); 161 XtDispatchEvent(&event); 162 } 163 } 164 165 void ui_show(UiObject *obj) { 166 uic_check_group_widgets(obj->ctx); 167 XtRealizeWidget(obj->widget); 168 } 169 170 void ui_close(UiObject *obj) { 171 172 } 173 174 175 void ui_set_enabled(UIWIDGET widget, int enabled) { 176 XtSetSensitive(widget, enabled); 177 } 178 179 void ui_set_show_all(UIWIDGET widget, int value) { 180 if(!value) { 181 XtUnmanageChild(widget); 182 } 183 } 184 185 void ui_set_visible(UIWIDGET widget, int visible) { 186 if(visible) { 187 XtManageChild(widget); 188 } else { 189 XtUnmanageChild(widget); 190 } 191 } 192 193 static Boolean ui_job_finished(void *data) { 194 UiJob *job = data; 195 if(job->finish_callback) { 196 UiEvent event; 197 event.obj = job->obj; 198 event.window = job->obj->window; 199 event.document = job->obj->ctx->document; 200 event.intval = 0; 201 event.eventdata = NULL; 202 job->finish_callback(&event, job->finish_data); 203 } 204 free(job); 205 return TRUE; 206 } 207 208 static void* ui_jobthread(void *data) { 209 UiJob *job = data; 210 int result = job->job_func(job->job_data); 211 if(!result) { 212 write(event_pipe[1], &job, sizeof(void*)); // hack 213 XtAppAddWorkProc(app, ui_job_finished, job); 214 215 } 216 return NULL; 217 } 218 219 void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd) { 220 UiJob *job = malloc(sizeof(UiJob)); 221 job->obj = obj; 222 job->job_func = tf; 223 job->job_data = td; 224 job->finish_callback = f; 225 job->finish_data = fd; 226 pthread_t pid; 227 pthread_create(&pid, NULL, ui_jobthread, job); 228 } 229 230 void ui_clipboard_set(char *str) { 231 int length = strlen(str) + 1; 232 233 Display *dp = XtDisplayOfObject(active_window); 234 Window window = XtWindowOfObject(active_window); 235 236 XmString label = XmStringCreateLocalized("toolkit_clipboard"); 237 long id = 0; 238 239 while(XmClipboardStartCopy( 240 dp, 241 window, 242 label, 243 CurrentTime, 244 NULL, 245 NULL, 246 &id) == ClipboardLocked); 247 XmStringFree(label); 248 249 while(XmClipboardCopy( 250 dp, 251 window, 252 id, 253 "STRING", 254 str, 255 length, 256 1, 257 NULL) == ClipboardLocked); 258 259 while(XmClipboardEndCopy(dp, window, id) == ClipboardLocked); 260 } 261 262 char* ui_clipboard_get() { 263 Display *dp = XtDisplayOfObject(active_window); 264 Window window = XtWindowOfObject(active_window); 265 266 long id; 267 size_t size = 128; 268 char *buf = malloc(size); 269 270 int r; 271 for(;;) { 272 r = XmClipboardRetrieve(dp, window, "STRING", buf, size, NULL, &id); 273 if(r == ClipboardSuccess) { 274 break; 275 } else if(r == ClipboardTruncate) { 276 size *= 2; 277 buf = realloc(buf, size); 278 } else if(r == ClipboardNoData) { 279 free(buf); 280 buf = NULL; 281 break; 282 } 283 } 284 285 return buf; 286 } 287 288 void ui_set_active_window(Widget w) { 289 active_window = w; 290 } 291 292 Widget ui_get_active_window() { 293 return active_window; 294 } 295 296 /* 297 * doesn't work with gnome anymore 298 */ 299 void ui_window_dark_theme(Display *dp, Window window) { 300 Atom atom = XInternAtom(dp, "_GTK_THEME_VARIANT", False); 301 Atom type = XInternAtom(dp, "UTF8_STRING", False); 302 XChangeProperty( 303 dp, 304 window, 305 atom, 306 type, 307 8, 308 PropModeReplace, 309 (const unsigned char*)"dark", 310 4); 311 } 312 313 void ui_destroy_eventdata(Widget w, XtPointer data, XtPointer d) { 314 free(data); 315 } 316 317 void ui_set_widget_groups(UiContext *ctx, Widget widget, const int *groups) { 318 if(!groups) { 319 return; 320 } 321 size_t ngroups = uic_group_array_size(groups); 322 ui_set_widget_ngroups(ctx, widget, groups, ngroups); 323 } 324 325 void ui_set_widget_ngroups(UiContext *ctx, Widget widget, const int *groups, size_t ngroups) { 326 if(ngroups > 0) { 327 uic_add_group_widget_i(ctx, widget, (ui_enablefunc)ui_set_enabled, groups, ngroups); 328 ui_set_enabled(widget, FALSE); 329 } 330 } 331 332