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 } |