ui/gtk/toolkit.c

changeset 431
bb7da585debc
parent 413
b8e41d42f400
--- 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);
+    }
+}

mercurial