--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "bookmarks.h"
+#include "application.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <cx/array_list.h>
+#include <cx/properties.h>
+#include <libidav/utils.h>
+
+static CxList *bookmarks;
+
+void bookmarks_init(void) {
+ bookmarks = cxArrayListCreateSimple(sizeof(MZBookmark), 8);
+
+ bookmarks_import_xdg_user_dirs(bookmarks, NULL);
+}
+
+void bookmarks_import_xdg_user_dirs(CxList *list, const char *optional_path) {
+ char *path = NULL;
+ if(!optional_path) {
+ char *home = getenv("HOME");
+ path = util_concat_path(home, ".config/user-dirs.dirs");
+ optional_path = path;
+ }
+
+ int fd = open(optional_path, O_RDONLY);
+ free(path);
+ if(fd == -1) {
+ return;
+ }
+
+ // we can parse the xdg user-dirs.dirs file with CxProperties
+ // format:
+ // key="value"
+ CxProperties parser;
+ cxPropertiesInit(&parser, cx_properties_config_default);
+
+ char buf[2048];
+ ssize_t r;
+ int i = 0;
+ while((r = read(fd, buf, 2048)) > 0) {
+ cxPropertiesFilln(&parser, buf, r);
+ cxstring key;
+ cxstring value;
+ CxPropertiesStatus status;
+ while((status=cxPropertiesNext(&parser, &key, &value)) == CX_PROPERTIES_NO_ERROR) {
+ // remove string quotes from value
+ if(value.length >= 2 && value.ptr[0] == '"' && value.ptr[value.length-1] == '"') {
+ value.ptr++;
+ value.length-=2;
+ }
+
+ cxmutstr bookmark_path;
+ if(cx_strprefix(value, CX_STR("$HOME/"))) {
+ bookmark_path = cx_strcat(2, cx_str(getenv("HOME")), cx_strsubs(value, 5));
+ } else {
+ bookmark_path = cx_strdup(value);
+ }
+
+ const char *icon = "folder-symbolic";
+ if(!cx_strcmp(key, CX_STR("XDG_DOWNLOAD_DIR"))) {
+ icon = "folder-download-symbolic";
+ } else if(!cx_strcmp(key, CX_STR("XDG_DOCUMENTS_DIR"))) {
+ icon = "folder-documents-symbolic";
+ } else if(!cx_strcmp(key, CX_STR("XDG_MUSIC_DIR"))) {
+ icon = "folder-music-symbolic";
+ } else if(!cx_strcmp(key, CX_STR("XDG_PICTURES_DIR"))) {
+ icon = "folder-pictures-symbolic";
+ } else if(!cx_strcmp(key, CX_STR("XDG_VIDEOS_DIR"))) {
+ icon = "folder-videos-symbolic";
+ } else if(!cx_strcmp(key, CX_STR("XDG_PUBLICSHARE_DIR"))) {
+ icon = "folder-publicshare-symbolic";
+ } else if(!cx_strcmp(key, CX_STR("XDG_DESKTOP_DIR"))) {
+ icon = "user-desktop-symbolic";
+ }
+
+ MZBookmark bookmark;
+ bookmark.icon = icon;
+ bookmark.name = util_resource_name(bookmark_path.ptr);
+ bookmark.path = bookmark_path.ptr;
+ bookmark.sort = i++;
+
+ cxListAdd(list, &bookmark);
+ }
+ if(status > CX_PROPERTIES_OK) {
+ break;
+ }
+ }
+ close(fd);
+}
+
+void bookmarks_init_windowdata(UiList *list) {
+ CxIterator i = cxListIterator(bookmarks);
+ cx_foreach(MZBookmark *, bookmark, i) {
+ ui_list_append(list, bookmark);
+ }
+}
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MZ_BOOKMARKS_H
+#define MZ_BOOKMARKS_H
+
+#include <ui/ui.h>
+#include <cx/list.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct MZBookmark {
+ const char *icon;
+ const char *name;
+ char *path;
+ int sort;
+} MZBookmark;
+
+void bookmarks_init(void);
+
+void bookmarks_import_xdg_user_dirs(CxList *list, const char *optional_path);
+
+void bookmarks_init_windowdata(UiList *list);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MZ_BOOKMARKS_H */
+