From 1be81e92d12eb21d398f9f9c4a39058eb9c6c161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20In=C3=A1cio?= <29243277+matheus-inacio@users.noreply.github.com> Date: Sat, 15 Aug 2026 16:17:30 -0300 Subject: [PATCH 1/3] refactor: move blocked applications management to a dedicated ClipboardPage preference section --- src/core/clipboard/clipboard-manager.ts | 41 ++- src/extension.ts | 20 +- src/prefs.ts | 5 + src/prefs/ClipboardPage.ts | 300 ++++++++++++++++++ src/prefs/GeneralPage.ts | 233 -------------- src/prefs/components/blocked-app-row.ts | 92 ++---- ...gnome.shell.extensions.vicinae.gschema.xml | 5 + src/types/prefs.ts | 9 +- src/ui/ClipboardPage.ui | 80 +++++ src/ui/GeneralPage.ui | 13 - 10 files changed, 466 insertions(+), 332 deletions(-) create mode 100644 src/prefs/ClipboardPage.ts create mode 100644 src/ui/ClipboardPage.ui diff --git a/src/core/clipboard/clipboard-manager.ts b/src/core/clipboard/clipboard-manager.ts index 02deb97..ef8e48c 100644 --- a/src/core/clipboard/clipboard-manager.ts +++ b/src/core/clipboard/clipboard-manager.ts @@ -26,7 +26,18 @@ export class VicinaeClipboardManager { } enable() { - this.setupClipboardMonitoring(); + if (!this.clipboard) { + this.setupClipboardMonitoring(); + } + } + + disable() { + if (this.clipboard) { + this.signals.disconnectAll(); + this.clipboard = null; + this.selection = null; + logger.info("Clipboard monitoring disabled"); + } } setSettings(settings: Gio.Settings): void { @@ -167,19 +178,19 @@ export class VicinaeClipboardManager { const context = handler.priority >= 1 ? { - storeBinaryData: ( - marker: string, - data: unknown, - mimeType: string, - ) => { - this.binaryStore.set( - marker, - data as BufferLike, - mimeType, - ); - logger.debug(`Stored binary data: ${marker}`); - }, - } + storeBinaryData: ( + marker: string, + data: unknown, + mimeType: string, + ) => { + this.binaryStore.set( + marker, + data as BufferLike, + mimeType, + ); + logger.debug(`Stored binary data: ${marker}`); + }, + } : undefined; handler.capture( @@ -382,7 +393,7 @@ export class VicinaeClipboardManager { } destroy(): void { - this.signals.disconnectAll(); + this.disable(); this.eventListeners = []; this.currentContent = ""; logger.debug( diff --git a/src/extension.ts b/src/extension.ts index 1e4a937..6eb2b7d 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -26,7 +26,9 @@ export default class Vicinae extends Extension { initializeLogger(this.settings); this.clipboardManager = new VicinaeClipboardManager(); - this.clipboardManager.enable(); + if (this.settings.get_boolean("enable-clipboard-monitoring")) { + this.clipboardManager.enable(); + } this.clipboardManager.setSettings(this.settings); const appClass = @@ -93,6 +95,22 @@ export default class Vicinae extends Extension { ); this.signals.add(() => this.settings?.disconnect(blockedAppsId)); + const enableMonitoringId = this.settings.connect( + "changed::enable-clipboard-monitoring", + () => { + if (this.clipboardManager && this.settings) { + if ( + this.settings.get_boolean("enable-clipboard-monitoring") + ) { + this.clipboardManager.enable(); + } else { + this.clipboardManager.disable(); + } + } + }, + ); + this.signals.add(() => this.settings?.disconnect(enableMonitoringId)); + logger.info("Vicinae extension initialized successfully"); } diff --git a/src/prefs.ts b/src/prefs.ts index fcc65b0..f72daf0 100644 --- a/src/prefs.ts +++ b/src/prefs.ts @@ -4,6 +4,7 @@ import type Gio from "gi://Gio"; import { ExtensionPreferences } from "resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js"; import { AboutPage } from "./prefs/AboutPage.js"; +import { ClipboardPage } from "./prefs/ClipboardPage.js"; import { GeneralPage } from "./prefs/GeneralPage.js"; export default class VicinaePrefs extends ExtensionPreferences { @@ -22,6 +23,10 @@ export default class VicinaePrefs extends ExtensionPreferences { generalPage.bindSettings(prefsWindow._settings); prefsWindow.add(generalPage); + const clipboardPage = new ClipboardPage(); + clipboardPage.bindSettings(prefsWindow._settings); + prefsWindow.add(clipboardPage); + const aboutPage = new AboutPage(); aboutPage.setMetadata(this.metadata); prefsWindow.add(aboutPage); diff --git a/src/prefs/ClipboardPage.ts b/src/prefs/ClipboardPage.ts new file mode 100644 index 0000000..d110a9f --- /dev/null +++ b/src/prefs/ClipboardPage.ts @@ -0,0 +1,300 @@ +import Adw from "gi://Adw"; +import Gio from "gi://Gio"; +import GObject from "gi://GObject"; +import type { ClipboardPageChildren } from "../types/prefs.js"; +import { getTemplate } from "../utils/getTemplate.js"; +import { logger } from "../utils/logger.js"; +import { + BlockedAppRow, + type BlockedAppRowInstance, +} from "./components/blocked-app-row.js"; + +export const ClipboardPage = GObject.registerClass( + { + GTypeName: "VicinaeClipboardPage", + Template: getTemplate("ClipboardPage"), + InternalChildren: [ + "enableClipboardMonitoring", + "blockedAppsGroup", + "emptyPlaceholderRow", + "addWindowButton", + ], + }, + class ClipboardPage extends Adw.PreferencesPage { + private settings!: Gio.Settings; + private blockedAppRows: Map = new Map(); + private emptyRows: Set = new Set(); + + bindSettings(settings: Gio.Settings) { + this.settings = settings; + logger.debug("Settings bound to ClipboardPage"); + + this.loadBlockedApplications(); + this.updateAddButtonState(); + + const children = this as unknown as ClipboardPageChildren; + + this.connectAddBlockedAppButton(children); + this.bindEnableClipboardMonitoring(settings, children); + } + + /** "Add window class" → append an empty blocked-app row. */ + private connectAddBlockedAppButton(children: ClipboardPageChildren) { + children._addWindowButton.connect("clicked", () => { + this.addEmptyBlockedAppRow(); + }); + } + + /** `enable-clipboard-monitoring` ↔ clipboard monitoring switch. */ + private bindEnableClipboardMonitoring( + settings: Gio.Settings, + children: ClipboardPageChildren, + ) { + settings.bind( + "enable-clipboard-monitoring", + children._enableClipboardMonitoring, + "active", + Gio.SettingsBindFlags.DEFAULT, + ); + + // Update sensitivity of blocked apps group based on the switch + const updateSensitivity = () => { + const isEnabled = settings.get_boolean( + "enable-clipboard-monitoring", + ); + children._blockedAppsGroup.set_sensitive(isEnabled); + }; + + settings.connect( + "changed::enable-clipboard-monitoring", + updateSensitivity, + ); + updateSensitivity(); + } + + private loadBlockedApplications() { + try { + const blockedApps = this.settings.get_strv( + "blocked-applications", + ); + + const uniqueBlockedApps = this.removeDuplicates(blockedApps); + if (uniqueBlockedApps.length !== blockedApps.length) { + this.settings.set_strv( + "blocked-applications", + uniqueBlockedApps, + ); + } + + const children = this as unknown as ClipboardPageChildren; + const existingRows = Array.from(this.blockedAppRows.values()); + existingRows.forEach((row) => { + children._blockedAppsGroup.remove(row); + }); + this.blockedAppRows.clear(); + this.emptyRows.clear(); + + uniqueBlockedApps.forEach((windowClass) => { + this.addBlockedAppRow(windowClass); + }); + } catch (error) { + logger.error("Error loading blocked applications", error); + } + } + + private removeDuplicates(apps: string[]): string[] { + const seen = new Set(); + return apps.filter((app) => { + const lowerApp = app.toLowerCase(); + if (seen.has(lowerApp)) { + return false; + } + seen.add(lowerApp); + return true; + }); + } + + private addEmptyBlockedAppRow() { + if (this.emptyRows.size > 0) { + const firstEmptyRow = this.emptyRows.values().next().value; + if (firstEmptyRow) { + firstEmptyRow.focusInput(); + } + return; + } + this.addBlockedAppRow(""); + } + + private addBlockedAppRow(windowClass: string) { + const children = this as unknown as ClipboardPageChildren; + + const row = new BlockedAppRow(); + row.setWindowClass(windowClass); + + row.connect("delete-requested", () => { + this.removeBlockedAppRow(row); + }); + + row.connect("save-requested", () => { + this.handleSaveRequest(row); + }); + + row.connect("input-changed", () => { + this.handleInputChange(row); + }); + + children._blockedAppsGroup.add_row(row); + + if (windowClass) { + this.blockedAppRows.set(windowClass, row); + } else { + this.emptyRows.add(row); + row.focusInput(); + } + + this.updateAddButtonState(); + } + + private handleInputChange(row: BlockedAppRowInstance) { + const isEmpty = row.isEmpty(); + const wasEmpty = this.emptyRows.has(row); + + if (isEmpty && !wasEmpty) { + this.emptyRows.add(row); + } else if (!isEmpty && wasEmpty) { + this.emptyRows.delete(row); + } + + this.updateAddButtonState(); + } + + private updateAddButtonState() { + const children = this as unknown as ClipboardPageChildren; + const hasEmptyRows = this.emptyRows.size > 0; + children._addWindowButton.set_sensitive(!hasEmptyRows); + + const hasAnyRows = + this.blockedAppRows.size > 0 || this.emptyRows.size > 0; + children._emptyPlaceholderRow.set_visible(!hasAnyRows); + } + + private handleSaveRequest(row: BlockedAppRowInstance) { + const oldClass = row.getOriginalWindowClass(); + const newClass = row.getInputValue().trim(); + + if (newClass) { + const currentBlockedApps = this.settings.get_strv( + "blocked-applications", + ); + + const isDuplicate = currentBlockedApps.some( + (app) => + app !== oldClass && + app.toLowerCase() === newClass.toLowerCase(), + ); + + if (isDuplicate) { + const root = this.get_root() as Adw.PreferencesWindow; + if (root && "add_toast" in root) { + const toast = new Adw.Toast({ + title: `Can't add ${newClass} to the list, because it's already there`, + }); + ( + root as Adw.PreferencesWindow & { + add_toast: (toast: Adw.Toast) => void; + } + ).add_toast(toast); + } + row.setWindowClass(oldClass); + return; + } + this.updateBlockedAppInSettings(row, oldClass, newClass); + } else { + this.removeBlockedAppFromSettings(row, oldClass); + } + this.updateAddButtonState(); + } + + private updateBlockedAppInSettings( + row: BlockedAppRowInstance, + oldClass: string, + newClass: string, + ) { + try { + const currentBlockedApps = this.settings.get_strv( + "blocked-applications", + ); + + let filteredApps: string[]; + + if (oldClass && oldClass.trim() !== "") { + filteredApps = currentBlockedApps.filter( + (app) => app !== oldClass, + ); + } else { + filteredApps = [...currentBlockedApps]; + } + + filteredApps.push(newClass); + + this.settings.set_strv("blocked-applications", filteredApps); + + if (oldClass && oldClass.trim() !== "") { + this.blockedAppRows.delete(oldClass); + } + this.blockedAppRows.set(newClass, row); + } catch (error) { + logger.error("Error updating blocked app in settings", error); + } + } + + private removeBlockedAppFromSettings( + _row: BlockedAppRowInstance, + oldClass: string, + ) { + try { + if (!oldClass || oldClass.trim() === "") { + return; + } + + const currentBlockedApps = this.settings.get_strv( + "blocked-applications", + ); + + const filteredApps = currentBlockedApps.filter( + (app) => app !== oldClass, + ); + + this.settings.set_strv("blocked-applications", filteredApps); + + this.blockedAppRows.delete(oldClass); + } catch (error) { + logger.error("Error removing blocked app from settings", error); + } + } + + private removeBlockedAppRow(row: BlockedAppRowInstance) { + const children = this as unknown as ClipboardPageChildren; + const windowClass = row.getWindowClass(); + + if (windowClass) { + const currentApps = this.settings.get_strv( + "blocked-applications", + ); + + const updatedApps = currentApps.filter( + (app) => app !== windowClass, + ); + this.settings.set_strv("blocked-applications", updatedApps); + + this.blockedAppRows.delete(windowClass); + } else { + this.emptyRows.delete(row); + } + + children._blockedAppsGroup.remove(row); + + this.updateAddButtonState(); + } + }, +); diff --git a/src/prefs/GeneralPage.ts b/src/prefs/GeneralPage.ts index 4b5e6dc..395f26e 100644 --- a/src/prefs/GeneralPage.ts +++ b/src/prefs/GeneralPage.ts @@ -4,10 +4,6 @@ import GObject from "gi://GObject"; import type { GeneralPageChildren } from "../types/prefs.js"; import { getTemplate } from "../utils/getTemplate.js"; import { logger } from "../utils/logger.js"; -import { - BlockedAppRow, - type BlockedAppRowInstance, -} from "./components/blocked-app-row.js"; /** GSettings `logging-level` string values, in ComboRow order. */ const LOGGING_LEVELS: readonly string[] = ["error", "warn", "info", "debug"]; @@ -17,8 +13,6 @@ export const GeneralPage = GObject.registerClass( GTypeName: "VicinaeGeneralPage", Template: getTemplate("GeneralPage"), InternalChildren: [ - "blockedAppsGroup", - "addWindowButton", "showStatusIndicator", "loggingLevel", "launcherAutoCloseFocusLoss", @@ -28,32 +22,19 @@ export const GeneralPage = GObject.registerClass( }, class GeneralPage extends Adw.PreferencesPage { private settings!: Gio.Settings; - private blockedAppRows: Map = new Map(); - private emptyRows: Set = new Set(); bindSettings(settings: Gio.Settings) { this.settings = settings; logger.debug("Settings bound to GeneralPage"); - this.loadBlockedApplications(); - this.updateAddButtonState(); - const children = this as unknown as GeneralPageChildren; - this.connectAddBlockedAppButton(children); this.bindShowStatusIndicator(settings, children); this.bindLoggingLevel(settings, children); this.bindLauncherAutoCloseFocusLoss(settings, children); this.bindLauncherAppClass(settings, children); } - /** "Add window class" → append an empty blocked-app row. */ - private connectAddBlockedAppButton(children: GeneralPageChildren) { - children._addWindowButton.connect("clicked", () => { - this.addEmptyBlockedAppRow(); - }); - } - /** `show-status-indicator` ↔ status indicator switch. */ private bindShowStatusIndicator( settings: Gio.Settings, @@ -117,219 +98,5 @@ export const GeneralPage = GObject.registerClass( Gio.SettingsBindFlags.DEFAULT, ); } - - private loadBlockedApplications() { - try { - const blockedApps = this.settings.get_strv( - "blocked-applications", - ); - - const uniqueBlockedApps = this.removeDuplicates(blockedApps); - if (uniqueBlockedApps.length !== blockedApps.length) { - this.settings.set_strv( - "blocked-applications", - uniqueBlockedApps, - ); - } - - const children = this as unknown as GeneralPageChildren; - const existingRows = Array.from(this.blockedAppRows.values()); - existingRows.forEach((row) => { - children._blockedAppsGroup.remove(row); - }); - this.blockedAppRows.clear(); - this.emptyRows.clear(); - - uniqueBlockedApps.forEach((windowClass) => { - this.addBlockedAppRow(windowClass); - }); - } catch (error) { - logger.error("Error loading blocked applications", error); - } - } - - private removeDuplicates(apps: string[]): string[] { - const seen = new Set(); - return apps.filter((app) => { - const lowerApp = app.toLowerCase(); - if (seen.has(lowerApp)) { - return false; - } - seen.add(lowerApp); - return true; - }); - } - - private addEmptyBlockedAppRow() { - this.addBlockedAppRow(""); - } - - private addBlockedAppRow(windowClass: string) { - const children = this as unknown as GeneralPageChildren; - - const row = new BlockedAppRow(); - row.setWindowClass(windowClass); - - row.connect("delete-requested", () => { - this.removeBlockedAppRow(row); - }); - - row.connect("save-requested", () => { - this.handleSaveRequest(row); - }); - - row.connect("input-changed", () => { - this.handleInputChange(row); - }); - - children._blockedAppsGroup.add(row); - - if (windowClass) { - this.blockedAppRows.set(windowClass, row); - } else { - this.emptyRows.add(row); - row.updateCheckButtonState(); - } - - this.updateAddButtonState(); - } - - private handleInputChange(row: BlockedAppRowInstance) { - const isEmpty = row.isEmpty(); - const wasEmpty = this.emptyRows.has(row); - - if (isEmpty && !wasEmpty) { - this.emptyRows.add(row); - } else if (!isEmpty && wasEmpty) { - this.emptyRows.delete(row); - } - - this.updateAddButtonState(); - } - - private updateAddButtonState() { - const children = this as unknown as GeneralPageChildren; - const hasEmptyRows = this.emptyRows.size > 0; - children._addWindowButton.set_sensitive(!hasEmptyRows); - } - - private handleSaveRequest(row: BlockedAppRowInstance) { - const oldClass = row.getOriginalWindowClass(); - const newClass = row.getInputValue().trim(); - - if (newClass) { - const currentBlockedApps = this.settings.get_strv( - "blocked-applications", - ); - - const isDuplicate = currentBlockedApps.some( - (app) => - app !== oldClass && - app.toLowerCase() === newClass.toLowerCase(), - ); - - if (isDuplicate) { - const root = this.get_root() as Adw.PreferencesWindow; - if (root && "add_toast" in root) { - const toast = new Adw.Toast({ - title: `Can't add ${newClass} to the list, because it's already there`, - }); - ( - root as Adw.PreferencesWindow & { - add_toast: (toast: Adw.Toast) => void; - } - ).add_toast(toast); - } - row.setWindowClass(oldClass); - return; - } - this.updateBlockedAppInSettings(row, oldClass, newClass); - } else { - this.removeBlockedAppFromSettings(row, oldClass); - } - this.updateAddButtonState(); - } - - private updateBlockedAppInSettings( - row: BlockedAppRowInstance, - oldClass: string, - newClass: string, - ) { - try { - const currentBlockedApps = this.settings.get_strv( - "blocked-applications", - ); - - let filteredApps: string[]; - - if (oldClass && oldClass.trim() !== "") { - filteredApps = currentBlockedApps.filter( - (app) => app !== oldClass, - ); - } else { - filteredApps = [...currentBlockedApps]; - } - - filteredApps.push(newClass); - - this.settings.set_strv("blocked-applications", filteredApps); - - if (oldClass && oldClass.trim() !== "") { - this.blockedAppRows.delete(oldClass); - } - this.blockedAppRows.set(newClass, row); - } catch (error) { - logger.error("Error updating blocked app in settings", error); - } - } - - private removeBlockedAppFromSettings( - _row: BlockedAppRowInstance, - oldClass: string, - ) { - try { - if (!oldClass || oldClass.trim() === "") { - return; - } - - const currentBlockedApps = this.settings.get_strv( - "blocked-applications", - ); - - const filteredApps = currentBlockedApps.filter( - (app) => app !== oldClass, - ); - - this.settings.set_strv("blocked-applications", filteredApps); - - this.blockedAppRows.delete(oldClass); - } catch (error) { - logger.error("Error removing blocked app from settings", error); - } - } - - private removeBlockedAppRow(row: BlockedAppRowInstance) { - const children = this as unknown as GeneralPageChildren; - const windowClass = row.getWindowClass(); - - if (windowClass) { - const currentApps = this.settings.get_strv( - "blocked-applications", - ); - - const updatedApps = currentApps.filter( - (app) => app !== windowClass, - ); - this.settings.set_strv("blocked-applications", updatedApps); - - this.blockedAppRows.delete(windowClass); - } else { - this.emptyRows.delete(row); - } - - children._blockedAppsGroup.remove(row); - - this.updateAddButtonState(); - } }, ); diff --git a/src/prefs/components/blocked-app-row.ts b/src/prefs/components/blocked-app-row.ts index 0ade6a9..c4dda48 100644 --- a/src/prefs/components/blocked-app-row.ts +++ b/src/prefs/components/blocked-app-row.ts @@ -1,9 +1,10 @@ import Adw from "gi://Adw"; +import GLib from "gi://GLib"; import GObject from "gi://GObject"; import Gtk from "gi://Gtk"; /** - * Expandable row for editing a blocked-application window class in preferences. + * Action row for editing a blocked-application window class in preferences. */ export const BlockedAppRow = GObject.registerClass( { @@ -23,31 +24,17 @@ export const BlockedAppRow = GObject.registerClass( "input-changed": {}, }, }, - class BlockedAppRow extends Adw.ExpanderRow { + class BlockedAppRow extends Adw.EntryRow { private windowClass: string = ""; - private inputValue: string = ""; private originalWindowClass: string = ""; - private windowEntry: Adw.EntryRow; - private checkButton: Gtk.Button; + private deleteButton: Gtk.Button; constructor() { super(); - this.set_title("Expand this row to enter window class"); - this.set_subtitle(""); - - this.windowEntry = new Adw.EntryRow({ - title: "Window Class", - text: "", - }); - - this.checkButton = new Gtk.Button({ - icon_name: "object-select-symbolic", - valign: Gtk.Align.CENTER, - tooltip_text: "Save and close", - css_classes: ["flat", "suggested-action"], - }); + this.set_title("Window Class"); + this.set_show_apply_button(true); this.deleteButton = new Gtk.Button({ icon_name: "user-trash-symbolic", @@ -56,38 +43,32 @@ export const BlockedAppRow = GObject.registerClass( css_classes: ["flat"], }); - this.add_suffix(this.checkButton); this.add_suffix(this.deleteButton); - this.add_row(this.windowEntry); - - this.checkButton.visible = false; - - this.checkButton.connect("clicked", () => { - this.saveChanges(); - }); this.deleteButton.connect("clicked", () => { this.emit("delete-requested"); }); - this.windowEntry.connect("changed", () => { - this.inputValue = this.windowEntry.get_text().trim(); - this.updateCheckButtonState(); + this.connect("changed", () => { this.emit("input-changed"); }); - this.connect("notify::expanded", () => { - this.updateButtonVisibility(); + this.connect("apply", () => { + this.saveChanges(); + }); + } + + focusInput() { + GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { + this.grab_focus(); + return GLib.SOURCE_REMOVE; }); } setWindowClass(windowClass: string) { this.windowClass = windowClass; - this.inputValue = windowClass; this.originalWindowClass = windowClass; - this.windowEntry.set_text(windowClass); - this.updateDisplay(); - this.updateCheckButtonState(); + this.set_text(windowClass); } getWindowClass(): string { @@ -95,11 +76,11 @@ export const BlockedAppRow = GObject.registerClass( } getInputValue(): string { - return this.inputValue; + return this.get_text().trim(); } getCurrentWindowClass(): string { - return this.inputValue.trim() || this.windowClass; + return this.getInputValue() || this.windowClass; } getOriginalWindowClass(): string { @@ -107,47 +88,22 @@ export const BlockedAppRow = GObject.registerClass( } isEmpty(): boolean { - return this.inputValue.trim() === ""; - } - - closeExpanded() { - this.set_expanded(false); + return this.getInputValue() === ""; } private saveChanges() { const oldValue = this.windowClass; - const newValue = this.inputValue.trim(); + const newValue = this.getInputValue(); if (newValue !== oldValue) { this.originalWindowClass = oldValue; this.windowClass = newValue; - this.updateDisplay(); this.emit("save-requested"); } - this.closeExpanded(); - } - - private updateButtonVisibility() { - this.checkButton.visible = this.get_expanded(); - if (this.get_expanded()) { - this.updateCheckButtonState(); - } - } - - updateCheckButtonState() { - this.checkButton.set_sensitive(this.inputValue.trim().length > 0); - } - - private updateDisplay() { - if (this.windowClass) { - this.set_title(this.windowClass); - this.set_subtitle( - `Expand this row to edit - ${this.windowClass}`, - ); - } else { - this.set_title("Expand this row to enter window class"); - this.set_subtitle(""); + const root = this.get_root(); + if (root) { + root.set_focus(null); } } }, diff --git a/src/schemas/org.gnome.shell.extensions.vicinae.gschema.xml b/src/schemas/org.gnome.shell.extensions.vicinae.gschema.xml index a0769c8..420096e 100644 --- a/src/schemas/org.gnome.shell.extensions.vicinae.gschema.xml +++ b/src/schemas/org.gnome.shell.extensions.vicinae.gschema.xml @@ -6,6 +6,11 @@ Blocked applications List of application names that should be blocked from clipboard access + + true + Enable clipboard monitoring + Whether to monitor clipboard changes. Disabling this saves memory but prevents Vicinae from accessing the clipboard history. + true Show status bar indicator diff --git a/src/types/prefs.ts b/src/types/prefs.ts index 9ca747c..1a96cfa 100644 --- a/src/types/prefs.ts +++ b/src/types/prefs.ts @@ -2,8 +2,6 @@ import type Adw from "gi://Adw"; import type Gtk from "gi://Gtk"; export interface GeneralPageChildren { - _blockedAppsGroup: Adw.PreferencesGroup; - _addWindowButton: Gtk.Button; _showStatusIndicator: Adw.SwitchRow; _loggingLevel: Adw.ComboRow; _launcherAutoCloseFocusLoss: Adw.SwitchRow; @@ -11,6 +9,13 @@ export interface GeneralPageChildren { _journalctlCommand: Adw.EntryRow; } +export interface ClipboardPageChildren { + _enableClipboardMonitoring: Adw.SwitchRow; + _blockedAppsGroup: Adw.ExpanderRow; + _emptyPlaceholderRow: Adw.ActionRow; + _addWindowButton: Gtk.Button; +} + export interface AboutPageChildren { _extensionIcon: Gtk.Image; _extensionName: Gtk.Label; diff --git a/src/ui/ClipboardPage.ui b/src/ui/ClipboardPage.ui new file mode 100644 index 0000000..9621d0f --- /dev/null +++ b/src/ui/ClipboardPage.ui @@ -0,0 +1,80 @@ + + + + + diff --git a/src/ui/GeneralPage.ui b/src/ui/GeneralPage.ui index 996c503..594e834 100644 --- a/src/ui/GeneralPage.ui +++ b/src/ui/GeneralPage.ui @@ -4,19 +4,6 @@