=> 3190f16e20bfe03d83cead40d4dc220d619ec924
[1mdiff --git a/CMakeLists.txt b/CMakeLists.txt[m [1mindex a3687e9c..095a279f 100644[m [1m--- a/CMakeLists.txt[m [1m+++ b/CMakeLists.txt[m [36m@@ -31,6 +31,7 @@[m [moption (ENABLE_KERNING "Enable kerning in font renderer (slower)" ON)[m option (ENABLE_RESOURCE_EMBED "Embed resources inside the executable" OFF)[m option (ENABLE_WINDOWPOS_FIX "Set position after showing window (workaround for SDL bug)" OFF)[m option (ENABLE_IDLE_SLEEP "While idle, sleep in the main thread instead of waiting for events" ON)[m [32m+[m[32moption (ENABLE_DOWNLOAD_EDIT "Allow changing the Downloads directory" ON)[m [m include (BuildType.cmake)[m include (res/Embed.cmake)[m [36m@@ -226,6 +227,9 @@[m [mendif ()[m if (ENABLE_IDLE_SLEEP)[m target_compile_definitions (app PUBLIC LAGRANGE_IDLE_SLEEP=1)[m endif ()[m [32m+[m[32mif (ENABLE_DOWNLOAD_EDIT)[m [32m+[m[32m target_compile_definitions (app PUBLIC LAGRANGE_DOWNLOAD_EDIT=1)[m [32m+[m[32mendif ()[m target_link_libraries (app PUBLIC the_Foundation::the_Foundation)[m target_link_libraries (app PUBLIC ${SDL2_LDFLAGS})[m if (APPLE)[m [1mdiff --git a/src/app.c b/src/app.c[m [1mindex 10e6d4ee..195b3b43 100644[m [1m--- a/src/app.c[m [1m+++ b/src/app.c[m [36m@@ -83,17 +83,17 @@[m [mstatic const char *dataDir_App_ = "~/AppData/Roaming/fi.skyjake.Lagrange";[m #endif[m #if defined (iPlatformLinux) || defined (iPlatformOther)[m #define EMB_BIN "../../share/lagrange/resources.lgr"[m [31m-static const char *dataDir_App_ = "~/.config/lagrange";[m [32m+[m[32mstatic const char *defaultDataDir_App_ = "~/.config/lagrange";[m #endif[m #if defined (LAGRANGE_EMB_BIN) /* specified in build config */[m # undef EMB_BIN[m # define EMB_BIN LAGRANGE_EMB_BIN[m #endif[m #define EMB_BIN2 "../resources.lgr" /* fallback from build/executable dir */[m [31m-static const char *prefsFileName_App_ = "prefs.cfg";[m [31m-static const char *oldStateFileName_App_ = "state.binary";[m [31m-static const char *stateFileName_App_ = "state.lgr";[m [31m-static const char *downloadDir_App_ = "~/Downloads";[m [32m+[m[32mstatic const char *prefsFileName_App_ = "prefs.cfg";[m [32m+[m[32mstatic const char *oldStateFileName_App_ = "state.binary";[m [32m+[m[32mstatic const char *stateFileName_App_ = "state.lgr";[m [32m+[m[32mstatic const char *defaultDownloadDir_App_ = "~/Downloads";[m [m static const int idleThreshold_App_ = 1000; /* ms */[m [m [36m@@ -213,14 +213,42 @@[m [mstatic iString *serializePrefs_App_(const iApp *d) {[m return str;[m }[m [m [32m+[m[32mstatic const char *dataDir_App_(void) {[m [32m+[m[32m#if defined (iPlatformLinux) || defined (iPlatformOther)[m [32m+[m[32m const char *configHome = getenv("XDG_CONFIG_HOME");[m [32m+[m[32m if (configHome) {[m [32m+[m[32m return concatPath_CStr(configHome, "lagrange");[m [32m+[m[32m }[m [32m+[m[32m#endif[m [32m+[m[32m return defaultDataDir_App_;[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic const char *downloadDir_App_(void) {[m [32m+[m[32m#if defined (iPlatformLinux) || defined (iPlatformOther)[m [32m+[m[32m /* Parse user-dirs.dirs using the `xdg-user-dir` tool. */[m [32m+[m[32m iProcess *proc = iClob(new_Process());[m [32m+[m[32m setArguments_Process([m [32m+[m[32m proc, iClob(newStringsCStr_StringList("/usr/bin/env", "xdg-user-dir", "DOWNLOAD", NULL)));[m [32m+[m[32m if (start_Process(proc)) {[m [32m+[m[32m iString *path = collect_String(newLocal_String(collect_Block([m [32m+[m[32m readOutputUntilClosed_Process(proc))));[m [32m+[m[32m trim_String(path);[m [32m+[m[32m if (!isEmpty_String(path)) {[m [32m+[m[32m return cstr_String(path);[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m#endif[m [32m+[m[32m return defaultDownloadDir_App_;[m [32m+[m[32m}[m [32m+[m static const iString *prefsFileName_(void) {[m [31m- return collect_String(concatCStr_Path(&iStringLiteral(dataDir_App_), prefsFileName_App_));[m [32m+[m[32m return collectNewCStr_String(concatPath_CStr(dataDir_App_(), prefsFileName_App_));[m }[m [m static void loadPrefs_App_(iApp *d) {[m iUnused(d);[m /* Create the data dir if it doesn't exist yet. */[m [31m- makeDirs_Path(collectNewCStr_String(dataDir_App_));[m [32m+[m[32m makeDirs_Path(collectNewCStr_String(dataDir_App_()));[m iFile *f = new_File(prefsFileName_());[m if (open_File(f, readOnly_FileMode | text_FileMode)) {[m iString *str = readString_File(f);[m [36m@@ -267,8 +295,8 @@[m [mstatic const char *magicTabDocument_App_ = "tabd";[m [m static iBool loadState_App_(iApp *d) {[m iUnused(d);[m [31m- const char *oldPath = concatPath_CStr(dataDir_App_, oldStateFileName_App_);[m [31m- const char *path = concatPath_CStr(dataDir_App_, stateFileName_App_);[m [32m+[m[32m const char *oldPath = concatPath_CStr(dataDir_App_(), oldStateFileName_App_);[m [32m+[m[32m const char *path = concatPath_CStr(dataDir_App_(), stateFileName_App_);[m iFile *f = iClob(newCStr_File(fileExistsCStr_FileInfo(path) ? path : oldPath));[m if (open_File(f, readOnly_FileMode)) {[m char magic[4];[m [36m@@ -323,7 +351,7 @@[m [miObjectList *listDocuments_App(void) {[m static void saveState_App_(const iApp *d) {[m iUnused(d);[m trimCache_App();[m [31m- iFile *f = newCStr_File(concatPath_CStr(dataDir_App_, stateFileName_App_));[m [32m+[m[32m iFile *f = newCStr_File(concatPath_CStr(dataDir_App_(), stateFileName_App_));[m if (open_File(f, writeOnly_FileMode)) {[m writeData_File(f, magicState_App_, 4);[m writeU32_File(f, latest_FileVersion); /* version */[m [36m@@ -348,7 +376,7 @@[m [mstatic uint32_t checkAsleep_App_(uint32_t interval, void *param) {[m #endif[m [m static void init_App_(iApp *d, int argc, char **argv) {[m [31m- const iBool isFirstRun = !fileExistsCStr_FileInfo(cleanedPath_CStr(dataDir_App_));[m [32m+[m[32m const iBool isFirstRun = !fileExistsCStr_FileInfo(cleanedPath_CStr(dataDir_App_()));[m d->isFinishedLaunching = iFalse;[m d->launchCommands = new_StringList();[m iZap(d->lastDropTime);[m [36m@@ -385,12 +413,12 @@[m [mstatic void init_App_(iApp *d, int argc, char **argv) {[m }[m #endif[m init_Prefs(&d->prefs);[m [31m- setCStr_String(&d->prefs.downloadDir, downloadDir_App_);[m [32m+[m[32m setCStr_String(&d->prefs.downloadDir, downloadDir_App_());[m d->isRunning = iFalse;[m d->window = NULL;[m set_Atomic(&d->pendingRefresh, iFalse);[m d->mimehooks = new_MimeHooks();[m [31m- d->certs = new_GmCerts(dataDir_App_);[m [32m+[m[32m d->certs = new_GmCerts(dataDir_App_());[m d->visited = new_Visited();[m d->bookmarks = new_Bookmarks();[m d->tabEnum = 0; /* generates unique IDs for tab pages */[m [36m@@ -405,10 +433,10 @@[m [mstatic void init_App_(iApp *d, int argc, char **argv) {[m #endif[m init_Keys();[m loadPrefs_App_(d);[m [31m- load_Keys(dataDir_App_);[m [31m- load_Visited(d->visited, dataDir_App_);[m [31m- load_Bookmarks(d->bookmarks, dataDir_App_);[m [31m- load_MimeHooks(d->mimehooks, dataDir_App_);[m [32m+[m[32m load_Keys(dataDir_App_());[m [32m+[m[32m load_Visited(d->visited, dataDir_App_());[m [32m+[m[32m load_Bookmarks(d->bookmarks, dataDir_App_());[m [32m+[m[32m load_MimeHooks(d->mimehooks, dataDir_App_());[m if (isFirstRun) {[m /* Create the default bookmarks for a quick start. */[m add_Bookmarks(d->bookmarks,[m [36m@@ -434,7 +462,7 @@[m [mstatic void init_App_(iApp *d, int argc, char **argv) {[m }[m #endif[m d->window = new_Window(d->initialWindowRect);[m [31m- init_Feeds(dataDir_App_);[m [32m+[m[32m init_Feeds(dataDir_App_());[m /* Widget state init. */[m processEvents_App(postedEventsOnly_AppEventMode);[m if (!loadState_App_(d)) {[m [36m@@ -469,13 +497,13 @@[m [mstatic void init_App_(iApp *d, int argc, char **argv) {[m static void deinit_App(iApp *d) {[m saveState_App_(d);[m deinit_Feeds();[m [31m- save_Keys(dataDir_App_);[m [32m+[m[32m save_Keys(dataDir_App_());[m deinit_Keys();[m savePrefs_App_(d);[m deinit_Prefs(&d->prefs);[m [31m- save_Bookmarks(d->bookmarks, dataDir_App_);[m [32m+[m[32m save_Bookmarks(d->bookmarks, dataDir_App_());[m delete_Bookmarks(d->bookmarks);[m [31m- save_Visited(d->visited, dataDir_App_);[m [32m+[m[32m save_Visited(d->visited, dataDir_App_());[m delete_Visited(d->visited);[m delete_GmCerts(d->certs);[m save_MimeHooks(d->mimehooks);[m [36m@@ -494,7 +522,7 @@[m [mconst iString *execPath_App(void) {[m }[m [m const iString *dataDir_App(void) {[m [31m- return collect_String(cleanedCStr_Path(dataDir_App_));[m [32m+[m[32m return collect_String(cleanedCStr_Path(dataDir_App_()));[m }[m [m const iString *downloadDir_App(void) {[m [36m@@ -854,8 +882,10 @@[m [mstatic iBool handlePrefsCommands_(iWidget *d, const char *cmd) {[m if (equal_Command(cmd, "prefs.dismiss") || equal_Command(cmd, "preferences")) {[m setUiScale_Window(get_Window(),[m toFloat_String(text_InputWidget(findChild_Widget(d, "prefs.uiscale"))));[m [32m+[m[32m#if defined (LAGRANGE_DOWNLOAD_EDIT)[m postCommandf_App("downloads path:%s",[m cstr_String(text_InputWidget(findChild_Widget(d, "prefs.downloads"))));[m [32m+[m[32m#endif[m postCommandf_App("window.retain arg:%d",[m isSelected_Widget(findChild_Widget(d, "prefs.retainwindow")));[m postCommandf_App("smoothscroll arg:%d",[m [36m@@ -1449,7 +1479,7 @@[m [miBool handleCommand_App(const char *cmd) {[m return iTrue;[m }[m else if (equal_Command(cmd, "bookmarks.changed")) {[m [31m- save_Bookmarks(d->bookmarks, dataDir_App_);[m [32m+[m[32m save_Bookmarks(d->bookmarks, dataDir_App_());[m return iFalse;[m }[m else if (equal_Command(cmd, "feeds.refresh")) {[m [36m@@ -1468,7 +1498,7 @@[m [miBool handleCommand_App(const char *cmd) {[m return iFalse;[m }[m else if (equal_Command(cmd, "visited.changed")) {[m [31m- save_Visited(d->visited, dataDir_App_);[m [32m+[m[32m save_Visited(d->visited, dataDir_App_());[m return iFalse;[m }[m else if (equal_Command(cmd, "ident.new")) {[m [1mdiff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c[m [1mindex 3f799e3c..1674040b 100644[m [1m--- a/src/ui/inputwidget.c[m [1m+++ b/src/ui/inputwidget.c[m [36m@@ -223,6 +223,7 @@[m [mstatic void updateBuffered_InputWidget_(iInputWidget *d) {[m }[m [m void setText_InputWidget(iInputWidget *d, const iString *text) {[m [32m+[m[32m if (!d) return;[m if (d->inFlags & isUrl_InputWidgetFlag) {[m /* If user wants URLs encoded, also Punycode the domain. */[m if (!prefs_App()->decodeUserVisibleURLs) {[m [1mdiff --git a/src/ui/util.c b/src/ui/util.c[m [1mindex 4d5ed916..d64a93b6 100644[m [1m--- a/src/ui/util.c[m [1m+++ b/src/ui/util.c[m [36m@@ -1023,6 +1023,7 @@[m [mstatic void makeTwoColumnHeading_(const char *title, iWidget *headings, iWidget[m }[m [m static void expandInputFieldWidth_(iInputWidget *input) {[m [32m+[m[32m if (!input) return;[m iWidget *page = as_Widget(input)->parent->parent->parent->parent; /* tabs > page > values > input */[m as_Widget(input)->rect.size.x =[m right_Rect(bounds_Widget(page)) - left_Rect(bounds_Widget(constAs_Widget(input)));[m [36m@@ -1056,8 +1057,10 @@[m [miWidget *makePreferences_Widget(void) {[m iWidget *headings, *values;[m /* General preferences. */ {[m appendTwoColumnPage_(tabs, "General", '1', &headings, &values);[m [32m+[m[32m#if defined (LAGRANGE_DOWNLOAD_EDIT)[m addChild_Widget(headings, iClob(makeHeading_Widget("Downloads folder:")));[m setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.downloads");[m [32m+[m[32m#endif[m addChild_Widget(headings, iClob(makeHeading_Widget("Show URL on hover:")));[m addChild_Widget(values, iClob(makeToggle_Widget("prefs.hoverlink")));[m addChild_Widget(headings, iClob(makeHeading_Widget("Smooth scrolling:")));[m
text/gemini; charset=utf-8
This content has been proxied by September (ba2dc).