ui/gtk/toolkit.c

changeset 431
bb7da585debc
parent 413
b8e41d42f400
equal deleted inserted replaced
169:fe49cff3c571 431:bb7da585debc
31 #include <string.h> 31 #include <string.h>
32 #include <stdbool.h> 32 #include <stdbool.h>
33 33
34 #include "toolkit.h" 34 #include "toolkit.h"
35 #include "toolbar.h" 35 #include "toolbar.h"
36 #include "model.h" 36 #include "icon.h"
37 #include "image.h"
38 #include "../common/document.h" 37 #include "../common/document.h"
39 #include "../common/properties.h" 38 #include "../common/properties.h"
40 39 #include "../common/menu.h"
41 #include <ucx/utils.h> 40 #include "../common/toolbar.h"
41 #include "../common/threadpool.h"
42
43 #include <cx/utils.h>
44 #include <cx/string.h>
45 #include <cx/printf.h>
42 46
43 #include <pthread.h> 47 #include <pthread.h>
44 48
45 #ifndef UI_GTK2 49 #ifdef UI_APPLICATION
46 static GtkApplication *app; 50 UI_APPLICATION app;
47 #endif 51 #endif
48 52
49 static char *application_name; 53 static const char *application_name;
50 54
51 static ui_callback startup_func; 55 static ui_callback startup_func;
52 static void *startup_data; 56 static void *startup_data;
53 static ui_callback open_func; 57 static ui_callback open_func;
54 void *open_data; 58 void *open_data;
60 64
61 static UiObject *active_window; 65 static UiObject *active_window;
62 66
63 static int scale_factor = 1; 67 static int scale_factor = 1;
64 68
65 void ui_init(char *appname, int argc, char **argv) { 69 UIEXPORT void ui_init(const char *appname, int argc, char **argv) {
70 application_name = appname;
66 uic_init_global_context(); 71 uic_init_global_context();
67 72
73 #if GTK_MAJOR_VERSION >= 4
74 gtk_init();
75 #else
68 gtk_init(&argc, &argv); 76 gtk_init(&argc, &argv);
69 application_name = appname; 77 #endif
70 78
79 ui_css_init();
71 uic_docmgr_init(); 80 uic_docmgr_init();
72 ui_toolbar_init(); 81 uic_menu_init();
73 82 uic_toolbar_init();
74 // init custom types
75 ui_list_init();
76
77 ui_image_init(); 83 ui_image_init();
78
79 uic_load_app_properties(); 84 uic_load_app_properties();
80 85
81 #ifdef UI_SUPPORTS_SCALE 86 #if GTK_MAJOR_VERSION >= 4
87 scale_factor = 1; // TODO
88 #elif defined(UI_SUPPORTS_SCALE)
82 scale_factor = gdk_monitor_get_scale_factor( 89 scale_factor = gdk_monitor_get_scale_factor(
83 gdk_display_get_primary_monitor(gdk_display_get_default())); 90 gdk_display_get_primary_monitor(gdk_display_get_default()));
84 #endif 91 #endif
85 } 92 }
86 93
87 char* ui_appname() { 94 const char* ui_appname() {
88 return application_name; 95 return application_name;
89 } 96 }
90 97
91 void ui_onstartup(ui_callback f, void *userdata) { 98 void ui_onstartup(ui_callback f, void *userdata) {
92 startup_func = f; 99 startup_func = f;
115 printf("activate\n"); 122 printf("activate\n");
116 } 123 }
117 #endif 124 #endif
118 125
119 void ui_main() { 126 void ui_main() {
120 #ifndef UI_GTK2 127 #ifdef UI_APPLICATION
121 sstr_t appid = ucx_sprintf( 128 cxmutstr appid = cx_asprintf(
122 "ui.%s", 129 "ui.%s",
123 application_name ? application_name : "application1"); 130 application_name ? application_name : "application1");
124 131 app = UI_APPLICATION_NEW(appid.ptr);
125 app = gtk_application_new(
126 appid.ptr,
127 G_APPLICATION_FLAGS_NONE);
128 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL); 132 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
129 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL); 133 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
130 g_application_run(G_APPLICATION (app), 0, NULL); 134 g_application_run(G_APPLICATION (app), 0, NULL);
131 g_object_unref (app); 135 g_object_unref (app);
132 136
147 void ui_app_quit() { 151 void ui_app_quit() {
148 g_application_quit(G_APPLICATION(app)); 152 g_application_quit(G_APPLICATION(app));
149 } 153 }
150 154
151 GtkApplication* ui_get_application() { 155 GtkApplication* ui_get_application() {
152 return app; 156 return GTK_APPLICATION(app);
153 } 157 }
154 #endif 158 #endif
155 159
156 void ui_show(UiObject *obj) { 160 void ui_show(UiObject *obj) {
161 gboolean visible = gtk_widget_is_visible(obj->widget);
162
157 uic_check_group_widgets(obj->ctx); 163 uic_check_group_widgets(obj->ctx);
164 #if GTK_MAJOR_VERSION >= 4
165 gtk_window_present(GTK_WINDOW(obj->widget));
166 #elif GTK_MAJOR_VERSION <= 3
158 gtk_widget_show_all(obj->widget); 167 gtk_widget_show_all(obj->widget);
168 #endif
169
170 if(!visible) {
171 obj->ref++;
172 }
159 } 173 }
160 174
161 void ui_close(UiObject *obj) { 175 void ui_close(UiObject *obj) {
176 uic_context_prepare_close(obj->ctx);
177 #if GTK_CHECK_VERSION(4, 0, 0)
178 gtk_window_close(GTK_WINDOW(obj->widget));
179 #else
162 gtk_widget_destroy(obj->widget); 180 gtk_widget_destroy(obj->widget);
181 #endif
163 } 182 }
164 183
165 184
166 static gboolean ui_job_finished(void *data) { 185 static gboolean ui_job_finished(void *data) {
167 UiJob *job = data; 186 UiJob *job = data;
179 } 198 }
180 199
181 static void* ui_jobthread(void *data) { 200 static void* ui_jobthread(void *data) {
182 UiJob *job = data; 201 UiJob *job = data;
183 int result = job->job_func(job->job_data); 202 int result = job->job_func(job->job_data);
184 if(!result) { 203 if(!result && job->finish_callback) {
185 g_idle_add(ui_job_finished, job); 204 g_idle_add(ui_job_finished, job);
205 } else {
206 free(job);
186 } 207 }
187 return NULL; 208 return NULL;
209 }
210
211 static gboolean ui_idle_func(void *data) {
212 UiJob *job = data;
213 job->job_func(job->job_data);
214 free(job);
215 return FALSE;
216 }
217
218 void ui_call_mainthread(ui_threadfunc tf, void* td) {
219 UiJob *job = malloc(sizeof(UiJob));
220 job->job_func = tf;
221 job->job_data = td;
222 job->finish_callback = NULL;
223 job->finish_data = NULL;
224 job->obj = NULL;
225 g_idle_add(ui_idle_func, job);
188 } 226 }
189 227
190 void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd) { 228 void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd) {
191 UiJob *job = malloc(sizeof(UiJob)); 229 UiJob *job = malloc(sizeof(UiJob));
192 job->obj = obj; 230 job->obj = obj;
201 void ui_set_enabled(UIWIDGET widget, int enabled) { 239 void ui_set_enabled(UIWIDGET widget, int enabled) {
202 gtk_widget_set_sensitive(widget, enabled); 240 gtk_widget_set_sensitive(widget, enabled);
203 } 241 }
204 242
205 void ui_set_show_all(UIWIDGET widget, int value) { 243 void ui_set_show_all(UIWIDGET widget, int value) {
244 // TODO: gtk4
245 #if GTK_MAJOR_VERSION <= 3
206 gtk_widget_set_no_show_all(widget, !value); 246 gtk_widget_set_no_show_all(widget, !value);
247 #endif
207 } 248 }
208 249
209 void ui_set_visible(UIWIDGET widget, int visible) { 250 void ui_set_visible(UIWIDGET widget, int visible) {
251 // TODO: gtk4
252 #if GTK_MAJOR_VERSION <= 3
210 if(visible) { 253 if(visible) {
211 gtk_widget_set_no_show_all(widget, FALSE); 254 gtk_widget_set_no_show_all(widget, FALSE);
212 gtk_widget_show_all(widget); 255 gtk_widget_show_all(widget);
213 } else { 256 } else {
214 gtk_widget_hide(widget); 257 gtk_widget_hide(widget);
215 } 258 }
259 #endif
216 } 260 }
217 261
218 void ui_clipboard_set(char *str) { 262 void ui_clipboard_set(char *str) {
263 #if GTK_MAJOR_VERSION >= 4
264 // TODO: gtk4: needs widget
265 #else
219 GtkClipboard *cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); 266 GtkClipboard *cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
220 gtk_clipboard_set_text(cb, str, strlen(str)); 267 gtk_clipboard_set_text(cb, str, strlen(str));
268 #endif
221 } 269 }
222 270
223 char* ui_clipboard_get() { 271 char* ui_clipboard_get() {
272 #if GTK_MAJOR_VERSION >= 4
273 // TODO: gtk4: needs widget
274 return NULL;
275 #else
224 GtkClipboard *cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); 276 GtkClipboard *cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
225 char *str = gtk_clipboard_wait_for_text(cb); 277 char *str = gtk_clipboard_wait_for_text(cb);
226 if(str) { 278 if(str) {
227 char *copy = strdup(str); 279 char *copy = strdup(str);
228 g_free(str); 280 g_free(str);
229 return copy; 281 return copy;
230 } else { 282 } else {
231 return NULL; 283 return NULL;
232 } 284 }
285 #endif
233 } 286 }
234 287
235 int ui_get_scalefactor() { 288 int ui_get_scalefactor() {
236 return scale_factor; 289 return scale_factor;
237 } 290 }
239 void ui_destroy_userdata(GtkWidget *object, void *userdata) { 292 void ui_destroy_userdata(GtkWidget *object, void *userdata) {
240 free(userdata); 293 free(userdata);
241 } 294 }
242 295
243 void ui_destroy_vardata(GtkWidget *object, UiVarEventData *data) { 296 void ui_destroy_vardata(GtkWidget *object, UiVarEventData *data) {
244 ui_destroy_boundvar(data->obj->ctx, data->var); 297 if(data->var) {
298 ui_destroy_boundvar(data->obj->ctx, data->var);
299 }
245 free(data); 300 free(data);
246 } 301 }
247 302
303 void ui_destroy_widget_var(GtkWidget *object, UiVar *var) {
304 ui_destroy_boundvar(NULL, var);
305 }
306
248 void ui_destroy_boundvar(UiContext *ctx, UiVar *var) { 307 void ui_destroy_boundvar(UiContext *ctx, UiVar *var) {
308 uic_unbind_var(var);
309
249 if(var->type == UI_VAR_SPECIAL) { 310 if(var->type == UI_VAR_SPECIAL) {
250 free(var); 311 ui_free(var->from_ctx, var);
251 } else { 312 } else {
252 uic_remove_bound_var(ctx, var); 313 ui_free(var->from_ctx, var);
314 // TODO: free or unbound
315 //uic_remove_bound_var(ctx, var);
253 } 316 }
254 } 317 }
255 318
256 void ui_set_active_window(UiObject *obj) { 319 void ui_set_active_window(UiObject *obj) {
257 active_window = obj; 320 active_window = obj;
260 UiObject *ui_get_active_window() { 323 UiObject *ui_get_active_window() {
261 return active_window; 324 return active_window;
262 } 325 }
263 326
264 327
328 #if GTK_MAJOR_VERSION >= 3
329
330 static GtkCssProvider* ui_gtk_css_provider;
331
332 #if GTK_MAJOR_VERSION == 4
333 static const char *ui_gtk_css =
334 "#path-textfield-box {\n"
335 " background-color: alpha(currentColor, 0.1);"
336 " border-radius: 6px;"
337 " padding: 0px;"
338 "}\n"
339 ".pathbar-extra-button {\n"
340 " border-top-right-radius: 6px;"
341 " border-bottom-right-radius: 6px;"
342 " border-top-left-radius: 0px;"
343 " border-bottom-left-radius: 0px;"
344 "}\n"
345 "#pathbar button {\n"
346 " margin: 3px;"
347 " border-radius: 4px;"
348 " padding-top: 0px;"
349 " padding-bottom: 0px;"
350 " padding-left: 8px;"
351 " padding-right: 8px;"
352 "}\n"
353 "#path-textfield-box entry {\n"
354 " background-color: #00000000;"
355 " border-top-left-radius: 6px;"
356 " border-bottom-left-radius: 6px;"
357 " border-top-right-radius: 0px;"
358 " border-bottom-right-radius: 0px;"
359 "}\n"
360 ".pathbar-button-inactive {\n"
361 " color: alpha(currentColor, 0.5);"
362 "}\n"
363 ".ui_test {\n"
364 " background-color: red;\n"
365 "}\n"
366 ".ui_label_title {\n"
367 " font-weight: bold;\n"
368 "}\n"
369 ".ui-listbox-header {\n"
370 " font-weight: bold;\n"
371 " margin-left: 10px;\n"
372 " margin-top: 12px;\n"
373 " margin-bottom: 10px;\n"
374 "}\n"
375 ".ui-listbox-header-first {\n"
376 " font-weight: bold;\n"
377 " margin-left: 10px;\n"
378 " margin-top: 4px;\n"
379 " margin-bottom: 10px;\n"
380 "}\n"
381 ;
382
383 #elif GTK_MAJOR_VERSION == 3
384 static const char *ui_gtk_css =
385 "#path-textfield-box {\n"
386 " background-color: @theme_base_color;\n"
387 " border-radius: 5px;\n"
388 " padding: 0px;\n"
389 "}\n"
390 ".pathbar-button-inactive {\n"
391 " color: alpha(currentColor, 0.5);"
392 "}\n"
393 ".ui_test {\n"
394 " background-color: red;\n"
395 "}\n"
396 ".ui_label_title {\n"
397 " font-weight: bold;\n"
398 "}\n"
399 "placessidebar row {\n"
400 " padding-left: 10px;\n"
401 "}\n"
402 ".ui-listbox-header {\n"
403 " font-weight: bold;\n"
404 " margin-left: 10px;\n"
405 " margin-top: 12px;\n"
406 " margin-bottom: 10px;\n"
407 "}\n"
408 ".ui-listbox-header-first {\n"
409 " font-weight: bold;\n"
410 " margin-left: 10px;\n"
411 " margin-top: 4px;\n"
412 " margin-bottom: 10px;\n"
413 "}\n"
414 ;
415 #endif
416
417 void ui_css_init(void) {
418 ui_gtk_css_provider = gtk_css_provider_new();
419
420 #ifdef UI_GTK3
421 gtk_css_provider_load_from_data(ui_gtk_css_provider, ui_gtk_css, -1, NULL);
422
423 GdkScreen *screen = gdk_screen_get_default();
424 gtk_style_context_add_provider_for_screen(
425 screen,
426 GTK_STYLE_PROVIDER(ui_gtk_css_provider),
427 GTK_STYLE_PROVIDER_PRIORITY_USER);
428 #endif /* UI_GTK3 */
429
430 #ifdef UI_GTK4
431
432
433 #if GTK_MINOR_VERSION < 12
434 gtk_css_provider_load_from_data(ui_gtk_css_provider, ui_gtk_css, -1);
435 #else
436 gtk_css_provider_load_from_string(ui_gtk_css_provider, ui_gtk_css);
437 #endif /* GTK_MINOR_VERSION < 12 */
438
439 GdkDisplay *display = gdk_display_get_default();
440 gtk_style_context_add_provider_for_display(display, GTK_STYLE_PROVIDER(ui_gtk_css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
441
442 #endif /* UI_GTK4 */
443 }
444
445
446
447 #endif
448
449 void ui_set_name_and_style(GtkWidget *widget, const char *name, const char *style_classes) {
450 if(name) {
451 gtk_widget_set_name(widget, name);
452 }
453 if(style_classes) {
454 cxstring *cls = NULL;
455 size_t numClasses = cx_strsplit_a(cxDefaultAllocator, cx_str(style_classes), CX_STR(" "), 128, &cls);
456 for(int i=0;i<numClasses;i++) {
457 cxmutstr m = cx_strdup(cls[i]);
458 #if GTK_MAJOR_VERSION >= 4
459 gtk_widget_add_css_class(widget, m.ptr);
460 #elif GTK_MAJOR_VERSION >= 3
461 GtkStyleContext *ctx = gtk_widget_get_style_context(widget);
462 gtk_style_context_add_class(ctx, m.ptr);
463 #endif
464 free(m.ptr);
465 }
466 free(cls);
467
468 }
469 }
470
471 void ui_set_widget_groups(UiContext *ctx, GtkWidget *widget, const int *groups) {
472 if(!groups) {
473 return;
474 }
475 size_t ngroups = uic_group_array_size(groups);
476 ui_set_widget_ngroups(ctx, widget, groups, ngroups);
477 }
478
479 void ui_set_widget_ngroups(UiContext *ctx, GtkWidget *widget, const int *groups, size_t ngroups) {
480 if(ngroups > 0) {
481 uic_add_group_widget_i(ctx, widget, (ui_enablefunc)ui_set_enabled, groups, ngroups);
482 ui_set_enabled(widget, FALSE);
483 }
484 }

mercurial