diff options
author | Vivien Kraus <vivien@planete-kraus.eu> | 2023-03-26 14:31:52 +0200 |
---|---|---|
committer | Vivien Kraus <vivien@planete-kraus.eu> | 2023-04-02 23:53:56 +0200 |
commit | c1ef27c64cab1b48308cb56515027bf09a8ad11f (patch) | |
tree | 7adea1997a8a0872a1649477b70d4cf3da8c8e85 /src | |
parent | ac95860f1f8817e3a589682db6d98ff77f36d995 (diff) |
Start a vala user interface
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 21 | ||||
-rw-r--r-- | src/gir/Makefile.am | 30 | ||||
-rw-r--r-- | src/libdisfluid/Makefile.am | 1 | ||||
-rw-r--r-- | src/libdisfluid/disfluid-authors.h | 66 | ||||
-rw-r--r-- | src/libdisfluid/disfluid-cache-entry.h | 65 | ||||
-rw-r--r-- | src/libdisfluid/disfluid-ui.h | 23 | ||||
-rw-r--r-- | src/libdisfluid/main.c | 54 | ||||
-rw-r--r-- | src/vala/Makefile.am | 37 | ||||
-rw-r--r-- | src/vala/about.vala | 51 | ||||
-rw-r--r-- | src/vala/main.vala | 26 | ||||
-rw-r--r-- | src/vala/main_window.vala | 55 |
11 files changed, 404 insertions, 25 deletions
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 <https://www.gnu.org/licenses/>.\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 <assert.h> # include <flexmember.h> @@ -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); + } + } +} |