| 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
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 |
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 26 * POSSIBILITY OF SUCH DAMAGE. |
26 * POSSIBILITY OF SUCH DAMAGE. |
| 27 */ |
27 */ |
| 28 |
28 |
| |
29 #include "toolkit.h" |
| |
30 #include "Windows.h" |
| |
31 |
| |
32 #include "../common/properties.h" |
| |
33 |
| 29 #include <stdio.h> |
34 #include <stdio.h> |
| 30 #include <stdlib.h> |
35 #include <stdlib.h> |
| 31 #include <unistd.h> |
|
| 32 #include <pthread.h> |
|
| 33 |
36 |
| 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; |
37 static const char *application_name; |
| 51 |
38 |
| 52 static ui_callback startup_func; |
39 static ui_callback startup_func; |
| 53 static void *startup_data; |
40 static void *startup_data; |
| 54 static ui_callback open_func; |
41 static ui_callback open_func; |
| 55 void *open_data; |
42 void *open_data; |
| 56 static ui_callback exit_func; |
43 static ui_callback exit_func; |
| 57 void *exit_data; |
44 void *exit_data; |
| 58 |
45 |
| 59 static ui_callback appclose_fnc; |
46 void ui_init(const char *appname, int argc, char **argv) { |
| 60 static void *appclose_udata; |
47 application_name = appname; |
| 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 } |
48 } |
| 118 |
49 |
| 119 const char* ui_appname() { |
50 const char* ui_appname() { |
| 120 return application_name; |
51 return application_name; |
| 121 } |
|
| 122 |
|
| 123 Display* ui_motif_get_display() { |
|
| 124 return display; |
|
| 125 } |
52 } |
| 126 |
53 |
| 127 void ui_onstartup(ui_callback f, void *userdata) { |
54 void ui_onstartup(ui_callback f, void *userdata) { |
| 128 startup_func = f; |
55 startup_func = f; |
| 129 startup_data = userdata; |
56 startup_data = userdata; |
| 141 |
68 |
| 142 void ui_main() { |
69 void ui_main() { |
| 143 if(startup_func) { |
70 if(startup_func) { |
| 144 startup_func(NULL, startup_data); |
71 startup_func(NULL, startup_data); |
| 145 } |
72 } |
| 146 XtAppMainLoop(app); |
73 |
| |
74 // event loop |
| |
75 MSG msg; |
| |
76 while (GetMessage(&msg, NULL, 0, 0)) { |
| |
77 TranslateMessage(&msg); |
| |
78 DispatchMessage(&msg); |
| |
79 } |
| |
80 |
| 147 if(exit_func) { |
81 if(exit_func) { |
| 148 exit_func(NULL, exit_data); |
82 exit_func(NULL, exit_data); |
| 149 } |
83 } |
| 150 uic_store_app_properties(); |
84 uic_store_app_properties(); |
| 151 } |
85 } |
| 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 if(!XtIsRealized(obj->widget)) { |
|
| 168 XtRealizeWidget(obj->widget); |
|
| 169 obj->ref++; |
|
| 170 } |
|
| 171 } |
|
| 172 |
|
| 173 void ui_close(UiObject *obj) { |
|
| 174 |
|
| 175 } |
|
| 176 |
|
| 177 |
|
| 178 void ui_set_enabled(UIWIDGET widget, int enabled) { |
|
| 179 XtSetSensitive(widget, enabled); |
|
| 180 } |
|
| 181 |
|
| 182 void ui_set_show_all(UIWIDGET widget, int value) { |
|
| 183 if(!value) { |
|
| 184 XtUnmanageChild(widget); |
|
| 185 } |
|
| 186 } |
|
| 187 |
|
| 188 void ui_set_visible(UIWIDGET widget, int visible) { |
|
| 189 if(visible) { |
|
| 190 XtManageChild(widget); |
|
| 191 } else { |
|
| 192 XtUnmanageChild(widget); |
|
| 193 } |
|
| 194 } |
|
| 195 |
|
| 196 static Boolean ui_job_finished(void *data) { |
|
| 197 UiJob *job = data; |
|
| 198 if(job->finish_callback) { |
|
| 199 UiEvent event; |
|
| 200 event.obj = job->obj; |
|
| 201 event.window = job->obj->window; |
|
| 202 event.document = job->obj->ctx->document; |
|
| 203 event.intval = 0; |
|
| 204 event.eventdata = NULL; |
|
| 205 job->finish_callback(&event, job->finish_data); |
|
| 206 } |
|
| 207 free(job); |
|
| 208 return TRUE; |
|
| 209 } |
|
| 210 |
|
| 211 static void* ui_jobthread(void *data) { |
|
| 212 UiJob *job = data; |
|
| 213 int result = job->job_func(job->job_data); |
|
| 214 if(!result) { |
|
| 215 write(event_pipe[1], &job, sizeof(void*)); // hack |
|
| 216 XtAppAddWorkProc(app, ui_job_finished, job); |
|
| 217 |
|
| 218 } |
|
| 219 return NULL; |
|
| 220 } |
|
| 221 |
|
| 222 void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd) { |
|
| 223 UiJob *job = malloc(sizeof(UiJob)); |
|
| 224 job->obj = obj; |
|
| 225 job->job_func = tf; |
|
| 226 job->job_data = td; |
|
| 227 job->finish_callback = f; |
|
| 228 job->finish_data = fd; |
|
| 229 pthread_t pid; |
|
| 230 pthread_create(&pid, NULL, ui_jobthread, job); |
|
| 231 } |
|
| 232 |
|
| 233 void ui_clipboard_set(char *str) { |
|
| 234 int length = strlen(str) + 1; |
|
| 235 |
|
| 236 Display *dp = XtDisplayOfObject(active_window); |
|
| 237 Window window = XtWindowOfObject(active_window); |
|
| 238 |
|
| 239 XmString label = XmStringCreateLocalized("toolkit_clipboard"); |
|
| 240 long id = 0; |
|
| 241 |
|
| 242 while(XmClipboardStartCopy( |
|
| 243 dp, |
|
| 244 window, |
|
| 245 label, |
|
| 246 CurrentTime, |
|
| 247 NULL, |
|
| 248 NULL, |
|
| 249 &id) == ClipboardLocked); |
|
| 250 XmStringFree(label); |
|
| 251 |
|
| 252 while(XmClipboardCopy( |
|
| 253 dp, |
|
| 254 window, |
|
| 255 id, |
|
| 256 "STRING", |
|
| 257 str, |
|
| 258 length, |
|
| 259 1, |
|
| 260 NULL) == ClipboardLocked); |
|
| 261 |
|
| 262 while(XmClipboardEndCopy(dp, window, id) == ClipboardLocked); |
|
| 263 } |
|
| 264 |
|
| 265 char* ui_clipboard_get() { |
|
| 266 Display *dp = XtDisplayOfObject(active_window); |
|
| 267 Window window = XtWindowOfObject(active_window); |
|
| 268 |
|
| 269 long id; |
|
| 270 size_t size = 128; |
|
| 271 char *buf = malloc(size); |
|
| 272 |
|
| 273 int r; |
|
| 274 for(;;) { |
|
| 275 r = XmClipboardRetrieve(dp, window, "STRING", buf, size, NULL, &id); |
|
| 276 if(r == ClipboardSuccess) { |
|
| 277 break; |
|
| 278 } else if(r == ClipboardTruncate) { |
|
| 279 size *= 2; |
|
| 280 buf = realloc(buf, size); |
|
| 281 } else if(r == ClipboardNoData) { |
|
| 282 free(buf); |
|
| 283 buf = NULL; |
|
| 284 break; |
|
| 285 } |
|
| 286 } |
|
| 287 |
|
| 288 return buf; |
|
| 289 } |
|
| 290 |
|
| 291 void ui_set_active_window(Widget w) { |
|
| 292 active_window = w; |
|
| 293 } |
|
| 294 |
|
| 295 Widget ui_get_active_window() { |
|
| 296 return active_window; |
|
| 297 } |
|
| 298 |
|
| 299 /* |
|
| 300 * doesn't work with gnome anymore |
|
| 301 */ |
|
| 302 void ui_window_dark_theme(Display *dp, Window window) { |
|
| 303 Atom atom = XInternAtom(dp, "_GTK_THEME_VARIANT", False); |
|
| 304 Atom type = XInternAtom(dp, "UTF8_STRING", False); |
|
| 305 XChangeProperty( |
|
| 306 dp, |
|
| 307 window, |
|
| 308 atom, |
|
| 309 type, |
|
| 310 8, |
|
| 311 PropModeReplace, |
|
| 312 (const unsigned char*)"dark", |
|
| 313 4); |
|
| 314 } |
|
| 315 |
|
| 316 void ui_destroy_eventdata(Widget w, XtPointer data, XtPointer d) { |
|
| 317 free(data); |
|
| 318 } |
|
| 319 |
|
| 320 void ui_set_widget_groups(UiContext *ctx, Widget widget, const int *groups) { |
|
| 321 if(!groups) { |
|
| 322 return; |
|
| 323 } |
|
| 324 size_t ngroups = uic_group_array_size(groups); |
|
| 325 ui_set_widget_ngroups(ctx, widget, groups, ngroups); |
|
| 326 } |
|
| 327 |
|
| 328 void ui_set_widget_ngroups(UiContext *ctx, Widget widget, const int *groups, size_t ngroups) { |
|
| 329 if(ngroups > 0) { |
|
| 330 uic_add_group_widget_i(ctx, widget, (ui_enablefunc)ui_set_enabled, groups, ngroups); |
|
| 331 ui_set_enabled(widget, FALSE); |
|
| 332 } |
|
| 333 } |
|
| 334 |
|