add existing code (build system, libs, initial mizucp code)
[mizunara.git] / ui / motif / toolkit.c
1 /*
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3  *
4  * Copyright 2014 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 "stock.h"
37 #include "../common/document.h"
38 #include "../common/properties.h"
39 #include <ucx/buffer.h>
40
41 static XtAppContext app;
42 static Display *display;
43 static Widget active_window;
44 static char *application_name;
45
46 static ui_callback   startup_func;
47 static void          *startup_data;
48 static ui_callback   open_func;
49 void                 *open_data;
50 static ui_callback   exit_func;
51 void                 *exit_data;
52
53 static ui_callback appclose_fnc;
54 static void *appclose_udata;
55
56 static int is_toplevel_realized = 0;
57
58 int event_pipe[2];
59
60
61 static String fallback[] = {
62         //"*fontList: -dt-interface system-medium-r-normal-s*utf*:",    
63         "*text_area*renderTable: f1",
64         "*f1*fontType: FONT_IS_XFT",
65         "*f1*fontName: Monospace",
66         "*f1*fontSize: 11",
67         "*renderTable: rt",
68         "*rt*fontType: FONT_IS_XFT",
69         "*rt*fontName: Sans",
70         "*rt*fontSize: 11",
71         NULL
72 };
73
74 void input_proc(XtPointer data, int *source, XtInputId *iid) {
75     void *ptr;
76     read(event_pipe[0], &ptr, sizeof(void*));
77 }
78
79 void ui_init(char *appname, int argc, char **argv) { 
80     application_name = appname;
81     
82     XtToolkitInitialize();
83     XtSetLanguageProc(NULL, NULL, NULL);
84     app = XtCreateApplicationContext();
85     XtAppSetFallbackResources(app, fallback);
86     
87     display =  XtOpenDisplay(app, NULL, appname, appname, NULL, 0, &argc, argv);
88     char **missing = NULL;
89     int nm = 0;
90     char *def = NULL;
91     XCreateFontSet(display, "-dt-interface system-medium-r-normal-s*utf*", &missing, &nm, &def);
92     
93     uic_docmgr_init();
94     ui_toolbar_init();
95     ui_stock_init();
96     
97     uic_load_app_properties();
98     
99     if(pipe(event_pipe)) {
100         fprintf(stderr, "UiError: Cannot create event pipe\n");
101         exit(-1);
102     }
103     XtAppAddInput(
104             app,
105             event_pipe[0],
106             (XtPointer)XtInputReadMask,
107             input_proc,
108             NULL);
109 }
110
111 char* ui_appname() {
112     return application_name;
113 }
114
115 Display* ui_get_display() {
116     return display;
117 }
118
119 void ui_onstartup(ui_callback f, void *userdata) {
120     startup_func = f;
121     startup_data = userdata;
122 }
123
124 void ui_onopen(ui_callback f, void *userdata) {
125     open_func = f;
126     open_data = userdata;
127 }
128
129 void ui_onexit(ui_callback f, void *userdata) {
130     exit_func = f;
131     exit_data = userdata;
132 }
133
134 void ui_main() {
135     if(startup_func) {
136         startup_func(NULL, startup_data);
137     }
138     XtAppMainLoop(app);
139     if(exit_func) {
140         exit_func(NULL, exit_data);
141     }
142     uic_store_app_properties();
143 }
144
145 void ui_exit_mainloop() {
146     XtAppSetExitFlag(app);
147 }
148
149 void ui_secondary_event_loop(int *loop) {
150     while(*loop && !XtAppGetExitFlag(app)) {
151         XEvent event;
152         XtAppNextEvent(app, &event);
153         XtDispatchEvent(&event);
154     }
155 }
156
157 void ui_show(UiObject *obj) {
158     uic_check_group_widgets(obj->ctx);
159     XtRealizeWidget(obj->widget);
160     ui_window_dark_theme(XtDisplay(obj->widget), XtWindow(obj->widget)); // TODO: if
161 }
162
163 // implemented in window.c
164 //void ui_close(UiObject *obj)
165
166 void ui_set_enabled(UIWIDGET widget, int enabled) {
167     XtSetSensitive(widget, enabled);
168 }
169
170 void ui_set_show_all(UIWIDGET widget, int value) {
171     if(!value) {
172         XtUnmanageChild(widget);
173     }
174 }
175
176 void ui_set_visible(UIWIDGET widget, int visible) {
177     if(visible) {
178         XtManageChild(widget);
179     } else {
180         XtUnmanageChild(widget);
181     }
182 }
183
184 static Boolean ui_job_finished(void *data) {
185     printf("WorkProc\n");
186     UiJob *job = data;
187     
188     UiEvent event;
189     event.obj = job->obj;
190     event.window = job->obj->window;
191     event.document = job->obj->ctx->document;
192     event.intval = 0;
193     event.eventdata = NULL;
194
195     job->finish_callback(&event, job->finish_data);
196     free(job);
197     return TRUE;
198 }
199
200 static void* ui_jobthread(void *data) {
201     UiJob *job = data;
202     int result = job->job_func(job->job_data);
203     if(!result) {
204         printf("XtAppAddWorkProc\n");
205         write(event_pipe[1], &job, sizeof(void*)); // hack
206         XtAppAddWorkProc(app, ui_job_finished, job);
207         
208     }
209 }
210
211 void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd) {
212     UiJob *job = malloc(sizeof(UiJob));
213     job->obj = obj;
214     job->job_func = tf;
215     job->job_data = td;
216     job->finish_callback = f;
217     job->finish_data = fd;
218     pthread_t pid;
219     pthread_create(&pid, NULL, ui_jobthread, job);
220 }
221
222 void ui_clipboard_set(char *str) {
223     printf("copy: {%s}\n", str);
224     int length = strlen(str) + 1;
225     
226     Display *dp = XtDisplayOfObject(active_window);
227     Window window = XtWindowOfObject(active_window);
228     
229     XmString label = XmStringCreateLocalized("toolkit_clipboard");
230     long id = 0;
231     
232     while(XmClipboardStartCopy(
233             dp,
234             window,
235             label,
236             CurrentTime,
237             NULL,
238             NULL,
239             &id) == ClipboardLocked);
240     XmStringFree(label);
241     
242     while(XmClipboardCopy(
243             dp,
244             window,
245             id,
246             "STRING",
247             str, 
248             length,
249             1,
250             NULL) == ClipboardLocked);
251     
252     while(XmClipboardEndCopy(dp, window, id) == ClipboardLocked);
253 }
254
255 char* ui_clipboard_get() {
256     Display *dp = XtDisplayOfObject(active_window);
257     Window window = XtWindowOfObject(active_window);
258     
259     long id;
260     size_t size = 128;
261     char *buf = malloc(size);
262     
263     int r;
264     for(;;) {
265         r = XmClipboardRetrieve(dp, window, "STRING", buf, size, NULL, &id);
266         if(r == ClipboardSuccess) {
267             break;
268         } else if(r == ClipboardTruncate) {
269             size *= 2;
270             buf = realloc(buf, size);
271         } else if(r == ClipboardNoData) {
272             free(buf);
273             buf = NULL;
274             break;
275         }
276     }
277     
278     return buf;
279 }
280
281 void ui_set_active_window(Widget w) {
282     active_window = w;
283 }
284
285 Widget ui_get_active_window() {
286     return active_window;
287 }
288
289 void ui_window_dark_theme(Display *dp, Window window) {
290     Atom atom = XInternAtom(dp, "_GTK_THEME_VARIANT", False);
291     Atom type = XInternAtom(dp, "UTF8_STRING", False);
292     XChangeProperty(
293             dp, 
294             window, 
295             atom,
296             type,
297             8,
298             PropModeReplace,
299             (const unsigned char*)"dark",
300             4);
301 }