From f2bcec31e13599bff9bff1f05df1649a3d688c9b Mon Sep 17 00:00:00 2001
From: Alexander Vanhee <160625516+AlexanderVanhee@users.noreply.github.com>
Date: Fri, 10 Jul 2026 14:35:44 +0200
Subject: [PATCH 1/3] Add daemon process
The daemon process is a wrapper around the actual Bazaar application, it's responsibilities are managing the application, forwarding launches with parameters (except --no-window) and implementing the search provider (also auto-updates in the future).
The search provider part consumes a ~2mb file with the data needed for the search engine, its generated after the entry-group cache.
The daemon does not link to gobject library to keep the memory footprint as low as possible, around 8 mb with a further 12mb for Flatpak stuff
---
.../flatpak/io.github.kolunmi.Bazaar.json | 2 +-
data/dbus/io.github.kolunmi.Bazaar.service.in | 2 +-
data/io.github.kolunmi.Bazaar.desktop.in | 4 +-
...thub.kolunmi.Bazaar.search-provider.ini.in | 2 +-
data/io.github.kolunmi.Bazaar.service.in | 2 +-
meson.build | 7 +
src/bazaar-daemon.c | 553 ++++++++++++++++++
src/bz-application.c | 62 +-
src/bz-gnome-shell-search-provider.c | 465 ---------------
src/bz-gnome-shell-search-provider.h | 50 --
src/bz-search-index-writer.c | 162 +++++
src/bz-search-index-writer.h | 50 ++
src/meson.build | 22 +-
src/search-index.c | 336 +++++++++++
src/search-index.h | 67 +++
15 files changed, 1222 insertions(+), 564 deletions(-)
create mode 100644 src/bazaar-daemon.c
delete mode 100644 src/bz-gnome-shell-search-provider.c
delete mode 100644 src/bz-gnome-shell-search-provider.h
create mode 100644 src/bz-search-index-writer.c
create mode 100644 src/bz-search-index-writer.h
create mode 100644 src/search-index.c
create mode 100644 src/search-index.h
diff --git a/build-aux/flatpak/io.github.kolunmi.Bazaar.json b/build-aux/flatpak/io.github.kolunmi.Bazaar.json
index 5fa71df0e..fba4ff9c6 100644
--- a/build-aux/flatpak/io.github.kolunmi.Bazaar.json
+++ b/build-aux/flatpak/io.github.kolunmi.Bazaar.json
@@ -3,7 +3,7 @@
"runtime": "org.gnome.Platform",
"runtime-version": "50",
"sdk": "org.gnome.Sdk",
- "command": "bazaar",
+ "command": "bazaar-daemon",
"sdk-extensions": [
"org.freedesktop.Sdk.Extension.llvm20"
],
diff --git a/data/dbus/io.github.kolunmi.Bazaar.service.in b/data/dbus/io.github.kolunmi.Bazaar.service.in
index b38d0193c..1be0f780e 100644
--- a/data/dbus/io.github.kolunmi.Bazaar.service.in
+++ b/data/dbus/io.github.kolunmi.Bazaar.service.in
@@ -1,4 +1,4 @@
[D-BUS Service]
Name=io.github.kolunmi.Bazaar
SystemdService=io.github.kolunmi.Bazaar.service
-Exec=@bindir@/bazaar service
+Exec=@bindir@/bazaar-daemon service
diff --git a/data/io.github.kolunmi.Bazaar.desktop.in b/data/io.github.kolunmi.Bazaar.desktop.in
index 095f00faf..2179bff9c 100644
--- a/data/io.github.kolunmi.Bazaar.desktop.in
+++ b/data/io.github.kolunmi.Bazaar.desktop.in
@@ -1,7 +1,7 @@
[Desktop Entry]
Name=Bazaar
Comment=Add, remove or update flatpak software on this computer
-Exec=bazaar %U
+Exec=bazaar-daemon %U
Icon=io.github.kolunmi.Bazaar
Terminal=false
Type=Application
@@ -14,4 +14,4 @@ X-Purism-FormFactor=Workstation;Mobile;
[Desktop Action new-window]
Name=New Window
-Exec=bazaar %U
+Exec=bazaar-daemon %U
diff --git a/data/io.github.kolunmi.Bazaar.search-provider.ini.in b/data/io.github.kolunmi.Bazaar.search-provider.ini.in
index 4cde63728..537beb5c8 100644
--- a/data/io.github.kolunmi.Bazaar.search-provider.ini.in
+++ b/data/io.github.kolunmi.Bazaar.search-provider.ini.in
@@ -1,5 +1,5 @@
[Shell Search Provider]
DesktopId=io.github.kolunmi.Bazaar.desktop
-BusName=io.github.kolunmi.Bazaar
+BusName=io.github.kolunmi.Bazaar.SearchProvider
ObjectPath=/io/github/kolunmi/Bazaar/SearchProvider
Version=2
\ No newline at end of file
diff --git a/data/io.github.kolunmi.Bazaar.service.in b/data/io.github.kolunmi.Bazaar.service.in
index ef38f4ab9..06a53722b 100644
--- a/data/io.github.kolunmi.Bazaar.service.in
+++ b/data/io.github.kolunmi.Bazaar.service.in
@@ -5,4 +5,4 @@ PartOf=graphical-session.target
[Service]
Type=dbus
BusName=io.github.kolunmi.Bazaar
-ExecStart=@bindir@/bazaar --no-window
+ExecStart=@bindir@/bazaar-daemon --no-window
diff --git a/meson.build b/meson.build
index f25b2adea..f74c9d812 100644
--- a/meson.build
+++ b/meson.build
@@ -105,6 +105,13 @@ else
dl_worker_bin_name = 'bazaar-dl-worker'
config_h.set_quoted('DL_WORKER_BIN_NAME', dl_worker_bin_name)
+ daemon_bin_name = 'bazaar-daemon'
+ config_h.set_quoted('DAEMON_BIN_NAME', daemon_bin_name)
+
+ bazaar_bin_name = 'bazaar'
+ config_h.set_quoted('BAZAAR_BIN_NAME', bazaar_bin_name)
+ config_h.set_quoted('BAZAAR_BIN_PATH', get_option('prefix') / get_option('bindir') / bazaar_bin_name)
+
if get_option('hardcoded_main_config_path') != ''
config_h.set_quoted('HARDCODED_MAIN_CONFIG', get_option('hardcoded_main_config_path'))
endif
diff --git a/src/bazaar-daemon.c b/src/bazaar-daemon.c
new file mode 100644
index 000000000..d02c67b42
--- /dev/null
+++ b/src/bazaar-daemon.c
@@ -0,0 +1,553 @@
+/* bazaar-daemon.c
+ *
+ * Copyright 2026 Alexander Vanhee
+ *
+ * This program 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 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "config.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "search-index.h"
+
+#define BUS_NAME "io.github.kolunmi.Bazaar.SearchProvider"
+#define OBJECT_PATH "/io/github/kolunmi/Bazaar/SearchProvider"
+#define DAEMON_IFACE "io.github.kolunmi.Bazaar.Daemon"
+#define MAX_SEARCH_RESULTS 25
+#define ACTIVATE_TIMEOUT_US 2000000
+
+#define _cleanup_(x) __attribute__ ((cleanup (x)))
+
+#define SD_BUS_CHECK(expr) \
+ do \
+ { \
+ r = (expr); \
+ if (r < 0) \
+ goto out; \
+ } \
+ while (0)
+
+static sd_event *event = NULL;
+static sd_bus *bus = NULL;
+static pid_t child_pid = -1;
+static SearchIndex *g_index = NULL;
+static char *g_index_path = NULL;
+
+static void log_msg (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+static char *build_index_path (void);
+static void ensure_index_loaded (void);
+static int strv_count_local (char **strv);
+static void strv_free_local (char **strv);
+static void strv_freep (char ***strv);
+static void generic_freep (void *p);
+static int on_child_exit (sd_event_source *s, const siginfo_t *si, void *userdata);
+static void launch_app (char **extra_args, int n_extra_args);
+static int build_and_send_search_reply (sd_bus_message *call, char **terms);
+static int method_get_result_set (sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
+static int method_get_result_metas (sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
+static int method_activate_result (sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
+static int method_launch_search (sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
+static int method_relaunch (sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
+static int method_quit (sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
+static int on_signal (sd_event_source *s, const struct signalfd_siginfo *si, void *userdata);
+static int forward_to_running_daemon (sd_bus *forward_bus, int argc, char *argv[]);
+
+static const sd_bus_vtable search_provider_vtable[] = {
+ SD_BUS_VTABLE_START (0),
+ SD_BUS_METHOD ("GetInitialResultSet", "as", "as", method_get_result_set, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD ("GetSubsearchResultSet", "asas", "as", method_get_result_set, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD ("GetResultMetas", "as", "aa{sv}", method_get_result_metas, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD ("ActivateResult", "sasu", "", method_activate_result, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD ("LaunchSearch", "asu", "", method_launch_search, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_VTABLE_END
+};
+
+static const sd_bus_vtable daemon_vtable[] = {
+ SD_BUS_VTABLE_START (0),
+ SD_BUS_METHOD ("Relaunch", "as", "", method_relaunch, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD ("Quit", "", "", method_quit, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_VTABLE_END
+};
+
+int
+main (int argc, char *argv[])
+{
+ sigset_t mask = { 0 };
+ int r = 0;
+ int no_window = 0;
+ _cleanup_ (generic_freep) char **fwd_args = NULL;
+ int n_fwd_args = 0;
+ int i = 0;
+
+ sigemptyset (&mask);
+ sigaddset (&mask, SIGTERM);
+ sigaddset (&mask, SIGINT);
+ sigaddset (&mask, SIGCHLD);
+ sigprocmask (SIG_BLOCK, &mask, NULL);
+
+ r = sd_event_default (&event);
+ if (r < 0)
+ return 1;
+
+ sd_event_add_signal (event, NULL, SIGTERM, on_signal, NULL);
+ sd_event_add_signal (event, NULL, SIGINT, on_signal, NULL);
+
+ r = sd_bus_open_user (&bus);
+ if (r < 0)
+ {
+ log_msg ("Failed to connect to session bus: %s", strerror (-r));
+ return 1;
+ }
+
+ r = sd_bus_request_name (bus, BUS_NAME, 0);
+ if (r < 0)
+ {
+ if (r == -EEXIST || r == -EALREADY)
+ {
+ log_msg ("App already running, forwarding");
+ forward_to_running_daemon (bus, argc, argv);
+ sd_bus_flush_close_unref (bus);
+ sd_event_unref (event);
+ return 0;
+ }
+
+ log_msg ("Failed to acquire bus name %s: %s", BUS_NAME, strerror (-r));
+ return 1;
+ }
+
+ r = sd_bus_add_object_vtable (bus, NULL, OBJECT_PATH,
+ "org.gnome.Shell.SearchProvider2",
+ search_provider_vtable, NULL);
+ if (r < 0)
+ log_msg ("Failed to register search provider object: %s", strerror (-r));
+
+ r = sd_bus_add_object_vtable (bus, NULL, OBJECT_PATH,
+ DAEMON_IFACE,
+ daemon_vtable, NULL);
+ if (r < 0)
+ log_msg ("Failed to register daemon object: %s", strerror (-r));
+
+ r = sd_bus_attach_event (bus, event, SD_EVENT_PRIORITY_NORMAL);
+ if (r < 0)
+ log_msg ("Failed to attach bus to event loop: %s", strerror (-r));
+
+ ensure_index_loaded ();
+
+ fwd_args = malloc (sizeof (char *) * (size_t) (argc > 0 ? argc : 1));
+ for (i = 1; i < argc; i++)
+ {
+ if (strcmp (argv[i], "--no-window") == 0)
+ {
+ no_window = 1;
+ continue;
+ }
+
+ fwd_args[n_fwd_args] = argv[i];
+ n_fwd_args++;
+ }
+
+ if (no_window)
+ log_msg ("staying headless");
+ else
+ launch_app (fwd_args, n_fwd_args);
+
+ sd_event_loop (event);
+
+ search_index_close (g_index);
+ free (g_index_path);
+
+ sd_bus_flush_close_unref (bus);
+ sd_event_unref (event);
+
+ return 0;
+}
+
+static int
+forward_to_running_daemon (sd_bus *forward_bus, int argc, char *argv[])
+{
+ _cleanup_ (sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_ (sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ _cleanup_ (sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ int r = 0;
+
+ r = sd_bus_message_new_method_call (forward_bus, &m, BUS_NAME, OBJECT_PATH,
+ DAEMON_IFACE, "Relaunch");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append_strv (m, argv + (argc > 0 ? 1 : 0));
+ if (r < 0)
+ return r;
+
+ r = sd_bus_call (forward_bus, m, ACTIVATE_TIMEOUT_US, &error, &reply);
+ if (r < 0)
+ log_msg ("Failed to forward relaunch request: %s",
+ sd_bus_error_is_set (&error) ? error.message : strerror (-r));
+
+ return r;
+}
+
+static int
+method_relaunch (sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
+{
+ _cleanup_ (strv_freep) char **terms = NULL;
+ int r = 0;
+
+ r = sd_bus_message_read_strv (m, &terms);
+ if (r < 0)
+ return r;
+
+ log_msg ("Relaunch requested via D-Bus");
+
+ launch_app (terms, strv_count_local (terms));
+
+ return sd_bus_reply_method_return (m, NULL);
+}
+
+static int
+method_quit (sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
+{
+ int r = 0;
+
+ log_msg ("Quit requested");
+
+ r = sd_bus_reply_method_return (m, NULL);
+
+ if (child_pid > 0)
+ kill (child_pid, SIGTERM);
+
+ sd_event_exit (event, 0);
+ return r;
+}
+
+static void
+log_msg (const char *fmt, ...)
+{
+ va_list args;
+
+ printf ("(bazaar-daemon): ");
+
+ va_start (args, fmt);
+ vprintf (fmt, args);
+ va_end (args);
+
+ printf ("\n");
+ fflush (stdout);
+}
+
+static char *
+build_index_path (void)
+{
+ const char *cache_home = NULL;
+ const char *home = NULL;
+ char buf[4096] = { 0 };
+
+ cache_home = getenv ("XDG_CACHE_HOME");
+ if (cache_home != NULL && *cache_home != '\0')
+ {
+ snprintf (buf, sizeof (buf),
+ "%s/io.github.kolunmi.Bazaar/core/search-index",
+ cache_home);
+ return strdup (buf);
+ }
+
+ home = getenv ("HOME");
+ if (home != NULL && *home != '\0')
+ {
+ snprintf (buf, sizeof (buf),
+ "%s/.cache/io.github.kolunmi.Bazaar/core/search-index",
+ home);
+ return strdup (buf);
+ }
+
+ return strdup ("/tmp/search-index");
+}
+
+static void
+ensure_index_loaded (void)
+{
+ if (g_index_path == NULL)
+ g_index_path = build_index_path ();
+
+ if (g_index == NULL)
+ {
+ g_index = search_index_open (g_index_path);
+ if (g_index == NULL)
+ log_msg ("Search index not yet available at %s", g_index_path);
+ return;
+ }
+
+ if (search_index_reload_if_stale (&g_index))
+ log_msg ("Search index reloaded ");
+}
+
+static int
+strv_count_local (char **strv)
+{
+ int n = 0;
+
+ if (strv == NULL)
+ return 0;
+
+ while (strv[n] != NULL)
+ n++;
+
+ return n;
+}
+
+static void
+strv_free_local (char **strv)
+{
+ char **p = NULL;
+
+ if (strv == NULL)
+ return;
+
+ for (p = strv; *p != NULL; p++)
+ free (*p);
+ free (strv);
+}
+
+static void
+strv_freep (char ***strv)
+{
+ strv_free_local (*strv);
+}
+
+static void
+generic_freep (void *p)
+{
+ free (*(void **) p);
+}
+
+static int
+on_child_exit (sd_event_source *s,
+ const siginfo_t *si,
+ void *userdata)
+{
+ log_msg ("Application exited (status %d)", si->si_status);
+
+ child_pid = -1;
+ sd_event_source_unref (s);
+ ensure_index_loaded ();
+
+ return 0;
+}
+
+static void
+launch_app (char **extra_args,
+ int n_extra_args)
+{
+ pid_t pid = -1;
+ _cleanup_ (generic_freep) char **argv = NULL;
+ int i = 0;
+ sigset_t mask = { 0 };
+
+ argv = malloc (sizeof (char *) * (size_t) (n_extra_args + 2));
+ argv[0] = (char *) BAZAAR_BIN_PATH;
+ for (i = 0; i < n_extra_args; i++)
+ argv[i + 1] = extra_args[i];
+ argv[n_extra_args + 1] = NULL;
+
+ log_msg ("Application starting");
+
+ pid = fork ();
+ if (pid == 0)
+ {
+ sigemptyset (&mask);
+ sigprocmask (SIG_SETMASK, &mask, NULL);
+
+ execvp (argv[0], argv);
+ perror ("execvp");
+ _exit (127);
+ }
+
+ if (pid < 0)
+ {
+ log_msg ("Failed to spawn application: %s", strerror (errno));
+ return;
+ }
+
+ if (child_pid <= 0)
+ child_pid = pid;
+
+ sd_event_add_child (event, NULL, pid, WEXITED, on_child_exit, NULL);
+}
+
+static int
+build_and_send_search_reply (sd_bus_message *call,
+ char **terms)
+{
+ _cleanup_ (sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ SearchIndexMatch matches[MAX_SEARCH_RESULTS] = { 0 };
+ size_t n_matches = 0;
+ size_t i = 0;
+ int r = 0;
+
+ ensure_index_loaded ();
+
+ n_matches = search_index_query (
+ g_index, (const char *const *) terms,
+ strv_count_local (terms),
+ matches, MAX_SEARCH_RESULTS);
+
+ SD_BUS_CHECK (sd_bus_message_new_method_return (call, &reply));
+ SD_BUS_CHECK (sd_bus_message_open_container (reply, 'a', "s"));
+
+ for (i = 0; i < n_matches; i++)
+ SD_BUS_CHECK (sd_bus_message_append (reply, "s", matches[i].entry->id));
+
+ SD_BUS_CHECK (sd_bus_message_close_container (reply));
+
+ return sd_bus_send (NULL, reply, NULL);
+
+out:
+ return r;
+}
+
+static int
+method_get_result_set (sd_bus_message *m,
+ void *userdata,
+ sd_bus_error *ret_error)
+{
+ _cleanup_ (strv_freep) char **terms = NULL;
+ const char *sig = NULL;
+ int r = 0;
+
+ sig = sd_bus_message_get_signature (m, 1);
+
+ if (sig != NULL && strcmp (sig, "asas") == 0)
+ {
+ _cleanup_ (strv_freep) char **previous = NULL;
+
+ r = sd_bus_message_read_strv (m, &previous);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_bus_message_read_strv (m, &terms);
+ if (r < 0)
+ return r;
+
+ return build_and_send_search_reply (m, terms);
+}
+
+static int
+method_get_result_metas (sd_bus_message *m,
+ void *userdata,
+ sd_bus_error *ret_error)
+{
+ _cleanup_ (sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_ (strv_freep) char **ids = NULL;
+ char **p = NULL;
+ int r = 0;
+
+ r = sd_bus_message_read_strv (m, &ids);
+ if (r < 0)
+ return r;
+
+ ensure_index_loaded ();
+
+ SD_BUS_CHECK (sd_bus_message_new_method_return (m, &reply));
+ SD_BUS_CHECK (sd_bus_message_open_container (reply, 'a', "a{sv}"));
+
+ for (p = ids; p != NULL && *p != NULL; p++)
+ {
+ const SearchIndexEntry *e = NULL;
+
+ e = search_index_find (g_index, *p);
+
+ if (e == NULL)
+ continue;
+
+ SD_BUS_CHECK (sd_bus_message_open_container (reply, 'a', "{sv}"));
+ SD_BUS_CHECK (sd_bus_message_append (reply, "{sv}", "id", "s", e->id));
+ SD_BUS_CHECK (sd_bus_message_append (reply, "{sv}", "name", "s", e->title));
+
+ if (e->description != NULL)
+ SD_BUS_CHECK (sd_bus_message_append (reply, "{sv}", "description", "s", e->description));
+
+ if (e->icon_path != NULL)
+ SD_BUS_CHECK (sd_bus_message_append (reply, "{sv}", "gicon", "s", e->icon_path));
+
+ SD_BUS_CHECK (sd_bus_message_close_container (reply));
+ }
+
+ SD_BUS_CHECK (sd_bus_message_close_container (reply));
+
+ return sd_bus_send (NULL, reply, NULL);
+
+out:
+ return r;
+}
+
+static int
+method_activate_result (sd_bus_message *m,
+ void *userdata,
+ sd_bus_error *ret_error)
+{
+ const char *id = NULL;
+ _cleanup_ (generic_freep) char *uri_arg = NULL;
+ char *args[1] = { NULL };
+ int r = 0;
+
+ r = sd_bus_message_read (m, "s", &id);
+ if (r < 0)
+ return r;
+
+ uri_arg = malloc (strlen ("appstream:") + strlen (id) + 1);
+ sprintf (uri_arg, "appstream:%s", id);
+
+ args[0] = uri_arg;
+ launch_app (args, 1);
+
+ return sd_bus_reply_method_return (m, NULL);
+}
+
+static int
+method_launch_search (sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
+{
+ _cleanup_ (strv_freep) char **terms = NULL;
+ // TODO: Actually open search in app with the terms
+ launch_app (NULL, 0);
+
+ return sd_bus_reply_method_return (m, NULL);
+}
+
+static int
+on_signal (sd_event_source *s,
+ const struct signalfd_siginfo *si,
+ void *userdata)
+{
+ log_msg ("Daemon shutting down");
+
+ if (child_pid > 0)
+ kill (child_pid, SIGTERM);
+
+ sd_event_exit (event, 0);
+
+ return 0;
+}
diff --git a/src/bz-application.c b/src/bz-application.c
index d0a6c434c..0fd909da2 100644
--- a/src/bz-application.c
+++ b/src/bz-application.c
@@ -46,7 +46,6 @@
#include "bz-flatpak-bundle-result.h"
#include "bz-flatpak-entry.h"
#include "bz-flatpak-instance.h"
-#include "bz-gnome-shell-search-provider.h"
#include "bz-hash-table-object.h"
#include "bz-inspector.h"
#include "bz-internal-config.h"
@@ -60,6 +59,7 @@
#include "bz-root-blocklist.h"
#include "bz-root-curated-config.h"
#include "bz-serializable.h"
+#include "bz-search-index-writer.h"
#include "bz-state-info.h"
#include "bz-transaction-manager.h"
#include "bz-window.h"
@@ -83,7 +83,6 @@ struct _BzApplication
BzFlathubState *flathub;
BzFlathubState *tmp_flathub;
BzFlatpakInstance *flatpak;
- BzGnomeShellSearchProvider *gs_search;
BzInternalConfig *internal_config;
BzMainConfig *config;
BzMalcontentService *malcontent;
@@ -415,7 +414,6 @@ bz_application_dispose (GObject *object)
g_clear_object (&self->group_filter);
g_clear_object (&self->group_filter_model);
g_clear_object (&self->groups);
- g_clear_object (&self->gs_search);
g_clear_object (&self->installed_apps);
g_clear_object (&self->malcontent);
g_clear_object (&self->internal_config);
@@ -464,7 +462,6 @@ bz_application_command_line (GApplication *app,
gint argc = 0;
g_auto (GStrv) argv = NULL;
gboolean help = FALSE;
- gboolean no_window = FALSE;
g_auto (GStrv) blocklists_strv = NULL;
g_auto (GStrv) content_configs_strv = NULL;
g_auto (GStrv) locations = NULL;
@@ -472,7 +469,7 @@ bz_application_command_line (GApplication *app,
GOptionEntry main_entries[] = {
{ "help", 0, 0, G_OPTION_ARG_NONE, &help, "Print help" },
- { "no-window", 0, 0, G_OPTION_ARG_NONE, &no_window, "Ensure the service is running without creating a new window" },
+ { "no-window", 0, 0, G_OPTION_ARG_NONE, NULL, "Ensure the service is running without creating a new window (daemon)" },
{ "extra-blocklist", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &blocklists_strv, "Add an extra blocklist to read from" },
{ "extra-curated-config", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &content_configs_strv, "Add an extra yaml file with which to configure the app browser" },
/* Here for backwards compat */
@@ -527,8 +524,6 @@ bz_application_command_line (GApplication *app,
g_autoptr (GtkStringList) content_configs = NULL;
g_autoptr (DexFuture) init = NULL;
- g_debug ("Starting daemon!");
- g_application_hold (G_APPLICATION (self));
self->running = TRUE;
blocklists = gtk_string_list_new (NULL);
@@ -575,7 +570,7 @@ bz_application_command_line (GApplication *app,
dex_future_disown (g_steal_pointer (&init));
}
- if (!no_window && !preview_metainfo)
+ if (!preview_metainfo)
{
if (locations == NULL || *locations == NULL)
new_window (self);
@@ -610,25 +605,6 @@ bz_application_local_command_line (GApplication *application,
return FALSE;
}
-static gboolean
-bz_application_dbus_register (GApplication *application,
- GDBusConnection *connection,
- const gchar *object_path,
- GError **error)
-{
- BzApplication *self = BZ_APPLICATION (application);
- return bz_gnome_shell_search_provider_set_connection (self->gs_search, connection, error);
-}
-
-static void
-bz_application_dbus_unregister (GApplication *application,
- GDBusConnection *connection,
- const gchar *object_path)
-{
- BzApplication *self = BZ_APPLICATION (application);
- bz_gnome_shell_search_provider_set_connection (self->gs_search, NULL, NULL);
-}
-
static void
bz_application_class_init (BzApplicationClass *klass)
{
@@ -640,8 +616,6 @@ bz_application_class_init (BzApplicationClass *klass)
app_class->activate = bz_application_activate;
app_class->command_line = bz_application_command_line;
app_class->local_command_line = bz_application_local_command_line;
- app_class->dbus_register = bz_application_dbus_register;
- app_class->dbus_unregister = bz_application_dbus_unregister;
g_type_ensure (BZ_TYPE_RESULT);
}
@@ -875,9 +849,23 @@ bz_application_quit_action (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
- BzApplication *self = user_data;
+ BzApplication *self = user_data;
+ g_autoptr (GDBusConnection) conn = NULL;
+ g_autoptr (GError) error = NULL;
- g_assert (BZ_IS_APPLICATION (self));
+ conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+ if (conn != NULL)
+ {
+ g_dbus_connection_call_sync (
+ conn, "io.github.kolunmi.Bazaar.SearchProvider",
+ "/io/github/kolunmi/Bazaar/SearchProvider",
+ "io.github.kolunmi.Bazaar.Daemon",
+ "Quit", NULL, NULL, G_DBUS_CALL_FLAGS_NONE,
+ -1, NULL, &error);
+ }
+
+ if (error != NULL)
+ g_warning ("Failed to quit daemon: %s", error->message);
g_application_quit (G_APPLICATION (self));
}
@@ -903,8 +891,6 @@ bz_application_init (BzApplication *self)
self->running = FALSE;
g_weak_ref_init (&self->main_window, NULL);
- self->gs_search = bz_gnome_shell_search_provider_new ();
-
g_action_map_add_action_entries (
G_ACTION_MAP (self),
app_actions,
@@ -1583,6 +1569,9 @@ cache_groups_fiber (GWeakRef *wr)
g_autoptr (GVariant) variant = NULL;
g_autoptr (GBytes) bytes = NULL;
guint n_groups = 0;
+ g_autoptr (GError) index_error = NULL;
+ g_autofree char *module_dir = NULL;
+ g_autofree char *index_path = NULL;
bz_weak_get_or_return_reject (self, wr);
@@ -1620,6 +1609,12 @@ cache_groups_fiber (GWeakRef *wr)
if (!result)
g_warning ("Failed to cache groups to %s: %s", groups_cache, local_error->message);
+ module_dir = bz_dup_module_dir ();
+ index_path = g_build_filename (module_dir, "search-index", NULL);
+
+ if (!bz_write_search_index (G_LIST_MODEL (self->groups), index_path, &index_error))
+ g_warning ("Failed to write search index to %s: %s", index_path, index_error->message);
+
return dex_future_new_true ();
}
@@ -3518,7 +3513,6 @@ init_service_struct (BzApplication *self,
self->search_engine = bz_search_engine_new ();
bz_search_engine_set_model (self->search_engine, G_LIST_MODEL (self->group_filter_model));
bz_search_engine_set_biases (self->search_engine, G_LIST_MODEL (self->search_biases));
- bz_gnome_shell_search_provider_set_engine (self->gs_search, self->search_engine);
self->curated_provider = bz_content_provider_new ();
bz_content_provider_set_input_files (
diff --git a/src/bz-gnome-shell-search-provider.c b/src/bz-gnome-shell-search-provider.c
deleted file mode 100644
index fa62acba5..000000000
--- a/src/bz-gnome-shell-search-provider.c
+++ /dev/null
@@ -1,465 +0,0 @@
-/* bz-gnome-shell-search-provider.c
- *
- * Copyright 2025 Adam Masciola
- *
- * This program 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 of the License, or
- * (at your option) any later version.
- *
- * 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#include "bz-gnome-shell-search-provider.h"
-#include "bz-entry-group.h"
-#include "bz-finished-search-query.h"
-#include "bz-search-result.h"
-#include "util.h"
-#include "gs-shell-search-provider-generated.h"
-
-struct _BzGnomeShellSearchProvider
-{
- GObject parent_instance;
-
- BzSearchEngine *engine;
- GDBusConnection *connection;
-
- BzShellSearchProvider2 *skeleton;
- DexFuture *task;
-
- GHashTable *last_results;
-};
-
-G_DEFINE_FINAL_TYPE (BzGnomeShellSearchProvider, bz_gnome_shell_search_provider, G_TYPE_OBJECT);
-
-enum
-{
- PROP_0,
-
- PROP_ENGINE,
- PROP_CONNECTION,
-
- LAST_PROP
-};
-static GParamSpec *props[LAST_PROP] = { 0 };
-
-BZ_DEFINE_DATA (
- request,
- Request,
- {
- BzGnomeShellSearchProvider *self;
- GDBusMethodInvocation *invocation;
- GApplication *application;
- },
- BZ_RELEASE_DATA (invocation, g_object_unref);
- BZ_RELEASE_DATA (application, g_application_release);)
-static DexFuture *
-request_finally (DexFuture *future,
- RequestData *data);
-
-static void
-start_request (BzGnomeShellSearchProvider *self,
- GDBusMethodInvocation *invocation,
- const char *const *terms);
-
-static void
-bz_gnome_shell_search_provider_dispose (GObject *object)
-{
- BzGnomeShellSearchProvider *self = BZ_GNOME_SHELL_SEARCH_PROVIDER (object);
-
- dex_clear (&self->task);
-
- g_clear_object (&self->engine);
- g_clear_object (&self->connection);
- g_clear_object (&self->skeleton);
- g_clear_pointer (&self->last_results, g_hash_table_unref);
-
- G_OBJECT_CLASS (bz_gnome_shell_search_provider_parent_class)->dispose (object);
-}
-
-static void
-bz_gnome_shell_search_provider_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- BzGnomeShellSearchProvider *self = BZ_GNOME_SHELL_SEARCH_PROVIDER (object);
-
- switch (prop_id)
- {
- case PROP_ENGINE:
- g_value_set_object (value, bz_gnome_shell_search_provider_get_engine (self));
- break;
- case PROP_CONNECTION:
- g_value_set_object (value, bz_gnome_shell_search_provider_get_connection (self));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-bz_gnome_shell_search_provider_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- BzGnomeShellSearchProvider *self = BZ_GNOME_SHELL_SEARCH_PROVIDER (object);
-
- switch (prop_id)
- {
- case PROP_ENGINE:
- bz_gnome_shell_search_provider_set_engine (self, g_value_get_object (value));
- break;
- case PROP_CONNECTION:
- bz_gnome_shell_search_provider_set_connection (self, g_value_get_object (value), NULL);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-bz_gnome_shell_search_provider_class_init (BzGnomeShellSearchProviderClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->set_property = bz_gnome_shell_search_provider_set_property;
- object_class->get_property = bz_gnome_shell_search_provider_get_property;
- object_class->dispose = bz_gnome_shell_search_provider_dispose;
-
- props[PROP_ENGINE] =
- g_param_spec_object (
- "engine",
- NULL, NULL,
- BZ_TYPE_SEARCH_ENGINE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
-
- props[PROP_CONNECTION] =
- g_param_spec_object (
- "connection",
- NULL, NULL,
- G_TYPE_DBUS_CONNECTION,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
-
- g_object_class_install_properties (object_class, LAST_PROP, props);
-}
-
-static gboolean
-get_initial_result_set (BzShellSearchProvider2 *skeleton,
- GDBusMethodInvocation *invocation,
- gchar **terms,
- BzGnomeShellSearchProvider *self)
-{
- start_request (self, invocation, (const char *const *) terms);
- return TRUE;
-}
-
-static gboolean
-get_subsearch_result_set (BzShellSearchProvider2 *skeleton,
- GDBusMethodInvocation *invocation,
- gchar **previous_results,
- gchar **terms,
- BzGnomeShellSearchProvider *self)
-{
- start_request (self, invocation, (const char *const *) terms);
- return TRUE;
-}
-
-static gboolean
-get_result_metas (BzShellSearchProvider2 *skeleton,
- GDBusMethodInvocation *invocation,
- gchar **results,
- BzGnomeShellSearchProvider *self)
-{
- g_autoptr (GVariantBuilder) builder = NULL;
-
- builder = g_variant_builder_new (G_VARIANT_TYPE ("aa{sv}"));
-
- for (char **result = results; *result != NULL; result++)
- {
- BzEntryGroup *group = NULL;
- g_autoptr (GVariantBuilder) meta_builder = NULL;
- const char *title = NULL;
- const char *description = NULL;
- GIcon *icon = NULL;
-
- group = g_hash_table_lookup (self->last_results, *result);
- if (group == NULL)
- {
- g_warning ("failed to find '%s' in gnome-shell search result cache", *result);
- continue;
- }
-
- meta_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
- g_variant_builder_add (meta_builder, "{sv}", "id", g_variant_new_string (*result));
-
- title = bz_entry_group_get_title (group);
- g_variant_builder_add (meta_builder, "{sv}", "name", g_variant_new_string (title));
-
- description = bz_entry_group_get_description (group);
- if (description != NULL)
- g_variant_builder_add (meta_builder, "{sv}", "description", g_variant_new_string (description));
-
- icon = bz_entry_group_get_mini_icon (group);
- if (icon != NULL)
- {
- g_autofree gchar *icon_str = NULL;
-
- icon_str = g_icon_to_string (icon);
- if (icon_str != NULL)
- g_variant_builder_add (meta_builder, "{sv}", "gicon", g_variant_new_string (icon_str));
- else
- {
- g_autoptr (GVariant) icon_serialized = NULL;
-
- icon_serialized = g_icon_serialize (icon);
- if (icon_serialized != NULL)
- g_variant_builder_add (meta_builder, "{sv}", "icon", icon_serialized);
- }
- }
-
- g_variant_builder_add_value (builder, g_variant_builder_end (meta_builder));
- }
-
- g_dbus_method_invocation_return_value (invocation, g_variant_new ("(aa{sv})", builder));
- return TRUE;
-}
-
-static gboolean
-activate_result (BzShellSearchProvider2 *skeleton,
- GDBusMethodInvocation *invocation,
- gchar *result,
- gchar **terms,
- guint32 timestamp,
- BzGnomeShellSearchProvider *self)
-{
- g_action_group_activate_action (
- G_ACTION_GROUP (g_application_get_default ()),
- "show-app-id",
- g_variant_new ("s", result));
-
- bz_shell_search_provider2_complete_activate_result (skeleton, invocation);
- return TRUE;
-}
-
-static gboolean
-launch_search (BzShellSearchProvider2 *skeleton,
- GDBusMethodInvocation *invocation,
- gchar **terms,
- guint32 timestamp,
- BzGnomeShellSearchProvider *self)
-{
- g_autofree gchar *string = NULL;
-
- string = g_strjoinv (" ", terms);
- g_action_group_activate_action (
- G_ACTION_GROUP (g_application_get_default ()),
- "show-app-id",
- g_variant_new ("s", string));
-
- bz_shell_search_provider2_complete_launch_search (skeleton, invocation);
- return TRUE;
-}
-
-static void
-bz_gnome_shell_search_provider_init (BzGnomeShellSearchProvider *self)
-{
- self->skeleton = bz_shell_search_provider2_skeleton_new ();
- self->last_results = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
-
- g_signal_connect (
- self->skeleton, "handle-get-initial-result-set",
- G_CALLBACK (get_initial_result_set), self);
- g_signal_connect (
- self->skeleton, "handle-get-subsearch-result-set",
- G_CALLBACK (get_subsearch_result_set), self);
- g_signal_connect (
- self->skeleton, "handle-get-result-metas",
- G_CALLBACK (get_result_metas), self);
- g_signal_connect (
- self->skeleton, "handle-activate-result",
- G_CALLBACK (activate_result), self);
- g_signal_connect (
- self->skeleton, "handle-launch-search",
- G_CALLBACK (launch_search), self);
-}
-
-BzGnomeShellSearchProvider *
-bz_gnome_shell_search_provider_new (void)
-{
- return g_object_new (BZ_TYPE_GNOME_SHELL_SEARCH_PROVIDER, NULL);
-}
-
-BzSearchEngine *
-bz_gnome_shell_search_provider_get_engine (BzGnomeShellSearchProvider *self)
-{
- g_return_val_if_fail (BZ_IS_GNOME_SHELL_SEARCH_PROVIDER (self), NULL);
- return self->engine;
-}
-
-void
-bz_gnome_shell_search_provider_set_engine (BzGnomeShellSearchProvider *self,
- BzSearchEngine *engine)
-{
- g_return_if_fail (BZ_IS_GNOME_SHELL_SEARCH_PROVIDER (self));
- g_return_if_fail (engine == NULL || BZ_IS_SEARCH_ENGINE (engine));
-
- g_clear_pointer (&self->engine, g_object_unref);
- if (engine != NULL)
- self->engine = g_object_ref (engine);
-
- g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ENGINE]);
-}
-
-GDBusConnection *
-bz_gnome_shell_search_provider_get_connection (BzGnomeShellSearchProvider *self)
-{
- g_return_val_if_fail (BZ_IS_GNOME_SHELL_SEARCH_PROVIDER (self), NULL);
- return self->connection;
-}
-
-gboolean
-bz_gnome_shell_search_provider_set_connection (BzGnomeShellSearchProvider *self,
- GDBusConnection *connection,
- GError **error)
-{
- gboolean success = TRUE;
-
- g_return_val_if_fail (BZ_IS_GNOME_SHELL_SEARCH_PROVIDER (self), FALSE);
- g_return_val_if_fail (connection == NULL || G_IS_DBUS_CONNECTION (connection), FALSE);
-
- if (self->connection != NULL)
- g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self->skeleton));
- g_clear_pointer (&self->connection, g_object_unref);
-
- if (connection != NULL)
- {
- g_autoptr (GError) local_error = NULL;
-
- self->connection = g_object_ref (connection);
-
- success = g_dbus_interface_skeleton_export (
- G_DBUS_INTERFACE_SKELETON (self->skeleton),
- connection,
- "/io/github/kolunmi/Bazaar/SearchProvider",
- &local_error);
- if (!success)
- {
- if (error != NULL)
- g_propagate_error (error, g_steal_pointer (&local_error));
- else
- g_warning ("Could not register gnome shell search provider: %s", local_error->message);
- }
- }
-
- g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CONNECTION]);
- return success;
-}
-
-static DexFuture *
-request_finally (DexFuture *future,
- RequestData *data)
-{
- BzGnomeShellSearchProvider *self = data->self;
- GDBusMethodInvocation *invocation = data->invocation;
- g_autoptr (GError) local_error = NULL;
- const GValue *value = NULL;
- BzFinishedSearchQuery *finished = NULL;
- GPtrArray *results = NULL;
- g_autoptr (GVariantBuilder) builder = NULL;
-
- value = dex_future_get_value (future, &local_error);
- if (value != NULL)
- {
- finished = g_value_get_object (value);
- results = bz_finished_search_query_get_results (finished);
- builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
-
- for (guint i = 0; i < results->len; i++)
- {
- BzSearchResult *result = NULL;
- BzEntryGroup *group = NULL;
- const char *id = NULL;
-
- result = g_ptr_array_index (results, i);
- group = bz_search_result_get_group (result);
- if (bz_entry_group_get_removable (group) > 0)
- /* Skip already installed groups */
- continue;
-
- id = bz_entry_group_get_id (group);
- g_variant_builder_add (builder, "s", id);
- g_hash_table_replace (
- self->last_results,
- g_strdup (id),
- g_object_ref (group));
- }
-
- g_dbus_method_invocation_return_value (
- invocation,
- g_variant_new ("(as)", builder));
- }
- else
- {
- g_warning ("search engine reported an error to the search provider, "
- "returning an empty response to invocation: %s",
- local_error->message);
- g_dbus_method_invocation_return_value (invocation, g_variant_new ("(as)", NULL));
- }
-
- return NULL;
-}
-
-static void
-start_request (BzGnomeShellSearchProvider *self,
- GDBusMethodInvocation *invocation,
- const char *const *terms)
-{
- g_autoptr (RequestData) data = NULL;
- g_autoptr (DexFuture) future = NULL;
-
- dex_clear (&self->task);
- g_hash_table_remove_all (self->last_results);
-
- if (g_strv_length ((gchar **) terms) == 1 &&
- g_utf8_strlen (terms[0], -1) == 1)
- {
- g_dbus_method_invocation_return_value (
- invocation,
- g_variant_new ("(as)", NULL));
- return;
- }
-
- if (self->engine == NULL)
- {
- g_warning ("search provider does not have an engine, "
- "returning empty response to invocation");
- g_dbus_method_invocation_return_value (
- invocation,
- g_variant_new ("(as)", NULL));
- return;
- }
-
- data = request_data_new ();
- data->self = self;
- data->invocation = g_object_ref (invocation);
- data->application = g_application_get_default ();
- g_application_hold (data->application);
-
- future = bz_search_engine_query (self->engine, terms);
- future = dex_future_finally (
- future, (DexFutureCallback) request_finally,
- request_data_ref (data), request_data_unref);
- self->task = g_steal_pointer (&future);
-}
-
-/* End of bz-gnome-shell-search-provider.c */
diff --git a/src/bz-gnome-shell-search-provider.h b/src/bz-gnome-shell-search-provider.h
deleted file mode 100644
index 5e4caef2e..000000000
--- a/src/bz-gnome-shell-search-provider.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* bz-gnome-shell-search-provider.h
- *
- * Copyright 2025 Adam Masciola
- *
- * This program 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 of the License, or
- * (at your option) any later version.
- *
- * 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include "bz-search-engine.h"
-
-G_BEGIN_DECLS
-
-#define BZ_TYPE_GNOME_SHELL_SEARCH_PROVIDER (bz_gnome_shell_search_provider_get_type ())
-G_DECLARE_FINAL_TYPE (BzGnomeShellSearchProvider, bz_gnome_shell_search_provider, BZ, GNOME_SHELL_SEARCH_PROVIDER, GObject)
-
-BzGnomeShellSearchProvider *
-bz_gnome_shell_search_provider_new (void);
-
-BzSearchEngine *
-bz_gnome_shell_search_provider_get_engine (BzGnomeShellSearchProvider *self);
-
-void
-bz_gnome_shell_search_provider_set_engine (BzGnomeShellSearchProvider *self,
- BzSearchEngine *engine);
-
-GDBusConnection *
-bz_gnome_shell_search_provider_get_connection (BzGnomeShellSearchProvider *self);
-
-gboolean
-bz_gnome_shell_search_provider_set_connection (BzGnomeShellSearchProvider *self,
- GDBusConnection *connection,
- GError **error);
-
-G_END_DECLS
-
-/* End of bz-gnome-shell-search-provider.h */
diff --git a/src/bz-search-index-writer.c b/src/bz-search-index-writer.c
new file mode 100644
index 000000000..f6ddc3005
--- /dev/null
+++ b/src/bz-search-index-writer.c
@@ -0,0 +1,162 @@
+/* bz-search-index-writer.c
+ *
+ * Copyright 2026 Alexander Vanhee
+ *
+ * This program 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 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "config.h"
+
+#define G_LOG_DOMAIN "BAZAAR::SEARCH-INDEX-WRITER"
+#define BAZAAR_MODULE "search-index-writer"
+
+#include "bz-search-index-writer.h"
+#include "bz-entry-group.h"
+
+#define INDEX_MAGIC "BZSI"
+#define INDEX_VERSION 1
+#define DESCRIPTION_MAX_LEN 200
+
+static gboolean write_u32 (GOutputStream *out, guint32 value, GError **error);
+static gboolean write_string (GOutputStream *out, const char *str, gsize max_len, GError **error);
+static gboolean entry_group_is_eligible (BzEntryGroup *group);
+static const char *entry_group_icon_path (BzEntryGroup *group);
+
+gboolean
+bz_write_search_index (GListModel *groups,
+ const char *out_path,
+ GError **error)
+{
+ g_autofree char *tmp_path = NULL;
+ g_autoptr (GFile) tmp_file = NULL;
+ g_autoptr (GFile) final_file = NULL;
+ g_autoptr (GOutputStream) out = NULL;
+ guint n_groups = 0;
+ guint32 count = 0;
+ gboolean result = FALSE;
+
+ g_return_val_if_fail (G_IS_LIST_MODEL (groups), FALSE);
+ g_return_val_if_fail (out_path != NULL, FALSE);
+
+ tmp_path = g_strdup_printf ("%s.tmp", out_path);
+ tmp_file = g_file_new_for_path (tmp_path);
+
+ out = G_OUTPUT_STREAM (g_file_replace (
+ tmp_file, NULL, FALSE,
+ G_FILE_CREATE_REPLACE_DESTINATION, NULL, error));
+ if (out == NULL)
+ return FALSE;
+
+ if (!g_output_stream_write_all (out, INDEX_MAGIC, 4, NULL, NULL, error))
+ return FALSE;
+ if (!write_u32 (out, INDEX_VERSION, error))
+ return FALSE;
+
+ n_groups = g_list_model_get_n_items (groups);
+ for (guint i = 0; i < n_groups; i++)
+ {
+ g_autoptr (BzEntryGroup) group = g_list_model_get_item (groups, i);
+ if (entry_group_is_eligible (group))
+ count++;
+ }
+
+ if (!write_u32 (out, count, error))
+ return FALSE;
+
+ for (guint i = 0; i < n_groups; i++)
+ {
+ g_autoptr (BzEntryGroup) group = g_list_model_get_item (groups, i);
+ const char *icon_path = NULL;
+
+ if (!entry_group_is_eligible (group))
+ continue;
+
+ icon_path = entry_group_icon_path (group);
+
+ if (!write_string (out, bz_entry_group_get_id (group), 0, error) ||
+ !write_string (out, bz_entry_group_get_title (group), 0, error) ||
+ !write_string (out, bz_entry_group_get_developer (group), 0, error) ||
+ !write_string (out, bz_entry_group_get_description (group), DESCRIPTION_MAX_LEN, error) ||
+ !write_string (out, bz_entry_group_get_search_tokens (group), 0, error) ||
+ !write_string (out, icon_path, 0, error))
+ return FALSE;
+ }
+
+ if (!g_output_stream_close (out, NULL, error))
+ return FALSE;
+
+ final_file = g_file_new_for_path (out_path);
+ result = g_file_move (
+ tmp_file, final_file,
+ G_FILE_COPY_OVERWRITE,
+ NULL, NULL, NULL, error);
+
+ return result;
+}
+
+static gboolean
+write_u32 (GOutputStream *out,
+ guint32 value,
+ GError **error)
+{
+ guint32 le = GUINT32_TO_LE (value);
+ return g_output_stream_write_all (out, &le, sizeof (le), NULL, NULL, error);
+}
+
+static gboolean
+write_string (GOutputStream *out,
+ const char *str,
+ gsize max_len,
+ GError **error)
+{
+ gsize len = 0;
+
+ if (str != NULL)
+ {
+ len = strlen (str);
+ if (max_len > 0 && len > max_len)
+ len = max_len;
+ }
+
+ if (!write_u32 (out, (guint32) len, error))
+ return FALSE;
+
+ if (len > 0)
+ return g_output_stream_write_all (out, str, len, NULL, NULL, error);
+
+ return TRUE;
+}
+
+static gboolean
+entry_group_is_eligible (BzEntryGroup *group)
+{
+ return bz_entry_group_is_searchable (group) &&
+ !bz_entry_group_is_addon (group) &&
+ bz_entry_group_get_removable (group) == 0 &&
+ bz_entry_group_get_eol (group) == NULL;
+}
+
+static const char *
+entry_group_icon_path (BzEntryGroup *group)
+{
+ GIcon *icon = NULL;
+
+ icon = bz_entry_group_get_mini_icon (group);
+ if (icon == NULL || !G_IS_FILE_ICON (icon))
+ return NULL;
+
+ return g_file_peek_path (g_file_icon_get_file (G_FILE_ICON (icon)));
+}
diff --git a/src/bz-search-index-writer.h b/src/bz-search-index-writer.h
new file mode 100644
index 000000000..0ebcae911
--- /dev/null
+++ b/src/bz-search-index-writer.h
@@ -0,0 +1,50 @@
+/* bz-search-index-writer.h
+ *
+ * Copyright 2026 Alexander Vanhee
+ *
+ * This program 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 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include
+
+G_BEGIN_DECLS
+
+/*
+ * HEADER:
+ * char[4] "BZSI"
+ * uint32 version
+ * uint32 entry count
+ *
+ * CONTENT:
+ * id
+ * title
+ * developer
+ * description (cut off)
+ * search_tokens
+ * icon_path
+ *
+ * with strings as uint32 length + uint8[] bytes
+ *
+ */
+
+gboolean
+bz_write_search_index (GListModel *groups,
+ const char *out_path,
+ GError **error);
+
+G_END_DECLS
diff --git a/src/meson.build b/src/meson.build
index 2c670b379..e4bbea9e6 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -17,6 +17,7 @@ libsecret_dep = dependency('libsecret-1', version: '>= 0.20')
libproxy_dep = dependency('libproxy-1.0', version: '>= 0.5')
malcontent_dep = dependency('malcontent-0', version: '>= 0.12.0')
gtksourceview_dep = dependency('gtksourceview-5', version: '>= 5.17')
+libsystemd_dep = dependency('libsystemd', version: '>= 245')
dl_worker_sources = [
@@ -39,19 +40,22 @@ dl_worker_exe = executable(dl_worker_bin_name, dl_worker_sources,
)
+daemon_sources = [
+ 'bazaar-daemon.c',
+ 'search-index.c',
+]
+
+daemon_exe = executable(daemon_bin_name, daemon_sources,
+ dependencies: [libsystemd_dep],
+ install: true,
+)
+
marshalers = gnome.genmarshal('bz-marshalers',
sources: 'bz-marshalers.list',
prefix: 'bz_marshal',
valist_marshallers: true,
)
-gdbus_src = gnome.gdbus_codegen(
- 'gs-shell-search-provider-generated',
- 'shell-search-provider-dbus-interfaces.xml',
- interface_prefix : 'org.gnome.',
- namespace : 'Bz',
-)
-
bz_sources = files(
'bz-addon-tile.c',
'bz-addons-dialog.c',
@@ -108,7 +112,6 @@ bz_sources = files(
'bz-flatpak-entry.c',
'bz-flatpak-instance.c',
'bz-full-view.c',
- 'bz-gnome-shell-search-provider.c',
'bz-group-tile-css-watcher.c',
'bz-hardware-support-dialog.c',
'bz-inspector.c',
@@ -138,6 +141,7 @@ bz_sources = files(
'bz-search-bar.c',
'bz-search-engine.c',
'bz-search-filter-popover.c',
+ 'bz-search-index-writer.c',
'bz-search-page.c',
'bz-search-pill-list.c',
'bz-section-view.c',
@@ -376,7 +380,7 @@ bz_sources += gnome.compile_resources('bz-resources',
dependencies: [blueprints, release_notes, countries_gvariant],
)
-executable(bazaar_bin_name, bz_sources + ['main.c'], gdbus_src, marshalers,
+executable(bazaar_bin_name, bz_sources + ['main.c'], marshalers,
dependencies: bz_deps,
install: true,
)
diff --git a/src/search-index.c b/src/search-index.c
new file mode 100644
index 000000000..88164cce6
--- /dev/null
+++ b/src/search-index.c
@@ -0,0 +1,336 @@
+/* search-index.c
+ *
+ * Copyright 2026 Alexander Vanhee
+ *
+ * This program 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 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "config.h"
+
+#include "search-index.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#define INDEX_MAGIC "BZSI"
+
+static int read_u32 (FILE *f, unsigned int *out);
+static char *read_field (FILE *f);
+static void free_entries (SearchIndexEntry *entries, unsigned int count);
+static double score_field (const char *term, const char *field, double weight);
+static double score_entry (const SearchIndexEntry *e, const char *const *terms, int n_terms);
+static int cmp_matches (const void *a, const void *b);
+
+SearchIndex *
+search_index_open (const char *path)
+{
+ FILE *f = NULL;
+ char magic[4] = { 0 };
+ unsigned int version = 0;
+ unsigned int count = 0;
+ SearchIndexEntry *entries = NULL;
+ SearchIndex *idx = NULL;
+ struct stat st = { 0 };
+ unsigned int i = 0;
+
+ f = fopen (path, "rb");
+ if (f == NULL)
+ return NULL;
+
+ if (fread (magic, 1, 4, f) != 4 || memcmp (magic, INDEX_MAGIC, 4) != 0)
+ {
+ fclose (f);
+ return NULL;
+ }
+
+ if (read_u32 (f, &version) < 0 || read_u32 (f, &count) < 0)
+ {
+ fclose (f);
+ return NULL;
+ }
+
+ entries = calloc (count, sizeof (SearchIndexEntry));
+ if (entries == NULL)
+ {
+ fclose (f);
+ return NULL;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ entries[i].id = read_field (f);
+ entries[i].title = read_field (f);
+ entries[i].developer = read_field (f);
+ entries[i].description = read_field (f);
+ entries[i].search_tokens = read_field (f);
+ entries[i].icon_path = read_field (f);
+
+ if (entries[i].id == NULL || entries[i].title == NULL)
+ {
+ free_entries (entries, count);
+ fclose (f);
+ return NULL;
+ }
+ }
+
+ fclose (f);
+
+ idx = calloc (1, sizeof (SearchIndex));
+ if (idx == NULL)
+ {
+ free_entries (entries, count);
+ return NULL;
+ }
+
+ idx->path = strdup (path);
+ idx->entries = entries;
+ idx->count = count;
+
+ if (stat (path, &st) == 0)
+ idx->mtime = st.st_mtime;
+
+ return idx;
+}
+
+void
+search_index_close (SearchIndex *idx)
+{
+ if (idx == NULL)
+ return;
+
+ free_entries (idx->entries, idx->count);
+ free (idx->path);
+ free (idx);
+}
+
+int
+search_index_reload_if_stale (SearchIndex **idx_ptr)
+{
+ struct stat st = { 0 };
+ SearchIndex *idx = NULL;
+ SearchIndex *fresh = NULL;
+
+ idx = *idx_ptr;
+
+ if (idx == NULL)
+ return 0;
+
+ if (stat (idx->path, &st) != 0)
+ return 0;
+
+ if (st.st_mtime == idx->mtime)
+ return 0;
+
+ fresh = search_index_open (idx->path);
+ if (fresh == NULL)
+ return 0;
+
+ search_index_close (idx);
+ *idx_ptr = fresh;
+ return 1;
+}
+
+size_t
+search_index_query (SearchIndex *idx,
+ const char *const *terms,
+ int n_terms,
+ SearchIndexMatch *out,
+ size_t max_results)
+{
+ size_t n_matches = 0;
+ unsigned int i = 0;
+ double score = 0.0;
+
+ if (idx == NULL || n_terms <= 0)
+ return 0;
+
+ for (i = 0; i < idx->count && n_matches < max_results * 8; i++)
+ {
+ score = score_entry (&idx->entries[i], terms, n_terms);
+
+ if (score > 0.0 && n_matches < max_results * 8)
+ {
+ if (n_matches < max_results)
+ {
+ out[n_matches].entry = &idx->entries[i];
+ out[n_matches].score = score;
+ }
+ n_matches++;
+ }
+ }
+
+ if (n_matches > max_results)
+ n_matches = max_results;
+
+ qsort (out, n_matches, sizeof (SearchIndexMatch), cmp_matches);
+
+ return n_matches;
+}
+
+const SearchIndexEntry *
+search_index_find (SearchIndex *idx,
+ const char *id)
+{
+ unsigned int i = 0;
+
+ if (idx == NULL || id == NULL)
+ return NULL;
+
+ for (i = 0; i < idx->count; i++)
+ {
+ if (strcmp (idx->entries[i].id, id) == 0)
+ return &idx->entries[i];
+ }
+
+ return NULL;
+}
+
+static int
+read_u32 (FILE *f,
+ unsigned int *out)
+{
+ unsigned char b[4] = { 0 };
+
+ if (fread (b, 1, 4, f) != 4)
+ return -1;
+
+ *out = (unsigned int) b[0] |
+ ((unsigned int) b[1] << 8) |
+ ((unsigned int) b[2] << 16) |
+ ((unsigned int) b[3] << 24);
+ return 0;
+}
+
+static char *
+read_field (FILE *f)
+{
+ unsigned int len = 0;
+ char *str = NULL;
+
+ if (read_u32 (f, &len) < 0)
+ return NULL;
+
+ if (len == 0)
+ return NULL;
+
+ str = malloc (len + 1);
+ if (str == NULL)
+ return NULL;
+
+ if (fread (str, 1, len, f) != len)
+ {
+ free (str);
+ return NULL;
+ }
+
+ str[len] = '\0';
+ return str;
+}
+
+static void
+free_entries (SearchIndexEntry *entries,
+ unsigned int count)
+{
+ unsigned int i = 0;
+
+ if (entries == NULL)
+ return;
+
+ for (i = 0; i < count; i++)
+ {
+ free (entries[i].id);
+ free (entries[i].title);
+ free (entries[i].developer);
+ free (entries[i].description);
+ free (entries[i].search_tokens);
+ free (entries[i].icon_path);
+ }
+
+ free (entries);
+}
+
+static double
+score_field (const char *term,
+ const char *field,
+ double weight)
+{
+ const char *hit = NULL;
+ size_t term_len = 0;
+ size_t field_len = 0;
+
+ if (field == NULL || term == NULL || *term == '\0')
+ return 0.0;
+
+ hit = strcasestr (field, term);
+ if (hit == NULL)
+ return 0.0;
+
+ term_len = strlen (term);
+ field_len = strlen (field);
+ if (field_len == 0)
+ return 0.0;
+
+ return weight * ((double) (term_len * term_len) / (double) field_len);
+}
+
+static double
+score_entry (const SearchIndexEntry *e,
+ const char *const *terms,
+ int n_terms)
+{
+ double total = 0.0;
+ int i = 0;
+ const char *term = NULL;
+ double term_score = 0.0;
+
+ for (i = 0; i < n_terms; i++)
+ {
+ term = terms[i];
+ term_score = 0.0;
+
+ if (term == NULL || *term == '\0')
+ continue;
+
+ term_score += score_field (term, e->title, 2.0);
+ term_score += score_field (term, e->developer, 1.0);
+ term_score += score_field (term, e->description, 1.0);
+ term_score += score_field (term, e->search_tokens, 1.5);
+
+ if (term_score <= 0.0)
+ return 0.0;
+
+ total += term_score;
+ }
+
+ return total;
+}
+
+static int
+cmp_matches (const void *a,
+ const void *b)
+{
+ const SearchIndexMatch *ma = a;
+ const SearchIndexMatch *mb = b;
+
+ if (mb->score > ma->score)
+ return 1;
+ if (mb->score < ma->score)
+ return -1;
+ return 0;
+}
diff --git a/src/search-index.h b/src/search-index.h
new file mode 100644
index 000000000..8b1295bd1
--- /dev/null
+++ b/src/search-index.h
@@ -0,0 +1,67 @@
+/* search-index.h
+ *
+ * Copyright 2026 Alexander Vanhee
+ *
+ * This program 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 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include
+#include
+
+typedef struct
+{
+ char *id;
+ char *title;
+ char *developer;
+ char *description;
+ char *search_tokens;
+ char *icon_path;
+} SearchIndexEntry;
+
+typedef struct
+{
+ char *path;
+ time_t mtime;
+ SearchIndexEntry *entries;
+ unsigned int count;
+} SearchIndex;
+
+typedef struct
+{
+ const SearchIndexEntry *entry;
+ double score;
+} SearchIndexMatch;
+
+SearchIndex *
+search_index_open (const char *path);
+
+void
+search_index_close (SearchIndex *idx);
+
+int
+search_index_reload_if_stale (SearchIndex **idx);
+
+size_t
+search_index_query (SearchIndex *idx,
+ const char *const *terms,
+ int n_terms,
+ SearchIndexMatch *out,
+ size_t max_results);
+
+const SearchIndexEntry *
+search_index_find (SearchIndex *idx, const char *id);
From 7969393e5e49d2456df80704efffc485f6463d2c Mon Sep 17 00:00:00 2001
From: Alexander Vanhee <160625516+AlexanderVanhee@users.noreply.github.com>
Date: Sat, 11 Jul 2026 21:55:38 +0200
Subject: [PATCH 2/3] Switch to Gio.DataOutputStream
---
src/bz-search-index-writer.c | 56 ++++++++++++++++--------------------
1 file changed, 25 insertions(+), 31 deletions(-)
diff --git a/src/bz-search-index-writer.c b/src/bz-search-index-writer.c
index f6ddc3005..f1eb466c2 100644
--- a/src/bz-search-index-writer.c
+++ b/src/bz-search-index-writer.c
@@ -23,15 +23,14 @@
#define G_LOG_DOMAIN "BAZAAR::SEARCH-INDEX-WRITER"
#define BAZAAR_MODULE "search-index-writer"
-#include "bz-search-index-writer.h"
#include "bz-entry-group.h"
+#include "bz-search-index-writer.h"
#define INDEX_MAGIC "BZSI"
#define INDEX_VERSION 1
#define DESCRIPTION_MAX_LEN 200
-static gboolean write_u32 (GOutputStream *out, guint32 value, GError **error);
-static gboolean write_string (GOutputStream *out, const char *str, gsize max_len, GError **error);
+static gboolean write_string (GDataOutputStream *out, const char *str, gsize max_len, GError **error);
static gboolean entry_group_is_eligible (BzEntryGroup *group);
static const char *entry_group_icon_path (BzEntryGroup *group);
@@ -40,13 +39,14 @@ bz_write_search_index (GListModel *groups,
const char *out_path,
GError **error)
{
- g_autofree char *tmp_path = NULL;
- g_autoptr (GFile) tmp_file = NULL;
- g_autoptr (GFile) final_file = NULL;
- g_autoptr (GOutputStream) out = NULL;
- guint n_groups = 0;
- guint32 count = 0;
- gboolean result = FALSE;
+ g_autofree char *tmp_path = NULL;
+ g_autoptr (GFile) tmp_file = NULL;
+ g_autoptr (GFile) final_file = NULL;
+ g_autoptr (GOutputStream) base_out = NULL;
+ g_autoptr (GDataOutputStream) out = NULL;
+ guint n_groups = 0;
+ guint32 count = 0;
+ gboolean result = FALSE;
g_return_val_if_fail (G_IS_LIST_MODEL (groups), FALSE);
g_return_val_if_fail (out_path != NULL, FALSE);
@@ -54,15 +54,18 @@ bz_write_search_index (GListModel *groups,
tmp_path = g_strdup_printf ("%s.tmp", out_path);
tmp_file = g_file_new_for_path (tmp_path);
- out = G_OUTPUT_STREAM (g_file_replace (
+ base_out = G_OUTPUT_STREAM (g_file_replace (
tmp_file, NULL, FALSE,
G_FILE_CREATE_REPLACE_DESTINATION, NULL, error));
- if (out == NULL)
+ if (base_out == NULL)
return FALSE;
- if (!g_output_stream_write_all (out, INDEX_MAGIC, 4, NULL, NULL, error))
+ out = g_data_output_stream_new (base_out);
+ g_data_output_stream_set_byte_order (out, G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN);
+
+ if (!g_output_stream_write_all (G_OUTPUT_STREAM (out), INDEX_MAGIC, 4, NULL, NULL, error))
return FALSE;
- if (!write_u32 (out, INDEX_VERSION, error))
+ if (!g_data_output_stream_put_uint32 (out, INDEX_VERSION, NULL, error))
return FALSE;
n_groups = g_list_model_get_n_items (groups);
@@ -73,7 +76,7 @@ bz_write_search_index (GListModel *groups,
count++;
}
- if (!write_u32 (out, count, error))
+ if (!g_data_output_stream_put_uint32 (out, count, NULL, error))
return FALSE;
for (guint i = 0; i < n_groups; i++)
@@ -95,7 +98,7 @@ bz_write_search_index (GListModel *groups,
return FALSE;
}
- if (!g_output_stream_close (out, NULL, error))
+ if (!g_output_stream_close (G_OUTPUT_STREAM (out), NULL, error))
return FALSE;
final_file = g_file_new_for_path (out_path);
@@ -108,19 +111,10 @@ bz_write_search_index (GListModel *groups,
}
static gboolean
-write_u32 (GOutputStream *out,
- guint32 value,
- GError **error)
-{
- guint32 le = GUINT32_TO_LE (value);
- return g_output_stream_write_all (out, &le, sizeof (le), NULL, NULL, error);
-}
-
-static gboolean
-write_string (GOutputStream *out,
- const char *str,
- gsize max_len,
- GError **error)
+write_string (GDataOutputStream *out,
+ const char *str,
+ gsize max_len,
+ GError **error)
{
gsize len = 0;
@@ -131,11 +125,11 @@ write_string (GOutputStream *out,
len = max_len;
}
- if (!write_u32 (out, (guint32) len, error))
+ if (!g_data_output_stream_put_uint32 (out, (guint32) len, NULL, error))
return FALSE;
if (len > 0)
- return g_output_stream_write_all (out, str, len, NULL, NULL, error);
+ return g_output_stream_write_all (G_OUTPUT_STREAM (out), str, len, NULL, NULL, error);
return TRUE;
}
From 2bcc8645927d0bf882eb5379eb04abeb53b70ef1 Mon Sep 17 00:00:00 2001
From: Alexander Vanhee <160625516+AlexanderVanhee@users.noreply.github.com>
Date: Sat, 11 Jul 2026 22:17:46 +0200
Subject: [PATCH 3/3] Rename search index write
---
src/bz-application.c | 2 +-
src/meson.build | 2 +-
src/{bz-search-index-writer.c => search-index-write.c} | 6 +++---
src/{bz-search-index-writer.h => search-index-write.h} | 2 +-
4 files changed, 6 insertions(+), 6 deletions(-)
rename src/{bz-search-index-writer.c => search-index-write.c} (97%)
rename src/{bz-search-index-writer.h => search-index-write.h} (97%)
diff --git a/src/bz-application.c b/src/bz-application.c
index 0fd909da2..e6adcd41b 100644
--- a/src/bz-application.c
+++ b/src/bz-application.c
@@ -59,7 +59,7 @@
#include "bz-root-blocklist.h"
#include "bz-root-curated-config.h"
#include "bz-serializable.h"
-#include "bz-search-index-writer.h"
+#include "search-index-write.h"
#include "bz-state-info.h"
#include "bz-transaction-manager.h"
#include "bz-window.h"
diff --git a/src/meson.build b/src/meson.build
index e4bbea9e6..a0458114c 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -141,7 +141,6 @@ bz_sources = files(
'bz-search-bar.c',
'bz-search-engine.c',
'bz-search-filter-popover.c',
- 'bz-search-index-writer.c',
'bz-search-page.c',
'bz-search-pill-list.c',
'bz-section-view.c',
@@ -172,6 +171,7 @@ bz_sources = files(
'io.c',
'refresh-worker.c',
'safety-calculator.c',
+ 'search-index-write.c',
'spdx.c',
'template-callbacks.c',
)
diff --git a/src/bz-search-index-writer.c b/src/search-index-write.c
similarity index 97%
rename from src/bz-search-index-writer.c
rename to src/search-index-write.c
index f1eb466c2..c365ea8f5 100644
--- a/src/bz-search-index-writer.c
+++ b/src/search-index-write.c
@@ -1,4 +1,4 @@
-/* bz-search-index-writer.c
+/* search-index-write.c
*
* Copyright 2026 Alexander Vanhee
*
@@ -20,11 +20,11 @@
#include "config.h"
-#define G_LOG_DOMAIN "BAZAAR::SEARCH-INDEX-WRITER"
+#define G_LOG_DOMAIN "BAZAAR::SEARCH-INDEX-WRITE"
#define BAZAAR_MODULE "search-index-writer"
#include "bz-entry-group.h"
-#include "bz-search-index-writer.h"
+#include "search-index-write.h"
#define INDEX_MAGIC "BZSI"
#define INDEX_VERSION 1
diff --git a/src/bz-search-index-writer.h b/src/search-index-write.h
similarity index 97%
rename from src/bz-search-index-writer.h
rename to src/search-index-write.h
index 0ebcae911..9e7883224 100644
--- a/src/bz-search-index-writer.h
+++ b/src/search-index-write.h
@@ -1,4 +1,4 @@
-/* bz-search-index-writer.h
+/* search-index-write.h
*
* Copyright 2026 Alexander Vanhee
*