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 "*text_area*renderTable: f1", 70 "*f1*fontType: FONT_IS_XFT", 71 "*f1*fontName: Monospace", 72 "*f1*fontSize: 11", 73 "*renderTable: rt", 74 "*rt*fontType: FONT_IS_XFT", 75 "*rt*fontName: Sans", 76 "*rt*fontSize: 11", 77 78 "*window_frame.shadowType: SHADOW_ETCHED_OUT", 79 "*window_frame.shadowThickness: 1", 80 "*togglebutton.shadowThickness: 1", 81 "*togglebutton.highlightThickness: 2", 82 NULL 83 }; 84 85 void input_proc(XtPointer data, int *source, XtInputId *iid) { 86 void *ptr; 87 read(event_pipe[0], &ptr, sizeof(void*)); 88 } 89 90 void ui_init(const char *appname, int argc, char **argv) { 91 application_name = appname; 92 uic_init_global_context(); 93 94 XtToolkitInitialize(); 95 XtSetLanguageProc(NULL, NULL, NULL); 96 app = XtCreateApplicationContext(); 97 XtAppSetFallbackResources(app, fallback); 98 99 display = XtOpenDisplay(app, NULL, appname, appname, NULL, 0, &argc, argv); 100 101 uic_docmgr_init(); 102 uic_menu_init(); 103 uic_toolbar_init(); 104 uic_load_app_properties(); 105 106 if(pipe(event_pipe)) { 107 fprintf(stderr, "UiError: Cannot create event pipe\n"); 108 exit(-1); 109 } 110 XtAppAddInput( 111 app, 112 event_pipe[0], 113 (XtPointer)XtInputReadMask, 114 input_proc, 115 NULL); 116 } 117 118 const char* ui_appname() { 119 return application_name; 120 } 121 122 Display* ui_motif_get_display() { 123 return display; 124 } 125 126 void ui_onstartup(ui_callback f, void *userdata) { 127 startup_func = f; 128 startup_data = userdata; 129 } 130 131 void ui_onopen(ui_callback f, void *userdata) { 132 open_func = f; 133 open_data = userdata; 134 } 135 136 void ui_onexit(ui_callback f, void *userdata) { 137 exit_func = f; 138 exit_data = userdata; 139 } 140 141 void ui_main() { 142 if(startup_func) { 143 startup_func(NULL, startup_data); 144 } 145 XtAppMainLoop(app); 146 if(exit_func) { 147 exit_func(NULL, exit_data); 148 } 149 uic_store_app_properties(); 150 } 151 152 void ui_exit_mainloop() { 153 XtAppSetExitFlag(app); 154 } 155 156 void ui_secondary_event_loop(int *loop) { 157 while(*loop && !XtAppGetExitFlag(app)) { 158 XEvent event; 159 XtAppNextEvent(app, &event); 160 XtDispatchEvent(&event); 161 } 162 } 163 164 void ui_show(UiObject *obj) { 165 uic_check_group_widgets(obj->ctx); 166 XtRealizeWidget(obj->widget); 167 } 168 169 void ui_close(UiObject *obj) { 170 171 } 172 173 174 void ui_set_enabled(UIWIDGET widget, int enabled) { 175 XtSetSensitive(widget, enabled); 176 } 177 178 void ui_set_show_all(UIWIDGET widget, int value) { 179 if(!value) { 180 XtUnmanageChild(widget); 181 } 182 } 183 184 void ui_set_visible(UIWIDGET widget, int visible) { 185 if(visible) { 186 XtManageChild(widget); 187 } else { 188 XtUnmanageChild(widget); 189 } 190 } 191 192 static Boolean ui_job_finished(void *data) { 193 UiJob *job = data; 194 if(job->finish_callback) { 195 UiEvent event; 196 event.obj = job->obj; 197 event.window = job->obj->window; 198 event.document = job->obj->ctx->document; 199 event.intval = 0; 200 event.eventdata = NULL; 201 job->finish_callback(&event, job->finish_data); 202 } 203 free(job); 204 return TRUE; 205 } 206 207 static void* ui_jobthread(void *data) { 208 UiJob *job = data; 209 int result = job->job_func(job->job_data); 210 if(!result) { 211 write(event_pipe[1], &job, sizeof(void*)); // hack 212 XtAppAddWorkProc(app, ui_job_finished, job); 213 214 } 215 return NULL; 216 } 217 218 void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd) { 219 UiJob *job = malloc(sizeof(UiJob)); 220 job->obj = obj; 221 job->job_func = tf; 222 job->job_data = td; 223 job->finish_callback = f; 224 job->finish_data = fd; 225 pthread_t pid; 226 pthread_create(&pid, NULL, ui_jobthread, job); 227 } 228 229 void ui_clipboard_set(char *str) { 230 int length = strlen(str) + 1; 231 232 Display *dp = XtDisplayOfObject(active_window); 233 Window window = XtWindowOfObject(active_window); 234 235 XmString label = XmStringCreateLocalized("toolkit_clipboard"); 236 long id = 0; 237 238 while(XmClipboardStartCopy( 239 dp, 240 window, 241 label, 242 CurrentTime, 243 NULL, 244 NULL, 245 &id) == ClipboardLocked); 246 XmStringFree(label); 247 248 while(XmClipboardCopy( 249 dp, 250 window, 251 id, 252 "STRING", 253 str, 254 length, 255 1, 256 NULL) == ClipboardLocked); 257 258 while(XmClipboardEndCopy(dp, window, id) == ClipboardLocked); 259 } 260 261 char* ui_clipboard_get() { 262 Display *dp = XtDisplayOfObject(active_window); 263 Window window = XtWindowOfObject(active_window); 264 265 long id; 266 size_t size = 128; 267 char *buf = malloc(size); 268 269 int r; 270 for(;;) { 271 r = XmClipboardRetrieve(dp, window, "STRING", buf, size, NULL, &id); 272 if(r == ClipboardSuccess) { 273 break; 274 } else if(r == ClipboardTruncate) { 275 size *= 2; 276 buf = realloc(buf, size); 277 } else if(r == ClipboardNoData) { 278 free(buf); 279 buf = NULL; 280 break; 281 } 282 } 283 284 return buf; 285 } 286 287 void ui_set_active_window(Widget w) { 288 active_window = w; 289 } 290 291 Widget ui_get_active_window() { 292 return active_window; 293 } 294 295 /* 296 * doesn't work with gnome anymore 297 */ 298 void ui_window_dark_theme(Display *dp, Window window) { 299 Atom atom = XInternAtom(dp, "_GTK_THEME_VARIANT", False); 300 Atom type = XInternAtom(dp, "UTF8_STRING", False); 301 XChangeProperty( 302 dp, 303 window, 304 atom, 305 type, 306 8, 307 PropModeReplace, 308 (const unsigned char*)"dark", 309 4); 310 } 311 312 void ui_destroy_eventdata(Widget w, XtPointer *data, XtPointer d) { 313 free(data); 314 } 315 316 void ui_set_widget_groups(UiContext *ctx, Widget widget, const int *groups) { 317 if(!groups) { 318 return; 319 } 320 size_t ngroups = uic_group_array_size(groups); 321 ui_set_widget_ngroups(ctx, widget, groups, ngroups); 322 } 323 324 void ui_set_widget_ngroups(UiContext *ctx, Widget widget, const int *groups, size_t ngroups) { 325 if(ngroups > 0) { 326 uic_add_group_widget_i(ctx, widget, (ui_enablefunc)ui_set_enabled, groups, ngroups); 327 ui_set_enabled(widget, FALSE); 328 } 329 } 330 331