Sun, 09 Jun 2024 15:43:08 +0200
update toolkit
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2017 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #include "toolkit.h" #include "toolbar.h" #include "image.h" #include "../common/document.h" #include "../common/properties.h" #include "../common/menu.h" #include "../common/toolbar.h" #include "../common/threadpool.h" #include <cx/utils.h> #include <cx/string.h> #include <cx/printf.h> #include <pthread.h> #ifndef UI_GTK2 static GtkApplication *app; #endif static const char *application_name; static ui_callback startup_func; static void *startup_data; static ui_callback open_func; void *open_data; static ui_callback exit_func; void *exit_data; static ui_callback appclose_fnc; static void *appclose_udata; static UiObject *active_window; static int scale_factor = 1; UIEXPORT void ui_init(const char *appname, int argc, char **argv) { uic_init_global_context(); gtk_init(&argc, &argv); application_name = appname; ui_css_init(); uic_docmgr_init(); uic_toolbar_init(); ui_image_init(); uic_load_app_properties(); #ifdef UI_SUPPORTS_SCALE scale_factor = gdk_monitor_get_scale_factor( gdk_display_get_primary_monitor(gdk_display_get_default())); #endif } const char* ui_appname() { return application_name; } void ui_onstartup(ui_callback f, void *userdata) { startup_func = f; startup_data = userdata; } void ui_onopen(ui_callback f, void *userdata) { open_func = f; open_data = userdata; } void ui_onexit(ui_callback f, void *userdata) { exit_func = f; exit_data = userdata; } #ifndef UI_GTK2 static void app_startup(GtkApplication* app, gpointer userdata) { if(startup_func) { startup_func(NULL, startup_data); } } static void app_activate(GtkApplication* app, gpointer userdata) { printf("activate\n"); } #endif void ui_main() { #ifndef UI_GTK2 cxmutstr appid = cx_asprintf( "ui.%s", application_name ? application_name : "application1"); app = gtk_application_new( appid.ptr, G_APPLICATION_FLAGS_NONE); 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); g_object_unref (app); free(appid.ptr); #else if(startup_func) { startup_func(NULL, startup_data); } gtk_main(); #endif if(exit_func) { exit_func(NULL, exit_data); } uic_store_app_properties(); } #ifndef UI_GTK2 void ui_app_quit() { g_application_quit(G_APPLICATION(app)); } GtkApplication* ui_get_application() { return app; } #endif void ui_show(UiObject *obj) { uic_check_group_widgets(obj->ctx); gtk_widget_show_all(obj->widget); } void ui_close(UiObject *obj) { gtk_widget_destroy(obj->widget); } static gboolean ui_job_finished(void *data) { UiJob *job = data; UiEvent event; event.obj = job->obj; event.window = job->obj->window; event.document = job->obj->ctx->document; event.intval = 0; event.eventdata = NULL; job->finish_callback(&event, job->finish_data); free(job); return FALSE; } static void* ui_jobthread(void *data) { UiJob *job = data; int result = job->job_func(job->job_data); if(!result) { g_idle_add(ui_job_finished, 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; job->job_func = tf; job->job_data = td; job->finish_callback = f; job->finish_data = fd; pthread_t pid; pthread_create(&pid, NULL, ui_jobthread, job); } void ui_set_enabled(UIWIDGET widget, int enabled) { gtk_widget_set_sensitive(widget, enabled); } void ui_set_show_all(UIWIDGET widget, int value) { gtk_widget_set_no_show_all(widget, !value); } void ui_set_visible(UIWIDGET widget, int visible) { if(visible) { gtk_widget_set_no_show_all(widget, FALSE); gtk_widget_show_all(widget); } else { gtk_widget_hide(widget); } } void ui_clipboard_set(char *str) { GtkClipboard *cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); gtk_clipboard_set_text(cb, str, strlen(str)); } char* ui_clipboard_get() { GtkClipboard *cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); char *str = gtk_clipboard_wait_for_text(cb); if(str) { char *copy = strdup(str); g_free(str); return copy; } else { return NULL; } } int ui_get_scalefactor() { return scale_factor; } void ui_destroy_userdata(GtkWidget *object, void *userdata) { free(userdata); } void ui_destroy_vardata(GtkWidget *object, UiVarEventData *data) { if(data->var) { ui_destroy_boundvar(data->obj->ctx, data->var); } free(data); } void ui_destroy_boundvar(UiContext *ctx, UiVar *var) { uic_unbind_var(var); if(var->type == UI_VAR_SPECIAL) { free(var); } else { ui_free(var->from_ctx, var); // TODO: free or unbound //uic_remove_bound_var(ctx, var); } } void ui_set_active_window(UiObject *obj) { active_window = obj; } UiObject *ui_get_active_window() { return active_window; } #if GTK_MAJOR_VERSION >= 3 static GtkCssProvider* ui_gtk_css_provider; static const char *ui_gtk_css = "#path-textfield-box {" " background-color: @theme_base_color;" " border-radius: 5px;" " padding: 0px;" "}"; void ui_css_init(void) { ui_gtk_css_provider = gtk_css_provider_new(); 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