From 49eaa5526552e171f50209491ff426321fb69ab8 Mon Sep 17 00:00:00 2001 From: Luke Hudson Date: Fri, 5 Sep 2025 21:51:10 +0200 Subject: [PATCH 1/2] feat: only update one button at a time #122 When changes occur in the directory, this only updates the buttons for scripts that have altered, rather than removing and adding all buttons. This allows for updating a single button. However this system can cause buttons with the same position numbering to change position in an unstable manner --- argos@pew.worldwidemann.com/button.js | 8 ++ argos@pew.worldwidemann.com/extension.js | 113 +++++++++++++++++------ 2 files changed, 93 insertions(+), 28 deletions(-) diff --git a/argos@pew.worldwidemann.com/button.js b/argos@pew.worldwidemann.com/button.js index 51f0101..4764ee0 100644 --- a/argos@pew.worldwidemann.com/button.js +++ b/argos@pew.worldwidemann.com/button.js @@ -74,6 +74,14 @@ class ArgosButton extends PanelMenu.Button { this._update(); } + getFileBasename() { + return this._file.get_basename(); + } + + addToPanel(panel, id, settings) { + panel.addToStatusArea(id, this, settings.position, settings.box); + } + _update() { if (this._updateRunning) return; diff --git a/argos@pew.worldwidemann.com/extension.js b/argos@pew.worldwidemann.com/extension.js index 945ca96..2f04f62 100644 --- a/argos@pew.worldwidemann.com/extension.js +++ b/argos@pew.worldwidemann.com/extension.js @@ -23,7 +23,6 @@ constructor() { this.directory = Gio.File.new_for_path(directoryPath); this.buttons = []; - this.debounceTimeout = null; if (!this.directory.query_exists(null)) { this.directory.make_directory(null); @@ -51,19 +50,17 @@ constructor() { } enable() { - this.addButtons(); + this.addAllButtons(); this.directoryChangedId = this.directoryMonitor.connect("changed", (monitor, file, otherFile, eventType) => { - this.removeButtons(); - - // Some high-level file operations trigger multiple "changed" events in rapid succession. - // Debouncing groups them together to avoid unnecessary updates. - if (this.debounceTimeout === null) { - this.debounceTimeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 100, () => { - this.debounceTimeout = null; - this.addButtons(); - return false; - }); + if (eventType !== Gio.FileMonitorEvent.CREATED) { + this.removeButtonForFile(file); + } + + let relevantFile = otherFile ? otherFile : file; + + if (this.isValidArgosScript(relevantFile)) { + this.addButtonForFile(relevantFile); } }); } @@ -71,13 +68,66 @@ enable() { disable() { this.directoryMonitor.disconnect(this.directoryChangedId); - if (this.debounceTimeout !== null) - GLib.source_remove(this.debounceTimeout); - this.removeButtons(); } -addButtons() { +addButtonForFile(file) { + let basename = file.get_basename(); + let settings = Utilities.parseFilename(basename); + let button = new ArgosButton(file, settings); + let index = this.buttons.findIndex((b) => b && b.getFileBasename() == basename); + + if (index < 0) { + // append it if not otherwise found + index = this.buttons.length; + } + + // destroy existing button as we'll recreate + if (this.buttons[index] !== null) { + this.removeButton(index); + } + + this.buttons[index] = button; + button.addToPanel(Main.panel, "argos-button-" + index, settings); +} + +removeButtonForFile(file) { + let basename = file.get_basename(); + let index = this.buttons.findIndex((b) => b && b.getFileBasename() == basename); + + if (index >= 0) { + this.removeButton(index); + } +} + +isValidArgosScript(file) { + return GLib.file_test(file.get_path(), GLib.FileTest.IS_EXECUTABLE) && + !GLib.file_test(file.get_path(), GLib.FileTest.IS_DIR) && + !file.get_basename().startsWith("."); +} + +compareFilesForSort(file1, file2) { + let basename1 = file1.get_basename(); + let basename2 = file2.get_basename(); + let settings1 = Utilities.parseFilename(basename1); + let settings2 = Utilities.parseFilename(basename2); + + let boxDiff = settings1.box.localeCompare(settings2.box); + + if (boxDiff !== 0) { + return boxDiff; + } + + let posDiff = settings1.position - settings2.position; + + if (posDiff !== 0) { + return posDiff; + } + + return basename1.localeCompare(basename2); +} + +findButtonFiles() { let files = []; let enumerator = this.directory.enumerate_children(Gio.FILE_ATTRIBUTE_STANDARD_NAME, Gio.FileQueryInfoFlags.NONE, null); @@ -86,30 +136,37 @@ addButtons() { while ((fileInfo = enumerator.next_file(null)) !== null) { let file = enumerator.get_child(fileInfo); - if (GLib.file_test(file.get_path(), GLib.FileTest.IS_EXECUTABLE) && - !GLib.file_test(file.get_path(), GLib.FileTest.IS_DIR) && - !file.get_basename().startsWith(".")) { + if (this.isValidArgosScript(file)) { files.push(file); } } - files.sort(function(file1, file2) { - return file1.get_basename().localeCompare(file2.get_basename()); - }); + files.sort(this.compareFilesForSort); + + return files; +} + +addAllButtons() { + const files = this.findButtonFiles(); // Iterate in reverse order as buttons are added right-to-left for (let i = files.length - 1; i >= 0; i--) { - let settings = Utilities.parseFilename(files[i].get_basename()); - let button = new ArgosButton(files[i], settings); - this.buttons.push(button); - Main.panel.addToStatusArea("argos-button-" + i, button, settings.position, settings.box); + this.addButtonForFile(files[i], i); + } +} + +removeButton(index) { + if (this.buttons[index]) { + this.buttons[index].destroy(); + this.buttons[index] = null; } } removeButtons() { for (let i = 0; i < this.buttons.length; i++) { - this.buttons[i].destroy(); + this.removeButton(i); } this.buttons = []; } -} + +} \ No newline at end of file From a824006f19320a2bc24b07a803f77a2e758995ff Mon Sep 17 00:00:00 2001 From: Luke Hudson Date: Sat, 6 Sep 2025 14:15:09 +0200 Subject: [PATCH 2/2] feat: improving update of one button at a time #122 Prevent changing of position in an unstable manner --- argos@pew.worldwidemann.com/extension.js | 50 +++++++++++++++++++----- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/argos@pew.worldwidemann.com/extension.js b/argos@pew.worldwidemann.com/extension.js index 2f04f62..70a06bf 100644 --- a/argos@pew.worldwidemann.com/extension.js +++ b/argos@pew.worldwidemann.com/extension.js @@ -52,15 +52,34 @@ constructor() { enable() { this.addAllButtons(); - this.directoryChangedId = this.directoryMonitor.connect("changed", (monitor, file, otherFile, eventType) => { - if (eventType !== Gio.FileMonitorEvent.CREATED) { - this.removeButtonForFile(file); - } - - let relevantFile = otherFile ? otherFile : file; - - if (this.isValidArgosScript(relevantFile)) { - this.addButtonForFile(relevantFile); + directoryChangedId = directoryMonitor.connect("changed", function(monitor, file, otherFile, eventType) { + switch (eventType) { + case Gio.FileMonitorEvent.CREATED: + case Gio.FileMonitorEvent.MOVED_IN: + if (this.isValidArgosScript(file)) { + this.addButtonForFile(file); + } + break; + + case Gio.FileMonitorEvent.DELETED: + case Gio.FileMonitorEvent.MOVED_OUT: + case Gio.FileMonitorEvent.PRE_UNMOUNT: + case Gio.FileMonitorEvent.UNMOUNTED: + this.removeButtonForFile(file); + break; + + case Gio.FileMonitorEvent.MOVED: + case Gio.FileMonitorEvent.RENAMED: + this.removeButtonForFile(file); + + if (this.isValidArgosScript(otherFile)) { + this.addButtonForFile(otherFile); + } + break; + + default: + this.updateButtonForFile(file); + break; } }); } @@ -71,6 +90,17 @@ disable() { this.removeButtons(); } +function updateButtonForFile(file) { + let basename = file.get_basename(); + let button = buttons.find((b) => b && b.getFileBasename() == basename); + + if (!button) { + return false; + } + + button.update(); +} + addButtonForFile(file) { let basename = file.get_basename(); let settings = Utilities.parseFilename(basename); @@ -169,4 +199,4 @@ removeButtons() { this.buttons = []; } -} \ No newline at end of file +}