// Copyright (C) 2026 Danilo M. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as // published by the Free Software Foundation. // // 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. .pragma library // The starter map, used when the config file is missing or unreadable, and the // seed for the settings page. The md-* glyphs are supplementary-plane, so they // are surrogate pairs; a five-digit \u escape would be a different character. var defaults = { generic: "\udb80\uded7", // md-help_circle scenes: { "Desktop": "\udb80\udf79", // md-monitor "Webcam Only": "\udb81\udd67", // md-video "Window Only": "\uf2d0", // fa-window_maximize "Intervallo": "\udb80\udd76", // md-coffee }, }; // Exactly one code point; a surrogate pair counts as one. function validGlyph(s) { if (typeof s !== "string" || s === "") return false; let n = 0; for (let i = 0; i < s.length; i++) { const c = s.charCodeAt(i); if (c >= 0xD800 && c <= 0xDBFF && i + 1 < s.length) { const d = s.charCodeAt(i + 1); if (d >= 0xDC00 && d <= 0xDFFF) i++; } n++; } return n === 1; } // The map as stored: an invalid generic falls back, invalid scenes drop. function normalize(map) { const src = map || {}; const out = { generic: validGlyph(src.generic) ? src.generic : defaults.generic, scenes: {}, }; const sc = src.scenes || {}; for (const k in sc) if (validGlyph(sc[k])) out.scenes[k] = sc[k]; return out; } // A missing or unparseable file is the starter map; a valid file is used as-is. function parse(text) { let v = null; try { v = JSON.parse(text); } catch (e) {} if (!v || typeof v !== "object" || Array.isArray(v)) return normalize(defaults); return normalize(v); } function serialize(map) { return JSON.stringify({ generic: map.generic, scenes: map.scenes }, null, 2) + "\n"; } function iconFor(map, name) { return (map && map.scenes && map.scenes[name]) || (map && map.generic) || defaults.generic; } // A draft may leave the generic empty; Save substitutes the default. function validMap(map) { if (!map || typeof map !== "object") return false; if (map.generic !== "" && !validGlyph(map.generic)) return false; const sc = map.scenes || {}; for (const k in sc) if (!validGlyph(sc[k])) return false; return true; }