From c1ef27c64cab1b48308cb56515027bf09a8ad11f Mon Sep 17 00:00:00 2001 From: Vivien Kraus Date: Sun, 26 Mar 2023 14:31:52 +0200 Subject: Start a vala user interface --- bootstrap-bootstrap | 2 +- bootstrap.conf | 5 +++ configure.ac | 34 +++++++++++++++++- guix.scm | 46 +++++------------------- include/disfluid-gobject.h | 4 +-- include/disfluid.h | 37 ++++++++++++++----- include/disfluid/cache_entry.h | 24 +++++++++++++ introspection/Makefile.am | 18 +++++----- introspection/doc.toml | 2 +- po/POTFILES.in | 2 ++ src/Makefile.am | 21 +++-------- src/gir/Makefile.am | 30 ++++++++++++++++ src/libdisfluid/Makefile.am | 1 + src/libdisfluid/disfluid-authors.h | 66 ++++++++++++++++++++++++++++++++-- src/libdisfluid/disfluid-cache-entry.h | 65 ++++++++++++++++++++++++++++++++- src/libdisfluid/disfluid-ui.h | 23 ++++++++++++ src/libdisfluid/main.c | 54 ++++++++++++++++++++++++++++ src/vala/Makefile.am | 37 ++++++++++++++++--- src/vala/about.vala | 51 ++++++++++++++++++++++++++ src/vala/main.vala | 26 ++++++++++++++ src/vala/main_window.vala | 55 ++++++++++++++++++++++++++++ tests/run-unit-tests.c | 1 + 22 files changed, 518 insertions(+), 86 deletions(-) create mode 100644 src/gir/Makefile.am create mode 100644 src/libdisfluid/disfluid-ui.h create mode 100644 src/vala/about.vala create mode 100644 src/vala/main.vala create mode 100644 src/vala/main_window.vala diff --git a/bootstrap-bootstrap b/bootstrap-bootstrap index b878b3c..0ac2032 100755 --- a/bootstrap-bootstrap +++ b/bootstrap-bootstrap @@ -1,3 +1,3 @@ #!/bin/sh -(cp -r gnulib/top/. . || cp -r "$GNULIB_SRCDIR/top/." . ) && ./bootstrap +cp -r gnulib/top/. . || cp -r "$GNULIB_SRCDIR/top/." . diff --git a/bootstrap.conf b/bootstrap.conf index e212745..e67ead1 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -44,13 +44,16 @@ read realloc-gnu relocatable-lib-lgpl remove +safe-alloc stdbool stdint stdio strdup +strftime-fixes strstr sys_stat time +time_r tmpfile useless-if-before-free valgrind-tests @@ -79,3 +82,5 @@ gnulib_tool_option_extras='--makefile-name=Makefile.gnulib --with-tests --tests- checkout_only_file=guix.scm po_download_command_format="git archive --format=tar translations | tar -x -C %s && echo %s" + +# End of bootstrap.conf diff --git a/configure.ac b/configure.ac index 21d89d1..2d8bec8 100644 --- a/configure.ac +++ b/configure.ac @@ -22,8 +22,10 @@ AM_PROG_AR LT_INIT([win32-dll]) gl_INIT AM_MISSING_PROG([CONVERT], [convert]) +AC_ARG_VAR([G_IR_SCANNER_FLAGS], [Extra arguments to g-ir-scanner]) AM_MISSING_PROG([G_IR_SCANNER], [g-ir-scanner]) AM_MISSING_PROG([VAPIGEN], [vapigen]) +AM_MISSING_PROG([VALAC], [valac]) GLIB_GSETTINGS # Checks for libraries. @@ -32,6 +34,11 @@ AC_ARG_WITH([gobject], [register types for the glib runtime @<:@default=check@:>@])], [], [: m4_divert_text([DEFAULTS], [with_gobject=check])]) +AC_ARG_WITH([gtk], + [AS_HELP_STRING([--with-gtk], + [build a gtk user interface @<:@default=check@:>@])], + [], + [: m4_divert_text([DEFAULTS], [with_gtk=check])]) AM_GNU_GETTEXT([external]) AM_GNU_GETTEXT_VERSION([0.19]) @@ -46,7 +53,10 @@ PKG_CHECK_MODULES([GNUTLS], [gnutls], [ LIBS="$LIBS $GNUTLS_LIBS" ], [AC_MSG_WARN([pkg-config does not know the "gnutls" module])]) AS_IF([test "x$with_gobject" != xno], - [PKG_CHECK_MODULES([GOBJECT], [gobject-2.0], [AC_MSG_WARN([pkg-config does not know the "gobject-2.0" module])])]) + [PKG_CHECK_MODULES([GOBJECT], [gobject-2.0],, [AC_MSG_WARN([pkg-config does not know the "gobject-2.0" module])])]) +AS_IF([test "x$with_gtk" != xno], + [PKG_CHECK_MODULES([GTK], [gtk4],, [AC_MSG_WARN([pkg-config does not know the "gtk4" module])]) + PKG_CHECK_MODULES([ADW], [libadwaita-1],, [AC_MSG_WARN([pkg-config does not know the "libadwaita-1" module])])]) # Checks for header files. AC_CHECK_HEADERS([check.h gnutls/gnutls.h gnutls/crypto.h],, @@ -61,6 +71,17 @@ AS_IF([test "x$with_gobject" != xno], [AS_IF([test "x$with_gobject" = xcheck], [with_gobject=no], [AC_MSG_FAILURE([--with-gobject was given, but glib-object.h is not found.])])])]) +CPPFLAGS="$SAVE_CPPFLAGS $GTK_CFLAGS $ADW_CFLAGS" +CFLAGS="$SAVE_CFLAGS $GTK_CFLAGS $ADW_CFLAGS" +AS_IF([test "x$with_gtk" != xno], + [AC_CHECK_HEADERS([gtk/gtk.h],, + [AS_IF([test "x$with_gtk" = xcheck], + [with_gtk=no], + [AC_MSG_FAILURE([--with-gtk was given, but gtk/gtk.h is not found.])])]) + AC_CHECK_HEADERS([adwaita.h],, + [AS_IF([test "x$with_gtk" = xcheck], + [with_gtk=no], + [AC_MSG_FAILURE([--with-gtk was given, but adwaita.h is not found.])])])]) CPPFLAGS="$SAVE_CPPFLAGS" CFLAGS="$SAVE_CFLAGS" @@ -85,6 +106,16 @@ AS_IF([test "x$with_gobject" != xno], [AS_IF([test "x$with_gobject" = xcheck], [with_gobject=no], [AC_MSG_FAILURE([--with-gobject was given, but g_boxed_copy is not found.])])])]) +LIBS="$SAVE_LIBS $GTK_LIBS $ADW_LIBS" +AS_IF([test "x$with_gtk" != xno], + [AC_CHECK_FUNCS([gtk_application_get_type],, + [AS_IF([test "x$with_gtk" = xcheck], + [with_gtk=no], + [AC_MSG_FAILURE([--with-gtk was given, but gtk_application_get_type is not found.])])]) + AC_CHECK_FUNCS([adw_application_get_type],, + [AS_IF([test "x$with_gtk" = xcheck], + [with_gtk=no], + [AC_MSG_FAILURE([--with-gtk was given, but adw_application_get_type is not found.])])])]) LIBS="$SAVE_LIBS" i_am_windows=no @@ -95,6 +126,7 @@ esac AM_CONDITIONAL([SHLIBS_IN_BINDIR], [test "x$i_am_windows" = "xyes"]) AM_CONDITIONAL([BUILD_GOBJECT], [test "x$with_gobject" != "xno"]) +AM_CONDITIONAL([WITH_GTK], [test "x$with_gtk" != "xno"]) case "$VERSION" in *-*) diff --git a/guix.scm b/guix.scm index 7a3e5ea..60855c1 100644 --- a/guix.scm +++ b/guix.scm @@ -212,12 +212,19 @@ (build-system gnu-build-system) (arguments (list + #:configure-flags + #~'("G_IR_SCANNER_FLAGS=--warn-all --warn-error") #:phases #~(modify-phases %standard-phases (add-before 'bootstrap 'bootstrap-bootstrap (lambda _ - (invoke "sh" "bootstrap-bootstrap"))) + (invoke "sh" "bootstrap-bootstrap") + (for-each patch-shebang + '("autopull.sh" "autogen.sh")) + (substitute* "bootstrap-funclib.sh" + (("\\$gnulib_tool \\$gnulib_tool_options") + "sh $gnulib_tool $gnulib_tool_options")))) (add-after 'bootstrap 'fix-/bin/sh-in-po (lambda _ (substitute* @@ -252,19 +259,15 @@ "announce-gen" "ar-lib" "config.guess" - "config.libpath" "config.sub" "depcomp" "do-release-commit-and-tag" "git-version-gen" "gitlog-to-changelog" - "install-reloc" "install-sh" - "libtool-reloc" "ltmain.sh" "mdate-sh" "missing" - "reloc-ldflags" "test-driver" "useless-if-before-free" "vc-list-files" @@ -299,37 +302,6 @@ "test-verify.sh" "test-binary-io.sh" ) - (("#!/gnu/store/.*/bin/sh") - "#!/bin/sh"))) - (with-directory-excursion "tests/libprog" - (substitute* '( - "executable-shell-script" - "test-binary-io.sh" - "test-execv.sh" - "test-execve.sh" - "test-fflush2.sh" - "test-fseek.sh" - "test-fseek2.sh" - "test-fseeko.sh" - "test-fseeko2.sh" - "test-fseeko3.sh" - "test-fseeko4.sh" - "test-ftell.sh" - "test-ftell2.sh" - "test-ftello.sh" - "test-ftello2.sh" - "test-ftello4.sh" - "test-ftruncate.sh" - "test-init.sh" - "test-lseek.sh" - "test-perror.sh" - "test-select-in.sh" - "test-select-out.sh" - "test-setlocale1.sh" - "test-setlocale2.sh" - "test-verify.sh" - "test-xalloc-die.sh" - ) (("#!/gnu/store/.*/bin/sh") "#!/bin/sh")))) (invoke "sh" "-c" "grep '/gnu/store/' -R disfluid-* && exit 1 ; true") @@ -348,7 +320,7 @@ texinfo (texlive-updmap.cfg (list texlive)) perl gnulib gtk check (list glib "bin") gobject-introspection imagemagick - indent cppi)) + indent cppi vala)) (inputs (list gtk libadwaita check gnu-gettext gnutls)) (home-page "https://labo.planete-kraus.eu/disfluid.git") diff --git a/include/disfluid-gobject.h b/include/disfluid-gobject.h index f9aa28a..b7e5daa 100644 --- a/include/disfluid-gobject.h +++ b/include/disfluid-gobject.h @@ -68,7 +68,7 @@ extern "C" * @entry: (type DisfluidCacheEntry): the entry to query. * @date: (out) (transfer full): the request date. */ - DISFLUID_API extern void + DISFLUID_G_API extern void disfluid_cache_entry_get_request_gdate (const struct disfluid_cache_entry *entry, GDateTime ** date); @@ -77,7 +77,7 @@ extern "C" * @entry: (type DisfluidCacheEntry): the entry to query. * @date: (out) (transfer full): the response date. */ - DISFLUID_API extern void + DISFLUID_G_API extern void disfluid_cache_entry_get_response_gdate (const struct disfluid_cache_entry *entry, GDateTime ** date); diff --git a/include/disfluid.h b/include/disfluid.h index b7e0211..0f6649e 100644 --- a/include/disfluid.h +++ b/include/disfluid.h @@ -117,7 +117,7 @@ extern "C" * * Returns: return the news. */ - DISFLUID_CONST DISFLUID_API extern const char *disfluid_whats_new (void); + DISFLUID_API extern const char *disfluid_whats_new (void); /** * disfluid_major_version: @@ -133,7 +133,7 @@ extern "C" * * Returns: the website for disfluid. */ - DISFLUID_CONST DISFLUID_API extern const char *disfluid_website (void); + DISFLUID_API extern const char *disfluid_website (void); /** * disfluid_run_tests: @@ -160,8 +160,7 @@ extern "C" * * Returns: the name of author @i. */ - DISFLUID_CONST DISFLUID_API extern const char - *disfluid_author_name (size_t i); + DISFLUID_API extern const char *disfluid_author_name (size_t i); /** * disfluid_author_email: @@ -169,8 +168,7 @@ extern "C" * * Returns: (nullable): the optional email address of author @i. */ - DISFLUID_CONST DISFLUID_API extern const char - *disfluid_author_email (size_t i); + DISFLUID_API extern const char *disfluid_author_email (size_t i); /** * disfluid_author_uri: @@ -178,8 +176,7 @@ extern "C" * * Returns: (nullable): the optional web address of author @i. */ - DISFLUID_CONST DISFLUID_API extern const char - *disfluid_author_uri (size_t i); + DISFLUID_API extern const char *disfluid_author_uri (size_t i); /** * disfluid_author_is_developer: @@ -221,7 +218,15 @@ extern "C" * * Returns: the credits for translations of your language. */ - DISFLUID_CONST DISFLUID_API const char *disfluid_translation_credits (void); + DISFLUID_API extern const char *disfluid_translation_credits (void); + + /** + * disfluid_copyright_statement: + * + * Returns: a copyright statement in your language. + */ + DISFLUID_API DISFLUID_DEALLOC_WITH_FREE extern char + *disfluid_copyright_statement (void); /** * disfluid_compute_cache_key: @@ -259,6 +264,20 @@ extern "C" size_t password_length, size_t max_hash, char *hash); + /** + * disfluid_greet_world: + * + * Returns: a greeting in the user’s language. + */ + DISFLUID_API const char *disfluid_greet_world (void); + + /** + * disfluid_metaphor_name: + * + * Returns: a GNOME metaphor name for the application. + */ + DISFLUID_API const char *disfluid_metaphor_name (void); + # ifdef __cplusplus } # endif /* __cplusplus */ diff --git a/include/disfluid/cache_entry.h b/include/disfluid/cache_entry.h index dddb92d..7f44357 100644 --- a/include/disfluid/cache_entry.h +++ b/include/disfluid/cache_entry.h @@ -360,6 +360,30 @@ extern "C" # define DISFLUID_CACHE_ENTRY_FREE(ptr) \ { free (ptr); ptr = NULL; } + /** + * disfluid_cache_entry_describe_request_date: + * @entry: (type DisfluidCacheEntry): the entry to describe. + * @description: (out): a short phrase stating the request date. + * + * Returns: 0 on success, or a negative error code. + */ + DISFLUID_NODISCARD DISFLUID_API extern int + disfluid_cache_entry_describe_request_date (const struct + disfluid_cache_entry *entry, + char **description); + + /** + * disfluid_cache_entry_describe_response_date: + * @entry: (type DisfluidCacheEntry): the entry to describe. + * @description: (out): a short phrase stating the response date. + * + * Returns: 0 on success, or a negative error code. + */ + DISFLUID_NODISCARD DISFLUID_API extern int + disfluid_cache_entry_describe_response_date (const struct + disfluid_cache_entry *entry, + char **description); + # ifdef __cplusplus } # endif /* __cplusplus */ diff --git a/introspection/Makefile.am b/introspection/Makefile.am index 7f24bbb..17143e4 100644 --- a/introspection/Makefile.am +++ b/introspection/Makefile.am @@ -1,15 +1,13 @@ -girdir = $(datarootdir)/gir-1.0 +.PHONY: prepare-introspection -dist_gir_DATA = %D%/Disfluid-$(DLL_VERSION).gir +# To avoid the race mentioned in src/gir/Makefile.am, this Makefile, +# which is executed early, prepares the libraries. The recursive call +# in the gir rule is thus a no-op, everything is OK. -$(abs_top_srcdir)/src/introspection-files: - $(MAKE) $(AM_MAKEFLAGS) -C .. src/introspection-files +prepare-introspection: + $(MAKE) $(AM_MAKEFLAGS) -C ../lib libgnu.la + $(MAKE) $(AM_MAKEFLAGS) -C .. update-introspected-libs -$(abs_top_srcdir)/src/introspection-libraries: - $(MAKE) $(AM_MAKEFLAGS) -C .. src/introspection-libraries - -%D%/Disfluid-$(DLL_VERSION).gir: $(abs_top_srcdir)/src/introspection-files $(abs_top_srcdir)/src/introspection-libraries - $(MAKE) $(AM_MAKEFLAGS) -C .. $$(cat $(abs_top_srcdir)/src/introspection-libraries) - $(AM_V_GEN) (cd .. && $(G_IR_SCANNER) --warn-all --warn-error --strict --format=gir -i GLib-2.0 -I$(abs_top_srcdir)/include --c-include=disfluid --c-include=disfluid/cache_entry.h -n Disfluid --nsversion=$(DLL_VERSION) --symbol-prefix=disfluid_ --output=%D%/Disfluid-$(DLL_VERSION).gir-t $$(for lib in $$(cat $(abs_top_srcdir)/src/introspection-libraries) ; do echo "--library=$$lib" ; done) --cflags-begin $(GOBJECT_CFLAGS) --cflags-end $$(cat $(abs_top_srcdir)/src/introspection-files)) && mv ../%D%/Disfluid-$(DLL_VERSION).gir-t $(srcdir)/%D%/Disfluid-$(DLL_VERSION).gir +all: prepare-introspection EXTRA_DIST = %D%/doc.toml diff --git a/introspection/doc.toml b/introspection/doc.toml index 411cf09..18a4f8c 100644 --- a/introspection/doc.toml +++ b/introspection/doc.toml @@ -9,4 +9,4 @@ dependencies = [ "GObject-2.0" ] [dependencies."GObject-2.0"] name = "GObject" description = "The base type system library" -docs_url = "https://docs.gtk.org/gobject/" \ No newline at end of file +docs_url = "https://docs.gtk.org/gobject/" diff --git a/po/POTFILES.in b/po/POTFILES.in index bad10a8..fe71f69 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,6 +1,8 @@ desktop/eu.planete_kraus.Disfluid.Devel.desktop.in desktop/eu.planete_kraus.Disfluid.desktop.in src/libdisfluid/disfluid-authors.h +src/libdisfluid/disfluid-cache-entry.h src/libdisfluid/disfluid-tests.h +src/libdisfluid/disfluid-ui.h src/libdisfluid/disfluid-version.h settings/eu.planete_kraus.Disfluid.gschema.xml.in diff --git a/src/Makefile.am b/src/Makefile.am index 5bd97d6..7925ce8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,25 +5,12 @@ RELOCATABLE_LIBRARY_PATH = $(libdir) include %D%/libdisfluid/Makefile.am include %D%/gobject/Makefile.am +include %D%/gir/Makefile.am include %D%/vala/Makefile.am DISTCLEANFILES += $(defexec_DATA) -EXTRA_DIST += %D%/introspection-files %D%/introspection-libraries +.PHONY: update-introspected-libs -if BUILD_GOBJECT - -%D%/introspection-files: $(INTROSPECTION_LISTS) $(INTROSPECTION_SRC) - $(AM_V_GEN) (for src in $(INTROSPECTED_FILES) ; do echo "$$src" ; done) > %D%/introspection-files-t && mv %D%/introspection-files-t $(srcdir)/%D%/introspection-files - -%D%/introspection-libraries: $(INTROSPECTION_LISTS) $(INTROSPECTION_SRC) - $(AM_V_GEN) (for lib in $(INTROSPECTED_LIBS) ; do echo "$$lib" ; done) > %D%/introspection-libraries-t && mv %D%/introspection-libraries-t %D%/introspection-libraries - -else # not BUILD_GOBJECT - -%D%/introspection-files: $(INTROSPECTION_LISTS) $(INTROSPECTION_SRC) - @(>&2 echo "The introspected files have changed, but gobject compilation is disabled." ; exit 1) -%D%/introspection-libraries: $(INTROSPECTION_LISTS) $(INTROSPECTION_SRC) - @(>&2 echo "The introspected files have changed, but gobject compilation is disabled." ; exit 1) - -endif # not BUILD_GOBJECT +update-introspected-libs: $(INTROSPECTED_LIBS) + @true diff --git a/src/gir/Makefile.am b/src/gir/Makefile.am new file mode 100644 index 0000000..860b2f0 --- /dev/null +++ b/src/gir/Makefile.am @@ -0,0 +1,30 @@ +girdir = $(datarootdir)/gir-1.0 + +dist_gir_DATA = $(srcdir)/%D%/Disfluid-$(DLL_VERSION).gir + +AM_G_IR_SCANNER_FLAGS = \ + --format=gir -i GLib-2.0 -I$(abs_top_srcdir)/include + +if BUILD_GOBJECT + +# The rule to build the .gir file recursively make the libraries. If +# you run "make -j all", and the libraries are not up to date, then +# there is a race to build the libraries by this call, and by the +# recursive calls due to the gir rules. + +# The introspection/Makefile.am is executed early and tries to make +# sure that the recursive call is a no-op. However, if you bypass the +# subdir order by executing "make -j src/gir/Disfluid-….gir", with the +# dll version as …, then the race is still there. Automated build +# scripts usually don’t do this, so it’s fine. + +%D%/Disfluid-$(DLL_VERSION).gir: $(INTROSPECTION_LISTS) $(INTROSPECTION_SRC) + $(MAKE) $(AM_MAKEFLAGS) $(INTROSPECTED_LIBS) + $(AM_V_GEN) $(G_IR_SCANNER) $(AM_G_IR_SCANNER_FLAGS) $(G_IR_SCANNER_FLAGS) --c-include=disfluid.h --c-include=disfluid/cache_entry.h --c-include=disfluid-gobject.h -n Disfluid --nsversion=$(DLL_VERSION) --symbol-prefix=disfluid_ --output=%D%/Disfluid-$(DLL_VERSION).gir-t $$(for lib in $(INTROSPECTED_LIBS) ; do echo "--library=$$lib" ; done) --cflags-begin $(GOBJECT_CFLAGS) --cflags-end $(INTROSPECTED_FILES) && $(SED) 's/shared-library="[^"]*"/shared-library=""/g' %D%/Disfluid-$(DLL_VERSION).gir-t > %D%/Disfluid-$(DLL_VERSION).gir-fixed && rm %D%/Disfluid-$(DLL_VERSION).gir-t && mv %D%/Disfluid-$(DLL_VERSION).gir-fixed $(srcdir)/%D%/Disfluid-$(DLL_VERSION).gir + +else # not BUILD_GOBJECT + +%D%/Disfluid-$(DLL_VERSION).gir: $(INTROSPECTION_LISTS) $(INTROSPECTION_SRC) + @>&2 echo "The introspection sources changed, so the gir file must be updated. Please configure with gobject." ; exit 1 + +endif # not BUILD_GOBJECT diff --git a/src/libdisfluid/Makefile.am b/src/libdisfluid/Makefile.am index 431fa2d..01a5945 100644 --- a/src/libdisfluid/Makefile.am +++ b/src/libdisfluid/Makefile.am @@ -7,6 +7,7 @@ lib_LTLIBRARIES += %D%/libdisfluid.la %D%/disfluid-cache-entry-hash.h \ %D%/disfluid-init.h \ %D%/disfluid-tests.h \ + %D%/disfluid-ui.h \ %D%/disfluid-version.h \ %D%/main.c diff --git a/src/libdisfluid/disfluid-authors.h b/src/libdisfluid/disfluid-authors.h index 149a556..6ccb8fe 100644 --- a/src/libdisfluid/disfluid-authors.h +++ b/src/libdisfluid/disfluid-authors.h @@ -1,6 +1,8 @@ #ifndef DISFLUID_AUTHORS_INCLUDED # define DISFLUID_AUTHORS_INCLUDED +# include "safe-alloc.h" + static inline size_t count_authors (void); static inline const char *author_name (size_t i); @@ -17,6 +19,8 @@ static inline bool author_is_documenter (size_t i); static inline const char *translation_credits (void); +static inline char *copyright_statement (void); + # include "disfluid-init.h" struct disfluid_author @@ -32,7 +36,7 @@ struct disfluid_author static struct disfluid_author disfluid_authors[] = { { - .name = "Vivien Kraus", + .name = N_("Vivien Kraus"), .email = "vivien@planete-kraus.eu", .uri = NULL, .is_developer = true, @@ -59,7 +63,7 @@ author_name (size_t i) { if (i < sizeof (disfluid_authors) / sizeof (disfluid_authors[0])) { - return disfluid_authors[i].name; + return _(disfluid_authors[i].name); } return NULL; } @@ -131,4 +135,62 @@ translation_credits (void) return _("translator-credits"); } +static inline char * +copyright_statement (void) +{ + ensure_init (); + int error = 0; + char *ret = NULL; + char *purpose; + error = asprintf (&purpose, _("disfluid interoperable web stack")); + if (error < 0) + { + goto cleanup; + } + char *copyright_line; + error = + asprintf (©right_line, + _("Copyright © %s the respective authors"), "2023"); + if (error < 0) + { + goto cleanup_purpose; + } + char *disclaimer; + error = asprintf (&disclaimer, + _("This program is free software: " + "you can redistribute it and/or modify it " + "under the terms of the GNU Affero General Public License " + "as published by the Free Software Foundation, " + "either version 3 of the License, " + "or (at your option) any later version.\n" + "This program 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 Affero General Public License for more details.\n" + "You should have received a copy " + "of the GNU Affero General Public License " + "along with this program. " + "If not, see .\n")); + if (error < 0) + { + goto cleanup_copyright_line; + } + error = asprintf (&ret, "%s\n%s\n%s", purpose, copyright_line, disclaimer); + if (error < 0) + { + FREE (ret); + ret = NULL; + goto cleanup_disclaimer; + } +cleanup_disclaimer: + FREE (disclaimer); +cleanup_copyright_line: + FREE (copyright_line); +cleanup_purpose: + FREE (purpose); +cleanup: + return ret; +} + #endif /* DISFLUID_AUTHORS_INCLUDED */ diff --git a/src/libdisfluid/disfluid-cache-entry.h b/src/libdisfluid/disfluid-cache-entry.h index ea76217..eb78a6c 100644 --- a/src/libdisfluid/disfluid-cache-entry.h +++ b/src/libdisfluid/disfluid-cache-entry.h @@ -115,6 +115,14 @@ cache_entry_write (const struct disfluid_cache_entry *entry, int fd); MAYBE_UNUSED static int cache_entry_fwrite (const struct disfluid_cache_entry *entry, FILE * f); +MAYBE_UNUSED static int +cache_entry_describe_request_date (const struct disfluid_cache_entry *entry, + char **description); + +MAYBE_UNUSED static int +cache_entry_describe_response_date (const struct disfluid_cache_entry *entry, + char **description); + # include # include @@ -198,7 +206,7 @@ cache_entry_init (struct disfluid_cache_entry *entry, size_t max_key, entry->header_length = 0; entry->body_length = 0; char *key = cache_entry_key (entry); - char *header = cache_entry_key (entry); + char *header = cache_entry_header (entry); *key = '\0'; *header = '\0'; } @@ -260,14 +268,17 @@ cache_entry_copy (struct disfluid_cache_entry *restrict dest, { strcpy (dest_key, src_key); } + dest->key_length = src_key_size; if (!(src->flags & HEADER_NOT_LOADED)) { strcpy (dest_header, src_header); } + dest->header_length = src_header_size; if (!(src->flags & BODY_NOT_LOADED)) { memcpy (dest_body, src_body, src_body_size); } + dest->body_length = src_body_size; } return -flags; } @@ -1023,4 +1034,56 @@ cache_entry_fwrite (const struct disfluid_cache_entry *entry, FILE * f) return cache_entry_save (entry, disfluid_cache_entry_saver_fwrite, f); } +static int +cache_entry_describe_date (const struct timespec *ts, const char *format, + char **description) +{ + struct tm date; + struct tm *result = localtime_r (&(ts->tv_sec), &date); + if (result == NULL) + { + return -1; + } + char buffer[256]; + size_t n_buffer = strftime (buffer, sizeof (buffer), "%c", &date); + if (n_buffer == 0) + { + return -1; + } + if (n_buffer >= sizeof (buffer)) + { + buffer[n_buffer - 1] = '\0'; + } + else + { + buffer[n_buffer] = '\0'; + } + /* TRANSLATORS: the argument is a date in the preferred format for + the locale. */ + int error = asprintf (description, format, buffer); + if (error < 0) + { + return -2; + } + return 0; +} + +static int +cache_entry_describe_request_date (const struct disfluid_cache_entry *entry, + char **description) +{ + struct timespec ts; + cache_entry_get_request_date (entry, &ts); + return cache_entry_describe_date (&ts, _("Requested %s"), description); +} + +static int +cache_entry_describe_response_date (const struct disfluid_cache_entry *entry, + char **description) +{ + struct timespec ts; + cache_entry_get_response_date (entry, &ts); + return cache_entry_describe_date (&ts, _("Responded %s"), description); +} + #endif /* DISFLUID_DISFLUID_CACHE_ENTRY_INCLUDED */ diff --git a/src/libdisfluid/disfluid-ui.h b/src/libdisfluid/disfluid-ui.h new file mode 100644 index 0000000..3555664 --- /dev/null +++ b/src/libdisfluid/disfluid-ui.h @@ -0,0 +1,23 @@ +#ifndef DISFLUID_UI_INCLUDED +# define DISFLUID_UI_INCLUDED + +static inline const char *greet_world (void); +static inline const char *metaphor_name (void); + +# include "disfluid-init.h" + +static inline const char * +greet_world (void) +{ + ensure_init (); + return _("Hello, world!"); +} + +static inline const char * +metaphor_name (void) +{ + ensure_init (); + return _("Experiences"); +} + +#endif /* DISFLUID_UI_INCLUDED */ diff --git a/src/libdisfluid/main.c b/src/libdisfluid/main.c index 6b21295..5aab482 100644 --- a/src/libdisfluid/main.c +++ b/src/libdisfluid/main.c @@ -25,6 +25,7 @@ #include "disfluid-cache-entry-key.h" #include "disfluid-cache-entry-hash.h" #include "disfluid-tests.h" +#include "disfluid-ui.h" #include "disfluid-version.h" const char * @@ -117,6 +118,12 @@ disfluid_translation_credits (void) return translation_credits (); } +char * +disfluid_copyright_statement (void) +{ + return copyright_statement (); +} + size_t disfluid_cache_entry_size (size_t max_key, size_t max_header, size_t max_body) { @@ -238,6 +245,27 @@ disfluid_cache_entry_is_invalidated (const struct disfluid_cache_entry *entry) return cache_entry_is_invalidated (entry); } +size_t +disfluid_cache_entry_get_key (const struct disfluid_cache_entry *entry, + size_t start, size_t max, char *key) +{ + return cache_entry_get_key (entry, start, max, key); +} + +size_t +disfluid_cache_entry_get_header (const struct disfluid_cache_entry *entry, + size_t start, size_t max, char *header) +{ + return cache_entry_get_header (entry, start, max, header); +} + +size_t +disfluid_cache_entry_get_body (const struct disfluid_cache_entry *entry, + size_t start, size_t max, char *body) +{ + return cache_entry_get_body (entry, start, max, body); +} + int disfluid_cache_entry_load (struct disfluid_cache_entry *entry, int load_key, @@ -307,3 +335,29 @@ disfluid_hash_primary_cache_key (const char *method, return hash_primary_cache_key (method, uri, password, password_length, max_hash, hash); } + +const char * +disfluid_greet_world (void) +{ + return greet_world (); +} + +const char * +disfluid_metaphor_name (void) +{ + return metaphor_name (); +} + +int +disfluid_cache_entry_describe_request_date (const struct disfluid_cache_entry + *entry, char **description) +{ + return cache_entry_describe_request_date (entry, description); +} + +int +disfluid_cache_entry_describe_response_date (const struct disfluid_cache_entry + *entry, char **description) +{ + return cache_entry_describe_response_date (entry, description); +} diff --git a/src/vala/Makefile.am b/src/vala/Makefile.am index acbb494..a0e4279 100644 --- a/src/vala/Makefile.am +++ b/src/vala/Makefile.am @@ -1,6 +1,3 @@ -introspection/Disfluid-$(DLL_VERSION).gir: - $(MAKE) $(AM_MAKEFLAGS) -C introspection Disfluid-$(DLL_VERSION).gir - vapidir = $(datarootdir)/vala/vapi dist_vapi_DATA = %D%/disfluid-$(DLL_VERSION).vapi @@ -10,5 +7,35 @@ VAPIGEN_VERBOSE_ = $(VAPIGEN_VERBOSE_@AM_DEFAULT_V@) VAPIGEN_VERBOSE_1 = $(VAPIGEN) VAPIGEN_VERBOSE_0 = @echo " VAPIGEN " $@; $(VAPIGEN) --quiet -%D%/disfluid-$(DLL_VERSION).vapi: introspection/Disfluid-$(DLL_VERSION).gir - $(AM_VAPIGEN) --library=disfluid-$(DLL_VERSION) -d $(srcdir)/%D% $(srcdir)/introspection/Disfluid-$(DLL_VERSION).gir +%D%/disfluid-$(DLL_VERSION).vapi: $(dist_gir_DATA) + @$(MKDIR_P) %D%/vapi-t + $(AM_VAPIGEN) --library=disfluid-$(DLL_VERSION) -d %D%/vapi-t $(dist_gir_DATA) && mv %D%/vapi-t/disfluid-$(DLL_VERSION).vapi %D%/disfluid-$(DLL_VERSION).vapi-t && rmdir %D%/vapi-t && mv %D%/disfluid-$(DLL_VERSION).vapi-t $(srcdir)/%D%/disfluid-$(DLL_VERSION).vapi + +AM_VALAFLAGS = --pkg gtk4 --pkg libadwaita-1 + +if WITH_GTK +bin_PROGRAMS += %D%/disfluid + +%C%_disfluid_SOURCES = \ + %D%/main.vala \ + %D%/about.vala \ + %D%/cache_entry_widget.vala \ + %D%/main_window.vala \ + %D%/disfluid-$(DLL_VERSION).vapi + +%C%_disfluid_CPPFLAGS = \ + -I include -I $(srcdir)/include \ + -I %D% -I $(srcdir)/%D% \ + -include config.h \ + $(GTK_CFLAGS) $(GOBJECT_CFLAGS) $(ADW_CFLAGS) + +%C%_disfluid_CFLAGS = \ + $(GTK_CFLAGS) $(GOBJECT_CFLAGS) $(ADW_CFLAGS) + +%C%_disfluid_LDADD = \ + src/libdisfluid/libdisfluid.la \ + src/gobject/libdisfluid-gobject.la + +%C%_disfluid_LDFLAGS = \ + $(GTK_LIBS) $(GOBJECT_LIBS) $(ADW_LIBS) +endif diff --git a/src/vala/about.vala b/src/vala/about.vala new file mode 100644 index 0000000..14ff2e8 --- /dev/null +++ b/src/vala/about.vala @@ -0,0 +1,51 @@ +namespace Disfluid { + Adw.AboutWindow make_about_window () { + string appid = "eu.planete_kraus.Disfluid"; + if (Disfluid.is_nightly ()) { + appid += ".Devel"; + } + var window = new Adw.AboutWindow (); + window.set_application_icon (appid); + window.set_application_name (appid); + window.set_version (Disfluid.version ()); + window.set_release_notes (Disfluid.whats_new ()); + window.set_release_notes_version (Disfluid.major_version ()); + window.set_website (Disfluid.website ()); + var n_authors = Disfluid.count_authors (); + string[] developers = new string[0]; + string[] designers = new string[0]; + string[] artists = new string[0]; + string[] documenters = new string[0]; + for (size_t i = 0; i < n_authors; i++) { + var email = Disfluid.author_email (i); + var uri = Disfluid.author_uri (i); + string full_name = Disfluid.author_name (i); + if (email != null) { + full_name += " <" + email + ">"; + } else if (uri != null) { + full_name += " " + uri; + } + if (Disfluid.author_is_developer (i)) { + developers += full_name; + } + if (Disfluid.author_is_designer (i)) { + designers += full_name; + } + if (Disfluid.author_is_artist (i)) { + artists += full_name; + } + if (Disfluid.author_is_documenter (i)) { + documenters += full_name; + } + } + window.set_developers (developers); + window.set_designers (designers); + window.set_artists (artists); + window.set_documenters (documenters); + var translation_credits = Disfluid.translation_credits (); + window.set_translator_credits (translation_credits); + window.set_copyright (Disfluid.copyright_statement ()); + window.set_license_type (Gtk.License.AGPL_3_0); + return window; + } +} diff --git a/src/vala/main.vala b/src/vala/main.vala new file mode 100644 index 0000000..535baf6 --- /dev/null +++ b/src/vala/main.vala @@ -0,0 +1,26 @@ +int main (string[] args) { + Intl.setlocale (LocaleCategory.ALL, ""); + var name = "eu.planete_kraus.Disfluid"; + if (Disfluid.is_nightly ()) { + name += ".Devel"; + } + var app = new Adw.Application( + name, + ApplicationFlags.FLAGS_NONE + ); + app.activate.connect(() => { + var cache_entry = new Disfluid.CacheEntry.alloc (512, 4096, 2 * 1024 * 1024); + cache_entry.set_request_gdate (new GLib.DateTime.utc (2023, 03, 26, 19, 38, 00)); + cache_entry.set_response_gdate (new GLib.DateTime.now ()); + cache_entry.set_key ("GET https://example.com\r\n"); + cache_entry.set_response_header ("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n"); + cache_entry.set_response_body ((char[]) "Hello"); + var cache_entry_view = new Disfluid.CacheEntryView.with_value ("/tmp/test.cache", cache_entry); + var cache_view = new Adw.PreferencesPage (); + cache_view.add (cache_entry_view); + var window = new Disfluid.MainWindow (cache_view); + window.set_application (app); + window.present(); + }); + return app.run(args); +} diff --git a/src/vala/main_window.vala b/src/vala/main_window.vala new file mode 100644 index 0000000..d4dec0d --- /dev/null +++ b/src/vala/main_window.vala @@ -0,0 +1,55 @@ +namespace Disfluid { + class MainWindow: Adw.ApplicationWindow { + private Adw.WindowTitle _window_title; + private Gtk.Box _layout; + + private string? _subtitle = null; + private Gtk.Widget? _disfluid_content = null; + + public string? subtitle { + get { + return this._subtitle; + } + set { + this._subtitle = value; + this._window_title.subtitle = value; + } + } + + public Gtk.Widget? disfluid_content { + get { + return this._disfluid_content; + } + set { + if (this._disfluid_content != null) { + this._layout.remove (this._disfluid_content); + } + this._disfluid_content = value; + if (value != null) { + this._layout.append (value); + } + } + } + + construct { + this._window_title = new Adw.WindowTitle (Disfluid.metaphor_name (), this._subtitle); + var bar = new Adw.HeaderBar (); + bar.centering_policy = Adw.CenteringPolicy.STRICT; + bar.title_widget = this._window_title; + this._layout = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); + this._layout.append (bar); + if (this._disfluid_content != null) { + this._layout.append (this._disfluid_content); + } + this.content = this._layout; + } + + public MainWindow (Gtk.Widget? content) { + Object (subtitle: null, disfluid_content: content); + } + + public MainWindow.specific (string subtitle, Gtk.Widget? content) { + Object (subtitle: subtitle, disfluid_content: content); + } + } +} diff --git a/tests/run-unit-tests.c b/tests/run-unit-tests.c index c6713fe..a290284 100644 --- a/tests/run-unit-tests.c +++ b/tests/run-unit-tests.c @@ -6,6 +6,7 @@ main (int argc, char *argv[]) { (void) argc; (void) argv; + /* This is just a test runner, do not call bindtextdomain () */ size_t n_tests, n_failures; char *output = disfluid_run_tests (&n_tests, &n_failures); free (output); -- cgit v1.2.3