anastasis-gtk

Demonstrator GUI for Anastasis
Log | Files | Refs | README | LICENSE

commit 0c17cf992250fe23cc1ac72433cd23f82f442a38
parent 0367d82c6170047b45e6a7b1798e382e0a91d6a5
Author: Christian Grothoff <grothoff@gnunet.org>
Date:   Sun, 12 Oct 2025 18:42:06 +0200

remove dependency on gnunet-gtk

Diffstat:
Mconfigure.ac | 27---------------------------
Mdebian/control | 1-
Mpo/POTFILES.in | 7+++++++
Msrc/anastasis/Makefile.am | 1-
Msrc/anastasis/anastasis-gtk.c | 14+++++++-------
Msrc/anastasis/anastasis-gtk.h | 5+++--
Msrc/anastasis/anastasis-gtk_action.c | 14+++++++-------
Msrc/anastasis/anastasis-gtk_handle-add-provider.c | 2+-
Msrc/anastasis/anastasis-gtk_handle-auth-edit-provider-clicked.c | 2+-
Msrc/anastasis/anastasis-gtk_handle-main-window-forward-clicked.c | 6+++---
Msrc/anastasis/anastasis-gtk_handle-method-email.c | 2+-
Msrc/anastasis/anastasis-gtk_handle-method-iban.c | 2+-
Msrc/anastasis/anastasis-gtk_handle-method-post.c | 2+-
Msrc/anastasis/anastasis-gtk_handle-method-question.c | 2+-
Msrc/anastasis/anastasis-gtk_handle-method-sms.c | 2+-
Msrc/anastasis/anastasis-gtk_handle-method-totp.c | 2+-
Msrc/anastasis/anastasis-gtk_handle-secret-buttons.c | 8++++----
Msrc/anastasis/anastasis-gtk_helper.c | 4++--
Msrc/anastasis/anastasis-gtk_io.c | 8++++----
Msrc/anastasis/anastasis-gtk_pe-edit-policy.c | 2+-
Msrc/include/anastasis_gtk_util.h | 260+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/util/Makefile.am | 3+++
Asrc/util/eventloop.c | 580+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/util/glade.c | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/util/nls.c | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
25 files changed, 1151 insertions(+), 67 deletions(-)

diff --git a/configure.ac b/configure.ac @@ -371,33 +371,6 @@ AC_SUBST(GLADE_CFLAGS) AC_SUBST(GLADE_LIBS) -# test for libgnunetgtk -gnunetgtk=0 -AC_MSG_CHECKING(for libgnunetgtk) -AC_ARG_WITH(gnunetgtk, - [ --with-gnunetgtk=PFX Base of libgnunetgtk installation], - [AC_MSG_RESULT([$with_gnunetgtk]) - AS_CASE([$with_gnunetgtk], - [no],[], - [yes],[ - AC_CHECK_HEADERS([gnunet-gtk/gnunet_gtk.h],gnunetgtk=1) - ], - [ - CPPFLAGS="-I$with_gnunetgtk/include $CPPFLAGS" - CFLAGS="-I$with_gnunetgtk/include $CFLAGS" - LIBS="-lgnunetgtk $LIBS" - AC_CHECK_HEADERS([gnunet-gtk/gnunet_gtk.h],gnunetgtk=1) - ]) - ], - [AC_MSG_RESULT([--with-gnunetgtk not specified]) - AC_CHECK_HEADERS([gnunet-gtk/gnunet_gtk.h],gnunetgtk=1)]) - -AS_IF([test "$gnunetgtk" != 1], -[ - AC_MSG_ERROR([anastasis-gtk requires libgnunetgtk]) -]) - - # Adam shostack suggests the following for Windows: # -D_FORTIFY_SOURCE=2 -fstack-protector-all AC_ARG_ENABLE(gcc-hardening, diff --git a/debian/control b/debian/control @@ -5,7 +5,6 @@ Maintainer: Bertrand Marc <bmarc@debian.org> Build-Depends: autopoint, debhelper-compat (= 12), - libgnunetgtk-dev (>= 0.24.0), libgnunet-dev (>= 0.24.0), libanastasis-dev (>= 0.6.3), libgladeui-dev (>=3.10.0), diff --git a/po/POTFILES.in b/po/POTFILES.in @@ -46,7 +46,14 @@ src/anastasis/anastasis-gtk_pe-edit-policy.c src/anastasis/anastasis-gtk_progress.c src/anastasis/print.c src/anastasis/test-print.c +src/util/about.c +src/util/animations.c +src/util/eventloop.c +src/util/glade.c +src/util/misc.c +src/util/nls.c src/util/os_installation.c +src/util/trayicon.c contrib/anastasis_gtk_add_provider.glade contrib/anastasis_gtk_auth_add_email.glade contrib/anastasis_gtk_auth_add_iban.glade diff --git a/src/anastasis/Makefile.am b/src/anastasis/Makefile.am @@ -78,7 +78,6 @@ anastasis_gtk_LDADD = \ -lanastasisutil \ -ltalerjson \ -ltalerutil \ - -lgnunetgtk \ -lgnunetutil \ -lgnunetcurl \ -lgnunetjson \ diff --git a/src/anastasis/anastasis-gtk.c b/src/anastasis/anastasis-gtk.c @@ -33,7 +33,7 @@ /** * Handle to our main loop. */ -struct GNUNET_GTK_MainLoop *AG_ml; +struct ANASTASIS_GTK_MainLoop *AG_ml; /** * Active policy discovery job, or NULL. @@ -139,7 +139,7 @@ shutdown_task (void *cls) GNUNET_CURL_gnunet_rc_destroy (rc); rc = NULL; } - GNUNET_GTK_main_loop_quit (AG_ml); + ANASTASIS_GTK_main_loop_quit (AG_ml); AG_ml = NULL; GNUNET_CONTAINER_multihashmap_destroy (AG_entry_attributes); AG_entry_attributes = NULL; @@ -217,14 +217,14 @@ run (void *cls) AG_ml = cls; AG_entry_attributes = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO); - GNUNET_GTK_setup_nls (); + ANASTASIS_GTK_setup_nls (); if (GNUNET_OK != - GNUNET_GTK_main_loop_build_window (ANASTASIS_GTK_project_data (), + ANASTASIS_GTK_main_loop_build_window (ANASTASIS_GTK_project_data (), AG_ml, NULL)) return; - AG_cfg = GNUNET_GTK_main_loop_get_gtk_configuration (AG_ml); - GNUNET_GTK_main_loop_get_args (AG_ml, + AG_cfg = ANASTASIS_GTK_main_loop_get_gtk_configuration (AG_ml); + ANASTASIS_GTK_main_loop_get_args (AG_ml, &argc, &argv); /* setup main window */ @@ -270,7 +270,7 @@ main (int argc, AG_application_id = GNUNET_strdup ("anastasis-standalone"); if (GNUNET_OK != - GNUNET_GTK_main_loop_start (ANASTASIS_GTK_project_data (), + ANASTASIS_GTK_main_loop_start (ANASTASIS_GTK_project_data (), "anastasis-gtk", "GTK GUI for Anastasis", argc, diff --git a/src/anastasis/anastasis-gtk.h b/src/anastasis/anastasis-gtk.h @@ -26,7 +26,8 @@ */ #ifndef ANASTASIS_GTK_H #define ANASTASIS_GTK_H -#include <gnunet-gtk/gnunet_gtk.h> + +#include "anastasis_gtk_util.h" #include <gtk/gtk.h> #include <anastasis/anastasis_service.h> #include <anastasis/anastasis_redux.h> @@ -34,7 +35,7 @@ /** * Handle to our main loop. */ -extern struct GNUNET_GTK_MainLoop *AG_ml; +extern struct ANASTASIS_GTK_MainLoop *AG_ml; /** * Active policy discovery job, or NULL. diff --git a/src/anastasis/anastasis-gtk_action.c b/src/anastasis/anastasis-gtk_action.c @@ -437,7 +437,7 @@ create_attribute_widget (const struct GNUNET_HashCode *uh, GtkBin *bin; builder = - GNUNET_GTK_get_new_builder ( + ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "this_stays_private.glade", NULL); @@ -2406,7 +2406,7 @@ add_challenge (GtkBox *challenge_box, if (GNUNET_NO == ret) ok = false; - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_challenge_template.glade", NULL); @@ -2512,7 +2512,7 @@ add_policy (GtkBox *policy_box, AG_error ("Policy did not parse correctly"); return false; } - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_policy_template.glade", NULL); @@ -3030,7 +3030,7 @@ diag_question (const json_t *details) GtkBuilder *builder; GtkDialog *ad; - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_challenge_question.glade", NULL); @@ -3097,7 +3097,7 @@ diag_code (const json_t *details) return NULL; } - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_challenge_code.glade", NULL); @@ -3163,7 +3163,7 @@ diag_totp (const json_t *details) return NULL; } - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_challenge_totp.glade", NULL); @@ -3261,7 +3261,7 @@ diag_iban (const json_t *details) } } - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_challenge_iban.glade", NULL); diff --git a/src/anastasis/anastasis-gtk_handle-add-provider.c b/src/anastasis/anastasis-gtk_handle-add-provider.c @@ -244,7 +244,7 @@ anastasis_gtk_add_provider_button_clicked_cb (GtkButton *object, GNUNET_break (0); return; } - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_add_provider.glade", NULL); diff --git a/src/anastasis/anastasis-gtk_handle-auth-edit-provider-clicked.c b/src/anastasis/anastasis-gtk_handle-auth-edit-provider-clicked.c @@ -441,7 +441,7 @@ anastasis_gtk_edit_provider_list_clicked_cb (GtkButton *object, GtkListStore *ls; json_t *providers; - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_edit_providers.glade", NULL); diff --git a/src/anastasis/anastasis-gtk_handle-main-window-forward-clicked.c b/src/anastasis/anastasis-gtk_handle-main-window-forward-clicked.c @@ -141,7 +141,7 @@ question_certainty (void) GtkBuilder *builder; GtkDialog *ad; - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_user_sure.glade", NULL); @@ -265,7 +265,7 @@ question_sanity (void) GtkBuilder *builder; GtkDialog *ad; - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_warn_multifactor.glade", NULL); @@ -306,7 +306,7 @@ refuse_insanity (void) GtkBuilder *builder; GtkDialog *ad; - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_deny_singlefactor.glade", NULL); diff --git a/src/anastasis/anastasis-gtk_handle-method-email.c b/src/anastasis/anastasis-gtk_handle-method-email.c @@ -252,7 +252,7 @@ anastasis_gtk_btn_add_auth_email_clicked_cb (GObject *object, GtkWidget *ad; GtkBuilder *builder; - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_auth_add_email.glade", NULL); diff --git a/src/anastasis/anastasis-gtk_handle-method-iban.c b/src/anastasis/anastasis-gtk_handle-method-iban.c @@ -150,7 +150,7 @@ anastasis_gtk_btn_add_auth_iban_clicked_cb (GObject *object, GtkWidget *ad; GtkBuilder *builder; - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_auth_add_iban.glade", NULL); diff --git a/src/anastasis/anastasis-gtk_handle-method-post.c b/src/anastasis/anastasis-gtk_handle-method-post.c @@ -184,7 +184,7 @@ anastasis_gtk_btn_add_auth_post_clicked_cb (GObject *object, GtkWidget *ad; GtkBuilder *builder; - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_auth_add_post.glade", NULL); diff --git a/src/anastasis/anastasis-gtk_handle-method-question.c b/src/anastasis/anastasis-gtk_handle-method-question.c @@ -140,7 +140,7 @@ anastasis_gtk_btn_add_auth_question_clicked_cb (GObject *object, GtkWidget *ad; GtkBuilder *builder; - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_auth_add_question.glade", NULL); diff --git a/src/anastasis/anastasis-gtk_handle-method-sms.c b/src/anastasis/anastasis-gtk_handle-method-sms.c @@ -232,7 +232,7 @@ anastasis_gtk_btn_add_auth_sms_clicked_cb (GObject *object, GtkWidget *ad; GtkBuilder *builder; - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_auth_add_sms.glade", NULL); diff --git a/src/anastasis/anastasis-gtk_handle-method-totp.c b/src/anastasis/anastasis-gtk_handle-method-totp.c @@ -340,7 +340,7 @@ anastasis_gtk_btn_add_auth_totp_clicked_cb (GObject *object, GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, totp_key, sizeof (totp_key)); - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_auth_add_totp.glade", NULL); diff --git a/src/anastasis/anastasis-gtk_handle-secret-buttons.c b/src/anastasis/anastasis-gtk_handle-secret-buttons.c @@ -66,7 +66,7 @@ open_secret_dialog_response_cb (GtkDialog *dialog, return; } filename = - GNUNET_GTK_filechooser_get_filename_utf8 (GTK_FILE_CHOOSER (dialog)); + ANASTASIS_GTK_filechooser_get_filename_utf8 (GTK_FILE_CHOOSER (dialog)); gtk_widget_destroy (GTK_WIDGET (dialog)); g_object_unref (G_OBJECT (builder)); fn = strrchr (filename, @@ -187,7 +187,7 @@ anastasis_gtk_enter_secret_open_button_clicked_cb (GtkButton *button, (void) button; (void) user_data; - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_open_secret_dialog.glade", NULL); @@ -247,7 +247,7 @@ save_secret_dialog_response_cb (GtkDialog *dialog, return; } filename = - GNUNET_GTK_filechooser_get_filename_utf8 (GTK_FILE_CHOOSER (dialog)); + ANASTASIS_GTK_filechooser_get_filename_utf8 (GTK_FILE_CHOOSER (dialog)); gtk_widget_destroy (GTK_WIDGET (dialog)); g_object_unref (G_OBJECT (builder)); cs = json_object_get (AG_redux_state, @@ -357,7 +357,7 @@ anastasis_gtk_secret_save_as_button_clicked_cb (GtkButton *button, GNUNET_JSON_parse (cs, spec, NULL, NULL)); - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_save_secret_dialog.glade", NULL); diff --git a/src/anastasis/anastasis-gtk_helper.c b/src/anastasis/anastasis-gtk_helper.c @@ -223,7 +223,7 @@ GCG_get_main_window_object (const char *name) { if (NULL == AG_ml) return NULL; - return GNUNET_GTK_main_loop_get_object (AG_ml, + return ANASTASIS_GTK_main_loop_get_object (AG_ml, name); } @@ -343,7 +343,7 @@ create_qrcode (unsigned int scale, /* We use a trick to create a pixbuf in a way that works for both Gtk2 and Gtk3 by loading a dummy file from disk; all other methods are not portable to both Gtk2 and Gtk3. */ - dir = GNUNET_GTK_get_data_dir (ANASTASIS_GTK_project_data ()); + dir = ANASTASIS_GTK_get_data_dir (ANASTASIS_GTK_project_data ()); GNUNET_asprintf (&fn, "%s%s", dir, diff --git a/src/anastasis/anastasis-gtk_io.c b/src/anastasis/anastasis-gtk_io.c @@ -52,7 +52,7 @@ open_directory_dialog_response_cb (GtkDialog *dialog, return; } filename = - GNUNET_GTK_filechooser_get_filename_utf8 (GTK_FILE_CHOOSER (dialog)); + ANASTASIS_GTK_filechooser_get_filename_utf8 (GTK_FILE_CHOOSER (dialog)); gtk_widget_destroy (GTK_WIDGET (dialog)); g_object_unref (G_OBJECT (builder)); AG_load (filename); @@ -73,7 +73,7 @@ anastasis_gtk_open_state_clicked_cb (GtkButton *button, GtkWidget *ad; GtkBuilder *builder; - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_open_file_dialog.glade", NULL); @@ -147,7 +147,7 @@ save_directory_dialog_response_cb (GtkDialog *dialog, } (void) AG_dispatch (save_state); filename = - GNUNET_GTK_filechooser_get_filename_utf8 (GTK_FILE_CHOOSER (dialog)); + ANASTASIS_GTK_filechooser_get_filename_utf8 (GTK_FILE_CHOOSER (dialog)); gtk_widget_destroy (GTK_WIDGET (dialog)); g_object_unref (G_OBJECT (builder)); @@ -231,7 +231,7 @@ anastasis_gtk_main_window_save_as_button_clicked_cb (GtkButton *button, GtkWidget *toplevel; toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button)); - builder = GNUNET_GTK_get_new_builder ( + builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_save_file_dialog.glade", NULL); diff --git a/src/anastasis/anastasis-gtk_pe-edit-policy.c b/src/anastasis/anastasis-gtk_pe-edit-policy.c @@ -439,7 +439,7 @@ AG_edit_policy (guint pindex) json_t *methods = NULL; edc = GNUNET_new (struct EditDialogContext); - edc->builder = GNUNET_GTK_get_new_builder ( + edc->builder = ANASTASIS_GTK_get_new_builder ( ANASTASIS_GTK_project_data (), "anastasis_gtk_edit_policy.glade", edc); diff --git a/src/include/anastasis_gtk_util.h b/src/include/anastasis_gtk_util.h @@ -23,6 +23,266 @@ #include <gnunet/gnunet_util_lib.h> + +#include <gtk/gtk.h> +#include <gladeui/glade.h> +#include <gdk/gdkkeysyms.h> + +#ifndef GDK_KEY_Return +#define GDK_KEY_Return GDK_Return +#endif +#ifndef GDK_KEY_Delete +#define GDK_KEY_Delete GDK_Delete +#endif + +#define _(String) dgettext (PACKAGE, String) + +#define DIR_SEPARATOR_STR "/" + +#define DIR_SEPARATOR '/' + + +/** + * Handle for our main loop. + */ +struct ANASTASIS_GTK_MainLoop; + + +/* ****************** Initialization *************** */ + + +/** + * Initialize natural language support. + */ +void +ANASTASIS_GTK_setup_nls (void); + + +/** + * Initialize GTK search path for icons. + * + * @param pd project data to use + */ +void +ANASTASIS_GTK_set_icon_search_path ( + const struct GNUNET_OS_ProjectData *pd); + + +/** + * Get the name of the directory where all of our package + * data is stored ($PREFIX/share/) + * + * @param pd project data to use + * @return name of the data directory + */ +const char * +ANASTASIS_GTK_get_data_dir ( + const struct GNUNET_OS_ProjectData *pd); + + +/** + * @brief get the path to a specific GNUnet installation directory or, + * with #GNUNET_OS_IPK_SELF_PREFIX, the current running apps installation + * directory + * @author Milan + * + * @param dirkind which directory should be returned + * @return a pointer to the dir path (to be freed by the caller) + */ +char * +ANASTASIS_GTK_installation_get_path ( + enum GNUNET_OS_InstallationPathKind dirkind); + + +/* **************** Glade/Gtk helpers *************** */ + +/** + * Create an initialize a new builder based on the + * GNUnet-GTK glade file. + * + * @param pd project data to use + * @param filename name of the resource file to load + * @param user_data user_data to pass to signal handlers, + * use "NULL" to pass the GtkBuilder itself. + * @param cb function to call before connecting signals + * @return NULL on error + */ +GtkBuilder * +ANASTASIS_GTK_get_new_builder2 ( + const struct GNUNET_OS_ProjectData *pd, + const char *filename, + void *user_data, + GtkBuilderConnectFunc cb); + + +/** + * Create an initialize a new builder based on the GNUnet-GTK glade + * file. + * + * @param pd project data to use + * @param filename name of the resource file to load + * @param user_data user_data to pass to signal handlers, + * use "NULL" to pass the GtkBuilder itself. + * @return NULL on error + */ +#define ANASTASIS_GTK_get_new_builder(pd, filename, user_data) \ + ANASTASIS_GTK_get_new_builder2 (pd, filename, user_data, NULL) + + +/** + * Convert a string from the current locale to UTF-8. + * + * @param str_loc string in current locale + * @return string in UTF-8, NULL if str_loc was NULL + */ +char * +ANASTASIS_GTK_from_loc_to_utf8 (const char *str_loc); + + +/** + * Returns filename form filechooser, encoded in UTF-8. + * + * @param fc file chooser to inspect + * @return selected filename as UTF-8, NULL on errors + */ +char * +ANASTASIS_GTK_filechooser_get_filename_utf8 (GtkFileChooser *fc); + + +/* ******************* main loop ***************** */ + + +/** + * Initialize the main loop. + * + * @param pd project data of the program we are launching + * @param binary_name binary name + * @param binary_help help text for the binary + * @param argc number of command line options + * @param argv command line options + * @param options allowed command line options + * @param main_window_file glade file for the main window + * @param main_task first task to run, closure will be set to the `struct + * ANASTASIS_GTK_MainLoop` + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (i.e. bad command-line + * options, etc) + */ +int +ANASTASIS_GTK_main_loop_start ( + const struct GNUNET_OS_ProjectData *pd, + const char *binary_name, + const char *binary_help, + int argc, + char *const *argv, + struct GNUNET_GETOPT_CommandLineOption *options, + const char *main_window_file, + GNUNET_SCHEDULER_TaskCallback main_task); + + +/** + * Get an object from the main window. + * + * @param ml handle to the main loop + * @param name name of the object + * @return NULL on error, otherwise the object + */ +GObject * +ANASTASIS_GTK_main_loop_get_object (struct ANASTASIS_GTK_MainLoop *ml, + const char *name); + + +/** + * Get the builder from the main window. + * + * @param ml handle to the main loop + * @return NULL on error, otherwise the builder + */ +GtkBuilder * +ANASTASIS_GTK_main_loop_get_builder (struct ANASTASIS_GTK_MainLoop *ml); + + +/** + * Get remaining command line arguments. + * + * @param ml handle to the main loop + * @param argc set to argument count + * @param argv set to argument vector + */ +void +ANASTASIS_GTK_main_loop_get_args (struct ANASTASIS_GTK_MainLoop *ml, + int *argc, + char *const **argv); + + +/** + * Initialize a GtkBuilder for the main window and exit + * the main loop if this fails. + * + * @param pd project data to use + * @param ml main loop contextual data + * @param data additional argument to pass to #ANASTASIS_GTK_get_new_builder() + * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure + */ +int +ANASTASIS_GTK_main_loop_build_window ( + const struct GNUNET_OS_ProjectData *pd, + struct ANASTASIS_GTK_MainLoop *ml, + gpointer data); + + +/** + * Obtain the name of the configuration file that is being used + * by gnunet-gtk. + * + * @param ml handle to the main loop + * @return name of configuration file + */ +const char * +ANASTASIS_GTK_main_loop_get_gtk_configuration_file ( + struct ANASTASIS_GTK_MainLoop *ml); + +/** + * Obtain the name of the configuration file that is being used + * by GNUnet (core). + * + * @param ml handle to the main loop + * @return name of configuration file + */ +const char * +ANASTASIS_GTK_main_loop_get_gnunet_configuration_file ( + struct ANASTASIS_GTK_MainLoop *ml); + + +/** + * Get the configuration. + * + * @param ml handle to the main loop + * @return handle to the configuration, never NULL + */ +const struct GNUNET_CONFIGURATION_Handle * +ANASTASIS_GTK_main_loop_get_gtk_configuration ( + struct ANASTASIS_GTK_MainLoop *ml); + + +/** + * Get the configuration. + * + * @param ml handle to the main loop + * @return handle to the configuration, never NULL + */ +const struct GNUNET_CONFIGURATION_Handle * +ANASTASIS_GTK_main_loop_get_gnunet_configuration (struct ANASTASIS_GTK_MainLoop *ml); + + +/** + * Trigger shutdown of the GUI and exit the main loop. + * + * @param ml handle to the main loop + */ +void +ANASTASIS_GTK_main_loop_quit (struct ANASTASIS_GTK_MainLoop *ml); + + /** * Return project data used by Anastasis-Gtk. * diff --git a/src/util/Makefile.am b/src/util/Makefile.am @@ -7,6 +7,9 @@ lib_LTLIBRARIES = \ libanastasisgtkutil.la libanastasisgtkutil_la_SOURCES = \ + eventloop.c \ + glade.c \ + nls.c \ os_installation.c libanastasisgtkutil_la_LIBADD = \ -lgnunetutil \ diff --git a/src/util/eventloop.c b/src/util/eventloop.c @@ -0,0 +1,580 @@ +/* + This file is part of GNUnet. + Copyright (C) 2010, 2011 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +/** + * @file src/lib/eventloop.c + * @brief code for merging GNUnet scheduler and Gtk Main Loop event loops + * @author Christian Grothoff + */ +#include "anastasis_gtk_util.h" +#if HAVE_GTK_GTKX_H +#include <gtk/gtkx.h> +#endif + +/** + * Initial size of our poll array cache. + * + * TODO: get some statistics, find the maximum number of fds ever + * polled during normal gnunet-gtk operation, and set this to that number. + * For non-Windows OSes, that is. For Windows it's always 64, because + * that's the limit anyway. + */ +#define INITIAL_POLL_ARRAY_SIZE 30 + +/** + * Main context for our event loop. + */ +struct ANASTASIS_GTK_MainLoop +{ + + /** + * Our configuration (includes defaults from gnunet-gtk/config.d/) + */ + const struct GNUNET_CONFIGURATION_Handle *gnunet_gtk_cfg; + + /** + * GNUnet configuration (includes defaults from gnunet/config.d/) + */ + struct GNUNET_CONFIGURATION_Handle *gnunet_cfg; + + /** + * Name of the glade file for the main window + */ + const char *main_window_file; + + /** + * Initial task to run to setup the system. + */ + GNUNET_SCHEDULER_TaskCallback main_task; + + /** + * Builder for the main window. + */ + GtkBuilder *builder; + + /** + * Gib's Main loop. + */ + GMainLoop *gml; + + /** + * GTK's main context. + */ + GMainContext *gmc; + + /** + * Read set. + */ + struct GNUNET_NETWORK_FDSet *rs; + + /** + * Write set. + */ + struct GNUNET_NETWORK_FDSet *ws; + + /** + * Recycled array of polling descriptors. + */ + GPollFD *cached_poll_array; + + /** + * Name of the configuration file for gnunet-gtk. + */ + char *gnunet_gtk_cfgfile; + + /** + * Name of the configuration file for GNUnet (core). + */ + char *gnunet_cfgfile; + + /** + * Size of the 'cached_poll_array'. + */ + guint cached_poll_array_size; + + /** + * Task we keep around just to keep the event loop running. + */ + struct GNUNET_SCHEDULER_Task *dummy_task; + + /** + * Remaining command-line arguments. + */ + char *const *argv; + + /** + * Number of remaining arguments. + */ + int argc; + +}; + + +const struct GNUNET_CONFIGURATION_Handle * +ANASTASIS_GTK_main_loop_get_gnunet_configuration ( + struct ANASTASIS_GTK_MainLoop *ml) +{ + return ml->gnunet_cfg; +} + + +const struct GNUNET_CONFIGURATION_Handle * +ANASTASIS_GTK_main_loop_get_gtk_configuration ( + struct ANASTASIS_GTK_MainLoop *ml) +{ + return ml->gnunet_gtk_cfg; +} + + +void +ANASTASIS_GTK_main_loop_quit (struct ANASTASIS_GTK_MainLoop *ml) +{ + g_main_loop_quit (ml->gml); + ml->gml = NULL; + if (NULL != ml->dummy_task) + { + GNUNET_SCHEDULER_cancel (ml->dummy_task); + ml->dummy_task = NULL; + } +} + + +GtkBuilder * +ANASTASIS_GTK_main_loop_get_builder (struct ANASTASIS_GTK_MainLoop *ml) +{ + return ml->builder; +} + + +int +ANASTASIS_GTK_main_loop_build_window ( + const struct GNUNET_OS_ProjectData *pd, + struct ANASTASIS_GTK_MainLoop *ml, + gpointer data) +{ + ANASTASIS_GTK_set_icon_search_path (pd); + ml->builder = ANASTASIS_GTK_get_new_builder (pd, + ml->main_window_file, + data); + if (NULL == ml->builder) + { + ANASTASIS_GTK_main_loop_quit (ml); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +const char * +ANASTASIS_GTK_main_loop_get_gnunet_configuration_file ( + struct ANASTASIS_GTK_MainLoop *ml) +{ + return ml->gnunet_cfgfile; +} + + +const char * +ANASTASIS_GTK_main_loop_get_gtk_configuration_file ( + struct ANASTASIS_GTK_MainLoop *ml) +{ + return ml->gnunet_gtk_cfgfile; +} + + +GObject * +ANASTASIS_GTK_main_loop_get_object (struct ANASTASIS_GTK_MainLoop *ml, + const char *name) +{ + return gtk_builder_get_object (ml->builder, + name); +} + + +void +ANASTASIS_GTK_main_loop_get_args ( + struct ANASTASIS_GTK_MainLoop *ml, + int *argc, + char *const **argv) +{ + *argc = ml->argc; + *argv = ml->argv; +} + + +/** + * Task to run Gtk events (within a GNUnet scheduler task). + * + * @param cls the main loop handle + */ +static void +dispatch_gtk_task (void *cls) +{ + struct ANASTASIS_GTK_MainLoop *ml = cls; + + g_main_context_dispatch (ml->gmc); +} + + +/** + * Change the size of the cached poll array to the given value. + * + * @param ml main loop context with the cached poll array + * @param new_size desired size of the cached poll array + */ +static void +resize_cached_poll_array (struct ANASTASIS_GTK_MainLoop *ml, + guint new_size) +{ + if (NULL == ml->cached_poll_array) + ml->cached_poll_array = g_new (GPollFD, + new_size); + else + ml->cached_poll_array = g_renew (GPollFD, + ml->cached_poll_array, + new_size); + ml->cached_poll_array_size = new_size; +} + + +/** + * Dummy task to keep our scheduler running. + */ +static void +keepalive_task (void *cls) +{ + struct ANASTASIS_GTK_MainLoop *ml = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Dummy task was scheduled\n"); + ml->dummy_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &keepalive_task, + ml); +} + + +#ifndef FD_COPY +#define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set))) +#endif + +/** + * Replacement for the GNUnet scheduler's "select" that integrates the + * Gtk event loop. We merge Gtk's events with those from GNUnet's + * scheduler and then use 'g_poll' on both. Then we process the Gtk + * events (by adding a task to do so to the GNUnet scheduler), and, if + * applicable, return the GNUnet-scheduler events back to GNUnet. + * + * @param cls the 'struct ANASTASIS_GTK_MainLoop' + * @param rfds set of sockets to be checked for readability + * @param wfds set of sockets to be checked for writability + * @param efds set of sockets to be checked for exceptions + * @param timeout relative value when to return + * @return number of selected sockets, GNUNET_SYSERR on error + */ +static int +gnunet_gtk_select (void *cls, + struct GNUNET_NETWORK_FDSet *rfds, + struct GNUNET_NETWORK_FDSet *wfds, + struct GNUNET_NETWORK_FDSet *efds, + const struct GNUNET_TIME_Relative timeout) +{ + struct ANASTASIS_GTK_MainLoop *ml = cls; + int max_nfds; + gint poll_result; + gint delay = INT_MAX; + int i; + guint ui; + guint fd_counter; + guint need_gfds = 0; + fd_set aread; + fd_set awrite; + fd_set aexcept; + int result = 0; + gint max_priority; + + if (ml->gml == NULL || TRUE != g_main_loop_is_running (ml->gml)) + return GNUNET_NETWORK_socket_select (rfds, wfds, efds, timeout); + if (NULL != rfds) + FD_COPY (&rfds->sds, &aread); + else + FD_ZERO (&aread); + if (NULL != wfds) + FD_COPY (&wfds->sds, &awrite); + else + FD_ZERO (&awrite); + if (NULL != efds) + FD_COPY (&efds->sds, &aexcept); + else + FD_ZERO (&aexcept); + + max_nfds = -1; + if (rfds != NULL) + max_nfds = GNUNET_MAX (max_nfds, rfds->nsds); + if (wfds != NULL) + max_nfds = GNUNET_MAX (max_nfds, wfds->nsds); + if (efds != NULL) + max_nfds = GNUNET_MAX (max_nfds, efds->nsds); + + if (ml->cached_poll_array_size == 0) + resize_cached_poll_array (ml, INITIAL_POLL_ARRAY_SIZE); + + fd_counter = 0; + for (i = 0; i < max_nfds; i++) + { + int isset[3]; + + isset[0] = (rfds == NULL) ? 0 : FD_ISSET (i, &rfds->sds); + isset[1] = (wfds == NULL) ? 0 : FD_ISSET (i, &wfds->sds); + isset[2] = (efds == NULL) ? 0 : FD_ISSET (i, &efds->sds); + if ((! isset[0]) && (! isset[1]) && (! isset[2])) + continue; + if (fd_counter >= ml->cached_poll_array_size) + resize_cached_poll_array (ml, ml->cached_poll_array_size * 2); + ml->cached_poll_array[fd_counter].fd = i; + ml->cached_poll_array[fd_counter].events = + (isset[0] ? G_IO_IN | G_IO_HUP | G_IO_ERR : 0) + | (isset[1] ? G_IO_OUT | G_IO_ERR : 0) | (isset[2] ? G_IO_ERR : 0); + fd_counter++; + } + + /* combine with Gtk events */ + if (NULL != ml->gmc) + { + g_main_context_prepare (ml->gmc, &max_priority); + while (1) + { + need_gfds = + g_main_context_query (ml->gmc, + max_priority, + &delay, + &ml->cached_poll_array[fd_counter], + ml->cached_poll_array_size - fd_counter); + if (ml->cached_poll_array_size >= need_gfds + fd_counter) + break; + resize_cached_poll_array (ml, fd_counter + need_gfds); + } + } + if (timeout.rel_value_us != GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) + { + if (delay >= 0) + delay = GNUNET_MIN (timeout.rel_value_us + / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us, + delay); + else + delay = timeout.rel_value_us / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "We have %d of our FDs and %d of GMC ones, going to wait %6dms\n", + fd_counter, + need_gfds, + delay); + poll_result = g_poll (ml->cached_poll_array, fd_counter + need_gfds, delay); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "g_poll returned : %d\n", poll_result); + if (-1 == poll_result) + return GNUNET_SYSERR; + + /* Take care of GUI events. + * Dispatching the events here will eventually crash the scheduler, must do this + * from within a task (currently we're not in a task, but in a select() call, remember) + * Startup reason is used to pass the scheduler sanity check. + */ + if (NULL != ml->gmc) + { + if (g_main_context_check (ml->gmc, + max_priority, + &ml->cached_poll_array[fd_counter], + need_gfds)) + GNUNET_SCHEDULER_add_with_reason_and_priority ( + &dispatch_gtk_task, + ml, + GNUNET_SCHEDULER_REASON_STARTUP, + GNUNET_SCHEDULER_PRIORITY_UI); + } + /* Now map back GNUnet scheduler events ... */ + if (NULL != rfds) + GNUNET_NETWORK_fdset_zero (rfds); + if (NULL != wfds) + GNUNET_NETWORK_fdset_zero (wfds); + if (NULL != efds) + GNUNET_NETWORK_fdset_zero (efds); + for (ui = 0; ui < fd_counter; ui++) + { + int set = 0; + + if ((NULL != rfds) && + (set |= (FD_ISSET (ml->cached_poll_array[ui].fd, &aread) && + (0 != (ml->cached_poll_array[ui].revents + & (G_IO_IN | G_IO_HUP | G_IO_ERR)))))) + GNUNET_NETWORK_fdset_set_native (rfds, ml->cached_poll_array[ui].fd); + if ((NULL != wfds) && + (set |= + (FD_ISSET (ml->cached_poll_array[ui].fd, &awrite) && + (0 != (ml->cached_poll_array[ui].revents & (G_IO_OUT | G_IO_ERR))))) + ) + GNUNET_NETWORK_fdset_set_native (wfds, ml->cached_poll_array[ui].fd); + if ((NULL != efds) && + (set |= (FD_ISSET (ml->cached_poll_array[ui].fd, &aexcept) && + (0 != (ml->cached_poll_array[ui].revents & G_IO_ERR))))) + GNUNET_NETWORK_fdset_set_native (efds, ml->cached_poll_array[ui].fd); + if (set) + result++; + } + return result; +} + + +/** + * Actual main function run right after GNUnet's scheduler + * is initialized. Initializes up GTK and Glade and starts the + * combined event loop. + * + * @param cls the `struct ANASTASIS_GTK_MainLoop` + * @param args leftover command line arguments (go to gtk) + * @param gnunet_gtk_cfgfile name of the gnunet-gtk configuration file + * @param gnunet_gtk_cfg handle to the configuration + */ +static void +run_main_loop (void *cls, + char *const *args, + const char *gnunet_gtk_cfgfile, + const struct GNUNET_CONFIGURATION_Handle *gnunet_gtk_cfg) +{ + struct ANASTASIS_GTK_MainLoop *ml = cls; + const struct GNUNET_OS_ProjectData *gnunet_pd + = GNUNET_OS_project_data_gnunet (); + int argc; + + /* command-line processing for Gtk arguments */ + argc = 0; + while (NULL != args[argc]) + argc++; + gtk_init (&argc, (char ***) &args); + ml->argc = argc; + ml->argv = args; + + if (NULL != gnunet_gtk_cfgfile) + ml->gnunet_gtk_cfgfile = GNUNET_strdup (gnunet_gtk_cfgfile); + ml->gnunet_gtk_cfg = gnunet_gtk_cfg; + ml->rs = GNUNET_NETWORK_fdset_create (); + ml->ws = GNUNET_NETWORK_fdset_create (); + ml->gml = g_main_loop_new (NULL, + TRUE); + ml->gmc = g_main_loop_get_context (ml->gml); + ml->gnunet_cfg + = GNUNET_CONFIGURATION_create (gnunet_pd); + if (GNUNET_OK != + GNUNET_CONFIGURATION_load (ml->gnunet_cfg, + ml->gnunet_cfgfile)) + { + GNUNET_break (0); + GNUNET_SCHEDULER_shutdown (); + return; + } + + /* start the Gtk event loop */ + GNUNET_assert (g_main_context_acquire (ml->gmc)); + GNUNET_SCHEDULER_set_select (&gnunet_gtk_select, + ml); + + /* keep Gtk event loop running even if there are no GNUnet tasks */ + ml->dummy_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &keepalive_task, + ml); + + /* run main task of the application */ + GNUNET_SCHEDULER_add_with_reason_and_priority (ml->main_task, + ml, + GNUNET_SCHEDULER_REASON_STARTUP, + GNUNET_SCHEDULER_PRIORITY_DEFAULT); +} + + +int +ANASTASIS_GTK_main_loop_start ( + const struct GNUNET_OS_ProjectData *pd, + const char *binary_name, + const char *binary_help, + int argc, + char *const *argv, + struct GNUNET_GETOPT_CommandLineOption *options, + const char *main_window_file, + GNUNET_SCHEDULER_TaskCallback main_task) +{ + struct ANASTASIS_GTK_MainLoop ml; + int ret; + unsigned int olen = 0; + + memset (&ml, 0, sizeof (ml)); + ml.main_window_file = main_window_file; + ml.main_task = main_task; + while (NULL != options[olen].name) + olen++; + { + struct GNUNET_GETOPT_CommandLineOption ox[] = { + GNUNET_GETOPT_option_string ('C', + "gnunet-config", + "FILENAME", + "configuration file used by GNUnet core", + &ml.gnunet_cfgfile) + }; + struct GNUNET_GETOPT_CommandLineOption *o2; + + o2 = GNUNET_new_array (olen + 2, + struct GNUNET_GETOPT_CommandLineOption); + memcpy (&o2[0], + &ox, + sizeof (struct GNUNET_GETOPT_CommandLineOption)); + memcpy (&o2[1], + options, + sizeof (struct GNUNET_GETOPT_CommandLineOption) * olen); + ret = GNUNET_PROGRAM_run (pd, + argc, + argv, + binary_name, + binary_help, + o2, + &run_main_loop, + &ml); + GNUNET_free (o2); + } + + + if (NULL != ml.cached_poll_array) + g_free (ml.cached_poll_array); + if (NULL != ml.rs) + GNUNET_NETWORK_fdset_destroy (ml.rs); + if (NULL != ml.ws) + GNUNET_NETWORK_fdset_destroy (ml.ws); + if (NULL != ml.builder) + g_object_unref (G_OBJECT (ml.builder)); + if (NULL != ml.gml) + g_main_loop_unref (ml.gml); + if (NULL != ml.gnunet_cfg) + { + GNUNET_CONFIGURATION_destroy (ml.gnunet_cfg); + ml.gnunet_cfg = NULL; + } + ml.gnunet_gtk_cfg = NULL; + GNUNET_free (ml.gnunet_cfgfile); + GNUNET_free (ml.gnunet_gtk_cfgfile); + return ret; +} + + +/* end of eventloop.c */ diff --git a/src/util/glade.c b/src/util/glade.c @@ -0,0 +1,112 @@ +/* + This file is part of GNUnet. + Copyright (C) 2010, 2024 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +/** + * @file src/lib/glade.c + * @brief code for integration with glade + * @author Christian Grothoff + */ +#include "anastasis_gtk_config.h" +#include "anastasis_gtk_util.h" + + +void +ANASTASIS_GTK_set_icon_search_path (const struct GNUNET_OS_ProjectData *pd) +{ + char *buf; + + buf = GNUNET_OS_installation_get_path (pd, + GNUNET_OS_IPK_ICONDIR); + gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), + buf); + GNUNET_free (buf); +} + + +const char * +ANASTASIS_GTK_get_data_dir (const struct GNUNET_OS_ProjectData *pd) +{ + static char *dd; + + if (NULL == dd) + dd = GNUNET_OS_installation_get_path (pd, + GNUNET_OS_IPK_DATADIR); + return dd; +} + + +GtkBuilder * +ANASTASIS_GTK_get_new_builder2 (const struct GNUNET_OS_ProjectData *pd, + const char *filename, + void *user_data, + GtkBuilderConnectFunc cb) +{ + char *glade_path; + GtkBuilder *ret; + GError *error; + + ret = gtk_builder_new (); + GNUNET_asprintf (&glade_path, + "%s%s", + ANASTASIS_GTK_get_data_dir (pd), + filename); + error = NULL; + if (0 == gtk_builder_add_from_file (ret, + glade_path, + &error)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ ("Failed to load `%s': %s\n"), + glade_path, + error->message); + g_error_free (error); + GNUNET_free (glade_path); + return NULL; + } + if (NULL == user_data) + user_data = ret; + if (NULL != cb) + gtk_builder_connect_signals_full (ret, + cb, user_data); + else + gtk_builder_connect_signals (ret, + user_data); + GNUNET_free (glade_path); + return ret; +} + + +void +GNUNET_FS_GTK_remove_treestore_subtree (GtkTreeStore *ts, + GtkTreeIter *root) +{ + GtkTreeIter child; + + while (gtk_tree_model_iter_children (GTK_TREE_MODEL (ts), + &child, + root)) + GNUNET_FS_GTK_remove_treestore_subtree (ts, + &child); + gtk_tree_store_remove (ts, + root); +} + + +/* end of glade.c */ diff --git a/src/util/nls.c b/src/util/nls.c @@ -0,0 +1,150 @@ +/* + This file is part of GNUnet. + Copyright (C) 2010, 2011, 2021 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +/** + * @file src/lib/nls.c + * @brief natural language support + * @author Christian Grothoff + */ +#include "anastasis_gtk_util.h" + +#if ENABLE_NLS +#include <locale.h> +#endif + + +void +ANASTASIS_GTK_setup_nls () +{ +#if ENABLE_NLS + const struct GNUNET_OS_ProjectData *pd; + char *path; + + pd = GNUNET_OS_project_data_get (); + setlocale (LC_ALL, ""); + GNUNET_asprintf (&path, + "%s/%s/locale/", + ANASTASIS_GTK_get_data_dir (), + PACKAGE_NAME); + bindtextdomain ("gnunet-gtk", + path); + if (NULL != pd->gettext_path) + bindtextdomain (pd->gettext_domain, + pd->gettext_path); + textdomain (pd->gettext_domain); + bind_textdomain_codeset ("GNUnet", + "UTF-8"); + bind_textdomain_codeset ("gnunet-gtk", + "UTF-8"); + bind_textdomain_codeset (pd->gettext_domain, + "UTF-8"); + GNUNET_free (path); +#else + fprintf ( + stderr, + "WARNING: gnunet-gtk was compiled without i18n support (did CFLAGS contain -Werror?).\n"); +#endif +} + + +/* This is copied from GLib */ +/** + * Obtain character set used for filenames on this system. + * + * @param filename_charset set to the character set used for filenames + * @return TRUE if the locale is utf-8 + */ +static gboolean +get_filename_charset (const gchar **filename_charset) +{ + const gchar **charsets; + gboolean is_utf8; + + is_utf8 = g_get_filename_charsets (&charsets); + if (filename_charset) + *filename_charset = charsets[0]; + return is_utf8; +} + + +char * +ANASTASIS_GTK_from_loc_to_utf8 (const char *str_loc) +{ + char *str_utf8; + const char *loc_charset; + gboolean is_UTF8; + + if (NULL == str_loc) + return NULL; + + is_UTF8 = g_get_charset (&loc_charset); + if (is_UTF8) + str_utf8 = GNUNET_strdup (str_loc); + else + str_utf8 = GNUNET_STRINGS_to_utf8 (str_loc, + strlen (str_loc), + loc_charset); + return str_utf8; +} + + +/** + * Convert from locale used for filenames to UTF-8. + * + * @param filename filename in locale encoding + * @return filename in utf-8 encoding + */ +static char * +from_filename_to_utf8 (gchar *filename) +{ + char *str_utf8; + const char *filename_charset; + gboolean is_UTF8; + + if (NULL == filename) + return NULL; + + is_UTF8 = get_filename_charset (&filename_charset); + if (is_UTF8) + str_utf8 = GNUNET_strdup (filename); + else + str_utf8 = + GNUNET_STRINGS_to_utf8 (filename, + strlen (filename), + filename_charset); + + return str_utf8; +} + + +char * +ANASTASIS_GTK_filechooser_get_filename_utf8 (GtkFileChooser *fc) +{ + char *filename_utf8; + gchar *filename = gtk_file_chooser_get_filename (fc); + + if (NULL == filename) + return NULL; + filename_utf8 = from_filename_to_utf8 (filename); + g_free (filename); + return filename_utf8; +} + + +/* end of nls.c */