diff --git a/quickshell/Common/SessionData.qml b/quickshell/Common/SessionData.qml index 12fb3477f..f1999eb35 100644 --- a/quickshell/Common/SessionData.qml +++ b/quickshell/Common/SessionData.qml @@ -1252,10 +1252,11 @@ Singleton { saveSettings(); } - function addLauncherHistory(query) { + function addLauncherHistory(query, skipLastQuery) { let q = query.trim(); - setLauncherLastQuery(q); + if (!skipLastQuery) + setLauncherLastQuery(q); if (!q) return; diff --git a/quickshell/Modals/DankLauncherV2/Controller.qml b/quickshell/Modals/DankLauncherV2/Controller.qml index 503df53c8..ea076a7b9 100644 --- a/quickshell/Modals/DankLauncherV2/Controller.qml +++ b/quickshell/Modals/DankLauncherV2/Controller.qml @@ -36,6 +36,7 @@ Item { property int viewModeVersion: 0 property string viewModeContext: "spotlight" property bool forceLinearNavigation: false + property bool explicitQuerySession: false signal itemExecuted signal searchCompleted @@ -54,7 +55,7 @@ Item { if (active) return; - SessionData.addLauncherHistory(searchQuery); + SessionData.addLauncherHistory(searchQuery, explicitQuerySession); sections = []; flatModel = []; selectedItem = null; @@ -1940,7 +1941,7 @@ Item { if (!item) return; - SessionData.addLauncherHistory(searchQuery); + SessionData.addLauncherHistory(searchQuery, explicitQuerySession); if (item.type === "plugin_browse") { var browsePluginId = item.data?.pluginId; diff --git a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml index be516eef2..c06fcb768 100644 --- a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml +++ b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml @@ -370,6 +370,7 @@ Item { } if (spotlightContent.controller) { var targetMode = mode || SessionData.getLauncherRestoreMode(); + spotlightContent.controller.explicitQuerySession = !!query; spotlightContent.controller.searchMode = targetMode; spotlightContent.controller.activePluginId = ""; spotlightContent.controller.activePluginName = ""; @@ -430,7 +431,10 @@ Item { root.keyboardActive = true; if (root.spotlightContent && root.spotlightContent.searchField) { root.spotlightContent.searchField.forceActiveFocus(); - root.spotlightContent.searchField.selectAll(); + if (query) + root.spotlightContent.searchField.cursorPosition = root.spotlightContent.searchField.text.length; + else + root.spotlightContent.searchField.selectAll(); } }); }); diff --git a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalSpotlight.qml b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalSpotlight.qml index e07e73768..4e615a8ce 100644 --- a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalSpotlight.qml +++ b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalSpotlight.qml @@ -161,6 +161,7 @@ Item { } if (spotlightContent.controller) { spotlightContent.controller.reset(); + spotlightContent.controller.explicitQuerySession = !!query; spotlightContent.controller.searchMode = targetMode; spotlightContent.controller.historyIndex = -1; if (targetQuery.length > 0) @@ -171,7 +172,10 @@ Item { } if (spotlightContent.searchField) { spotlightContent.searchField.forceActiveFocus(); - spotlightContent.searchField.selectAll(); + if (query) + spotlightContent.searchField.cursorPosition = targetQuery.length; + else + spotlightContent.searchField.selectAll(); } } diff --git a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalStandalone.qml b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalStandalone.qml index 6ba742aae..39747f749 100644 --- a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalStandalone.qml +++ b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalStandalone.qml @@ -154,10 +154,14 @@ Item { if (spotlightContent.searchField) { spotlightContent.searchField.text = targetQuery; - spotlightContent.searchField.selectAll(); + if (query) + spotlightContent.searchField.cursorPosition = targetQuery.length; + else + spotlightContent.searchField.selectAll(); } if (spotlightContent.controller) { var targetMode = mode || SessionData.getLauncherRestoreMode(); + spotlightContent.controller.explicitQuerySession = !!query; spotlightContent.controller.searchMode = targetMode; spotlightContent.controller.activePluginId = ""; spotlightContent.controller.activePluginName = ""; diff --git a/quickshell/Modules/AppDrawer/AppDrawerPopout.qml b/quickshell/Modules/AppDrawer/AppDrawerPopout.qml index 0cdb91afd..7273d72e8 100644 --- a/quickshell/Modules/AppDrawer/AppDrawerPopout.qml +++ b/quickshell/Modules/AppDrawer/AppDrawerPopout.qml @@ -70,6 +70,7 @@ DankPopout { lc.searchField.forceActiveFocus(); } if (lc.controller) { + lc.controller.explicitQuerySession = !!query; lc.controller.searchMode = mode; lc.controller.pluginFilter = ""; lc.controller.searchQuery = ""; diff --git a/quickshell/Widgets/DankTextField.qml b/quickshell/Widgets/DankTextField.qml index 3ad7f6a25..38e2a6a3a 100644 --- a/quickshell/Widgets/DankTextField.qml +++ b/quickshell/Widgets/DankTextField.qml @@ -22,6 +22,7 @@ StyledRect { } property alias text: textInput.text + property alias cursorPosition: textInput.cursorPosition property string placeholderText: "" property string labelText: "" property alias font: textInput.font diff --git a/quickshell/translations/extract_settings_index.py b/quickshell/translations/extract_settings_index.py index 41a5e94cf..152146bd0 100755 --- a/quickshell/translations/extract_settings_index.py +++ b/quickshell/translations/extract_settings_index.py @@ -306,21 +306,45 @@ def extract_property(block, prop_name): return None -def find_settings_components(content, filename): +def load_wrapper_components(root_dir): + widgets_dir = Path(root_dir) / "Modules" / "Settings" / "Widgets" + wrappers = {} + + for qml_file in sorted(widgets_dir.glob("*.qml")): + if qml_file.stem in SEARCHABLE_COMPONENTS: + continue + + with open(qml_file, "r", encoding="utf-8") as f: + content = f.read() + + root_match = re.search(r"^(\w+)\s*\{", content, re.MULTILINE) + if not root_match or root_match.group(1) not in SEARCHABLE_COMPONENTS: + continue + + wrappers[qml_file.stem] = { + prop: extract_property(content, prop) + for prop in ("settingKey", "title", "text", "description", "iconName", "tags") + } + + return wrappers + + +def find_settings_components(content, filename, wrappers): results = [] file_tab_index = TAB_INDEX_MAP.get(filename, -1) if file_tab_index == -1: return results - for component in SEARCHABLE_COMPONENTS: + for component in SEARCHABLE_COMPONENTS + sorted(wrappers): + defaults = wrappers.get(component, {}) pattern = rf"\b{component}\s*\{{" for match in re.finditer(pattern, content): block = parse_component_block(content, match.start(), component) if not block: continue - setting_key = extract_property(block, "settingKey") + setting_key = extract_property(block, "settingKey") or defaults.get("settingKey") if setting_key: setting_key = setting_key.strip("\"'") @@ -332,8 +356,8 @@ def find_settings_components(content, filename): if tab_raw and tab_raw.strip("\"'") == "appearance": tab_index = 6 - title_raw = extract_property(block, "title") - text_raw = extract_property(block, "text") + title_raw = extract_property(block, "title") or defaults.get("title") + text_raw = extract_property(block, "text") or defaults.get("text") label = None if title_raw: label = extract_i18n_string(title_raw) @@ -343,19 +367,19 @@ def find_settings_components(content, filename): if not label: continue - icon_raw = extract_property(block, "iconName") + icon_raw = extract_property(block, "iconName") or defaults.get("iconName") icon = None if icon_raw: icon = icon_raw.strip("\"'") if icon.startswith("{") or "?" in icon: icon = None - tags_raw = extract_property(block, "tags") + tags_raw = extract_property(block, "tags") or defaults.get("tags") tags = [] if tags_raw: tags = extract_tags(tags_raw) - desc_raw = extract_property(block, "description") + desc_raw = extract_property(block, "description") or defaults.get("description") description = None if desc_raw: description = extract_i18n_string(desc_raw) @@ -509,6 +533,7 @@ def generate_tab_entries(sidebar_file, settings_entries=None): def extract_settings_index(root_dir): settings_dir = Path(root_dir) / "Modules" / "Settings" + wrappers = load_wrapper_components(root_dir) all_entries = [] seen_keys = set() @@ -519,7 +544,7 @@ def extract_settings_index(root_dir): with open(qml_file, "r", encoding="utf-8") as f: content = f.read() - entries = find_settings_components(content, qml_file.name) + entries = find_settings_components(content, qml_file.name, wrappers) for entry in entries: key = entry["section"] if key not in seen_keys: diff --git a/quickshell/translations/settings_search_index.json b/quickshell/translations/settings_search_index.json index cb4ad7b56..31d12aa2a 100644 --- a/quickshell/translations/settings_search_index.json +++ b/quickshell/translations/settings_search_index.json @@ -2898,6 +2898,19 @@ "icon": "search", "description": "Show All, Apps, Files, and Plugins chips beside the Spotlight Bar input." }, + { + "section": "terminalOverride", + "label": "Terminal", + "tabIndex": 9, + "category": "Launcher", + "keywords": [ + "drawer", + "launcher", + "menu", + "start", + "terminal" + ] + }, { "section": "dankLauncherV2BorderThickness", "label": "Thickness", @@ -4835,6 +4848,27 @@ ], "description": "Automatically lock the screen when the system prepares to suspend" }, + { + "section": "lockScreenFontFamily", + "label": "Lock screen font", + "tabIndex": 11, + "category": "Lock Screen", + "keywords": [ + "clock", + "date", + "font", + "lock", + "lockscreen", + "login", + "password", + "screen", + "security", + "time", + "typography", + "watch" + ], + "description": "Font used for the clock and date on the lock screen" + }, { "section": "lockScreenNotificationMode", "label": "Notification Display", @@ -7839,6 +7873,22 @@ ], "icon": "info" }, + { + "section": "greeterFontFamily", + "label": "Greeter font", + "tabIndex": 31, + "category": "Greeter", + "keywords": [ + "display manager", + "font", + "greetd", + "greeter", + "login", + "screen", + "typography" + ], + "description": "Font used on the login screen" + }, { "section": "greeterAuth", "label": "Login Authentication",