AmendHub

Download:

jcs

/

detritus

/

amendments

/

42

settings: Add bookmark menu editor, saving of prefs file


jcs made amendment 42 about 1 year ago
--- detritus.π.r Fri Nov 15 15:26:43 2024 +++ detritus.π.r Mon Nov 18 21:16:57 2024 @@ -23,22 +23,15 @@ data 'MENU' (131) { data 'MENU' (132) { $"0084 0000 0000 0000 0000 FFFF FFFF 0942" /* .Ñ............∆B */ - $"6F6F 6B6D 6172 6B73 00" /* ookmarks. */ + $"6F6F 6B6D 6172 6B73 1145 6469 7420 426F" /* ookmarks.Edit Bo */ + $"6F6B 6D61 726B 732E 2E2E 0042 0000 00" /* okmarks....B... */ }; data 'MBAR' (128) { $"0005 0080 0081 0082 0083 0084" /* ...Ä.Å.Ç.É.Ñ */ }; -data 'DITL' (130, "ASK") { - $"0003 0000 0000 004E 00FA 0064 0134 0403" /* .......N...d.4.. */ - $"5965 7321 0000 0000 004E 00B4 0064 00EE" /* Yes!.....N.¥.d.. */ - $"0402 4E6F 0000 0000 000D 004E 0041 0136" /* ..No.....¬.N.A.6 */ - $"0802 5E30 0000 0000 000D 0017 002D 0037" /* ..^0.....¬...-.7 */ - $"A002 0001" /* †... */ -}; - -data 'DITL' (128) { +data 'DITL' (128, "input") { $"0003 0000 0000 004B 00D2 005F 0113 0406" /* .......K.“._.... */ $"5375 626D 6974 0000 0000 004B 0082 005F" /* Submit.....K.Ç._ */ $"00C3 0406 4361 6E63 656C 0000 0000 000A" /* .√..Cancel...... */ @@ -46,6 +39,29 @@ data 'DITL' (128) { $"3F75 0000 0000 002D 000F 003D 017A 1000" /* ?u.....-...=.z.. */ }; +data 'DITL' (129) { + $"0015 0000 0000 0106 0195 011A 01CF 0404" /* .........ï...œ.. */ + $"5361 7665 0000 0000 0106 0154 011A 018E" /* Save.......T...é */ + $"0406 4361 6E63 656C 0000 0000 000A 000A" /* ..Cancel........ */ + $"001A 00A9 1000 0000 0000 000A 00B9 001A" /* ...©.........π.. */ + $"01D0 1000 0000 0000 0023 000A 0033 00A9" /* .–.......#...3.© */ + $"1000 0000 0000 0023 00B9 0033 01D0 1000" /* .......#.π.3.–.. */ + $"0000 0000 003C 000A 004C 00A9 1000 0000" /* .....<...L.©.... */ + $"0000 003C 00B9 004C 01D0 1000 0000 0000" /* ...<.π.L.–...... */ + $"0055 000A 0065 00A9 1000 0000 0000 0055" /* .U...e.©.......U */ + $"00B9 0065 01D0 1000 0000 0000 006E 000A" /* .π.e.–.......n.. */ + $"007E 00A9 1000 0000 0000 006E 00B9 007E" /* .~.©.......n.π.~ */ + $"01D0 1000 0000 0000 0087 000A 0097 00A9" /* .–.......á...ó.© */ + $"1000 0000 0000 0087 00B9 0097 01D0 1000" /* .......á.π.ó.–.. */ + $"0000 0000 00A0 000A 00B0 00A9 1000 0000" /* .....†...∞.©.... */ + $"0000 00A0 00B9 00B0 01D0 1000 0000 0000" /* ...†.π.∞.–...... */ + $"00B9 000A 00C9 00A9 1000 0000 0000 00B9" /* .π...….©.......π */ + $"00B9 00C9 01D0 1000 0000 0000 00D2 000A" /* .π.….–.......“.. */ + $"00E2 00A9 1000 0000 0000 00D2 00B9 00E2" /* ...©.......“.π.. */ + $"01D0 1000 0000 0000 00EB 000A 00FB 00A9" /* .–.............© */ + $"1000 0000 0000 00EB 00B9 00FB 01D0 1000" /* .........π...–.. */ +}; + data 'vers' (1) { $"0010 6000 0000 0330 2E31 2630 2E31 20A9" /* ..`....0.1&0.1 © */ $"2032 3032 342C 206A 6F73 6875 6120 7374" /* 2024, joshua st */ @@ -114,5 +130,11 @@ data 'DLOG' (128) { $"0060 002C 00C8 01B4 0010 0000 0100 0000" /* .`.,.».¥........ */ $"0000 0080 0F49 6E70 7574 2052 6571 7565" /* ...Ä.Input Reque */ $"7374 6564" /* sted */ +}; + +data 'DLOG' (129) { + $"002E 0010 0150 01EA 0010 0000 0100 0000" /* .....P.......... */ + $"0000 0081 0E45 6469 7420 426F 6F6B 6D61" /* ...Å.Edit Bookma */ + $"726B 73" /* rks */ }; --- detritus.h Thu Nov 14 20:54:52 2024 +++ detritus.h Mon Nov 18 17:17:02 2024 @@ -19,6 +19,7 @@ #include "browser.h" #include "request.h" +#include "settings.h" #include "util.h" #define PROGRAM_NAME "Detritus" @@ -44,9 +45,18 @@ #define HISTORY_MENU_ID 131 #define BOOKMARKS_MENU_ID 132 +#define BOOKMARKS_MENU_EDIT_ID 1 +#define BOOKMARKS_MENU_SEP_ID 2 extern MenuHandle file_menu, edit_menu, bookmarks_menu; +struct default_bookmark { + char name[64]; + char uri[256]; +}; +extern const struct default_bookmark default_bookmarks[]; + void menu_defaults(void); +void menu_load_bookmarks(void); #endif \ No newline at end of file --- main.c Mon Nov 11 22:21:29 2024 +++ main.c Mon Nov 18 21:13:16 2024 @@ -22,6 +22,14 @@ #include "tcp.h" #include "util.h" +/* be sure this is NULL terminated */ +const struct default_bookmark default_bookmarks[] = { + { "Floodgap Gopher", "gopher://gopher.floodgap.com/", }, + { "SDF Gopher", "gopher://sdf.org/", }, + { "Gemini Protocol", "gemini://geminiprotocol.net/", }, + { 0 }, +}; + MenuHandle apple_menu, file_menu, edit_menu, bookmarks_menu; bool quitting = false; @@ -60,19 +68,17 @@ main(void) edit_menu = GetMHandle(EDIT_MENU_ID); bookmarks_menu = GetMHandle(BOOKMARKS_MENU_ID); menu_defaults(); - -AppendMenu(bookmarks_menu, "\p."); -SetItem(bookmarks_menu, 1, "\pgemini://geminiprotocol.net/history/"); -AppendMenu(bookmarks_menu, "\p."); -SetItem(bookmarks_menu, 2, "\pgopher://gopher.floodgap.com/"); - + DrawMenuBar(); if (_TCPInit() != 0) panic("Failed initializing MacTCP"); + + settings_load(); + menu_load_bookmarks(); + /* browser before scsi so the user can look at something while we poll */ browser_init(); - scsi_find_tls(); while (!quitting) { @@ -176,8 +182,9 @@ SetItem(bookmarks_menu, 2, "\pgopher://gopher.floodgap bool handle_menu(long menu_id) { + struct browser *browser; struct focusable *focused; - short menu, item; + short menu, item, n; menu = HiWord(menu_id); item = LoWord(menu_id); @@ -186,6 +193,8 @@ handle_menu(long menu_id) focused->menu(focused, menu, item)) goto handled; + browser = (struct browser *)focused->cookie; + switch (menu) { case APPLE_MENU_ID: switch (item) { @@ -212,16 +221,19 @@ handle_menu(long menu_id) break; } break; - case BOOKMARKS_MENU_ID: { - Str255 uri; - struct browser *browser = (struct browser *)focused->cookie; - - GetItem(bookmarks_menu, item, uri); - PtoCstr(uri); - browser_go_uri(browser,(char *)uri); + case BOOKMARKS_MENU_ID: + switch (item) { + case BOOKMARKS_MENU_EDIT_ID: + bookmarks_dialog(); + break; + default: + n = item - BOOKMARKS_MENU_SEP_ID - 1; + if (settings.bookmark_uris[n][0] != '\0') + browser_go_uri(browser, settings.bookmark_uris[n]); + break; + } break; } - } handled: HiliteMenu(0); @@ -235,6 +247,41 @@ menu_defaults(void) DisableItem(edit_menu, EDIT_MENU_COPY_ID); DisableItem(edit_menu, EDIT_MENU_PASTE_ID); DisableItem(edit_menu, EDIT_MENU_SELECT_ALL_ID); +} + +void +menu_load_bookmarks(void) +{ + Str255 title; + short count, n; + + count = CountMItems(bookmarks_menu); + while (count >= BOOKMARKS_MENU_SEP_ID) { + DelMenuItem(bookmarks_menu, count); + count--; + } + + for (n = 0; n < BOOKMARKS_COUNT; n++) { + if (settings.bookmark_uris[n][0] == '\0') + break; + + if (count < BOOKMARKS_MENU_SEP_ID) { + AppendMenu(bookmarks_menu, "\p(-"); + count++; + } + + if (settings.bookmark_names[n][0] == '\0') + strlcpy((char *)&title, (char *)&settings.bookmark_uris[n], + sizeof(title)); + else + strlcpy((char *)&title, (char *)&settings.bookmark_names[n], + sizeof(title)); + + CtoPstr(title); + AppendMenu(bookmarks_menu, "\p."); + count++; + SetItem(bookmarks_menu, count, title); + } } void --- settings.c Mon Nov 18 21:08:28 2024 +++ settings.c Mon Nov 18 21:08:28 2024 @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2021-2024 joshua stein <jcs@jcs.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <OSUtils.h> +#include <Files.h> +#include <Folders.h> +#include <GestaltEqu.h> +#include <Traps.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include "browser.h" +#include "settings.h" +#include "util.h" + +enum { + SETTING_STRING, + SETTING_SHORT, + SETTING_USHORT, + SETTING_LONG, + SETTING_PASSWORD, + SETTING_BOOL +}; + +enum { + SETTING_FLAG_ALLOW_BLANK = (1 << 0) +}; + +struct settings settings = { 0 }; + +struct setting { + char name[32]; + short type; + long flags; + long min; + long max; + char sdefault[32]; + short ditl_id; + unsigned long offset; + unsigned long size; + char password_storage[256]; +}; + +void settings_load_defaults(void); +void settings_find_prefs_folder(short *vrefnum, long *dirid); +bool settings_edit(struct setting *defs, size_t defs_count, short dlog_id, + bool use_defaults); + +void +settings_load(void) +{ + HParamBlockRec pb = { 0 }; + struct settings tsettings = { 0 }; + char fn[] = SETTINGS_FILENAME; + char *res; + short error, vrefnum, prefrefnum; + long len, rlen, dirid; + Handle h; + + GetSystemSubfolder(kPreferencesFolderType, true, &vrefnum, &dirid); + + pb.ioParam.ioNamePtr = (StringPtr)&fn; + pb.ioParam.ioVRefNum = vrefnum; + pb.ioParam.ioPermssn = fsRdPerm; + pb.fileParam.ioDirID = dirid; + error = PBHOpen(&pb, false); + if (error) { + if (error != fnfErr) + panic("Failed reading preferences file %s: %d", PtoCstr(fn), + error); + + goto load_defaults; + } + + rlen = len = sizeof(struct settings); + FSRead(pb.ioParam.ioRefNum, &rlen, &tsettings); + + while (tsettings.version < SETTINGS_VERSION) { + switch (tsettings.version) { + default: + FSClose(pb.ioParam.ioRefNum); + + if (ask("Unknown preferences version (%d), reset?", + tsettings.version)) + goto load_defaults; + + ExitToShell(); + } + + tsettings.version++; + } + + FSClose(pb.ioParam.ioRefNum); + + settings = tsettings; + return; + +load_defaults: + settings_load_defaults(); +} + +void +settings_load_defaults(void) +{ + short n; + + memset(&settings, 0, sizeof(settings)); + + for (n = 0; default_bookmarks[n].name[0] != '\0'; n++) { + strlcpy(settings.bookmark_names[n], default_bookmarks[n].name, + sizeof(settings.bookmark_names[0])); + strlcpy(settings.bookmark_uris[n], default_bookmarks[n].uri, + sizeof(settings.bookmark_uris[0])); + } + + settings.version = SETTINGS_VERSION; +} + +void +settings_save(struct settings *tsettings) +{ + HParamBlockRec pb = { 0 }; + char fn[] = SETTINGS_FILENAME; + short error, vrefnum, prefrefnum; + long dirid, len; + Handle h; + + GetSystemSubfolder(kPreferencesFolderType, true, &vrefnum, &dirid); + + pb.ioParam.ioNamePtr = (StringPtr)&fn; + pb.ioParam.ioVRefNum = vrefnum; + pb.fileParam.ioDirID = dirid; + error = PBHCreate(&pb, false); + if (error && error != dupFNErr) + goto create_failed; + if (!error) { + memset(&pb, 0, sizeof(pb)); + pb.ioParam.ioNamePtr = (StringPtr)&fn; + pb.ioParam.ioVRefNum = vrefnum; + pb.fileParam.ioDirID = dirid; + if ((error = PBHGetFInfo(&pb, false))) + goto create_failed; + + pb.fileParam.ioDirID = dirid; /* required after PBHGetFInfo */ + pb.fileParam.ioFlFndrInfo.fdType = 'pref'; + pb.fileParam.ioFlFndrInfo.fdCreator = SETTINGS_FILE_CREATOR; + if ((error = PBHSetFInfo(&pb, false))) + goto create_failed; + + memset(&pb, 0, sizeof(pb)); + pb.ioParam.ioVRefNum = vrefnum; + PBFlushVol(&pb, false); + } + + memset(&pb, 0, sizeof(pb)); + pb.ioParam.ioNamePtr = (StringPtr)&fn; + pb.ioParam.ioVRefNum = vrefnum; + pb.ioParam.ioPermssn = fsWrPerm; + pb.fileParam.ioDirID = dirid; + error = PBHOpen(&pb, false); + if (error) + goto create_failed; + + len = sizeof(struct settings); + tsettings->version = SETTINGS_VERSION; + FSWrite(pb.ioParam.ioRefNum, &len, tsettings); + FSClose(pb.ioParam.ioRefNum); + + return; + +create_failed: + panic("Failed creating preferences file %s: %d", PtoCstr(fn), error); +} + +bool +bookmarks_dialog(void) +{ + Str255 txt; + WindowPtr win; + DialogPtr dlg; + struct settings tsettings; + struct URI *uri; + short name_id, uri_id, itype, n, hit, bookmarkn; + Handle ihandle; + Rect irect, dlgrect; + + GetPort(&win); + + if ((dlg = GetNewDialog(BOOKMARKS_DLOG_ID, NULL, + (WindowPtr)-1)) == NULL) { + warn("Can't find DLOG %d", BOOKMARKS_DLOG_ID); + return false; + } + center_in_screen(dlg->portRect.right - dlg->portRect.left, + dlg->portRect.bottom - dlg->portRect.top, true, &dlgrect); + MoveWindow(dlg, dlgrect.left, dlgrect.top, true); + + for (n = 0; n < BOOKMARKS_COUNT; n++) { + if (settings.bookmark_uris[n][0] == '\0') + continue; + + name_id = BOOKMARKS_NAME_ID_START + (n * 2); + GetDItem(dlg, name_id, &itype, &ihandle, &irect); + strlcpy((char *)&txt, settings.bookmark_names[n], sizeof(txt)); + CtoPstr(txt); + SetIText(ihandle, txt); + + uri_id = BOOKMARKS_URI_ID_START + (n * 2); + GetDItem(dlg, uri_id, &itype, &ihandle, &irect); + strlcpy((char *)&txt, settings.bookmark_uris[n], sizeof(txt)); + CtoPstr(txt); + SetIText(ihandle, txt); + } + + tsettings = settings; + + ShowWindow(dlg); + for (;;) { +modal: + ModalDialog(ModalDialogFilter, &hit); + if (hit == cancel) + break; + if (hit != ok) + continue; + + memset(&tsettings.bookmark_names, 0, + sizeof(tsettings.bookmark_names)); + memset(&tsettings.bookmark_uris, 0, + sizeof(tsettings.bookmark_uris)); + + for (n = 0, bookmarkn = 0; n < BOOKMARKS_COUNT; n++) { + uri_id = BOOKMARKS_URI_ID_START + (n * 2); + GetDItem(dlg, uri_id, &itype, &ihandle, &irect); + GetIText(ihandle, txt); + + if (txt[0] != '\0') { + PtoCstr(txt); + + uri = parse_uri((char *)&txt); + if (uri == NULL) { + warn("Could not parse URI \"%s\"", txt); + goto modal; + } + xfree(&uri); + strlcpy(tsettings.bookmark_uris[bookmarkn], (char *)&txt, + sizeof(tsettings.bookmark_uris[bookmarkn])); + + name_id = BOOKMARKS_NAME_ID_START + (n * 2); + GetDItem(dlg, name_id, &itype, &ihandle, &irect); + GetIText(ihandle, txt); + PtoCstr(txt); + strlcpy(tsettings.bookmark_names[bookmarkn], (char *)&txt, + sizeof(tsettings.bookmark_names[bookmarkn])); + + bookmarkn++; + } + } + + settings_save(&tsettings); + menu_load_bookmarks(); + break; + } + + DisposDialog(dlg); + SetPort(win); +} + +bool +settings_edit(struct setting *defs, size_t defs_count, short dlog_id, + bool use_defaults) +{ + struct settings tsettings = settings; + struct setting *s; + DialogTHndl dlgh; + DialogPtr dlg; + Handle ihandle; + Rect irect; + size_t size, n, m, slen; + long lval; + bool bval, save; + short hit, itype, ret; + char *sdata, *strval; + Str255 stmp; + + /* center dialog in screen */ + dlgh = (DialogTHndl)xGetResource('DLOG', dlog_id); + HLock(dlgh); + center_in_screen((**dlgh).boundsRect.right - (**dlgh).boundsRect.left, + (**dlgh).boundsRect.bottom - (**dlgh).boundsRect.top, + true, &(**dlgh).boundsRect); + HUnlock(dlgh); + + if ((dlg = GetNewDialog(dlog_id, nil, (WindowPtr)-1)) == NULL) + panic("Can't find settings DLOG %d", dlog_id); + + for (n = 0; n < defs_count; n++) { + s = &defs[n]; + sdata = (char *)&tsettings + s->offset; + + GetDItem(dlg, s->ditl_id, &itype, &ihandle, &irect); + + switch (s->type) { + case SETTING_PASSWORD: + PasswordDialogFieldFilterSetup(s->ditl_id, + (char *)s->password_storage, sizeof(s->password_storage)); + + strval = (use_defaults ? (char *)s->sdefault : sdata); + size = strlen(strval); + if (size >= sizeof(s->password_storage) - 1) + size = 0; + + /* show a masked value */ + stmp[0] = size; + for (m = 1; m <= size; m++) + stmp[m] = '•'; + SetIText(ihandle, stmp); + + /* but store the actual password */ + memcpy(s->password_storage, strval, size); + s->password_storage[size] = '\0'; + break; + case SETTING_STRING: + strval = (use_defaults ? s->sdefault : sdata); + memcpy(stmp, strval, sizeof(stmp)); + stmp[sizeof(stmp) - 1] = '\0'; + CtoPstr(stmp); + SetIText(ihandle, stmp); + break; + case SETTING_SHORT: + case SETTING_USHORT: + case SETTING_LONG: + if (use_defaults) { + memcpy(stmp, s->sdefault, sizeof(stmp)); + stmp[sizeof(stmp) - 1] = '\0'; + } else if (s->type == SETTING_SHORT) { + snprintf((char *)stmp, sizeof(stmp), "%d", + BYTES_TO_SHORT(sdata[0], sdata[1])); + } else if (s->type == SETTING_USHORT) { + snprintf((char *)stmp, sizeof(stmp), "%u", + BYTES_TO_SHORT(sdata[0], sdata[1])); + } else if (s->type == SETTING_LONG) { + snprintf((char *)stmp, sizeof(stmp), "%ld", + BYTES_TO_LONG(sdata[0], sdata[1], sdata[2], sdata[3])); + } + CtoPstr(stmp); + SetIText(ihandle, stmp); + break; + case SETTING_BOOL: + SetCtlValue(ihandle, (use_defaults ? s->sdefault[0] : + sdata[0]) == 1); + break; + default: + panic("Unknown setting type %d", s->type); + } + } + + ret = false; + ShowWindow(dlg); + SelectWindow(dlg); + +get_input: + ModalDialog(PasswordDialogFieldFilter, &hit); + switch (hit) { + case -1: + goto settings_done; + case OK: + goto verify; + default: + GetDItem(dlg, hit, &itype, &ihandle, &irect); + if (itype == (ctrlItem + chkCtrl)) + SetCtlValue(ihandle, !GetCtlValue(ihandle)); + goto get_input; + } + + save = false; +verify: + for (n = 0; n < defs_count; n++) { + s = &defs[n]; + sdata = (char *)&tsettings + s->offset; + + GetDItem(dlg, s->ditl_id, &itype, &ihandle, &irect); + + if (s->type == SETTING_PASSWORD) { + memcpy((char *)&stmp, s->password_storage, sizeof(stmp)); + } else if (s->type == SETTING_BOOL) { + snprintf((char *)&stmp, sizeof(stmp), "%d", + GetCtlValue(ihandle)); + } else { + GetIText(ihandle, stmp); + PtoCstr(stmp); + } + + switch (s->type) { + case SETTING_STRING: + case SETTING_PASSWORD: + slen = strlen((char *)stmp); + + if (slen == 0 && (s->flags & SETTING_FLAG_ALLOW_BLANK)) { + /* ok */ + } else { + if (s->min && s->max && s->min == s->max && + slen != s->min) { + warn("%s must be %ld character%s", s->name, s->min, + s->min == 1 ? "" : "s"); + goto get_input; + } + if (s->min && slen < s->min) { + warn("%s is too short (minimum %ld)", s->name, s->min); + goto get_input; + } + if (s->max && slen > s->max) { + warn("%s is too long (maximum %ld)", s->name, s->max); + goto get_input; + } + } + + if (save) { + memset(sdata, 0, s->size); + strlcpy(sdata, (char *)stmp, s->size); + } + break; + case SETTING_SHORT: + case SETTING_USHORT: + case SETTING_LONG: + lval = atol((char *)stmp); + if (lval < s->min) { + if (s->type == SETTING_USHORT) + warn("%s must be at least %ul", s->name, s->min); + else + warn("%s must be at least %ld", s->name, s->min); + goto get_input; + } + if (lval > s->max) { + if (s->type == SETTING_USHORT) + warn("%s must be less than %ul", s->name, s->max); + else + warn("%s must be less than %ld", s->name, s->max); + goto get_input; + } + if (save) { + if (s->type == SETTING_LONG) { + sdata[0] = (lval >> 24) & 0xff; + sdata[1] = (lval >> 16) & 0xff; + sdata[2] = (lval >> 8) & 0xff; + sdata[3] = lval & 0xff; + } else { + sdata[0] = (lval >> 8) & 0xff; + sdata[1] = lval & 0xff; + } + } + break; + case SETTING_BOOL: + if (save) + sdata[0] = (stmp[0] == '1'); + break; + } + } + + if (!save) { + save = true; + goto verify; + } + + /* all validated ok and fields written */ + settings_save(&tsettings); + settings = tsettings; + ret = true; + +settings_done: + PasswordDialogFieldFinish(); + DisposeDialog(dlg); + ReleaseResource(dlgh); + + return ret; +} --- settings.h Mon Nov 18 16:28:51 2024 +++ settings.h Mon Nov 18 16:28:51 2024 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 joshua stein <jcs@jcs.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __SETTINGS_H__ +#define __SETTINGS_H__ + +#include "stdint.h" + +#define SETTINGS_FILENAME "\pDetritus Preferences" +#define SETTINGS_FILE_CREATOR 'DTRT' + +#define BOOKMARKS_DLOG_ID 129 +#define BOOKMARKS_COUNT 10 +#define BOOKMARKS_NAME_ID_START 3 +#define BOOKMARKS_URI_ID_START 4 + +struct settings { + short version; +#define SETTINGS_VERSION 1 + char bookmark_names[BOOKMARKS_COUNT][64]; + char bookmark_uris[BOOKMARKS_COUNT][256]; +}; + +extern struct settings settings; + +void settings_load(void); +void settings_save(struct settings *tsettings); +bool bookmarks_dialog(void); + +#endif \ No newline at end of file