--- a/ui/gtk/toolkit.c Sun May 23 09:44:43 2021 +0200 +++ b/ui/gtk/toolkit.c Sat Jan 04 16:38:48 2025 +0100 @@ -33,20 +33,24 @@ #include "toolkit.h" #include "toolbar.h" -#include "model.h" -#include "image.h" +#include "icon.h" #include "../common/document.h" #include "../common/properties.h" +#include "../common/menu.h" +#include "../common/toolbar.h" +#include "../common/threadpool.h" -#include <ucx/utils.h> +#include <cx/utils.h> +#include <cx/string.h> +#include <cx/printf.h> #include <pthread.h> -#ifndef UI_GTK2 -static GtkApplication *app; +#ifdef UI_APPLICATION +UI_APPLICATION app; #endif -static char *application_name; +static const char *application_name; static ui_callback startup_func; static void *startup_data; @@ -62,29 +66,32 @@ static int scale_factor = 1; -void ui_init(char *appname, int argc, char **argv) { +UIEXPORT void ui_init(const char *appname, int argc, char **argv) { + application_name = appname; uic_init_global_context(); +#if GTK_MAJOR_VERSION >= 4 + gtk_init(); +#else gtk_init(&argc, &argv); - application_name = appname; - - uic_docmgr_init(); - ui_toolbar_init(); +#endif - // init custom types - ui_list_init(); - + ui_css_init(); + uic_docmgr_init(); + uic_menu_init(); + uic_toolbar_init(); ui_image_init(); - uic_load_app_properties(); -#ifdef UI_SUPPORTS_SCALE +#if GTK_MAJOR_VERSION >= 4 + scale_factor = 1; // TODO +#elif defined(UI_SUPPORTS_SCALE) scale_factor = gdk_monitor_get_scale_factor( gdk_display_get_primary_monitor(gdk_display_get_default())); #endif } -char* ui_appname() { +const char* ui_appname() { return application_name; } @@ -117,14 +124,11 @@ #endif void ui_main() { -#ifndef UI_GTK2 - sstr_t appid = ucx_sprintf( +#ifdef UI_APPLICATION + cxmutstr appid = cx_asprintf( "ui.%s", application_name ? application_name : "application1"); - - app = gtk_application_new( - appid.ptr, - G_APPLICATION_FLAGS_NONE); + app = UI_APPLICATION_NEW(appid.ptr); g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL); g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL); g_application_run(G_APPLICATION (app), 0, NULL); @@ -149,17 +153,32 @@ } GtkApplication* ui_get_application() { - return app; + return GTK_APPLICATION(app); } #endif void ui_show(UiObject *obj) { + gboolean visible = gtk_widget_is_visible(obj->widget); + uic_check_group_widgets(obj->ctx); +#if GTK_MAJOR_VERSION >= 4 + gtk_window_present(GTK_WINDOW(obj->widget)); +#elif GTK_MAJOR_VERSION <= 3 gtk_widget_show_all(obj->widget); +#endif + + if(!visible) { + obj->ref++; + } } void ui_close(UiObject *obj) { + uic_context_prepare_close(obj->ctx); +#if GTK_CHECK_VERSION(4, 0, 0) + gtk_window_close(GTK_WINDOW(obj->widget)); +#else gtk_widget_destroy(obj->widget); +#endif } @@ -181,12 +200,31 @@ static void* ui_jobthread(void *data) { UiJob *job = data; int result = job->job_func(job->job_data); - if(!result) { + if(!result && job->finish_callback) { g_idle_add(ui_job_finished, job); + } else { + free(job); } return NULL; } +static gboolean ui_idle_func(void *data) { + UiJob *job = data; + job->job_func(job->job_data); + free(job); + return FALSE; +} + +void ui_call_mainthread(ui_threadfunc tf, void* td) { + UiJob *job = malloc(sizeof(UiJob)); + job->job_func = tf; + job->job_data = td; + job->finish_callback = NULL; + job->finish_data = NULL; + job->obj = NULL; + g_idle_add(ui_idle_func, job); +} + void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd) { UiJob *job = malloc(sizeof(UiJob)); job->obj = obj; @@ -203,24 +241,38 @@ } void ui_set_show_all(UIWIDGET widget, int value) { + // TODO: gtk4 +#if GTK_MAJOR_VERSION <= 3 gtk_widget_set_no_show_all(widget, !value); +#endif } void ui_set_visible(UIWIDGET widget, int visible) { + // TODO: gtk4 +#if GTK_MAJOR_VERSION <= 3 if(visible) { gtk_widget_set_no_show_all(widget, FALSE); gtk_widget_show_all(widget); } else { gtk_widget_hide(widget); } +#endif } void ui_clipboard_set(char *str) { +#if GTK_MAJOR_VERSION >= 4 + // TODO: gtk4: needs widget +#else GtkClipboard *cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); gtk_clipboard_set_text(cb, str, strlen(str)); +#endif } char* ui_clipboard_get() { +#if GTK_MAJOR_VERSION >= 4 + // TODO: gtk4: needs widget + return NULL; +#else GtkClipboard *cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); char *str = gtk_clipboard_wait_for_text(cb); if(str) { @@ -230,6 +282,7 @@ } else { return NULL; } +#endif } int ui_get_scalefactor() { @@ -241,15 +294,25 @@ } void ui_destroy_vardata(GtkWidget *object, UiVarEventData *data) { - ui_destroy_boundvar(data->obj->ctx, data->var); + if(data->var) { + ui_destroy_boundvar(data->obj->ctx, data->var); + } free(data); } +void ui_destroy_widget_var(GtkWidget *object, UiVar *var) { + ui_destroy_boundvar(NULL, var); +} + void ui_destroy_boundvar(UiContext *ctx, UiVar *var) { + uic_unbind_var(var); + if(var->type == UI_VAR_SPECIAL) { - free(var); + ui_free(var->from_ctx, var); } else { - uic_remove_bound_var(ctx, var); + ui_free(var->from_ctx, var); + // TODO: free or unbound + //uic_remove_bound_var(ctx, var); } } @@ -262,3 +325,160 @@ } +#if GTK_MAJOR_VERSION >= 3 + +static GtkCssProvider* ui_gtk_css_provider; + +#if GTK_MAJOR_VERSION == 4 +static const char *ui_gtk_css = +"#path-textfield-box {\n" +" background-color: alpha(currentColor, 0.1);" +" border-radius: 6px;" +" padding: 0px;" +"}\n" +".pathbar-extra-button {\n" +" border-top-right-radius: 6px;" +" border-bottom-right-radius: 6px;" +" border-top-left-radius: 0px;" +" border-bottom-left-radius: 0px;" +"}\n" +"#pathbar button {\n" +" margin: 3px;" +" border-radius: 4px;" +" padding-top: 0px;" +" padding-bottom: 0px;" +" padding-left: 8px;" +" padding-right: 8px;" +"}\n" +"#path-textfield-box entry {\n" +" background-color: #00000000;" +" border-top-left-radius: 6px;" +" border-bottom-left-radius: 6px;" +" border-top-right-radius: 0px;" +" border-bottom-right-radius: 0px;" +"}\n" +".pathbar-button-inactive {\n" +" color: alpha(currentColor, 0.5);" +"}\n" +".ui_test {\n" +" background-color: red;\n" +"}\n" +".ui_label_title {\n" +" font-weight: bold;\n" +"}\n" +".ui-listbox-header {\n" +" font-weight: bold;\n" +" margin-left: 10px;\n" +" margin-top: 12px;\n" +" margin-bottom: 10px;\n" +"}\n" +".ui-listbox-header-first {\n" +" font-weight: bold;\n" +" margin-left: 10px;\n" +" margin-top: 4px;\n" +" margin-bottom: 10px;\n" +"}\n" +; + +#elif GTK_MAJOR_VERSION == 3 +static const char *ui_gtk_css = +"#path-textfield-box {\n" +" background-color: @theme_base_color;\n" +" border-radius: 5px;\n" +" padding: 0px;\n" +"}\n" +".pathbar-button-inactive {\n" +" color: alpha(currentColor, 0.5);" +"}\n" +".ui_test {\n" +" background-color: red;\n" +"}\n" +".ui_label_title {\n" +" font-weight: bold;\n" +"}\n" +"placessidebar row {\n" +" padding-left: 10px;\n" +"}\n" +".ui-listbox-header {\n" +" font-weight: bold;\n" +" margin-left: 10px;\n" +" margin-top: 12px;\n" +" margin-bottom: 10px;\n" +"}\n" +".ui-listbox-header-first {\n" +" font-weight: bold;\n" +" margin-left: 10px;\n" +" margin-top: 4px;\n" +" margin-bottom: 10px;\n" +"}\n" +; +#endif + +void ui_css_init(void) { + ui_gtk_css_provider = gtk_css_provider_new(); + +#ifdef UI_GTK3 + gtk_css_provider_load_from_data(ui_gtk_css_provider, ui_gtk_css, -1, NULL); + + GdkScreen *screen = gdk_screen_get_default(); + gtk_style_context_add_provider_for_screen( + screen, + GTK_STYLE_PROVIDER(ui_gtk_css_provider), + GTK_STYLE_PROVIDER_PRIORITY_USER); +#endif /* UI_GTK3 */ + +#ifdef UI_GTK4 + + +#if GTK_MINOR_VERSION < 12 + gtk_css_provider_load_from_data(ui_gtk_css_provider, ui_gtk_css, -1); +#else + gtk_css_provider_load_from_string(ui_gtk_css_provider, ui_gtk_css); +#endif /* GTK_MINOR_VERSION < 12 */ + + GdkDisplay *display = gdk_display_get_default(); + gtk_style_context_add_provider_for_display(display, GTK_STYLE_PROVIDER(ui_gtk_css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + +#endif /* UI_GTK4 */ +} + + + +#endif + +void ui_set_name_and_style(GtkWidget *widget, const char *name, const char *style_classes) { + if(name) { + gtk_widget_set_name(widget, name); + } + if(style_classes) { + cxstring *cls = NULL; + size_t numClasses = cx_strsplit_a(cxDefaultAllocator, cx_str(style_classes), CX_STR(" "), 128, &cls); + for(int i=0;i<numClasses;i++) { + cxmutstr m = cx_strdup(cls[i]); +#if GTK_MAJOR_VERSION >= 4 + gtk_widget_add_css_class(widget, m.ptr); +#elif GTK_MAJOR_VERSION >= 3 + GtkStyleContext *ctx = gtk_widget_get_style_context(widget); + gtk_style_context_add_class(ctx, m.ptr); +#endif + free(m.ptr); + } + free(cls); + + } +} + +void ui_set_widget_groups(UiContext *ctx, GtkWidget *widget, const int *groups) { + if(!groups) { + return; + } + size_t ngroups = uic_group_array_size(groups); + ui_set_widget_ngroups(ctx, widget, groups, ngroups); +} + +void ui_set_widget_ngroups(UiContext *ctx, GtkWidget *widget, const int *groups, size_t ngroups) { + if(ngroups > 0) { + uic_add_group_widget_i(ctx, widget, (ui_enablefunc)ui_set_enabled, groups, ngroups); + ui_set_enabled(widget, FALSE); + } +}