diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/README.md b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/README.md index 9ac517a..fb547b3 100644 --- a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/README.md +++ b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/README.md @@ -4,7 +4,7 @@ Bring some color to your GNOME desktop by syncing your desktop and lockscreen wa [![Get it on GNOME extensions](/screenshot/get_it_on_gnome_extensions.png)](https://extensions.gnome.org/extension/1262/bing-wallpaper-changer/) [![<3 Sponsor this project on GitHub <3](/screenshot/sponsor.png)](https://github.com/sponsors/neffo) -![Screenshot](/screenshot/notification.png) +![Screenshot](/screenshot/overview.jpg) As featured on [OMG! Ubuntu](https://www.omgubuntu.co.uk/2017/07/bing-wallpaper-changer-gnome-extension). @@ -18,10 +18,44 @@ Also, check out my related [Google Earth View wallpaper extension](https://githu * Image gallery to view, select and curate stored images * Optionally delete old images after a week, or you can keep (and curate) them forever * Override the lockscreen blur (NEW: lockscreen blur is now dynamic!) -* Language support: English (en), German (de), Dutch (nl), Italian (it), Polish (pl), Chinese (zh_CN, zh_TW), French (fr_FR), Portuguese (pt, pt_BR), Ukrainian (uk), Russian (ru_RU), Spanish (es), Korean (ko), Indonesian (id), Catalan (ca), Norwegian Bokmål (nb) & Nynorsk (nn), Swedish (sv), Arabic (ar), Hungarian (hu), Japanese (ja), Czech (cs_CZ), Finnish (fi_FI) and Turkish (tr) - a HUGE thanks to the translators +* Language support: English (en), German (de), Dutch (nl), Italian (it), Polish (pl), Chinese (zh_CN, zh_TW), French (fr_FR), Portuguese (pt, pt_BR), Ukrainian (uk), Russian (ru_RU), Spanish (es), Korean (ko), Indonesian (id), Catalan (ca), Norwegian Bokmål (nb) & Nynorsk (nn), Swedish (sv), Arabic (ar), Hungarian (hu), Japanese (ja), Czech (cs_CZ), Finnish (fi_FI) and Turkish (tr), Persian (fa_ir) - a HUGE thanks to the translators * Image preview in menus & ability to manually set wallpapers individually or copy image to clipboard * A selection of different theme-aware indicator (tray) icons to choose (or hide it completely) +## Quickstart guide + +* Install from [GNOME extensions](https://extensions.gnome.org/extension/1262/bing-wallpaper-changer/), by default your wallpaper will be synced to the current Bing image of the day - if that's all you want you don't have to do anymore, everything is automatic +* Bing Wallpaper (by default) builds a collection of images over time (this can be disabled if required) + +### Control bar +![Bing Wallpaper menu control bar](/screenshot/controlbar.png) + +* 🤍 - Favorite/unfavorite current image (can be used to shuffle only favorite images and favorites are never deleted automatically) +* 🗑️ - Trash/untrash current image (exclude from shuffle selection or optionally deleted from disk) +* ⏪ - select previous day's image (in date order) +* ⏩ - select next day's image (in date order) +* ⏭️ - select today's image (skip to current) +* 🎲 - I'm feeling lucky, show me a random image (by default you should have at least 8 images available, curated with favorite and trash buttons) + +### Quick settings +![Bing Wallpaper menu control bar](/screenshot/quicksettings.png) + +* Always show new images - when a new Bing wallpaper is available switch to it immediately +* Image shuffle mode - switch to a random image at user defined intervals (default once per day or once per startup) +* Image shuffle only favorites - only select favorite images (🤍), by default 'trashed' images are always excluded +* Image shuffle only UHD resolution - occasionally some images are not UHD, exclude these from selection + +### Gallery + +![Gallery item](/screenshot/gallery.png) + +The 4 buttons in the gallery (3rd page in the preferences) do have tool-tips but these do the following: +- Favorite - favorite this image (equivalent to doing this via the control bar) +- Apply - set this image as wallpaper +- View - open image in image viewer +- Info - open the Bing description of the image +- Trash - trash the image + ## TODO * add more languages (#14) - [please help if you can](https://github.com/neffo/bing-wallpaper-gnome-extension/issues/14) @@ -33,10 +67,25 @@ Also, check out my related [Google Earth View wallpaper extension](https://githu * Bing may detect your location incorrectly (and force a locale as above) - if you see this, please let me know what Bing.com itself does * GNOME Shell themes can break some GNOME popup menu elements (toggle switches for example). This impacts GNOME more generally, not just this extension. Double check you are running latest versions of your themes (or disable them). -## Requirements +## System Requirements GNOME 3.36+ or 40+ (Ubuntu 20.04 LTS or later, older versions of the extension work with 3.18+, but are no longer supported). +## Package dependencies + +Below packages are required to build the extension + +``` +npm +gettext +intltool +zip +``` +For Ubuntu you can hit below command to install +``` +sudo apt install npm gettext intltool zip -y +``` + ## Install [Install from extensions.gnome.org](https://extensions.gnome.org/extension/1262/bing-wallpaper-changer/) @@ -53,7 +102,7 @@ sh install.sh ## Enable debug logging -Enable debug logging through the exptension preferences 'Debug options' tab or if unable to open preferences you can enable debugging using dconf-editor with this command: +Enable debug logging through the extension preferences 'Debug options' tab or if unable to open preferences you can enable debugging using dconf-editor with this command: ``` GSETTINGS_SCHEMA_DIR=$HOME/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/schemas dconf-editor /org/gnome/shell/extensions/bingwallpaper/ ``` diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/blur.js b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/blur.js index 95c7b77..b6111bf 100644 --- a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/blur.js +++ b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/blur.js @@ -20,6 +20,7 @@ var shellVersionMajor = parseInt(Config.PACKAGE_VERSION.split('.')[0]); var shellVersionMinor = parseInt(Config.PACKAGE_VERSION.split('.')[1]); var shellVersionPoint = parseInt(Config.PACKAGE_VERSION.split('.')[2]); +var blurField = shellVersionMajor >= 46 ? "radius" : "sigma"; // default BWP mild blur var BWP_BLUR_SIGMA = 2; var BWP_BLUR_BRIGHTNESS = 55; @@ -50,7 +51,7 @@ export function _updateBackgroundEffects_BWP(monitorIndex) { if (effect) { effect.set({ // GNOME defaults when login prompt is visible brightness: BLUR_BRIGHTNESS, - sigma: BLUR_SIGMA * themeContext.scale_factor, + [blurField]: BLUR_SIGMA * themeContext.scale_factor, }); } } @@ -59,7 +60,7 @@ export function _updateBackgroundEffects_BWP(monitorIndex) { if (effect) { effect.set({ // adjustable blur when clock is visible brightness: BWP_BLUR_BRIGHTNESS * 0.01, // we use 0-100 rather than 0-1, so divide by 100 - sigma: BWP_BLUR_SIGMA * themeContext.scale_factor, + [blurField]: BWP_BLUR_SIGMA * themeContext.scale_factor, }); } } @@ -91,7 +92,7 @@ export function _clampValue(value) { export default class Blur { constructor() { this.enabled = false; - log('Bing Wallpaper adjustable blur is '+supportedVersion()?'available':'not available'); + log('Bing Wallpaper adjustable blur is '+(supportedVersion()?'available':'not available')); } set_blur_strength(value) { diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/carousel.js b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/carousel.js index f522ee7..6b0c294 100644 --- a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/carousel.js +++ b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/carousel.js @@ -108,7 +108,7 @@ export default class Carousel { this.log('Delete requested for '+filename); Utils.deleteImage(filename); Utils.setImageHiddenStatus(this.settings, image.urlbase, true); - Utils.cleanupImageList(this.settings); // hide image instead + Utils.purgeImages(this.settings); // hide image instead widget.get_parent().get_parent().set_visible(false); // bit of a hack if (this.callbackfunc) this.callbackfunc(); diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/extension.js b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/extension.js index 493e2c8..c520b31 100644 --- a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/extension.js +++ b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/extension.js @@ -55,10 +55,16 @@ const newMenuSwitchItem = (label, state) => { } function log(msg) { - if (bingWallpaperIndicator && bingWallpaperIndicator._settings.get_boolean('debug-logging')) + if (BingDebug()) console.log('BingWallpaper extension: ' + msg); // disable to keep the noise down in journal } +function BingDebug() { + if (bingWallpaperIndicator && bingWallpaperIndicator._settings.get_boolean('debug-logging')) + return true; + return false; +} + function notifyError(msg) { Main.notifyError("BingWallpaper extension error", msg); } @@ -152,12 +158,12 @@ class BingWallpaperIndicator extends Button { this.toggleSetBackground = newMenuSwitchItem(_("Set background image"), this._settings.get_boolean('set-background')); this.toggleSelectNew = newMenuSwitchItem(_("Always show new images"), this._settings.get_boolean('revert-to-current-image')); this.toggleShuffle = newMenuSwitchItem(_("Image shuffle mode"), true); - this.toggleShuffleOnlyFaves = newMenuSwitchItem(_("Image shuffle only favourites"), this._settings.get_boolean('random-mode-include-only-favourites')); - this.toggleNotifications = newMenuSwitchItem(_("Enable desktop notifications"), this._settings.get_boolean('notify')); + this.toggleShuffleOnlyFaves = newMenuSwitchItem(_("Image shuffle only favorites"), this._settings.get_boolean('random-mode-include-only-favourites')); + /*this.toggleNotifications = newMenuSwitchItem(_("Enable desktop notifications"), this._settings.get_boolean('notify'));*/ this.toggleImageCount = newMenuSwitchItem(_("Show image count"), this._settings.get_boolean('show-count-in-image-title')); this.toggleShuffleOnlyUHD = newMenuSwitchItem(_("Image shuffle only UHD resolutions"), this._settings.get_boolean('random-mode-include-only-uhd')); - [this.toggleNotifications, /*this.toggleImageCount, this.toggleSetBackground,*/ this.toggleSelectNew, + [/*this.toggleNotifications, this.toggleImageCount, this.toggleSetBackground,*/ this.toggleSelectNew, this.toggleShuffle, this.toggleShuffleOnlyFaves, this.toggleShuffleOnlyUHD] .forEach(e => this.settingsSubMenu.menu.addMenuItem(e)); @@ -220,15 +226,21 @@ class BingWallpaperIndicator extends Button { // listen for configuration changes _setConnections() { - this._settings.connect('changed::hide', () => { - this.visible = !this._settings.get_boolean('hide'); - }); + this.settings_connections = []; + + this.settings_connections.push( + this._settings.connect('changed::hide', () => { + this.visible = !this._settings.get_boolean('hide'); + }) + ); let settingConnections = [ {signal: 'changed::icon-name', call: this._setIcon}, {signal: 'changed::market', call: this._refresh}, {signal: 'changed::set-background', call: this._setBackground}, {signal: 'changed::override-lockscreen-blur', call: this._setBlur}, + {signal: 'changed::lockscreen-blur-strength', call: this._setBlur}, + {signal: 'changed::lockscreen-blur-brightness', call: this._setBlur}, {signal: 'changed::selected-image', call: this._setImage}, {signal: 'changed::delete-previous', call: this._cleanUpImages}, {signal: 'changed::notify', call: this._notifyCurrentImage}, @@ -244,11 +256,10 @@ class BingWallpaperIndicator extends Button { // _setShuffleToggleState settingConnections.forEach((e) => { - this._settings.connect(e.signal, e.call.bind(this)); + this.settings_connections.push( + this._settings.connect(e.signal, e.call.bind(this)) + ); }); - - this._settings.connect('changed::lockscreen-blur-strength', blur.set_blur_strength.bind(this, this._settings.get_int('lockscreen-blur-strength'))); - this._settings.connect('changed::lockscreen-blur-brightness', blur.set_blur_brightness.bind(this, this._settings.get_int('lockscreen-blur-brightness'))); // ensure we're in a sensible initial state this._setIcon(); @@ -275,19 +286,23 @@ class BingWallpaperIndicator extends Button { let toggles = [ /*{key: 'set-background', toggle: this.toggleSetBackground},*/ {key: 'revert-to-current-image', toggle: this.toggleSelectNew}, - {key: 'notify', toggle: this.toggleNotifications}, - /*{key: 'show-count-in-image-title', toggle: this.toggleImageCount},*/ + /*{key: 'notify', toggle: this.toggleNotifications}, + {key: 'show-count-in-image-title', toggle: this.toggleImageCount},*/ {key: 'random-mode-enabled', toggle: this.toggleShuffle}, {key: 'random-mode-include-only-favourites', toggle: this.toggleShuffleOnlyFaves}, /*{key: 'random-mode-include-only-unhidden', toggle: this.toggleShuffleOnlyUnhidden},*/ {key: 'random-mode-include-only-uhd', toggle: this.toggleShuffleOnlyUHD}]; - toggles.forEach( (e) => { - this._settings.connect('changed::'+e.key, () => { - e.toggle.setToggleState(this._settings.get_boolean(e.key)); - }); + toggles.forEach( (e) => { + this.settings_connections.push( + this._settings.connect('changed::'+e.key, () => { + log(e.key+' setting changed to '+ (this._settings.get_boolean(e.key)?'true':'false')); + e.toggle.setToggleState(this._settings.get_boolean(e.key)); + }) + ); e.toggle.connect('toggled', (item, state) => { - this._settings.set_boolean(e.key, state); + log(e.key+' switch toggled to '+ (state?'true':'false')); + this._setBooleanSetting(e.key, state); }); }); @@ -300,7 +315,32 @@ class BingWallpaperIndicator extends Button { [this.clipboardImageItem, this.clipboardURLItem]. forEach(e => e.setSensitive(false)); } - } + } + + _setBooleanSetting(key, state) { + let success = this._settings.set_boolean(key, state); + log('key '+key+' set to ' + (state?'true':'false') + ' (returned ' + (success?'true':'false')+')'); + } + + _setStringSetting(key, value) { + let success = this._settings.set_string(key, value); + log('key '+key+' set to ' + value + ' (returned ' + (success?'true':'false')+')'); + } + + _setIntSetting(key, value) { + let success = this._settings.set_int(key, value); + log('key '+key+' set to ' + value + ' (returned ' + (success?'true':'false')+')'); + } + + _onDestroy() { + this._unsetConnections(); + } + + _unsetConnections() { + this.settings_connections.forEach((e) => { + this._settings.disconnect(e); + }); + } _openPrefs() { this._extension.openPreferences(); @@ -312,7 +352,6 @@ class BingWallpaperIndicator extends Button { this.clipboardImageItem.setSensitive(!this._updatePending && this.imageURL != ""); this.clipboardURLItem.setSensitive(!this._updatePending && this.imageURL != ""); this.thumbnailItem.setSensitive(!this._updatePending && this.imageURL != ""); - //this.showItem.setSensitive(!this._updatePending && this.title != "" && this.explanation != ""); this.dwallpaperItem.setSensitive(!this._updatePending && this.filename != ""); this.swallpaperItem.setSensitive(!this._updatePending && this.filename != ""); this.titleItem.setSensitive(!this._updatePending && this.imageinfolink != ""); @@ -348,7 +387,7 @@ class BingWallpaperIndicator extends Button { if (this._settings.get_boolean('notify')) { let image = this._getCurrentImage(); if (image) { - this._createNotification(image); + this._createImageNotification(image); } } } @@ -555,7 +594,7 @@ class BingWallpaperIndicator extends Button { } _curImage() { - this._settings.set_string('selected-image', 'current'); + this._setStringSetting('selected-image', 'current'); this._gotoImage(0); } @@ -569,13 +608,13 @@ class BingWallpaperIndicator extends Button { if (randomEnabled) { log('enabled shuffle mode, by setting a shuffe timer (5 seconds)'); this._restartShuffleTimeout(5); - this._settings.set_boolean('revert-to-current-image', false); + this._setBooleanSetting('revert-to-current-image', false); } else { // clear shuffle timer if (this._shuffleTimeout) GLib.source_remove(this._shuffleTimeout); - this._settings.set_boolean('revert-to-current-image', true); + this._setBooleanSetting('revert-to-current-image', true); } } @@ -627,7 +666,7 @@ class BingWallpaperIndicator extends Button { let newImage = Utils.getImageByIndex(imageList, curIndex + relativePos); if (newImage) - this._settings.set_string('selected-image', newImage.urlbase.replace('/th?id=OHR.', '')); + this._setStringSetting('selected-image', newImage.urlbase.replace('/th?id=OHR.', '')); } _getCurrentImage() { @@ -645,10 +684,17 @@ class BingWallpaperIndicator extends Button { this._restartTimeout(); let market = this._settings.get_string('market'); + // Soup3 should be the version used, but in the past some distros have packaged older versions only if (Soup.MAJOR_VERSION >= 3) { let url = BingImageURL; let params = Utils.BingParams; params['mkt'] = ( market != 'auto' ? market : '' ); + + // if we've set previous days to be something less than 8 and + // delete previous is active we want to just request a subset of wallpapers + if (this._settings.get_boolean('delete-previous') == true && this._settings.get_int('previous-days')<8) { + params['n'] = ""+this._settings.get_int('previous-days'); + } let request = Soup.Message.new_from_encoded_form('GET', url, Soup.form_encode_hash(params)); request.request_headers.append('Accept', 'application/json'); @@ -660,6 +706,7 @@ class BingWallpaperIndicator extends Button { } catch(error) { log('unable to send libsoup json message '+error); + notifyError('Unable to fetch Bing metadata\n'+error); } } else { @@ -675,6 +722,7 @@ class BingWallpaperIndicator extends Button { } catch (error) { log('unable to send libsoup json message '+error); + notifyError('Unable to fetch Bing metadata\n'+error); } } } @@ -694,6 +742,7 @@ class BingWallpaperIndicator extends Button { } catch (error) { log('Network error occured: ' + error); + notifyError('network error occured\n'+error); this._updatePending = false; this._restartTimeout(TIMEOUT_SECONDS_ON_HTTP_ERROR); } @@ -759,13 +808,13 @@ class BingWallpaperIndicator extends Button { log('WARNING: Bing returning market data for ' + datamarket + ' rather than selected ' + prefmarket); Utils.purgeImages(this._settings); // delete older images if enabled - //Utils.cleanupImageList(this._settings); // disabled, as old images should still be downloadble in theory + //Utils.cleanupImageList(this._settings); // merged into purgeImages this._downloadAllImages(); // fetch missing images that are still available Utils.populateImageListResolutions(this._settings); if (newImages.length > 0 && this._settings.get_boolean('revert-to-current-image')) { // user wants to switch to the new image when it arrives - this._settings.set_string('selected-image', 'current'); + this._setStringSetting('selected-image', 'current'); } if (this._settings.get_boolean('notify')) { @@ -773,7 +822,7 @@ class BingWallpaperIndicator extends Button { // notify all new images newImages.forEach((image) => { log('New image to notify: ' + Utils.getImageTitle(image)); - this._createNotification(image); + this._createImageNotification(image); }); } else { @@ -781,7 +830,7 @@ class BingWallpaperIndicator extends Button { let last = newImages.pop(); if (last) { log('New image to notify: ' + Utils.getImageTitle(last)); - this._createNotification(last); + this._createImageNotification(last); } } } @@ -791,6 +840,7 @@ class BingWallpaperIndicator extends Button { } catch (error) { log('_parseData() failed with error ' + error + ' @ '+error.lineNumber); + notifyError('Bing metadata parsing error check ' + error + ' @ '+error.lineNumber); log(error.stack); } } @@ -801,15 +851,25 @@ class BingWallpaperIndicator extends Button { } } - _createNotification(image) { - // set notifications icon - let source = new MessageTray.Source('Bing Wallpaper', 'preferences-desktop-wallpaper-symbolic'); - Main.messageTray.add(source); + _createImageNotification(image) { let msg = _('Bing Wallpaper of the Day for') + ' ' + this._localeDate(image.fullstartdate); let details = Utils.getImageTitle(image); - let notification = new MessageTray.Notification(source, msg, details); - notification.setTransient(this._settings.get_boolean('transient')); - source.showNotification(notification); + this._createNotification(msg, details); + log('_createImageNotification: '+msg+' details: '+details); + } + + _createNotification(msg, details) { + const systemSource = MessageTray.getSystemSource(); + const bingNotify = new MessageTray.Notification({ + source: systemSource, + title: msg, + body: details, + gicon: new Gio.ThemedIcon({name: 'image-x-generic'}), + iconName: 'image-x-generic', + }); + systemSource.addNotification(bingNotify); + //Main.notify(msg, details); + log('_createNotification: '+msg+' details: '+details); } _shuffleImage() { @@ -889,7 +949,7 @@ class BingWallpaperIndicator extends Button { this.dimensions.width = image.width?image.width:null; this.dimensions.height = image.height?image.height:null; this.selected_image = Utils.getImageUrlBase(image); - this._settings.set_string('selected-image', this.selected_image); + this._setStringSetting('selected-image', this.selected_image); if (("favourite" in image) && image.favourite === true ) { this.favourite_status = true; @@ -944,14 +1004,14 @@ class BingWallpaperIndicator extends Button { let stateJSON = JSON.stringify(state); log('Storing state as JSON: ' + stateJSON); - this._settings.set_string('state', stateJSON); + this._setStringSetting('state', stateJSON); } } _reStoreState() { try { // patch for relative paths, ensures that users running git version don't end up with broken state - see EGO review for version 38 https://extensions.gnome.org/review/30299 - this._settings.set_string('download-folder', this._settings.get_string('download-folder').replace('$HOME', '~')); + this._setStringSetting('download-folder', this._settings.get_string('download-folder').replace('$HOME', '~')); let stateJSON = this._settings.get_string('state'); let state = JSON.parse(stateJSON); let maxLongDate = null; @@ -1015,7 +1075,9 @@ class BingWallpaperIndicator extends Button { let BingWallpaperDir = Utils.getWallpaperDir(this._settings); let dir = Gio.file_new_for_path(BingWallpaperDir); if (!dir.query_exists(null)) { - dir.make_directory_with_parents(null); + //dir.make_directory_with_parents(null); + notifyError('Download folder '+BingWallpaperDir+' does not exist or is not writable'); + return; } log("Downloading " + url + " to " + file.get_uri()); let request = Soup.Message.new('GET', url); @@ -1035,6 +1097,7 @@ class BingWallpaperIndicator extends Button { } catch (error) { log('error sending libsoup message '+error); + notifyError('Network error '+error); } } @@ -1059,12 +1122,14 @@ class BingWallpaperIndicator extends Button { } catch(e) { log('Error writing file: ' + e); + notifyError('Image '+file.get_path()+' is not writable, check folder permissions or select a different folder\n'+e); } } ); } catch (error) { log('Unable download image '+error); + notifyError('Image '+file.get_path()+' file error, check folder permissions, disk space or select a different folder\n'+e); } } diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/cs/LC_MESSAGES/BingWallpaper.mo b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/cs/LC_MESSAGES/BingWallpaper.mo index 7a93e54..27c1a6f 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/cs/LC_MESSAGES/BingWallpaper.mo and b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/cs/LC_MESSAGES/BingWallpaper.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/de/LC_MESSAGES/BingWallpaper.mo b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/de/LC_MESSAGES/BingWallpaper.mo index 8842884..f93b804 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/de/LC_MESSAGES/BingWallpaper.mo and b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/de/LC_MESSAGES/BingWallpaper.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/fa_IR/LC_MESSAGES/BingWallpaper.mo b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/fa_IR/LC_MESSAGES/BingWallpaper.mo new file mode 100644 index 0000000..ec28f70 Binary files /dev/null and b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/fa_IR/LC_MESSAGES/BingWallpaper.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/it/LC_MESSAGES/BingWallpaper.mo b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/it/LC_MESSAGES/BingWallpaper.mo index 2f74f53..89c35e9 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/it/LC_MESSAGES/BingWallpaper.mo and b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/it/LC_MESSAGES/BingWallpaper.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/pt_BR/LC_MESSAGES/BingWallpaper.mo b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/pt_BR/LC_MESSAGES/BingWallpaper.mo index 618d397..dc715c9 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/pt_BR/LC_MESSAGES/BingWallpaper.mo and b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/pt_BR/LC_MESSAGES/BingWallpaper.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/ru_RU/LC_MESSAGES/BingWallpaper.mo b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/ru_RU/LC_MESSAGES/BingWallpaper.mo index bcc78b3..f920373 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/ru_RU/LC_MESSAGES/BingWallpaper.mo and b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/ru_RU/LC_MESSAGES/BingWallpaper.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/tr/LC_MESSAGES/BingWallpaper.mo b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/tr/LC_MESSAGES/BingWallpaper.mo index 18fa19b..469b170 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/tr/LC_MESSAGES/BingWallpaper.mo and b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/tr/LC_MESSAGES/BingWallpaper.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/uk/LC_MESSAGES/BingWallpaper.mo b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/uk/LC_MESSAGES/BingWallpaper.mo index 574e917..bed788d 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/uk/LC_MESSAGES/BingWallpaper.mo and b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/uk/LC_MESSAGES/BingWallpaper.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/zh_CN/LC_MESSAGES/BingWallpaper.mo b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/zh_CN/LC_MESSAGES/BingWallpaper.mo index b2e8a82..d9d4e82 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/zh_CN/LC_MESSAGES/BingWallpaper.mo and b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/locale/zh_CN/LC_MESSAGES/BingWallpaper.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/metadata.json b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/metadata.json index 8d55d13..43b2bc4 100644 --- a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/metadata.json +++ b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/metadata.json @@ -6,9 +6,10 @@ "settings-schema": "org.gnome.shell.extensions.bingwallpaper", "shell-version": [ "45", - "46" + "46", + "47" ], "url": "https://github.com/neffo/bing-wallpaper-gnome-extension", "uuid": "BingWallpaper@ineffable-gmail.com", - "version": 49 + "version": 50 } \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/prefs.js b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/prefs.js index a2a1c20..228a467 100644 --- a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/prefs.js +++ b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/prefs.js @@ -73,6 +73,8 @@ export default class BingWallpaperExtensionPreferences extends ExtensionPreferen const debugSwitch = buildable.get_object('debug_switch'); const revertSwitch = buildable.get_object('revert_switch'); const trash_purge_switch = buildable.get_object('trash_purge_switch'); + const delete_previous_switch = buildable.get_object('delete_previous_switch'); + const delete_previous_adjustment = buildable.get_object('delete_previous_adjustment'); const always_export_switch = buildable.get_object('always_export_switch'); const gallery_page = buildable.get_object('gallery_page'); const carouselFlowBox = buildable.get_object('carouselFlowBox'); @@ -213,6 +215,7 @@ export default class BingWallpaperExtensionPreferences extends ExtensionPreferen settings.bind('random-interval', randomIntervalEntry, 'value', Gio.SettingsBindFlags.DEFAULT); settings.bind('trash-deletes-images', trash_purge_switch, 'active', Gio.SettingsBindFlags.DEFAULT); settings.bind('always-export-bing-json', always_export_switch, 'active', Gio.SettingsBindFlags.DEFAULT); + settings.bind('delete-previous', delete_previous_switch, 'active', Gio.SettingsBindFlags.DEFAULT); // button opens Nautilus at our image folder openBtn.connect('clicked', (widget) => { @@ -276,6 +279,7 @@ export default class BingWallpaperExtensionPreferences extends ExtensionPreferen settings.bind('override-lockscreen-blur', overrideSwitch, 'active', Gio.SettingsBindFlags.DEFAULT); settings.bind('lockscreen-blur-strength', strengthEntry, 'value', Gio.SettingsBindFlags.DEFAULT); settings.bind('lockscreen-blur-brightness', brightnessEntry, 'value', Gio.SettingsBindFlags.DEFAULT); + settings.bind('previous-days', delete_previous_adjustment, 'value', Gio.SettingsBindFlags.DEFAULT); // add a couple of preset buttons defaultBtn.connect('clicked', (widget) => { diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/schemas/gschemas.compiled b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/schemas/gschemas.compiled index bdd63d2..fd85d11 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/schemas/gschemas.compiled and b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/schemas/gschemas.compiled differ diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/schemas/org.gnome.shell.extensions.bingwallpaper.gschema.xml b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/schemas/org.gnome.shell.extensions.bingwallpaper.gschema.xml index b01c105..9d9143d 100644 --- a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/schemas/org.gnome.shell.extensions.bingwallpaper.gschema.xml +++ b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/schemas/org.gnome.shell.extensions.bingwallpaper.gschema.xml @@ -69,7 +69,14 @@ Save disk space + + true + Keep previous wallpapers if they are favourites + Sensible default behaivour + + + 8 Number of days to keep wallpapers Delete wallpapers after this number of days diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/ui/carousel4.ui b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/ui/carousel4.ui index c322874..4953091 100644 --- a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/ui/carousel4.ui +++ b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/ui/carousel4.ui @@ -162,7 +162,7 @@ Author: Michael Carroll - Set random mode + Image shuffle mode 1 0 diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/ui/prefsadw.ui b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/ui/prefsadw.ui index 538035c..2d48805 100644 --- a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/ui/prefsadw.ui +++ b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/ui/prefsadw.ui @@ -201,6 +201,11 @@ Bing Wallpaper GNOME extension by: Michael Carroll Enable logging to system journal + + + + + Advanced options Always show new images @@ -210,7 +215,7 @@ Bing Wallpaper GNOME extension by: Michael Carroll Purge on trash - Trashing an image will remove it from database + Trashing an image will remove it from database and disk @@ -233,6 +238,26 @@ Bing Wallpaper GNOME extension by: Michael Carroll + + + Delete older images + Automatically delete older images (excludes favourites) + + + + + Number of days to keep images + Keep images for this number of days (favourites are kept forever) + + + 1 + 90 + 5 + 1 + + + + diff --git a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/utils.js b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/utils.js index 1ebe159..7c9f1ef 100644 --- a/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/utils.js +++ b/gnome/.local/share/gnome-shell/extensions/BingWallpaper@ineffable-gmail.com/utils.js @@ -118,14 +118,16 @@ export function fetch_change_log(version, label, httpSession) { httpSession.send_and_read_async(request, GLib.PRIORITY_DEFAULT, null, (httpSession, message) => { let data = decoder.decode(httpSession.send_and_read_finish(message).get_data()); let text = JSON.parse(data).body; - label.set_label(text); + if (text) + label.set_label(text); }); } else { httpSession.queue_message(request, (httpSession, message) => { let data = message.response_body.data; let text = JSON.parse(data).body; - label.set_label(text); + if (text) + label.set_label(text); }); } } @@ -299,26 +301,6 @@ export function getImageByIndex(imageList, index) { return imageList[index]; } -export function cleanupImageList(settings) { - if (settings.get_boolean('trash-deletes-images') == false) - return; - let curList = imageListSortByDate(getImageList(settings)); - let cutOff = GLib.DateTime.new_now_utc().add_days(-8); // 8 days ago - let newList = []; - curList.forEach( function (x, i) { - let filename = imageToFilename(settings, x); - let diff = dateFromLongDate(x.fullstartdate, 0).difference(cutOff); - // image is still downloadable (< 8 days old) or still on disk, so we keep - if (diff > 0 || Gio.file_new_for_path(filename).query_exists(null)) { - newList.push(x); - } - else { - BingLog('Cleaning up: '+filename); - } - }); - setImageList(settings, newList); -} - export function populateImageListResolutions(settings) { let curList = imageListSortByDate(getImageList(settings)); let newList = []; @@ -337,7 +319,11 @@ export function populateImageListResolutions(settings) { export function getFetchableImageList(settings) { let imageList = getImageList(settings); - let cutOff = GLib.DateTime.new_now_utc().add_days(-8); // 8 days ago + let maxpictures = settings.get_int('previous-days'); + let maxdownload = 8; + if (maxpictures < maxdownload && maxpictures >=1) + maxdownload = maxpictures; + let cutOff = GLib.DateTime.new_now_utc().add_days(-maxdownload); // default 8 days ago, 1 day = 1 picture let dlList = []; imageList.forEach( function (x, i) { let diff = dateFromLongDate(x.fullstartdate, 0).difference(cutOff); @@ -369,7 +355,10 @@ export function getWallpaperDir(settings) { dir.make_directory_with_parents(null); } //FIXME: test if dir is good and writable - return BingWallpaperDir; + if (dir.query_exists(null)) + return BingWallpaperDir; + else + return null; } export function setWallpaperDir(settings, uri) { @@ -547,24 +536,43 @@ export function deleteImage(to_delete) { } } -// add image to persistant list so we can delete it later (in chronological order), delete the oldest image (if user wants this) +// optionally purge trashed images (default is not, these just don't get select in random mode), optionally purge older images export function purgeImages(settings) { - let deletepictures = settings.get_boolean('delete-previous'); - if (deletepictures === false) - return; + let deleteprevious = settings.get_boolean('delete-previous'); + let keepfavourites = settings.get_boolean('keep-favourites'); + let emptytrash = settings.get_boolean('trash-deletes-images'); + let maxDays = settings.get_int('previous-days'); + BingLog('purgeImages() dp: '+(deleteprevious?'true':'false')+'days:'+maxDays+' favs: '+(keepfavourites?'true':'false')+' trash: '+(emptytrash?'true':'false')); + + /*if (deleteprevious === false) + return;*/ let imagelist = imageListSortByDate(getImageList(settings)); - let maxpictures = settings.get_int('previous-days'); let origlength = imagelist.length; - while (imagelist.length > maxpictures) { - var to_delete = imagelist.shift(); // get the first (oldest item from the list) - if (deletepictures && to_delete != '') { - let imageFilename = imageToFilename(settings, to_delete); + let cutOff = GLib.DateTime.new_now_utc().add_days(-maxDays); // 8 days ago + let newList = []; + imagelist.forEach( function (image, i) { + var diff = dateFromLongDate(image.fullstartdate, 0).difference(cutOff); // relative age of image, < 0 we can delete + // always keep favourites, keep images that are less than minimum period (previous days) or if clean up delete previous is disabled (default) + var keep_image = (keepfavourites && image.favourite && image.favourite === true) || diff > 0 || !deleteprevious; + var ok_to_delete = !keep_image || (emptytrash && image.hidden); + var imageFilename = imageToFilename(settings, image); + + if (emptytrash && image.hidden && diff < 0) + ok_to_delete = true; + + + if (deleteprevious && image != '' && ok_to_delete) { BingLog('deleting '+imageFilename); deleteImage(imageFilename); } - } + else { + BingLog('keeping '+imageFilename); + newList.push(image); + } + }); + setImageList(settings, newList); BingLog('cleaned up image list, count was '+origlength+' now '+imagelist.length); - cleanupImageList(settings); + //cleanupImageList(settings); validate_imagename(settings); // if we deleted our current image, we want to reset it to something valid } @@ -605,7 +613,8 @@ export function importBingJSON(settings) { let parsed = JSON.parse(decoder.decode(contents)); // FIXME: triggers GJS warning without the conversion, need to investigate // need to implement some checks for validity here mergeImageLists(settings, parsed); - cleanupImageList(settings); // remove the older missing images + purgeImages(settings); // remove the older missing images + //cleanupImageList(settings); } } else { diff --git a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/convenience.js b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/convenience.js index 33c9f99..d507fc9 100644 --- a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/convenience.js +++ b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/convenience.js @@ -33,7 +33,7 @@ var debugEnabled = false; /** * @param {boolean} d Enable/Disable debug logging */ -function setDebugEnabled(d) { +export function setDebugEnabled(d) { debugEnabled = d; } @@ -41,9 +41,9 @@ function setDebugEnabled(d) { * @param {string} msg the message to log * @class */ -function TalkativeLog(msg) { +export function TalkativeLog(msg) { if (debugEnabled) - log(`[ESC]${msg}`); + console.log(`[ESC]${msg}`); } /** @@ -53,8 +53,8 @@ function TalkativeLog(msg) { * * @returns {string} the version */ -function getFullVersion() { - return '1.9.0'; // FULL_VERSION +export function getFullVersion() { + return '1.10.0'; // FULL_VERSION } /** @@ -64,7 +64,7 @@ function getFullVersion() { * @param {string} name filename of the image * @returns {Gio.FileIcon} the icon */ -function loadIcon(extensionDir, name) { +export function loadIcon(extensionDir, name) { return new Gio.FileIcon({ file: Gio.File.new_for_path( getImagePath(extensionDir, name) @@ -79,8 +79,6 @@ function loadIcon(extensionDir, name) { * @param {string} name filename of the image * @returns {string} the path */ -function getImagePath(extensionDir, name) { +export function getImagePath(extensionDir, name) { return extensionDir.get_child(`images/${name}`).get_path(); } - -export {TalkativeLog, getFullVersion, setDebugEnabled, loadIcon, getImagePath}; diff --git a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/display_module.js b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/display_module.js index 1f1702b..ceff7cc 100644 --- a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/display_module.js +++ b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/display_module.js @@ -3,7 +3,7 @@ /** * @type {{_display(): Meta_Display, number_of_displays(): int}} */ -var DisplayApi = { +export const DisplayApi = { /** * Returns the Wayland display or screen * @@ -36,5 +36,3 @@ var DisplayApi = { this._display().set_cursor(cursor); }, }; - -export {DisplayApi}; diff --git a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/metadata.json b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/metadata.json index 5fb398b..b0c7dfb 100644 --- a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/metadata.json +++ b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/metadata.json @@ -5,9 +5,10 @@ "name": "EasyScreenCast", "settings-schema": "org.gnome.shell.extensions.EasyScreenCast", "shell-version": [ - "46" + "46", + "47" ], "url": "https://github.com/EasyScreenCast/EasyScreenCast", "uuid": "EasyScreenCast@iacopodeenosee.gmail.com", - "version": 50 + "version": 51 } \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/selection.js b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/selection.js index 0ed9c7a..c59076c 100644 --- a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/selection.js +++ b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/selection.js @@ -27,6 +27,7 @@ import Meta from 'gi://Meta'; import Clutter from 'gi://Clutter'; import St from 'gi://St'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; +import * as Signals from 'resource:///org/gnome/shell/misc/signals.js'; import {gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js'; @@ -38,15 +39,7 @@ import {DisplayApi} from './display_module.js'; /** * @type {Capture} */ -const Capture = GObject.registerClass({ - GTypeName: 'EasyScreenCast_Capture', - Signals: { - 'captured-event': { - param_types: [Clutter.Event.$gtype], - }, - 'stop': {}, - }, -}, class Capture extends GObject.Object { +class Capture extends Signals.EventEmitter { constructor() { super(); Lib.TalkativeLog('-£-capture selection init'); @@ -183,14 +176,9 @@ const Capture = GObject.registerClass({ toString() { return this.GTypeName; } -}); +} -var SelectionArea = GObject.registerClass({ - GTypeName: 'EasyScreenCast_SelectionArea', - Signals: { - 'stop': {}, - }, -}, class SelectionArea extends GObject.Object { +export class SelectionArea extends Signals.EventEmitter { constructor() { super(); Lib.TalkativeLog('-£-area selection init'); @@ -238,14 +226,9 @@ var SelectionArea = GObject.registerClass({ toString() { return this.GTypeName; } -}); +} -var SelectionWindow = GObject.registerClass({ - GTypeName: 'EasyScreenCast_SelectionWindow', - Signals: { - 'stop': {}, - }, -}, class SelectionWindow extends GObject.Object { +export class SelectionWindow extends Signals.EventEmitter { constructor() { super(); Lib.TalkativeLog('-£-window selection init'); @@ -285,12 +268,12 @@ var SelectionWindow = GObject.registerClass({ if (this._selectedWindow) { this._capture._stop(); - var maxHeight = global.screen_height; - var maxWidth = global.screen_width; + let maxHeight = global.screen_height; + let maxWidth = global.screen_width; Lib.TalkativeLog(`-£-global screen area H: ${maxHeight} W: ${maxWidth}`); - var [w, h] = this._selectedWindow.get_size(); - var [wx, wy] = this._selectedWindow.get_position(); + let [w, h] = this._selectedWindow.get_size(); + let [wx, wy] = this._selectedWindow.get_position(); Lib.TalkativeLog(`-£-windows pre wx: ${wx} wy: ${wy} height: ${h} width: ${w}`); @@ -331,22 +314,17 @@ var SelectionWindow = GObject.registerClass({ toString() { return this.GTypeName; } -}); +} -var SelectionDesktop = GObject.registerClass({ - GTypeName: 'EasyScreenCast_SelectionDesktop', - Signals: { - 'stop': {}, - }, -}, class SelectionDesktop extends GObject.Object { +export class SelectionDesktop extends Signals.EventEmitter { constructor() { super(); Lib.TalkativeLog('-£-desktop selection init'); const displayCount = DisplayApi.number_displays(); Lib.TalkativeLog(`-£-Number of monitor ${displayCount}`); - for (var i = 0; i < displayCount; i++) { - var tmpM = DisplayApi.display_geometry_for_index(i); + for (let i = 0; i < displayCount; i++) { + let tmpM = DisplayApi.display_geometry_for_index(i); Lib.TalkativeLog(`-£-monitor ${i} geometry x=${tmpM.x} y=${tmpM.y} w=${tmpM.width} h=${tmpM.height}`); } @@ -376,10 +354,10 @@ var SelectionDesktop = GObject.registerClass({ let tmpM = Main.layoutManager.currentMonitor; - var x = tmpM.x; - var y = tmpM.y; - var height = tmpM.height; - var width = tmpM.width; + let x = tmpM.x; + let y = tmpM.y; + let height = tmpM.height; + let width = tmpM.width; Lib.TalkativeLog(`-£-desktop x: ${x} y: ${y} height: ${height} width: ${width}`); this._capture._saveRect(x, y, height, width); @@ -389,11 +367,9 @@ var SelectionDesktop = GObject.registerClass({ toString() { return this.GTypeName; } -}); +} -var AreaRecording = GObject.registerClass({ - GTypeName: 'EasyScreenCast_AreaRecording', -}, class AreaRecording extends GObject.Object { +export class AreaRecording extends GObject.Object { constructor() { super(); Lib.TalkativeLog('-£-area recording init'); @@ -407,9 +383,9 @@ var AreaRecording = GObject.registerClass({ y: -10, }); - var [recX, recY, recW, recH] = Ext.Indicator.getSelectedRect(); - var tmpH = Main.layoutManager.currentMonitor.height; - var tmpW = Main.layoutManager.currentMonitor.width; + let [recX, recY, recW, recH] = Ext.Indicator.getSelectedRect(); + let tmpH = Main.layoutManager.currentMonitor.height; + let tmpW = Main.layoutManager.currentMonitor.width; Main.uiGroup.add_child(this._areaRecording); @@ -463,7 +439,7 @@ var AreaRecording = GObject.registerClass({ toString() { return this.GTypeName; } -}); +} /** * @param {number} x1 left position @@ -530,5 +506,3 @@ function _selectWindow(windows, x, y) { return filtered[0]; } - -export {SelectionArea, SelectionWindow, SelectionDesktop, AreaRecording}; diff --git a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/settings.js b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/settings.js index 290d2f2..5d67302 100644 --- a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/settings.js +++ b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/settings.js @@ -15,51 +15,51 @@ import GObject from 'gi://GObject'; // setting keys -var INPUT_AUDIO_SOURCE_SETTING_KEY = 'input-audio-source'; -var ACTIVE_POST_CMD_SETTING_KEY = 'execute-post-cmd'; -var POST_CMD_SETTING_KEY = 'post-cmd'; -var ACTIVE_PRE_CMD_SETTING_KEY = 'execute-pre-cmd'; -var PRE_CMD_SETTING_KEY = 'pre-cmd'; -var ACTIVE_CUSTOM_GSP_SETTING_KEY = 'active-custom-gsp'; -var ACTIVE_SHORTCUT_SETTING_KEY = 'active-shortcut'; -var SHORTCUT_KEY_SETTING_KEY = 'shortcut-key'; -var TIME_DELAY_SETTING_KEY = 'delay-time'; -var SHOW_NOTIFY_ALERT_SETTING_KEY = 'show-notify-alert'; -var SHOW_AREA_REC_SETTING_KEY = 'show-area-rec'; -var VERBOSE_DEBUG_SETTING_KEY = 'verbose-debug'; -var PIPELINE_REC_SETTING_KEY = 'pipeline'; -var FPS_SETTING_KEY = 'fps'; -var STATUS_INDICATORS_SETTING_KEY = 'status-indicators'; -var X_POS_SETTING_KEY = 'x-pos'; -var Y_POS_SETTING_KEY = 'y-pos'; -var WIDTH_SETTING_KEY = 'width-rec'; -var HEIGHT_SETTING_KEY = 'height-rec'; -var DRAW_CURSOR_SETTING_KEY = 'draw-cursor'; -var AREA_SCREEN_SETTING_KEY = 'area-screen'; -var FILE_NAME_SETTING_KEY = 'file-name'; -var FILE_FOLDER_SETTING_KEY = 'file-folder'; -var FILE_CONTAINER_SETTING_KEY = 'file-container'; -var FILE_RESOLUTION_TYPE_SETTING_KEY = 'file-resolution-type'; -var FILE_RESOLUTION_KAR_SETTING_KEY = 'file-resolution-kar'; -var FILE_RESOLUTION_WIDTH_SETTING_KEY = 'file-resolution-width'; -var FILE_RESOLUTION_HEIGHT_SETTING_KEY = 'file-resolution-height'; -var QUALITY_SETTING_KEY = 'quality-index'; -var DEVICE_INDEX_WEBCAM_SETTING_KEY = 'device-webcam-index'; -var DEVICE_WEBCAM_SETTING_KEY = 'device-webcam'; -var QUALITY_WEBCAM_SETTING_KEY = 'quality-webcam'; -var WIDTH_WEBCAM_SETTING_KEY = 'width-webcam'; -var HEIGHT_WEBCAM_SETTING_KEY = 'height-webcam'; -var TYPE_UNIT_WEBCAM_SETTING_KEY = 'type-unit-webcam'; -var MARGIN_X_WEBCAM_SETTING_KEY = 'margin-x-webcam'; -var MARGIN_Y_WEBCAM_SETTING_KEY = 'margin-y-webcam'; -var ALPHA_CHANNEL_WEBCAM_SETTING_KEY = 'alpha-channel-webcam'; -var CORNER_POSITION_WEBCAM_SETTING_KEY = 'corner-position-webcam'; +export const INPUT_AUDIO_SOURCE_SETTING_KEY = 'input-audio-source'; +export const ACTIVE_POST_CMD_SETTING_KEY = 'execute-post-cmd'; +export const POST_CMD_SETTING_KEY = 'post-cmd'; +export const ACTIVE_PRE_CMD_SETTING_KEY = 'execute-pre-cmd'; +export const PRE_CMD_SETTING_KEY = 'pre-cmd'; +export const ACTIVE_CUSTOM_GSP_SETTING_KEY = 'active-custom-gsp'; +export const ACTIVE_SHORTCUT_SETTING_KEY = 'active-shortcut'; +export const SHORTCUT_KEY_SETTING_KEY = 'shortcut-key'; +export const TIME_DELAY_SETTING_KEY = 'delay-time'; +export const SHOW_NOTIFY_ALERT_SETTING_KEY = 'show-notify-alert'; +export const SHOW_AREA_REC_SETTING_KEY = 'show-area-rec'; +export const VERBOSE_DEBUG_SETTING_KEY = 'verbose-debug'; +export const PIPELINE_REC_SETTING_KEY = 'pipeline'; +export const FPS_SETTING_KEY = 'fps'; +export const STATUS_INDICATORS_SETTING_KEY = 'status-indicators'; +export const X_POS_SETTING_KEY = 'x-pos'; +export const Y_POS_SETTING_KEY = 'y-pos'; +export const WIDTH_SETTING_KEY = 'width-rec'; +export const HEIGHT_SETTING_KEY = 'height-rec'; +export const DRAW_CURSOR_SETTING_KEY = 'draw-cursor'; +export const AREA_SCREEN_SETTING_KEY = 'area-screen'; +export const FILE_NAME_SETTING_KEY = 'file-name'; +export const FILE_FOLDER_SETTING_KEY = 'file-folder'; +export const FILE_CONTAINER_SETTING_KEY = 'file-container'; +export const FILE_RESOLUTION_TYPE_SETTING_KEY = 'file-resolution-type'; +export const FILE_RESOLUTION_KAR_SETTING_KEY = 'file-resolution-kar'; +export const FILE_RESOLUTION_WIDTH_SETTING_KEY = 'file-resolution-width'; +export const FILE_RESOLUTION_HEIGHT_SETTING_KEY = 'file-resolution-height'; +export const QUALITY_SETTING_KEY = 'quality-index'; +export const DEVICE_INDEX_WEBCAM_SETTING_KEY = 'device-webcam-index'; +export const DEVICE_WEBCAM_SETTING_KEY = 'device-webcam'; +export const QUALITY_WEBCAM_SETTING_KEY = 'quality-webcam'; +export const WIDTH_WEBCAM_SETTING_KEY = 'width-webcam'; +export const HEIGHT_WEBCAM_SETTING_KEY = 'height-webcam'; +export const TYPE_UNIT_WEBCAM_SETTING_KEY = 'type-unit-webcam'; +export const MARGIN_X_WEBCAM_SETTING_KEY = 'margin-x-webcam'; +export const MARGIN_Y_WEBCAM_SETTING_KEY = 'margin-y-webcam'; +export const ALPHA_CHANNEL_WEBCAM_SETTING_KEY = 'alpha-channel-webcam'; +export const CORNER_POSITION_WEBCAM_SETTING_KEY = 'corner-position-webcam'; // shortcut tree view columns -var SHORTCUT_COLUMN_KEY = 0; -var SHORTCUT_COLUMN_MODS = 1; +export const SHORTCUT_COLUMN_KEY = 0; +export const SHORTCUT_COLUMN_MODS = 1; -var Settings = GObject.registerClass(class EasyScreenCastSettings extends GObject.Object { +export const Settings = GObject.registerClass(class EasyScreenCastSettings extends GObject.Object { constructor(settings) { super(); this._settings = settings; @@ -137,56 +137,10 @@ var Settings = GObject.registerClass(class EasyScreenCastSettings extends GObjec * @param {boolean} audio with or without audio * @returns {string} */ -function getGSPstd(audio) { +export function getGSPstd(audio) { // TODO update gsp if (audio) return 'queue max-size-buffers=0 max-size-time=0 max-size-bytes=0 ! videorate ! vp8enc min_quantizer=0 max_quantizer=5 cpu-used=3 deadline=1000000 threads=%T ! queue max-size-buffers=0 max-size-time=0 max-size-bytes=0 ! mux. pulsesrc ! queue max-size-buffers=0 max-size-time=0 max-size-bytes=0 ! audioconvert ! vorbisenc ! queue max-size-buffers=0 max-size-time=0 max-size-bytes=0 ! mux. webmmux name=mux '; else return 'vp9enc min_quantizer=0 max_quantizer=5 cpu-used=3 deadline=1000000 threads=%T ! queue max-size-buffers=0 max-size-time=0 max-size-bytes=0 ! webmmux'; } - -export { - getGSPstd, - Settings, - INPUT_AUDIO_SOURCE_SETTING_KEY, - ACTIVE_POST_CMD_SETTING_KEY, - POST_CMD_SETTING_KEY, - ACTIVE_PRE_CMD_SETTING_KEY, - PRE_CMD_SETTING_KEY, - ACTIVE_CUSTOM_GSP_SETTING_KEY, - ACTIVE_SHORTCUT_SETTING_KEY, - SHORTCUT_KEY_SETTING_KEY, - TIME_DELAY_SETTING_KEY, - SHOW_NOTIFY_ALERT_SETTING_KEY, - SHOW_AREA_REC_SETTING_KEY, - VERBOSE_DEBUG_SETTING_KEY, - PIPELINE_REC_SETTING_KEY, - FPS_SETTING_KEY, - STATUS_INDICATORS_SETTING_KEY, - X_POS_SETTING_KEY, - Y_POS_SETTING_KEY, - WIDTH_SETTING_KEY, - HEIGHT_SETTING_KEY, - DRAW_CURSOR_SETTING_KEY, - AREA_SCREEN_SETTING_KEY, - FILE_NAME_SETTING_KEY, - FILE_FOLDER_SETTING_KEY, - FILE_CONTAINER_SETTING_KEY, - FILE_RESOLUTION_TYPE_SETTING_KEY, - FILE_RESOLUTION_KAR_SETTING_KEY, - FILE_RESOLUTION_WIDTH_SETTING_KEY, - FILE_RESOLUTION_HEIGHT_SETTING_KEY, - QUALITY_SETTING_KEY, - DEVICE_INDEX_WEBCAM_SETTING_KEY, - DEVICE_WEBCAM_SETTING_KEY, - QUALITY_WEBCAM_SETTING_KEY, - WIDTH_WEBCAM_SETTING_KEY, - HEIGHT_WEBCAM_SETTING_KEY, - TYPE_UNIT_WEBCAM_SETTING_KEY, - MARGIN_X_WEBCAM_SETTING_KEY, - MARGIN_Y_WEBCAM_SETTING_KEY, - ALPHA_CHANNEL_WEBCAM_SETTING_KEY, - CORNER_POSITION_WEBCAM_SETTING_KEY, - SHORTCUT_COLUMN_KEY, - SHORTCUT_COLUMN_MODS -}; diff --git a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/timer.js b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/timer.js index 9e35712..ca168f1 100644 --- a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/timer.js +++ b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/timer.js @@ -27,7 +27,7 @@ let ElapsedSec; /** * @type {TimerDelay} */ -const TimerDelay = GObject.registerClass({ +export const TimerDelay = GObject.registerClass({ GTypeName: 'EasyScreenCast_TimerDelay', }, class TimerDelay extends GObject.Object { /** @@ -145,7 +145,7 @@ let secpassed = 0; /** * @type {TimerCounting} */ -var TimerCounting = GObject.registerClass({ +export const TimerCounting = GObject.registerClass({ GTypeName: 'EasyScreenCast_TimerCounting', }, class TimerCounting extends GObject.Object { /** @@ -255,5 +255,3 @@ var TimerCounting = GObject.registerClass({ } } }); - -export {TimerDelay, TimerCounting}; diff --git a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilaudio.js b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilaudio.js index 27201fc..b07e181 100644 --- a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilaudio.js +++ b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilaudio.js @@ -27,7 +27,7 @@ import * as Ext from './extension.js'; /** * @type {MixerAudio} */ -var MixerAudio = GObject.registerClass({ +export const MixerAudio = GObject.registerClass({ GTypeName: 'EasyScreenCast_MixerAudio', }, class MixerAudio extends GObject.Object { constructor() { @@ -317,5 +317,3 @@ var MixerAudio = GObject.registerClass({ } } }); - -export {MixerAudio}; diff --git a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilexecmd.js b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilexecmd.js index 2ee88c6..058b810 100644 --- a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilexecmd.js +++ b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilexecmd.js @@ -20,7 +20,7 @@ import * as Lib from './convenience.js'; /** * @type {ExecuteStuff} */ -var ExecuteStuff = GObject.registerClass({ +export const ExecuteStuff = GObject.registerClass({ GTypeName: 'EasyScreenCast_ExecuteStuff', }, class ExecuteStuff extends GObject.Object { /** @@ -262,5 +262,3 @@ var ExecuteStuff = GObject.registerClass({ } } }); - -export {ExecuteStuff}; diff --git a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilgsp.js b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilgsp.js index f9f45a3..e2bd0b9 100644 --- a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilgsp.js +++ b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilgsp.js @@ -321,7 +321,7 @@ const CONTAINER = [webmVP8, webmVP9, mp4, mkv, ogg, mp4Aac]; * * @returns {string} */ -function composeGSP(settings, mixer) { +export function composeGSP(settings, mixer) { Lib.TalkativeLog('-§-COMPOSE GSP'); let tmpGSP = ''; @@ -703,7 +703,7 @@ function _getWebCamDimension(settings) { * @param {int} container selected container format * @returns {string} */ -function getDescr(quality, container) { +export function getDescr(quality, container) { Lib.TalkativeLog(`-§-get description Q-> ${quality} C-> ${container}`); return CONTAINER[container].quality[quality].descr; @@ -716,7 +716,7 @@ function getDescr(quality, container) { * @param {int} container selected container format * @returns {number} */ -function getFps(quality, container) { +export function getFps(quality, container) { Lib.TalkativeLog(`-§-get fps Q-> ${quality} C-> ${container}`); return CONTAINER[container].quality[quality].fps; @@ -728,10 +728,8 @@ function getFps(quality, container) { * @param {int} container selected container format * @returns {string} */ -function getFileExtension(container) { +export function getFileExtension(container) { Lib.TalkativeLog(`-§-get file extension C-> ${container}`); return CONTAINER[container].fileExt; } - -export {composeGSP, getDescr, getFps, getFileExtension}; diff --git a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilnotify.js b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilnotify.js index 1bdb476..90f41b0 100644 --- a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilnotify.js +++ b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilnotify.js @@ -27,7 +27,7 @@ import {gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js' /** * @type {NotifyManager} */ -var NotifyManager = GObject.registerClass({ +export const NotifyManager = GObject.registerClass({ GTypeName: 'EasyScreenCast_NotifyManager', }, class NotifyManager extends GObject.Object { /** @@ -143,5 +143,3 @@ var NotifyManager = GObject.registerClass({ } } }); - -export {NotifyManager}; diff --git a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilrecorder.js b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilrecorder.js index 1b0a434..6ab68e9 100644 --- a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilrecorder.js +++ b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilrecorder.js @@ -27,7 +27,7 @@ import * as Ext from './extension.js'; /** * @type {CaptureVideo} */ -var CaptureVideo = GObject.registerClass({ +export const CaptureVideo = GObject.registerClass({ GTypeName: 'EasyScreenCast_CaptureVideo', }, class CaptureVideo extends GObject.Object { /** @@ -212,5 +212,3 @@ var CaptureVideo = GObject.registerClass({ return result; } }); - -export {CaptureVideo}; diff --git a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilwebcam.js b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilwebcam.js index d1ab076..2f43a36 100644 --- a/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilwebcam.js +++ b/gnome/.local/share/gnome-shell/extensions/EasyScreenCast@iacopodeenosee.gmail.com/utilwebcam.js @@ -17,7 +17,7 @@ import GLib from 'gi://GLib'; import Gst from 'gi://Gst?version=1.0'; import * as Lib from './convenience.js'; -var HelperWebcam = GObject.registerClass({ +export const HelperWebcam = GObject.registerClass({ GTypeName: 'EasyScreenCast_HelperWebcam', }, class HelperWebcam extends GObject.Object { /** @@ -241,10 +241,18 @@ var HelperWebcam = GObject.registerClass({ // example, a pipewiresrc or a v4l2src. For now, we are only // using v4l2src. // See also: Gst.DeviceMonitor.get_providers: pipewiredeviceprovider,decklinkdeviceprovider,v4l2deviceprovider + // CLI: "/usr/bin/gst-device-monitor-1.0 Video/Source" // // So, here we filter the devices, that have a device.path property, which // means, these are only v4l2 devices - var filtered = list.filter(device => device.get_properties().get_string('device.path') !== null); + + var filtered = list.filter(device => { + let props = device.get_properties(); + let hasDevice = props != null && props.get_string('device.path') !== null; + if (props != null) + props.free(); + return hasDevice; + }); Lib.TalkativeLog(`-@-devices number after filtering for v4l2: ${filtered.length}`); return filtered; @@ -311,5 +319,3 @@ var HelperWebcam = GObject.registerClass({ } } }); - -export {HelperWebcam}; diff --git a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/battery-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/battery-symbolic.svg index 70df9ee..28a9887 100644 --- a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/battery-symbolic.svg +++ b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/battery-symbolic.svg @@ -1,8 +1 @@ - - - - - - - - + \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/cpu-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/cpu-symbolic.svg index 86ca8bf..31c397b 100644 --- a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/cpu-symbolic.svg +++ b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/cpu-symbolic.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/fan-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/fan-symbolic.svg index ea2b44f..234f797 100644 --- a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/fan-symbolic.svg +++ b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/fan-symbolic.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/gpu-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/gpu-symbolic.svg index d5cf157..b59beda 100644 --- a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/gpu-symbolic.svg +++ b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/gpu-symbolic.svg @@ -1,15 +1 @@ - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/memory-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/memory-symbolic.svg index 1946901..7fb2200 100644 --- a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/memory-symbolic.svg +++ b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/memory-symbolic.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/network-download-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/network-download-symbolic.svg index 4fc170b..7ec91a8 100644 --- a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/network-download-symbolic.svg +++ b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/network-download-symbolic.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/network-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/network-symbolic.svg index 2ff9778..125ba60 100644 --- a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/network-symbolic.svg +++ b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/network-symbolic.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/network-upload-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/network-upload-symbolic.svg index 0d67f65..bd31f33 100644 --- a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/network-upload-symbolic.svg +++ b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/network-upload-symbolic.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/storage-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/storage-symbolic.svg index 30d9007..b0d4753 100644 --- a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/storage-symbolic.svg +++ b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/storage-symbolic.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/system-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/system-symbolic.svg index bfbf1bd..a041518 100644 --- a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/system-symbolic.svg +++ b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/system-symbolic.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/temperature-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/temperature-symbolic.svg index e00a2eb..ed976bf 100644 --- a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/temperature-symbolic.svg +++ b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/temperature-symbolic.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/voltage-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/voltage-symbolic.svg index 1aa2210..c786442 100644 --- a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/voltage-symbolic.svg +++ b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/icons/gnome/voltage-symbolic.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/locale/ar/LC_MESSAGES/vitals.mo b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/locale/ar/LC_MESSAGES/vitals.mo new file mode 100644 index 0000000..5d1d5ac Binary files /dev/null and b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/locale/ar/LC_MESSAGES/vitals.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/locale/cs/LC_MESSAGES/vitals.mo b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/locale/cs/LC_MESSAGES/vitals.mo index b468c53..1b2495d 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/locale/cs/LC_MESSAGES/vitals.mo and b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/locale/cs/LC_MESSAGES/vitals.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/locale/uk/LC_MESSAGES/vitals.mo b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/locale/uk/LC_MESSAGES/vitals.mo index c24b01b..9f11b14 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/locale/uk/LC_MESSAGES/vitals.mo and b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/locale/uk/LC_MESSAGES/vitals.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/metadata.json b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/metadata.json index 4c78f3a..cddf98d 100644 --- a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/metadata.json +++ b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/metadata.json @@ -9,9 +9,10 @@ "settings-schema": "org.gnome.shell.extensions.vitals", "shell-version": [ "45", - "46" + "46", + "47" ], "url": "https://github.com/corecoding/Vitals", "uuid": "Vitals@CoreCoding.com", - "version": 66 + "version": 69 } \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/prefs.ui b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/prefs.ui index ab07185..537decf 100644 --- a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/prefs.ui +++ b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/prefs.ui @@ -1222,6 +1222,7 @@ BAT0 BAT1 BAT2 + BATT CMB0 macsmc-battery diff --git a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/sensors.js b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/sensors.js index 2ba8c2e..10f93c7 100644 --- a/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/sensors.js +++ b/gnome/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/sensors.js @@ -140,6 +140,8 @@ export const Sensors = GObject.registerClass({ let used = total - avail let utilized = used / total; + let swapUsed = swapTotal - swapFree + let swapUtilized = swapUsed / swapTotal; this._returnValue(callback, 'Usage', utilized, 'memory', 'percent'); this._returnValue(callback, 'memory', utilized, 'memory-group', 'percent'); @@ -148,7 +150,10 @@ export const Sensors = GObject.registerClass({ this._returnValue(callback, 'Allocated', used, 'memory', 'memory'); this._returnValue(callback, 'Cached', cached, 'memory', 'memory'); this._returnValue(callback, 'Free', memFree, 'memory', 'memory'); - this._returnValue(callback, 'Swap', swapTotal - swapFree, 'memory', 'memory'); + this._returnValue(callback, 'Swap Total', swapTotal, 'memory', 'memory'); + this._returnValue(callback, 'Swap Free', swapFree, 'memory', 'memory'); + this._returnValue(callback, 'Swap Used', swapUsed, 'memory', 'memory'); + this._returnValue(callback, 'Swap Usage', swapUtilized, 'memory', 'percent'); }).catch(err => { }); } @@ -373,9 +378,11 @@ export const Sensors = GObject.registerClass({ // addresses issue #161 let battery_key = 'BAT'; // BAT0, BAT1 and BAT2 if (battery_slot == 3) { + battery_slot = 'T'; + } else if (battery_slot == 4) { battery_key = 'CMB'; // CMB0 battery_slot = 0; - } else if (battery_slot == 4) { + } else if (battery_slot == 5) { battery_key = 'macsmc-battery'; // supports Asahi linux battery_slot = ''; } diff --git a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/appIndicator.js b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/appIndicator.js index bbcaac6..944afcc 100644 --- a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/appIndicator.js +++ b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/appIndicator.js @@ -37,6 +37,7 @@ Gio._promisify(GdkPixbuf.Pixbuf, 'get_file_info_async'); Gio._promisify(GdkPixbuf.Pixbuf, 'new_from_stream_at_scale_async', 'new_from_stream_finish'); Gio._promisify(St.IconInfo.prototype, 'load_symbolic_async'); +Gio._promisify(Gio.DBusConnection.prototype, 'call'); const MAX_UPDATE_FREQUENCY = 30; // In ms const FALLBACK_ICON_NAME = 'image-loading-symbolic'; @@ -199,10 +200,10 @@ class AppIndicatorProxy extends DBusProxy { })); } - _onSignal(...args) { - this._onSignalAsync(...args).catch(e => { + _onSignal(sender, signal, ...args) { + this._onSignalAsync(sender, signal, ...args).catch(e => { if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e); + logError(e, `Error while processing signal '${signal}'`); }); } @@ -311,7 +312,10 @@ class AppIndicatorProxy extends DBusProxy { } catch (e) { if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { // the property may not even exist, silently ignore it - Util.Logger.debug(`While refreshing property ${propertyName}: ${e}`); + Util.Logger.debug(`Error when calling 'Get(${propertyName})' ` + + `in ${this.gName}, ${this.gObjectPath}, ` + + `org.freedesktop.DBus.Properties, ${this.gInterfaceName} ` + + `while refreshing property ${propertyName}: ${e}`); this.set_cached_property(propertyName, null); this._cancellables.delete(propertyName); delete this._changedProperties[propertyName]; @@ -435,6 +439,25 @@ export class AppIndicator extends Signals.EventEmitter { } } + // We try to lookup the activate method to see if the app supports it + try { + const introspectionVariant = await this._proxy.gConnection.call( + this._proxy.gNameOwner, this._proxy.gObjectPath, + 'org.freedesktop.DBus.Introspectable', 'Introspect', null, null, + Gio.DBusCallFlags.NONE, -1, cancellable); + const [introspectionXml] = introspectionVariant.deep_unpack(); + const nodeInfo = Gio.DBusNodeInfo.new_for_xml(introspectionXml); + const interfaceInfo = nodeInfo.lookup_interface(this._proxy.gInterfaceName); + this.supportsActivation = !!interfaceInfo.lookup_method('Activate'); + this._hasAyatanaSecondaryActivate = + !!interfaceInfo.lookup_method('XAyatanaSecondaryActivate'); + } catch (e) { + if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { + Util.Logger.debug( + `${this.uniqueId}, check for Activation support: ${e.message}`); + } + } + try { this._commandLine = await Util.getProcessName(this.busName, cancellable, GLib.PRIORITY_LOW); diff --git a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/dbusMenu.js b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/dbusMenu.js index 4f9467f..95dcea0 100644 --- a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/dbusMenu.js +++ b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/dbusMenu.js @@ -130,6 +130,11 @@ export class DbusMenuItem extends Signals.EventEmitter { this.emit('property-changed', prop, this.propertyGetVariant(prop)); } + resetProperties() { + Object.entries(PropertyStore.DefaultValues).forEach(([prop, value]) => + this.propertySet(prop, value)); + } + getChildrenIds() { return this._children_ids.concat(); // clone it! } @@ -297,6 +302,8 @@ export const DBusClient = GObject.registerClass({ if (!item) return; + item.resetProperties(); + for (const [prop, value] of Object.entries(properties)) item.propertySet(prop, value); }); @@ -495,6 +502,9 @@ export const DBusClient = GObject.registerClass({ // we don't need to cache and burst-send that since it will not happen that frequently async sendAboutToShow(id) { + if (this._hasAboutToShow === false) + return; + /* Some indicators (you, dropbox!) don't use the right signature * and don't return a boolean, so we need to support both cases */ try { @@ -507,6 +517,13 @@ export const DBusClient = GObject.registerClass({ ret.is_of_type(new GLib.VariantType('()'))) this._requestLayoutUpdate(); } catch (e) { + Util.Logger.debug('Error when calling \'AboutToShow()\' in ' + + `${this.gName}, ${this.gObjectPath}, ${this.gInterfaceName}`); + if (e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_METHOD) || + e.matches(Gio.DBusError, Gio.DBusError.FAILED)) { + this._hasAboutToShow = false; + return; + } if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) logError(e); } diff --git a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/extension.js b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/extension.js index 16e6596..6f69aa1 100644 --- a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/extension.js +++ b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/extension.js @@ -22,7 +22,7 @@ import * as TrayIconsManager from './trayIconsManager.js'; import * as Util from './util.js'; import {SettingsManager} from './settingsManager.js'; -export default class DashToDockExtension extends Extension.Extension { +export default class AppIndicatorExtension extends Extension.Extension { constructor(...args) { super(...args); diff --git a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/iconCache.js b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/iconCache.js index b775307..3610184 100644 --- a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/iconCache.js +++ b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/iconCache.js @@ -49,7 +49,7 @@ export class IconCache { } const oldIcon = this._cache.get(id); - if (!oldIcon || !oldIcon.equals(icon)) { + if (!oldIcon || !oldIcon.equal(icon)) { Util.Logger.debug(`IconCache: adding ${id}: ${icon}`); this._cache.set(id, icon); } else { diff --git a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/indicatorStatusIcon.js b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/indicatorStatusIcon.js index 5ef516c..49ecde8 100644 --- a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/indicatorStatusIcon.js +++ b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/indicatorStatusIcon.js @@ -276,15 +276,15 @@ class IndicatorStatusIcon extends BaseStatusIcon { yAlign: Clutter.ActorAlign.CENTER, }); this._label = new St.Label(); - this._labelBin.add_actor(this._label); - this._box.add_actor(this._labelBin); + Util.addActor(this._labelBin, this._label); + Util.addActor(this._box, this._labelBin); } this._label.set_text(label); if (!this._box.contains(this._labelBin)) - this._box.add_actor(this._labelBin); // FIXME: why is it suddenly necessary? + Util.addActor(this._box, this._labelBin); // FIXME: why is it suddenly necessary? } else if (this._label) { this._labelBin.destroy_all_children(); - this._box.remove_actor(this._labelBin); + Util.removeActor(this._box, this._labelBin); this._labelBin.destroy(); delete this._labelBin; delete this._label; @@ -420,13 +420,6 @@ class IndicatorStatusIcon extends BaseStatusIcon { return Clutter.EVENT_PROPAGATE; } - vfunc_button_release_event(event) { - if (!this._indicator.supportsActivation) - return this._maybeHandleDoubleClick(event); - - return Clutter.EVENT_PROPAGATE; - } - vfunc_scroll_event(event) { // Since Clutter 1.10, clutter will always send a smooth scrolling event // with explicit deltas, no matter what input device is used diff --git a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/locale/cs/LC_MESSAGES/AppIndicatorExtension.mo b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/locale/cs/LC_MESSAGES/AppIndicatorExtension.mo index c66d72e..93c4c6d 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/locale/cs/LC_MESSAGES/AppIndicatorExtension.mo and b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/locale/cs/LC_MESSAGES/AppIndicatorExtension.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/locale/hu/LC_MESSAGES/AppIndicatorExtension.mo b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/locale/hu/LC_MESSAGES/AppIndicatorExtension.mo index 2e558a8..ffbe4ed 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/locale/hu/LC_MESSAGES/AppIndicatorExtension.mo and b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/locale/hu/LC_MESSAGES/AppIndicatorExtension.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/locale/uk/LC_MESSAGES/AppIndicatorExtension.mo b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/locale/uk/LC_MESSAGES/AppIndicatorExtension.mo new file mode 100644 index 0000000..88c7fbc Binary files /dev/null and b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/locale/uk/LC_MESSAGES/AppIndicatorExtension.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/locale/zh_TW/LC_MESSAGES/AppIndicatorExtension.mo b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/locale/zh_TW/LC_MESSAGES/AppIndicatorExtension.mo new file mode 100644 index 0000000..f66fd67 Binary files /dev/null and b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/locale/zh_TW/LC_MESSAGES/AppIndicatorExtension.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/metadata.json b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/metadata.json index 5024157..00567e1 100644 --- a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/metadata.json +++ b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/metadata.json @@ -5,9 +5,11 @@ "name": "AppIndicator and KStatusNotifierItem Support", "settings-schema": "org.gnome.shell.extensions.appindicator", "shell-version": [ - "45" + "45", + "46", + "47" ], "url": "https://github.com/ubuntu/gnome-shell-extension-appindicator", "uuid": "appindicatorsupport@rgcjonas.gmail.com", - "version": 57 + "version": 59 } \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/trayIconsManager.js b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/trayIconsManager.js index cdc2a8e..6003966 100644 --- a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/trayIconsManager.js +++ b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/trayIconsManager.js @@ -45,6 +45,19 @@ export class TrayIconsManager extends Signals.EventEmitter { this._changedId = SettingsManager.getDefaultGSettings().connect( 'changed::legacy-tray-enabled', () => this._toggle()); + // On theme changed, need to update the bg color to match style, + // This may not be required anymore on newer shell versions that use + // ARGBA visuals. + this._styleChangedID = Main.panel.connect('style-changed', () => { + const panelBgColor = this._getPanelBgColor(); + const {bgColor} = this._tray ?? {bgColor: null}; + if (bgColor === panelBgColor || bgColor?.equal(panelBgColor)) + return; + + this._disable(); + this._toggle(); + }); + this._toggle(); } @@ -55,11 +68,16 @@ export class TrayIconsManager extends Signals.EventEmitter { this._disable(); } + _getPanelBgColor() { + return Main.panel?.get_parent() + ? Main.panel.get_theme_node()?.get_background_color() : null; + } + _enable() { if (this._tray) return; - this._tray = new Shell.TrayManager(); + this._tray = new Shell.TrayManager({bgColor: this._getPanelBgColor()}); Util.connectSmart(this._tray, 'tray-icon-added', this, this.onTrayIconAdded); Util.connectSmart(this._tray, 'tray-icon-removed', this, this.onTrayIconRemoved); @@ -71,14 +89,8 @@ export class TrayIconsManager extends Signals.EventEmitter { return; IndicatorStatusIcon.getTrayIcons().forEach(i => i.destroy()); - if (this._tray.unmanage_screen) { - this._tray.unmanage_screen(); - this._tray = null; - } else { - // FIXME: This is very ugly, but it's needed by old shell versions - this._tray = null; - imports.system.gc(); // force finalizing tray to unmanage screen - } + this._tray.unmanage_screen(); + this._tray = null; } onTrayIconAdded(_tray, icon) { @@ -98,6 +110,7 @@ export class TrayIconsManager extends Signals.EventEmitter { destroy() { this.emit('destroy'); SettingsManager.getDefaultGSettings().disconnect(this._changedId); + Main.panel.disconnect(this._styleChangedID); this._disable(); trayIconsManager = null; } diff --git a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/util.js b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/util.js index d2cb352..0aba244 100644 --- a/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/util.js +++ b/gnome/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com/util.js @@ -19,8 +19,6 @@ import GLib from 'gi://GLib'; import GObject from 'gi://GObject'; import St from 'gi://St'; -const ByteArray = imports.byteArray; - import * as Main from 'resource:///org/gnome/shell/ui/main.js'; import * as Config from 'resource:///org/gnome/shell/misc/config.js'; import * as Signals from 'resource:///org/gnome/shell/misc/signals.js'; @@ -102,7 +100,8 @@ export async function getProcessName(connectionName, cancellable = null, const cmdFile = Gio.File.new_for_path(`/proc/${pid}/cmdline`); const inputStream = await cmdFile.read_async(priority, cancellable); const bytes = await inputStream.read_bytes_async(2048, priority, cancellable); - return ByteArray.toString(bytes.toArray().map(v => !v ? 0x20 : v)); + const textDecoder = new TextDecoder(); + return textDecoder.decode(bytes.toArray().map(v => !v ? 0x20 : v)); } export async function* introspectBusObject(bus, name, cancellable, @@ -376,6 +375,20 @@ export function tryCleanupOldIndicators() { new Set(indicators).forEach(i => i.destroy()); } +export function addActor(obj, actor) { + if (obj.add_actor) + obj.add_actor(actor); + else + obj.add_child(actor); +} + +export function removeActor(obj, actor) { + if (obj.remove_actor) + obj.remove_actor(actor); + else + obj.remove_child(actor); +} + export const CancellableChild = GObject.registerClass({ Properties: { 'parent': GObject.ParamSpec.object( diff --git a/gnome/.local/share/gnome-shell/extensions/auto-activities@CleoMenezesJr.github.io/metadata.json b/gnome/.local/share/gnome-shell/extensions/auto-activities@CleoMenezesJr.github.io/metadata.json index 230b379..7757c11 100644 --- a/gnome/.local/share/gnome-shell/extensions/auto-activities@CleoMenezesJr.github.io/metadata.json +++ b/gnome/.local/share/gnome-shell/extensions/auto-activities@CleoMenezesJr.github.io/metadata.json @@ -11,11 +11,10 @@ "original-author": "mi-jan-sena@proton.me", "settings-schema": "org.gnome.shell.extensions.auto-activities", "shell-version": [ - "45", - "46" + "47" ], "url": "https://github.com/CleoMenezesJr/auto-activities", "uuid": "auto-activities@CleoMenezesJr.github.io", - "version": 13, - "version-name": "46.1" + "version": 14, + "version-name": "47.0" } \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/appfolders.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/appfolders.js index d16f32b..8824777 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/appfolders.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/appfolders.js @@ -1,11 +1,22 @@ import Shell from 'gi://Shell'; import Clutter from 'gi://Clutter'; +import Cogl from 'gi://Cogl'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; +import { adjustAnimationTime } from 'resource:///org/gnome/shell/misc/animationUtils.js'; -import { PaintSignals } from '../effects/paint_signals.js'; +import { PaintSignals } from '../conveniences/paint_signals.js'; +// TODO drop Tweener in favour of Clutter's `ease` (will need to extend the blur effect for it) const Tweener = imports.tweener.tweener; -const transparent = Clutter.Color.from_pixel(0x00000000); +// TODO: Drop GNOME 46 backwards compatibility +const transparent = Clutter.Color ? + Clutter.Color.from_pixel(0x00000000) : + new Cogl.Color({ + red: 0, + green: 0, + blue: 0, + alpha: 0 + }); const FOLDER_DIALOG_ANIMATION_TIME = 200; const DIALOGS_STYLES = [ @@ -43,7 +54,7 @@ let _zoomAndFadeIn = function () { { radius: sigma * 2, brightness: brightness, - time: FOLDER_DIALOG_ANIMATION_TIME / 1000, + time: adjustAnimationTime(FOLDER_DIALOG_ANIMATION_TIME / 1000), transition: 'easeOutQuad' } ); @@ -87,7 +98,7 @@ let _zoomAndFadeOut = function () { { radius: 0, brightness: 1.0, - time: FOLDER_DIALOG_ANIMATION_TIME / 1000, + time: adjustAnimationTime(FOLDER_DIALOG_ANIMATION_TIME / 1000), transition: 'easeInQuad' } ); @@ -120,6 +131,8 @@ let _zoomAndFadeOut = function () { export const AppFoldersBlur = class AppFoldersBlur { + // we do not use the effects manager and dummy pipelines here because we + // really want to manage our sigma value ourself during the transition constructor(connections, settings, _) { this.connections = connections; this.paint_signals = new PaintSignals(connections); @@ -129,12 +142,8 @@ export const AppFoldersBlur = class AppFoldersBlur { enable() { this._log("blurring appfolders"); - brightness = this.settings.appfolder.CUSTOMIZE - ? this.settings.appfolder.BRIGHTNESS - : this.settings.BRIGHTNESS; - sigma = this.settings.appfolder.CUSTOMIZE - ? this.settings.appfolder.SIGMA - : this.settings.SIGMA; + brightness = this.settings.appfolder.BRIGHTNESS; + sigma = this.settings.appfolder.SIGMA; let appDisplay = Main.overview._overview.controls._appDisplay; @@ -143,15 +152,15 @@ export const AppFoldersBlur = class AppFoldersBlur { } this.connections.connect( - appDisplay, 'view-loaded', this.blur_appfolders.bind(this) + appDisplay, 'view-loaded', _ => this.blur_appfolders() ); } blur_appfolders() { let appDisplay = Main.overview._overview.controls._appDisplay; - if (this.settings.HACKS_LEVEL === 1 || this.settings.HACKS_LEVEL === 2) - this._log(`appfolders hack level ${this.settings.HACKS_LEVEL}`); + if (this.settings.HACKS_LEVEL === 1) + this._log("appfolders hack level 1"); appDisplay._folderIcons.forEach(icon => { icon._ensureFolderDialog(); @@ -197,7 +206,7 @@ export const AppFoldersBlur = class AppFoldersBlur { // // [1]: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857 - if (this.settings.HACKS_LEVEL === 1 || this.settings.HACKS_LEVEL === 2) { + if (this.settings.HACKS_LEVEL === 1) { this.paint_signals.disconnect_all_for_actor(icon._dialog); this.paint_signals.connect(icon._dialog, blur_effect); } else { @@ -218,11 +227,6 @@ export const AppFoldersBlur = class AppFoldersBlur { this.blur_appfolders(); } - // not implemented for dynamic blur - set_color(c) { } - set_noise_amount(n) { } - set_noise_lightness(l) { } - disable() { this._log("removing blur from appfolders"); diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/applications.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/applications.js index 1a454ca..e2a8bdf 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/applications.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/applications.js @@ -1,24 +1,20 @@ -import Shell from 'gi://Shell'; -import Clutter from 'gi://Clutter'; import Meta from 'gi://Meta'; import Gio from 'gi://Gio'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import { PaintSignals } from '../effects/paint_signals.js'; import { ApplicationsService } from '../dbus/services.js'; +import { PaintSignals } from '../conveniences/paint_signals.js'; +import { DummyPipeline } from '../conveniences/dummy_pipeline.js'; export const ApplicationsBlur = class ApplicationsBlur { - constructor(connections, settings, _) { + constructor(connections, settings, effects_manager) { this.connections = connections; this.settings = settings; + this.effects_manager = effects_manager; this.paint_signals = new PaintSignals(connections); - this.mutter_gsettings = new Gio.Settings({ schema: 'org.gnome.mutter' }); - - // stores every blurred window - this.window_map = new Map(); - // stores every blur actor - this.blur_actor_map = new Map(); + // stores every blurred meta window + this.meta_window_map = new Map(); } enable() { @@ -28,6 +24,8 @@ export const ApplicationsBlur = class ApplicationsBlur { this.service = new ApplicationsService; this.service.export(); + this.mutter_gsettings = new Gio.Settings({ schema: 'org.gnome.mutter' }); + // blur already existing windows this.update_all_windows(); @@ -38,16 +36,42 @@ export const ApplicationsBlur = class ApplicationsBlur { (_meta_display, meta_window) => { this._log("window created"); - if (meta_window) { - let window_actor = meta_window.get_compositor_private(); - this.track_new(window_actor, meta_window); - } + if (meta_window) + this.track_new(meta_window); + } + ); + + // update window blur when focus is changed + this.focused_window_pid = null; + this.init_dynamic_opacity(); + this.connections.connect( + global.display, + 'focus-window', + (_meta_display, meta_window, _p0) => { + if (meta_window && meta_window.bms_pid != this.focused_window_pid) + this.set_focus_for_window(meta_window); + else if (!meta_window) + this.set_focus_for_window(null); } ); this.connect_to_overview(); } + /// Initializes the dynamic opacity for windows, without touching to the connections. + /// This is used both when enabling the component, and when changing the dynamic-opacity pref. + init_dynamic_opacity() { + if (this.settings.applications.DYNAMIC_OPACITY) { + // make the currently focused window solid + if (global.display.focus_window) + this.set_focus_for_window(global.display.focus_window); + } else { + // remove old focused window if the pref was changed + if (this.focused_window_pid) + this.set_focus_for_window(null); + } + } + /// Connect to the overview being opened/closed to force the blur being /// shown on every window of the workspaces viewer. connect_to_overview() { @@ -58,9 +82,9 @@ export const ApplicationsBlur = class ApplicationsBlur { // allows the blur to be shown too) this.connections.connect( Main.overview, 'showing', - _ => this.window_map.forEach((meta_window, _pid) => { + _ => this.meta_window_map.forEach((meta_window, _pid) => { let window_actor = meta_window.get_compositor_private(); - window_actor.show(); + window_actor?.show(); }) ); @@ -69,7 +93,7 @@ export const ApplicationsBlur = class ApplicationsBlur { this.connections.connect( Main.overview, 'hidden', _ => { - this.window_map.forEach((meta_window, _pid) => { + this.meta_window_map.forEach((meta_window, _pid) => { let window_actor = meta_window.get_compositor_private(); if ( @@ -86,7 +110,7 @@ export const ApplicationsBlur = class ApplicationsBlur { update_all_windows() { // remove all previously blurred windows, in the case where the // whitelist was changed - this.window_map.forEach(((_meta_window, pid) => { + this.meta_window_map.forEach(((_meta_window, pid) => { this.remove_blur(pid); })); @@ -98,82 +122,81 @@ export const ApplicationsBlur = class ApplicationsBlur { let workspace = global.workspace_manager.get_workspace_by_index(i); let windows = workspace.list_windows(); - windows.forEach(meta_window => { - let window_actor = meta_window.get_compositor_private(); - - // disconnect previous signals - this.connections.disconnect_all_for(window_actor); - - this.track_new(window_actor, meta_window); - }); + windows.forEach(meta_window => this.track_new(meta_window)); } } /// Adds the needed signals to every new tracked window, and adds blur if /// needed. - track_new(window_actor, meta_window) { - let pid = ("" + Math.random()).slice(2, 16); + /// Accepts only untracked meta windows (i.e no `bms_pid` set) + track_new(meta_window) { + // create a pid that will follow the window during its whole life + const pid = ("" + Math.random()).slice(2, 16); + meta_window.bms_pid = pid; - window_actor['blur_provider_pid'] = pid; - meta_window['blur_provider_pid'] = pid; + this._log(`new window tracked, pid: ${pid}`); - // remove the blur when the window is destroyed - this.connections.connect(window_actor, 'destroy', window_actor => { - let pid = window_actor.blur_provider_pid; - if (this.blur_actor_map.has(pid)) { - this.remove_blur(pid); - } - this.window_map.delete(pid); - }); + // register the blurred window + this.meta_window_map.set(pid, meta_window); - // update the blur when mutter-hint or wm-class is changed - for (const prop of ['mutter-hints', 'wm-class']) { - this.connections.connect( - meta_window, - `notify::${prop}`, - _ => { - let pid = meta_window.blur_provider_pid; - this._log(`${prop} changed for pid ${pid}`); - - let window_actor = meta_window.get_compositor_private(); - this.check_blur(pid, window_actor, meta_window); - } - ); - } + // update the blur when wm-class is changed + this.connections.connect( + meta_window, 'notify::wm-class', + _ => this.check_blur(meta_window) + ); // update the position and size when the window size changes - this.connections.connect(meta_window, 'size-changed', () => { - if (this.blur_actor_map.has(pid)) { - let allocation = this.compute_allocation(meta_window); - let blur_actor = this.blur_actor_map.get(pid); + this.connections.connect( + meta_window, 'size-changed', + _ => this.update_size(pid) + ); + + // remove the blur when the window is unmanaged + this.connections.connect( + meta_window, 'unmanaging', + _ => this.untrack_meta_window(pid) + ); + + this.check_blur(meta_window); + } + + /// Updates the size of the blur actor associated to a meta window from its pid. + /// Accepts only tracked meta window (i.e `bms_pid` set), be it blurred or not. + update_size(pid) { + if (this.meta_window_map.has(pid)) { + const meta_window = this.meta_window_map.get(pid); + const blur_actor = meta_window.blur_actor; + if (blur_actor) { + const allocation = this.compute_allocation(meta_window); blur_actor.x = allocation.x; blur_actor.y = allocation.y; blur_actor.width = allocation.width; blur_actor.height = allocation.height; } - }); - - this.check_blur(pid, window_actor, meta_window); + } else + // the pid was visibly not removed + this.untrack_meta_window(pid); } /// Checks if the given actor needs to be blurred. + /// Accepts only tracked meta window, be it blurred or not. /// /// In order to be blurred, a window either: /// - is whitelisted in the user preferences if not enable-all /// - is not blacklisted if enable-all - /// - has a correct mutter hint, set to `blur-provider=sigma_value` - check_blur(pid, window_actor, meta_window) { - let mutter_hint = meta_window.get_mutter_hints(); - let window_wm_class = meta_window.get_wm_class(); + check_blur(meta_window) { + const window_wm_class = meta_window.get_wm_class(); + const enable_all = this.settings.applications.ENABLE_ALL; + const whitelist = this.settings.applications.WHITELIST; + const blacklist = this.settings.applications.BLACKLIST; + if (window_wm_class) + this._log(`pid ${meta_window.bms_pid} associated to wm class name ${window_wm_class}`); - let enable_all = this.settings.applications.ENABLE_ALL; - let whitelist = this.settings.applications.WHITELIST; - let blacklist = this.settings.applications.BLACKLIST; - this._log(`checking blur for ${pid}`); - - // either the window is included in whitelist - if (window_wm_class !== "" + // if we are in blacklist mode and the window is not blacklisted + // or if we are in whitelist mode and the window is whitelisted + if ( + window_wm_class !== "" && ((enable_all && !blacklist.includes(window_wm_class)) || (!enable_all && whitelist.includes(window_wm_class)) ) @@ -183,209 +206,114 @@ export const ApplicationsBlur = class ApplicationsBlur { Meta.FrameType.MODAL_DIALOG ].includes(meta_window.get_frame_type()) ) { - this._log(`application ${pid} listed, blurring it`); - - // get blur effect parameters - - let brightness, sigma; - - if (this.settings.applications.CUSTOMIZE) { - brightness = this.settings.applications.BRIGHTNESS; - sigma = this.settings.applications.SIGMA; - } else { - brightness = this.settings.BRIGHTNESS; - sigma = this.settings.SIGMA; - } - - this.update_blur(pid, window_actor, meta_window, brightness, sigma); + // only blur the window if it is not already done + if (!meta_window.blur_actor) + this.create_blur_effect(meta_window); } - // or blur is asked by window itself - else if ( - mutter_hint != null && - mutter_hint.includes("blur-provider") - ) { - this._log(`application ${pid} has hint ${mutter_hint}, parsing`); - - // get blur effect parameters - let [brightness, sigma] = this.parse_xprop(mutter_hint); - - this.update_blur(pid, window_actor, meta_window, brightness, sigma); - } - - // remove blur if the mutter hint is no longer valid, and the window - // is not explicitly whitelisted or un-blacklisted - else if (this.blur_actor_map.has(pid)) { - this.remove_blur(pid); - } - } - - /// When given the xprop property, returns the brightness and sigma values - /// matching. If one of the two values is invalid, or missing, then it uses - /// default values. - /// - /// An xprop property is valid if it is in one of the following formats: - /// - /// blur-provider=sigma:60,brightness:0.9 - /// blur-provider=s:10,brightness:0.492 - /// blur-provider=b:1.0,s:16 - /// - /// Brightness is a floating-point between 0.0 and 1.0 included. - /// Sigma is an integer between 0 and 999 included. - /// - /// If sigma is set to 0, then the blur is removed. - /// Setting "default" instead of the two values will make the - /// extension use its default value. - /// - /// Note that no space can be inserted. - /// - parse_xprop(property) { - // set brightness and sigma to default values - let brightness, sigma; - if (this.settings.applications.CUSTOMIZE) { - brightness = this.settings.applications.BRIGHTNESS; - sigma = this.settings.applications.SIGMA; - } else { - brightness = this.settings.BRIGHTNESS; - sigma = this.settings.SIGMA; - } - - // get the argument of the property - let arg = property.match("blur-provider=(.*)"); - this._log(`argument = ${arg}`); - - // if argument is valid, parse it - if (arg != null) { - // verify if there is only one value: in this case, this is sigma - let maybe_sigma = parseInt(arg[1]); - - if ( - !isNaN(maybe_sigma) && - maybe_sigma >= 0 && - maybe_sigma <= 999 - ) { - sigma = maybe_sigma; - } else { - // perform pattern matching - let res_b = arg[1].match("(brightness|b):(default|0?1?\.[0-9]*)"); - let res_s = arg[1].match("(sigma|s):(default|\\d{1,3})"); - - // if values are valid and not default, change them to the xprop one - if ( - res_b != null && res_b[2] !== 'default' - ) { - brightness = parseFloat(res_b[2]); - } - - if ( - res_s != null && res_s[2] !== 'default' - ) { - sigma = parseInt(res_s[2]); - } - } - } - - this._log(`brightness = ${brightness}, sigma = ${sigma}`); - - return [brightness, sigma]; - } - - /// Updates the blur on a window which needs to be blurred. - update_blur(pid, window_actor, meta_window, brightness, sigma) { - // the window is already blurred, update its blur effect - if (this.blur_actor_map.has(pid)) { - // window is already blurred, but sigma is null: remove the blur - if (sigma === 0) { - this.remove_blur(pid); - } - // window is already blurred and sigma is non-null: update it - else { - this.update_blur_effect( - this.blur_actor_map.get(pid), - brightness, - sigma - ); - } - } - - // the window is not blurred, and sigma is a non-null value: blur it - else if (sigma !== 0) { - // window is not blurred, blur it - this.create_blur_effect( - pid, - window_actor, - meta_window, - brightness, - sigma - ); - } + // remove blur it is not explicitly whitelisted or un-blacklisted + else if (meta_window.blur_actor) + this.remove_blur(meta_window.bms_pid); } /// Add the blur effect to the window. - create_blur_effect(pid, window_actor, meta_window, brightness, sigma) { - let blur_effect = new Shell.BlurEffect({ - radius: sigma * 2, - brightness: brightness, - mode: Shell.BlurMode.BACKGROUND - }); + /// Accepts only tracked meta window that is NOT already blurred. + create_blur_effect(meta_window) { + const pid = meta_window.bms_pid; + const window_actor = meta_window.get_compositor_private(); - let blur_actor = this.create_blur_actor( - meta_window, - window_actor, - blur_effect + const pipeline = new DummyPipeline(this.effects_manager, this.settings.applications); + let [blur_actor, bg_manager] = pipeline.create_background_with_effect( + window_actor, 'bms-application-blurred-widget' ); + meta_window.blur_actor = blur_actor; + meta_window.bg_manager = bg_manager; + // if hacks are selected, force to repaint the window - if (this.settings.HACKS_LEVEL === 1 || this.settings.HACKS_LEVEL === 2) { - this._log("applications hack level 1 or 2"); + if (this.settings.HACKS_LEVEL === 1) { + this._log("hack level 1"); - this.paint_signals.disconnect_all(); - this.paint_signals.connect(blur_actor, blur_effect); + this.paint_signals.disconnect_all_for_actor(blur_actor); + this.paint_signals.connect(blur_actor, pipeline.effect); } else { - this.paint_signals.disconnect_all(); + this.paint_signals.disconnect_all_for_actor(blur_actor); } - // insert the blurred widget - window_actor.insert_child_at_index(blur_actor, 0); - // make sure window is blurred in overview if (this.settings.applications.BLUR_ON_OVERVIEW) this.enforce_window_visibility_on_overview_for(window_actor); + // update the size + this.update_size(pid); + // set the window actor's opacity this.set_window_opacity(window_actor, this.settings.applications.OPACITY); + // now set up the signals, for the window actor only: they are disconnected + // in `remove_blur`, whereas the signals for the meta window are disconnected + // only when the whole component is disabled + + // update the window opacity when it changes, else we don't control it fully this.connections.connect( - window_actor, - 'notify::opacity', - _ => this.set_window_opacity(window_actor, this.settings.applications.OPACITY) + window_actor, 'notify::opacity', + _ => { + if (this.focused_window_pid != pid) + this.set_window_opacity(window_actor, this.settings.applications.OPACITY); + } ); - // register the blur actor/effect - blur_actor['blur_provider_pid'] = pid; - this.blur_actor_map.set(pid, blur_actor); - this.window_map.set(pid, meta_window); - - // hide the blur if window is invisible - if (!window_actor.visible) { - blur_actor.hide(); - } - // hide the blur if window becomes invisible + if (!window_actor.visible) + blur_actor.hide(); + this.connections.connect( window_actor, 'notify::visible', window_actor => { - let pid = window_actor.blur_provider_pid; - if (window_actor.visible) { - this.blur_actor_map.get(pid).show(); - } else { - this.blur_actor_map.get(pid).hide(); - } + if (window_actor.visible) + meta_window.blur_actor.show(); + else + meta_window.blur_actor.hide(); } ); } + /// With `focus=true`, tells us we are focused on said window (which can be null if + /// we are not focused anymore). It automatically removes the ancient focus. + /// With `focus=false`, just remove the focus from said window (which can still be null). + set_focus_for_window(meta_window, focus = true) { + let blur_actor = null; + let window_actor = null; + let new_pid = null; + if (meta_window) { + blur_actor = meta_window.blur_actor; + window_actor = meta_window.get_compositor_private(); + new_pid = meta_window.bms_pid; + } + + if (focus) { + // remove old focused window if any + if (this.focused_window_pid) { + const old_focused_window = this.meta_window_map.get(this.focused_window_pid); + if (old_focused_window) + this.set_focus_for_window(old_focused_window, false); + } + // set new focused window pid + this.focused_window_pid = new_pid; + // if we have blur, hide it and make the window opaque + if (this.settings.applications.DYNAMIC_OPACITY && blur_actor) { + blur_actor.hide(); + this.set_window_opacity(window_actor, 255); + } + } + // if we remove the focus and have blur, show it and make the window transparent + else if (blur_actor) { + blur_actor.show(); + this.set_window_opacity(window_actor, this.settings.applications.OPACITY); + } + } + /// Makes sure that, when the overview is visible, the window actor will /// stay visible no matter what. /// We can instead hide the last child of the window actor, which will @@ -412,12 +340,24 @@ export const ApplicationsBlur = class ApplicationsBlur { /// Set the opacity of the window actor that sits on top of the blur effect. set_window_opacity(window_actor, opacity) { - window_actor.get_children().forEach(child => { + window_actor?.get_children().forEach(child => { if (child.name !== "blur-actor" && child.opacity != opacity) child.opacity = opacity; }); } + /// Update the opacity of all window actors. + set_opacity() { + let opacity = this.settings.applications.OPACITY; + + this.meta_window_map.forEach(((meta_window, pid) => { + if (pid != this.focused_window_pid && meta_window.blur_actor) { + let window_actor = meta_window.get_compositor_private(); + this.set_window_opacity(window_actor, opacity); + } + })); + } + /// Compute the size and position for a blur actor. /// If `scale-monitor-framebuffer` experimental feature if on, we don't need to manage scaling. /// Else, on wayland, we need to divide by the scale to get the correct result. @@ -442,107 +382,68 @@ export const ApplicationsBlur = class ApplicationsBlur { }; } - /// Returns a new already blurred widget, configured to follow the size and - /// position of its target window. - create_blur_actor(meta_window, window_actor, blur_effect) { - // compute the size and position - let allocation = this.compute_allocation(meta_window); - - // create the actor - let blur_actor = new Clutter.Actor({ - x: allocation.x, - y: allocation.y, - width: allocation.width, - height: allocation.height - }); - - // add the effect - blur_actor.add_effect_with_name('blur-effect', blur_effect); - - return blur_actor; - } - - /// Updates the blur effect by overwriting its sigma and brightness values. - update_blur_effect(blur_actor, brightness, sigma) { - let effect = blur_actor.get_effect('blur-effect'); - effect.radius = sigma * 2; - effect.brightness = brightness; - } - - /// Removes the blur actor from the shell and unregister it. + /// Removes the blur actor to make a blurred window become normal again. + /// It however does not untrack the meta window itself. + /// Accepts a pid corresponding (or not) to a blurred (or not) meta window. remove_blur(pid) { this._log(`removing blur for pid ${pid}`); - let meta_window = this.window_map.get(pid); - // disconnect needed signals and untrack window + let meta_window = this.meta_window_map.get(pid); if (meta_window) { - this.window_map.delete(pid); let window_actor = meta_window.get_compositor_private(); + let blur_actor = meta_window.blur_actor; + let bg_manager = meta_window.bg_manager; - let blur_actor = this.blur_actor_map.get(pid); - if (blur_actor) { - this.blur_actor_map.delete(pid); + if (blur_actor && window_actor) { + // reset the opacity + this.set_window_opacity(window_actor, 255); - if (window_actor) { - // reset the opacity - this.set_window_opacity(window_actor, 255); + // remove the blurred actor + window_actor.remove_child(blur_actor); + bg_manager._bms_pipeline.destroy(); + bg_manager.destroy(); + blur_actor.destroy(); - // remove the blurred actor - window_actor.remove_child(blur_actor); + // kinda untrack the blurred actor, as its presence is how we know + // whether we are blurred or not + delete meta_window.blur_actor; + delete meta_window.bg_manager; - // disconnect the signals about overview animation etc - this.connections.disconnect_all_for(window_actor); - } + // disconnect the signals of the window actor + this.paint_signals.disconnect_all_for_actor(blur_actor); + this.connections.disconnect_all_for(window_actor); } } } + /// Kinda the same as `remove_blur`, but better: it also untracks the window. + /// This needs to be called when the component is being disabled, else it + /// would cause havoc by having untracked windows during normal operations, + /// which is not the point at all! + /// Accepts a pid corresponding (or not) to a blurred (or not) meta window. + untrack_meta_window(pid) { + this.remove_blur(pid); + let meta_window = this.meta_window_map.get(pid); + if (meta_window) { + this.connections.disconnect_all_for(meta_window); + this.meta_window_map.delete(pid); + } + } + disable() { this._log("removing blur from applications..."); this.service?.unexport(); delete this.mutter_gsettings; - this.blur_actor_map.forEach(((_blur_actor, pid) => { - this.remove_blur(pid); - })); + this.meta_window_map.forEach((_meta_window, pid) => { + this.untrack_meta_window(pid); + }); this.connections.disconnect_all(); this.paint_signals.disconnect_all(); } - /// Update the opacity of all window actors. - set_opacity() { - let opacity = this.settings.applications.OPACITY; - - this.window_map.forEach(((meta_window, _pid) => { - let window_actor = meta_window.get_compositor_private(); - this.set_window_opacity(window_actor, opacity); - })); - } - - /// Updates each blur effect to use new sigma value - // FIXME set_sigma and set_brightness are called when the extension is - // loaded and when sigma is changed, and do not respect the per-app - // xprop behaviour - set_sigma(s) { - this.blur_actor_map.forEach((actor, _) => { - actor.get_effect('blur-effect').set_sigma(s); - }); - } - - /// Updates each blur effect to use new brightness value - set_brightness(b) { - this.blur_actor_map.forEach((actor, _) => { - actor.get_effect('blur-effect').set_brightness(b); - }); - } - - // not implemented for dynamic blur - set_color(c) { } - set_noise_amount(n) { } - set_noise_lightness(l) { } - _log(str) { if (this.settings.DEBUG) console.log(`[Blur my Shell > applications] ${str}`); diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/coverflow_alt_tab.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/coverflow_alt_tab.js new file mode 100644 index 0000000..e4b0f19 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/coverflow_alt_tab.js @@ -0,0 +1,91 @@ +import * as Main from "resource:///org/gnome/shell/ui/main.js"; + +import { PaintSignals } from "../conveniences/paint_signals.js"; +import { Pipeline } from "../conveniences/pipeline.js"; + +export const CoverflowAltTabBlur = class CoverflowAltTabBlur { + constructor(connections, settings, effects_manager) { + this.connections = connections; + this.settings = settings; + this.paint_signals = new PaintSignals(connections); + this.effects_manager = effects_manager; + this.background_actors = []; + this.background_managers = []; + } + + enable() { + this._log("blurring coverflow alt-tab"); + + this.update_backgrounds(); + + this.connections.connect( + Main.layoutManager.uiGroup, + "child-added", + (_, child) => this.try_blur(child) + ); + + this.connections.connect(Main.layoutManager, "monitors-changed", (_) => { + this.update_backgrounds(); + }); + } + + update_backgrounds() { + this.remove_background_actors(); + + Main.layoutManager.uiGroup + .get_children() + .forEach((child) => this.try_blur(child)); + } + + try_blur(actor) { + if ( + actor.constructor.name !== "Meta_BackgroundGroup" || + actor.get_name() !== "coverflow-alt-tab-background-group" + ) { + return; + } + + this._log("found coverflow alt-tab to blur"); + + for (let i = 0; i < Main.layoutManager.monitors.length; i++) { + const pipeline = new Pipeline( + this.effects_manager, + global.blur_my_shell._pipelines_manager, + this.settings.coverflow_alt_tab.PIPELINE + ); + + const background_actor = pipeline.create_background_with_effects( + i, + this.background_managers, + actor, + "bms-coverflow-alt-tab-blurred-widget" + ); + + this.background_actors.push(background_actor); + } + } + + remove_background_actors() { + this.background_actors.forEach((actor) => actor.destroy); + this.background_actors = []; + + this.background_managers.forEach((background_manager) => { + background_manager._bms_pipeline.destroy(); + background_manager.destroy(); + }); + this.background_managers = []; + } + + disable() { + this._log("removing blur from coverflow alt-tab"); + + this.remove_background_actors(); + this.connections.disconnect_all(); + } + + _log(str) { + if (this.settings.DEBUG) { + console.log(`[Blur my Shell > coverflow alt-tab] ${str}`); + } + } +}; diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/dash_to_dock.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/dash_to_dock.js index 7d84c23..4ff212c 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/dash_to_dock.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/dash_to_dock.js @@ -1,12 +1,11 @@ -import St from 'gi://St'; -import Shell from 'gi://Shell'; import Meta from 'gi://Meta'; -import Mtk from 'gi://Mtk'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -const Signals = imports.signals; +import * as Signals from 'resource:///org/gnome/shell/misc/signals.js'; -import { PaintSignals } from '../effects/paint_signals.js'; -import { BlurEffect } from '../effects/blur_effect.js'; +import { PaintSignals } from '../conveniences/paint_signals.js'; + +import { Pipeline } from '../conveniences/pipeline.js'; +import { DummyPipeline } from '../conveniences/dummy_pipeline.js'; const DASH_STYLES = [ "transparent-dash", @@ -15,150 +14,65 @@ const DASH_STYLES = [ ]; -// An helper function to find the monitor in which an actor is situated, -/// there might be a pre-existing function in GLib already -function find_monitor_for(actor) { - let extents = actor.get_transformed_extents(); - let rect = new Mtk.Rectangle({ - x: extents.get_x(), - y: extents.get_y(), - width: extents.get_width(), - height: extents.get_height(), - }); - - let index = global.display.get_monitor_index_for_rect(rect); - - return Main.layoutManager.monitors[index]; -} - - /// This type of object is created for every dash found, and talks to the main /// DashBlur thanks to signals. /// /// This allows to dynamically track the created dashes for each screen. class DashInfos { - constructor(dash_blur, dash, dash_container, dash_background, background, background_parent, effect) { + constructor( + dash_blur, dash, dash_container, dash_background, + background, background_group, bg_manager + ) { // the parent DashBlur object, to communicate this.dash_blur = dash_blur; - this.dash_container = dash_container; - // the blurred dash this.dash = dash; + this.dash_container = dash_container; this.dash_background = dash_background; - this.background_parent = background_parent; this.background = background; - this.effect = effect; + this.background_group = background_group; + this.bg_manager = bg_manager; this.settings = dash_blur.settings; this.old_style = this.dash._background.style; - dash_blur.connections.connect(dash_blur, 'remove-dashes', () => { - this._log("removing blur from dash"); - this.dash.get_parent().remove_child(this.background_parent); - this.remove_style(); - }); + this.dash_destroy_id = dash.connect('destroy', () => this.remove_dash_blur(false)); + this.dash_blur_connections_ids = []; + this.dash_blur_connections_ids.push( + this.dash_blur.connect('remove-dashes', () => this.remove_dash_blur()), + this.dash_blur.connect('override-style', () => this.override_style()), + this.dash_blur.connect('remove-style', () => this.remove_style()), + this.dash_blur.connect('show', () => this.background_group.show()), + this.dash_blur.connect('hide', () => this.background_group.hide()), + this.dash_blur.connect('update-size', () => this.update_size()), + this.dash_blur.connect('change-blur-type', () => this.change_blur_type()), + this.dash_blur.connect('update-pipeline', () => this.update_pipeline()) + ); + } - dash_blur.connections.connect(dash_blur, 'update-sigma', () => { - if (this.dash_blur.is_static) { - this.dash_blur.update_size(); - } - this.effect.radius = 2 * this.dash_blur.sigma * this.effect.scale; - }); + // IMPORTANT: do never call this in a mutable `this.dash_blur.forEach` + remove_dash_blur(dash_not_already_destroyed = true) { + // remove the style and destroy the effects + this.remove_style(); + this.destroy_dash(dash_not_already_destroyed); - dash_blur.connections.connect(dash_blur, 'update-brightness', () => { - this.effect.brightness = this.dash_blur.brightness; - }); + // remove the dash infos from their list + const dash_infos_index = this.dash_blur.dashes.indexOf(this); + if (dash_infos_index >= 0) + this.dash_blur.dashes.splice(dash_infos_index, 1); - dash_blur.connections.connect(dash_blur, 'update-corner-radius', () => { - if (this.dash_blur.is_static) { - let monitor = find_monitor_for(this.dash); - let corner_radius = this.dash_blur.corner_radius * monitor.geometry_scale; - this.effect.corner_radius = Math.min( - corner_radius, this.effect.width / 2, this.effect.height / 2 - ); - } - }); + // disconnect everything + this.dash_blur_connections_ids.forEach(id => { if (id) this.dash_blur.disconnect(id); }); + this.dash_blur_connections_ids = []; + if (this.dash_destroy_id) + this.dash.disconnect(this.dash_destroy_id); + this.dash_destroy_id = null; + } - dash_blur.connections.connect(dash_blur, 'override-background', () => { - this.remove_style(); + override_style() { + this.remove_style(); - this.dash.set_style_class_name( - DASH_STYLES[this.settings.dash_to_dock.STYLE_DASH_TO_DOCK] - ); - }); - - dash_blur.connections.connect(dash_blur, 'reset-background', () => this.remove_style()); - - dash_blur.connections.connect(dash_blur, 'show', () => { - if (this.dash_blur.is_static) - this.background_parent.show(); - else - this.effect.radius = this.dash_blur.sigma * 2 * this.effect.scale; - }); - - dash_blur.connections.connect(dash_blur, 'hide', () => { - if (this.dash_blur.is_static) - this.background_parent.hide(); - else - this.effect.radius = 0; - }); - - dash_blur.connections.connect(dash_blur, 'update-wallpaper', () => { - if (this.dash_blur.is_static) { - let bg = Main.layoutManager._backgroundGroup.get_child_at_index( - Main.layoutManager.monitors.length - - find_monitor_for(this.dash).index - 1 - ); - if (bg && bg.get_content()) { - this.background.content.set({ - background: bg.get_content().background - }); - this._log('wallpaper updated'); - } else { - this._warn("could not get background for dash-to-dock"); - } - } - }); - - dash_blur.connections.connect(dash_blur, 'update-size', () => { - if (this.dash_blur.is_static) { - let [x, y] = this.get_dash_position(this.dash_container, this.dash_background); - - this.background.x = -x; - this.background.y = -y; - - this.effect.width = this.dash_background.width; - this.effect.height = this.dash_background.height; - - this.dash_blur.set_corner_radius(this.dash_blur.corner_radius); - - if (dash_container.get_style_class_name().includes("top")) { - this.background.set_clip(x, y + this.dash.y + this.dash_background.y, this.dash_background.width, this.dash_background.height); - } else if (dash_container.get_style_class_name().includes("bottom")) { - this.background.set_clip(x, y + this.dash.y + this.dash_background.y, this.dash_background.width, this.dash_background.height); - } else if (dash_container.get_style_class_name().includes("left")) { - this.background.set_clip(x + this.dash.x + this.dash_background.x, y + this.dash.y + this.dash_background.y, this.dash_background.width, this.dash_background.height); - } else if (dash_container.get_style_class_name().includes("right")) { - this.background.set_clip(x + this.dash.x + this.dash_background.x, y + this.dash.y + this.dash_background.y, this.dash_background.width, this.dash_background.height); - } - } else { - this.background.width = this.dash_background.width; - this.background.height = this.dash_background.height; - - this.background.x = this.dash_background.x; - this.background.y = this.dash_background.y + this.dash.y; - } - }); - - dash_blur.connections.connect(dash_blur, 'change-blur-type', () => { - this.background_parent.remove_child(this.background); - if (this.effect.chained_effect) - this.effect.get_actor()?.remove_effect(this.effect.chained_effect); - this.effect.get_actor()?.remove_effect(this.effect); - - let [background, effect] = this.dash_blur.add_blur(this.dash, this.dash_background, this.dash_container); - this.background = background; - this.effect = effect; - this.background_parent.add_child(this.background); - }); + this.dash.set_style_class_name( + DASH_STYLES[this.settings.dash_to_dock.STYLE_DASH_TO_DOCK] + ); } remove_style() { @@ -169,10 +83,88 @@ class DashInfos { ); } + destroy_dash(dash_not_already_destroyed = true) { + if (!dash_not_already_destroyed) + this.bg_manager.backgroundActor = null; + + this.paint_signals?.disconnect_all(); + this.dash.get_parent().remove_child(this.background_group); + this.bg_manager._bms_pipeline.destroy(); + this.bg_manager.destroy(); + this.background_group.destroy(); + } + + change_blur_type() { + this.destroy_dash(); + + let [ + background, background_group, bg_manager, paint_signals + ] = this.dash_blur.add_blur(this.dash); + + this.background = background; + this.background_group = background_group; + this.bg_manager = bg_manager; + this.paint_signals = paint_signals; + + this.dash.get_parent().insert_child_at_index(this.background_group, 0); + + this.update_size(); + } + + update_pipeline() { + this.bg_manager._bms_pipeline.change_pipeline_to( + this.settings.dash_to_dock.PIPELINE + ); + } + + update_size() { + if (this.dash_blur.is_static) { + let [x, y] = this.get_dash_position(this.dash_container, this.dash_background); + + this.background.x = -x; + this.background.y = -y; + + if (this.dash_container.get_style_class_name().includes("top")) + this.background.set_clip( + x, + y + this.dash.y + this.dash_background.y, + this.dash_background.width, + this.dash_background.height + ); + else if (this.dash_container.get_style_class_name().includes("bottom")) + this.background.set_clip( + x, + y + this.dash.y + this.dash_background.y, + this.dash_background.width, + this.dash_background.height + ); + else if (this.dash_container.get_style_class_name().includes("left")) + this.background.set_clip( + x + this.dash.x + this.dash_background.x, + y + this.dash.y + this.dash_background.y, + this.dash_background.width, + this.dash_background.height + ); + else if (this.dash_container.get_style_class_name().includes("right")) + this.background.set_clip( + x + this.dash.x + this.dash_background.x, + y + this.dash.y + this.dash_background.y, + this.dash_background.width, + this.dash_background.height + ); + } else { + this.background.width = this.dash_background.width; + this.background.height = this.dash_background.height; + + this.background.x = this.dash_background.x; + this.background.y = this.dash_background.y + this.dash.y; + } + } + get_dash_position(dash_container, dash_background) { var x, y; - let monitor = find_monitor_for(dash_container); + let monitor = Main.layoutManager.findMonitorForActor(dash_container); let dash_box = dash_container._slider.get_child(); if (dash_container.get_style_class_name().includes("top")) { @@ -202,19 +194,13 @@ class DashInfos { } } -export const DashBlur = class DashBlur { +export const DashBlur = class DashBlur extends Signals.EventEmitter { constructor(connections, settings, _) { + super(); this.dashes = []; this.connections = connections; this.settings = settings; this.paint_signals = new PaintSignals(connections); - this.sigma = this.settings.dash_to_dock.CUSTOMIZE - ? this.settings.dash_to_dock.SIGMA - : this.settings.SIGMA; - this.brightness = this.settings.dash_to_dock.CUSTOMIZE - ? this.settings.dash_to_dock.BRIGHTNESS - : this.settings.BRIGHTNESS; - this.corner_radius = this.settings.dash_to_dock.CORNER_RADIUS; this.is_static = this.settings.dash_to_dock.STATIC_BLUR; this.enabled = false; } @@ -231,7 +217,6 @@ export const DashBlur = class DashBlur { this.blur_existing_dashes(); this.connect_to_overview(); - this.update_wallpaper(); this.update_size(); this.enabled = true; @@ -246,7 +231,7 @@ export const DashBlur = class DashBlur { Main.uiGroup.get_children().filter((child) => { return (child.get_name() === "dashtodockContainer") && (child.constructor.name === 'DashToDock'); - }).forEach(this.try_blur.bind(this)); + }).forEach(dash_container => this.try_blur(dash_container)); } // Tries to blur the dash contained in the given actor @@ -254,9 +239,9 @@ export const DashBlur = class DashBlur { let dash_box = dash_container._slider.get_child(); // verify that we did not already blur that dash - if (!dash_box.get_children().some((child) => { - return child.get_name() === "dash-blurred-background-parent"; - })) { + if (!dash_box.get_children().some(child => + child.get_name() === "bms-dash-backgroundgroup" + )) { this._log("dash to dock found, blurring it"); // finally blur the dash @@ -270,48 +255,26 @@ export const DashBlur = class DashBlur { // Blurs the dash and returns a `DashInfos` containing its information blur_dash_from(dash, dash_container) { - // dash background parent, not visible - let background_parent = new St.Widget({ - name: 'dash-blurred-background-parent', - style_class: 'dash-blurred-background-parent', - width: 0, - height: 0 - }); + let [background, background_group, bg_manager, paint_signals] = this.add_blur(dash); - // finally blur the dash - let dash_background = dash.get_children().find(child => { - return child.get_style_class_name() === 'dash-background'; - }); - - let [background, effect] = this.add_blur(dash, dash_background, dash_container); - - this.update_wallpaper(); - this.update_size(); + // insert the background group to the right element + dash.get_parent().insert_child_at_index(background_group, 0); // updates size and position on change - this.connections.connect(dash, 'notify::width', _ => { - this.update_size(); - }); - this.connections.connect(dash, 'notify::height', _ => { - this.update_size(); - }); - this.connections.connect(dash_container, 'notify::width', _ => { - this.update_size(); - }); - this.connections.connect(dash_container, 'notify::height', _ => { - this.update_size(); - }); - this.connections.connect(dash_container, 'notify::y', _ => { - this.update_wallpaper(); - this.update_size(); - }); - this.connections.connect(dash_container, 'notify::x', _ => { - this.update_wallpaper(); - this.update_size(); - }); + this.connections.connect( + dash, + ['notify::width', 'notify::height'], + _ => this.update_size() + ); + this.connections.connect( + dash_container, + ['notify::width', 'notify::height', 'notify::y', 'notify::x'], + _ => this.update_size() + ); - background_parent.add_child(background); - dash.get_parent().insert_child_at_index(background_parent, 0); + const dash_background = dash.get_children().find(child => { + return child.get_style_class_name() === 'dash-background'; + }); // create infos let infos = new DashInfos( @@ -320,137 +283,81 @@ export const DashBlur = class DashBlur { dash_container, dash_background, background, - background_parent, - effect + background_group, + bg_manager, + paint_signals ); - // update the background + this.update_size(); this.update_background(); // returns infos return infos; } - add_blur(dash, dash_background, dash_container) { - let monitor = find_monitor_for(dash); + add_blur(dash) { + const monitor = Main.layoutManager.findMonitorForActor(dash); + if (!monitor) + return; - // dash background widget - let background = this.is_static - ? new Meta.BackgroundActor({ - meta_display: global.display, - monitor: monitor.index, - }) - : new St.Widget({ - name: 'dash-blurred-background', - style_class: 'dash-blurred-background', - x: dash_background.x, - y: dash_background.y + dash.y, - width: dash_background.width, - height: dash_background.height, - }); + const background_group = new Meta.BackgroundGroup({ + name: 'bms-dash-backgroundgroup', width: 0, height: 0 + }); - // the effect to be applied - let effect; - if (this.is_static) { - let corner_radius = this.corner_radius * monitor.geometry_scale; - corner_radius = Math.min(corner_radius, dash_background.width / 2, dash_background.height / 2); - - effect = new BlurEffect({ - radius: 2 * this.sigma * monitor.geometry_scale, - brightness: this.brightness, - width: dash_background.width, - height: dash_background.height, - corner_radius: corner_radius - }); - - // connect to every background change (even without changing image) - // FIXME this signal is fired very often, so we should find another one - // fired only when necessary (but that still catches all cases) - this.connections.connect( - Main.layoutManager._backgroundGroup, - 'notify', - _ => this.update_wallpaper() + let background, bg_manager, paint_signals; + let static_blur = this.settings.dash_to_dock.STATIC_BLUR; + if (static_blur) { + let bg_manager_list = []; + const pipeline = new Pipeline( + global.blur_my_shell._effects_manager, + global.blur_my_shell._pipelines_manager, + this.settings.dash_to_dock.PIPELINE ); - } else { - effect = new Shell.BlurEffect({ - brightness: this.brightness, - radius: this.sigma * 2 * monitor.geometry_scale, - mode: Shell.BlurMode.BACKGROUND - }); + background = pipeline.create_background_with_effects( + monitor.index, bg_manager_list, + background_group, 'bms-dash-blurred-widget' + ); + bg_manager = bg_manager_list[0]; + } + else { + const pipeline = new DummyPipeline( + global.blur_my_shell._effects_manager, + this.settings.dash_to_dock + ); + [background, bg_manager] = pipeline.create_background_with_effect( + background_group, 'bms-dash-blurred-widget' + ); + + paint_signals = new PaintSignals(this.connections); // HACK // //`Shell.BlurEffect` does not repaint when shadows are under it. [1] // // This does not entirely fix this bug (shadows caused by windows - // still cause artifacts), but it prevents the shadows of the panel - // buttons to cause artifacts on the panel itself + // still cause artifacts), but it prevents the shadows of the dash + // buttons to cause artifacts on the dash itself // // [1]: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857 if (this.settings.HACKS_LEVEL === 1) { - this._log("dash hack level 1"); - this.paint_signals.disconnect_all(); + this._log("hack level 1"); - let rp = () => { - effect.queue_repaint(); - }; - - dash._box.get_children().forEach((icon) => { - try { - let zone = icon.get_child_at_index(0); - - this.connections.connect(zone, [ - 'enter-event', 'leave-event', 'button-press-event' - ], rp); - } catch (e) { - this._warn(`${e}, continuing`); - } - }); - - this.connections.connect(dash._box, 'actor-added', (_, actor) => { - try { - let zone = actor.get_child_at_index(0); - - this.connections.connect(zone, [ - 'enter-event', 'leave-event', 'button-press-event' - ], rp); - } catch (e) { - this._warn(`${e}, continuing`); - } - }); - - let show_apps = dash._showAppsIcon; - - this.connections.connect(show_apps, [ - 'enter-event', 'leave-event', 'button-press-event' - ], rp); - - this.connections.connect(dash, 'leave-event', rp); - } else if (this.settings.HACKS_LEVEL === 2) { - this._log("dash hack level 2"); - - this.paint_signals.connect(background, effect); + paint_signals.disconnect_all(); + paint_signals.connect(background, pipeline.effect); } else { - this.paint_signals.disconnect_all(); + paint_signals.disconnect_all(); } } - // store the scale in the effect in order to retrieve it in set_sigma - effect.scale = monitor.geometry_scale; - - background.add_effect(effect); - - return [background, effect]; + return [background, background_group, bg_manager, paint_signals]; } change_blur_type() { this.is_static = this.settings.dash_to_dock.STATIC_BLUR; - this.emit('change-blur-type', true); + this.emit('change-blur-type'); - this.update_wallpaper(); this.update_background(); - this.update_size(); } /// Connect when overview if opened/closed to hide/show the blur accordingly @@ -459,10 +366,10 @@ export const DashBlur = class DashBlur { if (this.settings.dash_to_dock.UNBLUR_IN_OVERVIEW) { this.connections.connect( - Main.overview, 'showing', this.hide.bind(this) + Main.overview, 'showing', _ => this.hide() ); this.connections.connect( - Main.overview, 'hidden', this.show.bind(this) + Main.overview, 'hidden', _ => this.show() ); } }; @@ -470,45 +377,32 @@ export const DashBlur = class DashBlur { /// Updates the background to either remove it or not, according to the /// user preferences. update_background() { + this._log("updating background"); if (this.settings.dash_to_dock.OVERRIDE_BACKGROUND) - this.emit('override-background', true); + this.emit('override-style'); else - this.emit('reset-background', true); + this.emit('remove-style'); } - update_wallpaper() { - if (this.is_static) - this.emit('update-wallpaper', true); + update_pipeline() { + this.emit('update-pipeline'); } update_size() { - this.emit('update-size', true); + this.emit('update-size'); } - set_sigma(sigma) { - this.sigma = sigma; - this.emit('update-sigma', true); + show() { + this.emit('show'); } - - set_brightness(brightness) { - this.brightness = brightness; - this.emit('update-brightness', true); + hide() { + this.emit('hide'); } - set_corner_radius(radius) { - this.corner_radius = radius; - this.emit('update-corner-radius', true); - } - - // not implemented for dynamic blur - set_color(c) { } - set_noise_amount(n) { } - set_noise_lightness(l) { } - disable() { this._log("removing blur from dashes"); - this.emit('remove-dashes', true); + this.emit('remove-dashes'); this.dashes = []; this.connections.disconnect_all(); @@ -516,13 +410,6 @@ export const DashBlur = class DashBlur { this.enabled = false; } - show() { - this.emit('show', true); - } - hide() { - this.emit('hide', true); - } - _log(str) { if (this.settings.DEBUG) console.log(`[Blur my Shell > dash manager] ${str}`); @@ -531,6 +418,4 @@ export const DashBlur = class DashBlur { _warn(str) { console.warn(`[Blur my Shell > dash manager] ${str}`); } -}; - -Signals.addSignalMethods(DashBlur.prototype); \ No newline at end of file +}; \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/lockscreen.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/lockscreen.js index 00895ea..7755ba9 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/lockscreen.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/lockscreen.js @@ -1,19 +1,14 @@ -import St from 'gi://St'; -import Shell from 'gi://Shell'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as Background from 'resource:///org/gnome/shell/ui/background.js'; import { UnlockDialog } from 'resource:///org/gnome/shell/ui/unlockDialog.js'; -let sigma; -let brightness; -let color; -let noise; -let lightness; +import { Pipeline } from '../conveniences/pipeline.js'; const original_createBackground = UnlockDialog.prototype._createBackground; const original_updateBackgroundEffects = UnlockDialog.prototype._updateBackgroundEffects; +const original_updateBackgrounds = + UnlockDialog.prototype._updateBackgrounds; export const LockscreenBlur = class LockscreenBlur { @@ -27,22 +22,6 @@ export const LockscreenBlur = class LockscreenBlur { enable() { this._log("blurring lockscreen"); - brightness = this.settings.lockscreen.CUSTOMIZE - ? this.settings.lockscreen.BRIGHTNESS - : this.settings.BRIGHTNESS; - sigma = this.settings.lockscreen.CUSTOMIZE - ? this.settings.lockscreen.SIGMA - : this.settings.SIGMA; - color = this.settings.lockscreen.CUSTOMIZE - ? this.settings.lockscreen.COLOR - : this.settings.COLOR; - noise = this.settings.lockscreen.CUSTOMIZE - ? this.settings.lockscreen.NOISE_AMOUNT - : this.settings.NOISE_AMOUNT; - lightness = this.settings.lockscreen.CUSTOMIZE - ? this.settings.lockscreen.NOISE_LIGHTNESS - : this.settings.NOISE_LIGHTNESS; - this.update_lockscreen(); this.enabled = true; @@ -53,103 +32,39 @@ export const LockscreenBlur = class LockscreenBlur { this._createBackground; UnlockDialog.prototype._updateBackgroundEffects = this._updateBackgroundEffects; + UnlockDialog.prototype._updateBackgrounds = + this._updateBackgrounds; } - _createBackground(monitorIndex) { - let monitor = Main.layoutManager.monitors[monitorIndex]; - let widget = new St.Widget({ - style_class: "screen-shield-background", - x: monitor.x, - y: monitor.y, - width: monitor.width, - height: monitor.height, - }); + _createBackground(monitor_index) { + let pipeline = new Pipeline( + global.blur_my_shell._effects_manager, global.blur_my_shell._pipelines_manager, + global.blur_my_shell._settings.lockscreen.PIPELINE + ); - let blur_effect = new Shell.BlurEffect({ - name: 'blur', - radius: sigma * 2, - brightness: brightness - }); - - // store the scale in the effect in order to retrieve later - blur_effect.scale = monitor.geometry_scale; - - let color_effect = global.blur_my_shell._lockscreen_blur.effects_manager.new_color_effect({ - name: 'color', - color: color - }, this.settings); - - let noise_effect = global.blur_my_shell._lockscreen_blur.effects_manager.new_noise_effect({ - name: 'noise', - noise: noise, - lightness: lightness - }, this.settings); - - widget.add_effect(color_effect); - widget.add_effect(noise_effect); - widget.add_effect(blur_effect); - - let bgManager = new Background.BackgroundManager({ - container: widget, - monitorIndex, - controlPosition: false, - }); - - this._bgManagers.push(bgManager); - - this._backgroundGroup.add_child(widget); + pipeline.create_background_with_effects( + monitor_index, + this._bgManagers, + this._backgroundGroup, + "screen-shield-background" + ); } _updateBackgroundEffects() { - for (const widget of this._backgroundGroup) { - const color_effect = widget.get_effect('color'); - const noise_effect = widget.get_effect('noise'); - const blur_effect = widget.get_effect('blur'); + this._updateBackgrounds(); + } - if (color_effect) - color_effect.set({ - color: color - }); - - if (noise_effect) { - noise_effect.set({ - noise: noise, - lightness: lightness, - }); - } - - if (blur_effect) { - blur_effect.set({ - brightness: brightness, - radius: sigma * 2 * blur_effect.scale, - }); - } + _updateBackgrounds() { + for (let i = 0; i < this._bgManagers.length; i++) { + this._bgManagers[i]._bms_pipeline.destroy(); + this._bgManagers[i].destroy(); } - } - set_sigma(s) { - sigma = s; - this.update_lockscreen(); - } + this._bgManagers = []; + this._backgroundGroup.destroy_all_children(); - set_brightness(b) { - brightness = b; - this.update_lockscreen(); - } - - set_color(c) { - color = c; - this.update_lockscreen(); - } - - set_noise_amount(n) { - noise = n; - this.update_lockscreen(); - } - - set_noise_lightness(l) { - lightness = l; - this.update_lockscreen(); + for (let i = 0; i < Main.layoutManager.monitors.length; i++) + this._createBackground(i); } disable() { @@ -159,6 +74,8 @@ export const LockscreenBlur = class LockscreenBlur { original_createBackground; UnlockDialog.prototype._updateBackgroundEffects = original_updateBackgroundEffects; + UnlockDialog.prototype._updateBackgrounds = + original_updateBackgrounds; this.connections.disconnect_all(); diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/overview.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/overview.js index d612370..1399234 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/overview.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/overview.js @@ -1,10 +1,11 @@ -import Shell from 'gi://Shell'; import Meta from 'gi://Meta'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; import { WorkspaceAnimationController } from 'resource:///org/gnome/shell/ui/workspaceAnimation.js'; const wac_proto = WorkspaceAnimationController.prototype; +import { Pipeline } from '../conveniences/pipeline.js'; + const OVERVIEW_COMPONENTS_STYLE = [ "overview-components-light", "overview-components-dark", @@ -15,40 +16,23 @@ const OVERVIEW_COMPONENTS_STYLE = [ export const OverviewBlur = class OverviewBlur { constructor(connections, settings, effects_manager) { this.connections = connections; - this.effects = []; this.settings = settings; this.effects_manager = effects_manager; - this._workspace_switch_bg_actors = []; + this.overview_background_managers = []; + this.overview_background_group = new Meta.BackgroundGroup( + { name: 'bms-overview-backgroundgroup' } + ); + this.animation_background_managers = []; + this.animation_background_group = new Meta.BackgroundGroup( + { name: 'bms-animation-backgroundgroup' } + ); this.enabled = false; + this.proto_patched = false; } enable() { this._log("blurring overview"); - // connect to every background change (even without changing image) - // FIXME this signal is fired very often, so we should find another one - // fired only when necessary (but that still catches all cases) - this.connections.connect( - Main.layoutManager._backgroundGroup, - 'notify', - _ => { - this._log("updated background"); - this.update_backgrounds(); - } - ); - - // connect to monitors change - this.connections.connect( - Main.layoutManager, - 'monitors-changed', - _ => { - if (Main.screenShield && !Main.screenShield.locked) { - this._log("changed monitors"); - this.update_backgrounds(); - } - } - ); - // add css class name for workspace-switch background Main.uiGroup.add_style_class_name("blurred-overview"); @@ -58,12 +42,16 @@ export const OverviewBlur = class OverviewBlur { // update backgrounds when the component is enabled this.update_backgrounds(); + // connect to monitors change + this.connections.connect(Main.layoutManager, 'monitors-changed', + _ => this.update_backgrounds() + ); // part for the workspace animation switch - // make sure not to do this part if the extension was enabled prior, as + // make sure not to do this part if the functions were patched prior, as // the functions would call themselves and cause infinite recursion - if (!this.enabled) { + if (!this.proto_patched) { // store original workspace switching methods for restoring them on // disable() this._original_PrepareSwitch = wac_proto._prepareWorkspaceSwitch; @@ -91,25 +79,20 @@ export const OverviewBlur = class OverviewBlur { ); } - Main.layoutManager.monitors.forEach(monitor => { - if ( - !( + Main.uiGroup.insert_child_above( + outer_this.animation_background_group, + global.window_group + ); + + outer_this.animation_background_managers.forEach(bg_manager => { + if (bg_manager._bms_pipeline.actor) + if ( Meta.prefs_get_workspaces_only_on_primary() && - (monitor !== Main.layoutManager.primaryMonitor) + bg_manager._monitorIndex !== Main.layoutManager.primaryMonitor.index ) - ) { - const bg_actor = outer_this.create_background_actor( - monitor, true - ); - - Main.uiGroup.insert_child_above( - bg_actor, - global.window_group - ); - - // store the actors so that we can delete them later - outer_this._workspace_switch_bg_actors.push(bg_actor); - } + bg_manager._bms_pipeline.actor.visible = false; + else + bg_manager._bms_pipeline.actor.visible = true; }); }; @@ -129,15 +112,10 @@ export const OverviewBlur = class OverviewBlur { ); } - outer_this.effects = outer_this.effects.filter( - effects_group => !effects_group.is_transition - ); - - outer_this._workspace_switch_bg_actors.forEach(actor => { - actor.destroy(); - }); - outer_this._workspace_switch_bg_actors = []; + Main.uiGroup.remove_child(outer_this.animation_background_group); }; + + this.proto_patched = true; } this.enabled = true; @@ -146,78 +124,30 @@ export const OverviewBlur = class OverviewBlur { update_backgrounds() { // remove every old background this.remove_background_actors(); - - // add new backgrounds - Main.layoutManager.monitors.forEach(monitor => { - const bg_actor = this.create_background_actor(monitor, false); - - Main.layoutManager.overviewGroup.insert_child_at_index( - bg_actor, - monitor.index + // create new backgrounds for the overview and the animation + for (let i = 0; i < Main.layoutManager.monitors.length; i++) { + const pipeline_overview = new Pipeline( + this.effects_manager, + global.blur_my_shell._pipelines_manager, + this.settings.overview.PIPELINE + ); + pipeline_overview.create_background_with_effects( + i, this.overview_background_managers, + this.overview_background_group, 'bms-overview-blurred-widget' ); - }); - } - create_background_actor(monitor, is_transition) { - let bg_actor = new Meta.BackgroundActor({ - name: "blur-my-shell_background_actor", - meta_display: global.display, - monitor: monitor.index - }); - let background_group = Main.layoutManager._backgroundGroup - .get_children() - .filter((child) => child instanceof Meta.BackgroundActor); - let background = - background_group[ - Main.layoutManager.monitors.length - monitor.index - 1 - ]; - - if (!background) { - this._warn("could not get background for overview"); - return bg_actor; + const pipeline_animation = new Pipeline( + this.effects_manager, + global.blur_my_shell._pipelines_manager, + this.settings.overview.PIPELINE + ); + pipeline_animation.create_background_with_effects( + i, this.animation_background_managers, + this.animation_background_group, 'bms-animation-blurred-widget' + ); } - - bg_actor.content.set({ - background: background.get_content().background - }); - - let blur_effect = new Shell.BlurEffect({ - brightness: this.settings.overview.CUSTOMIZE - ? this.settings.overview.BRIGHTNESS - : this.settings.BRIGHTNESS, - radius: (this.settings.overview.CUSTOMIZE - ? this.settings.overview.SIGMA - : this.settings.SIGMA) * 2 * monitor.geometry_scale, - mode: Shell.BlurMode.ACTOR - }); - - // store the scale in the effect in order to retrieve it in set_sigma - blur_effect.scale = monitor.geometry_scale; - - let color_effect = this.effects_manager.new_color_effect({ - color: this.settings.overview.CUSTOMIZE - ? this.settings.overview.COLOR - : this.settings.COLOR - }, this.settings); - - let noise_effect = this.effects_manager.new_noise_effect({ - noise: this.settings.overview.CUSTOMIZE - ? this.settings.overview.NOISE_AMOUNT - : this.settings.NOISE_AMOUNT, - lightness: this.settings.overview.CUSTOMIZE - ? this.settings.overview.NOISE_LIGHTNESS - : this.settings.NOISE_LIGHTNESS - }, this.settings); - - bg_actor.add_effect(color_effect); - bg_actor.add_effect(noise_effect); - bg_actor.add_effect(blur_effect); - this.effects.push({ blur_effect, color_effect, noise_effect, is_transition }); - - bg_actor.set_x(monitor.x); - bg_actor.set_y(monitor.y); - - return bg_actor; + // add the container widget for the overview only to the overview group + Main.layoutManager.overviewGroup.insert_child_at_index(this.overview_background_group, 0); } /// Updates the classname to style overview components with semi-transparent @@ -233,71 +163,43 @@ export const OverviewBlur = class OverviewBlur { ); } - set_sigma(s) { - this.effects.forEach(effect => { - effect.blur_effect.radius = s * 2 * effect.blur_effect.scale; - }); - } - - set_brightness(b) { - this.effects.forEach(effect => { - effect.blur_effect.brightness = b; - }); - } - - set_color(c) { - this.effects.forEach(effect => { - effect.color_effect.color = c; - }); - } - - set_noise_amount(n) { - this.effects.forEach(effect => { - effect.noise_effect.noise = n; - }); - } - - set_noise_lightness(l) { - this.effects.forEach(effect => { - effect.noise_effect.lightness = l; - }); - } - remove_background_actors() { - Main.layoutManager.overviewGroup.get_children().forEach(child => { - if (child instanceof Meta.BackgroundActor - && child.get_name() == "blur-my-shell_background_actor" - ) { - child.get_effects().forEach(effect => { - this.effects_manager.remove(effect); - }); - Main.layoutManager.overviewGroup.remove_child(child); - child.destroy(); - } + this.overview_background_group.remove_all_children(); + this.animation_background_group.remove_all_children(); + this.overview_background_managers.forEach(background_manager => { + background_manager._bms_pipeline.destroy(); + background_manager.destroy(); }); - this.effects = []; + this.animation_background_managers.forEach(background_manager => { + background_manager._bms_pipeline.destroy(); + background_manager.destroy(); + }); + this.overview_background_managers = []; + this.animation_background_managers = []; } disable() { this._log("removing blur from overview"); + this.remove_background_actors(); Main.uiGroup.remove_style_class_name("blurred-overview"); OVERVIEW_COMPONENTS_STYLE.forEach( style => Main.uiGroup.remove_style_class_name(style) ); - // make sure to absolutely not do this if the component was not enabled - // prior, as this would cause infinite recursion - if (this.enabled) { - // restore original behavior + this.connections.disconnect_all(); + this.enabled = false; + } + + restore_patched_proto() { + if (this.proto_patched) { if (this._original_PrepareSwitch) wac_proto._prepareWorkspaceSwitch = this._original_PrepareSwitch; if (this._original_FinishSwitch) wac_proto._finishWorkspaceSwitch = this._original_FinishSwitch; - } - this.connections.disconnect_all(); - this.enabled = false; + this.proto_patched = false; + } } _log(str) { diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/panel.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/panel.js index d1d3edb..df1be7b 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/panel.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/panel.js @@ -1,10 +1,11 @@ import St from 'gi://St'; -import Shell from 'gi://Shell'; import Meta from 'gi://Meta'; -import Mtk from 'gi://Mtk'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import { PaintSignals } from '../effects/paint_signals.js'; +import { PaintSignals } from '../conveniences/paint_signals.js'; + +import { Pipeline } from '../conveniences/pipeline.js'; +import { DummyPipeline } from '../conveniences/dummy_pipeline.js'; const DASH_TO_PANEL_UUID = 'dash-to-panel@jderose9.github.com'; const PANEL_STYLES = [ @@ -56,26 +57,9 @@ export const PanelBlur = class PanelBlur { // update the classname if the panel to have or have not light text this.update_light_text_classname(); - // connect to every background change (even without changing image) - // FIXME this signal is fired very often, so we should find another one - // fired only when necessary (but that still catches all cases) - this.connections.connect( - Main.layoutManager._backgroundGroup, - 'notify', - _ => this.actors_list.forEach(actors => - this.update_wallpaper(actors) - ) - ); - - // connect to monitors change - this.connections.connect( - Main.layoutManager, - 'monitors-changed', - _ => { - if (Main.screenShield && !Main.screenShield.locked) { - this.reset(); - } - } + // connect to workareas change + this.connections.connect(global.display, 'workareas-changed', + _ => this.reset() ); this.enabled = true; @@ -131,9 +115,6 @@ export const PanelBlur = class PanelBlur { if (!actors) // if the actors is not blurred, blur it this.blur_panel(panel); - else - // if it is blurred, update the blur anyway - this.change_blur_type(actors); } /// Blur a panel @@ -145,71 +126,74 @@ export const PanelBlur = class PanelBlur { panel_box = panel_box.get_parent(); } - let monitor = this.find_monitor_for(panel); + let monitor = Main.layoutManager.findMonitorForActor(panel); if (!monitor) return; - let background_parent = new St.Widget({ - name: 'topbar-blurred-background-parent', - x: 0, y: 0, width: 0, height: 0 - }); + let background_group = new Meta.BackgroundGroup( + { name: 'bms-panel-backgroundgroup', width: 0, height: 0 } + ); - let background = this.settings.panel.STATIC_BLUR - ? new Meta.BackgroundActor({ - meta_display: global.display, - monitor: monitor.index - }) - : new St.Widget; + let background, bg_manager; + let static_blur = this.settings.panel.STATIC_BLUR; + if (static_blur) { + let bg_manager_list = []; + const pipeline = new Pipeline( + this.effects_manager, + global.blur_my_shell._pipelines_manager, + this.settings.panel.PIPELINE + ); + background = pipeline.create_background_with_effects( + monitor.index, bg_manager_list, + background_group, 'bms-panel-blurred-widget' + ); + bg_manager = bg_manager_list[0]; + } + else { + const pipeline = new DummyPipeline(this.effects_manager, this.settings.panel); + [background, bg_manager] = pipeline.create_background_with_effect( + background_group, 'bms-panel-blurred-widget' + ); - background_parent.add_child(background); + let paint_signals = new PaintSignals(this.connections); - // insert background parent - panel_box.insert_child_at_index(background_parent, 0); + // HACK + // + //`Shell.BlurEffect` does not repaint when shadows are under it. [1] + // + // This does not entirely fix this bug (shadows caused by windows + // still cause artifacts), but it prevents the shadows of the panel + // buttons to cause artifacts on the panel itself + // + // [1]: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857 - let blur = new Shell.BlurEffect({ - brightness: this.settings.panel.CUSTOMIZE - ? this.settings.panel.BRIGHTNESS - : this.settings.BRIGHTNESS, - radius: (this.settings.panel.CUSTOMIZE - ? this.settings.panel.SIGMA - : this.settings.SIGMA) * 2 * monitor.geometry_scale, - mode: this.settings.panel.STATIC_BLUR - ? Shell.BlurMode.ACTOR - : Shell.BlurMode.BACKGROUND - }); + { + if (this.settings.HACKS_LEVEL === 1) { + this._log("panel hack level 1"); - // store the scale in the effect in order to retrieve it in set_sigma - blur.scale = monitor.geometry_scale; + paint_signals.disconnect_all(); + paint_signals.connect(background, pipeline.effect); + } else { + paint_signals.disconnect_all(); + } + } + } - let color = this.effects_manager.new_color_effect({ - color: this.settings.panel.CUSTOMIZE - ? this.settings.panel.COLOR - : this.settings.COLOR - }, this.settings); - - let noise = this.effects_manager.new_noise_effect({ - noise: this.settings.panel.CUSTOMIZE - ? this.settings.panel.NOISE_AMOUNT - : this.settings.NOISE_AMOUNT, - lightness: this.settings.panel.CUSTOMIZE - ? this.settings.panel.NOISE_LIGHTNESS - : this.settings.NOISE_LIGHTNESS - }, this.settings); - - let paint_signals = new PaintSignals(this.connections); + // insert the background group to the panel box + panel_box.insert_child_at_index(background_group, 0); + // the object that is used to remembering each elements that is linked to the blur effect let actors = { - widgets: { panel, panel_box, background, background_parent }, - effects: { blur, color, noise }, - paint_signals, + widgets: { panel, panel_box, background, background_group }, + static_blur, monitor, + bg_manager, is_dtp_panel }; - this.actors_list.push(actors); - // perform updates - this.change_blur_type(actors); + // update the size of the actor + this.update_size(actors); // connect to panel, panel_box and its parent position or size change // this should fire update_size every time one of its params change @@ -228,157 +212,47 @@ export const PanelBlur = class PanelBlur { 'notify::position', _ => this.update_size(actors) ); - } - update_all_blur_type() { - this.actors_list.forEach(actors => this.change_blur_type(actors)); - } - - change_blur_type(actors) { - let is_static = this.settings.panel.STATIC_BLUR; - - // reset widgets to right state - actors.widgets.background_parent.remove_child(actors.widgets.background); - this.effects_manager.remove(actors.effects.blur); - this.effects_manager.remove(actors.effects.color); - this.effects_manager.remove(actors.effects.noise); - - // create new background actor - actors.widgets.background = is_static - ? new Meta.BackgroundActor({ - meta_display: global.display, - monitor: this.find_monitor_for(actors.widgets.panel).index - }) - : new St.Widget; - - // change blur mode - actors.effects.blur.set_mode(is_static ? 0 : 1); - - // disable other effects if the blur is dynamic, as they makes it opaque - actors.effects.color._static = is_static; - actors.effects.noise._static = is_static; - actors.effects.color.update_enabled(); - actors.effects.noise.update_enabled(); - - // add the effects in order - actors.widgets.background.add_effect(actors.effects.color); - actors.widgets.background.add_effect(actors.effects.noise); - actors.widgets.background.add_effect(actors.effects.blur); - - // add the background actor behing the panel - actors.widgets.background_parent.add_child(actors.widgets.background); - - // perform updates - this.update_wallpaper(actors); - this.update_size(actors); - - - // HACK - // - //`Shell.BlurEffect` does not repaint when shadows are under it. [1] - // - // This does not entirely fix this bug (shadows caused by windows - // still cause artifacts), but it prevents the shadows of the panel - // buttons to cause artifacts on the panel itself - // - // [1]: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857 - - if (!is_static) { - if (this.settings.HACKS_LEVEL === 1) { - this._log("panel hack level 1"); - actors.paint_signals.disconnect_all(); - - let rp = () => { actors.effects.blur.queue_repaint(); }; - - this.connections.connect(actors.widgets.panel, [ - 'enter-event', 'leave-event', 'button-press-event' - ], rp); - - actors.widgets.panel.get_children().forEach(child => { - this.connections.connect(child, [ - 'enter-event', 'leave-event', 'button-press-event' - ], rp); - }); - } else if (this.settings.HACKS_LEVEL === 2) { - this._log("panel hack level 2"); - actors.paint_signals.disconnect_all(); - - actors.paint_signals.connect( - actors.widgets.background, actors.effects.blur - ); - } else { - actors.paint_signals.disconnect_all(); - } - } - } - - update_wallpaper(actors) { - // if static blur, get right wallpaper and update blur with it - if (this.settings.panel.STATIC_BLUR) { - let bg = Main.layoutManager._backgroundGroup.get_child_at_index( - Main.layoutManager.monitors.length - - this.find_monitor_for(actors.widgets.panel).index - 1 - ); - if (bg && bg.get_content()) - actors.widgets.background.content.set({ - background: bg.get_content().background - }); - else - this._warn("could not get background for panel"); - } + // connect to the panel getting destroyed + this.connections.connect( + panel, + 'destroy', + _ => this.destroy_blur(actors, true) + ); } update_size(actors) { let panel = actors.widgets.panel; let panel_box = actors.widgets.panel_box; let background = actors.widgets.background; - let monitor = this.find_monitor_for(panel); - if (!monitor) - return; - let [width, height] = panel_box.get_size(); - background.width = width; - background.height = height; // if static blur, need to clip the background - if (this.settings.panel.STATIC_BLUR) { + if (actors.static_blur) { + let monitor = Main.layoutManager.findMonitorForActor(panel); + if (!monitor) + return; + // an alternative to panel.get_transformed_position, because it // sometimes yields NaN (probably when the actor is not fully // positionned yet) let [p_x, p_y] = panel_box.get_position(); let [p_p_x, p_p_y] = panel_box.get_parent().get_position(); - let x = p_x + p_p_x - monitor.x; - let y = p_y + p_p_y - monitor.y; + let x = p_x + p_p_x - monitor.x + (width - panel.width) / 2; + let y = p_y + p_p_y - monitor.y + (height - panel.height) / 2; - background.set_clip(x, y, width, height); - background.x = -x; - background.y = -y; - - // fixes a bug where the blur is washed away when changing the sigma - this.invalidate_blur(actors); + background.set_clip(x, y, panel.width, panel.height); + background.x = (width - panel.width) / 2 - x; + background.y = .5 + (height - panel.height) / 2 - y; } else { background.x = panel.x; background.y = panel.y; + background.width = panel.width; + background.height = panel.height; } // update the monitor panel is on - actors.monitor = this.find_monitor_for(panel); - } - - /// An helper function to find the monitor in which an actor is situated, - /// there might be a pre-existing function in GLib already - find_monitor_for(actor) { - let extents = actor.get_transformed_extents(); - let rect = new Mtk.Rectangle({ - x: extents.get_x(), - y: extents.get_y(), - width: extents.get_width(), - height: extents.get_height(), - }); - - let index = global.display.get_monitor_index_for_rect(rect); - - return Main.layoutManager.monitors[index]; + actors.monitor = Main.layoutManager.findMonitorForActor(panel); } /// Connect when overview if opened/closed to hide/show the blur accordingly @@ -396,22 +270,22 @@ export const PanelBlur = class PanelBlur { ) { if (!this.settings.hidetopbar.COMPATIBILITY) { this.connections.connect( - Main.overview, 'showing', this.hide.bind(this) + Main.overview, 'showing', _ => this.hide() ); this.connections.connect( - Main.overview, 'hidden', this.show.bind(this) + Main.overview, 'hidden', _ => this.show() ); } else { let appDisplay = Main.overview._overview._controls._appDisplay; this.connections.connect( - appDisplay, 'show', this.hide.bind(this) + appDisplay, 'show', _ => this.hide() ); this.connections.connect( - appDisplay, 'hide', this.show.bind(this) + appDisplay, 'hide', _ => this.show() ); this.connections.connect( - Main.overview, 'hidden', this.show.bind(this) + Main.overview, 'hidden', _ => this.show() ); } @@ -425,12 +299,12 @@ export const PanelBlur = class PanelBlur { ) { // connect to overview opening/closing this.connections.connect(Main.overview, ['showing', 'hiding'], - this.update_visibility.bind(this) + _ => this.update_visibility() ); // connect to session mode update this.connections.connect(Main.sessionMode, 'updated', - this.update_visibility.bind(this) + _ => this.update_visibility() ); // manage already-existing windows @@ -450,7 +324,7 @@ export const PanelBlur = class PanelBlur { // connect to a workspace change this.connections.connect(global.window_manager, 'switch-workspace', - this.update_visibility.bind(this) + _ => this.update_visibility() ); // perform early update @@ -600,75 +474,45 @@ export const PanelBlur = class PanelBlur { ); } - /// Fixes a bug where the blur is washed away when changing the sigma, or - /// enabling/disabling other effects. - invalidate_blur(actors) { - if (this.settings.panel.STATIC_BLUR && actors.widgets.background) - actors.widgets.background.get_content()?.invalidate(); - } - - invalidate_all_blur() { - this.actors_list.forEach(actors => this.invalidate_blur(actors)); - } - - set_sigma(s) { - this.actors_list.forEach(actors => { - actors.effects.blur.radius = s * 2 * actors.effects.blur.scale; - this.invalidate_blur(actors); - }); - } - - set_brightness(b) { - this.actors_list.forEach(actors => { - actors.effects.blur.brightness = b; - }); - } - - set_color(c) { - this.actors_list.forEach(actors => { - actors.effects.color.color = c; - }); - } - - set_noise_amount(n) { - this.actors_list.forEach(actors => { - actors.effects.noise.noise = n; - }); - } - - set_noise_lightness(l) { - this.actors_list.forEach(actors => { - actors.effects.noise.lightness = l; - }); + update_pipeline() { + this.actors_list.forEach(actors => + actors.bg_manager._bms_pipeline.change_pipeline_to( + this.settings.panel.PIPELINE + ) + ); } show() { this.actors_list.forEach(actors => { - actors.widgets.background_parent.show(); + actors.widgets.background.show(); }); } hide() { this.actors_list.forEach(actors => { - actors.widgets.background_parent.hide(); + actors.widgets.background.hide(); }); } - // destroy every blurred background left, necessary after sleep - destroy_blur_effects() { - Main.panel?.get_parent()?.get_children().forEach( - child => { - if (child.name === 'topbar-blurred-background-parent') { - child.get_children().forEach(meta_background_actor => { - meta_background_actor.get_effects().forEach(effect => { - this.effects_manager.remove(effect); - }); - }); - child.destroy_all_children(); - child.destroy(); - } - } - ); + // IMPORTANT: do never call this in a mutable `this.actors_list.forEach` + destroy_blur(actors, panel_already_destroyed) { + this.set_should_override_panel(actors, false); + + actors.bg_manager._bms_pipeline.destroy(); + + if (panel_already_destroyed) + actors.bg_manager.backgroundActor = null; + actors.bg_manager.destroy(); + + if (!panel_already_destroyed) { + actors.widgets.panel_box.remove_child(actors.widgets.background_group); + actors.widgets.background_group.destroy_all_children(); + actors.widgets.background_group.destroy(); + } + + let index = this.actors_list.indexOf(actors); + if (index >= 0) + this.actors_list.splice(index, 1); } disable() { @@ -678,21 +522,8 @@ export const PanelBlur = class PanelBlur { this.update_light_text_classname(true); - this.actors_list.forEach(actors => { - this.set_should_override_panel(actors, false); - this.effects_manager.remove(actors.effects.noise); - this.effects_manager.remove(actors.effects.color); - this.effects_manager.remove(actors.effects.blur); - try { - actors.widgets.panel_box.remove_child( - actors.widgets.background_parent - ); - } catch (e) { } - actors.widgets.background_parent?.destroy(); - }); - - this.destroy_blur_effects(); - + const immutable_actors_list = [...this.actors_list]; + immutable_actors_list.forEach(actors => this.destroy_blur(actors, false)); this.actors_list = []; this.connections.disconnect_all(); diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/screenshot.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/screenshot.js index 8241f0c..dcf05eb 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/screenshot.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/screenshot.js @@ -1,41 +1,21 @@ -import Shell from 'gi://Shell'; -import Meta from 'gi://Meta'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; +import { Pipeline } from '../conveniences/pipeline.js'; export const ScreenshotBlur = class ScreenshotBlur { constructor(connections, settings, effects_manager) { this.connections = connections; - this.effects = []; this.settings = settings; + this.screenshot_background_managers = []; this.effects_manager = effects_manager; } enable() { this._log("blurring screenshot's window selector"); - // connect to every background change (even without changing image) - // FIXME this signal is fired very often, so we should find another one - // fired only when necessary (but that still catches all cases) - this.connections.connect( - Main.layoutManager._backgroundGroup, - 'notify', - _ => { - this._log("updated background for screenshot's window selector"); - this.update_backgrounds(); - } - ); - // connect to monitors change - this.connections.connect( - Main.layoutManager, - 'monitors-changed', - _ => { - if (Main.screenShield && !Main.screenShield.locked) { - this._log("changed monitors for screenshot's window selector"); - this.update_backgrounds(); - } - } + this.connections.connect(Main.layoutManager, 'monitors-changed', + _ => this.update_backgrounds() ); // update backgrounds when the component is enabled @@ -44,121 +24,78 @@ export const ScreenshotBlur = class ScreenshotBlur { update_backgrounds() { // remove every old background - this.remove(); - - // add new backgrounds + this.remove_background_actors(); + // create new backgrounds for the screenshot window selector for (let i = 0; i < Main.screenshotUI._windowSelectors.length; i++) { - const actor = Main.screenshotUI._windowSelectors[i]; - const monitor = Main.layoutManager.monitors[i]; + const window_selector = Main.screenshotUI._windowSelectors[i]; + const pipeline = new Pipeline( + this.effects_manager, + global.blur_my_shell._pipelines_manager, + this.settings.screenshot.PIPELINE + ); + pipeline.create_background_with_effects( + window_selector._monitorIndex, this.screenshot_background_managers, + window_selector, 'bms-screenshot-blurred-widget', false + ); - if (!monitor) - continue; + // prevent old `BackgroundActor` from being accessed, which creates a whole bug of logs + this.connections.connect(window_selector.get_parent(), 'destroy', _ => { + this.screenshot_background_managers.forEach(background_manager => { + if (background_manager.backgroundActor) { + let widget = background_manager.backgroundActor.get_parent(); + let parent = widget?.get_parent(); - const bg_actor = this.create_background_actor(monitor); - actor.insert_child_at_index(bg_actor, 0); - actor._blur_actor = bg_actor; + if (parent == window_selector) { + background_manager._bms_pipeline.destroy(); + parent.remove_child(widget); + } + } + background_manager.destroy(); + }); + + window_selector.get_children().forEach(child => { + if (child.get_name() == 'bms-screenshot-blurred-widget') + window_selector.remove_child(child); + }); + + let index = this.screenshot_background_managers.indexOf(window_selector); + this.screenshot_background_managers.splice(index, 1); + }); } } - create_background_actor(monitor) { - let bg_actor = new Meta.BackgroundActor({ - meta_display: global.display, - monitor: monitor.index + update_pipeline() { + this.screenshot_background_managers.forEach(background_manager => + background_manager._bms_pipeline.change_pipeline_to( + this.settings.screenshot.PIPELINE + ) + ); + } + + remove_background_actors() { + this.screenshot_background_managers.forEach(background_manager => { + background_manager._bms_pipeline.destroy(); + if (background_manager.backgroundActor) { + let widget = background_manager.backgroundActor.get_parent(); + widget?.get_parent()?.remove_child(widget); + } + background_manager.destroy(); }); - let background = Main.layoutManager._backgroundGroup.get_child_at_index( - Main.layoutManager.monitors.length - monitor.index - 1 + + Main.screenshotUI._windowSelectors.forEach(window_selector => + window_selector.get_children().forEach(child => { + if (child.get_name() == 'bms-screenshot-blurred-widget') + window_selector.remove_child(child); + }) ); - if (!background) { - this._warn("could not get background for screenshot's window selector"); - return bg_actor; - } - - bg_actor.content.set({ - background: background.get_content().background - }); - - let blur_effect = new Shell.BlurEffect({ - brightness: this.settings.screenshot.CUSTOMIZE - ? this.settings.screenshot.BRIGHTNESS - : this.settings.BRIGHTNESS, - radius: (this.settings.screenshot.CUSTOMIZE - ? this.settings.screenshot.SIGMA - : this.settings.SIGMA) * 2 * monitor.geometry_scale, - mode: Shell.BlurMode.ACTOR - }); - - // store the scale in the effect in order to retrieve it in set_sigma - blur_effect.scale = monitor.geometry_scale; - - let color_effect = this.effects_manager.new_color_effect({ - color: this.settings.screenshot.CUSTOMIZE - ? this.settings.screenshot.COLOR - : this.settings.COLOR - }, this.settings); - - let noise_effect = this.effects_manager.new_noise_effect({ - noise: this.settings.screenshot.CUSTOMIZE - ? this.settings.screenshot.NOISE_AMOUNT - : this.settings.NOISE_AMOUNT, - lightness: this.settings.screenshot.CUSTOMIZE - ? this.settings.screenshot.NOISE_LIGHTNESS - : this.settings.NOISE_LIGHTNESS - }, this.settings); - - bg_actor.add_effect(color_effect); - bg_actor.add_effect(noise_effect); - bg_actor.add_effect(blur_effect); - this.effects.push({ blur_effect, color_effect, noise_effect }); - - return bg_actor; - } - - set_sigma(s) { - this.effects.forEach(effect => { - effect.blur_effect.radius = s * 2 * effect.blur_effect; - }); - } - - set_brightness(b) { - this.effects.forEach(effect => { - effect.blur_effect.brightness = b; - }); - } - - set_color(c) { - this.effects.forEach(effect => { - effect.color_effect.color = c; - }); - } - - set_noise_amount(n) { - this.effects.forEach(effect => { - effect.noise_effect.noise = n; - }); - } - - set_noise_lightness(l) { - this.effects.forEach(effect => { - effect.noise_effect.lightness = l; - }); - } - - remove() { - Main.screenshotUI._windowSelectors.forEach(actor => { - if (actor._blur_actor) { - actor.remove_child(actor._blur_actor); - actor._blur_actor.destroy(); - delete actor._blur_actor; - } - }); - this.effects = []; + this.screenshot_background_managers = []; } disable() { this._log("removing blur from screenshot's window selector"); - this.remove(); + this.remove_background_actors(); this.connections.disconnect_all(); } diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/window_list.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/window_list.js index 2ba50b4..6ab0644 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/window_list.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/components/window_list.js @@ -1,15 +1,16 @@ -import Shell from 'gi://Shell'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import { PaintSignals } from '../effects/paint_signals.js'; +import { PaintSignals } from '../conveniences/paint_signals.js'; +import { DummyPipeline } from '../conveniences/dummy_pipeline.js'; export const WindowListBlur = class WindowListBlur { - constructor(connections, settings, _) { + constructor(connections, settings, effects_manager) { this.connections = connections; this.settings = settings; this.paint_signals = new PaintSignals(connections); - this.effects = []; + this.effects_manager = effects_manager; + this.pipelines = []; } enable() { @@ -37,36 +38,35 @@ export const WindowListBlur = class WindowListBlur { }); } - try_blur(child) { + try_blur(actor) { if ( - child.constructor.name === "WindowList" && - child.style !== "background:transparent;" + actor.constructor.name === "WindowList" && + actor.style !== "background:transparent;" ) { this._log("found window list to blur"); - let blur_effect = new Shell.BlurEffect({ - name: 'window-list-blur', - radius: (this.settings.window_list.CUSTOMIZE - ? this.settings.window_list.SIGMA - : this.settings.SIGMA) * 2, - brightness: this.settings.window_list.CUSTOMIZE - ? this.settings.window_list.BRIGHTNESS - : this.settings.BRIGHTNESS, - mode: Shell.BlurMode.BACKGROUND - }); + const pipeline = new DummyPipeline( + this.effects_manager, this.settings.window_list + ); + pipeline.attach_effect_to_actor(actor); + this.pipelines.push(pipeline); - child.set_style("background:transparent;"); - child.add_effect(blur_effect); - this.effects.push({ blur_effect }); + actor.set_style("background:transparent;"); - child._windowList.get_children().forEach( - window => this.blur_window_button(window) + actor._windowList.get_children().forEach( + window => this.style_window_button(window) ); this.connections.connect( - child._windowList, + actor._windowList, 'child-added', - (_, window) => this.blur_window_button(window) + (_, window) => this.style_window_button(window) + ); + + this.connections.connect( + actor, + 'destroy', + _ => this.destroy_blur(pipeline, true) ); @@ -83,75 +83,61 @@ export const WindowListBlur = class WindowListBlur { if (this.settings.HACKS_LEVEL === 1) { this._log("window list hack level 1"); - this.paint_signals.connect(child, blur_effect); - - } else if (this.settings.HACKS_LEVEL === 2) { - this._log("window list hack level 2"); - - this.paint_signals.connect(child, blur_effect); + this.paint_signals.disconnect_all_for_actor(actor); + this.paint_signals.connect(actor, pipeline.effect); } else { - this.paint_signals.disconnect_all(); + this.paint_signals.disconnect_all_for_actor(actor); } } } - blur_window_button(window) { + style_window_button(window) { window.get_child_at_index(0).set_style( "box-shadow:none; background-color:rgba(0,0,0,0.2); border-radius:5px;" ); } - try_remove_blur(child) { - if ( - child.constructor.name === "WindowList" && - child.style === "background:transparent;" - ) { - child.style = null; - child.remove_effect_by_name('window-list-blur'); + // IMPORTANT: do never call this in a mutable `this.pipelines.forEach` + destroy_blur(pipeline, actor_destroyed = false) { + if (!actor_destroyed) { + this.remove_style(pipeline.actor); + this.paint_signals.disconnect_all_for_actor(pipeline.actor); + } - child._windowList.get_children().forEach( + pipeline.destroy(); + + let index = this.pipelines.indexOf(pipeline); + if (index >= 0) + this.pipelines.splice(pipeline, 1); + } + + remove_style(actor) { + if ( + actor.constructor.name === "WindowList" && + actor.style === "background:transparent;" + ) { + actor.style = null; + actor._windowList.get_children().forEach( child => child.get_child_at_index(0).set_style(null) ); } } - set_sigma(s) { - this.effects.forEach(effect => { - effect.blur_effect.radius = s * 2; - }); - } - - set_brightness(b) { - this.effects.forEach(effect => { - effect.blur_effect.brightness = b; - }); - } - - // not implemented for dynamic blur - set_color(c) { } - set_noise_amount(n) { } - set_noise_lightness(l) { } - hide() { - this.set_sigma(0); + this.pipelines.forEach(pipeline => pipeline.effect?.set_enabled(false)); } show() { - this.set_sigma( - this.settings.window_list.CUSTOMIZE - ? this.settings.window_list.SIGMA - : this.settings.SIGMA - ); + this.pipelines.forEach(pipeline => pipeline.effect?.set_enabled(true)); } disable() { this._log("removing blur from window list"); - Main.layoutManager.uiGroup.get_children().forEach( - child => this.try_remove_blur(child) - ); + const immutable_pipelines_list = [...this.pipelines]; + immutable_pipelines_list.forEach(pipeline => this.destroy_blur(pipeline)); - this.effects = []; + this.pipelines = []; this.connections.disconnect_all(); } diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/connections.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/connections.js index c15ef48..0583db3 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/connections.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/connections.js @@ -53,6 +53,7 @@ export const Connections = class Connections { this.buffer.splice(index, 1); } }); + infos.destroy_id = destroy_id; } this.buffer.push(infos); @@ -66,10 +67,12 @@ export const Connections = class Connections { ); // remove each of them - actor_connections.forEach((connection) => { + actor_connections.forEach(connection => { // disconnect try { connection.actor.disconnect(connection.id); + if ('destroy_id' in connection) + connection.actor.disconnect(connection.destroy_id); } catch (e) { this._warn(`error removing connection: ${e}; continuing`); } @@ -82,10 +85,12 @@ export const Connections = class Connections { /// Disconnect every connection for each actor. disconnect_all() { - this.buffer.forEach((connection) => { + this.buffer.forEach(connection => { // disconnect try { connection.actor.disconnect(connection.id); + if ('destroy_id' in connection) + connection.actor.disconnect(connection.destroy_id); } catch (e) { this._warn(`error removing connection: ${e}; continuing`); } diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/dummy_pipeline.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/dummy_pipeline.js new file mode 100644 index 0000000..544d68c --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/dummy_pipeline.js @@ -0,0 +1,112 @@ +import St from 'gi://St'; +import Clutter from 'gi://Clutter'; + +/// A dummy `Pipeline`, for dynamic blur only. +/// Instead of a pipeline id, we take the settings of the component we want to blur. +export const DummyPipeline = class DummyPipeline { + constructor(effects_manager, settings, actor = null) { + this.effects_manager = effects_manager; + this.settings = settings; + this.effect = null; + this.attach_effect_to_actor(actor); + } + + create_background_with_effect( + background_group, + widget_name + ) { + // create the new actor + this.actor = new St.Widget({ name: widget_name }); + + this.attach_effect_to_actor(this.actor); + + // a dummy `BackgroundManager`, just to access the pipeline easily + let bg_manager = new Clutter.Actor; + bg_manager.backgroundActor = this.actor; + bg_manager._bms_pipeline = this; + + background_group.insert_child_at_index(this.actor, 0); + + return [this.actor, bg_manager]; + }; + + attach_effect_to_actor(actor) { + // set the actor + if (actor) + this.actor = actor; + else { + this.remove_pipeline_from_actor(); + return; + } + + // build the new effect to be added + this.build_effect({ + unscaled_radius: 2 * this.settings.SIGMA, + brightness: this.settings.BRIGHTNESS, + }); + + this.actor_destroy_id = this.actor.connect( + "destroy", () => this.remove_pipeline_from_actor() + ); + + // add the effect to the actor + if (this.actor) + this.actor.add_effect(this.effect); + else + this._warn(`could not add effect to actor, actor does not exist anymore`); + } + + remove_pipeline_from_actor() { + this.remove_effect(); + if (this.actor && this.actor_destroy_id) + this.actor.disconnect(this.actor_destroy_id); + this.actor_destroy_id = null; + this.actor = null; + } + + build_effect(params) { + // create the effect + this.effect = this.effects_manager.new_native_dynamic_gaussian_blur_effect(params); + + // connect to settings changes, using the true gsettings object + this._sigma_changed_id = this.settings.settings.connect( + 'changed::sigma', () => this.effect.unscaled_radius = 2 * this.settings.SIGMA + ); + this._brightness_changed_id = this.settings.settings.connect( + 'changed::brightness', () => this.effect.brightness = this.settings.BRIGHTNESS + ); + } + + repaint_effect() { + this.effect?.queue_repaint(); + } + + /// Remove every effect from the actor it is attached to. Please note that they are not + /// destroyed, but rather stored (thanks to the `EffectManager` class) to be reused later. + remove_effect() { + if (this.effect) + this.effects_manager.remove(this.effect); + this.effect = null; + + if (this._sigma_changed_id) + this.settings.settings.disconnect(this._sigma_changed_id); + if (this._brightness_changed_id) + this.settings.settings.disconnect(this._brightness_changed_id); + delete this._sigma_changed_id; + delete this._brightness_changed_id; + } + + /// Do nothing for this dummy pipeline. + /// Note: exposed to public API. + change_pipeline_to() { return; } + + /// Note: exposed to public API. + destroy() { + this.remove_effect(); + this.remove_pipeline_from_actor(); + } + + _warn(str) { + console.warn(`[Blur my Shell > dummy pip] ${str}`); + } +}; \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/effects_manager.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/effects_manager.js index 7ef7b22..947d535 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/effects_manager.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/effects_manager.js @@ -1,21 +1,41 @@ -import { ColorEffect } from '../effects/color_effect.js'; -import { NoiseEffect } from '../effects/noise_effect.js'; - +import { get_supported_effects } from '../effects/effects.js'; /// An object to manage effects (by not destroying them all the time) export const EffectsManager = class EffectsManager { constructor(connections) { this.connections = connections; this.used = []; - this.color_effects = []; - this.noise_effects = []; + this.SUPPORTED_EFFECTS = get_supported_effects(); + + Object.keys(this.SUPPORTED_EFFECTS).forEach(effect_name => { + // init the arrays containing each unused effect + this[effect_name + '_effects'] = []; + + // init the functions for each effect + this['new_' + effect_name + '_effect'] = function (params) { + let effect; + if (this[effect_name + '_effects'].length > 0) { + effect = this[effect_name + '_effects'].splice(0, 1)[0]; + effect.set({ + ...this.SUPPORTED_EFFECTS[effect_name].class.default_params, ...params + }); + } else + effect = new this.SUPPORTED_EFFECTS[effect_name].class({ + ...this.SUPPORTED_EFFECTS[effect_name].class.default_params, ...params + }); + + this.used.push(effect); + this.connect_to_destroy(effect); + return effect; + }; + }); } connect_to_destroy(effect) { effect.old_actor = effect.get_actor(); if (effect.old_actor) effect.old_actor_id = effect.old_actor.connect('destroy', _ => { - this.remove(effect); + this.remove(effect, true); }); this.connections.connect(effect, 'notify::actor', _ => { @@ -24,42 +44,22 @@ export const EffectsManager = class EffectsManager { if (effect.old_actor && actor != effect.old_actor) effect.old_actor.disconnect(effect.old_actor_id); - if (actor) { + if (actor && actor != effect.old_actor) { effect.old_actor_id = actor.connect('destroy', _ => { - this.remove(effect); + this.remove(effect, true); }); } }); } - new_color_effect(params, settings) { - let effect; - if (this.color_effects.length > 0) { - effect = this.color_effects.splice(0, 1)[0]; - effect.set(params); - } else - effect = new ColorEffect(params, settings); - - this.used.push(effect); - this.connect_to_destroy(effect); - return effect; - } - - new_noise_effect(params, settings) { - let effect; - if (this.noise_effects.length > 0) { - effect = this.noise_effects.splice(0, 1)[0]; - effect.set(params); - } else - effect = new NoiseEffect(params, settings); - - this.used.push(effect); - this.connect_to_destroy(effect); - return effect; - } - - remove(effect) { - effect.get_actor()?.remove_effect(effect); + // IMPORTANT: do never call this in a mutable `this.used.forEach` + remove(effect, actor_already_destroyed = false) { + if (!actor_already_destroyed) + try { + effect.get_actor()?.remove_effect(effect); + } catch (e) { + this._warn(`could not remove the effect, continuing: ${e}`); + } if (effect.old_actor) effect.old_actor.disconnect(effect.old_actor_id); delete effect.old_actor; @@ -69,21 +69,22 @@ export const EffectsManager = class EffectsManager { if (index >= 0) { this.used.splice(index, 1); - if (effect instanceof ColorEffect) - this.color_effects.push(effect); - else if (effect instanceof NoiseEffect) - this.noise_effects.push(effect); + Object.keys(this.SUPPORTED_EFFECTS).forEach(effect_name => { + if (effect instanceof this.SUPPORTED_EFFECTS[effect_name].class) + this[effect_name + '_effects'].push(effect); + }); } } destroy_all() { - this.used.forEach(effect => { this.remove(effect); }); - [ - this.used, - this.color_effects, - this.noise_effects - ].forEach(array => { - array.splice(0, array.length); + const immutable_used_list = [...this.used]; + immutable_used_list.forEach(effect => this.remove(effect)); + Object.keys(this.SUPPORTED_EFFECTS).forEach(effect_name => { + this[effect_name + '_effects'].splice(0, this[effect_name + '_effects'].length); }); } + + _warn(str) { + console.warn(`[Blur my Shell > effects mng] ${str}`); + } }; diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/keys.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/keys.js index 71a357c..1e1dba8 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/keys.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/keys.js @@ -1,15 +1,10 @@ import { Type } from './settings.js'; // This lists the preferences keys -export const Keys = [ +export const KEYS = [ { component: "general", schemas: [ - { type: Type.I, name: "sigma" }, - { type: Type.D, name: "brightness" }, - { type: Type.C, name: "color" }, - { type: Type.D, name: "noise-amount" }, - { type: Type.D, name: "noise-lightness" }, - { type: Type.B, name: "color-and-noise" }, + { type: Type.PIPELINES, name: "pipelines" }, { type: Type.I, name: "hacks-level" }, { type: Type.B, name: "debug" }, ] @@ -17,37 +12,25 @@ export const Keys = [ { component: "overview", schemas: [ { type: Type.B, name: "blur" }, - { type: Type.B, name: "customize" }, - { type: Type.I, name: "sigma" }, - { type: Type.D, name: "brightness" }, - { type: Type.C, name: "color" }, - { type: Type.D, name: "noise-amount" }, - { type: Type.D, name: "noise-lightness" }, + { type: Type.S, name: "pipeline" }, { type: Type.I, name: "style-components" }, ] }, { component: "appfolder", schemas: [ { type: Type.B, name: "blur" }, - { type: Type.B, name: "customize" }, { type: Type.I, name: "sigma" }, { type: Type.D, name: "brightness" }, - { type: Type.C, name: "color" }, - { type: Type.D, name: "noise-amount" }, - { type: Type.D, name: "noise-lightness" }, { type: Type.I, name: "style-dialogs" }, ] }, { component: "panel", schemas: [ { type: Type.B, name: "blur" }, - { type: Type.B, name: "customize" }, + { type: Type.B, name: "static-blur" }, + { type: Type.S, name: "pipeline" }, { type: Type.I, name: "sigma" }, { type: Type.D, name: "brightness" }, - { type: Type.C, name: "color" }, - { type: Type.D, name: "noise-amount" }, - { type: Type.D, name: "noise-lightness" }, - { type: Type.B, name: "static-blur" }, { type: Type.B, name: "unblur-in-overview" }, { type: Type.B, name: "force-light-text" }, { type: Type.B, name: "override-background" }, @@ -58,29 +41,22 @@ export const Keys = [ { component: "dash-to-dock", schemas: [ { type: Type.B, name: "blur" }, - { type: Type.B, name: "customize" }, + { type: Type.B, name: "static-blur" }, + { type: Type.S, name: "pipeline" }, { type: Type.I, name: "sigma" }, { type: Type.D, name: "brightness" }, - { type: Type.C, name: "color" }, - { type: Type.D, name: "noise-amount" }, - { type: Type.D, name: "noise-lightness" }, - { type: Type.B, name: "static-blur" }, { type: Type.B, name: "unblur-in-overview" }, { type: Type.B, name: "override-background" }, { type: Type.I, name: "style-dash-to-dock" }, - { type: Type.I, name: "corner-radius" }, ] }, { component: "applications", schemas: [ { type: Type.B, name: "blur" }, - { type: Type.B, name: "customize" }, { type: Type.I, name: "sigma" }, { type: Type.D, name: "brightness" }, - { type: Type.C, name: "color" }, - { type: Type.D, name: "noise-amount" }, - { type: Type.D, name: "noise-lightness" }, { type: Type.I, name: "opacity" }, + { type: Type.B, name: "dynamic-opacity" }, { type: Type.B, name: "blur-on-overview" }, { type: Type.B, name: "enable-all" }, { type: Type.AS, name: "whitelist" }, @@ -90,34 +66,27 @@ export const Keys = [ { component: "lockscreen", schemas: [ { type: Type.B, name: "blur" }, - { type: Type.B, name: "customize" }, - { type: Type.I, name: "sigma" }, - { type: Type.D, name: "brightness" }, - { type: Type.C, name: "color" }, - { type: Type.D, name: "noise-amount" }, - { type: Type.D, name: "noise-lightness" }, + { type: Type.S, name: "pipeline" }, ] }, { component: "window-list", schemas: [ { type: Type.B, name: "blur" }, - { type: Type.B, name: "customize" }, + { type: Type.S, name: "pipeline" }, { type: Type.I, name: "sigma" }, { type: Type.D, name: "brightness" }, - { type: Type.C, name: "color" }, - { type: Type.D, name: "noise-amount" }, - { type: Type.D, name: "noise-lightness" }, + ] + }, + { + component: "coverflow-alt-tab", schemas: [ + { type: Type.B, name: "blur" }, + { type: Type.S, name: "pipeline" }, ] }, { component: "screenshot", schemas: [ { type: Type.B, name: "blur" }, - { type: Type.B, name: "customize" }, - { type: Type.I, name: "sigma" }, - { type: Type.D, name: "brightness" }, - { type: Type.C, name: "color" }, - { type: Type.D, name: "noise-amount" }, - { type: Type.D, name: "noise-lightness" }, + { type: Type.S, name: "pipeline" }, ] }, { @@ -130,4 +99,90 @@ export const Keys = [ { type: Type.B, name: "blur-original-panel" }, ] }, +]; + + +// This lists the deprecated preferences keys +export const DEPRECATED_KEYS = [ + { + component: "general", schemas: [ + { type: Type.I, name: "sigma" }, + { type: Type.D, name: "brightness" }, + { type: Type.C, name: "color" }, + { type: Type.D, name: "noise-amount" }, + { type: Type.D, name: "noise-lightness" }, + { type: Type.B, name: "color-and-noise" }, + ] + }, + { + component: "overview", schemas: [ + { type: Type.B, name: "customize" }, + { type: Type.I, name: "sigma" }, + { type: Type.D, name: "brightness" }, + { type: Type.C, name: "color" }, + { type: Type.D, name: "noise-amount" }, + { type: Type.D, name: "noise-lightness" }, + ] + }, + { + component: "appfolder", schemas: [ + { type: Type.B, name: "customize" }, + { type: Type.C, name: "color" }, + { type: Type.D, name: "noise-amount" }, + { type: Type.D, name: "noise-lightness" }, + ] + }, + { + component: "panel", schemas: [ + { type: Type.B, name: "customize" }, + { type: Type.C, name: "color" }, + { type: Type.D, name: "noise-amount" }, + { type: Type.D, name: "noise-lightness" }, + ] + }, + { + component: "dash-to-dock", schemas: [ + { type: Type.B, name: "customize" }, + { type: Type.C, name: "color" }, + { type: Type.D, name: "noise-amount" }, + { type: Type.D, name: "noise-lightness" }, + { type: Type.I, name: "corner-radius" }, + ] + }, + { + component: "applications", schemas: [ + { type: Type.B, name: "customize" }, + { type: Type.C, name: "color" }, + { type: Type.D, name: "noise-amount" }, + { type: Type.D, name: "noise-lightness" }, + ] + }, + { + component: "lockscreen", schemas: [ + { type: Type.B, name: "customize" }, + { type: Type.I, name: "sigma" }, + { type: Type.D, name: "brightness" }, + { type: Type.C, name: "color" }, + { type: Type.D, name: "noise-amount" }, + { type: Type.D, name: "noise-lightness" }, + ] + }, + { + component: "window-list", schemas: [ + { type: Type.B, name: "customize" }, + { type: Type.C, name: "color" }, + { type: Type.D, name: "noise-amount" }, + { type: Type.D, name: "noise-lightness" }, + ] + }, + { + component: "screenshot", schemas: [ + { type: Type.B, name: "customize" }, + { type: Type.I, name: "sigma" }, + { type: Type.D, name: "brightness" }, + { type: Type.C, name: "color" }, + { type: Type.D, name: "noise-amount" }, + { type: Type.D, name: "noise-lightness" }, + ] + }, ]; \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/paint_signals.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/paint_signals.js similarity index 92% rename from gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/paint_signals.js rename to gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/paint_signals.js index 84a895b..5fbfee4 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/paint_signals.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/paint_signals.js @@ -37,7 +37,8 @@ export const PaintSignals = class PaintSignals { ) ) this.connections.connect(actor, 'destroy', () => { - this.buffer.forEach(infos => { + const immutable_buffer = [...this.buffer]; + immutable_buffer.forEach(infos => { if (infos.actor === actor) { // remove from buffer let index = this.buffer.indexOf(infos); @@ -50,7 +51,8 @@ export const PaintSignals = class PaintSignals { } disconnect_all_for_actor(actor) { - this.buffer.forEach(infos => { + const immutable_buffer = [...this.buffer]; + immutable_buffer.forEach(infos => { if (infos.actor === actor) { this.connections.disconnect_all_for(infos.paint_effect); infos.actor.remove_effect(infos.paint_effect); diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/pipeline.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/pipeline.js new file mode 100644 index 0000000..84b1d7a --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/pipeline.js @@ -0,0 +1,223 @@ +import St from 'gi://St'; +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; +import * as Background from 'resource:///org/gnome/shell/ui/background.js'; + +/// A `Pipeline` object is a handy way to manage the effects attached to an actor. It only manages +/// one actor at a time (so blurring multiple widgets will need multiple `Pipeline`), and is +/// linked to a `pipeline_id` that has been (hopefully) defined in the settings. +/// +/// It communicates with the settings through the `PipelinesManager` object, and receives different +/// signals (with `pipeline_id` being an unique string): +/// - `'pipeline_id'::pipeline-updated`, handing a new pipeline descriptor object, when the pipeline +/// has been changed enough that it needs to rebuild the effects configuration +/// - `'pipeline_id'::pipeline-destroyed`, when the pipeline has been destroyed; thus making the +/// `Pipeline` change its id to `pipeline_default` +/// +/// And each effect, with an unique `id`, is connected to the `PipelinesManager` for the signals: +/// - `'pipeline_id'::effect-'id'-key-removed`, handing the key that was removed +/// - `'pipeline_id'::effect-'id'-key-updated`, handing the key that was changed and its new value +/// - `'pipeline_id'::effect-'id'-key-added`, handing the key that was added and its value +export const Pipeline = class Pipeline { + constructor(effects_manager, pipelines_manager, pipeline_id, actor = null) { + this.effects_manager = effects_manager; + this.pipelines_manager = pipelines_manager; + this.effects = []; + this.set_pipeline_id(pipeline_id); + this.attach_pipeline_to_actor(actor); + } + + /// Create a background linked to the monitor with index `monitor_index`, with a + /// `BackgroundManager` that is appended to the list `background_managers`. The background actor + /// will be given the name `widget_name` and inserted into the given `background_group`. + /// If `use_absolute_position` is false, then the position used is at (0,0); useful when the + /// positioning is relative. + /// Note: exposed to public API. + create_background_with_effects( + monitor_index, + background_managers, + background_group, + widget_name, + use_absolute_position = true + ) { + let monitor = Main.layoutManager.monitors[monitor_index]; + + // create the new actor + this.actor = new St.Widget({ + name: widget_name, + x: use_absolute_position ? monitor.x : 0, + y: .5 + (use_absolute_position ? monitor.y : 0), // add 1 to correct z-position + z_position: 1, // seems to fix the multi-monitor glitch + width: monitor.width, + height: monitor.height + }); + + // remove the effects, wether or not we attach the pipeline to the actor: if they are fired + // while the actor has changed, this could go bad + this.remove_all_effects(); + if (this.pipeline_id) + this.attach_pipeline_to_actor(this.actor); + + let bg_manager = new Background.BackgroundManager({ + container: this.actor, + monitorIndex: monitor_index, + controlPosition: false, + }); + bg_manager._bms_pipeline = this; + + background_managers.push(bg_manager); + background_group.insert_child_at_index(this.actor, 0); + + return this.actor; + }; + + /// Set the pipeline id, correctly connecting the `Pipeline` object to listen the pipelines + /// manager for pipeline-wide changes. This does not update the effects in consequence, call + /// `change_pipeline_to` instead if you want to reconstruct the effects too. + set_pipeline_id(pipeline_id) { + // disconnect ancient signals + this.remove_connections(); + + // change the id + this.pipeline_id = pipeline_id; + + // connect to settings changes + this._pipeline_changed_id = this.pipelines_manager.connect( + this.pipeline_id + '::pipeline-updated', + (_, new_pipeline) => this.update_effects_from_pipeline(new_pipeline) + ); + this._pipeline_destroyed_id = this.pipelines_manager.connect( + this.pipeline_id + '::pipeline-destroyed', + _ => this.change_pipeline_to("pipeline_default") + ); + } + + /// Disconnect the signals for the pipeline changes. Please note that the signals related to the + /// effects are stored with them and removed with `remove_all_effects`. + remove_connections() { + if (this._pipeline_changed_id) + this.pipelines_manager.disconnect(this._pipeline_changed_id); + if (this._pipeline_destroyed_id) + this.pipelines_manager.disconnect(this._pipeline_destroyed_id); + this._pipeline_changed_id = null; + this._pipeline_destroyed_id = null; + } + + /// Attach a Pipeline object with `pipeline_id` already set to an actor. + attach_pipeline_to_actor(actor) { + // set the actor + if (actor) + this.actor = actor; + else { + this.remove_pipeline_from_actor(); + return; + } + + // attach the pipeline + let pipeline = this.pipelines_manager.pipelines[this.pipeline_id]; + if (!pipeline) { + this._warn(`could not attach pipeline to actor, pipeline "${this.pipeline_id}" not found`); + // do not recurse... + if ("pipeline_default" in this.pipelines_manager.pipelines) { + this.set_pipeline_id("pipeline_default"); + pipeline = this.pipelines_manager.pipelines["pipeline_default"]; + } else + return; + } + + this.actor_destroy_id = this.actor.connect( + "destroy", () => this.remove_pipeline_from_actor() + ); + + // update the effects + this.update_effects_from_pipeline(pipeline); + } + + remove_pipeline_from_actor() { + this.remove_all_effects(); + if (this.actor && this.actor_destroy_id) + this.actor.disconnect(this.actor_destroy_id); + this.actor_destroy_id = null; + this.actor = null; + } + + /// Update the effects from the given pipeline object, the hard way. + update_effects_from_pipeline(pipeline) { + // remove all effects + this.remove_all_effects(); + + // build the new effects to be added + pipeline.effects.forEach(effect => { + if ('new_' + effect.type + '_effect' in this.effects_manager) + this.build_effect(effect); + else + this._warn(`could not add effect to actor, effect "${effect.type}" not found`); + }); + this.effects.reverse(); + + // add the effects to the actor + if (this.actor) + this.effects.forEach(effect => this.actor.add_effect(effect)); + else + this._warn(`could not add effect to actor, actor does not exist anymore`); + } + + /// Given an `effect_infos` object containing the effect type, id and params, build an effect + /// and append it to the effects list + build_effect(effect_infos) { + let effect = this.effects_manager['new_' + effect_infos.type + '_effect'](effect_infos.params); + this.effects.push(effect); + + // connect to settings changes + effect._effect_key_removed_id = this.pipelines_manager.connect( + this.pipeline_id + '::effect-' + effect_infos.id + '-key-removed', + (_, key) => effect[key] = effect.constructor.default_params[key] + ); + effect._effect_key_updated_id = this.pipelines_manager.connect( + this.pipeline_id + '::effect-' + effect_infos.id + '-key-updated', + (_, key, value) => effect[key] = value + ); + effect._effect_key_added_id = this.pipelines_manager.connect( + this.pipeline_id + '::effect-' + effect_infos.id + '-key-added', + (_, key, value) => effect[key] = value + ); + } + + /// Remove every effect from the actor it is attached to. Please note that they are not + /// destroyed, but rather stored (thanks to the `EffectManager` class) to be reused later. + remove_all_effects() { + this.effects.forEach(effect => { + this.effects_manager.remove(effect); + [ + effect._effect_key_removed_id, + effect._effect_key_updated_id, + effect._effect_key_added_id + ].forEach( + id => { if (id) this.pipelines_manager.disconnect(id); } + ); + delete effect._effect_key_removed_id; + delete effect._effect_key_updated_id; + delete effect._effect_key_added_id; + }); + this.effects = []; + } + + /// Change the pipeline id, and update the effects according to this change. + /// Note: exposed to public API. + change_pipeline_to(pipeline_id) { + this.set_pipeline_id(pipeline_id); + this.attach_pipeline_to_actor(this.actor); + } + + /// Resets the `Pipeline` object to a sane state, removing every effect and signal. + /// Note: exposed to public API. + destroy() { + this.remove_all_effects(); + this.remove_connections(); + this.remove_pipeline_from_actor(); + this.pipeline_id = null; + } + + _warn(str) { + console.warn(`[Blur my Shell > pipeline] ${str}`); + } +}; \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/pipelines_manager.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/pipelines_manager.js new file mode 100644 index 0000000..0fdfe9e --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/pipelines_manager.js @@ -0,0 +1,168 @@ +const Signals = imports.signals; + +/// The `PipelinesManager` object permits to store the list of pipelines and their effects in +/// memory. It is meant to *always* be in sync with the `org.gnome.shell.extensions.blur-my-shell`'s +/// `pipelines` gschema. However, we do not want to re-create every effect each time this schema is +/// changed, so the pipelines manager handles it, and dispatches the updates with targeted signals. +/// +/// It is only connected to ONE signal (the pipelines schema being changed), and emits numerous +/// which are connected to by both the different `Pipeline` objects in the extension, and by the +/// different pages of the extension preferences. +/// It emits three different types of signals: +/// +/// - general changes to the pipelines list, connected to by the extension preferences: +/// - `pipeline-list-changed`, when the list of pipelines has changed (by creation or deletion) +/// - `pipeline-names-changed`, when the name of a pipeline is changed +/// +/// - signals that are targeted towards a given pipeline, with `pipeline_id` being its unique id: +/// - `'pipeline_id'::pipeline-updated`, handing a new pipeline descriptor object, when the +/// pipeline has been changed quite a bit (added/destroyed/reordered the effects) +/// - `'pipeline_id'::pipeline-destroyed`, when the pipeline has been destroyed +/// - `'pipeline_id'::pipeline-renamed`, handing the new name, when the pipeline has been +/// renamed, which is only important for the preferences +/// +/// - signals that are targeted towards a given effect, with `effect_id` being its unique id, and +/// `pipeline_id` the unique id of the pipeline it is attached to: +/// - `'pipeline_id'::effect-'effect_id'-key-removed`, handing the key that was removed +/// - `'pipeline_id'::effect-'effect_id'-key-updated`, handing the key that was changed and its +/// new value +/// - `'pipeline_id'::effect-'effect_id'-key-added`, handing the key that was added and its +/// value +export class PipelinesManager { + constructor(settings) { + this.settings = settings; + this.pipelines = this.settings.PIPELINES; + this.settings.PIPELINES_changed(_ => this.on_pipeline_update()); + } + + create_pipeline(name, effects = []) { + // select a random id for the pipeline + let id = "pipeline_" + ("" + Math.random()).slice(2, 16); + // add a random ID for each effect, to help tracking them + effects.forEach(effect => effect.id = "effect_" + ("" + Math.random()).slice(2, 16)); + + this.pipelines[id] = { name, effects }; + this.settings.PIPELINES = this.pipelines; + this._emit('pipeline-created', id, this.pipelines[id]); + this._emit('pipeline-list-changed'); + return id; + } + + duplicate_pipeline(id) { + if (!(id in this.pipelines)) { + this._warn(`could not duplicate pipeline, id ${id} does not exist`); + return; + } + const pipeline = this.pipelines[id]; + this.create_pipeline(pipeline.name + " - duplicate", [...pipeline.effects]); + this.settings.PIPELINES = this.pipelines; + } + + delete_pipeline(id) { + if (!(id in this.pipelines)) { + this._warn(`could not delete pipeline, id ${id} does not exist`); + return; + } + if (id == "pipeline_default") { + this._warn(`could not delete pipeline "pipeline_default" as it is immutable`); + return; + } + delete this.pipelines[id]; + this.settings.PIPELINES = this.pipelines; + this._emit(id + '::pipeline-destroyed'); + this._emit('pipeline-list-changed'); + } + + update_pipeline_effects(id, effects, emit_update_signal = true) { + if (!(id in this.pipelines)) { + this._warn(`could not update pipeline effects, id ${id} does not exist`); + return; + } + this.pipelines[id].effects = [...effects]; + this.settings.PIPELINES = this.pipelines; + if (emit_update_signal) + this._emit(id + '::pipeline-updated'); + } + + rename_pipeline(id, name) { + if (!(id in this.pipelines)) { + this._warn(`could not rename pipeline, id ${id} does not exist`); + return; + } + this.pipelines[id].name = name.slice(); + this.settings.PIPELINES = this.pipelines; + this._emit(id + '::pipeline-renamed', name); + this._emit('pipeline-names-changed'); + } + + on_pipeline_update() { + const old_pipelines = this.pipelines; + this.pipelines = this.settings.PIPELINES; + + for (var pipeline_id in old_pipelines) { + // if we find a pipeline that does not exist anymore, signal it + if (!(pipeline_id in this.pipelines)) { + this._emit(pipeline_id + '::pipeline-destroyed'); + continue; + } + + const old_pipeline = old_pipelines[pipeline_id]; + const new_pipeline = this.pipelines[pipeline_id]; + + // verify if both pipelines have effects in the same order + // if they have, then check for their parameters + if ( + old_pipeline.effects.length == new_pipeline.effects.length && + old_pipeline.effects.every((effect, i) => effect.id === new_pipeline.effects[i].id) + ) { + for (let i = 0; i < old_pipeline.effects.length; i++) { + const old_effect = old_pipeline.effects[i]; + const new_effect = new_pipeline.effects[i]; + const id = old_effect.id; + for (let key in old_effect.params) { + // if a key was removed, we emit to tell the effect to use the default value + if (!(key in new_effect.params)) + this._emit( + pipeline_id + '::effect-' + id + '-key-removed', key + ); + // if a key was updated, we emit to tell the effect to change its value + else if (old_effect.params[key] != new_effect.params[key]) + this._emit( + pipeline_id + '::effect-' + id + '-key-updated', key, new_effect.params[key] + ); + } + for (let key in new_effect.params) { + // if a key was added, we emit to tell the effect the key and its value + if (!(key in old_effect.params)) + this._emit( + pipeline_id + '::effect-' + id + '-key-added', key, new_effect.params[key] + ); + } + } + } + // if either the order has changed, or there are new effects, then rebuild it + else + this._emit(pipeline_id + '::pipeline-updated', new_pipeline); + } + } + + destroy() { + this.settings.PIPELINES_disconnect(); + } + + _emit(signal, ...args) { + this.emit(signal, ...args); + this._log(`signal: '${signal}', arguments: ${args}`); + } + + _log(str) { + if (this.settings.DEBUG) + console.log(`[Blur my Shell > pipelines] ${str}`); + } + + _warn(str) { + console.warn(`[Blur my Shell > pipelines] ${str}`); + } +} + +Signals.addSignalMethods(PipelinesManager.prototype); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/settings.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/settings.js index d2bef17..53f8497 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/settings.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/settings.js @@ -1,5 +1,4 @@ import GLib from 'gi://GLib'; - const Signals = imports.signals; /// An enum non-extensively describing the type of gsettings key. @@ -9,7 +8,8 @@ export const Type = { D: 'Double', S: 'String', C: 'Color', - AS: 'StringArray' + AS: 'StringArray', + PIPELINES: 'Pipelines' }; /// An object to get and manage the gsettings preferences. @@ -118,20 +118,197 @@ export const Settings = class Settings { } }); break; + + case Type.PIPELINES: + Object.defineProperty(component, property_name, { + get() { + let pips = component_settings.get_value(key.name).deep_unpack(); + Object.keys(pips).forEach(pipeline_id => { + let pipeline = pips[pipeline_id]; + + if (!('name' in pipeline)) { + this._warn('impossible to get pipelines, pipeline has not name, resetting'); + component[property_name + '_reset'](); + return component[property_name]; + } + let name = pipeline.name.deep_unpack(); + if (typeof name !== 'string') { + this._warn('impossible to get pipelines, pipeline name is not a string, resetting'); + component[property_name + '_reset'](); + return component[property_name]; + } + + if (!('effects' in pipeline)) { + this._warn('impossible to get pipelines, pipeline has not effects, resetting'); + component[property_name + '_reset'](); + return component[property_name]; + } + let effects = pipeline.effects.deep_unpack(); + if (!Array.isArray(effects)) { + this._warn('impossible to get pipelines, pipeline effects is not an array, resetting'); + component[property_name + '_reset'](); + return component[property_name]; + } + + effects = effects.map(effect => effect.deep_unpack()); + effects.forEach(effect => { + if (!('type' in effect)) { + this._warn('impossible to get pipelines, effect has not type, resetting'); + component[property_name + '_reset'](); + return component[property_name]; + } + let type = effect.type.deep_unpack(); + if (typeof type !== 'string') { + this._warn('impossible to get pipelines, effect type is not a string, resetting'); + component[property_name + '_reset'](); + return component[property_name]; + } + + if (!('id' in effect)) { + this._warn('impossible to get pipelines, effect has not id, resetting'); + component[property_name + '_reset'](); + return component[property_name]; + } + let id = effect.id.deep_unpack(); + if (typeof id !== 'string') { + this._warn('impossible to get pipelines, effect id is not a string, resetting'); + component[property_name + '_reset'](); + return component[property_name]; + } + + let params = {}; + if ('params' in effect) + params = effect.params.deep_unpack(); + if (!(params && typeof params === 'object' && params.constructor === Object)) { + this._warn('impossible to get pipelines, effect params is not an object, resetting'); + component[property_name + '_reset'](); + return component[property_name]; + } + Object.keys(params).forEach(param_key => { + params[param_key] = params[param_key].deep_unpack(); + }); + + effect.type = type; + effect.id = id; + effect.params = params; + }); + pipeline.name = name; + pipeline.effects = effects; + }); + return pips; + }, + set(pips) { + let pipelines = {}; + Object.keys(pips).forEach(pipeline_id => { + let pipeline = pips[pipeline_id]; + if (!(pipeline && typeof pipeline === 'object' && pipeline.constructor === Object)) { + this._warn('impossible to set pipelines, pipeline is not an object'); + return; + } + + if (!('name' in pipeline)) { + this._warn('impossible to set pipelines, pipeline has no name'); + return; + } + if (typeof pipeline.name !== 'string') { + this._warn('impossible to set pipelines, pipeline name is not a string'); + return; + } + + if (!('effects' in pipeline)) { + this._warn('impossible to set pipelines, pipeline has no effect'); + return; + } + if (!Array.isArray(pipeline.effects)) { + this._warn('impossible to set pipelines, effects is not an array'); + return; + } + + let gvariant_effects = []; + pipeline.effects.forEach(effect => { + if (!(effect instanceof Object)) { + this._warn('impossible to set pipelines, effect is not an object'); + return; + } + + if (!('type' in effect)) { + this._warn('impossible to set pipelines, effect has not type'); + return; + } + if (typeof effect.type !== 'string') { + this._warn('impossible to set pipelines, effect type is not a string'); + return; + } + + if (!('id' in effect)) { + this._warn('impossible to set pipelines, effect has not id'); + return; + } + if (typeof effect.id !== 'string') { + this._warn('impossible to set pipelines, effect id is not a string'); + return; + } + + let params = {}; + if ('params' in effect) { + params = effect.params; + } + let gvariant_params = {}; + Object.keys(params).forEach(param_key => { + let param = params[param_key]; + if (typeof param === 'boolean') + gvariant_params[param_key] = GLib.Variant.new_boolean(param); + else if (typeof param === 'number') { + if (Number.isInteger(param)) + gvariant_params[param_key] = GLib.Variant.new_int32(param); + else + gvariant_params[param_key] = GLib.Variant.new_double(param); + } else if (typeof param === 'string') + gvariant_params[param_key] = GLib.Variant.new_string(param); + else if (Array.isArray(param) && param.length == 4) + gvariant_params[param_key] = new GLib.Variant("(dddd)", param); + else + this._warn('impossible to set pipeline, effect parameter type is unknown'); + }); + + gvariant_effects.push( + new GLib.Variant("a{sv}", { + type: GLib.Variant.new_string(effect.type), + id: GLib.Variant.new_string(effect.id), + params: new GLib.Variant("a{sv}", gvariant_params) + }) + ); + }); + + pipelines[pipeline_id] = { + name: GLib.Variant.new_string(pipeline.name), + effects: new GLib.Variant("av", gvariant_effects) + }; + }); + let val = new GLib.Variant("a{sa{sv}}", pipelines); + component_settings.set_value(key.name, val); + } + }); + break; } + component[property_name + '_reset'] = function () { return component_settings.reset(key.name); }; + component[property_name + '_signal_ids'] = []; component[property_name + '_changed'] = function (cb) { - return component_settings.connect('changed::' + key.name, cb); + component[property_name + '_signal_ids'].push( + component_settings.connect('changed::' + key.name, cb) + ); }; component[property_name + '_disconnect'] = function () { - return component_settings.disconnect.apply( - component_settings, arguments + component[property_name + '_signal_ids'].forEach( + id => component_settings.disconnect(id) ); + component[property_name + '_signal_ids'] = []; }; }); }); @@ -177,6 +354,10 @@ export const Settings = class Settings { }); }); } + + _warn(str) { + console.warn(`[Blur my Shell > settings] ${str}`); + } }; Signals.addSignalMethods(Settings.prototype); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/settings_updater.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/settings_updater.js new file mode 100644 index 0000000..2affbc1 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/settings_updater.js @@ -0,0 +1,40 @@ +import { Settings } from './settings.js'; +import { KEYS, DEPRECATED_KEYS } from './keys.js'; + +const CURRENT_SETTINGS_VERSION = 2; + +export function update_from_old_settings(gsettings) { + const preferences = new Settings(KEYS, gsettings); + const deprecated_preferences = new Settings(DEPRECATED_KEYS, gsettings); + const old_version = preferences.settings.get_int('settings-version'); + + if (old_version < CURRENT_SETTINGS_VERSION) { + // set artifacts hacks to be 1 at most, as it should be suitable now that most big bugs have + // been resolved (and especially because hack levels to 2 now means disabling clipped + // redraws entirely, which is very much not what we want for users that update) + if (preferences.HACKS_LEVEL > 1) + preferences.HACKS_LEVEL = 1; + + // enable dash-to-dock blurring, as most disabled it due to the lack of rounded corners; set + // it to static blur by default too and with transparent background + preferences.dash_to_dock.BLUR = true; + preferences.dash_to_dock.STATIC_BLUR = true; + preferences.dash_to_dock.STYLE_DASH_TO_DOCK = 0; + + // 'customize' has been removed: we merge the current used settings + ['appfolder', 'panel', 'dash_to_dock', 'applications', 'window_list'].forEach( + component_name => { + const deprecated_component = deprecated_preferences[component_name]; + const new_component = preferences[component_name]; + if (!deprecated_component.CUSTOMIZE) { + new_component.SIGMA = deprecated_preferences.SIGMA; + new_component.BRIGHTNESS = deprecated_preferences.BRIGHTNESS; + } + }); + + // remove old preferences in order not to clutter the gsettings + deprecated_preferences.reset(); + } + + preferences.settings.set_int('settings-version', CURRENT_SETTINGS_VERSION); +} \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/utils.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/utils.js new file mode 100644 index 0000000..0277e0e --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/conveniences/utils.js @@ -0,0 +1,38 @@ +import GLib from 'gi://GLib'; + +export const IS_IN_PREFERENCES = typeof global === 'undefined'; + +// Taken from https://github.com/Schneegans/Burn-My-Windows/blob/main/src/utils.js +// This method can be used to import a module in the GNOME Shell process only. This +// is useful if you want to use a module in extension.js, but not in the preferences +// process. This method returns null if it is called in the preferences process. +export async function import_in_shell_only(module) { + if (IS_IN_PREFERENCES) + return null; + return (await import(module)).default; +} + +// In use for the effects, to prevent boilerplate code +export function setup_params(outer_this, params) { + // setup each parameter, either with the given or the default value + for (const params_name in outer_this.constructor.default_params) { + outer_this["_" + params_name] = null; + outer_this[params_name] = params_name in params ? + params[params_name] : + outer_this.constructor.default_params[params_name]; + } +}; + +export const get_shader_source = (Shell, shader_filename, self_uri) => { + if (!Shell) + return; + const shader_path = GLib.filename_from_uri( + GLib.uri_resolve_relative(self_uri, shader_filename, GLib.UriFlags.NONE) + )[0]; + try { + return Shell.get_file_contents_utf8_sync(shader_path); + } catch (e) { + console.warn(`[Blur my Shell > effect] error loading shader from ${shader_path}: ${e}`); + return null; + } +}; \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/blur_effect.glsl b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/blur_effect.glsl deleted file mode 100644 index 37059ae..0000000 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/blur_effect.glsl +++ /dev/null @@ -1,114 +0,0 @@ -uniform sampler2D tex; -uniform float sigma; -uniform int dir; -uniform float brightness; -uniform float corner_radius; -uniform float width; -uniform float height; - -float circleBounds(vec2 p, vec2 center, float clip_radius) { - vec2 delta = p - center; - float dist_squared = dot(delta, delta); - - float outer_radius = clip_radius + 0.5; - if (dist_squared >= (outer_radius * outer_radius)) - return 0.0; - - float inner_radius = clip_radius - 0.5; - if (dist_squared <= (inner_radius * inner_radius)) - return 1.0; - - return outer_radius - sqrt(dist_squared); -} - -vec4 shapeCorner(vec4 pixel, vec2 p, vec2 center, float clip_radius) { - float alpha = circleBounds(p, center, clip_radius); - return vec4(pixel.rgb * alpha, min(alpha, pixel.a)); -} - -vec4 getTexture(vec2 uv) { - if (uv.x < 2. / width) - uv.x = 2. / width; - - if (uv.y < 2. / height) - uv.y = 2. / height; - - if (uv.x > 1. - 3. / width) - uv.x = 1. - 3. / width; - - if (uv.y > 1. - 3. / height) - uv.y = 1. - 3. / height; - - return texture2D(tex, uv); -} - -void main(void) { - vec2 uv = cogl_tex_coord_in[0].xy; - - vec2 pos = uv * vec2(width, height); - - vec2 direction = vec2(dir, (1.0 - dir)); - - float pixel_step; - if (dir == 0) - pixel_step = 1.0 / height; - else - pixel_step = 1.0 / width; - - vec3 gauss_coefficient; - gauss_coefficient.x = 1.0 / (sqrt(2.0 * 3.14159265) * sigma); - gauss_coefficient.y = exp(-0.5 / (sigma * sigma)); - gauss_coefficient.z = gauss_coefficient.y * gauss_coefficient.y; - - float gauss_coefficient_total = gauss_coefficient.x; - - vec4 ret = getTexture(uv) * gauss_coefficient.x; - gauss_coefficient.xy *= gauss_coefficient.yz; - - int n_steps = int(ceil(1.5 * sigma)) * 2; - - for (int i = 1; i <= n_steps; i += 2) { - float coefficient_subtotal = gauss_coefficient.x; - gauss_coefficient.xy *= gauss_coefficient.yz; - coefficient_subtotal += gauss_coefficient.x; - - float gauss_ratio = gauss_coefficient.x / coefficient_subtotal; - - float foffset = float(i) + gauss_ratio; - vec2 offset = direction * foffset * pixel_step; - - ret += getTexture(uv + offset) * coefficient_subtotal; - ret += getTexture(uv - offset) * coefficient_subtotal; - - gauss_coefficient_total += 2.0 * coefficient_subtotal; - gauss_coefficient.xy *= gauss_coefficient.yz; - } - vec4 outColor = ret / gauss_coefficient_total; - - // apply brightness and rounding on the second pass (dir==0 comes last) - if (dir == 0) { - // left side - if (pos.x < corner_radius) { - // top left corner - if (pos.y < corner_radius) { - outColor = shapeCorner(outColor, pos, vec2(corner_radius + 2., corner_radius + 2.), corner_radius); - // bottom left corner - } else if (pos.y > height - corner_radius) { - outColor = shapeCorner(outColor, pos, vec2(corner_radius + 2., height - corner_radius - 1.), corner_radius); - } - // right side - } else if (pos.x > width - corner_radius) { - // top right corner - if (pos.y < corner_radius) { - outColor = shapeCorner(outColor, pos, vec2(width - corner_radius - 1., corner_radius + 2.), corner_radius); - // bottom right corner - } else if (pos.y > height - corner_radius) { - outColor = shapeCorner(outColor, pos, vec2(width - corner_radius - 1., height - corner_radius - 1.), corner_radius); - } - } - - outColor.rgb *= brightness; - } - - cogl_color_out = outColor; -} \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/blur_effect.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/blur_effect.js deleted file mode 100644 index 71d28d0..0000000 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/blur_effect.js +++ /dev/null @@ -1,236 +0,0 @@ -import GLib from 'gi://GLib'; -import GObject from 'gi://GObject'; -import Clutter from 'gi://Clutter'; -import Shell from 'gi://Shell'; - -const SHADER_PATH = GLib.filename_from_uri(GLib.uri_resolve_relative(import.meta.url, 'blur_effect.glsl', GLib.UriFlags.NONE))[0]; - - -const get_shader_source = _ => { - try { - return Shell.get_file_contents_utf8_sync(SHADER_PATH); - } catch (e) { - console.warn(`[Blur my Shell] error loading shader from ${SHADER_PATH}: ${e}`); - return null; - } -}; - -export const BlurEffect = new GObject.registerClass({ - GTypeName: "BlurEffect", - Properties: { - 'radius': GObject.ParamSpec.double( - `radius`, - `Radius`, - `Blur radius`, - GObject.ParamFlags.READWRITE, - 0.0, 2000.0, - 200.0, - ), - 'brightness': GObject.ParamSpec.double( - `brightness`, - `Brightness`, - `Blur brightness`, - GObject.ParamFlags.READWRITE, - 0.0, 1.0, - 0.6, - ), - 'width': GObject.ParamSpec.double( - `width`, - `Width`, - `Width`, - GObject.ParamFlags.READWRITE, - 0.0, Number.MAX_SAFE_INTEGER, - 0.0, - ), - 'height': GObject.ParamSpec.double( - `height`, - `Height`, - `Height`, - GObject.ParamFlags.READWRITE, - 0.0, Number.MAX_SAFE_INTEGER, - 0.0, - ), - 'corner_radius': GObject.ParamSpec.double( - `corner_radius`, - `Corner Radius`, - `Corner Radius`, - GObject.ParamFlags.READWRITE, - 0, Number.MAX_SAFE_INTEGER, - 0, - ), - 'direction': GObject.ParamSpec.int( - `direction`, - `Direction`, - `Direction`, - GObject.ParamFlags.READWRITE, - 0, 1, - 0, - ), - 'chained_effect': GObject.ParamSpec.object( - `chained_effect`, - `Chained Effect`, - `Chained Effect`, - GObject.ParamFlags.READABLE, - GObject.Object, - ), - } -}, class BlurEffect extends Clutter.ShaderEffect { - constructor(params, settings) { - super(params); - - this._sigma = null; - this._brightness = null; - this._width = null; - this._height = null; - this._corner_radius = null; - - this._static = true; - this._settings = settings; - - this._direction = 0; - - this._chained_effect = null; - - if (params.sigma) - this.sigma = params.sigma; - if (params.brightness) - this.brightness = params.brightness; - if (params.width) - this.width = params.width; - if (params.height) - this.height = params.height; - if (params.corner_radius) - this.corner_radius = params.corner_radius; - if (params.direction) - this.direction = params.direction; - - // set shader source - this._source = get_shader_source(); - if (this._source) - this.set_shader_source(this._source); - } - - get radius() { - return this._radius; - } - - set radius(value) { - if (this._radius !== value) { - this._radius = value; - - // like Clutter, we use the assumption radius = 2*sigma - this.set_uniform_value('sigma', parseFloat(this._radius / 2 - 1e-6)); - - if (this._chained_effect) { - this._chained_effect.radius = value; - } - } - } - - get brightness() { - return this._brightness; - } - - set brightness(value) { - if (this._brightness !== value) { - this._brightness = value; - - this.set_uniform_value('brightness', parseFloat(this._brightness - 1e-6)); - - if (this._chained_effect) { - this._chained_effect.brightness = value; - } - } - } - - get width() { - return this._width; - } - - set width(value) { - if (this._width !== value) { - this._width = value; - - this.set_uniform_value('width', parseFloat(this._width + 3.0 - 1e-6)); - - if (this._chained_effect) { - this._chained_effect.width = value; - } - } - } - - get height() { - return this._height; - } - - set height(value) { - if (this._height !== value) { - this._height = value; - - this.set_uniform_value('height', parseFloat(this._height + 3.0 - 1e-6)); - - if (this._chained_effect) { - this._chained_effect.height = value; - } - } - } - - get corner_radius() { - return this._corner_radius; - } - - set corner_radius(value) { - if (this._corner_radius !== value) { - this._corner_radius = value; - - this.set_uniform_value('corner_radius', parseFloat(this._corner_radius - 1e-6)); - - if (this._chained_effect) { - this._chained_effect.corner_radius = value; - } - } - } - - get direction() { - return this._direction; - } - - set direction(value) { - if (this._direction !== value) { - this._direction = value; - } - } - - get chained_effect() { - return this._chained_effect; - } - - vfunc_set_actor(actor) { - super.vfunc_set_actor(actor); - - if (this._direction == 0) { - this._chained_effect = new BlurEffect({ - radius: this.radius, - brightness: this.brightness, - width: this.width, - height: this.height, - corner_radius: this.corner_radius, - direction: 1 - }); - if (actor !== null) - actor.add_effect(this._chained_effect); - } - } - - vfunc_paint_target(paint_node = null, paint_context = null) { - this.set_uniform_value("tex", 0); - this.set_uniform_value("dir", this._direction); - - if (paint_node && paint_context) - super.vfunc_paint_target(paint_node, paint_context); - else if (paint_node) - super.vfunc_paint_target(paint_node); - else - super.vfunc_paint_target(); - } -}); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/color_effect.glsl b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/color.glsl similarity index 100% rename from gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/color_effect.glsl rename to gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/color.glsl diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/color.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/color.js new file mode 100644 index 0000000..7de753d --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/color.js @@ -0,0 +1,140 @@ +import GObject from 'gi://GObject'; + +import * as utils from '../conveniences/utils.js'; +const Shell = await utils.import_in_shell_only('gi://Shell'); +const Clutter = await utils.import_in_shell_only('gi://Clutter'); + +const SHADER_FILENAME = 'color.glsl'; +const DEFAULT_PARAMS = { + color: [0.0, 0.0, 0.0, 0.0] +}; + + +export const ColorEffect = utils.IS_IN_PREFERENCES ? + { default_params: DEFAULT_PARAMS } : + new GObject.registerClass({ + GTypeName: "ColorEffect", + Properties: { + 'red': GObject.ParamSpec.double( + `red`, + `Red`, + `Red value in shader`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 0.0, + ), + 'green': GObject.ParamSpec.double( + `green`, + `Green`, + `Green value in shader`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 0.0, + ), + 'blue': GObject.ParamSpec.double( + `blue`, + `Blue`, + `Blue value in shader`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 0.0, + ), + 'blend': GObject.ParamSpec.double( + `blend`, + `Blend`, + `Amount of blending between the colors`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 0.0, + ), + } + }, class ColorEffect extends Clutter.ShaderEffect { + constructor(params) { + // initialize without color as a parameter + const { color, ...parent_params } = params; + super(parent_params); + + this._red = null; + this._green = null; + this._blue = null; + this._blend = null; + + // set shader source + this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); + if (this._source) + this.set_shader_source(this._source); + + // set shader color + this.color = 'color' in params ? color : this.constructor.default_params.color; + } + + static get default_params() { + return DEFAULT_PARAMS; + } + + get red() { + return this._red; + } + + set red(value) { + if (this._red !== value) { + this._red = value; + + this.set_uniform_value('red', parseFloat(this._red - 1e-6)); + } + } + + get green() { + return this._green; + } + + set green(value) { + if (this._green !== value) { + this._green = value; + + this.set_uniform_value('green', parseFloat(this._green - 1e-6)); + } + } + + get blue() { + return this._blue; + } + + set blue(value) { + if (this._blue !== value) { + this._blue = value; + + this.set_uniform_value('blue', parseFloat(this._blue - 1e-6)); + } + } + + get blend() { + return this._blend; + } + + set blend(value) { + if (this._blend !== value) { + this._blend = value; + + this.set_uniform_value('blend', parseFloat(this._blend - 1e-6)); + this.set_enabled(this.blend > 0); + } + } + + set color(rgba) { + let [r, g, b, a] = rgba; + this.red = r; + this.green = g; + this.blue = b; + this.blend = a; + } + + get color() { + return [this.red, this.green, this.blue, this.blend]; + } + + /// False set function, only cares about the color. Too hard to change. + set(params) { + this.color = params.color; + } + }); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/color_effect.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/color_effect.js deleted file mode 100644 index 2ae9191..0000000 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/color_effect.js +++ /dev/null @@ -1,181 +0,0 @@ -import GLib from 'gi://GLib'; -import GObject from 'gi://GObject'; -import Clutter from 'gi://Clutter'; -import Shell from 'gi://Shell'; - - -const SHADER_PATH = GLib.filename_from_uri(GLib.uri_resolve_relative(import.meta.url, 'color_effect.glsl', GLib.UriFlags.NONE))[0]; - - -const get_shader_source = _ => { - try { - return Shell.get_file_contents_utf8_sync(SHADER_PATH); - } catch (e) { - console.warn(`[Blur my Shell] error loading shader from ${SHADER_PATH}: ${e}`); - return null; - } -}; - -/// New Clutter Shader Effect that simply mixes a color in, the class applies -/// the GLSL shader programmed into vfunc_get_static_shader_source and applies -/// it to an Actor. -/// -/// Clutter Shader Source Code: -/// https://github.com/GNOME/clutter/blob/master/clutter/clutter-shader-effect.c -/// -/// GJS Doc: -/// https://gjs-docs.gnome.org/clutter10~10_api/clutter.shadereffect -export const ColorEffect = new GObject.registerClass({ - GTypeName: "ColorEffect", - Properties: { - 'red': GObject.ParamSpec.double( - `red`, - `Red`, - `Red value in shader`, - GObject.ParamFlags.READWRITE, - 0.0, 1.0, - 0.4, - ), - 'green': GObject.ParamSpec.double( - `green`, - `Green`, - `Green value in shader`, - GObject.ParamFlags.READWRITE, - 0.0, 1.0, - 0.4, - ), - 'blue': GObject.ParamSpec.double( - `blue`, - `Blue`, - `Blue value in shader`, - GObject.ParamFlags.READWRITE, - 0.0, 1.0, - 0.4, - ), - 'blend': GObject.ParamSpec.double( - `blend`, - `Blend`, - `Amount of blending between the colors`, - GObject.ParamFlags.READWRITE, - 0.0, 1.0, - 0.4, - ), - } -}, class ColorShader extends Clutter.ShaderEffect { - constructor(params, settings) { - // initialize without color as a parameter - let _color = params.color; - delete params.color; - - super(params); - - this._red = null; - this._green = null; - this._blue = null; - this._blend = null; - - this._static = true; - this._settings = settings; - - // set shader source - this._source = get_shader_source(); - if (this._source) - this.set_shader_source(this._source); - - // set shader color - if (_color) - this.color = _color; - - this.update_enabled(); - } - - get red() { - return this._red; - } - - set red(value) { - if (this._red !== value) { - this._red = value; - - this.set_uniform_value('red', parseFloat(this._red - 1e-6)); - } - } - - get green() { - return this._green; - } - - set green(value) { - if (this._green !== value) { - this._green = value; - - this.set_uniform_value('green', parseFloat(this._green - 1e-6)); - } - } - - get blue() { - return this._blue; - } - - set blue(value) { - if (this._blue !== value) { - this._blue = value; - - this.set_uniform_value('blue', parseFloat(this._blue - 1e-6)); - } - } - - get blend() { - return this._blend; - } - - set blend(value) { - if (this._blend !== value) { - this._blend = value; - - this.set_uniform_value('blend', parseFloat(this._blend - 1e-6)); - } - this.update_enabled(); - } - - set color(rgba) { - let [r, g, b, a] = rgba; - this.red = r; - this.green = g; - this.blue = b; - this.blend = a; - } - - get color() { - return [this.red, this.green, this.blue, this.blend]; - } - - /// False set function, only cares about the color. Too hard to change. - set(params) { - this.color = params.color; - } - - update_enabled() { - // don't anything if this._settings is undefined (when calling super) - if (this._settings === undefined) - return; - - this.set_enabled( - this.blend > 0 && - this._settings.COLOR_AND_NOISE && - this._static - ); - } - - - vfunc_paint_target(paint_node = null, paint_context = null) { - this.set_uniform_value("tex", 0); - - if (paint_node && paint_context) - super.vfunc_paint_target(paint_node, paint_context); - else if (paint_node) - super.vfunc_paint_target(paint_node); - else - super.vfunc_paint_target(); - } -}); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/corner.glsl b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/corner.glsl new file mode 100644 index 0000000..760798a --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/corner.glsl @@ -0,0 +1,93 @@ +// Heavily based on https://github.com/yilozt/rounded-window-corners +// which is itself based on upstream Mutter code + +uniform sampler2D tex; +uniform float radius; +uniform float width; +uniform float height; +uniform bool corners_top; +uniform bool corners_bottom; + +uniform float clip_x0; +uniform float clip_y0; +uniform float clip_width; +uniform float clip_height; + +float circle_bounds(vec2 p, vec2 center, float clip_radius) { + vec2 delta = p - center; + float dist_squared = dot(delta, delta); + + float outer_radius = clip_radius + 0.5; + if (dist_squared >= (outer_radius * outer_radius)) + return 0.0; + + float inner_radius = clip_radius - 0.5; + if (dist_squared <= (inner_radius * inner_radius)) + return 1.0; + + return outer_radius - sqrt(dist_squared); +} + +vec4 getTexture(vec2 uv) { + if (uv.x < 2. / width) + uv.x = 2. / width; + + if (uv.y < 2. / height) + uv.y = 2. / height; + + if (uv.x > 1. - 3. / width) + uv.x = 1. - 3. / width; + + if (uv.y > 1. - 3. / height) + uv.y = 1. - 3. / height; + + return texture2D(tex, uv); +} + +float rounded_rect_coverage(vec2 p, vec4 bounds, float clip_radius) { + // Outside the bounds + if (p.x < bounds.x || p.x > bounds.z || p.y < bounds.y || p.y > bounds.w) { + return 0.; + } + + vec2 center; + + float center_left = bounds.x + clip_radius; + float center_right = bounds.z - clip_radius; + + if (p.x < center_left) + center.x = center_left + 2.; + else if (p.x > center_right) + center.x = center_right - 1.; + else + return 1.0; + + float center_top = bounds.y + clip_radius; + float center_bottom = bounds.w - clip_radius; + + if (corners_top && p.y < center_top) + center.y = center_top + 2.; + else if (corners_bottom && p.y > center_bottom) + center.y = center_bottom - 1.; + else + return 1.0; + + return circle_bounds(p, center, clip_radius); +} + +void main(void) { + vec2 uv = cogl_tex_coord_in[0].xy; + vec2 pos = uv * vec2(width, height); + vec4 c = getTexture(uv); + + vec4 bounds; + if (clip_width < 0. || clip_height < 0.) { + bounds = vec4(clip_x0, clip_y0, clip_x0 + width, clip_y0 + height); + } else { + bounds = vec4(clip_x0, clip_y0, clip_x0 + clip_width, clip_y0 + clip_height); + } + + float alpha = rounded_rect_coverage(pos, bounds, radius); + + cogl_color_out = vec4(c.rgb * alpha, min(alpha, c.a)); +} \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/corner.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/corner.js new file mode 100644 index 0000000..109be12 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/corner.js @@ -0,0 +1,211 @@ +import GObject from 'gi://GObject'; + +import * as utils from '../conveniences/utils.js'; +const St = await utils.import_in_shell_only('gi://St'); +const Shell = await utils.import_in_shell_only('gi://Shell'); +const Clutter = await utils.import_in_shell_only('gi://Clutter'); + +const SHADER_FILENAME = 'corner.glsl'; +const DEFAULT_PARAMS = { + radius: 12, width: 0, height: 0, + corners_top: true, corners_bottom: true, + clip: [0, 0, -1, -1] +}; + + +export const CornerEffect = utils.IS_IN_PREFERENCES ? + { default_params: DEFAULT_PARAMS } : + new GObject.registerClass({ + GTypeName: "CornerEffect", + Properties: { + 'radius': GObject.ParamSpec.double( + `radius`, + `Corner Radius`, + `Corner Radius`, + GObject.ParamFlags.READWRITE, + 0, Number.MAX_SAFE_INTEGER, + 12, + ), + 'width': GObject.ParamSpec.double( + `width`, + `Width`, + `Width`, + GObject.ParamFlags.READWRITE, + 0.0, Number.MAX_SAFE_INTEGER, + 0.0, + ), + 'height': GObject.ParamSpec.double( + `height`, + `Height`, + `Height`, + GObject.ParamFlags.READWRITE, + 0.0, Number.MAX_SAFE_INTEGER, + 0.0, + ), + 'corners_top': GObject.ParamSpec.boolean( + `corners_top`, + `Round top corners`, + `Round top corners`, + GObject.ParamFlags.READWRITE, + true, + ), + 'corners_bottom': GObject.ParamSpec.boolean( + `corners_bottom`, + `Round bottom corners`, + `Round bottom corners`, + GObject.ParamFlags.READWRITE, + true, + ), + // FIXME this works but it logs an error, because I'm not a double... + // I don't want to fiddle with GVariants again + 'clip': GObject.ParamSpec.double( + `clip`, + `Clip`, + `Clip`, + GObject.ParamFlags.READWRITE, + 0.0, Number.MAX_SAFE_INTEGER, + 0.0, + ), + } + }, class CornerEffect extends Clutter.ShaderEffect { + constructor(params) { + super(params); + + this._clip_x0 = null; + this._clip_y0 = null; + this._clip_width = null; + this._clip_height = null; + + utils.setup_params(this, params); + + // set shader source + this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); + if (this._source) + this.set_shader_source(this._source); + + const theme_context = St.ThemeContext.get_for_stage(global.stage); + theme_context.connectObject('notify::scale-factor', _ => this.update_radius(), this); + } + + static get default_params() { + return DEFAULT_PARAMS; + } + + get radius() { + return this._radius; + } + + set radius(value) { + if (this._radius !== value) { + this._radius = value; + + this.update_radius(); + } + } + + update_radius() { + const theme_context = St.ThemeContext.get_for_stage(global.stage); + let radius = Math.min( + this.radius * theme_context.scale_factor, + this.width / 2, this.height / 2 + ); + if (this._clip_width >= 0 || this._clip_height >= 0) + radius = Math.min(radius, this._clip_width / 2, this._clip_height / 2); + + this.set_uniform_value('radius', parseFloat(radius - 1e-6)); + } + + get width() { + return this._width; + } + + set width(value) { + if (this._width !== value) { + this._width = value; + + this.set_uniform_value('width', parseFloat(this._width + 3.0 - 1e-6)); + this.update_radius(); + } + } + + get height() { + return this._height; + } + + set height(value) { + if (this._height !== value) { + this._height = value; + + this.set_uniform_value('height', parseFloat(this._height + 3.0 - 1e-6)); + this.update_radius(); + } + } + + get corners_top() { + return this._corners_top; + } + + set corners_top(value) { + if (this._corners_top !== value) { + this._corners_top = value; + + this.set_uniform_value('corners_top', this._corners_top ? 1 : 0); + } + } + + get corners_bottom() { + return this._corners_bottom; + } + + set corners_bottom(value) { + if (this._corners_bottom !== value) { + this._corners_bottom = value; + + this.set_uniform_value('corners_bottom', this._corners_bottom ? 1 : 0); + } + } + + get clip() { + return [this._clip_x0, this._clip_y0, this._clip_width, this._clip_height]; + } + + set clip(value) { + [this._clip_x0, this._clip_y0, this._clip_width, this._clip_height] = value; + this.set_uniform_value('clip_x0', parseFloat(this._clip_x0 - 1e-6)); + this.set_uniform_value('clip_y0', parseFloat(this._clip_y0 - 1e-6)); + this.set_uniform_value('clip_width', parseFloat(this._clip_width + 3 - 1e-6)); + this.set_uniform_value('clip_height', parseFloat(this._clip_height + 3 - 1e-6)); + this.update_radius(); + } + + vfunc_set_actor(actor) { + if (this._actor_connection_size_id) { + let old_actor = this.get_actor(); + old_actor?.disconnect(this._actor_connection_size_id); + } + if (this._actor_connection_clip_rect_id) { + let old_actor = this.get_actor(); + old_actor?.disconnect(this._actor_connection_clip_rect_id); + } + + if (actor) { + this.width = actor.width; + this.height = actor.height; + this._actor_connection_size_id = actor.connect('notify::size', _ => { + this.width = actor.width; + this.height = actor.height; + }); + + this.clip = actor.has_clip ? actor.get_clip() : [0, 0, -10, -10]; + this._actor_connection_clip_rect_id = actor.connect('notify::clip-rect', _ => { + this.clip = actor.has_clip ? actor.get_clip() : [0, 0, -10, -10]; + }); + } + else { + this._actor_connection_size_id = null; + this._actor_connection_clip_rect_id = null; + } + + super.vfunc_set_actor(actor); + } + }); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/derivative.glsl b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/derivative.glsl new file mode 100644 index 0000000..64c1682 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/derivative.glsl @@ -0,0 +1,71 @@ +uniform sampler2D tex; +uniform int operation; +uniform float width; +uniform float height; + +#define CORRECTION 2.25 +#define SIZE_ADDITION 3 + +vec4 get_texture_at_position(vec2 position) { + vec2 raw_position = position + vec2(CORRECTION, CORRECTION); + vec2 raw_uv = raw_position / vec2(width + SIZE_ADDITION, height + SIZE_ADDITION); + + return texture2D(tex, raw_uv); +} + +vec4 try_get_texture_at_position(vec2 position, inout int count) { + if (any(greaterThanEqual(position, vec2(width, height))) || + any(lessThan(position, vec2(0, 0)))) { + return vec4(0); + } else { + count++; + return get_texture_at_position(position); + } +} + +ivec2 get_corrected_position() { + vec2 raw_uv = cogl_tex_coord0_in.st; + vec2 raw_position = raw_uv * vec2(width + SIZE_ADDITION, height + SIZE_ADDITION); + return ivec2(raw_position - vec2(CORRECTION, CORRECTION)); +} + +void main() { + ivec2 corrected_position = get_corrected_position(); + + // 1-step derivative + if (operation == 0) { + vec4 color = vec4(0); + int c = 0; + color += try_get_texture_at_position(corrected_position + vec2(0, 1), c); + color -= try_get_texture_at_position(corrected_position + vec2(0, 0), c); + color += try_get_texture_at_position(corrected_position + vec2(1, 0), c); + color -= try_get_texture_at_position(corrected_position + vec2(0, 0), c); + if (c < 4) { + color = vec4(0); + } + cogl_color_out = vec4(color.xyz, 1); + } else + // 2-step derivative + if (operation == 1) { + vec4 color = vec4(0); + int c = 0; + color += try_get_texture_at_position(corrected_position + vec2(0, 1), c); + color -= try_get_texture_at_position(corrected_position + vec2(0, -1), c); + color += try_get_texture_at_position(corrected_position + vec2(1, 0), c); + color -= try_get_texture_at_position(corrected_position + vec2(-1, 0), c); + if (c < 4) { + color = vec4(0); + } + cogl_color_out = vec4(color.xyz / 2, 1); + } else + // laplacian + if (operation == 2) { + vec4 color = vec4(0); + color = -4 * get_texture_at_position(corrected_position); + color += get_texture_at_position(corrected_position + vec2(0, 1)); + color += get_texture_at_position(corrected_position + vec2(0, -1)); + color += get_texture_at_position(corrected_position + vec2(1, 0)); + color += get_texture_at_position(corrected_position + vec2(-1, 0)); + cogl_color_out = vec4(color.xyz, 1); + } +} \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/derivative.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/derivative.js new file mode 100644 index 0000000..04d6100 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/derivative.js @@ -0,0 +1,120 @@ +import GObject from 'gi://GObject'; + +import * as utils from '../conveniences/utils.js'; +const Shell = await utils.import_in_shell_only('gi://Shell'); +const Clutter = await utils.import_in_shell_only('gi://Clutter'); + +const SHADER_FILENAME = 'derivative.glsl'; +const DEFAULT_PARAMS = { + operation: 0, width: 0, height: 0 +}; + + +export const DerivativeEffect = utils.IS_IN_PREFERENCES ? + { default_params: DEFAULT_PARAMS } : + new GObject.registerClass({ + GTypeName: "DerivativeEffect", + Properties: { + 'operation': GObject.ParamSpec.int( + `operation`, + `Operation`, + `Operation`, + GObject.ParamFlags.READWRITE, + 0, 2, + 0, + ), + 'width': GObject.ParamSpec.double( + `width`, + `Width`, + `Width`, + GObject.ParamFlags.READWRITE, + 0.0, Number.MAX_SAFE_INTEGER, + 0.0, + ), + 'height': GObject.ParamSpec.double( + `height`, + `Height`, + `Height`, + GObject.ParamFlags.READWRITE, + 0.0, Number.MAX_SAFE_INTEGER, + 0.0, + ) + } + }, class DerivativeEffect extends Clutter.ShaderEffect { + constructor(params) { + super(params); + + utils.setup_params(this, params); + + // set shader source + this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); + if (this._source) + this.set_shader_source(this._source); + } + + static get default_params() { + return DEFAULT_PARAMS; + } + + get operation() { + return this._operation; + } + + set operation(value) { + if (this._operation !== value) { + this._operation = value; + + this.set_uniform_value('operation', this._operation); + } + } + + get width() { + return this._width; + } + + set width(value) { + if (this._width !== value) { + this._width = value; + + this.set_uniform_value('width', parseFloat(this._width - 1e-6)); + } + } + + get height() { + return this._height; + } + + set height(value) { + if (this._height !== value) { + this._height = value; + + this.set_uniform_value('height', parseFloat(this._height - 1e-6)); + } + } + + vfunc_set_actor(actor) { + if (this._actor_connection_size_id) { + let old_actor = this.get_actor(); + old_actor?.disconnect(this._actor_connection_size_id); + } + if (actor) { + this.width = actor.width; + this.height = actor.height; + this._actor_connection_size_id = actor.connect('notify::size', _ => { + this.width = actor.width; + this.height = actor.height; + }); + } + else + this._actor_connection_size_id = null; + + super.vfunc_set_actor(actor); + } + + vfunc_paint_target(paint_node, paint_context) { + // force setting nearest-neighbour texture filtering + this.get_pipeline().set_layer_filters(0, 9728, 9728); + + super.vfunc_paint_target(paint_node, paint_context); + } + }); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/downscale.glsl b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/downscale.glsl new file mode 100644 index 0000000..9871268 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/downscale.glsl @@ -0,0 +1,76 @@ +uniform sampler2D tex; +uniform int divider; +uniform float width; +uniform float height; +uniform int downsampling_mode; + +#define CORRECTION 2.25 +#define SIZE_ADDITION 3 + +vec4 get_texture_at_position(vec2 position) { + vec2 raw_position = position + vec2(CORRECTION, CORRECTION); + vec2 raw_uv = raw_position / vec2(width + SIZE_ADDITION, height + SIZE_ADDITION); + + return texture2D(tex, raw_uv); +} + +vec2 get_corrected_position() { + vec2 raw_uv = cogl_tex_coord0_in.st; + vec2 raw_position = raw_uv * vec2(width + SIZE_ADDITION, height + SIZE_ADDITION); + return raw_position - vec2(CORRECTION, CORRECTION); +} + +void main() { + ivec2 corrected_position = ivec2(get_corrected_position()); + vec2 multiplied_position = corrected_position * divider; + + if (any(greaterThan(multiplied_position, vec2(width, height)))) { + discard; + } + + // mode 0: boxcar downsampling + if (downsampling_mode == 0) { + + vec4 color = vec4(0.); + int count = 0; + for (int i = 0; i < divider; i++) { + for (int j = 0; j < divider; j++) { + vec2 lookup_position = multiplied_position + vec2(i, j); + if (all(greaterThanEqual(lookup_position, vec2(0, 0))) && + all(lessThan(lookup_position, vec2(width, height)))) { + color += get_texture_at_position(lookup_position); + count += 1; + } + } + } + cogl_color_out = color / count; + + } else + // mode 1: triangular downsampling + if (downsampling_mode == 1) { + + vec4 color = vec4(0.); + int count = 0; + int force = 1; + for (int i = 0; i < divider; i++) { + for (int j = 0; j < divider; j++) { + vec2 lookup_position = multiplied_position + vec2(i, j); + if (all(greaterThanEqual(lookup_position, vec2(0, 0))) && + all(lessThan(lookup_position, vec2(width, height)))) { + force = 1 + divider - int(abs(divider - i - j)); + color += get_texture_at_position(lookup_position) * force; + count += force; + } + } + } + cogl_color_out = color / count; + + } else + // mode 2: Dirac downsampling + if (downsampling_mode == 2) { + + vec2 lookup_position = min(multiplied_position + vec2(divider, divider) / 2, vec2(width - 1, height - 1)); + cogl_color_out = get_texture_at_position(lookup_position); + + } +} \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/downscale.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/downscale.js new file mode 100644 index 0000000..8103486 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/downscale.js @@ -0,0 +1,140 @@ +import GObject from 'gi://GObject'; + +import * as utils from '../conveniences/utils.js'; +const Shell = await utils.import_in_shell_only('gi://Shell'); +const Clutter = await utils.import_in_shell_only('gi://Clutter'); + +const SHADER_FILENAME = 'downscale.glsl'; +const DEFAULT_PARAMS = { + divider: 8, downsampling_mode: 0, width: 0, height: 0 +}; + + +export const DownscaleEffect = utils.IS_IN_PREFERENCES ? + { default_params: DEFAULT_PARAMS } : + new GObject.registerClass({ + GTypeName: "DownscaleEffect", + Properties: { + 'divider': GObject.ParamSpec.int( + `divider`, + `Divider`, + `Divider`, + GObject.ParamFlags.READWRITE, + 0, 64, + 8, + ), + 'downsampling_mode': GObject.ParamSpec.int( + `downsampling_mode`, + `Downsampling mode`, + `Downsampling mode`, + GObject.ParamFlags.READWRITE, + 0, 2, + 0, + ), + 'width': GObject.ParamSpec.double( + `width`, + `Width`, + `Width`, + GObject.ParamFlags.READWRITE, + 0.0, Number.MAX_SAFE_INTEGER, + 0.0, + ), + 'height': GObject.ParamSpec.double( + `height`, + `Height`, + `Height`, + GObject.ParamFlags.READWRITE, + 0.0, Number.MAX_SAFE_INTEGER, + 0.0, + ) + } + }, class DownscaleEffect extends Clutter.ShaderEffect { + constructor(params) { + super(params); + + utils.setup_params(this, params); + + // set shader source + this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); + if (this._source) + this.set_shader_source(this._source); + } + + static get default_params() { + return DEFAULT_PARAMS; + } + + get divider() { + return this._divider; + } + + set divider(value) { + if (this._divider !== value) { + this._divider = value; + + this.set_uniform_value('divider', this._divider); + } + } + + get downsampling_mode() { + return this._downsampling_mode; + } + + set downsampling_mode(value) { + if (this._downsampling_mode !== value) { + this._downsampling_mode = value; + + this.set_uniform_value('downsampling_mode', this._downsampling_mode); + } + } + + get width() { + return this._width; + } + + set width(value) { + if (this._width !== value) { + this._width = value; + + this.set_uniform_value('width', parseFloat(this._width - 1e-6)); + } + } + + get height() { + return this._height; + } + + set height(value) { + if (this._height !== value) { + this._height = value; + + this.set_uniform_value('height', parseFloat(this._height - 1e-6)); + } + } + + vfunc_set_actor(actor) { + if (this._actor_connection_size_id) { + let old_actor = this.get_actor(); + old_actor?.disconnect(this._actor_connection_size_id); + } + if (actor) { + this.width = actor.width; + this.height = actor.height; + this._actor_connection_size_id = actor.connect('notify::size', _ => { + this.width = actor.width; + this.height = actor.height; + }); + } + else + this._actor_connection_size_id = null; + + super.vfunc_set_actor(actor); + } + + vfunc_paint_target(paint_node, paint_context) { + // force setting nearest-neighbour texture filtering + this.get_pipeline().set_layer_filters(0, 9728, 9728); + + super.vfunc_paint_target(paint_node, paint_context); + } + }); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/effects.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/effects.js new file mode 100644 index 0000000..8678d9a --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/effects.js @@ -0,0 +1,332 @@ +import { NativeDynamicBlurEffect } from '../effects/native_dynamic_gaussian_blur.js'; +import { NativeStaticBlurEffect } from '../effects/native_static_gaussian_blur.js'; +import { GaussianBlurEffect } from '../effects/gaussian_blur.js'; +import { MonteCarloBlurEffect } from '../effects/monte_carlo_blur.js'; +import { ColorEffect } from '../effects/color.js'; +import { NoiseEffect } from '../effects/noise.js'; +import { CornerEffect } from '../effects/corner.js'; +import { DownscaleEffect } from './downscale.js'; +import { UpscaleEffect } from './upscale.js'; +import { PixelizeEffect } from './pixelize.js'; +import { DerivativeEffect } from './derivative.js'; +import { RgbToHslEffect } from './rgb_to_hsl.js'; +import { HslToRgbEffect } from './hsl_to_rgb.js'; + +// We do in this way because I've not found another way to store our preferences in a dictionnary +// while calling `gettext` on it while in preferences. Not so pretty, but works. +export function get_effects_groups(_ = _ => "") { + return { + blur_effects: { + name: _("Blur effects"), + contains: [ + "native_static_gaussian_blur", + "gaussian_blur", + "monte_carlo_blur" + ] + }, + texture_effects: { + name: _("Texture effects"), + contains: [ + "downscale", + "upscale", + "pixelize", + "derivative", + "noise", + "color", + "rgb_to_hsl", + "hsl_to_rgb" + ] + }, + shape_effects: { + name: _("Shape effects"), + contains: [ + "corner" + ] + } + }; +}; + +export function get_supported_effects(_ = () => "") { + return { + native_dynamic_gaussian_blur: { + class: NativeDynamicBlurEffect + }, + + native_static_gaussian_blur: { + class: NativeStaticBlurEffect, + name: _("Native gaussian blur"), + description: _("An optimized blur effect that smoothly blends pixels within a given radius."), + is_advanced: false, + editable_params: { + unscaled_radius: { + name: _("Radius"), + description: _("The intensity of the blur effect."), + type: "float", + min: 0., + max: 100., + increment: 1.0, + big_increment: 10., + digits: 0 + }, + brightness: { + name: _("Brightness"), + description: _("The brightness of the blur effect, a high value might make the text harder to read."), + type: "float", + min: 0., + max: 1., + increment: 0.01, + big_increment: 0.1, + digits: 2 + }, + } + }, + + gaussian_blur: { + class: GaussianBlurEffect, + name: _("Gaussian blur (advanced effect)"), + description: _("A blur effect that smoothly blends pixels within a given radius. This effect is more precise, but way less optimized."), + is_advanced: true, + editable_params: { + radius: { + name: _("Radius"), + description: _("The intensity of the blur effect. The bigger it is, the slower it will be."), + type: "float", + min: 0., + max: 100., + increment: .1, + big_increment: 10., + digits: 1 + }, + brightness: { + name: _("Brightness"), + description: _("The brightness of the blur effect, a high value might make the text harder to read."), + type: "float", + min: 0., + max: 1., + increment: 0.01, + big_increment: 0.1, + digits: 2 + }, + } + }, + + monte_carlo_blur: { + class: MonteCarloBlurEffect, + name: _("Monte Carlo blur"), + description: _("A blur effect that mimics a random walk, by picking pixels further and further away from its origin and mixing them all together."), + is_advanced: false, + editable_params: { + radius: { + name: _("Radius"), + description: _("The maximum travel distance for each step in the random walk. A higher value will make the blur more randomized."), + type: "float", + min: 0., + max: 10., + increment: 0.01, + big_increment: 0.1, + digits: 2 + }, + iterations: { + name: _("Iterations"), + description: _("The number of iterations. The more there are, the smoother the blur is."), + type: "integer", + min: 0, + max: 50, + increment: 1 + }, + brightness: { + name: _("Brightness"), + description: _("The brightness of the blur effect, a high value might make the text harder to read."), + type: "float", + min: 0., + max: 1., + increment: 0.01, + big_increment: 0.1, + digits: 2 + }, + use_base_pixel: { + name: _("Use base pixel"), + description: _("Whether or not the original pixel is counted for the blur. If it is, the image will be more legible."), + type: "boolean" + } + } + }, + + color: { + class: ColorEffect, + name: _("Color"), + description: _("An effect that blends a color into the pipeline."), + is_advanced: false, + // TODO make this RGB + blend + editable_params: { + color: { + name: _("Color"), + description: _("The color to blend in. The blending amount is controled by the opacity of the color."), + type: "rgba" + } + } + }, + + pixelize: { + class: PixelizeEffect, + name: _("Pixelize"), + description: _("An effect that pixelizes the image."), + is_advanced: false, + editable_params: { + factor: { + name: _("Factor"), + description: _("How much to scale down the image."), + type: "integer", + min: 1, + max: 50, + increment: 1 + }, + downsampling_mode: { + name: _("Downsampling mode"), + description: _("The downsampling method that is used."), + type: "dropdown", + options: [ + _("Boxcar"), + _("Triangular"), + _("Dirac") + ] + } + } + }, + + downscale: { + class: DownscaleEffect, + name: _("Downscale (advanced effect)"), + description: _("An effect that downscales the image and put it on the top-left corner."), + is_advanced: true, + editable_params: { + divider: { + name: _("Factor"), + description: _("How much to scale down the image."), + type: "integer", + min: 1, + max: 50, + increment: 1 + }, + downsampling_mode: { + name: _("Downsampling mode"), + description: _("The downsampling method that is used."), + type: "dropdown", + options: [ + _("Boxcar"), + _("Triangular"), + _("Dirac") + ] + } + } + }, + + upscale: { + class: UpscaleEffect, + name: _("Upscale (advanced effect)"), + description: _("An effect that upscales the image from the top-left corner."), + is_advanced: true, + editable_params: { + factor: { + name: _("Factor"), + description: _("How much to scale up the image."), + type: "integer", + min: 1, + max: 50, + increment: 1 + } + } + }, + + derivative: { + class: DerivativeEffect, + name: _("Derivative"), + description: _("Apply a spatial derivative, or a laplacian."), + is_advanced: false, + editable_params: { + operation: { + name: _("Operation"), + description: _("The mathematical operation to apply."), + type: "dropdown", + options: [ + _("1-step derivative"), + _("2-step derivative"), + _("Laplacian") + ] + } + } + }, + + noise: { + class: NoiseEffect, + name: _("Noise"), + description: _("An effect that adds a random noise. Prefer the Monte Carlo blur for a more organic effect if needed."), + is_advanced: false, + editable_params: { + noise: { + name: _("Noise"), + description: _("The amount of noise to add."), + type: "float", + min: 0., + max: 1., + increment: 0.01, + big_increment: 0.1, + digits: 2 + }, + lightness: { + name: _("Lightness"), + description: _("The luminosity of the noise. A setting of '1.0' will make the effect transparent."), + type: "float", + min: 0., + max: 2., + increment: 0.01, + big_increment: 0.1, + digits: 2 + } + } + }, + + rgb_to_hsl: { + class: RgbToHslEffect, + name: _("RGB to HSL (advanced effect)"), + description: _("Converts the image from RGBA colorspace to HSLA."), + is_advanced: true, + editable_params: {} + }, + + hsl_to_rgb: { + class: HslToRgbEffect, + name: _("HSL to RGB (advanced effect)"), + description: _("Converts the image from HSLA colorspace to RGBA."), + is_advanced: true, + editable_params: {} + }, + + corner: { + class: CornerEffect, + name: _("Corner"), + description: _("An effect that draws corners. Add it last not to have the other effects perturb the corners."), + is_advanced: false, + editable_params: { + radius: { + name: _("Radius"), + description: _("The radius of the corner. GNOME apps use a radius of 12 px by default."), + type: "integer", + min: 0, + max: 50, + increment: 1, + }, + corners_top: { + name: _("Top corners"), + description: _("Whether or not to round the top corners."), + type: "boolean" + }, + corners_bottom: { + name: _("Bottom corners"), + description: _("Whether or not to round the bottom corners."), + type: "boolean" + } + } + } + }; +}; \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/gaussian_blur.glsl b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/gaussian_blur.glsl new file mode 100644 index 0000000..809cc93 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/gaussian_blur.glsl @@ -0,0 +1,70 @@ +uniform sampler2D tex; +uniform float sigma; +uniform int dir; +uniform float brightness; +uniform float width; +uniform float height; + +vec4 getTexture(vec2 uv) { + if (uv.x < 3. / width) + uv.x = 3. / width; + + if (uv.y < 3. / height) + uv.y = 3. / height; + + if (uv.x > 1. - 3. / width) + uv.x = 1. - 3. / width; + + if (uv.y > 1. - 3. / height) + uv.y = 1. - 3. / height; + + return texture2D(tex, uv); +} + +void main(void) { + vec2 uv = cogl_tex_coord_in[0].xy; + vec2 direction = vec2(dir, (1.0 - dir)); + + float pixel_step; + if (dir == 0) + pixel_step = 1.0 / height; + else + pixel_step = 1.0 / width; + + vec3 gauss_coefficient; + gauss_coefficient.x = 1.0 / (sqrt(2.0 * 3.14159265) * sigma); + gauss_coefficient.y = exp(-0.5 / (sigma * sigma)); + gauss_coefficient.z = gauss_coefficient.y * gauss_coefficient.y; + + float gauss_coefficient_total = gauss_coefficient.x; + + vec4 ret = getTexture(uv) * gauss_coefficient.x; + gauss_coefficient.xy *= gauss_coefficient.yz; + + int n_steps = int(ceil(1.5 * sigma)) * 2; + + for (int i = 1; i <= n_steps; i += 2) { + float coefficient_subtotal = gauss_coefficient.x; + gauss_coefficient.xy *= gauss_coefficient.yz; + coefficient_subtotal += gauss_coefficient.x; + + float gauss_ratio = gauss_coefficient.x / coefficient_subtotal; + + float foffset = float(i) + gauss_ratio; + vec2 offset = direction * foffset * pixel_step; + + ret += getTexture(uv + offset) * coefficient_subtotal; + ret += getTexture(uv - offset) * coefficient_subtotal; + + gauss_coefficient_total += 2.0 * coefficient_subtotal; + gauss_coefficient.xy *= gauss_coefficient.yz; + } + vec4 outColor = ret / gauss_coefficient_total; + + // apply brightness on the second pass (dir==0 comes last) + if (dir == 0) { + outColor.rgb *= brightness; + } + + cogl_color_out = outColor; +} \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/gaussian_blur.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/gaussian_blur.js new file mode 100644 index 0000000..113a6fd --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/gaussian_blur.js @@ -0,0 +1,213 @@ +import GObject from 'gi://GObject'; + +import * as utils from '../conveniences/utils.js'; +const St = await utils.import_in_shell_only('gi://St'); +const Shell = await utils.import_in_shell_only('gi://Shell'); +const Clutter = await utils.import_in_shell_only('gi://Clutter'); + +const SHADER_FILENAME = 'gaussian_blur.glsl'; +const DEFAULT_PARAMS = { + radius: 30, brightness: .6, + width: 0, height: 0, direction: 0, chained_effect: null +}; + + +export const GaussianBlurEffect = utils.IS_IN_PREFERENCES ? + { default_params: DEFAULT_PARAMS } : + new GObject.registerClass({ + GTypeName: "GaussianBlurEffect", + Properties: { + 'radius': GObject.ParamSpec.double( + `radius`, + `Radius`, + `Blur radius`, + GObject.ParamFlags.READWRITE, + 0.0, 2000.0, + 30.0, + ), + 'brightness': GObject.ParamSpec.double( + `brightness`, + `Brightness`, + `Blur brightness`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 0.6, + ), + 'width': GObject.ParamSpec.double( + `width`, + `Width`, + `Width`, + GObject.ParamFlags.READWRITE, + 0.0, Number.MAX_SAFE_INTEGER, + 0.0, + ), + 'height': GObject.ParamSpec.double( + `height`, + `Height`, + `Height`, + GObject.ParamFlags.READWRITE, + 0.0, Number.MAX_SAFE_INTEGER, + 0.0, + ), + 'direction': GObject.ParamSpec.int( + `direction`, + `Direction`, + `Direction`, + GObject.ParamFlags.READWRITE, + 0, 1, + 0, + ), + 'chained_effect': GObject.ParamSpec.object( + `chained_effect`, + `Chained Effect`, + `Chained Effect`, + GObject.ParamFlags.READWRITE, + GObject.Object, + ), + } + }, class GaussianBlurEffect extends Clutter.ShaderEffect { + constructor(params) { + super(params); + + utils.setup_params(this, params); + + // set shader source + this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); + if (this._source) + this.set_shader_source(this._source); + + const theme_context = St.ThemeContext.get_for_stage(global.stage); + theme_context.connectObject( + 'notify::scale-factor', _ => + this.set_uniform_value('sigma', + parseFloat(this.radius * theme_context.scale_factor / 2 - 1e-6) + ), + this + ); + } + + static get default_params() { + return DEFAULT_PARAMS; + } + + get radius() { + return this._radius; + } + + set radius(value) { + if (this._radius !== value) { + this._radius = value; + + const scale_factor = St.ThemeContext.get_for_stage(global.stage).scale_factor; + + // like Clutter, we use the assumption radius = 2*sigma + this.set_uniform_value('sigma', parseFloat(this._radius * scale_factor / 2 - 1e-6)); + this.set_enabled(this.radius > 0.); + + if (this.chained_effect) + this.chained_effect.radius = value; + } + } + + get brightness() { + return this._brightness; + } + + set brightness(value) { + if (this._brightness !== value) { + this._brightness = value; + + this.set_uniform_value('brightness', parseFloat(this._brightness - 1e-6)); + + if (this.chained_effect) + this.chained_effect.brightness = value; + } + } + + get width() { + return this._width; + } + + set width(value) { + if (this._width !== value) { + this._width = value; + + this.set_uniform_value('width', parseFloat(this._width + 3.0 - 1e-6)); + + if (this.chained_effect) + this.chained_effect.width = value; + } + } + + get height() { + return this._height; + } + + set height(value) { + if (this._height !== value) { + this._height = value; + + this.set_uniform_value('height', parseFloat(this._height + 3.0 - 1e-6)); + + if (this.chained_effect) + this.chained_effect.height = value; + } + } + + get direction() { + return this._direction; + } + + set direction(value) { + if (this._direction !== value) + this._direction = value; + } + + get chained_effect() { + return this._chained_effect; + } + + set chained_effect(value) { + this._chained_effect = value; + } + + vfunc_set_actor(actor) { + if (this._actor_connection_size_id) { + let old_actor = this.get_actor(); + old_actor?.disconnect(this._actor_connection_size_id); + } + if (actor) { + this.width = actor.width; + this.height = actor.height; + this._actor_connection_size_id = actor.connect('notify::size', _ => { + this.width = actor.width; + this.height = actor.height; + }); + } + else + this._actor_connection_size_id = null; + + super.vfunc_set_actor(actor); + + if (this.direction == 0) { + if (this.chained_effect) + this.chained_effect.get_actor()?.remove_effect(this.chained_effect); + else + this.chained_effect = new GaussianBlurEffect({ + radius: this.radius, + brightness: this.brightness, + width: this.width, + height: this.height, + direction: 1 + }); + if (actor !== null) + actor.add_effect(this.chained_effect); + } + } + + vfunc_paint_target(paint_node, paint_context) { + this.set_uniform_value("dir", this.direction); + + super.vfunc_paint_target(paint_node, paint_context); + } + }); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/hsl_to_rgb.glsl b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/hsl_to_rgb.glsl new file mode 100644 index 0000000..58d2694 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/hsl_to_rgb.glsl @@ -0,0 +1,14 @@ +uniform sampler2D tex; + +vec3 hsl_to_rgb(vec3 c) { + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} + +void main(void) { + vec2 uv = cogl_tex_coord_in[0].xy; + vec4 hsla = texture2D(tex, uv); + vec4 rgba = vec4(hsl_to_rgb(hsla.xyz), hsla.w); + cogl_color_out = rgba; +} \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/hsl_to_rgb.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/hsl_to_rgb.js new file mode 100644 index 0000000..fe53114 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/hsl_to_rgb.js @@ -0,0 +1,31 @@ +import GObject from 'gi://GObject'; + +import * as utils from '../conveniences/utils.js'; +const Shell = await utils.import_in_shell_only('gi://Shell'); +const Clutter = await utils.import_in_shell_only('gi://Clutter'); + +const SHADER_FILENAME = 'hsl_to_rgb.glsl'; +const DEFAULT_PARAMS = {}; + + +export const HslToRgbEffect = utils.IS_IN_PREFERENCES ? + { default_params: DEFAULT_PARAMS } : + new GObject.registerClass({ + GTypeName: "HslToRgbEffect", + Properties: {} + }, class HslToRgbEffect extends Clutter.ShaderEffect { + constructor(params) { + super(params); + + utils.setup_params(this, params); + + // set shader source + this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); + if (this._source) + this.set_shader_source(this._source); + } + + static get default_params() { + return DEFAULT_PARAMS; + } + }); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/monte_carlo_blur.glsl b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/monte_carlo_blur.glsl new file mode 100644 index 0000000..4142a46 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/monte_carlo_blur.glsl @@ -0,0 +1,44 @@ +uniform sampler2D tex; +uniform float radius; +uniform int iterations; +uniform float brightness; +uniform float width; +uniform float height; +uniform bool use_base_pixel; + +float srand(vec2 a) { + return sin(dot(a, vec2(1233.224, 1743.335))); +} + +float rand(inout float r) { + r = fract(3712.65 * r + 0.61432); + return (r - 0.5) * 2.0; +} + +void main() { + vec2 uv = cogl_tex_coord0_in.st; + vec2 p = 16 * radius / vec2(width, height); + float r = srand(uv); + vec2 rv; + + int count = 0; + vec4 c = vec4(0.); + + for (int i = 0; i < iterations; i++) { + rv.x = rand(r); + rv.y = rand(r); + vec2 new_uv = uv + rv * p; + if (new_uv.x > 2. / width && new_uv.y > 2. / height && new_uv.x < 1. - 3. / width && new_uv.y < 1. - 3. / height) { + c += texture2D(tex, new_uv); + count += 1; + } + } + + if (count == 0 || use_base_pixel) { + c += texture2D(tex, uv); + count += 1; + } + + c.xyz *= brightness; + cogl_color_out = c / count; +} \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/monte_carlo_blur.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/monte_carlo_blur.js new file mode 100644 index 0000000..fbf01a7 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/monte_carlo_blur.js @@ -0,0 +1,187 @@ +import GObject from 'gi://GObject'; + +import * as utils from '../conveniences/utils.js'; +const St = await utils.import_in_shell_only('gi://St'); +const Shell = await utils.import_in_shell_only('gi://Shell'); +const Clutter = await utils.import_in_shell_only('gi://Clutter'); + +const SHADER_FILENAME = 'monte_carlo_blur.glsl'; +const DEFAULT_PARAMS = { + radius: 2., iterations: 5, brightness: .6, + width: 0, height: 0, use_base_pixel: true +}; + + +export const MonteCarloBlurEffect = utils.IS_IN_PREFERENCES ? + { default_params: DEFAULT_PARAMS } : + new GObject.registerClass({ + GTypeName: "MonteCarloBlurEffect", + Properties: { + 'radius': GObject.ParamSpec.double( + `radius`, + `Radius`, + `Blur radius`, + GObject.ParamFlags.READWRITE, + 0.0, 2000.0, + 2.0, + ), + 'iterations': GObject.ParamSpec.int( + `iterations`, + `Iterations`, + `Blur iterations`, + GObject.ParamFlags.READWRITE, + 0, 64, + 5, + ), + 'brightness': GObject.ParamSpec.double( + `brightness`, + `Brightness`, + `Blur brightness`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 0.6, + ), + 'width': GObject.ParamSpec.double( + `width`, + `Width`, + `Width`, + GObject.ParamFlags.READWRITE, + 0.0, Number.MAX_SAFE_INTEGER, + 0.0, + ), + 'height': GObject.ParamSpec.double( + `height`, + `Height`, + `Height`, + GObject.ParamFlags.READWRITE, + 0.0, Number.MAX_SAFE_INTEGER, + 0.0, + ), + 'use_base_pixel': GObject.ParamSpec.boolean( + `use_base_pixel`, + `Use base pixel`, + `Use base pixel`, + GObject.ParamFlags.READWRITE, + true, + ), + } + }, class MonteCarloBlurEffect extends Clutter.ShaderEffect { + constructor(params) { + super(params); + + utils.setup_params(this, params); + + // set shader source + this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); + if (this._source) + this.set_shader_source(this._source); + + const theme_context = St.ThemeContext.get_for_stage(global.stage); + theme_context.connectObject( + 'notify::scale-factor', + _ => this.set_uniform_value('radius', + parseFloat(this._radius * theme_context.scale_factor - 1e-6) + ), + this + ); + } + + static get default_params() { + return DEFAULT_PARAMS; + } + + get radius() { + return this._radius; + } + + set radius(value) { + if (this._radius !== value) { + this._radius = value; + + const scale_factor = St.ThemeContext.get_for_stage(global.stage).scale_factor; + + this.set_uniform_value('radius', parseFloat(this._radius * scale_factor - 1e-6)); + this.set_enabled(this.radius > 0. && this.iterations > 0); + } + } + + get iterations() { + return this._iterations; + } + + set iterations(value) { + if (this._iterations !== value) { + this._iterations = value; + + this.set_uniform_value('iterations', this._iterations); + this.set_enabled(this.radius > 0. && this.iterations > 0); + } + } + + get brightness() { + return this._brightness; + } + + set brightness(value) { + if (this._brightness !== value) { + this._brightness = value; + + this.set_uniform_value('brightness', parseFloat(this._brightness - 1e-6)); + } + } + + get width() { + return this._width; + } + + set width(value) { + if (this._width !== value) { + this._width = value; + + this.set_uniform_value('width', parseFloat(this._width + 3.0 - 1e-6)); + } + } + + get height() { + return this._height; + } + + set height(value) { + if (this._height !== value) { + this._height = value; + + this.set_uniform_value('height', parseFloat(this._height + 3.0 - 1e-6)); + } + } + + get use_base_pixel() { + return this._use_base_pixel; + } + + set use_base_pixel(value) { + if (this._use_base_pixel !== value) { + this._use_base_pixel = value; + + this.set_uniform_value('use_base_pixel', this._use_base_pixel ? 1 : 0); + } + } + + vfunc_set_actor(actor) { + if (this._actor_connection_size_id) { + let old_actor = this.get_actor(); + old_actor?.disconnect(this._actor_connection_size_id); + } + if (actor) { + this.width = actor.width; + this.height = actor.height; + this._actor_connection_size_id = actor.connect('notify::size', _ => { + this.width = actor.width; + this.height = actor.height; + }); + } + else + this._actor_connection_size_id = null; + + super.vfunc_set_actor(actor); + } + }); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/native_dynamic_gaussian_blur.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/native_dynamic_gaussian_blur.js new file mode 100644 index 0000000..556ffa4 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/native_dynamic_gaussian_blur.js @@ -0,0 +1,43 @@ +import GObject from 'gi://GObject'; + +import * as utils from '../conveniences/utils.js'; +const St = await utils.import_in_shell_only('gi://St'); +const Shell = await utils.import_in_shell_only('gi://Shell'); + +const DEFAULT_PARAMS = { + unscaled_radius: 30, brightness: 0.6 +}; + + +export const NativeDynamicBlurEffect = utils.IS_IN_PREFERENCES ? + { default_params: DEFAULT_PARAMS } : + new GObject.registerClass({ + GTypeName: "NativeDynamicBlurEffect" + }, class NativeDynamicBlurEffect extends Shell.BlurEffect { + constructor(params) { + const { unscaled_radius, brightness, ...parent_params } = params; + super({ ...parent_params, mode: Shell.BlurMode.BACKGROUND }); + + this._theme_context = St.ThemeContext.get_for_stage(global.stage); + this._theme_context.connectObject( + 'notify::scale-factor', + _ => this.radius = this.unscaled_radius * this._theme_context.scale_factor, + this + ); + + utils.setup_params(this, params); + } + + static get default_params() { + return DEFAULT_PARAMS; + } + + get unscaled_radius() { + return this._unscaled_radius; + } + + set unscaled_radius(value) { + this._unscaled_radius = value; + this.radius = value * this._theme_context.scale_factor; + } + }); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/native_static_gaussian_blur.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/native_static_gaussian_blur.js new file mode 100644 index 0000000..fe003f5 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/native_static_gaussian_blur.js @@ -0,0 +1,43 @@ +import GObject from 'gi://GObject'; + +import * as utils from '../conveniences/utils.js'; +const St = await utils.import_in_shell_only('gi://St'); +const Shell = await utils.import_in_shell_only('gi://Shell'); + +const DEFAULT_PARAMS = { + unscaled_radius: 30, brightness: 0.6 +}; + + +export const NativeStaticBlurEffect = utils.IS_IN_PREFERENCES ? + { default_params: DEFAULT_PARAMS } : + new GObject.registerClass({ + GTypeName: "NativeStaticBlurEffect" + }, class NativeStaticBlurEffect extends Shell.BlurEffect { + constructor(params) { + const { unscaled_radius, brightness, ...parent_params } = params; + super({ ...parent_params, mode: Shell.BlurMode.ACTOR }); + + this._theme_context = St.ThemeContext.get_for_stage(global.stage); + this._theme_context.connectObject( + 'notify::scale-factor', + _ => this.radius = this.unscaled_radius * this._theme_context.scale_factor, + this + ); + + utils.setup_params(this, params); + } + + static get default_params() { + return DEFAULT_PARAMS; + } + + get unscaled_radius() { + return this._unscaled_radius; + } + + set unscaled_radius(value) { + this._unscaled_radius = value; + this.radius = value * this._theme_context.scale_factor; + } + }); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/noise_effect.glsl b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/noise.glsl similarity index 100% rename from gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/noise_effect.glsl rename to gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/noise.glsl diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/noise.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/noise.js new file mode 100644 index 0000000..3049fa1 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/noise.js @@ -0,0 +1,76 @@ +import GObject from 'gi://GObject'; + +import * as utils from '../conveniences/utils.js'; +const Shell = await utils.import_in_shell_only('gi://Shell'); +const Clutter = await utils.import_in_shell_only('gi://Clutter'); + +const SHADER_FILENAME = 'noise.glsl'; +const DEFAULT_PARAMS = { + noise: 0.4, lightness: 0.4 +}; + + +export const NoiseEffect = utils.IS_IN_PREFERENCES ? + { default_params: DEFAULT_PARAMS } : + new GObject.registerClass({ + GTypeName: "NoiseEffect", + Properties: { + 'noise': GObject.ParamSpec.double( + `noise`, + `Noise`, + `Amount of noise integrated with the image`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 0.4, + ), + 'lightness': GObject.ParamSpec.double( + `lightness`, + `Lightness`, + `Lightness of the grey used for the noise`, + GObject.ParamFlags.READWRITE, + 0.0, 2.0, + 0.4, + ), + } + }, class NoiseEffect extends Clutter.ShaderEffect { + constructor(params) { + super(params); + + utils.setup_params(this, params); + + // set shader source + this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); + if (this._source) + this.set_shader_source(this._source); + } + + static get default_params() { + return DEFAULT_PARAMS; + } + + get noise() { + return this._noise; + } + + set noise(value) { + if (this._noise !== value) { + this._noise = value; + + this.set_uniform_value('noise', parseFloat(this._noise - 1e-6)); + this.set_enabled(this.noise > 0. && this.lightness != 1); + } + } + + get lightness() { + return this._lightness; + } + + set lightness(value) { + if (this._lightness !== value) { + this._lightness = value; + + this.set_uniform_value('lightness', parseFloat(this._lightness - 1e-6)); + this.set_enabled(this.noise > 0. && this.lightness != 1); + } + } + }); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/noise_effect.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/noise_effect.js deleted file mode 100644 index 8d9464c..0000000 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/noise_effect.js +++ /dev/null @@ -1,109 +0,0 @@ -import GLib from 'gi://GLib'; -import GObject from 'gi://GObject'; -import Clutter from 'gi://Clutter'; -import Shell from 'gi://Shell'; - - -const SHADER_PATH = GLib.filename_from_uri(GLib.uri_resolve_relative(import.meta.url, 'noise_effect.glsl', GLib.UriFlags.NONE))[0]; - -const get_shader_source = _ => { - try { - return Shell.get_file_contents_utf8_sync(SHADER_PATH); - } catch (e) { - console.warn(`[Blur my Shell] error loading shader from ${SHADER_PATH}: ${e}`); - return null; - } -}; - -export const NoiseEffect = new GObject.registerClass({ - GTypeName: "NoiseEffect", - Properties: { - 'noise': GObject.ParamSpec.double( - `noise`, - `Noise`, - `Amount of noise integrated with the image`, - GObject.ParamFlags.READWRITE, - 0.0, 1.0, - 0.4, - ), - 'lightness': GObject.ParamSpec.double( - `lightness`, - `Lightness`, - `Lightness of the grey used for the noise`, - GObject.ParamFlags.READWRITE, - 0.0, 2.0, - 0.4, - ), - } -}, class NoiseShader extends Clutter.ShaderEffect { - constructor(params, settings) { - super(params); - - this._noise = null; - this._lightness = null; - - this._static = true; - this._settings = settings; - - if (params.noise) - this.noise = params.noise; - if (params.lightness) - this.lightness = params.lightness; - - // set shader source - this._source = get_shader_source(); - if (this._source) - this.set_shader_source(this._source); - - this.update_enabled(); - } - - get noise() { - return this._noise; - } - - set noise(value) { - if (this._noise !== value) { - this._noise = value; - - this.set_uniform_value('noise', parseFloat(this._noise - 1e-6)); - } - this.update_enabled(); - } - - get lightness() { - return this._lightness; - } - - set lightness(value) { - if (this._lightness !== value) { - this._lightness = value; - - this.set_uniform_value('lightness', parseFloat(this._lightness - 1e-6)); - } - } - - update_enabled() { - // don't anything if this._settings is undefined (when calling super) - if (this._settings === undefined) - return; - - this.set_enabled( - this.noise > 0 && - this._settings.COLOR_AND_NOISE && - this._static - ); - } - - - vfunc_paint_target(paint_node = null, paint_context = null) { - this.set_uniform_value("tex", 0); - - if (paint_node && paint_context) - super.vfunc_paint_target(paint_node, paint_context); - else if (paint_node) - super.vfunc_paint_target(paint_node); - else - super.vfunc_paint_target(); - } -}); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/pixelize.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/pixelize.js new file mode 100644 index 0000000..e9cad9b --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/pixelize.js @@ -0,0 +1,88 @@ +import GObject from 'gi://GObject'; + +import * as utils from '../conveniences/utils.js'; +const Clutter = await utils.import_in_shell_only('gi://Clutter'); + +import { UpscaleEffect } from './upscale.js'; +import { DownscaleEffect } from './downscale.js'; + +const DEFAULT_PARAMS = { + factor: 8, downsampling_mode: 0 +}; + + +export const PixelizeEffect = utils.IS_IN_PREFERENCES ? + { default_params: DEFAULT_PARAMS } : + new GObject.registerClass({ + GTypeName: "PixelizeEffect", + Properties: { + 'factor': GObject.ParamSpec.int( + `factor`, + `Factor`, + `Factor`, + GObject.ParamFlags.READWRITE, + 0, 64, + 8, + ), + 'downsampling_mode': GObject.ParamSpec.int( + `downsampling_mode`, + `Downsampling mode`, + `Downsampling mode`, + GObject.ParamFlags.READWRITE, + 0, 2, + 0, + ) + } + }, class PixelizeEffect extends Clutter.Effect { + constructor(params) { + super(); + + this.upscale_effect = new UpscaleEffect({}); + this.downscale_effect = new DownscaleEffect({}); + + utils.setup_params(this, params); + } + + static get default_params() { + return DEFAULT_PARAMS; + } + + get factor() { + // should be the same as `this.downscale_effect.divider` + return this.upscale_effect.factor; + } + + set factor(value) { + this.upscale_effect.factor = value; + this.downscale_effect.divider = value; + } + + get downsampling_mode() { + return this.downscale_effect.downsampling_mode; + } + + set downsampling_mode(value) { + this.downscale_effect.downsampling_mode = value; + } + + vfunc_set_actor(actor) { + // deattach effects from old actor + this.upscale_effect?.actor?.remove_effect(this.upscale_effect); + this.downscale_effect?.actor?.remove_effect(this.downscale_effect); + // attach effects to new actor + if (actor) { + if (this.upscale_effect) + actor.add_effect(this.upscale_effect); + if (this.downscale_effect) + actor.add_effect(this.downscale_effect); + } + + super.vfunc_set_actor(actor); + } + + vfunc_set_enabled(is_enabled) { + this.upscale_effect?.set_enabled(is_enabled); + this.downscale_effect?.set_enabled(is_enabled); + super.vfunc_set_enabled(is_enabled); + } + }); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/rgb_to_hsl.glsl b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/rgb_to_hsl.glsl new file mode 100644 index 0000000..b7a35ac --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/rgb_to_hsl.glsl @@ -0,0 +1,18 @@ +uniform sampler2D tex; + +vec3 rgb_to_hsl(vec3 c) { + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +void main(void) { + vec2 uv = cogl_tex_coord_in[0].xy; + vec4 rgba = texture2D(tex, uv); + vec4 hsla = vec4(rgb_to_hsl(rgba.xyz), rgba.w); + cogl_color_out = hsla; +} \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/rgb_to_hsl.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/rgb_to_hsl.js new file mode 100644 index 0000000..5c4eb05 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/rgb_to_hsl.js @@ -0,0 +1,31 @@ +import GObject from 'gi://GObject'; + +import * as utils from '../conveniences/utils.js'; +const Shell = await utils.import_in_shell_only('gi://Shell'); +const Clutter = await utils.import_in_shell_only('gi://Clutter'); + +const SHADER_FILENAME = 'rgb_to_hsl.glsl'; +const DEFAULT_PARAMS = {}; + + +export const RgbToHslEffect = utils.IS_IN_PREFERENCES ? + { default_params: DEFAULT_PARAMS } : + new GObject.registerClass({ + GTypeName: "RgbToHslEffect", + Properties: {} + }, class RgbToHslEffect extends Clutter.ShaderEffect { + constructor(params) { + super(params); + + utils.setup_params(this, params); + + // set shader source + this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); + if (this._source) + this.set_shader_source(this._source); + } + + static get default_params() { + return DEFAULT_PARAMS; + } + }); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/upscale.glsl b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/upscale.glsl new file mode 100644 index 0000000..5cc06ec --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/upscale.glsl @@ -0,0 +1,57 @@ +uniform sampler2D tex; +uniform int factor; +uniform float width; +uniform float height; + +#define CORRECTION 2.25 +#define SIZE_ADDITION 3 + +vec4 get_texture_at_position(vec2 position) { + vec2 raw_position = position + vec2(CORRECTION, CORRECTION); + vec2 raw_uv = raw_position / vec2(width + SIZE_ADDITION, height + SIZE_ADDITION); + + return texture2D(tex, raw_uv); +} + +ivec2 get_corrected_position() { + vec2 raw_uv = cogl_tex_coord0_in.st; + vec2 raw_position = raw_uv * vec2(width + SIZE_ADDITION, height + SIZE_ADDITION); + return ivec2(raw_position - vec2(CORRECTION, CORRECTION)); +} + +void main() { + ivec2 corrected_position = get_corrected_position(); + + vec2 adjusted_position = corrected_position / factor; + + cogl_color_out = get_texture_at_position(adjusted_position); + + // round + if (distance(corrected_position, (floor(adjusted_position) + 0.5) * factor) < factor / 2.5) { + //cogl_color_out = get_texture_at_position(adjusted_position); + } else { + //cogl_color_out = vec4(0, 0, 0, 1); + } + + // square + if (mod(corrected_position.x, factor) >= 2 && mod(corrected_position.y, factor) >= 2) { + //cogl_color_out = get_texture_at_position(adjusted_position); + } else { + //cogl_color_out = vec4(0, 0, 0, 1); + } + + // local mix + vec4 color = vec4(0); + int count = 0; + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + vec2 lookup_position = adjusted_position + vec2(i, j); + if (all(greaterThanEqual(lookup_position, vec2(0, 0))) && + all(lessThan(lookup_position, vec2(width, height) / factor))) { + color += get_texture_at_position(lookup_position); + count += 1; + } + } + } + //cogl_color_out = color / count; +} \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/upscale.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/upscale.js new file mode 100644 index 0000000..fb719c3 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/upscale.js @@ -0,0 +1,120 @@ +import GObject from 'gi://GObject'; + +import * as utils from '../conveniences/utils.js'; +const Shell = await utils.import_in_shell_only('gi://Shell'); +const Clutter = await utils.import_in_shell_only('gi://Clutter'); + +const SHADER_FILENAME = 'upscale.glsl'; +const DEFAULT_PARAMS = { + factor: 8, width: 0, height: 0 +}; + + +export const UpscaleEffect = utils.IS_IN_PREFERENCES ? + { default_params: DEFAULT_PARAMS } : + new GObject.registerClass({ + GTypeName: "UpscaleEffect", + Properties: { + 'factor': GObject.ParamSpec.int( + `factor`, + `Factor`, + `Factor`, + GObject.ParamFlags.READWRITE, + 0, 64, + 8, + ), + 'width': GObject.ParamSpec.double( + `width`, + `Width`, + `Width`, + GObject.ParamFlags.READWRITE, + 0.0, Number.MAX_SAFE_INTEGER, + 0.0, + ), + 'height': GObject.ParamSpec.double( + `height`, + `Height`, + `Height`, + GObject.ParamFlags.READWRITE, + 0.0, Number.MAX_SAFE_INTEGER, + 0.0, + ) + } + }, class UpscaleEffect extends Clutter.ShaderEffect { + constructor(params) { + super(params); + + utils.setup_params(this, params); + + // set shader source + this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); + if (this._source) + this.set_shader_source(this._source); + } + + static get default_params() { + return DEFAULT_PARAMS; + } + + get factor() { + return this._factor; + } + + set factor(value) { + if (this._factor !== value) { + this._factor = value; + + this.set_uniform_value('factor', this._factor); + } + } + + get width() { + return this._width; + } + + set width(value) { + if (this._width !== value) { + this._width = value; + + this.set_uniform_value('width', parseFloat(this._width - 1e-6)); + } + } + + get height() { + return this._height; + } + + set height(value) { + if (this._height !== value) { + this._height = value; + + this.set_uniform_value('height', parseFloat(this._height - 1e-6)); + } + } + + vfunc_set_actor(actor) { + if (this._actor_connection_size_id) { + let old_actor = this.get_actor(); + old_actor?.disconnect(this._actor_connection_size_id); + } + if (actor) { + this.width = actor.width; + this.height = actor.height; + this._actor_connection_size_id = actor.connect('notify::size', _ => { + this.width = actor.width; + this.height = actor.height; + }); + } + else + this._actor_connection_size_id = null; + + super.vfunc_set_actor(actor); + } + + vfunc_paint_target(paint_node, paint_context) { + // force setting nearest-neighbour texture filtering + this.get_pipeline().set_layer_filters(0, 9728, 9728); + + super.vfunc_paint_target(paint_node, paint_context); + } + }); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/extension.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/extension.js index cd65616..443d7b6 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/extension.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/extension.js @@ -4,10 +4,12 @@ import * as Main from 'resource:///org/gnome/shell/ui/main.js'; import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js'; +import { update_from_old_settings } from './conveniences/settings_updater.js'; +import { PipelinesManager } from './conveniences/pipelines_manager.js'; import { EffectsManager } from './conveniences/effects_manager.js'; import { Connections } from './conveniences/connections.js'; import { Settings } from './conveniences/settings.js'; -import { Keys } from './conveniences/keys.js'; +import { KEYS } from './conveniences/keys.js'; import { PanelBlur } from './components/panel.js'; import { OverviewBlur } from './components/overview.js'; @@ -15,16 +17,10 @@ import { DashBlur } from './components/dash_to_dock.js'; import { LockscreenBlur } from './components/lockscreen.js'; import { AppFoldersBlur } from './components/appfolders.js'; import { WindowListBlur } from './components/window_list.js'; +import { CoverflowAltTabBlur } from './components/coverflow_alt_tab.js'; import { ApplicationsBlur } from './components/applications.js'; import { ScreenshotBlur } from './components/screenshot.js'; -// This lists the components that need to be connected in order to either use -// general sigma/brightness or their own. -const INDEPENDENT_COMPONENTS = [ - "overview", "appfolder", "panel", "dash_to_dock", "applications", - "lockscreen", "window_list", "screenshot" -]; - /// The main extension class, created when the GNOME Shell is loaded. export default class BlurMyShell extends Extension { @@ -34,9 +30,12 @@ export default class BlurMyShell extends Extension { // create it first as it is very useful when debugging crashes global.blur_my_shell = this; + // update from old settings, very important for hacks level specifically + update_from_old_settings(this.getSettings()); + // create a Settings instance, to manage extension's preferences // it needs to be loaded before logging, as it checks for DEBUG - this._settings = new Settings(Keys, this.getSettings()); + this._settings = new Settings(KEYS, this.getSettings()); this._log("enabling extension..."); @@ -49,8 +48,11 @@ export default class BlurMyShell extends Extension { // create a global effects manager (to prevent RAM bleeding) this._effects_manager = new EffectsManager(this._connection); + // create a global pipelines manager, that helps talking with preferences + this._pipelines_manager = new PipelinesManager(this._settings); + // create an instance of each component, with its associated Connections - let init = _ => { + let init = () => { // create a Connections instance, to manage signals let connection = new Connections; @@ -66,6 +68,7 @@ export default class BlurMyShell extends Extension { this._lockscreen_blur = new LockscreenBlur(...init()); this._appfolder_blur = new AppFoldersBlur(...init()); this._window_list_blur = new WindowListBlur(...init()); + this._coverflow_alt_tab_blur = new CoverflowAltTabBlur(...init()); this._applications_blur = new ApplicationsBlur(...init()); this._screenshot_blur = new ScreenshotBlur(...init()); @@ -82,7 +85,7 @@ export default class BlurMyShell extends Extension { // watch for changes to the session mode this._connection.connect(Main.sessionMode, 'updated', - _ => this._on_session_mode_changed(Main.sessionMode) + () => this._on_session_mode_changed(Main.sessionMode) ); } @@ -100,11 +103,10 @@ export default class BlurMyShell extends Extension { this._connection.connect( Main.layoutManager, 'startup-complete', - this._enable_components.bind(this) + () => this._enable_components() ); - } else { + } else this._enable_components(); - } // try to enable the components as soon as possible anyway, this way the // overview may load before the user sees it @@ -155,6 +157,7 @@ export default class BlurMyShell extends Extension { // disable every component from user session mode if (this._user_session_mode_enabled) this._disable_user_session(); + this._overview_blur.restore_patched_proto(); // disable lockscreen blur too this._lockscreen_blur.disable(); @@ -166,6 +169,7 @@ export default class BlurMyShell extends Extension { this._appfolder_blur = null; this._lockscreen_blur = null; this._window_list_blur = null; + this._coverflow_alt_tab_blur = null; this._applications_blur = null; this._screenshot_blur = null; @@ -199,6 +203,7 @@ export default class BlurMyShell extends Extension { this._overview_blur.disable(); this._appfolder_blur.disable(); this._window_list_blur.disable(); + this._coverflow_alt_tab_blur.disable(); this._applications_blur.disable(); this._screenshot_blur.disable(); @@ -240,7 +245,7 @@ export default class BlurMyShell extends Extension { /// the user really needs it, as clipped redraws are a huge performance /// boost for the compositor. _update_clipped_redraws() { - if (this._settings.HACKS_LEVEL === 3) + if (this._settings.HACKS_LEVEL === 2) this._disable_clipped_redraws(); else this._reenable_clipped_redraws(); @@ -283,6 +288,9 @@ export default class BlurMyShell extends Extension { if (this._settings.window_list.BLUR) this._window_list_blur.enable(); + if (this._settings.coverflow_alt_tab.BLUR) + this._coverflow_alt_tab_blur.enable(); + if (this._settings.screenshot.BLUR) this._screenshot_blur.enable(); @@ -291,58 +299,31 @@ export default class BlurMyShell extends Extension { /// Updates needed things in each component when a preference changed _connect_to_settings() { - - // global blur values changed, update everybody - - this._settings.SIGMA_changed(() => { - this._update_sigma(); - }); - this._settings.BRIGHTNESS_changed(() => { - this._update_brightness(); - }); - this._settings.COLOR_changed(() => { - this._update_color(); - }); - this._settings.NOISE_AMOUNT_changed(() => { - this._update_noise_amount(); - }); - this._settings.NOISE_LIGHTNESS_changed(() => { - this._update_noise_lightness(); - }); - this._settings.COLOR_AND_NOISE_changed(() => { - // both updating noise amount and color calls `update_enabled` on - // each color and noise effects - this._update_noise_amount(); - this._update_color(); - }); - // restart the extension when hacks level is changed, easier than // restarting individual components and should not happen often either - this._settings.HACKS_LEVEL_changed(_ => this._restart()); + this._settings.HACKS_LEVEL_changed(() => this._restart()); - // connect each component to use the proper sigma/brightness/color - INDEPENDENT_COMPONENTS.forEach(component => { - this._connect_to_individual_settings(component); - }); - - // other component's preferences changed // ---------- OVERVIEW ---------- // toggled on/off this._settings.overview.BLUR_changed(() => { - if (this._settings.overview.BLUR) { + if (this._settings.overview.BLUR) this._overview_blur.enable(); - } else { + else this._overview_blur.disable(); - } + }); + + // overview pipeline changed + this._settings.overview.PIPELINE_changed(() => { + if (this._settings.overview.BLUR) + this._overview_blur.update_backgrounds(); }); // overview components style changed this._settings.overview.STYLE_COMPONENTS_changed(() => { - if (this._settings.overview.BLUR) { + if (this._settings.overview.BLUR) this._overview_blur.update_components_classname(); - } }); @@ -350,11 +331,26 @@ export default class BlurMyShell extends Extension { // toggled on/off this._settings.appfolder.BLUR_changed(() => { - if (this._settings.appfolder.BLUR) { + if (this._settings.appfolder.BLUR) this._appfolder_blur.enable(); - } else { + else this._appfolder_blur.disable(); - } + }); + + // appfolder sigma changed + this._settings.appfolder.SIGMA_changed(() => { + if (this._settings.appfolder.BLUR) + this._appfolder_blur.set_sigma( + this._settings.appfolder.SIGMA + ); + }); + + // appfolder brightness changed + this._settings.appfolder.BRIGHTNESS_changed(() => { + if (this._settings.appfolder.BLUR) + this._appfolder_blur.set_brightness( + this._settings.appfolder.BRIGHTNESS + ); }); // appfolder dialogs style changed @@ -368,24 +364,22 @@ export default class BlurMyShell extends Extension { // toggled on/off this._settings.panel.BLUR_changed(() => { - if (this._settings.panel.BLUR) { - this._panel_blur.enable(); - } else { - this._panel_blur.disable(); - } - }); - - this._settings.COLOR_AND_NOISE_changed(() => { - // permits making sure that the blur is not washed out when disabling - // the other effects if (this._settings.panel.BLUR) - this._panel_blur.invalidate_all_blur(); + this._panel_blur.enable(); + else + this._panel_blur.disable(); }); - // static blur toggled on/off + // static blur toggled on/off, really we can just reload the blur at this point this._settings.panel.STATIC_BLUR_changed(() => { if (this._settings.panel.BLUR) - this._panel_blur.update_all_blur_type(); + this._panel_blur.reset(); + }); + + // panel pipeline changed + this._settings.panel.PIPELINE_changed(() => { + if (this._settings.panel.BLUR) + this._panel_blur.update_pipeline(); }); // panel blur's overview connection toggled on/off @@ -422,11 +416,10 @@ export default class BlurMyShell extends Extension { // toggled on/off this._settings.dash_to_dock.BLUR_changed(() => { - if (this._settings.dash_to_dock.BLUR) { + if (this._settings.dash_to_dock.BLUR) this._dash_to_dock_blur.enable(); - } else { + else this._dash_to_dock_blur.disable(); - } }); // static blur toggled on/off @@ -435,10 +428,10 @@ export default class BlurMyShell extends Extension { this._dash_to_dock_blur.change_blur_type(); }); - // dash-to-dock corner radius changed - this._settings.dash_to_dock.CORNER_RADIUS_changed(() => { - if (this._settings.dash_to_dock.STATIC_BLUR) - this._dash_to_dock_blur.set_corner_radius(this._settings.dash_to_dock.CORNER_RADIUS); + // overview pipeline changed + this._settings.dash_to_dock.PIPELINE_changed(() => { + if (this._settings.dash_to_dock.BLUR) + this._dash_to_dock_blur.update_pipeline(); }); // dash-to-dock override background toggled on/off @@ -464,35 +457,40 @@ export default class BlurMyShell extends Extension { // toggled on/off this._settings.applications.BLUR_changed(() => { - if (this._settings.applications.BLUR) { + if (this._settings.applications.BLUR) this._applications_blur.enable(); - } else { + else this._applications_blur.disable(); - } }); // application opacity changed - this._settings.applications.OPACITY_changed(_ => { + this._settings.applications.OPACITY_changed(() => { if (this._settings.applications.BLUR) this._applications_blur.set_opacity( this._settings.applications.OPACITY ); }); + // application dynamic-opacity changed + this._settings.applications.DYNAMIC_OPACITY_changed(() => { + if (this._settings.applications.BLUR) + this._applications_blur.init_dynamic_opacity(); + }); + // application blur-on-overview changed - this._settings.applications.BLUR_ON_OVERVIEW_changed(_ => { + this._settings.applications.BLUR_ON_OVERVIEW_changed(() => { if (this._settings.applications.BLUR) this._applications_blur.connect_to_overview(); }); // application enable-all changed - this._settings.applications.ENABLE_ALL_changed(_ => { + this._settings.applications.ENABLE_ALL_changed(() => { if (this._settings.applications.BLUR) this._applications_blur.update_all_windows(); }); // application whitelist changed - this._settings.applications.WHITELIST_changed(_ => { + this._settings.applications.WHITELIST_changed(() => { if ( this._settings.applications.BLUR && !this._settings.applications.ENABLE_ALL @@ -501,7 +499,7 @@ export default class BlurMyShell extends Extension { }); // application blacklist changed - this._settings.applications.BLACKLIST_changed(_ => { + this._settings.applications.BLACKLIST_changed(() => { if ( this._settings.applications.BLUR && this._settings.applications.ENABLE_ALL @@ -514,11 +512,16 @@ export default class BlurMyShell extends Extension { // toggled on/off this._settings.lockscreen.BLUR_changed(() => { - if (this._settings.lockscreen.BLUR) { + if (this._settings.lockscreen.BLUR) this._lockscreen_blur.enable(); - } else { + else this._lockscreen_blur.disable(); - } + }); + + // lockscreen pipeline changed + this._settings.lockscreen.PIPELINE_changed(() => { + if (this._settings.lockscreen.BLUR) + this._lockscreen_blur.update_lockscreen(); }); @@ -526,11 +529,21 @@ export default class BlurMyShell extends Extension { // toggled on/off this._settings.window_list.BLUR_changed(() => { - if (this._settings.window_list.BLUR) { + if (this._settings.window_list.BLUR) this._window_list_blur.enable(); - } else { + else this._window_list_blur.disable(); - } + }); + + + // ---------- COVERFLOW ALT-TAB ---------- + + // toggled on/off + this._settings.coverflow_alt_tab.BLUR_changed(() => { + if (this._settings.coverflow_alt_tab.BLUR) + this._coverflow_alt_tab_blur.enable(); + else + this._coverflow_alt_tab_blur.disable(); }); @@ -556,157 +569,16 @@ export default class BlurMyShell extends Extension { // toggled on/off this._settings.screenshot.BLUR_changed(() => { - if (this._settings.screenshot.BLUR) { + if (this._settings.screenshot.BLUR) this._screenshot_blur.enable(); - } else { + else this._screenshot_blur.disable(); - } - }); - } - - /// Select the component by its name and connect it to its preferences - /// changes for general values, sigma and brightness. - /// - /// Doing this in such a way is less accessible but prevents a lot of - /// boilerplate and headaches. - _connect_to_individual_settings(name) { - // get component and preferences needed - let component = this['_' + name + '_blur']; - let component_settings = this._settings[name]; - - // general values switch is toggled - component_settings.CUSTOMIZE_changed(() => { - if (component_settings.CUSTOMIZE) { - component.set_sigma(component_settings.SIGMA); - component.set_brightness(component_settings.BRIGHTNESS); - component.set_color(component_settings.COLOR); - component.set_noise_amount(component_settings.NOISE_AMOUNT); - component.set_noise_lightness(component_settings.NOISE_LIGHTNESS); - } - else { - component.set_sigma(this._settings.SIGMA); - component.set_brightness(this._settings.BRIGHTNESS); - component.set_color(this._settings.COLOR); - component.set_noise_amount(this._settings.NOISE_AMOUNT); - component.set_noise_lightness(this._settings.NOISE_LIGHTNESS); - } }); - // sigma is changed - component_settings.SIGMA_changed(() => { - if (component_settings.CUSTOMIZE) - component.set_sigma(component_settings.SIGMA); - else - component.set_sigma(this._settings.SIGMA); - }); - - // brightness is changed - component_settings.BRIGHTNESS_changed(() => { - if (component_settings.CUSTOMIZE) - component.set_brightness(component_settings.BRIGHTNESS); - else - component.set_brightness(this._settings.BRIGHTNESS); - }); - - // color is changed - component_settings.COLOR_changed(() => { - if (component_settings.CUSTOMIZE) - component.set_color(component_settings.COLOR); - else - component.set_color(this._settings.COLOR); - }); - - // noise amount is changed - component_settings.NOISE_AMOUNT_changed(() => { - if (component_settings.CUSTOMIZE) - component.set_noise_amount(component_settings.NOISE_AMOUNT); - else - component.set_noise_amount(this._settings.NOISE_AMOUNT); - }); - - // noise lightness is changed - component_settings.NOISE_LIGHTNESS_changed(() => { - if (component_settings.CUSTOMIZE) - component.set_noise_lightness(component_settings.NOISE_LIGHTNESS); - else - component.set_noise_lightness(this._settings.NOISE_LIGHTNESS); - }); - } - - /// Update each component's sigma value - _update_sigma() { - INDEPENDENT_COMPONENTS.forEach(name => { - // get component and preferences needed - let component = this['_' + name + '_blur']; - let component_settings = this._settings[name]; - - // update sigma accordingly - if (component_settings.CUSTOMIZE) { - component.set_sigma(component_settings.SIGMA); - } - else { - component.set_sigma(this._settings.SIGMA); - } - }); - } - - /// Update each component's brightness value - _update_brightness() { - INDEPENDENT_COMPONENTS.forEach(name => { - // get component and preferences needed - let component = this['_' + name + '_blur']; - let component_settings = this._settings[name]; - - // update brightness accordingly - if (component_settings.CUSTOMIZE) - component.set_brightness(component_settings.BRIGHTNESS); - else - component.set_brightness(this._settings.BRIGHTNESS); - }); - } - - /// Update each component's color value - _update_color() { - INDEPENDENT_COMPONENTS.forEach(name => { - // get component and preferences needed - let component = this['_' + name + '_blur']; - let component_settings = this._settings[name]; - - // update color accordingly - if (component_settings.CUSTOMIZE) - component.set_color(component_settings.COLOR); - else - component.set_color(this._settings.COLOR); - }); - } - - /// Update each component's noise amount value - _update_noise_amount() { - INDEPENDENT_COMPONENTS.forEach(name => { - // get component and preferences needed - let component = this['_' + name + '_blur']; - let component_settings = this._settings[name]; - - // update color accordingly - if (component_settings.CUSTOMIZE) - component.set_noise_amount(component_settings.NOISE_AMOUNT); - else - component.set_noise_amount(this._settings.NOISE_AMOUNT); - }); - } - - /// Update each component's noise lightness value - _update_noise_lightness() { - INDEPENDENT_COMPONENTS.forEach(name => { - // get component and preferences needed - let component = this['_' + name + '_blur']; - let component_settings = this._settings[name]; - - // update color accordingly - if (component_settings.CUSTOMIZE) - component.set_noise_lightness(component_settings.NOISE_LIGHTNESS); - else - component.set_noise_lightness(this._settings.NOISE_LIGHTNESS); + // screenshot pipeline changed + this._settings.screenshot.PIPELINE_changed(() => { + if (this._settings.screenshot.BLUR) + this._screenshot_blur.update_pipeline(); }); } diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/add-window-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/add-row-symbolic.svg similarity index 100% rename from gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/add-window-symbolic.svg rename to gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/add-row-symbolic.svg diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/down-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/down-symbolic.svg new file mode 100644 index 0000000..652f8c0 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/down-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/duplicate-row-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/duplicate-row-symbolic.svg new file mode 100644 index 0000000..925e900 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/duplicate-row-symbolic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/dynamic-mode-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/dynamic-mode-symbolic.svg new file mode 100644 index 0000000..c37b9aa --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/dynamic-mode-symbolic.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/edit-row-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/edit-row-symbolic.svg new file mode 100644 index 0000000..f4115ad --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/edit-row-symbolic.svg @@ -0,0 +1,14 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/general-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/general-symbolic.svg deleted file mode 100644 index e11da07..0000000 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/general-symbolic.svg +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/heart-filled-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/heart-filled-symbolic.svg deleted file mode 100644 index 8378c9c..0000000 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/heart-filled-symbolic.svg +++ /dev/null @@ -1,40 +0,0 @@ - - diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/heart-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/heart-symbolic.svg new file mode 100644 index 0000000..fa045a8 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/heart-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/pipelines-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/pipelines-symbolic.svg new file mode 100644 index 0000000..d451b23 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/pipelines-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/remove-window-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/remove-row-symbolic.svg similarity index 100% rename from gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/remove-window-symbolic.svg rename to gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/remove-row-symbolic.svg diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/select-mode-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/select-mode-symbolic.svg deleted file mode 100644 index cad2da8..0000000 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/select-mode-symbolic.svg +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/select-row-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/select-row-symbolic.svg new file mode 100644 index 0000000..e6d2d9e --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/select-row-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/static-mode-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/static-mode-symbolic.svg new file mode 100644 index 0000000..5b0eb20 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/icons/hicolor/scalable/actions/static-mode-symbolic.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/af/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/af/LC_MESSAGES/blur-my-shell@aunetx.mo index a190bd4..9228b72 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/af/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/af/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ar/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ar/LC_MESSAGES/blur-my-shell@aunetx.mo index d44c239..782420b 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ar/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ar/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/az/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/az/LC_MESSAGES/blur-my-shell@aunetx.mo index c7e0d94..118ad99 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/az/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/az/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/be/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/be/LC_MESSAGES/blur-my-shell@aunetx.mo index 2643e11..818a7e2 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/be/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/be/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/bg/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/bg/LC_MESSAGES/blur-my-shell@aunetx.mo index f95a0e8..5f80e8b 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/bg/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/bg/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ca/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ca/LC_MESSAGES/blur-my-shell@aunetx.mo index d397f3e..a03611b 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ca/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ca/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/cs/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/cs/LC_MESSAGES/blur-my-shell@aunetx.mo index f16a792..799f757 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/cs/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/cs/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/da/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/da/LC_MESSAGES/blur-my-shell@aunetx.mo new file mode 100644 index 0000000..155dcbb Binary files /dev/null and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/da/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/de/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/de/LC_MESSAGES/blur-my-shell@aunetx.mo index 7785a81..0a31cf8 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/de/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/de/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/el/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/el/LC_MESSAGES/blur-my-shell@aunetx.mo index 5825103..fc3ca9b 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/el/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/el/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/es/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/es/LC_MESSAGES/blur-my-shell@aunetx.mo index c9ea2a6..756a723 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/es/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/es/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/et/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/et/LC_MESSAGES/blur-my-shell@aunetx.mo new file mode 100644 index 0000000..2719fca Binary files /dev/null and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/et/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/fi/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/fi/LC_MESSAGES/blur-my-shell@aunetx.mo new file mode 100644 index 0000000..09c4422 Binary files /dev/null and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/fi/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/fr/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/fr/LC_MESSAGES/blur-my-shell@aunetx.mo index 0b25369..1bb85eb 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/fr/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/fr/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/he/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/he/LC_MESSAGES/blur-my-shell@aunetx.mo index b996b90..abb4ac0 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/he/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/he/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/hi/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/hi/LC_MESSAGES/blur-my-shell@aunetx.mo index 91c892e..ee819a7 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/hi/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/hi/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/hu/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/hu/LC_MESSAGES/blur-my-shell@aunetx.mo index b1831e1..f181edb 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/hu/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/hu/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/id/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/id/LC_MESSAGES/blur-my-shell@aunetx.mo index 2f8f20f..cf71764 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/id/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/id/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/it/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/it/LC_MESSAGES/blur-my-shell@aunetx.mo index f1eb271..484f405 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/it/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/it/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ja/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ja/LC_MESSAGES/blur-my-shell@aunetx.mo new file mode 100644 index 0000000..1a8f89e Binary files /dev/null and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ja/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ka/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ka/LC_MESSAGES/blur-my-shell@aunetx.mo index e354e4d..8c7b510 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ka/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ka/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ko/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ko/LC_MESSAGES/blur-my-shell@aunetx.mo index 1147607..c940d4b 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ko/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ko/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/nb_NO/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/nb_NO/LC_MESSAGES/blur-my-shell@aunetx.mo index acfeabf..2436b7c 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/nb_NO/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/nb_NO/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/nl/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/nl/LC_MESSAGES/blur-my-shell@aunetx.mo index e0be4d0..fdca051 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/nl/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/nl/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/nn/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/nn/LC_MESSAGES/blur-my-shell@aunetx.mo index 6bf2475..c872ad0 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/nn/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/nn/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/pl/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/pl/LC_MESSAGES/blur-my-shell@aunetx.mo index 2f3fe06..071cbd4 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/pl/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/pl/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/pt/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/pt/LC_MESSAGES/blur-my-shell@aunetx.mo index 1387462..8206001 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/pt/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/pt/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/pt_BR/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/pt_BR/LC_MESSAGES/blur-my-shell@aunetx.mo index a68cb99..efcc800 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/pt_BR/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/pt_BR/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ro/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ro/LC_MESSAGES/blur-my-shell@aunetx.mo index 7b7e190..eb69073 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ro/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ro/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ru/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ru/LC_MESSAGES/blur-my-shell@aunetx.mo index 22d2a2b..25e129d 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ru/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ru/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/sl/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/sl/LC_MESSAGES/blur-my-shell@aunetx.mo index abb13d0..0ceab79 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/sl/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/sl/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/sv/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/sv/LC_MESSAGES/blur-my-shell@aunetx.mo index 491c32b..efa421e 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/sv/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/sv/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ta/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ta/LC_MESSAGES/blur-my-shell@aunetx.mo index f524fad..6efb1c7 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ta/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/ta/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/tr/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/tr/LC_MESSAGES/blur-my-shell@aunetx.mo index ba45f9b..603f521 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/tr/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/tr/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/uk/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/uk/LC_MESSAGES/blur-my-shell@aunetx.mo index 7a24fdd..38b4c47 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/uk/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/uk/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/vi/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/vi/LC_MESSAGES/blur-my-shell@aunetx.mo index 5364ed4..38be0d0 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/vi/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/vi/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/zh_Hans/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/zh_Hans/LC_MESSAGES/blur-my-shell@aunetx.mo index ad6d992..19e2cfb 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/zh_Hans/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/zh_Hans/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/zh_TW/LC_MESSAGES/blur-my-shell@aunetx.mo b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/zh_TW/LC_MESSAGES/blur-my-shell@aunetx.mo index 4d7557c..c18174d 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/zh_TW/LC_MESSAGES/blur-my-shell@aunetx.mo and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/locale/zh_TW/LC_MESSAGES/blur-my-shell@aunetx.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/metadata.json b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/metadata.json index 497ccca..582a13f 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/metadata.json +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/metadata.json @@ -1,6 +1,6 @@ { "_generated": "Generated by SweetTooth, do not edit", - "description": "Adds a blur look to different parts of the GNOME Shell, including the top panel, dash and overview.\n\nYou can support my work by sponsoring me on:\n- github: https://github.com/sponsors/aunetx\n- ko-fi: https://ko-fi.com/aunetx\n\nNote: if the extension shows an error after updating, please make sure to restart your session to see if it persists. This is due to a bug in gnome shell, which I can't fix by myself.", + "description": "Adds a blur look to different parts of the GNOME Shell, including the top panel, dash and overview.\n\nYou can support my work by sponsoring me on:\n- github: https://github.com/sponsors/aunetx\n- ko-fi: https://ko-fi.com/aunetx\n\nIf you use Ubuntu, you may want to change the radius of the corner effect for Dash-to-Dock in preferences, else you may see unpleasantly mixed radii in your dock.\n\nNote: if the extension shows an error after updating, please make sure to restart your session to see if it persists. This is due to a bug in gnome shell, which I can't fix by myself.", "donations": { "github": "aunetx", "kofi": "aunetx" @@ -16,9 +16,10 @@ ], "settings-schema": "org.gnome.shell.extensions.blur-my-shell", "shell-version": [ - "46" + "46", + "47" ], "url": "https://github.com/aunetx/blur-my-shell", "uuid": "blur-my-shell@aunetx", - "version": 59 + "version": 67 } \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/applications.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/applications.js index 6bac74c..620d59e 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/applications.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/applications.js @@ -3,7 +3,7 @@ import GLib from 'gi://GLib'; import GObject from 'gi://GObject'; import Gio from 'gi://Gio'; -import { WindowRow } from './window_row.js'; +import { ApplicationRow } from './applications_management/application_row.js'; const make_array = prefs_group => { @@ -30,8 +30,10 @@ export const Applications = GObject.registerClass({ Template: GLib.uri_resolve_relative(import.meta.url, '../ui/applications.ui', GLib.UriFlags.NONE), InternalChildren: [ 'blur', - 'customize', + 'sigma', + 'brightness', 'opacity', + 'dynamic_opacity', 'blur_on_overview', 'enable_all', 'whitelist', @@ -54,6 +56,10 @@ export const Applications = GObject.registerClass({ 'opacity', this._opacity, 'value', Gio.SettingsBindFlags.DEFAULT ); + this.preferences.applications.settings.bind( + 'dynamic-opacity', this._dynamic_opacity, 'active', + Gio.SettingsBindFlags.DEFAULT + ); this.preferences.applications.settings.bind( 'blur-on-overview', this._blur_on_overview, 'active', Gio.SettingsBindFlags.DEFAULT @@ -62,8 +68,14 @@ export const Applications = GObject.registerClass({ 'enable-all', this._enable_all, 'active', Gio.SettingsBindFlags.DEFAULT ); - - this._customize.connect_to(this.preferences, this.preferences.applications, false); + this.preferences.applications.settings.bind( + 'sigma', this._sigma, 'value', + Gio.SettingsBindFlags.DEFAULT + ); + this.preferences.applications.settings.bind( + 'brightness', this._brightness, 'value', + Gio.SettingsBindFlags.DEFAULT + ); // connect 'enable all' button to whitelist/blacklist visibility this._enable_all.bind_property( @@ -82,16 +94,16 @@ export const Applications = GObject.registerClass({ // listen to app row addition this._add_window_whitelist.connect('clicked', - _ => this.add_to_whitelist() + () => this.add_to_whitelist() ); this._add_window_blacklist.connect('clicked', - _ => this.add_to_blacklist() + () => this.add_to_blacklist() ); // add initial applications this.add_widgets_from_lists(); - this.preferences.connect('reset', _ => { + this.preferences.connect('reset', () => { this.remove_all_widgets(); this.add_widgets_from_lists(); }); @@ -137,12 +149,12 @@ export const Applications = GObject.registerClass({ } add_to_whitelist(app_name = null) { - let window_row = new WindowRow('whitelist', this, app_name); + let window_row = new ApplicationRow('whitelist', this, app_name); this._whitelist.add(window_row); } add_to_blacklist(app_name = null) { - let window_row = new WindowRow('blacklist', this, app_name); + let window_row = new ApplicationRow('blacklist', this, app_name); this._blacklist.add(window_row); } diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/window_row.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/applications_management/application_row.js similarity index 83% rename from gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/window_row.js rename to gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/applications_management/application_row.js index fd150e0..4af3bf8 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/window_row.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/applications_management/application_row.js @@ -4,19 +4,19 @@ import GObject from 'gi://GObject'; import Gio from 'gi://Gio'; import Gtk from 'gi://Gtk'; -import { pick, on_picking, on_picked } from '../dbus/client.js'; +import { pick, on_picking, on_picked } from '../../dbus/client.js'; -export const WindowRow = GObject.registerClass({ - GTypeName: 'WindowRow', - Template: GLib.uri_resolve_relative(import.meta.url, '../ui/window-row.ui', GLib.UriFlags.NONE), +export const ApplicationRow = GObject.registerClass({ + GTypeName: 'ApplicationRow', + Template: GLib.uri_resolve_relative(import.meta.url, '../../ui/application-row.ui', GLib.UriFlags.NONE), InternalChildren: [ 'window_picker', 'window_class', 'picking_failure_toast', 'window_not_found_toast' ], -}, class WindowRow extends Adw.ExpanderRow { +}, class ApplicationRow extends Adw.ExpanderRow { constructor(list, app_page, app_name) { super({}); this._list = list; @@ -25,7 +25,7 @@ export const WindowRow = GObject.registerClass({ // add a 'remove' button before the text let action_row = this.child.get_first_child().get_first_child(); let remove_button = new Gtk.Button({ - 'icon-name': 'remove-window-symbolic', + 'icon-name': 'remove-row-symbolic', 'width-request': 38, 'height-request': 38, 'margin-top': 6, @@ -36,7 +36,7 @@ export const WindowRow = GObject.registerClass({ action_row.add_prefix(remove_button); // connect the button to the whitelist / blacklist removal - remove_button.connect('clicked', _ => this._remove_row()); + remove_button.connect('clicked', () => this._remove_row()); // bind row title to text buffer this._window_class.buffer.bind_property( @@ -54,11 +54,11 @@ export const WindowRow = GObject.registerClass({ } // pick a window when the picker button is clicked - this._window_picker.connect('clicked', _ => this._do_pick_window()); + this._window_picker.connect('clicked', () => this._do_pick_window()); // update list on text buffer change this._window_class.connect('changed', - _ => this._update_rows_titles() + () => this._update_rows_titles() ); } @@ -74,7 +74,7 @@ export const WindowRow = GObject.registerClass({ // a mechanism to know if the extension is listening correcly let has_responded = false; let should_take_answer = true; - setTimeout(_ => { + setTimeout(() => { if (!has_responded) { // show toast about failure this._app_page._preferences_window.add_toast( @@ -90,7 +90,7 @@ export const WindowRow = GObject.registerClass({ } }, 250); - on_picking(_ => + on_picking(() => has_responded = true ); diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/customize_row.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/customize_row.js deleted file mode 100644 index 0115966..0000000 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/customize_row.js +++ /dev/null @@ -1,163 +0,0 @@ -import Adw from 'gi://Adw'; -import GLib from 'gi://GLib'; -import GObject from 'gi://GObject'; -import Gio from 'gi://Gio'; -import Gtk from 'gi://Gtk'; - - -/// Given a component (described by its preferences node), a gschema key and -/// a Gtk.ColorButton, binds everything transparently. -let bind_color = function (component, key, widget) { - let property_name = key.replaceAll('-', '_').toUpperCase(); - - let parse_color = _ => { - let [r, g, b, a] = component[property_name]; - let w = widget.rgba; - w.red = r; - w.green = g; - w.blue = b; - w.alpha = a; - widget.rgba = w; - }; - component.settings.connect('changed::' + key, parse_color); - - widget.connect('color-set', _ => { - let c = widget.rgba; - component[property_name] = [c.red, c.green, c.blue, c.alpha]; - }); - - parse_color(); -}; - -export const CustomizeRow = GObject.registerClass({ - GTypeName: 'CustomizeRow', - Template: GLib.uri_resolve_relative(import.meta.url, '../ui/customize-row.ui', GLib.UriFlags.NONE), - InternalChildren: [ - 'sigma', - 'brightness', - 'color', - 'color_row', - 'noise_amount', - 'noise_amount_row', - 'noise_lightness', - 'noise_lightness_row', - 'noise_color_notice' - ], -}, class CustomizeRow extends Adw.ExpanderRow { - /// Makes the required connections between the widgets and the preferences. - /// - /// This function may be bound to another object than CustomizeRow, if we - /// are using it for the General page; some things will then change (no - /// expansion row, and no notice) - /// - /// The color_and_noise parameter is either a boolean (true by default) or - /// a widget; and permits selecting weather or not we want to show the color - /// and noise buttons to the user. If it is a widget, it means we need to - /// dynamically update their visibility, according to the widget's state. - connect_to(settings, component_settings, color_and_noise = true) { - let s = component_settings.settings; - - // is not fired if in General page - if (this instanceof CustomizeRow) - // bind the customize button - s.bind( - 'customize', this, 'enable-expansion', - Gio.SettingsBindFlags.DEFAULT - ); - - // bind sigma and brightness - s.bind( - 'sigma', this._sigma, 'value', - Gio.SettingsBindFlags.DEFAULT - ); - s.bind( - 'brightness', this._brightness, 'value', - Gio.SettingsBindFlags.DEFAULT - ); - - // bind the color button - bind_color(component_settings, 'color', this._color); - - // bind noise sliders - s.bind( - 'noise-amount', this._noise_amount, 'value', - Gio.SettingsBindFlags.DEFAULT - ); - s.bind( - 'noise-lightness', this._noise_lightness, 'value', - Gio.SettingsBindFlags.DEFAULT - ); - - // color_and_noise is either a boolean or a widget, if true, or it is a - // widget, this will appropriately show the required preferences about - // setting the color and noise - if (color_and_noise) { - // if we gave the static_blur widget, we are dealing with the panel, - // and binding it to enable/disable the required components when - // switching between static and dynamic blur - if (color_and_noise instanceof Gtk.Switch) { - // bind its state to dynamically toggle the notice and rows - color_and_noise.bind_property( - 'active', this._color_row, 'visible', - GObject.BindingFlags.SYNC_CREATE - ); - color_and_noise.bind_property( - 'active', this._noise_amount_row, 'visible', - GObject.BindingFlags.SYNC_CREATE - ); - color_and_noise.bind_property( - 'active', this._noise_lightness_row, 'visible', - GObject.BindingFlags.SYNC_CREATE - ); - color_and_noise.bind_property( - 'active', this._noise_color_notice, 'visible', - GObject.BindingFlags.INVERT_BOOLEAN - ); - - // only way to get the correct state when first opening the - // window... - setTimeout(_ => { - let is_visible = color_and_noise.active; - this._color_row.visible = is_visible; - this._noise_amount_row.visible = is_visible; - this._noise_lightness_row.visible = is_visible; - this._noise_color_notice.visible = !is_visible; - }, 10); - } - - // if in General page, there is no notice at all - if (this instanceof CustomizeRow) { - // disable the notice - this._noise_color_notice.visible = false; - } - } else { - // enable the notice and disable color and noise preferences - this._color_row.visible = false; - this._noise_amount_row.visible = false; - this._noise_lightness_row.visible = false; - this._noise_color_notice.visible = true; - } - - // now we bind the color-and-noise preference to the sensitivity of the - // associated widgets, this will grey them out if the user choose not to - // have color and noise enabled - // note: I would love to bind to the visibility instead, but this part - // is already dirty enough, it would look like I obfuscate my code - // intentionally... (I am not) - settings.settings.bind( - 'color-and-noise', - this._color_row, 'sensitive', - Gio.SettingsBindFlags.DEFAULT - ); - settings.settings.bind( - 'color-and-noise', - this._noise_amount_row, 'sensitive', - Gio.SettingsBindFlags.DEFAULT - ); - settings.settings.bind( - 'color-and-noise', - this._noise_lightness_row, 'sensitive', - Gio.SettingsBindFlags.DEFAULT - ); - }; -}); diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/dash.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/dash.js index 3a42ff2..aae3768 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/dash.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/dash.js @@ -9,31 +9,49 @@ export const Dash = GObject.registerClass({ Template: GLib.uri_resolve_relative(import.meta.url, '../ui/dash.ui', GLib.UriFlags.NONE), InternalChildren: [ 'blur', - 'customize', - 'static_blur', - 'corner_radius', + 'pipeline_choose_row', + 'mode_static', + 'mode_dynamic', + 'sigma_row', + 'sigma', + 'brightness_row', + 'brightness', 'override_background', 'style_dash_to_dock', 'unblur_in_overview' ], }, class Dash extends Adw.PreferencesPage { - constructor(preferences) { + constructor(preferences, pipelines_manager, pipelines_page) { super({}); this.preferences = preferences; + this.pipelines_manager = pipelines_manager; + this.pipelines_page = pipelines_page; this.preferences.dash_to_dock.settings.bind( 'blur', this._blur, 'active', Gio.SettingsBindFlags.DEFAULT ); + + this._pipeline_choose_row.initialize( + this.preferences.dash_to_dock, this.pipelines_manager, this.pipelines_page + ); + + this.change_blur_mode(this.preferences.dash_to_dock.STATIC_BLUR, true); + + this._mode_static.connect('toggled', + () => this.preferences.dash_to_dock.STATIC_BLUR = this._mode_static.active + ); + this.preferences.dash_to_dock.STATIC_BLUR_changed( + () => this.change_blur_mode(this.preferences.dash_to_dock.STATIC_BLUR, false) + ); + this.preferences.dash_to_dock.settings.bind( - 'static-blur', - this._static_blur, 'active', + 'sigma', this._sigma, 'value', Gio.SettingsBindFlags.DEFAULT ); this.preferences.dash_to_dock.settings.bind( - 'corner-radius', - this._corner_radius, 'value', + 'brightness', this._brightness, 'value', Gio.SettingsBindFlags.DEFAULT ); this.preferences.dash_to_dock.settings.bind( @@ -49,7 +67,15 @@ export const Dash = GObject.registerClass({ 'unblur-in-overview', this._unblur_in_overview, 'active', Gio.SettingsBindFlags.DEFAULT ); + } - this._customize.connect_to(this.preferences, this.preferences.dash_to_dock, false); + change_blur_mode(is_static_blur, first_run) { + this._mode_static.set_active(is_static_blur); + if (first_run) + this._mode_dynamic.set_active(!is_static_blur); + + this._pipeline_choose_row.set_visible(is_static_blur); + this._sigma_row.set_visible(!is_static_blur); + this._brightness_row.set_visible(!is_static_blur); } }); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/general.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/general.js deleted file mode 100644 index 3067a2d..0000000 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/general.js +++ /dev/null @@ -1,49 +0,0 @@ -import Adw from 'gi://Adw'; -import GLib from 'gi://GLib'; -import GObject from 'gi://GObject'; -import Gio from 'gi://Gio'; - -import { CustomizeRow } from './customize_row.js'; - - -export const General = GObject.registerClass({ - GTypeName: 'General', - Template: GLib.uri_resolve_relative(import.meta.url, '../ui/general.ui', GLib.UriFlags.NONE), - InternalChildren: [ - 'sigma', - 'brightness', - 'color', - 'color_row', - 'noise_amount', - 'noise_amount_row', - 'noise_lightness', - 'noise_lightness_row', - 'color_and_noise', - 'hack_level', - 'debug', - 'reset' - ], -}, class General extends Adw.PreferencesPage { - constructor(preferences) { - super({}); - - this.preferences = preferences; - - CustomizeRow.prototype.connect_to.call(this, preferences, preferences); - - this.preferences.settings.bind( - 'color-and-noise', this._color_and_noise, 'active', - Gio.SettingsBindFlags.DEFAULT - ); - this.preferences.settings.bind( - 'hacks-level', this._hack_level, 'selected', - Gio.SettingsBindFlags.DEFAULT - ); - this.preferences.settings.bind( - 'debug', this._debug, 'active', - Gio.SettingsBindFlags.DEFAULT - ); - - this._reset.connect('clicked', _ => this.preferences.reset()); - } -}); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/menu.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/menu.js index 5ea2f3f..899fdcf 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/menu.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/menu.js @@ -25,7 +25,8 @@ function addMenuToHeader(window, builder) { const pages_stack = page.get_parent(); // AdwViewStack const content_stack = pages_stack.get_parent().get_parent(); // GtkStack const preferences = content_stack.get_parent(); // GtkBox - const headerbar = preferences.get_first_child(); // AdwHeaderBar + const headerbar = preferences.get_first_child().get_next_sibling() + .get_first_child().get_first_child().get_first_child(); // AdwHeaderBar headerbar.pack_start(builder.get_object('info_menu')); // setup menu actions @@ -60,7 +61,7 @@ function addMenuToHeader(window, builder) { let act = new Gio.SimpleAction({ name: action.name }); act.connect( 'activate', - _ => Gtk.show_uri(window, action.link, Gdk.CURRENT_TIME) + () => Gtk.show_uri(window, action.link, Gdk.CURRENT_TIME) ); actionGroup.add_action(act); }); diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/other.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/other.js index d01f541..0fac364 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/other.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/other.js @@ -9,41 +9,78 @@ export const Other = GObject.registerClass({ Template: GLib.uri_resolve_relative(import.meta.url, '../ui/other.ui', GLib.UriFlags.NONE), InternalChildren: [ 'lockscreen_blur', - 'lockscreen_customize', + 'lockscreen_pipeline_choose_row', 'screenshot_blur', - 'screenshot_customize', + 'screenshot_pipeline_choose_row', 'window_list_blur', - 'window_list_customize', + 'window_list_sigma', + 'window_list_brightness', + + 'coverflow_alt_tab_blur', + 'coverflow_alt_tab_pipeline_choose_row', + + 'hack_level', + 'debug', + 'reset' ], }, class Overview extends Adw.PreferencesPage { - constructor(preferences) { + constructor(preferences, pipelines_manager, pipelines_page) { super({}); this.preferences = preferences; + this.pipelines_manager = pipelines_manager; + this.pipelines_page = pipelines_page; this.preferences.lockscreen.settings.bind( 'blur', this._lockscreen_blur, 'active', Gio.SettingsBindFlags.DEFAULT ); - this._lockscreen_customize.connect_to(this.preferences, this.preferences.lockscreen); + this._lockscreen_pipeline_choose_row.initialize( + this.preferences.lockscreen, this.pipelines_manager, this.pipelines_page + ); this.preferences.screenshot.settings.bind( 'blur', this._screenshot_blur, 'active', Gio.SettingsBindFlags.DEFAULT ); - this._screenshot_customize.connect_to(this.preferences, this.preferences.screenshot); + this._screenshot_pipeline_choose_row.initialize( + this.preferences.screenshot, this.pipelines_manager, this.pipelines_page + ); this.preferences.window_list.settings.bind( 'blur', this._window_list_blur, 'active', Gio.SettingsBindFlags.DEFAULT ); - - this._window_list_customize.connect_to( - this.preferences, this.preferences.window_list, false + this.preferences.window_list.settings.bind( + 'sigma', this._window_list_sigma, 'value', + Gio.SettingsBindFlags.DEFAULT ); + this.preferences.window_list.settings.bind( + 'brightness', this._window_list_brightness, 'value', + Gio.SettingsBindFlags.DEFAULT + ); + + this.preferences.coverflow_alt_tab.settings.bind( + 'blur', this._coverflow_alt_tab_blur, 'active', + Gio.SettingsBindFlags.DEFAULT + ); + this._coverflow_alt_tab_pipeline_choose_row.initialize( + this.preferences.coverflow_alt_tab, this.pipelines_manager, this.pipelines_page + ); + + this.preferences.settings.bind( + 'hacks-level', this._hack_level, 'selected', + Gio.SettingsBindFlags.DEFAULT + ); + this.preferences.settings.bind( + 'debug', this._debug, 'active', + Gio.SettingsBindFlags.DEFAULT + ); + + this._reset.connect('clicked', () => this.preferences.reset()); } }); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/overview.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/overview.js index 2560e3b..f6fe592 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/overview.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/overview.js @@ -9,39 +9,51 @@ export const Overview = GObject.registerClass({ Template: GLib.uri_resolve_relative(import.meta.url, '../ui/overview.ui', GLib.UriFlags.NONE), InternalChildren: [ 'overview_blur', - 'overview_customize', + 'pipeline_choose_row', 'overview_style_components', 'appfolder_blur', - 'appfolder_customize', + 'appfolder_sigma', + 'appfolder_brightness', 'appfolder_style_dialogs' ], }, class Overview extends Adw.PreferencesPage { - constructor(preferences) { + constructor(preferences, pipelines_manager, pipelines_page) { super({}); this.preferences = preferences; + this.pipelines_manager = pipelines_manager; + this.pipelines_page = pipelines_page; this.preferences.overview.settings.bind( 'blur', this._overview_blur, 'active', Gio.SettingsBindFlags.DEFAULT ); + + this._pipeline_choose_row.initialize( + this.preferences.overview, this.pipelines_manager, this.pipelines_page + ); + this.preferences.overview.settings.bind( 'style-components', this._overview_style_components, 'selected', Gio.SettingsBindFlags.DEFAULT ); - this._overview_customize.connect_to(this.preferences, this.preferences.overview); - this.preferences.appfolder.settings.bind( 'blur', this._appfolder_blur, 'active', Gio.SettingsBindFlags.DEFAULT ); + this.preferences.appfolder.settings.bind( + 'sigma', this._appfolder_sigma, 'value', + Gio.SettingsBindFlags.DEFAULT + ); + this.preferences.appfolder.settings.bind( + 'brightness', this._appfolder_brightness, 'value', + Gio.SettingsBindFlags.DEFAULT + ); this.preferences.appfolder.settings.bind( 'style-dialogs', this._appfolder_style_dialogs, 'selected', Gio.SettingsBindFlags.DEFAULT ); - - this._appfolder_customize.connect_to(this.preferences, this.preferences.appfolder, false); } }); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/panel.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/panel.js index 6243f1f..c49f323 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/panel.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/panel.js @@ -9,8 +9,13 @@ export const Panel = GObject.registerClass({ Template: GLib.uri_resolve_relative(import.meta.url, '../ui/panel.ui', GLib.UriFlags.NONE), InternalChildren: [ 'blur', - 'customize', - 'static_blur', + 'pipeline_choose_row', + 'mode_static', + 'mode_dynamic', + 'sigma_row', + 'sigma', + 'brightness_row', + 'brightness', 'unblur_in_overview', 'force_light_text', 'override_background', @@ -20,17 +25,37 @@ export const Panel = GObject.registerClass({ 'dtp_blur_original_panel' ], }, class Panel extends Adw.PreferencesPage { - constructor(preferences) { + constructor(preferences, pipelines_manager, pipelines_page) { super({}); this.preferences = preferences; + this.pipelines_manager = pipelines_manager; + this.pipelines_page = pipelines_page; this.preferences.panel.settings.bind( 'blur', this._blur, 'active', Gio.SettingsBindFlags.DEFAULT ); + + this._pipeline_choose_row.initialize( + this.preferences.panel, this.pipelines_manager, this.pipelines_page + ); + + this.change_blur_mode(this.preferences.panel.STATIC_BLUR, true); + + this._mode_static.connect('toggled', + () => this.preferences.panel.STATIC_BLUR = this._mode_static.active + ); + this.preferences.panel.STATIC_BLUR_changed( + () => this.change_blur_mode(this.preferences.panel.STATIC_BLUR, false) + ); + this.preferences.panel.settings.bind( - 'static-blur', this._static_blur, 'active', + 'sigma', this._sigma, 'value', + Gio.SettingsBindFlags.DEFAULT + ); + this.preferences.panel.settings.bind( + 'brightness', this._brightness, 'value', Gio.SettingsBindFlags.DEFAULT ); this.preferences.panel.settings.bind( @@ -55,9 +80,6 @@ export const Panel = GObject.registerClass({ this._override_background_dynamically, 'active', Gio.SettingsBindFlags.DEFAULT ); - - this._customize.connect_to(this.preferences, this.preferences.panel, this._static_blur); - this.preferences.hidetopbar.settings.bind( 'compatibility', this._hidetopbar_compatibility, 'active', Gio.SettingsBindFlags.DEFAULT @@ -67,4 +89,14 @@ export const Panel = GObject.registerClass({ Gio.SettingsBindFlags.DEFAULT ); } + + change_blur_mode(is_static_blur, first_run) { + this._mode_static.set_active(is_static_blur); + if (first_run) + this._mode_dynamic.set_active(!is_static_blur); + + this._pipeline_choose_row.set_visible(is_static_blur); + this._sigma_row.set_visible(!is_static_blur); + this._brightness_row.set_visible(!is_static_blur); + } }); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/pipelines.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/pipelines.js new file mode 100644 index 0000000..158ea9a --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/pipelines.js @@ -0,0 +1,98 @@ +import Adw from 'gi://Adw'; +import GLib from 'gi://GLib'; +import GObject from 'gi://GObject'; +import { gettext as _ } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'; + +import { PipelineGroup } from './pipelines_management/pipeline_group.js'; +import { EffectsDialog } from './pipelines_management/effects_dialog.js'; + + +export const Pipelines = GObject.registerClass({ + GTypeName: 'Pipelines', + Template: GLib.uri_resolve_relative(import.meta.url, '../ui/pipelines.ui', GLib.UriFlags.NONE), + InternalChildren: [ + 'add_pipeline' + ], +}, class Pipelines extends Adw.PreferencesPage { + constructor(preferences, pipelines_manager, window) { + super({}); + + this.preferences = preferences; + this.pipelines_manager = pipelines_manager; + this.window = window; + + this.pipelines_map = new Map; + + for (let pipeline_id in this.pipelines_manager.pipelines) + this.add_pipeline(pipeline_id, false); + + this.preferences.connect('reset', _ => { + this.pipelines_map.forEach((_infos, pid) => this.remove_pipeline(pid)); + for (let pipeline_id in this.pipelines_manager.pipelines) + this.add_pipeline(pipeline_id, false); + }); + + this._add_pipeline.connect( + "clicked", + () => this.pipelines_manager.create_pipeline(_("New pipeline")) + ); + + this.pipelines_manager.connect( + "pipeline-created", + (_obj, id, _pipeline) => this.add_pipeline(id, true) + ); + } + + add_pipeline(pipeline_id, scroll_to_bottom) { + let pipeline = this.pipelines_manager.pipelines[pipeline_id]; + let pipeline_group = new PipelineGroup( + this.pipelines_manager, pipeline_id, pipeline, this + ); + + let pipeline_destroyed_id = this.pipelines_manager.connect( + pipeline_id + "::pipeline-destroyed", + () => this.remove_pipeline(pipeline_id) + ); + + let pipeline_renamed_id = this.pipelines_manager.connect( + pipeline_id + "::pipeline-renamed", + (_obj, name) => this.rename_pipeline(pipeline_id, name) + ); + + this.pipelines_map.set(pipeline_id, { + pipeline_group, pipeline_destroyed_id, pipeline_renamed_id + }); + + this.add(pipeline_group); + + // scroll to the bottom of the page + if (scroll_to_bottom) { + this.window.set_visible_page(this); + setTimeout(() => { + const scroll_adjustment = this.get_first_child().get_vadjustment(); + scroll_adjustment.value = scroll_adjustment.get_upper(); + }, 10); + pipeline_group._title.grab_focus(); + } + } + + remove_pipeline(pipeline_id) { + let pipeline_infos = this.pipelines_map.get(pipeline_id); + if (pipeline_infos) { + this.pipelines_manager.disconnect(pipeline_infos.pipeline_destroyed_id); + this.remove(pipeline_infos.pipeline_group); + this.pipelines_map.delete(pipeline_id); + } + } + + rename_pipeline(pipeline_id, name) { + let pipeline_infos = this.pipelines_map.get(pipeline_id); + if (pipeline_infos) + pipeline_infos.pipeline_group.set_title(name.length > 0 ? name : " "); + } + + open_effects_dialog(pipeline_id) { + let dialog = new EffectsDialog(this.pipelines_manager, pipeline_id); + dialog.present(this.window); + } +}); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/pipelines_management/effect_row.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/pipelines_management/effect_row.js new file mode 100644 index 0000000..130edfd --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/pipelines_management/effect_row.js @@ -0,0 +1,222 @@ +import Adw from 'gi://Adw'; +import GObject from 'gi://GObject'; +import Gtk from 'gi://Gtk'; +import { gettext as _ } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'; + +import { get_supported_effects } from '../../effects/effects.js'; + + +export const EffectRow = GObject.registerClass({ + GTypeName: 'EffectRow', + InternalChildren: [], +}, class EffectRow extends Adw.ExpanderRow { + constructor(effect, effects_dialog) { + super({}); + + this.SUPPORTED_EFFECTS = get_supported_effects(_); + + this.effect = effect; + this.effects_dialog = effects_dialog; + this.pipeline_id = effects_dialog.pipeline_id; + this.pipelines_manager = effects_dialog.pipelines_manager; + + if (effect.type in this.SUPPORTED_EFFECTS) { + this.set_title(this.SUPPORTED_EFFECTS[effect.type].name); + this.set_subtitle(this.SUPPORTED_EFFECTS[effect.type].description); + this.populate_options(); + } + else { + this._warn(`could not assign effect ${effect.type} to its correct name`); + this.set_title(effect.type); + } + + let prefix_bin = new Gtk.Box({ + spacing: 6 + }); + this.add_prefix(prefix_bin); + + let move_bin = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + 'width-request': 38, + 'height-request': 38, + 'margin-top': 6, + 'margin-bottom': 6 + }); + prefix_bin.append(move_bin); + move_bin.add_css_class('linked'); + + this._move_up_button = new Gtk.Button({ + 'icon-name': 'go-up-symbolic', + 'width-request': 38, + 'height-request': 19 + }); + this._move_down_button = new Gtk.Button({ + 'icon-name': 'go-down-symbolic', + 'width-request': 38, + 'height-request': 19 + }); + this._move_up_button.add_css_class('flat'); + this._move_down_button.add_css_class('flat'); + move_bin.append(this._move_up_button); + move_bin.append(this._move_down_button); + + this._move_up_button.connect('clicked', () => effects_dialog.move_row_by(this, -1)); + this._move_down_button.connect('clicked', () => effects_dialog.move_row_by(this, +1)); + + let remove_button = new Gtk.Button({ + 'icon-name': 'remove-row-symbolic', + 'width-request': 38, + 'height-request': 38, + 'margin-top': 6, + 'margin-bottom': 6, + 'valign': Gtk.Align.CENTER + }); + prefix_bin.append(remove_button); + remove_button.add_css_class('destructive-action'); + + remove_button.connect('clicked', () => effects_dialog.remove_row(this)); + } + + populate_options() { + const editable_params = this.SUPPORTED_EFFECTS[this.effect.type].editable_params; + + if (Object.keys(editable_params).length == 0) + this.enable_expansion = false; + + for (const param_key in editable_params) { + let param = editable_params[param_key]; + let row; + switch (param.type) { + case "integer": + row = new Adw.SpinRow({ + adjustment: new Gtk.Adjustment({ + lower: param.min, + upper: param.max, + step_increment: param.increment + }) + }); + row.adjustment.set_value(this.get_effect_param(param_key)); + row.adjustment.connect( + 'value-changed', () => this.set_effect_param(param_key, row.adjustment.value) + ); + break; + + case "float": + row = new Adw.ActionRow; + let scale = new Gtk.Scale({ + valign: Gtk.Align.CENTER, + hexpand: true, + width_request: 200, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT, + digits: param.digits, + adjustment: new Gtk.Adjustment({ + lower: param.min, + upper: param.max, + step_increment: param.increment, + page_increment: param.big_increment + }) + }); + // TODO check if it's a good idea to set the default parameter, as the "good" + // value really change depending on the user wallpaper... if so, do for dynamic + // blur too + scale.add_mark( + this.get_default_effect_param(param_key), Gtk.PositionType.BOTTOM, null + ); + row.add_suffix(scale); + scale.adjustment.set_value(this.get_effect_param(param_key)); + scale.adjustment.connect( + 'value-changed', () => this.set_effect_param(param_key, scale.adjustment.value) + ); + break; + + case "boolean": + row = new Adw.SwitchRow; + row.set_active(this.get_effect_param(param_key)); + row.connect( + 'notify::active', () => this.set_effect_param(param_key, row.active) + ); + break; + + case "dropdown": + row = new Adw.ComboRow({ model: new Gtk.StringList }); + param.options.forEach(option => row.model.append(option)); + row.selected = this.get_effect_param(param_key); + row.connect( + 'notify::selected', () => this.set_effect_param(param_key, row.selected) + ); + break; + + case "rgba": + row = new Adw.ActionRow; + let color_button = new Gtk.ColorButton({ + valign: Gtk.Align.CENTER, + width_request: 75, + height_request: 45, + show_editor: true, + use_alpha: true + }); + row.add_suffix(color_button); + // set original color + let c = color_button.get_rgba().copy(); + [c.red, c.green, c.blue, c.alpha] = this.get_effect_param(param_key); + color_button.set_rgba(c); + // update on on 'color-set' + color_button.connect( + 'color-set', () => { + let c = color_button.get_rgba(); + this.set_effect_param(param_key, [c.red, c.green, c.blue, c.alpha]); + } + ); + break; + + default: + row = new Adw.ActionRow; + break; + } + row.set_title(param.name); + row.set_subtitle(param.description); + this.add_row(row); + } + } + + get_effect_param(key) { + let effects = this.pipelines_manager.pipelines[this.pipeline_id].effects; + const gsettings_effect = effects.find(e => e.id == this.effect.id); + + if ('params' in gsettings_effect && key in gsettings_effect.params) + return gsettings_effect.params[key]; + else + return this.get_default_effect_param(key); + } + + get_default_effect_param(key) { + return this.SUPPORTED_EFFECTS[this.effect.type].class.default_params[key]; + } + + set_effect_param(key, value) { + // we must pay attention not to change the effects in the pipelines manager before updating + // it in gsettings, else it won't be updated (or every effect will be) + let effects = this.pipelines_manager.pipelines[this.pipeline_id].effects; + const effect_index = effects.findIndex(e => e.id == this.effect.id); + + if (effect_index >= 0) { + effects[effect_index] = { + ...this.effect, params: { ...this.effect.params } + }; + effects[effect_index].params[key] = value; + this.effect = effects[effect_index]; + } + else + this._warn(`effect not found when setting key ${key}`); + + this.pipelines_manager.update_pipeline_effects(this.pipeline_id, effects, false); + } + + _warn(str) { + console.warn( + `[Blur my Shell > effect row] pipeline '${this.pipeline_id}',` + + ` effect '${this.effect.id}': ${str}` + ); + } +}); diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/pipelines_management/effects_dialog.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/pipelines_management/effects_dialog.js new file mode 100644 index 0000000..222a92e --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/pipelines_management/effects_dialog.js @@ -0,0 +1,174 @@ +import Adw from 'gi://Adw'; +import GLib from 'gi://GLib'; +import GObject from 'gi://GObject'; +import Gtk from 'gi://Gtk'; +import Gio from 'gi://Gio'; +import { gettext as _ } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'; + +import { EffectRow } from './effect_row.js'; +import { get_effects_groups, get_supported_effects } from '../../effects/effects.js'; + +export const EffectsDialog = GObject.registerClass({ + GTypeName: 'EffectsDialog', + Template: GLib.uri_resolve_relative(import.meta.url, '../../ui/effects-dialog.ui', GLib.UriFlags.NONE), + InternalChildren: [ + "add_effect", + "add_effect_alt_menu", + "effects_list" + ], +}, class EffectsDialog extends Adw.PreferencesDialog { + constructor(pipelines_manager, pipeline_id) { + super({}); + + this.EFFECTS_GROUPS = get_effects_groups(_); + this.SUPPORTED_EFFECTS = get_supported_effects(_); + + this.pipelines_manager = pipelines_manager; + this.pipeline_id = pipeline_id; + + let pipeline = pipelines_manager.pipelines[pipeline_id]; + + this.set_title(pipeline.name.length > 0 ? _(`Effects for "${pipeline.name}"`) : _("Effects")); + + pipeline.effects.forEach(effect => { + const effect_row = new EffectRow(effect, this); + this._effects_list.add(effect_row); + this.update_rows_insensitive_mover(effect_row); + }); + + // setup advanced effects chooser action + this.show_advanced_effects = false; + let action_group = new Gio.SimpleActionGroup(); + this.insert_action_group('effects-dialog', action_group); + let advanced_effects_action = Gio.SimpleAction.new_stateful( + 'advanced-effects-bool', + null, + GLib.Variant.new_boolean(this.show_advanced_effects) + ); + advanced_effects_action.connect( + 'change-state', + (_, state) => { + this.show_advanced_effects = state.get_boolean(); + this.build_effects_chooser(); + advanced_effects_action.set_state(state); + } + ); + action_group.add_action(advanced_effects_action); + + this.build_effects_chooser(); + this._add_effect.connect('clicked', () => this.effects_chooser_dialog.present(this)); + } + + build_effects_chooser() { + this.effects_chooser_dialog = new Adw.Dialog({ + presentation_mode: Adw.DialogPresentationMode.BOTTOM_SHEET, + content_width: 450 + }); + + let page = new Adw.PreferencesPage; + this.effects_chooser_dialog.set_child(page); + + for (const effects_group in this.EFFECTS_GROUPS) { + const group_infos = this.EFFECTS_GROUPS[effects_group]; + + let group = new Adw.PreferencesGroup({ + title: group_infos.name + }); + page.add(group); + + for (const effect_type of group_infos.contains) { + if (!(effect_type in this.SUPPORTED_EFFECTS)) + continue; + + if (!this.show_advanced_effects && this.SUPPORTED_EFFECTS[effect_type].is_advanced) + continue; + + let action_row = new Adw.ActionRow({ + title: this.SUPPORTED_EFFECTS[effect_type].name, + subtitle: this.SUPPORTED_EFFECTS[effect_type].description + }); + let select_button = new Gtk.Button({ + 'icon-name': 'select-row-symbolic', + 'width-request': 38, + 'height-request': 38, + 'margin-top': 6, + 'margin-bottom': 6 + }); + group.add(action_row); + + select_button.add_css_class('flat'); + action_row.add_suffix(select_button); + action_row.set_activatable_widget(select_button); + select_button.connect('clicked', () => { + this.append_effect(effect_type); + this.effects_chooser_dialog.close(); + }); + } + } + } + + append_effect(effect_type) { + const effect = { + type: effect_type, id: "effect_" + ("" + Math.random()).slice(2, 16) + }; + this.pipelines_manager.update_pipeline_effects( + this.pipeline_id, + [...this.pipelines_manager.pipelines[this.pipeline_id].effects, effect] + ); + + const effect_row = new EffectRow(effect, this); + this._effects_list.add(effect_row); + this.move_row_by(effect_row, 0); + this.update_rows_insensitive_mover(effect_row); + } + + move_row_by(row, number) { + const effects = this.pipelines_manager.pipelines[this.pipeline_id].effects; + const effect_index = effects.findIndex(e => e.id == row.effect.id); + + if (effect_index >= 0) { + effects.splice(effect_index, 1); + effects.splice(effect_index + number, 0, row.effect); + + const listbox = row.get_parent(); + listbox.set_sort_func((row_a, row_b) => { + const id_a = effects.findIndex(e => e.id == row_a.effect.id); + const id_b = effects.findIndex(e => e.id == row_b.effect.id); + return id_a > id_b; + }); + + this.update_rows_insensitive_mover(row); + + this.pipelines_manager.update_pipeline_effects( + this.pipeline_id, effects + ); + } + } + + update_rows_insensitive_mover(any_row) { + if (this._insensitive_top) + this._insensitive_top.set_sensitive(true); + if (this._insensitive_bottom) + this._insensitive_bottom.set_sensitive(true); + + const listbox = any_row.get_parent(); + this._insensitive_top = listbox.get_first_child()._move_up_button; + this._insensitive_top?.set_sensitive(false); + this._insensitive_bottom = listbox.get_last_child()._move_down_button; + this._insensitive_bottom?.set_sensitive(false); + } + + remove_row(row) { + const effects = this.pipelines_manager.pipelines[this.pipeline_id].effects; + const effect_index = effects.findIndex(e => e.id == row.effect.id); + + if (effect_index >= 0) { + effects.splice(effect_index, 1); + this.pipelines_manager.update_pipeline_effects( + this.pipeline_id, effects + ); + } + + this._effects_list.remove(row); + } +}); diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/pipelines_management/pipeline_choose_row.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/pipelines_management/pipeline_choose_row.js new file mode 100644 index 0000000..e0c5165 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/pipelines_management/pipeline_choose_row.js @@ -0,0 +1,106 @@ +import Adw from 'gi://Adw'; +import GLib from 'gi://GLib'; +import GObject from 'gi://GObject'; +import Gtk from 'gi://Gtk'; +import { gettext as _ } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'; + + +export const PipelineChooseRow = GObject.registerClass({ + GTypeName: 'PipelineChooseRow', + Template: GLib.uri_resolve_relative(import.meta.url, '../../ui/pipeline-choose-row.ui', GLib.UriFlags.NONE), + InternalChildren: [ + 'pipeline_choose', + 'pipeline_model', + 'pipeline_edit' + ], +}, class PipelineChooseRow extends Adw.ActionRow { + initialize(preferences, pipelines_manager, pipelines_page) { + this.preferences = preferences; + this.pipelines_manager = pipelines_manager; + this.pipelines_page = pipelines_page; + + this.create_pipelines_list(); + + // display the correct pipeline name in the drop-down instead of their ids + const closure_func = string_object => { + const pipeline_id = string_object.get_string(); + if (pipeline_id == 'create_new') + return _("Create new pipeline"); + if (pipeline_id in this.pipelines_manager.pipelines) + return this.pipelines_manager.pipelines[pipeline_id].name; + else + return ""; + }; + + const expression = new Gtk.ClosureExpression(GObject.TYPE_STRING, closure_func, []); + this._pipeline_choose.expression = expression; + + // TODO fix the expression not being re-evaluated other than by setting it again + this.pipelines_manager.connect( + 'pipeline-names-changed', + () => this._pipeline_choose.expression = new Gtk.ClosureExpression( + GObject.TYPE_STRING, closure_func, [] + ) + ); + + this.preferences.PIPELINE_changed(() => this.on_settings_pipeline_changed()); + + this.pipelines_manager.connect('pipeline-list-changed', () => this.create_pipelines_list()); + + this._pipeline_choose.connect('notify::selected', () => this.on_selected_pipeline_changed()); + + this._pipeline_edit.connect( + 'clicked', + () => this.pipelines_page.open_effects_dialog(this.preferences.PIPELINE) + ); + } + + on_selected_pipeline_changed() { + if (!this._pipeline_choose.selected_item || this._is_creating_pipelines_list) + return; + + const pipeline_id = this._pipeline_choose.selected_item.get_string(); + if (pipeline_id == 'create_new') { + const id = this.pipelines_manager.create_pipeline(_("New pipeline")); + this.preferences.PIPELINE = id; + } + else + this.preferences.PIPELINE = pipeline_id; + } + + on_settings_pipeline_changed() { + for (let i = 0; i < this._pipeline_model.n_items; i++) { + const pipeline_id = this._pipeline_model.get_string(i); + // if we have more pipelines than we should have: rebuild... + // that is the case when resetting the preferences for example + if (!(pipeline_id in this.pipelines_manager)) { + this.create_pipelines_list(); + return; + } + if (pipeline_id == this.preferences.PIPELINE) + this._pipeline_choose.set_selected(i); + } + } + + create_pipelines_list() { + // prevent the pipeline selector from being updated while re-creating the list + this._is_creating_pipelines_list = true; + + // remove ancient items + this._pipeline_model.splice(0, this._pipeline_model.n_items, null); + + // add new ones + let i = 0; + for (let pipeline_id in this.pipelines_manager.pipelines) { + this._pipeline_model.append(pipeline_id); + if (pipeline_id == this.preferences.PIPELINE) + this._pipeline_choose.set_selected(i); + i++; + } + this._pipeline_model.append('create_new'); + + // now update the drop-down selector + this._is_creating_pipelines_list = false; + this.on_selected_pipeline_changed(); + } +}); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/pipelines_management/pipeline_group.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/pipelines_management/pipeline_group.js new file mode 100644 index 0000000..627b576 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/preferences/pipelines_management/pipeline_group.js @@ -0,0 +1,99 @@ +import Adw from 'gi://Adw'; +import GLib from 'gi://GLib'; +import GObject from 'gi://GObject'; +import Gtk from 'gi://Gtk'; +import { gettext as _ } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'; + +import { get_supported_effects } from '../../effects/effects.js'; + + +export const PipelineGroup = GObject.registerClass({ + GTypeName: 'PipelineGroup', + Template: GLib.uri_resolve_relative(import.meta.url, '../../ui/pipeline-group.ui', GLib.UriFlags.NONE), + InternalChildren: [ + "title", + "effects_description_row", + "manage_effects" + ], +}, class PipelineGroup extends Adw.PreferencesGroup { + constructor(pipelines_manager, pipeline_id, pipeline, pipelines_page) { + super({}); + + this.SUPPORTED_EFFECTS = get_supported_effects(_); + + this._pipelines_manager = pipelines_manager; + this._pipelines_page = pipelines_page; + this._pipeline_id = pipeline_id; + + // set the description + this.set_description(_(`Pipeline id: "${pipeline_id}"`)); + + // set the title and connect it to the text entry + this.set_title(pipeline.name.length > 0 ? pipeline.name : " "); + this._title.set_text(pipeline.name); + this._title.connect( + 'changed', + () => pipelines_manager.rename_pipeline(pipeline_id, this._title.get_text()) + ); + + // the bin containing the actions + let prefix_bin = new Gtk.Box; + prefix_bin.add_css_class('linked'); + this._title.add_prefix(prefix_bin); + + // add a 'remove' button if we are not the default pipeline + if (pipeline_id != "pipeline_default") { + let remove_button = new Gtk.Button({ + 'icon-name': 'remove-row-symbolic', + 'width-request': 38, + 'height-request': 38, + 'margin-top': 6, + 'margin-bottom': 6 + }); + remove_button.add_css_class('destructive-action'); + prefix_bin.append(remove_button); + remove_button.connect('clicked', () => pipelines_manager.delete_pipeline(pipeline_id)); + } + // add a 'duplicate' button + let duplicate_button = new Gtk.Button({ + 'icon-name': 'duplicate-row-symbolic', + 'width-request': 38, + 'height-request': 38, + 'margin-top': 6, + 'margin-bottom': 6 + }); + prefix_bin.append(duplicate_button); + duplicate_button.connect('clicked', () => pipelines_manager.duplicate_pipeline(pipeline_id)); + + this.update_effects_description_row(); + this._pipelines_manager.connect( + pipeline_id + '::pipeline-updated', + () => this.update_effects_description_row() + ); + + this._manage_effects.connect( + 'clicked', + () => pipelines_page.open_effects_dialog(pipeline_id) + ); + } + + update_effects_description_row() { + const effects = this._pipelines_manager.pipelines[this._pipeline_id].effects; + + if (effects.length == 0) + this._effects_description_row.set_title(_("No effect")); + else if (effects.length == 1) + this._effects_description_row.set_title(_("1 effect")); + else + this._effects_description_row.set_title(_(`${effects.length} effects`)); + + let subtitle = ""; + effects.forEach(effect => { + if (effect.type in this.SUPPORTED_EFFECTS) + subtitle += _(`${this.SUPPORTED_EFFECTS[effect.type].name}, `); + else + subtitle += _("Unknown effect, "); + }); + this._effects_description_row.set_subtitle(subtitle.slice(0, -2)); + } +}); diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/prefs.js b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/prefs.js index df622ed..d90bdda 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/prefs.js +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/prefs.js @@ -2,17 +2,21 @@ import Gdk from 'gi://Gdk'; import Gtk from 'gi://Gtk'; import { ExtensionPreferences } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'; +import { update_from_old_settings } from './conveniences/settings_updater.js'; +import { PipelinesManager } from './conveniences/pipelines_manager.js'; import { Settings } from './conveniences/settings.js'; -import { Keys } from './conveniences/keys.js'; +import { KEYS } from './conveniences/keys.js'; import { addMenu } from './preferences/menu.js'; -import { General } from './preferences/general.js'; +import { Pipelines } from './preferences/pipelines.js'; import { Panel } from './preferences/panel.js'; import { Overview } from './preferences/overview.js'; import { Dash } from './preferences/dash.js'; import { Applications } from './preferences/applications.js'; import { Other } from './preferences/other.js'; +import './preferences/pipelines_management/pipeline_choose_row.js'; + export default class BlurMyShellPreferences extends ExtensionPreferences { constructor(metadata) { @@ -27,14 +31,20 @@ export default class BlurMyShellPreferences extends ExtensionPreferences { fillPreferencesWindow(window) { addMenu(window); - const preferences = new Settings(Keys, this.getSettings()); + // update from old settings, very important for hacks level specifically + update_from_old_settings(this.getSettings()); - window.add(new General(preferences)); - window.add(new Panel(preferences)); - window.add(new Overview(preferences)); - window.add(new Dash(preferences)); + const preferences = new Settings(KEYS, this.getSettings()); + const pipelines_manager = new PipelinesManager(preferences); + + const pipelines_page = new Pipelines(preferences, pipelines_manager, window); + + window.add(pipelines_page); + window.add(new Panel(preferences, pipelines_manager, pipelines_page)); + window.add(new Overview(preferences, pipelines_manager, pipelines_page)); + window.add(new Dash(preferences, pipelines_manager, pipelines_page)); window.add(new Applications(preferences, window)); - window.add(new Other(preferences)); + window.add(new Other(preferences, pipelines_manager, pipelines_page)); window.search_enabled = true; } diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/schemas/gschemas.compiled b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/schemas/gschemas.compiled index 36fefef..6f781f4 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/schemas/gschemas.compiled and b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/schemas/gschemas.compiled differ diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/schemas/org.gnome.shell.extensions.blur-my-shell.gschema.xml b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/schemas/org.gnome.shell.extensions.blur-my-shell.gschema.xml index 1e237e7..5708ca3 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/schemas/org.gnome.shell.extensions.blur-my-shell.gschema.xml +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/schemas/org.gnome.shell.extensions.blur-my-shell.gschema.xml @@ -3,6 +3,52 @@ + + + 1 + The version of the settings to update from. + + + + , + 'effects': <[ + <{ + 'type': <'native_static_gaussian_blur'>, + 'id': <'effect_000000000000'>, + 'params': <{ + 'radius': <30>, + 'brightness': <0.6> + }> + }> + ]> + }, + 'pipeline_default_rounded': { + 'name': <'Default rounded'>, + 'effects': <[ + <{ + 'type': <'native_static_gaussian_blur'>, + 'id': <'effect_000000000001'>, + 'params': <{ + 'radius': <30>, + 'brightness': <0.6> + }> + }>, + <{ + 'type': <'corner'>, + 'id': <'effect_000000000002'>, + 'params': <{ + 'radius': <24> + }> + }> + ]> + } + } + ]]> + A dictionnary describing the different pipelines and their effects. + 30 @@ -36,7 +82,7 @@ 1 - Level of hacks to use (from 0 to 3, 3 disabling clipped redraws entirely) + Level of hacks to use (from 0 to 2, 2 disabling clipped redraws entirely) @@ -52,6 +98,7 @@ + @@ -64,6 +111,11 @@ true Boolean, whether to blur activate the blur for this component or not + + + "pipeline_default" + String, the name of the pipeline to use. It must exist, else "pipeline_default" will be used + false @@ -154,6 +206,11 @@ true Boolean, whether to blur activate the blur for this component or not + + + "pipeline_default" + String, the name of the pipeline to use. It must exist, else "pipeline_default" will be used + false @@ -221,9 +278,14 @@ path="/org/gnome/shell/extensions/blur-my-shell/dash-to-dock/"> - false + true Boolean, whether to blur activate the blur for this component or not + + + "pipeline_default_rounded" + String, the name of the pipeline to use. It must exist, else "pipeline_default" will be used + false @@ -266,7 +328,7 @@ - 1 + 0 Enum to select the style of dash to dock (0 transparent, 1 light, 2 dark) @@ -321,9 +383,14 @@ - 230 + 215 Opacity of the window actor on top of the blur effect + + + true + Wether or not to make the focused window opaque + false @@ -354,6 +421,11 @@ true Boolean, whether to blur activate the blur for this component or not + + + "pipeline_default" + String, the name of the pipeline to use. It must exist, else "pipeline_default" will be used + false @@ -394,6 +466,11 @@ true Boolean, whether to blur activate the blur for this component or not + + + "pipeline_default" + String, the name of the pipeline to use. It must exist, else "pipeline_default" will be used + false @@ -434,6 +511,11 @@ true Boolean, whether to blur activate the blur for this component or not + + + "pipeline_default" + String, the name of the pipeline to use. It must exist, else "pipeline_default" will be used + false @@ -466,6 +548,21 @@ + + + + + true + Boolean, whether to blur activate the blur for this component or not + + + + "pipeline_default" + String, the name of the pipeline to use. It must exist, else "pipeline_default" will be used + + + diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/stylesheet.css b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/stylesheet.css index 7cfc773..b61e530 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/stylesheet.css +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/stylesheet.css @@ -123,12 +123,14 @@ .overview-components-transparent .overview-tile, .overview-components-transparent .overview-icon, +.overview-components-transparent .grid-search-result, .overview-components-transparent .list-search-result, .overview-components-transparent .search-provider-icon, /* prevents the extension from interfering with Just Perfection */ .overview-components-transparent.just-perfection .search-section-content, /* remove the rectangular background from the dash */ -.overview-components-transparent #dash .overview-tile { +.overview-components-transparent #dash .overview-tile, +.overview-components-transparent #dashtopanelScrollview .overview-tile { background-color: transparent; } @@ -146,6 +148,10 @@ .overview-components-transparent .overview-tile:focus, .overview-components-transparent .overview-tile:selected, .overview-components-transparent .overview-tile:highlighted, +.overview-components-transparent .grid-search-result:hover, +.overview-components-transparent .grid-search-result:focus, +.overview-components-transparent .grid-search-result:selected, +.overview-components-transparent .grid-search-result:highlighted, .overview-components-transparent .list-search-result:hover, .overview-components-transparent .list-search-result:focus, .overview-components-transparent .list-search-result:selected, @@ -168,6 +174,10 @@ .overview-components-transparent .overview-tile:drop, .overview-components-transparent .overview-tile:selected:hover, .overview-components-transparent .overview-tile:highlighted:hover, +.overview-components-transparent .grid-search-result:active, +.overview-components-transparent .grid-search-result:focus:hover, +.overview-components-transparent .grid-search-result:selected:hover, +.overview-components-transparent .grid-search-result:highlighted:hover, .overview-components-transparent .list-search-result:active, .overview-components-transparent .list-search-result:focus:hover, .overview-components-transparent .list-search-result:selected:hover, @@ -188,6 +198,9 @@ .overview-components-transparent .overview-tile:focus:active, .overview-components-transparent .overview-tile:selected:active, .overview-components-transparent .overview-tile:highlighted:active, +.overview-components-transparent .grid-search-result:focus:active, +.overview-components-transparent .grid-search-result:selected:active, +.overview-components-transparent .grid-search-result:highlighted:active, .overview-components-transparent .list-search-result:focus:active, .overview-components-transparent .list-search-result:selected:active, .overview-components-transparent .list-search-result:highlighted:active, @@ -216,12 +229,14 @@ .overview-components-light .overview-tile, .overview-components-light .overview-icon, +.overview-components-light .grid-search-result, .overview-components-light .list-search-result, .overview-components-light .search-provider-icon, /* prevents the extension from interfering with Just Perfection */ .overview-components-light.just-perfection .search-section-content, /* remove the rectangular background from the dash */ -.overview-components-light #dash .overview-tile { +.overview-components-light #dash .overview-tile, +.overview-components-light #dashtopanelScrollview .overview-tile { background-color: transparent; } @@ -239,6 +254,10 @@ .overview-components-light .overview-tile:focus, .overview-components-light .overview-tile:selected, .overview-components-light .overview-tile:highlighted, +.overview-components-light .grid-search-result:hover, +.overview-components-light .grid-search-result:focus, +.overview-components-light .grid-search-result:selected, +.overview-components-light .grid-search-result:highlighted, .overview-components-light .list-search-result:hover, .overview-components-light .list-search-result:focus, .overview-components-light .list-search-result:selected, @@ -261,6 +280,10 @@ .overview-components-light .overview-tile:drop, .overview-components-light .overview-tile:selected:hover, .overview-components-light .overview-tile:highlighted:hover, +.overview-components-light .grid-search-result:active, +.overview-components-light .grid-search-result:focus:hover, +.overview-components-light .grid-search-result:selected:hover, +.overview-components-light .grid-search-result:highlighted:hover, .overview-components-light .list-search-result:active, .overview-components-light .list-search-result:focus:hover, .overview-components-light .list-search-result:selected:hover, @@ -281,6 +304,9 @@ .overview-components-light .overview-tile:focus:active, .overview-components-light .overview-tile:selected:active, .overview-components-light .overview-tile:highlighted:active, +.overview-components-light .grid-search-result:focus:active, +.overview-components-light .grid-search-result:selected:active, +.overview-components-light .grid-search-result:highlighted:active, .overview-components-light .list-search-result:focus:active, .overview-components-light .list-search-result:selected:active, .overview-components-light .list-search-result:highlighted:active, @@ -309,12 +335,14 @@ .overview-components-dark .overview-tile, .overview-components-dark .overview-icon, +.overview-components-dark .grid-search-result, .overview-components-dark .list-search-result, .overview-components-dark .search-provider-icon, /* prevents the extension from interfering with Just Perfection */ .overview-components-dark.just-perfection .search-section-content, /* remove the rectangular background from the dash */ -.overview-components-dark #dash .overview-tile { +.overview-components-dark #dash .overview-tile, +.overview-components-dark #dashtopanelScrollview .overview-tile { background-color: transparent; } @@ -332,6 +360,10 @@ .overview-components-dark .overview-tile:focus, .overview-components-dark .overview-tile:selected, .overview-components-dark .overview-tile:highlighted, +.overview-components-dark .grid-search-result:hover, +.overview-components-dark .grid-search-result:focus, +.overview-components-dark .grid-search-result:selected, +.overview-components-dark .grid-search-result:highlighted, .overview-components-dark .list-search-result:hover, .overview-components-dark .list-search-result:focus, .overview-components-dark .list-search-result:selected, @@ -354,6 +386,10 @@ .overview-components-dark .overview-tile:drop, .overview-components-dark .overview-tile:selected:hover, .overview-components-dark .overview-tile:highlighted:hover, +.overview-components-dark .grid-search-result:active, +.overview-components-dark .grid-search-result:focus:hover, +.overview-components-dark .grid-search-result:selected:hover, +.overview-components-dark .grid-search-result:highlighted:hover, .overview-components-dark .list-search-result:active, .overview-components-dark .list-search-result:focus:hover, .overview-components-dark .list-search-result:selected:hover, @@ -374,6 +410,9 @@ .overview-components-dark .overview-tile:focus:active, .overview-components-dark .overview-tile:selected:active, .overview-components-dark .overview-tile:highlighted:active, +.overview-components-dark .grid-search-result:focus:active, +.overview-components-dark .grid-search-result:selected:active, +.overview-components-dark .grid-search-result:highlighted:active, .overview-components-dark .list-search-result:focus:active, .overview-components-dark .list-search-result:selected:active, .overview-components-dark .list-search-result:highlighted:active, diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/window-row.ui b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/application-row.ui similarity index 96% rename from gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/window-row.ui rename to gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/application-row.ui index 953585f..2a26d14 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/window-row.ui +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/application-row.ui @@ -1,6 +1,6 @@ - + + 0 + 100 + 1 + + + + 0.0 + 1.0 + 0.01 + + Transparent @@ -110,10 +169,4 @@ Dark - - - 0 - 50 - 1 - \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/effects-dialog.ui b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/effects-dialog.ui new file mode 100644 index 0000000..c6baf62 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/effects-dialog.ui @@ -0,0 +1,77 @@ + + + + + +
+ + Include advanced effects + effects-dialog.advanced-effects-bool + +
+
+
\ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/general.ui b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/general.ui deleted file mode 100644 index 73c6b29..0000000 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/general.ui +++ /dev/null @@ -1,234 +0,0 @@ - - - - - - 0 - 200 - 1 - - - - 0.0 - 1.0 - 0.01 - - - - 0.0 - 1.0 - 0.01 - - - - 0.0 - 2.0 - 0.01 - - - - - High performances - Default - High quality - No artifact - - - \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/menu.ui b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/menu.ui index e7b9210..6d2a474 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/menu.ui +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/menu.ui @@ -30,7 +30,7 @@ info_menu_model - heart-filled-symbolic + heart-symbolic diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/other.ui b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/other.ui index d1d24f8..e136e38 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/other.ui +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/other.ui @@ -16,7 +16,7 @@ - + @@ -34,7 +34,7 @@ - + @@ -52,11 +52,157 @@ - + + Sigma + The intensity of the blur. + window_list_sigma_scale + + + + center + true + 200px + true + right + 0 + window_list_sigma + + + + + + + + Brightness + The brightness of the blur effect, a high value might make the text harder to read. + window_list_brightness_scale + + + + + center + true + 200px + true + right + 2 + window_list_brightness + + + + + + Coverflow Alt-Tab extension blur + Make the coverflow alt-tab extension blurred, if it is used. + + + center + + + + + + + + + + + + + + Performance + Various options to tweak the performance. + + + + Hack level + Changes the behaviour of the dynamic blur effect. The default value is highly recommended. +The “No artifact” option will entirely disable clipped redraws in GNOME shell, and will impact your computer performances significantly. + hack_level + + + center + hack_level_model + + + + + + + + Debug + Makes the extension verbose in logs, activate when you need to report an issue. + debug + + + center + + + + + + + + + + + Reset preferences + Resets preferences of Blur my Shell irreversibly. + + + start + center + + + 20 + 20 + 6 + 6 + + + 6 + reset-symbolic + + + + + Reset + + + + + + + + + + + + 0 + 100 + 1 + + + + 0.0 + 1.0 + 0.01 + + + + + High performances + Default + No artifact + + \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/overview.ui b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/overview.ui index 191c70b..36b91fc 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/overview.ui +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/overview.ui @@ -16,7 +16,7 @@ - + @@ -50,8 +50,44 @@ - + + Sigma + The intensity of the blur. + appfolder_sigma_scale + + + + center + true + 200px + true + right + 0 + appfolder_sigma + + + + + + + + Brightness + The brightness of the blur effect, a high value might make the text harder to read. + appfolder_brightness_scale + + + + + center + true + 200px + true + right + 2 + appfolder_brightness + + @@ -83,6 +119,19 @@ + + 0 + 100 + 1 + + + + 0.0 + 1.0 + 0.01 + + + Do not style diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/panel.ui b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/panel.ui index f7a40e0..306f4ef 100644 --- a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/panel.ui +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/panel.ui @@ -16,21 +16,93 @@ - + + Blur type + The dynamic blur is slower and only compatible with a gaussian blur effect. + blur_mode_choose + + + + + center + false + + + + + center + true + mode_dynamic + + + static-mode-symbolic + Static + + + + + + + center + true + + + dynamic-mode-symbolic + Dynamic + + + + + + + + + + + - - Static blur - Uses a static blurred image, more performant and stable. - static_blur + + Sigma + The intensity of the blur. + sigma_scale - + center + true + 200px + true + right + 0 + sigma + + + + + + + + Brightness + The brightness of the blur effect, a high value might make the text harder to read. + brightness_scale + + + + + center + true + 200px + true + right + 2 + brightness @@ -153,4 +225,16 @@ Recommended unless you want to customize your GNOME theme. Contrasted + + + 0 + 100 + 1 + + + + 0.0 + 1.0 + 0.01 + \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/pipeline-choose-row.ui b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/pipeline-choose-row.ui new file mode 100644 index 0000000..72b854b --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/pipeline-choose-row.ui @@ -0,0 +1,39 @@ + + + + \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/pipeline-group.ui b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/pipeline-group.ui new file mode 100644 index 0000000..19a12bf --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/pipeline-group.ui @@ -0,0 +1,29 @@ + + + + \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/pipelines.ui b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/pipelines.ui new file mode 100644 index 0000000..555ec0a --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/ui/pipelines.ui @@ -0,0 +1,44 @@ + + + + \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/config/windows.json b/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/config/windows.json index 2b9f450..76e0559 100644 --- a/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/config/windows.json +++ b/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/config/windows.json @@ -19,11 +19,23 @@ { "wmClass": "zoom", "mode": "float" }, { "wmClass": "firefox", "wmTitle": "About Mozilla Firefox", "mode": "float" }, { "wmClass": "firefox", "wmTitle": "!Mozilla Firefox", "mode": "float" }, - { "wmClass": "org.mozilla.firefox.desktop", "wmTitle": "About Mozilla Firefox", "mode": "float" }, + { + "wmClass": "org.mozilla.firefox.desktop", + "wmTitle": "About Mozilla Firefox", + "mode": "float" + }, { "wmClass": "org.mozilla.firefox.desktop", "wmTitle": "!Mozilla Firefox", "mode": "float" }, { "wmClass": "thunderbird", "wmTitle": "About Mozilla Thunderbird", "mode": "float" }, { "wmClass": "thunderbird", "wmTitle": "!Mozilla Thunderbird", "mode": "float" }, - { "wmClass": "org.mozilla.Thunderbird.desktop", "wmTitle": "About Mozilla Thunderbird", "mode": "float" }, - { "wmClass": "org.mozilla.Thunderbird.desktop", "wmTitle": "!Mozilla Thunderbird", "mode": "float" } + { + "wmClass": "org.mozilla.Thunderbird.desktop", + "wmTitle": "About Mozilla Thunderbird", + "mode": "float" + }, + { + "wmClass": "org.mozilla.Thunderbird.desktop", + "wmTitle": "!Mozilla Thunderbird", + "mode": "float" + } ] } diff --git a/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/lib/extension/tree.js b/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/lib/extension/tree.js index ea0d767..0fa2981 100644 --- a/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/lib/extension/tree.js +++ b/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/lib/extension/tree.js @@ -17,6 +17,7 @@ */ // Gnome imports +import Clutter from "gi://Clutter"; import GObject from "gi://GObject"; import Meta from "gi://Meta"; import Shell from "gi://Shell"; @@ -490,11 +491,22 @@ export class Node extends GObject.Object { metaWin.activate(global.display.get_current_time()); }; - iconBin.connect("clicked", clickFn); - titleButton.connect("clicked", clickFn); - closeButton.connect("clicked", () => { + let closeFn = () => { metaWin.delete(global.get_current_time()); - }); + }; + + let middleClickCloseFn = (_, event) => { + if (event.get_button() === Clutter.BUTTON_MIDDLE) { + metaWin.delete(global.get_current_time()); + } + }; + + iconBin.connect("clicked", clickFn); + iconBin.connect("button-release-event", middleClickCloseFn); + titleButton.connect("clicked", clickFn); + titleButton.connect("button-release-event", middleClickCloseFn); + closeButton.connect("clicked", closeFn); + closeButton.connect("button-release-event", middleClickCloseFn); if (metaWin === global.display.get_focus_window()) { tabContents.add_style_class_name("window-tabbed-tab-active"); @@ -1215,6 +1227,18 @@ export class Tree extends Node { if (!this.extWm.floatingWindow(node)) cleanUpParent(existParent); } + // If only a single tab remains, exit tabbed layout + if ( + this.settings.get_boolean("auto-exit-tabbed") && + parentNode.nodeType === NODE_TYPES.CON && + parentNode.layout === LAYOUT_TYPES.TABBED && + parentNode.childNodes.length === 1 + ) { + parentNode.layout = this.extWm.determineSplitLayout(); + this.resetSiblingPercent(parentNode); + parentNode.lastTabFocus = null; + } + if (node === this.attachNode) { this.attachNode = null; } else { @@ -1511,7 +1535,6 @@ export class Tree extends Node { if (gap === 0) { adjustY = renderRect.y; - nodeY = renderRect.y + params.stackedHeight + adjust / 4; } let decoration = node.decoration; diff --git a/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/lib/extension/utils.js b/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/lib/extension/utils.js index 189a4b0..e9132e0 100644 --- a/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/lib/extension/utils.js +++ b/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/lib/extension/utils.js @@ -261,11 +261,16 @@ export function positionFromGrabOp(grabOp) { } export function allowResizeGrabOp(grabOp) { + grabOp &= ~1024; // ignore META_GRAB_OP_WINDOW_FLAG_UNCONSTRAINED return ( grabOp === Meta.GrabOp.RESIZING_N || grabOp === Meta.GrabOp.RESIZING_E || grabOp === Meta.GrabOp.RESIZING_W || grabOp === Meta.GrabOp.RESIZING_S || + grabOp === Meta.GrabOp.RESIZING_NE || + grabOp === Meta.GrabOp.RESIZING_NW || + grabOp === Meta.GrabOp.RESIZING_SE || + grabOp === Meta.GrabOp.RESIZING_SW || grabOp === Meta.GrabOp.KEYBOARD_RESIZING_N || grabOp === Meta.GrabOp.KEYBOARD_RESIZING_E || grabOp === Meta.GrabOp.KEYBOARD_RESIZING_W || @@ -275,11 +280,16 @@ export function allowResizeGrabOp(grabOp) { } export function grabMode(grabOp) { + grabOp &= ~1024; // ignore META_GRAB_OP_WINDOW_FLAG_UNCONSTRAINED if ( grabOp === Meta.GrabOp.RESIZING_N || grabOp === Meta.GrabOp.RESIZING_E || grabOp === Meta.GrabOp.RESIZING_W || grabOp === Meta.GrabOp.RESIZING_S || + grabOp === Meta.GrabOp.RESIZING_NE || + grabOp === Meta.GrabOp.RESIZING_NW || + grabOp === Meta.GrabOp.RESIZING_SE || + grabOp === Meta.GrabOp.RESIZING_SW || grabOp === Meta.GrabOp.KEYBOARD_RESIZING_N || grabOp === Meta.GrabOp.KEYBOARD_RESIZING_E || grabOp === Meta.GrabOp.KEYBOARD_RESIZING_W || @@ -297,6 +307,22 @@ export function grabMode(grabOp) { return GRAB_TYPES.UNKNOWN; } +export function decomposeGrabOp(grabOp) { + grabOp &= ~1024; // ignore META_GRAB_OP_WINDOW_FLAG_UNCONSTRAINED + switch (grabOp) { + case Meta.GrabOp.RESIZING_NE: + return [Meta.GrabOp.RESIZING_N, Meta.GrabOp.RESIZING_E]; + case Meta.GrabOp.RESIZING_NW: + return [Meta.GrabOp.RESIZING_N, Meta.GrabOp.RESIZING_W]; + case Meta.GrabOp.RESIZING_SE: + return [Meta.GrabOp.RESIZING_S, Meta.GrabOp.RESIZING_E]; + case Meta.GrabOp.RESIZING_SW: + return [Meta.GrabOp.RESIZING_S, Meta.GrabOp.RESIZING_W]; + default: + return [grabOp]; + } +} + export function directionFromGrab(grabOp) { if (grabOp === Meta.GrabOp.RESIZING_E || grabOp === Meta.GrabOp.KEYBOARD_RESIZING_E) { return Meta.MotionDirection.RIGHT; diff --git a/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/lib/extension/window.js b/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/lib/extension/window.js index b5d3ceb..b5e60d5 100644 --- a/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/lib/extension/window.js +++ b/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/lib/extension/window.js @@ -2348,143 +2348,145 @@ export class WindowManager extends GObject.Object { _handleResizing(focusNodeWindow) { if (!focusNodeWindow || focusNodeWindow.isFloat()) return; - let grabOp = this.grabOp; - let initGrabOp = focusNodeWindow.initGrabOp; - let direction = Utils.directionFromGrab(grabOp); - let orientation = Utils.orientationFromGrab(grabOp); - let parentNodeForFocus = focusNodeWindow.parentNode; - let position = Utils.positionFromGrabOp(grabOp); - // normalize the rect without gaps - let frameRect = this.focusMetaWindow.get_frame_rect(); - let gaps = this.calculateGaps(focusNodeWindow); - let currentRect = Utils.removeGapOnRect(frameRect, gaps); - let firstRect; - let secondRect; - let parentRect; - let resizePairForWindow; + let grabOps = Utils.decomposeGrabOp(this.grabOp); + for (let grabOp of grabOps) { + let initGrabOp = focusNodeWindow.initGrabOp; + let direction = Utils.directionFromGrab(grabOp); + let orientation = Utils.orientationFromGrab(grabOp); + let parentNodeForFocus = focusNodeWindow.parentNode; + let position = Utils.positionFromGrabOp(grabOp); + // normalize the rect without gaps + let frameRect = this.focusMetaWindow.get_frame_rect(); + let gaps = this.calculateGaps(focusNodeWindow); + let currentRect = Utils.removeGapOnRect(frameRect, gaps); + let firstRect; + let secondRect; + let parentRect; + let resizePairForWindow; - if (initGrabOp === Meta.GrabOp.RESIZING_UNKNOWN) { - // the direction is null so do not process yet below. - return; - } else { - resizePairForWindow = this.tree.nextVisible(focusNodeWindow, direction); - } - - let sameParent = resizePairForWindow - ? resizePairForWindow.parentNode === focusNodeWindow.parentNode - : false; - - if (orientation === ORIENTATION_TYPES.HORIZONTAL) { - if (sameParent) { - // use the window or con pairs - if (this.tree.getTiledChildren(parentNodeForFocus.childNodes).length <= 1) { - return; - } - - firstRect = focusNodeWindow.initRect; - if (resizePairForWindow) { - if ( - !this.floatingWindow(resizePairForWindow) && - !this.minimizedWindow(resizePairForWindow) - ) { - secondRect = resizePairForWindow.rect; - } else { - // TODO try to get the next resize pair? - } - } - - if (!firstRect || !secondRect) { - return; - } - - parentRect = parentNodeForFocus.rect; - let changePx = currentRect.width - firstRect.width; - let firstPercent = (firstRect.width + changePx) / parentRect.width; - let secondPercent = (secondRect.width - changePx) / parentRect.width; - focusNodeWindow.percent = firstPercent; - resizePairForWindow.percent = secondPercent; + if (initGrabOp === Meta.GrabOp.RESIZING_UNKNOWN) { + // the direction is null so do not process yet below. + return; } else { - // use the parent pairs (con to another con or window) - if (resizePairForWindow && resizePairForWindow.parentNode) { - if (this.tree.getTiledChildren(resizePairForWindow.parentNode.childNodes).length <= 1) { + resizePairForWindow = this.tree.nextVisible(focusNodeWindow, direction); + } + + let sameParent = resizePairForWindow + ? resizePairForWindow.parentNode === focusNodeWindow.parentNode + : false; + + if (orientation === ORIENTATION_TYPES.HORIZONTAL) { + if (sameParent) { + // use the window or con pairs + if (this.tree.getTiledChildren(parentNodeForFocus.childNodes).length <= 1) { return; } - let firstWindowRect = focusNodeWindow.initRect; - let index = resizePairForWindow.index; - if (position === POSITION.BEFORE) { - // Find the opposite node - index = index + 1; - } else { - index = index - 1; + + firstRect = focusNodeWindow.initRect; + if (resizePairForWindow) { + if ( + !this.floatingWindow(resizePairForWindow) && + !this.minimizedWindow(resizePairForWindow) + ) { + secondRect = resizePairForWindow.rect; + } else { + // TODO try to get the next resize pair? + } } - parentNodeForFocus = resizePairForWindow.parentNode.childNodes[index]; - firstRect = parentNodeForFocus.rect; - secondRect = resizePairForWindow.rect; + if (!firstRect || !secondRect) { return; } - parentRect = parentNodeForFocus.parentNode.rect; - let changePx = currentRect.width - firstWindowRect.width; + parentRect = parentNodeForFocus.rect; + let changePx = currentRect.width - firstRect.width; let firstPercent = (firstRect.width + changePx) / parentRect.width; let secondPercent = (secondRect.width - changePx) / parentRect.width; - parentNodeForFocus.percent = firstPercent; + focusNodeWindow.percent = firstPercent; resizePairForWindow.percent = secondPercent; - } - } - } else if (orientation === ORIENTATION_TYPES.VERTICAL) { - if (sameParent) { - // use the window or con pairs - if (this.tree.getTiledChildren(parentNodeForFocus.childNodes).length <= 1) { - return; - } - firstRect = focusNodeWindow.initRect; - if (resizePairForWindow) { - if ( - !this.floatingWindow(resizePairForWindow) && - !this.minimizedWindow(resizePairForWindow) - ) { + } else { + // use the parent pairs (con to another con or window) + if (resizePairForWindow && resizePairForWindow.parentNode) { + if (this.tree.getTiledChildren(resizePairForWindow.parentNode.childNodes).length <= 1) { + return; + } + let firstWindowRect = focusNodeWindow.initRect; + let index = resizePairForWindow.index; + if (position === POSITION.BEFORE) { + // Find the opposite node + index = index + 1; + } else { + index = index - 1; + } + parentNodeForFocus = resizePairForWindow.parentNode.childNodes[index]; + firstRect = parentNodeForFocus.rect; secondRect = resizePairForWindow.rect; - } else { - // TODO try to get the next resize pair? + if (!firstRect || !secondRect) { + return; + } + + parentRect = parentNodeForFocus.parentNode.rect; + let changePx = currentRect.width - firstWindowRect.width; + let firstPercent = (firstRect.width + changePx) / parentRect.width; + let secondPercent = (secondRect.width - changePx) / parentRect.width; + parentNodeForFocus.percent = firstPercent; + resizePairForWindow.percent = secondPercent; } } - if (!firstRect || !secondRect) { - return; - } - parentRect = parentNodeForFocus.rect; - let changePx = currentRect.height - firstRect.height; - let firstPercent = (firstRect.height + changePx) / parentRect.height; - let secondPercent = (secondRect.height - changePx) / parentRect.height; - focusNodeWindow.percent = firstPercent; - resizePairForWindow.percent = secondPercent; - } else { - // use the parent pairs (con to another con or window) - if (resizePairForWindow && resizePairForWindow.parentNode) { - if (this.tree.getTiledChildren(resizePairForWindow.parentNode.childNodes).length <= 1) { + } else if (orientation === ORIENTATION_TYPES.VERTICAL) { + if (sameParent) { + // use the window or con pairs + if (this.tree.getTiledChildren(parentNodeForFocus.childNodes).length <= 1) { return; } - let firstWindowRect = focusNodeWindow.initRect; - let index = resizePairForWindow.index; - if (position === POSITION.BEFORE) { - // Find the opposite node - index = index + 1; - } else { - index = index - 1; + firstRect = focusNodeWindow.initRect; + if (resizePairForWindow) { + if ( + !this.floatingWindow(resizePairForWindow) && + !this.minimizedWindow(resizePairForWindow) + ) { + secondRect = resizePairForWindow.rect; + } else { + // TODO try to get the next resize pair? + } } - parentNodeForFocus = resizePairForWindow.parentNode.childNodes[index]; - firstRect = parentNodeForFocus.rect; - secondRect = resizePairForWindow.rect; if (!firstRect || !secondRect) { return; } - - parentRect = parentNodeForFocus.parentNode.rect; - let changePx = currentRect.height - firstWindowRect.height; + parentRect = parentNodeForFocus.rect; + let changePx = currentRect.height - firstRect.height; let firstPercent = (firstRect.height + changePx) / parentRect.height; let secondPercent = (secondRect.height - changePx) / parentRect.height; - parentNodeForFocus.percent = firstPercent; + focusNodeWindow.percent = firstPercent; resizePairForWindow.percent = secondPercent; + } else { + // use the parent pairs (con to another con or window) + if (resizePairForWindow && resizePairForWindow.parentNode) { + if (this.tree.getTiledChildren(resizePairForWindow.parentNode.childNodes).length <= 1) { + return; + } + let firstWindowRect = focusNodeWindow.initRect; + let index = resizePairForWindow.index; + if (position === POSITION.BEFORE) { + // Find the opposite node + index = index + 1; + } else { + index = index - 1; + } + parentNodeForFocus = resizePairForWindow.parentNode.childNodes[index]; + firstRect = parentNodeForFocus.rect; + secondRect = resizePairForWindow.rect; + if (!firstRect || !secondRect) { + return; + } + + parentRect = parentNodeForFocus.parentNode.rect; + let changePx = currentRect.height - firstWindowRect.height; + let firstPercent = (firstRect.height + changePx) / parentRect.height; + let secondPercent = (secondRect.height - changePx) / parentRect.height; + parentNodeForFocus.percent = firstPercent; + resizePairForWindow.percent = secondPercent; + } } } } diff --git a/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/lib/prefs/settings.js b/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/lib/prefs/settings.js index 9333fe2..04d688f 100644 --- a/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/lib/prefs/settings.js +++ b/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/lib/prefs/settings.js @@ -74,6 +74,19 @@ export class SettingsPage extends PreferencesPage { ], }); + this.add_group({ + title: _("Behavior"), + children: [ + new SwitchRow({ + title: _("Move Pointer with the Focus"), + subtitle: _("Move the pointer when focusing or swapping via keyboard"), + experimental: true, + settings, + bind: "move-pointer-focus-enabled", + }), + ], + }); + this.add_group({ title: _("Tiling"), children: [ @@ -106,6 +119,12 @@ export class SettingsPage extends PreferencesPage { { id: "stacked", name: _("Stacked") }, ], }), + new SwitchRow({ + title: _("Auto Exit Tabbed Tiling Mode"), + subtitle: _("Exit tabbed tiling mode when only a single tab remains"), + settings, + bind: "auto-exit-tabbed", + }), new SwitchRow({ title: _("Auto Split"), subtitle: _("Quarter Tiling"), @@ -130,19 +149,6 @@ export class SettingsPage extends PreferencesPage { ], }); - this.add_group({ - title: _("Behavior"), - children: [ - new SwitchRow({ - title: _("Move Pointer with the Focus"), - subtitle: _("Move the pointer when focusing or swapping via keyboard"), - experimental: true, - settings, - bind: "move-pointer-focus-enabled", - }), - ], - }); - if (!production) { this.add_group({ title: _("Logger"), diff --git a/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/locale/fr/LC_MESSAGES/forge.mo b/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/locale/fr/LC_MESSAGES/forge.mo index b3234e1..0c3fba1 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/locale/fr/LC_MESSAGES/forge.mo and b/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/locale/fr/LC_MESSAGES/forge.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/metadata.json b/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/metadata.json index dda6394..aef9827 100644 --- a/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/metadata.json +++ b/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/metadata.json @@ -10,9 +10,10 @@ "settings-schema": "org.gnome.shell.extensions.forge", "shell-version": [ "45", - "46" + "46", + "47" ], "url": "https://github.com/forge-ext/forge", "uuid": "forge@jmmaranan.com", - "version": 78 + "version": 84 } \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/schemas/gschemas.compiled b/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/schemas/gschemas.compiled index 3884f40..b7ad5be 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/schemas/gschemas.compiled and b/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/schemas/gschemas.compiled differ diff --git a/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/schemas/org.gnome.shell.extensions.forge.gschema.xml b/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/schemas/org.gnome.shell.extensions.forge.gschema.xml index 40cf788..ee42081 100644 --- a/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/schemas/org.gnome.shell.extensions.forge.gschema.xml +++ b/gnome/.local/share/gnome-shell/extensions/forge@jmmaranan.com/schemas/org.gnome.shell.extensions.forge.gschema.xml @@ -120,13 +120,17 @@ - true + false Move the pointer when focusing or swapping via kbd true Floating windows toggle always-on-top + + true + Exit tabbed tiling mode when only a single tab remains + true Enable auto split or quarter-tiling based based on smaller side diff --git a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/keycodes.tar.xz b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/keycodes.tar.xz new file mode 100644 index 0000000..a57820a Binary files /dev/null and b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/keycodes.tar.xz differ diff --git a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/physicalLayouts.json b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/physicalLayouts.json new file mode 100644 index 0000000..17407d3 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/physicalLayouts.json @@ -0,0 +1,73 @@ +{ + "Full Sized International":[ + [{"key":"ESC"}, {"width":1}, {"key":"FK01"}, {"key":"FK02"}, {"key":"FK03"}, {"key":"FK04"}, {"width":0.5}, {"key":"FK05"}, {"key":"FK06"}, {"key":"FK07"}, {"key":"FK08"}, {"width":0.5}, {"key":"FK09"}, {"key":"FK10"}, {"key":"FK11"}, {"key":"FK12"}, {"key":"PRSC"}, {"key":"SCLK"}, {"key":"PAUS"}, {"width":4}], + [{"key":"TLDE"}, {"key":"AE01"}, {"key":"AE02"}, {"key":"AE03"}, {"key":"AE04"}, {"key":"AE05"}, {"key":"AE06"}, {"key":"AE07"}, {"key":"AE08"}, {"key":"AE09"}, {"key":"AE10"}, {"key":"AE11"}, {"key":"AE12"}, {"key":"BKSP", "width":2}, {"key":"INS"}, {"key":"HOME"}, {"key":"PGUP"}, {"key":"NMLK"}, {"key":"KPDV"}, {"key":"KPMU"}, {"key":"KPSU"}], + [{"key":"TAB", "width":1.5}, {"key":"AD01"}, {"key":"AD02"}, {"key":"AD03"}, {"key":"AD04"}, {"key":"AD05"}, {"key":"AD06"}, {"key":"AD07"}, {"key":"AD08"}, {"key":"AD09"}, {"key":"AD10"}, {"key":"AD11"}, {"key":"AD12"}, {"key":"RTRN", "width":1.5, "height":2}, {"key":"DELE"}, {"key":"END"}, {"key":"PGDN"}, {"key":"KP7"}, {"key":"KP8"}, {"key":"KP9"}, {"key":"KPAD", "width":1, "height":2}], + [{"key":"CAPS", "width":2}, {"key":"AC01"}, {"key":"AC02"}, {"key":"AC03"}, {"key":"AC04"}, {"key":"AC05"}, {"key":"AC06"}, {"key":"AC07"}, {"key":"AC08"}, {"key":"AC09"}, {"key":"AC10"}, {"key":"AC11"}, {"key":"BKSL", "width":0.5}, {"width":1.5}, {"width":3}, {"key":"KP4"}, {"key":"KP5"}, {"key":"KP6"}, {"width":1}], + [{"key":"LFSH", "width":2}, {"key":"LSGT"}, {"key":"AB01"}, {"key":"AB02"}, {"key":"AB03"}, {"key":"AB04"}, {"key":"AB05"}, {"key":"AB06"}, {"key":"AB07"}, {"key":"AB08"}, {"key":"AB09"}, {"key":"AB10"}, {"key":"RTSH", "width":2}, {"width":1}, {"key":"UP"}, {"width":1}, {"key":"KP1"}, {"key":"KP2"}, {"key":"KP3"}, {"key":"KPEN", "height":2}], + [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":10}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, {"key":"DOWN"}, {"key":"RGHT"}, {"key":"KP0", "width":2}, {"key":"KPDL"}, {"width":1}] + ], + + "Full Sized US":[ + [{"key":"ESC"}, {"width":1}, {"key":"FK01"}, {"key":"FK02"}, {"key":"FK03"}, {"key":"FK04"}, {"width":0.5}, {"key":"FK05"}, {"key":"FK06"}, {"key":"FK07"}, {"key":"FK08"}, {"width":0.5}, {"key":"FK09"}, {"key":"FK10"}, {"key":"FK11"}, {"key":"FK12"}, {"key":"PRSC"}, {"key":"SCLK"}, {"key":"PAUS"}, {"width":4}], + [{"key":"TLDE"}, {"key":"AE01"}, {"key":"AE02"}, {"key":"AE03"}, {"key":"AE04"}, {"key":"AE05"}, {"key":"AE06"}, {"key":"AE07"}, {"key":"AE08"}, {"key":"AE09"}, {"key":"AE10"}, {"key":"AE11"}, {"key":"AE12"}, {"key":"BKSP", "width":2}, {"key":"INS"}, {"key":"HOME"}, {"key":"PGUP"}, {"key":"NMLK"}, {"key":"KPDV"}, {"key":"KPMU"}, {"key":"KPSU"}], + [{"key":"TAB", "width":1.5}, {"key":"AD01"}, {"key":"AD02"}, {"key":"AD03"}, {"key":"AD04"}, {"key":"AD05"}, {"key":"AD06"}, {"key":"AD07"}, {"key":"AD08"}, {"key":"AD09"}, {"key":"AD10"}, {"key":"AD11"}, {"key":"AD12"}, {"key":"BKSL", "width":1.5}, {"key":"DELE"}, {"key":"END"}, {"key":"PGDN"}, {"key":"KP7"}, {"key":"KP8"}, {"key":"KP9"}, {"key":"KPAD", "width":1, "height":2}], + [{"key":"CAPS", "width":2}, {"key":"AC01"}, {"key":"AC02"}, {"key":"AC03"}, {"key":"AC04"}, {"key":"AC05"}, {"key":"AC06"}, {"key":"AC07"}, {"key":"AC08"}, {"key":"AC09"}, {"key":"AC10"}, {"key":"AC11"}, {"key": "RTRN", "width": 2}, {"width":3}, {"key":"KP4"}, {"key":"KP5"}, {"key":"KP6"}, {"width":1}], + [{"key":"LFSH", "width":2}, {"key":"LSGT"}, {"key":"AB01"}, {"key":"AB02"}, {"key":"AB03"}, {"key":"AB04"}, {"key":"AB05"}, {"key":"AB06"}, {"key":"AB07"}, {"key":"AB08"}, {"key":"AB09"}, {"key":"AB10"}, {"key":"RTSH", "width":2}, {"width":1}, {"key":"UP"}, {"width":1}, {"key":"KP1"}, {"key":"KP2"}, {"key":"KP3"}, {"key":"KPEN", "height":2}], + [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":10}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, {"key":"DOWN"}, {"key":"RGHT"}, {"key":"KP0", "width":2}, {"key":"KPDL"}, {"width":1}] + ], + + "Tenkeyless International":[ + [{"key":"ESC"}, {"width":1}, {"key":"FK01"}, {"key":"FK02"}, {"key":"FK03"}, {"key":"FK04"}, {"width":0.5}, {"key":"FK05"}, {"key":"FK06"}, {"key":"FK07"}, {"key":"FK08"}, {"width":0.5}, {"key":"FK09"}, {"key":"FK10"}, {"key":"FK11"}, {"key":"FK12"}, {"key":"PRSC"}, {"key":"SCLK"}, {"key":"PAUS"}], + [{"key":"TLDE"}, {"key":"AE01"}, {"key":"AE02"}, {"key":"AE03"}, {"key":"AE04"}, {"key":"AE05"}, {"key":"AE06"}, {"key":"AE07"}, {"key":"AE08"}, {"key":"AE09"}, {"key":"AE10"}, {"key":"AE11"}, {"key":"AE12"}, {"key":"BKSP", "width":2}, {"key":"INS"}, {"key":"HOME"}, {"key":"PGUP"}], + [{"key":"TAB", "width":1.5}, {"key":"AD01"}, {"key":"AD02"}, {"key":"AD03"}, {"key":"AD04"}, {"key":"AD05"}, {"key":"AD06"}, {"key":"AD07"}, {"key":"AD08"}, {"key":"AD09"}, {"key":"AD10"}, {"key":"AD11"}, {"key":"AD12"}, {"key":"RTRN", "width":1.5, "height":2}, {"key":"DELE"}, {"key":"END"}, {"key":"PGDN"}], + [{"key":"CAPS", "width":2}, {"key":"AC01"}, {"key":"AC02"}, {"key":"AC03"}, {"key":"AC04"}, {"key":"AC05"}, {"key":"AC06"}, {"key":"AC07"}, {"key":"AC08"}, {"key":"AC09"}, {"key":"AC10"}, {"key":"AC11"}, {"key":"BKSL", "width":0.5}, {"width":1.5}, {"width":3}], + [{"key":"LFSH", "width":2}, {"key":"LSGT"}, {"key":"AB01"}, {"key":"AB02"}, {"key":"AB03"}, {"key":"AB04"}, {"key":"AB05"}, {"key":"AB06"}, {"key":"AB07"}, {"key":"AB08"}, {"key":"AB09"}, {"key":"AB10"}, {"key":"RTSH", "width":2}, {"width":1}, {"key":"UP"}, {"width":1}], + [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":10}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, {"key":"DOWN"}, {"key":"RGHT"}] + ], + + "Tenkeyless US":[ + [{"key":"ESC"}, {"width":1}, {"key":"FK01"}, {"key":"FK02"}, {"key":"FK03"}, {"key":"FK04"}, {"width":0.5}, {"key":"FK05"}, {"key":"FK06"}, {"key":"FK07"}, {"key":"FK08"}, {"width":0.5}, {"key":"FK09"}, {"key":"FK10"}, {"key":"FK11"}, {"key":"FK12"}, {"key":"PRSC"}, {"key":"SCLK"}, {"key":"PAUS"}], + [{"key":"TLDE"}, {"key":"AE01"}, {"key":"AE02"}, {"key":"AE03"}, {"key":"AE04"}, {"key":"AE05"}, {"key":"AE06"}, {"key":"AE07"}, {"key":"AE08"}, {"key":"AE09"}, {"key":"AE10"}, {"key":"AE11"}, {"key":"AE12"}, {"key":"BKSP", "width":2}, {"key":"INS"}, {"key":"HOME"}, {"key":"PGUP"}], + [{"key":"TAB", "width":1.5}, {"key":"AD01"}, {"key":"AD02"}, {"key":"AD03"}, {"key":"AD04"}, {"key":"AD05"}, {"key":"AD06"}, {"key":"AD07"}, {"key":"AD08"}, {"key":"AD09"}, {"key":"AD10"}, {"key":"AD11"}, {"key":"AD12"}, {"key":"BKSL", "width":1.5}, {"key":"DELE"}, {"key":"END"}, {"key":"PGDN"}], + [{"key":"CAPS", "width":2}, {"key":"AC01"}, {"key":"AC02"}, {"key":"AC03"}, {"key":"AC04"}, {"key":"AC05"}, {"key":"AC06"}, {"key":"AC07"}, {"key":"AC08"}, {"key":"AC09"}, {"key":"AC10"}, {"key":"AC11"}, {"key": "RTRN", "width": 2}, {"width":3}], + [{"key":"LFSH", "width":2}, {"key":"LSGT"}, {"key":"AB01"}, {"key":"AB02"}, {"key":"AB03"}, {"key":"AB04"}, {"key":"AB05"}, {"key":"AB06"}, {"key":"AB07"}, {"key":"AB08"}, {"key":"AB09"}, {"key":"AB10"}, {"key":"RTSH", "width":2}, {"width":1}, {"key":"UP"}, {"width":1}], + [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":10}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, {"key":"DOWN"}, {"key":"RGHT"}] + ], + + "Compact International":[ + [{"key":"ESC"}, {"key":"FK01"}, {"key":"FK02"}, {"key":"FK03"}, {"key":"FK04"}, {"key":"FK05"}, {"key":"FK06"}, {"key":"FK07"}, {"key":"FK08"}, {"key":"FK09"}, {"key":"FK10"}, {"key":"FK11"}, {"key":"FK12"}, {"key":"PRSC"}, {"key":"DELE"}], + [{"key":"TLDE"}, {"key":"AE01"}, {"key":"AE02"}, {"key":"AE03"}, {"key":"AE04"}, {"key":"AE05"}, {"key":"AE06"}, {"key":"AE07"}, {"key":"AE08"}, {"key":"AE09"}, {"key":"AE10"}, {"key":"AE11"}, {"key":"AE12"}, {"key":"BKSP", "width":2}], + [{"key":"TAB", "width":1.5}, {"key":"AD01"}, {"key":"AD02"}, {"key":"AD03"}, {"key":"AD04"}, {"key":"AD05"}, {"key":"AD06"}, {"key":"AD07"}, {"key":"AD08"}, {"key":"AD09"}, {"key":"AD10"}, {"key":"AD11"}, {"key":"AD12"}, {"key":"RTRN", "width":1.5, "height":2}], + [{"key":"CAPS", "width":2}, {"key":"AC01"}, {"key":"AC02"}, {"key":"AC03"}, {"key":"AC04"}, {"key":"AC05"}, {"key":"AC06"}, {"key":"AC07"}, {"key":"AC08"}, {"key":"AC09"}, {"key":"AC10"}, {"key":"AC11"}, {"key":"BKSL", "width":0.5}, {"width":1.5}], + [{"key":"LFSH", "width":2}, {"key":"LSGT"}, {"key":"AB01"}, {"key":"AB02"}, {"key":"AB03"}, {"key":"AB04"}, {"key":"AB05"}, {"key":"AB06"}, {"key":"AB07"}, {"key":"AB08"}, {"key":"AB09"}, {"key":"AB10"}, {"key":"RTSH", "width": 2}], + [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":7}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, [{"key":"UP", "height": 0.5}, {"key":"DOWN", "height": 0.5}], {"key":"RGHT"}] + ], + + "Compact US":[ + [{"key":"ESC"}, {"key":"FK01"}, {"key":"FK02"}, {"key":"FK03"}, {"key":"FK04"}, {"key":"FK05"}, {"key":"FK06"}, {"key":"FK07"}, {"key":"FK08"}, {"key":"FK09"}, {"key":"FK10"}, {"key":"FK11"}, {"key":"FK12"}, {"key":"PRSC"}, {"key":"DELE"}], + [{"key":"TLDE"}, {"key":"AE01"}, {"key":"AE02"}, {"key":"AE03"}, {"key":"AE04"}, {"key":"AE05"}, {"key":"AE06"}, {"key":"AE07"}, {"key":"AE08"}, {"key":"AE09"}, {"key":"AE10"}, {"key":"AE11"}, {"key":"AE12"}, {"key":"BKSP", "width":2}], + [{"key":"TAB", "width":1.5}, {"key":"AD01"}, {"key":"AD02"}, {"key":"AD03"}, {"key":"AD04"}, {"key":"AD05"}, {"key":"AD06"}, {"key":"AD07"}, {"key":"AD08"}, {"key":"AD09"}, {"key":"AD10"}, {"key":"AD11"}, {"key":"AD12"}, {"key":"BKSL", "width":1.5}], + [{"key":"CAPS", "width":2}, {"key":"AC01"}, {"key":"AC02"}, {"key":"AC03"}, {"key":"AC04"}, {"key":"AC05"}, {"key":"AC06"}, {"key":"AC07"}, {"key":"AC08"}, {"key":"AC09"}, {"key":"AC10"}, {"key":"AC11"}, {"key": "RTRN", "width": 2}], + [{"key":"LFSH", "width":2}, {"key":"LSGT"}, {"key":"AB01"}, {"key":"AB02"}, {"key":"AB03"}, {"key":"AB04"}, {"key":"AB05"}, {"key":"AB06"}, {"key":"AB07"}, {"key":"AB08"}, {"key":"AB09"}, {"key":"AB10"}, {"key":"RTSH", "width": 2}], + [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":7}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, [{"key":"UP", "height": 0.5}, {"key":"DOWN", "height": 0.5}], {"key":"RGHT"}] + ], + + "Split International":[ + [{"key":"ESC", "width": 0.5}, {"key":"FK01"}, {"key":"FK02"}, {"key":"FK03"}, {"key":"FK04"}, {"key":"FK05"}, {"key":"FK06"}, {"key":"FK07"}, {"split":true}, {"key":"FK08"}, {"key":"FK09"}, {"key":"FK10"}, {"key":"FK11"}, {"key":"FK12"}, {"key":"PRSC"}, {"key":"DELE"}], + [{"key":"TLDE", "width": 1}, {"key":"AE01"}, {"key":"AE02"}, {"key":"AE03"}, {"key":"AE04"}, {"key":"AE05"}, {"key":"AE06"}, {"split":true}, {"key":"AE07"}, {"key":"AE08"}, {"key":"AE09"}, {"key":"AE10"}, {"key":"AE11"}, {"key":"AE12"}, {"key":"BKSP", "width":1.5}], + [{"key":"TAB", "width":1.5}, {"key":"AD01"}, {"key":"AD02"}, {"key":"AD03"}, {"key":"AD04"}, {"key":"AD05"}, {"key":"AD06"}, {"split":true}, {"key":"AD07"}, {"key":"AD08"}, {"key":"AD09"}, {"key":"AD10"}, {"key":"AD11"}, {"key":"AD12"}, {"key":"RTRN", "height":2}], + [{"key":"CAPS", "width":2}, {"key":"AC01"}, {"key":"AC02"}, {"key":"AC03"}, {"key":"AC04"}, {"key":"AC05"}, {"split":true}, {"key":"AC06"}, {"key":"AC07"}, {"key":"AC08"}, {"key":"AC09"}, {"key":"AC10"}, {"key":"AC11"}, {"key":"BKSL", "width":0.5}, {"width":1}], + [{"key":"LFSH", "width":2}, {"key":"LSGT"}, {"key":"AB01"}, {"key":"AB02"}, {"key":"AB03"}, {"key":"AB04"}, {"split":true}, {"key":"AB05"}, {"key":"AB06"}, {"key":"AB07"}, {"key":"AB08"}, {"key":"AB09"}, {"key":"AB10"}, {"key":"RTSH", "width": 1.5}], + [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":4}, {"split":true}, {"key":"SPCE", "width":2.5}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, [{"key":"UP", "height": 0.5}, {"key":"DOWN", "height": 0.5}], {"key":"RGHT"}] + ], + + "Split US":[ + [{"key":"ESC", "width": 0.5}, {"key":"FK01"}, {"key":"FK02"}, {"key":"FK03"}, {"key":"FK04"}, {"key":"FK05"}, {"key":"FK06"}, {"key":"FK07"}, {"split":true}, {"key":"FK08"}, {"key":"FK09"}, {"key":"FK10"}, {"key":"FK11"}, {"key":"FK12"}, {"key":"PRSC"}, {"key":"DELE"}], + [{"key":"TLDE", "width": 1}, {"key":"AE01"}, {"key":"AE02"}, {"key":"AE03"}, {"key":"AE04"}, {"key":"AE05"}, {"key":"AE06"}, {"split":true}, {"key":"AE07"}, {"key":"AE08"}, {"key":"AE09"}, {"key":"AE10"}, {"key":"AE11"}, {"key":"AE12"}, {"key":"BKSP", "width":1.5}], + [{"key":"TAB", "width":1.5}, {"key":"AD01"}, {"key":"AD02"}, {"key":"AD03"}, {"key":"AD04"}, {"key":"AD05"}, {"key":"AD06"}, {"split":true}, {"key":"AD07"}, {"key":"AD08"}, {"key":"AD09"}, {"key":"AD10"}, {"key":"AD11"}, {"key":"AD12"}, {"key":"BKSL"}], + [{"key":"CAPS", "width":2}, {"key":"AC01"}, {"key":"AC02"}, {"key":"AC03"}, {"key":"AC04"}, {"key":"AC05"}, {"split":true}, {"key":"AC06"}, {"key":"AC07"}, {"key":"AC08"}, {"key":"AC09"}, {"key":"AC10"}, {"key":"AC11"}, {"key": "RTRN", "width": 1.5}], + [{"key":"LFSH", "width":2}, {"key":"LSGT"}, {"key":"AB01"}, {"key":"AB02"}, {"key":"AB03"}, {"key":"AB04"}, {"split":true}, {"key":"AB05"}, {"key":"AB06"}, {"key":"AB07"}, {"key":"AB08"}, {"key":"AB09"}, {"key":"AB10"}, {"key":"RTSH", "width": 1.5}], + [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":4}, {"split":true}, {"key":"SPCE", "width":2.5}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, [{"key":"UP", "height": 0.5}, {"key":"DOWN", "height": 0.5}], {"key":"RGHT"}] + ] +} \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/ui/icons/hicolor/scalable/actions/settings-dark.svg b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/ui/icons/hicolor/scalable/actions/settings-dark.svg new file mode 100644 index 0000000..88204dd --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/ui/icons/hicolor/scalable/actions/settings-dark.svg @@ -0,0 +1,37 @@ + + diff --git a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/ui/icons/hicolor/scalable/actions/settings.svg b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/ui/icons/hicolor/scalable/actions/settings.svg new file mode 100644 index 0000000..18735f5 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/ui/icons/hicolor/scalable/actions/settings.svg @@ -0,0 +1,37 @@ + + diff --git a/gnome/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/init.js b/gnome/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/init.js new file mode 100644 index 0000000..038f60e --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/init.js @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: GSConnect Developers https://github.com/GSConnect +// +// SPDX-License-Identifier: GPL-2.0-or-later + +import GLib from 'gi://GLib'; + +import setup, {setupGettext} from '../utils/setup.js'; + + +// Bootstrap +setup(GLib.path_get_dirname(GLib.path_get_dirname(GLib.filename_from_uri(import.meta.url)[0]))); +setupGettext(); diff --git a/gnome/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/index.js b/gnome/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/index.js new file mode 100644 index 0000000..249c7ee --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/index.js @@ -0,0 +1,102 @@ +// SPDX-FileCopyrightText: GSConnect Developers https://github.com/GSConnect +// +// SPDX-License-Identifier: GPL-2.0-or-later + +import * as atspi from './atspi.js'; +import * as clipboard from './clipboard.js'; +import * as contacts from './contacts.js'; +import * as input from './input.js'; +import * as mpris from './mpris.js'; +import * as notification from './notification.js'; +import * as pulseaudio from './pulseaudio.js'; +import * as session from './session.js'; +import * as sound from './sound.js'; +import * as upower from './upower.js'; +import * as ydotool from './ydotool.js'; + +export const functionOverrides = {}; + +const components = { + atspi, + clipboard, + contacts, + input, + mpris, + notification, + pulseaudio, + session, + sound, + upower, + ydotool, +}; + +/* + * Singleton Tracker + */ +const Default = new Map(); + + +/** + * Acquire a reference to a component. Calls to this function should always be + * followed by a call to `release()`. + * + * @param {string} name - The module name + * @return {*} The default instance of a component + */ +export function acquire(name) { + if (functionOverrides.acquire) + return functionOverrides.acquire(name); + + let component; + + try { + let info = Default.get(name); + + if (info === undefined) { + const module = components[name]; + + info = { + instance: new module.default(), + refcount: 0, + }; + + Default.set(name, info); + } + + info.refcount++; + component = info.instance; + } catch (e) { + debug(e, name); + } + + return component; +} + + +/** + * Release a reference on a component. If the caller was the last reference + * holder, the component will be freed. + * + * @param {string} name - The module name + * @return {null} A %null value, useful for overriding a traced variable + */ +export function release(name) { + if (functionOverrides.release) + return functionOverrides.release(name); + + try { + const info = Default.get(name); + + if (info.refcount === 1) { + info.instance.destroy(); + Default.delete(name); + } + + info.refcount--; + } catch (e) { + debug(e, name); + } + + return null; +} + diff --git a/gnome/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/init.js b/gnome/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/init.js new file mode 100644 index 0000000..313c70b --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/init.js @@ -0,0 +1,428 @@ +// SPDX-FileCopyrightText: GSConnect Developers https://github.com/GSConnect +// +// SPDX-License-Identifier: GPL-2.0-or-later + +import {watchService} from '../wl_clipboard.js'; + +import Gio from 'gi://Gio'; +import GIRepository from 'gi://GIRepository'; +import GLib from 'gi://GLib'; + +import Config from '../config.js'; +import setup, {setupGettext} from '../utils/setup.js'; + + +// Promise Wrappers +// We don't use top-level await since it returns control flow to importing module, causing bugs +import('gi://EBook').then(({default: EBook}) => { + Gio._promisify(EBook.BookClient, 'connect'); + Gio._promisify(EBook.BookClient.prototype, 'get_view'); + Gio._promisify(EBook.BookClient.prototype, 'get_contacts'); +}).catch(console.debug); +import('gi://EDataServer').then(({default: EDataServer}) => { + Gio._promisify(EDataServer.SourceRegistry, 'new'); +}).catch(console.debug); + +Gio._promisify(Gio.AsyncInitable.prototype, 'init_async'); +Gio._promisify(Gio.DBusConnection.prototype, 'call'); +Gio._promisify(Gio.DBusProxy.prototype, 'call'); +Gio._promisify(Gio.DataInputStream.prototype, 'read_line_async', + 'read_line_finish_utf8'); +Gio._promisify(Gio.File.prototype, 'delete_async'); +Gio._promisify(Gio.File.prototype, 'enumerate_children_async'); +Gio._promisify(Gio.File.prototype, 'load_contents_async'); +Gio._promisify(Gio.File.prototype, 'mount_enclosing_volume'); +Gio._promisify(Gio.File.prototype, 'query_info_async'); +Gio._promisify(Gio.File.prototype, 'read_async'); +Gio._promisify(Gio.File.prototype, 'replace_async'); +Gio._promisify(Gio.File.prototype, 'replace_contents_bytes_async', + 'replace_contents_finish'); +Gio._promisify(Gio.FileEnumerator.prototype, 'next_files_async'); +Gio._promisify(Gio.Mount.prototype, 'unmount_with_operation'); +Gio._promisify(Gio.InputStream.prototype, 'close_async'); +Gio._promisify(Gio.OutputStream.prototype, 'close_async'); +Gio._promisify(Gio.OutputStream.prototype, 'splice_async'); +Gio._promisify(Gio.OutputStream.prototype, 'write_all_async'); +Gio._promisify(Gio.SocketClient.prototype, 'connect_async'); +Gio._promisify(Gio.SocketListener.prototype, 'accept_async'); +Gio._promisify(Gio.Subprocess.prototype, 'communicate_utf8_async'); +Gio._promisify(Gio.Subprocess.prototype, 'wait_check_async'); +Gio._promisify(Gio.TlsConnection.prototype, 'handshake_async'); +Gio._promisify(Gio.DtlsConnection.prototype, 'handshake_async'); + + +// User Directories +Config.CACHEDIR = GLib.build_filenamev([GLib.get_user_cache_dir(), 'gsconnect']); +Config.CONFIGDIR = GLib.build_filenamev([GLib.get_user_config_dir(), 'gsconnect']); +Config.RUNTIMEDIR = GLib.build_filenamev([GLib.get_user_runtime_dir(), 'gsconnect']); + +// Bootstrap +const serviceFolder = GLib.path_get_dirname(GLib.filename_from_uri(import.meta.url)[0]); +const extensionFolder = GLib.path_get_dirname(serviceFolder); +setup(extensionFolder); +setupGettext(); + +if (Config.IS_USER) { + // Infer libdir by assuming gnome-shell shares a common prefix with gjs; + // assume the parent directory if it's not there + let libdir = GIRepository.Repository.get_search_path().find(path => { + return path.endsWith('/gjs/girepository-1.0'); + }).replace('/gjs/girepository-1.0', ''); + + const gsdir = GLib.build_filenamev([libdir, 'gnome-shell']); + + if (!GLib.file_test(gsdir, GLib.FileTest.IS_DIR)) { + const currentDir = `/${GLib.path_get_basename(libdir)}`; + libdir = libdir.replace(currentDir, ''); + } + + Config.GNOME_SHELL_LIBDIR = libdir; +} + + +// Load DBus interfaces +Config.DBUS = (() => { + const bytes = Gio.resources_lookup_data( + GLib.build_filenamev([Config.APP_PATH, `${Config.APP_ID}.xml`]), + Gio.ResourceLookupFlags.NONE + ); + + const xml = new TextDecoder().decode(bytes.toArray()); + const dbus = Gio.DBusNodeInfo.new_for_xml(xml); + dbus.nodes.forEach(info => info.cache_build()); + + return dbus; +})(); + + +// Init User Directories +for (const path of [Config.CACHEDIR, Config.CONFIGDIR, Config.RUNTIMEDIR]) + GLib.mkdir_with_parents(path, 0o755); + + +globalThis.HAVE_GNOME = GLib.getenv('GSCONNECT_MODE')?.toLowerCase() !== 'cli' && (GLib.getenv('GNOME_SETUP_DISPLAY') !== null || GLib.getenv('XDG_CURRENT_DESKTOP')?.toUpperCase()?.includes('GNOME') || GLib.getenv('XDG_SESSION_DESKTOP')?.toLowerCase() === 'gnome'); + + +/** + * A custom debug function that logs at LEVEL_MESSAGE to avoid the need for env + * variables to be set. + * + * @param {Error|string} message - A string or Error to log + * @param {string} [prefix] - An optional prefix for the warning + */ +const _debugCallerMatch = new RegExp(/([^@]*)@([^:]*):([^:]*)/); +// eslint-disable-next-line func-style +const _debugFunc = function (error, prefix = null) { + let caller, message; + + if (error.stack) { + caller = error.stack.split('\n')[0]; + message = `${error.message}\n${error.stack}`; + } else { + caller = (new Error()).stack.split('\n')[1]; + message = JSON.stringify(error, null, 2); + } + + if (prefix) + message = `${prefix}: ${message}`; + + const [, func, file, line] = _debugCallerMatch.exec(caller); + const script = file.replace(Config.PACKAGE_DATADIR, ''); + + GLib.log_structured('GSConnect', GLib.LogLevelFlags.LEVEL_MESSAGE, { + 'MESSAGE': `[${script}:${func}:${line}]: ${message}`, + 'SYSLOG_IDENTIFIER': 'org.gnome.Shell.Extensions.GSConnect', + 'CODE_FILE': file, + 'CODE_FUNC': func, + 'CODE_LINE': line, + }); +}; + +// Swap the function out for a no-op anonymous function for speed +const settings = new Gio.Settings({ + settings_schema: Config.GSCHEMA.lookup(Config.APP_ID, true), +}); + +settings.connect('changed::debug', (settings, key) => { + globalThis.debug = settings.get_boolean(key) ? _debugFunc : () => {}; +}); + +if (settings.get_boolean('debug')) + globalThis.debug = _debugFunc; +else + globalThis.debug = () => {}; + + +/** + * Start wl_clipboard if not under Gnome + */ +if (!globalThis.HAVE_GNOME) { + debug('Not running as a Gnome extension'); + watchService(); +} + + +/** + * A simple (for now) pre-comparison sanitizer for phone numbers + * See: https://github.com/KDE/kdeconnect-kde/blob/master/smsapp/conversationlistmodel.cpp#L200-L210 + * + * @return {string} Return the string stripped of leading 0, and ' ()-+' + */ +String.prototype.toPhoneNumber = function () { + const strippedNumber = this.replace(/^0*|[ ()+-]/g, ''); + + if (strippedNumber.length) + return strippedNumber; + + return this; +}; + + +/** + * A simple equality check for phone numbers based on `toPhoneNumber()` + * + * @param {string} number - A phone number string to compare + * @return {boolean} If `this` and @number are equivalent phone numbers + */ +String.prototype.equalsPhoneNumber = function (number) { + const a = this.toPhoneNumber(); + const b = number.toPhoneNumber(); + + return (a.length && b.length && (a.endsWith(b) || b.endsWith(a))); +}; + + +/** + * An implementation of `rm -rf` in Gio + * + * @param {Gio.File|string} file - a GFile or filepath + */ +Gio.File.rm_rf = function (file) { + try { + if (typeof file === 'string') + file = Gio.File.new_for_path(file); + + try { + const iter = file.enumerate_children( + 'standard::name', + Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, + null + ); + + let info; + + while ((info = iter.next_file(null))) + Gio.File.rm_rf(iter.get_child(info)); + + iter.close(null); + } catch (e) { + // Silence errors + } + + file.delete(null); + } catch (e) { + // Silence errors + } +}; + + +/** + * Extend GLib.Variant with a static method to recursively pack a variant + * + * @param {*} [obj] - May be a GLib.Variant, Array, standard Object or literal. + * @return {GLib.Variant} The resulting GVariant + */ +function _full_pack(obj) { + let packed; + const type = typeof obj; + + switch (true) { + case (obj instanceof GLib.Variant): + return obj; + + case (type === 'string'): + return GLib.Variant.new('s', obj); + + case (type === 'number'): + return GLib.Variant.new('d', obj); + + case (type === 'boolean'): + return GLib.Variant.new('b', obj); + + case (obj instanceof Uint8Array): + return GLib.Variant.new('ay', obj); + + case (obj === null): + return GLib.Variant.new('mv', null); + + case (typeof obj.map === 'function'): + return GLib.Variant.new( + 'av', + obj.filter(e => e !== undefined).map(e => _full_pack(e)) + ); + + case (obj instanceof Gio.Icon): + return obj.serialize(); + + case (type === 'object'): + packed = {}; + + for (const [key, val] of Object.entries(obj)) { + if (val !== undefined) + packed[key] = _full_pack(val); + } + + return GLib.Variant.new('a{sv}', packed); + + default: + throw Error(`Unsupported type '${type}': ${obj}`); + } +} + +GLib.Variant.full_pack = _full_pack; + + +/** + * Extend GLib.Variant with a method to recursively deepUnpack() a variant + * + * @param {*} [obj] - May be a GLib.Variant, Array, standard Object or literal. + * @return {*} The resulting object + */ +function _full_unpack(obj) { + obj = (obj === undefined) ? this : obj; + const unpacked = {}; + + switch (true) { + case (obj === null): + return obj; + + case (obj instanceof GLib.Variant): + return _full_unpack(obj.deepUnpack()); + + case (obj instanceof Uint8Array): + return obj; + + case (typeof obj.map === 'function'): + return obj.map(e => _full_unpack(e)); + + case (typeof obj === 'object'): + for (const [key, value] of Object.entries(obj)) { + // Try to detect and deserialize GIcons + try { + if (key === 'icon' && value.get_type_string() === '(sv)') + unpacked[key] = Gio.Icon.deserialize(value); + else + unpacked[key] = _full_unpack(value); + } catch (e) { + unpacked[key] = _full_unpack(value); + } + } + + return unpacked; + + default: + return obj; + } +} + +GLib.Variant.prototype.full_unpack = _full_unpack; + + +/** + * Creates a GTlsCertificate from the PEM-encoded data in @cert_path and + * @key_path. If either are missing a new pair will be generated. + * + * Additionally, the private key will be added using ssh-add to allow sftp + * connections using Gio. + * + * See: https://github.com/KDE/kdeconnect-kde/blob/master/core/kdeconnectconfig.cpp#L119 + * + * @param {string} certPath - Absolute path to a x509 certificate in PEM format + * @param {string} keyPath - Absolute path to a private key in PEM format + * @param {string} commonName - A unique common name for the certificate + * @return {Gio.TlsCertificate} A TLS certificate + */ +Gio.TlsCertificate.new_for_paths = function (certPath, keyPath, commonName = null) { + // Check if the certificate/key pair already exists + const certExists = GLib.file_test(certPath, GLib.FileTest.EXISTS); + const keyExists = GLib.file_test(keyPath, GLib.FileTest.EXISTS); + + // Create a new certificate and private key if necessary + if (!certExists || !keyExists) { + // If we weren't passed a common name, generate a random one + if (!commonName) + commonName = GLib.uuid_string_random(); + + const proc = new Gio.Subprocess({ + argv: [ + Config.OPENSSL_PATH, 'req', + '-new', '-x509', '-sha256', + '-out', certPath, + '-newkey', 'rsa:4096', '-nodes', + '-keyout', keyPath, + '-days', '3650', + '-subj', `/O=andyholmes.github.io/OU=GSConnect/CN=${commonName}`, + ], + flags: (Gio.SubprocessFlags.STDOUT_SILENCE | + Gio.SubprocessFlags.STDERR_SILENCE), + }); + proc.init(null); + proc.wait_check(null); + } + + return Gio.TlsCertificate.new_from_files(certPath, keyPath); +}; + +Object.defineProperties(Gio.TlsCertificate.prototype, { + /** + * The common name of the certificate. + */ + 'common_name': { + get: function () { + if (!this.__common_name) { + const proc = new Gio.Subprocess({ + argv: [Config.OPENSSL_PATH, 'x509', '-noout', '-subject', '-inform', 'pem'], + flags: Gio.SubprocessFlags.STDIN_PIPE | Gio.SubprocessFlags.STDOUT_PIPE, + }); + proc.init(null); + + const stdout = proc.communicate_utf8(this.certificate_pem, null)[1]; + this.__common_name = /(?:cn|CN) ?= ?([^,\n]*)/.exec(stdout)[1]; + } + + return this.__common_name; + }, + configurable: true, + enumerable: true, + }, + + /** + * Get just the pubkey as a DER ByteArray of a certificate. + * + * @return {GLib.Bytes} The pubkey as DER of the certificate. + */ + 'pubkey_der': { + value: function () { + if (!this.__pubkey_der) { + let proc = new Gio.Subprocess({ + argv: [Config.OPENSSL_PATH, 'x509', '-noout', '-pubkey', '-inform', 'pem'], + flags: Gio.SubprocessFlags.STDIN_PIPE | Gio.SubprocessFlags.STDOUT_PIPE, + }); + proc.init(null); + + const pubkey = proc.communicate_utf8(this.certificate_pem, null)[1]; + proc = new Gio.Subprocess({ + argv: [Config.OPENSSL_PATH, 'pkey', '-pubin', '-inform', 'pem', '-outform', 'der'], + flags: Gio.SubprocessFlags.STDIN_PIPE | Gio.SubprocessFlags.STDOUT_PIPE, + }); + proc.init(null); + this.__pubkey_der = proc.communicate(new TextEncoder().encode(pubkey), null)[1]; + } + + return this.__pubkey_der; + }, + configurable: true, + enumerable: false, + }, + +}); diff --git a/gnome/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/index.js b/gnome/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/index.js new file mode 100644 index 0000000..3d304a0 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/index.js @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: GSConnect Developers https://github.com/GSConnect +// +// SPDX-License-Identifier: GPL-2.0-or-later + +import * as battery from './battery.js'; +import * as clipboard from './clipboard.js'; +import * as connectivity_report from './connectivity_report.js'; +import * as contacts from './contacts.js'; +import * as findmyphone from './findmyphone.js'; +import * as mousepad from './mousepad.js'; +import * as mpris from './mpris.js'; +import * as notification from './notification.js'; +import * as ping from './ping.js'; +import * as presenter from './presenter.js'; +import * as runcommand from './runcommand.js'; +import * as sftp from './sftp.js'; +import * as share from './share.js'; +import * as sms from './sms.js'; +import * as systemvolume from './systemvolume.js'; +import * as telephony from './telephony.js'; + +export default { + battery, + clipboard, + connectivity_report, + contacts, + findmyphone, + mousepad, + mpris, + notification, + ping, + presenter, + runcommand, + sftp, + share, + sms, + systemvolume, + telephony, +}; diff --git a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/busUtils.js b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/displayConfigState.js similarity index 53% rename from gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/busUtils.js rename to gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/displayConfigState.js index 6839c8c..97a7af8 100644 --- a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/busUtils.js +++ b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/displayConfigState.js @@ -1,6 +1,6 @@ -/* busUtils.js +/* displayConfigState.js * -* Copyright (C) 2022 kosmospredanie, efosmark +* Copyright (C) 2024 kosmospredanie, shyzus * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,65 +17,11 @@ */ import GLib from 'gi://GLib'; -import Gio from 'gi://Gio'; -export const Methods = Object.freeze({ - 'verify': 0, - 'temporary': 1, - 'persistent': 2 -}); +import { Monitor } from './monitor.js' +import { LogicalMonitor } from './logicalMonitor.js' -export const Monitor = class Monitor { - constructor(variant) { - let unpacked = variant.unpack(); - this.connector = unpacked[0].unpack()[0].unpack(); - - let modes = unpacked[1].unpack(); - for (let i = 0; i < modes.length; i++) { - let mode = modes[i].unpack(); - let id = mode[0].unpack(); - let mode_props = mode[6].unpack(); - if ('is-current' in mode_props) { - let is_current = mode_props['is-current'].unpack().get_boolean(); - if (is_current) { - this.current_mode_id = id; - break; - } - } - } - - let props = unpacked[2].unpack(); - if ('is-underscanning' in props) { - this.is_underscanning = props['is-underscanning'].unpack().get_boolean(); - } else { - this.is_underscanning = false; - } - if ('is-builtin' in props) { - this.is_builtin = props['is-builtin'].unpack().get_boolean(); - } else { - this.is_builtin = false; - } - } -} - -export const LogicalMonitor = class LogicalMonitor { - constructor(variant) { - let unpacked = variant.unpack(); - this.x = unpacked[0].unpack(); - this.y = unpacked[1].unpack(); - this.scale = unpacked[2].unpack(); - this.transform = unpacked[3].unpack(); - this.primary = unpacked[4].unpack(); - // [ [connector, vendor, product, serial]* ] - this.monitors = unpacked[5].deep_unpack(); - this.properties = unpacked[6].unpack(); - for (let key in this.properties) { - this.properties[key] = this.properties[key].unpack().unpack(); - } - } -} - -export const DisplayConfigState = class DisplayConfigState { +export class DisplayConfigState { constructor(result) { let unpacked = result.unpack(); @@ -102,8 +48,7 @@ export const DisplayConfigState = class DisplayConfigState { } get builtin_monitor() { - for (let i = 0; i < this.monitors.length; i++) { - let monitor = this.monitors[i]; + for (let monitor of this.monitors) { if (monitor.is_builtin) { return monitor; } @@ -112,8 +57,7 @@ export const DisplayConfigState = class DisplayConfigState { } get_monitor(connector) { - for (let i = 0; i < this.monitors.length; i++) { - let monitor = this.monitors[i]; + for (let monitor of this.monitors) { if (monitor.connector === connector) { return monitor; } @@ -122,12 +66,10 @@ export const DisplayConfigState = class DisplayConfigState { } get_logical_monitor_for(connector) { - for (let i = 0; i < this.logical_monitors.length; i++) { - let lmonitor = this.logical_monitors[i]; - for (let j = 0; j < lmonitor.monitors.length; j++) { - let lm_connector = lmonitor.monitors[j][0]; - if (connector === lm_connector) { - return lmonitor; + for (let log_monitor of this.logical_monitors) { + for (let lm_monitor of log_monitor.monitors) { + if (connector === lm_monitor[0]) { + return log_monitor; } } } @@ -149,8 +91,8 @@ export const DisplayConfigState = class DisplayConfigState { [] ]; let monitors = lmonitor_pack[5]; - for (let i = 0; i < lmonitor.monitors.length; i++) { - let connector = lmonitor.monitors[i][0]; + for (let log_monitor of lmonitor.monitors) { + let connector = log_monitor[0]; let monitor = this.get_monitor(connector); monitors.push([ connector, diff --git a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/extension.js b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/extension.js index 9b5b509..edf89a0 100644 --- a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/extension.js +++ b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/extension.js @@ -15,197 +15,109 @@ * along with this program. If not, see . */ -import { Extension, gettext as _ } from 'resource:///org/gnome/shell/extensions/extension.js'; - import Gio from 'gi://Gio'; -import GObject from 'gi://GObject'; -import GLib from 'gi://GLib'; -import * as SystemActions from 'resource:///org/gnome/shell/misc/systemActions.js'; +import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; +import * as SystemActions from 'resource:///org/gnome/shell/misc/systemActions.js'; + import * as Rotator from './rotator.js' -import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js'; +import { Orientation } from './orientation.js'; +import { ManualOrientationIndicator } from './manualOrientationIndicator.js'; +import { SensorProxy } from './sensorProxy.js'; const ORIENTATION_LOCK_SCHEMA = 'org.gnome.settings-daemon.peripherals.touchscreen'; const ORIENTATION_LOCK_KEY = 'orientation-lock'; +const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications'; +const SHOW_KEYBOARD = 'screen-keyboard-enabled'; +const PERIPHERAL_TOUCHPAD_SCHEMA = 'org.gnome.desktop.peripherals.touchpad'; +const TOUCHPAD_EVENTS = 'send-events'; -import { QuickMenuToggle, QuickSettingsMenu, SystemIndicator } from 'resource:///org/gnome/shell/ui/quickSettings.js'; - -// Orientation names must match those provided by net.hadess.SensorProxy -const Orientation = Object.freeze({ - 'normal': 0, - 'left-up': 1, - 'bottom-up': 2, - 'right-up': 3 -}); - -const ManualOrientationIndicator = GObject.registerClass( -class ManualOrientationIndicator extends SystemIndicator { - _init(ext_ref) { - super._init(); - this.toggle = new ManualOrientationMenuToggle(ext_ref); - this.quickSettingsItems.push(this.toggle); - } - - destroy() { - this.quickSettingsItems.pop(this.toggle); - this.toggle.destroy(); - } -}); - -const ManualOrientationMenuToggle = GObject.registerClass( -class ManualOrientationMenuToggle extends QuickMenuToggle { - _init(ext) { - super._init({ - title: _('Rotate'), - iconName: 'object-rotate-left-symbolic', - menuEnabled: true, - toggleMode: true, - }); - - this.menu.setHeader('object-rotate-left-symbolic', _('Screen Rotate')); - - this._section = new PopupMenu.PopupMenuSection(); - this.menu.addMenuItem(this._section); - - this.landscapeItem = new PopupMenu.PopupMenuItem('Landscape', { - reactive: true, - can_focus: true, - }); - - this.portraitLeftItem = new PopupMenu.PopupMenuItem('Portrait Left', { - reactive: true, - can_focus: true, - }); - - this.landscapeFlipItem = new PopupMenu.PopupMenuItem('Landscape Flipped', { - reactive: true, - can_focus: true, - }); - - this.portraitRightItem = new PopupMenu.PopupMenuItem('Portrait Right', { - reactive: true, - can_focus: true, - }); - - this.landscapeItem.connect('activate', () => { - this._onItemActivate(this.landscapeItem); - ext.rotate_to('normal'); - }); - this.portraitLeftItem.connect('activate', () => { - this._onItemActivate(this.portraitLeftItem); - ext.rotate_to('left-up'); - }); - this.landscapeFlipItem.connect('activate', () => { - this._onItemActivate(this.landscapeFlipItem); - ext.rotate_to('bottom-up'); - }); - this.portraitRightItem.connect('activate', () => { - this._onItemActivate(this.portraitRightItem); - ext.rotate_to('right-up'); - }); - - this._section.addMenuItem(this.landscapeItem); - this._section.addMenuItem(this.portraitLeftItem); - this._section.addMenuItem(this.landscapeFlipItem); - this._section.addMenuItem(this.portraitRightItem); - - this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); - this.menu.addSettingsAction(_('Extension Settings'), - 'com.mattjakeman.ExtensionManager.desktop'); - - this.connect('clicked', () => { - if (this.checked == true) { - ext.rotate_to('right-up'); - } else { - ext.rotate_to('normal'); - } - }); - } - - _onItemActivate(item) { - this.landscapeItem.setOrnament(PopupMenu.Ornament.HIDDEN); - this.portraitLeftItem.setOrnament(PopupMenu.Ornament.HIDDEN); - this.landscapeFlipItem.setOrnament(PopupMenu.Ornament.HIDDEN); - this.portraitRightItem.setOrnament(PopupMenu.Ornament.HIDDEN); - - item.setOrnament(PopupMenu.Ornament.CHECK); - } -}); - -class SensorProxy { - constructor(rotate_cb) { - this._rotate_cb = rotate_cb; - this._proxy = null; - this._enabled = false; - this._watcher_id = Gio.bus_watch_name( - Gio.BusType.SYSTEM, - 'net.hadess.SensorProxy', - Gio.BusNameWatcherFlags.NONE, - this.appeared.bind(this), - this.vanished.bind(this) - ); - } - - destroy() { - Gio.bus_unwatch_name(this._watcher_id); - if (this._enabled) this.disable(); - this._proxy = null; - } - +export default class ScreenAutoRotateExtension extends Extension { enable() { - this._enabled = true; - if (this._proxy === null) return; - this._proxy.call_sync('ClaimAccelerometer', null, Gio.DBusCallFlags.NONE, -1, null); - } - - disable() { - this._enabled = false; - if (this._proxy === null) return; - this._proxy.call_sync('ReleaseAccelerometer', null, Gio.DBusCallFlags.NONE, -1, null); - } - - appeared(connection, name, name_owner) { - this._proxy = Gio.DBusProxy.new_for_bus_sync( - Gio.BusType.SYSTEM, Gio.DBusProxyFlags.NONE, null, - 'net.hadess.SensorProxy', '/net/hadess/SensorProxy', 'net.hadess.SensorProxy', - null); - this._proxy.connect('g-properties-changed', this.properties_changed.bind(this)); - if (this._enabled) { - this._proxy.call_sync('ClaimAccelerometer', null, Gio.DBusCallFlags.NONE, -1, null); - } - } - - vanished(connection, name) { - this._proxy = null; - } - - properties_changed(proxy, changed, invalidated) { - if (!this._enabled) return; - let properties = changed.deep_unpack(); - for (let [name, value] of Object.entries(properties)) { - if (name != 'AccelerometerOrientation') continue; - let target = value.unpack(); - this._rotate_cb(target); - } - } -} - -class ScreenAutorotate { - constructor(settings) { + this._settings = this.getSettings(); this._system_actions = SystemActions.getDefault(); - this._settings = settings; this._system_actions_backup = null; this._override_system_actions(); + + this._a11yApplicationsSettings = new Gio.Settings({ schema_id: A11Y_APPLICATIONS_SCHEMA }); + this._peripheralTouchpadSettings = new Gio.Settings({ schema_id: PERIPHERAL_TOUCHPAD_SCHEMA }); this._orientation_settings = new Gio.Settings({ schema_id: ORIENTATION_LOCK_SCHEMA }); - this._orientation_settings.connect('changed::' + ORIENTATION_LOCK_KEY, this._orientation_lock_changed.bind(this)); + this._orientation_settings_handler = this._orientation_settings.connect('changed::' + ORIENTATION_LOCK_KEY, this._orientation_lock_changed.bind(this)); this._sensor_proxy = new SensorProxy(this.rotate_to.bind(this)); - this._state = false; // enabled or not + this._state = false; let locked = this._orientation_settings.get_boolean(ORIENTATION_LOCK_KEY); - if (!locked) this.enable(); + if (!locked) { + this.toggle_rotation_lock() + } + + this._manual_flip_settings_handler = this._settings.connect('changed::manual-flip', (settings, key) => { + if (settings.get_boolean(key)) { + this._add_manual_flip(); + } else { + this._remove_manual_flip(); + } + }); + + this._hide_lock_rotate_settings_handler = this._settings.connect('changed::hide-lock-rotate', (settings, key) => { + this._set_hide_lock_rotate(settings.get_boolean(key)); + }); + + if (this._settings.get_boolean('manual-flip')) { + this._add_manual_flip(); + } else { + this._remove_manual_flip(); + } + + /* Timeout needed due to unknown race condition causing 'Auto Rotate' + * Quick Toggle to be undefined for a brief moment. + */ + this._timeoutId = setTimeout(() => { + this._set_hide_lock_rotate(this._settings.get_boolean('hide-lock-rotate')); + }, 1000); + } + + toggle_rotation_lock() { + if (this._state) { + this._a11yApplicationsSettings.set_boolean(SHOW_KEYBOARD, this._originala11yKeyboardSetting); + this._originala11yKeyboardSetting = null; + this._sensor_proxy.disable(); + this._state = false; + } else { + this._originala11yKeyboardSetting = this._a11yApplicationsSettings.get_boolean(SHOW_KEYBOARD); + this._sensor_proxy.enable(); + this._state = true; + } + } + + _set_hide_lock_rotate(state) { + const autoRotateIndicator = Main.panel.statusArea.quickSettings._autoRotate; + + if (state) { + Main.panel.statusArea.quickSettings._indicators.remove_child(autoRotateIndicator); + Main.panel.statusArea.quickSettings.menu._grid.remove_child(autoRotateIndicator.quickSettingsItems[0]); + } else { + Main.panel.statusArea.quickSettings._indicators.add_child(autoRotateIndicator); + Main.panel.statusArea.quickSettings._addItemsBefore( + autoRotateIndicator.quickSettingsItems, + Main.panel.statusArea.quickSettings._rfkill.quickSettingsItems[0] + ); + } + } + + _add_manual_flip() { + this.flipIndicator = new ManualOrientationIndicator(this); + Main.panel.statusArea.quickSettings.addExternalIndicator(this.flipIndicator); + } + + _remove_manual_flip() { + if (this.flipIndicator !== null && this.flipIndicator !== undefined) { + this.flipIndicator.destroy(); + this.flipIndicator = null; + } } _override_system_actions() { @@ -230,34 +142,76 @@ class ScreenAutorotate { _orientation_lock_changed() { let locked = this._orientation_settings.get_boolean(ORIENTATION_LOCK_KEY); - if (this._state == locked) { - this.toggle(); + if (this._state === locked) { + this.toggle_rotation_lock(); } } - destroy() { - this._sensor_proxy.destroy(); - this._orientation_settings = null; - this._restore_system_actions(); - } - - toggle() { - if (this._state) { - this.disable(); - } else { - this.enable(); + _handle_osk(target) { + const landscapeOsk = this._settings.get_boolean('landscape-osk'); + const portraitRightOsk = this._settings.get_boolean('portrait-right-osk'); + const portraitLeftOsk = this._settings.get_boolean('portrait-left-osk'); + const landscapeFlippedOsk = this._settings.get_boolean('landscape-flipped-osk'); + switch (target) { + case 0: + this._a11yApplicationsSettings.set_boolean(SHOW_KEYBOARD, landscapeOsk); + break; + case 1: + this._a11yApplicationsSettings.set_boolean(SHOW_KEYBOARD, portraitLeftOsk); + break; + case 2: + this._a11yApplicationsSettings.set_boolean(SHOW_KEYBOARD, landscapeFlippedOsk); + break; + case 3: + this._a11yApplicationsSettings.set_boolean(SHOW_KEYBOARD, portraitRightOsk); + break; } } - enable() { - this._sensor_proxy.enable(); - this._state = true; - } - disable() { - this._sensor_proxy.disable(); - this._state = false; - } + _handle_dor_touchpad(target) { + const dorLandscape = this._settings.get_boolean('dor-touchpad-landscape'); + const dorPortraitRight = this._settings.get_boolean('dor-touchpad-portrait-right'); + const dorPortraitLeft = this._settings.get_boolean('dor-touchpad-portrait-left'); + const dorLandscapeFlipped = this._settings.get_boolean('dor-touchpad-landscape-flipped'); + let setting_value = undefined; + + switch (target) { + case 0: + if (dorLandscape) { + setting_value = "disabled"; + } else { + setting_value = "enabled"; + } + this._peripheralTouchpadSettings.set_string(TOUCHPAD_EVENTS, setting_value); + break; + case 1: + if (dorPortraitLeft) { + setting_value = "disabled"; + } else { + setting_value = "enabled"; + } + this._peripheralTouchpadSettings.set_string(TOUCHPAD_EVENTS, setting_value); + break; + case 2: + if (dorLandscapeFlipped) { + setting_value = "disabled"; + } else { + setting_value = "enabled"; + } + this._peripheralTouchpadSettings.set_string(TOUCHPAD_EVENTS, setting_value); + break; + case 3: + if (dorPortraitRight) { + setting_value = "disabled"; + } else { + setting_value = "enabled"; + } + this._peripheralTouchpadSettings.set_string(TOUCHPAD_EVENTS, setting_value); + break; + } + } + rotate_to(orientation) { const sensor = Orientation[orientation]; const invert_horizontal_direction = this._settings.get_boolean('invert-horizontal-rotation-direction'); @@ -294,70 +248,13 @@ class ScreenAutorotate { target = (target + offset) % 4; if (this._settings.get_boolean('debug-logging')) { - console.debug(`sensor=${Orientation[orientation]}`); - console.debug(`offset=${offset}`); - console.debug(`target=${target}`); + console.log(`sensor=${Orientation[orientation]}`); + console.log(`offset=${offset}`); + console.log(`target=${target}`); } Rotator.rotate_to(target); - } -} - -export default class ScreenAutoRotateExtension extends Extension { - enable() { - this._settings = this.getSettings(); - this._ext = new ScreenAutorotate(this._settings); - - this._settings.connect('changed::manual-flip', (settings, key) => { - if (settings.get_boolean(key)) { - this._add_manual_flip(); - } else { - this._remove_manual_flip(); - } - }); - - this._settings.connect('changed::hide-lock-rotate', (settings, key) => { - this._set_hide_lock_rotate(settings.get_boolean(key)); - }); - - if (this._settings.get_boolean('manual-flip')) { - this._add_manual_flip(); - } else { - this._remove_manual_flip(); - } - - /* Timeout needed due to unknown race condition causing 'Auto Rotate' - * Quick Toggle to be undefined for a brief moment. - */ - this._timeoutId = setTimeout(() => { - this._set_hide_lock_rotate(this._settings.get_boolean('hide-lock-rotate')); - }, 1000); - } - - _set_hide_lock_rotate(state) { - const autoRotateIndicator = Main.panel.statusArea.quickSettings._autoRotate; - - if (state) { - Main.panel.statusArea.quickSettings._indicators.remove_child(autoRotateIndicator); - Main.panel.statusArea.quickSettings.menu._grid.remove_child(autoRotateIndicator.quickSettingsItems[0]); - } else { - Main.panel.statusArea.quickSettings._indicators.add_child(autoRotateIndicator); - Main.panel.statusArea.quickSettings._addItemsBefore( - autoRotateIndicator.quickSettingsItems, - Main.panel.statusArea.quickSettings._rfkill.quickSettingsItems[0] - ); - } - } - - _add_manual_flip() { - this.flipIndicator = new ManualOrientationIndicator(this._ext); - Main.panel.statusArea.quickSettings.addExternalIndicator(this.flipIndicator); - } - - _remove_manual_flip() { - if (this.flipIndicator != null) { - this.flipIndicator.destroy(); - this.flipIndicator = null; - } + this._handle_osk(target); + this._handle_dor_touchpad(target); } disable() { @@ -368,12 +265,17 @@ export default class ScreenAutoRotateExtension extends Extension { have auto-locked. This provides the ability to log back in regardless of the orientation of the device in tablet mode. */ + this._settings.disconnect(this._manual_flip_settings_handler); + this._settings.disconnect(this._hide_lock_rotate_settings_handler); this._settings = null; clearTimeout(this._timeoutId); this._timeoutId = null; this._remove_manual_flip(); - this._ext.destroy(); - this._ext = null; + this._sensor_proxy.destroy(); + this._orientation_settings.disconnect(this._orientation_settings_handler); + this._orientation_settings = null; + this._a11yApplicationsSettings = null; + this._restore_system_actions(); } } diff --git a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/logicalMonitor.js b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/logicalMonitor.js new file mode 100644 index 0000000..5862e49 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/logicalMonitor.js @@ -0,0 +1,34 @@ +/* logicalMonitor.js +* +* Copyright (C) 2024 kosmospredanie, shyzus +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* 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. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +export class LogicalMonitor { + constructor(variant) { + let unpacked = variant.unpack(); + this.x = unpacked[0].unpack(); + this.y = unpacked[1].unpack(); + this.scale = unpacked[2].unpack(); + this.transform = unpacked[3].unpack(); + this.primary = unpacked[4].unpack(); + // [ [connector, vendor, product, serial]* ] + this.monitors = unpacked[5].deep_unpack(); + this.properties = unpacked[6].unpack(); + for (let key in this.properties) { + this.properties[key] = this.properties[key].unpack().unpack(); + } + } +} diff --git a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/manualOrientationIndicator.js b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/manualOrientationIndicator.js new file mode 100644 index 0000000..2e2c20e --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/manualOrientationIndicator.js @@ -0,0 +1,36 @@ +/* manualOrientationIndicator.js +* Copyright (C) 2024 shyzus +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* 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. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +import GObject from 'gi://GObject'; + +import { SystemIndicator } from 'resource:///org/gnome/shell/ui/quickSettings.js'; + +import { ManualOrientationMenuToggle } from './manualOrientationMenuToggle.js'; + +export const ManualOrientationIndicator = GObject.registerClass( +class ManualOrientationIndicator extends SystemIndicator { + constructor(ext) { + super(); + this.toggle = new ManualOrientationMenuToggle(ext); + this.quickSettingsItems.push(this.toggle); + } + + destroy() { + this.quickSettingsItems.pop(this.toggle); + this.toggle.destroy(); + } +}); diff --git a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/manualOrientationMenuToggle.js b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/manualOrientationMenuToggle.js new file mode 100644 index 0000000..d7f6a14 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/manualOrientationMenuToggle.js @@ -0,0 +1,102 @@ +/* manualOrientationMenuToggle.js +* Copyright (C) 2024 shyzus +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* 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. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +import GObject from 'gi://GObject'; + +import { QuickMenuToggle } from 'resource:///org/gnome/shell/ui/quickSettings.js'; +import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js'; + +export const ManualOrientationMenuToggle = GObject.registerClass( +class ManualOrientationMenuToggle extends QuickMenuToggle { + constructor(ext) { + super({ + title: 'Rotate', + iconName: 'object-rotate-left-symbolic', + menuEnabled: true, + toggleMode: true, + }); + + this.menu.setHeader('object-rotate-left-symbolic', 'Screen Rotate'); + + this._section = new PopupMenu.PopupMenuSection(); + this.menu.addMenuItem(this._section); + + this.landscapeItem = new PopupMenu.PopupMenuItem('Landscape', { + reactive: true, + can_focus: true, + }); + + this.portraitLeftItem = new PopupMenu.PopupMenuItem('Portrait Left', { + reactive: true, + can_focus: true, + }); + + this.landscapeFlipItem = new PopupMenu.PopupMenuItem('Landscape Flipped', { + reactive: true, + can_focus: true, + }); + + this.portraitRightItem = new PopupMenu.PopupMenuItem('Portrait Right', { + reactive: true, + can_focus: true, + }); + + this.landscapeItem.connect('activate', () => { + this._onItemActivate(this.landscapeItem); + ext.rotate_to('normal'); + }); + this.portraitLeftItem.connect('activate', () => { + this._onItemActivate(this.portraitLeftItem); + ext.rotate_to('left-up'); + }); + this.landscapeFlipItem.connect('activate', () => { + this._onItemActivate(this.landscapeFlipItem); + ext.rotate_to('bottom-up'); + }); + this.portraitRightItem.connect('activate', () => { + this._onItemActivate(this.portraitRightItem); + ext.rotate_to('right-up'); + }); + + this._section.addMenuItem(this.landscapeItem); + this._section.addMenuItem(this.portraitLeftItem); + this._section.addMenuItem(this.landscapeFlipItem); + this._section.addMenuItem(this.portraitRightItem); + + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + this.menu.addSettingsAction('Extension Settings', + 'com.mattjakeman.ExtensionManager.desktop'); + + this.connect('clicked', () => { + if (this.checked === true) { + ext.rotate_to('right-up'); + } else { + ext.rotate_to('normal'); + } + }); + } + + _onItemActivate(item) { + this.landscapeItem.setOrnament(PopupMenu.Ornament.HIDDEN); + this.portraitLeftItem.setOrnament(PopupMenu.Ornament.HIDDEN); + this.landscapeFlipItem.setOrnament(PopupMenu.Ornament.HIDDEN); + this.portraitRightItem.setOrnament(PopupMenu.Ornament.HIDDEN); + + item.setOrnament(PopupMenu.Ornament.CHECK); + } +}); + diff --git a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/metadata.json b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/metadata.json index 69547d5..aa7faf1 100644 --- a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/metadata.json +++ b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/metadata.json @@ -10,9 +10,10 @@ "settings-schema": "org.gnome.shell.extensions.screen-rotate", "shell-version": [ "45", - "46" + "46", + "47" ], "url": "https://github.com/shyzus/gnome-shell-extension-screen-autorotate", "uuid": "screen-rotate@shyzus.github.io", - "version": 19 + "version": 24 } \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/monitor.js b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/monitor.js new file mode 100644 index 0000000..369217f --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/monitor.js @@ -0,0 +1,50 @@ +/* monitor.js +* +* Copyright (C) 2024 kosmospredanie, efosmark, shyzus +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* 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. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +export class Monitor { + constructor(variant) { + let unpacked = variant.unpack(); + this.connector = unpacked[0].unpack()[0].unpack(); + + let modes = unpacked[1].unpack(); + for (let mode_idx in modes) { + let mode = modes[mode_idx].unpack(); + let id = mode[0].unpack(); + let mode_props = mode[6].unpack(); + if ('is-current' in mode_props) { + let is_current = mode_props['is-current'].unpack().get_boolean(); + if (is_current) { + this.current_mode_id = id; + break; + } + } + } + + let props = unpacked[2].unpack(); + if ('is-underscanning' in props) { + this.is_underscanning = props['is-underscanning'].unpack().get_boolean(); + } else { + this.is_underscanning = false; + } + if ('is-builtin' in props) { + this.is_builtin = props['is-builtin'].unpack().get_boolean(); + } else { + this.is_builtin = false; + } + } +} diff --git a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/orientation.js b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/orientation.js new file mode 100644 index 0000000..bbd47f4 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/orientation.js @@ -0,0 +1,24 @@ +/* orientation.js +* Copyright (C) 2024 shyzus +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* 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. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +// Orientation names must match those provided by net.hadess.SensorProxy +export const Orientation = Object.freeze({ + 'normal': 0, + 'left-up': 1, + 'bottom-up': 2, + 'right-up': 3 +}); diff --git a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/prefs.js b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/prefs.js index 85c2e6c..d28b383 100644 --- a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/prefs.js +++ b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/prefs.js @@ -21,6 +21,8 @@ import Adw from 'gi://Adw'; import { ExtensionPreferences } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'; +import { Orientation } from './orientation.js'; + export default class MyExtensionPreferences extends ExtensionPreferences { fillPreferencesWindow(window) { @@ -37,6 +39,14 @@ export default class MyExtensionPreferences extends ExtensionPreferences { shellMenuGroup.set_title('GNOME Shell Menu Settings'); page.add(shellMenuGroup); + const oskSettingsGroup = new Adw.PreferencesGroup(); + oskSettingsGroup.set_title('On-Screen-Keyboard Settings'); + page.add(oskSettingsGroup); + + const disableOnRotateGroup = new Adw.PreferencesGroup(); + disableOnRotateGroup.set_title('Disable-On-Rotation Settings'); + page.add(disableOnRotateGroup); + const debugGroup = new Adw.PreferencesGroup(); debugGroup.set_title('Debug Settings'); page.add(debugGroup); @@ -59,9 +69,10 @@ export default class MyExtensionPreferences extends ExtensionPreferences { const setOffsetRow = new Adw.ActionRow({ title: 'Set orientation offset', - subtitle: 'Valid offset range: 0 to 3. Default is 0\nExperiment with this in case\ - orientation is incorrect due to the display being mounted in a non-landscape orientation\ - e.g PineTab2 or GPD Pocket 3' + subtitle: 'Valid offset range: 0 to 3. Default is 0\nExperiment with' + + ' this in case orientation is incorrect due to the display' + + ' being mounted in a non-landscape orientation' + + ' e.g PineTab2 or GPD Pocket 3' }); orientationGroup.add(setOffsetRow); @@ -77,6 +88,26 @@ export default class MyExtensionPreferences extends ExtensionPreferences { }); shellMenuGroup.add(hideLockRotateRow); + const landscapeOskRow = new Adw.ActionRow({ + title: 'Show OSK in landscape orientation' + }); + oskSettingsGroup.add(landscapeOskRow); + + const portraitRightOskRow = new Adw.ActionRow({ + title: 'Show OSK in portrait (right) orientation' + }); + oskSettingsGroup.add(portraitRightOskRow); + + const landscapeFlippedOskRow = new Adw.ActionRow({ + title: 'Show OSK in landscape (flipped) orientation' + }); + oskSettingsGroup.add(landscapeFlippedOskRow); + + const portraitLeftOskRow = new Adw.ActionRow({ + title: 'Show OSK in portrait (left) orientation' + }); + oskSettingsGroup.add(portraitLeftOskRow); + const toggleLoggingRow = new Adw.ActionRow({ title: 'Enable debug logging', subtitle: 'Use "journalctl /usr/bin/gnome-shell -f" to see log output.' @@ -111,6 +142,125 @@ export default class MyExtensionPreferences extends ExtensionPreferences { valign: Gtk.Align.CENTER, }); + const landscapeOskCheckButton = new Gtk.CheckButton({ + active: window._settings.get_boolean('landscape-osk'), + valign: Gtk.Align.CENTER + }); + + const portraitRightOskCheckButton = new Gtk.CheckButton({ + active: window._settings.get_boolean('portrait-right-osk'), + valign: Gtk.Align.CENTER + }); + + const portraitLeftOskCheckButton = new Gtk.CheckButton({ + active: window._settings.get_boolean('portrait-left-osk'), + valign: Gtk.Align.CENTER + }); + + const landscapeFlippedOskCheckButton = new Gtk.CheckButton({ + active: window._settings.get_boolean('landscape-flipped-osk'), + valign: Gtk.Align.CENTER + }); + + const dorNotebook = new Gtk.Notebook(); + + const dorKeyboardPage = new Gtk.ListBox(); + dorKeyboardPage.set_visible(false); // Keep hidden until feature can be implemented. + dorKeyboardPage.set_selection_mode(Gtk.SelectionMode.NONE); + + for (let orientation in Orientation) { + let actionRowTitle = undefined; + let checkButtonBoolId = undefined; + + switch (orientation) { + case 'normal': + actionRowTitle = "Landscape"; + checkButtonBoolId = "dor-keyboard-landscape"; + break; + case 'left-up': + actionRowTitle = "Portrait (Left)"; + checkButtonBoolId = "dor-keyboard-portrait-left"; + break; + case 'bottom-up': + actionRowTitle = "Landscape Flipped"; + checkButtonBoolId = "dor-keyboard-landscape-flipped"; + break; + case 'right-up': + actionRowTitle = "Portrait (Right)"; + checkButtonBoolId = "dor-keyboard-portrait-right"; + break; + } + + const dorActionRow = new Adw.ActionRow({ + title: actionRowTitle + }); + + const dorCheckButton = new Gtk.CheckButton({ + active: window._settings.get_boolean(checkButtonBoolId), + valign: Gtk.Align.CENTER + }); + + window._settings.bind(checkButtonBoolId, + dorCheckButton, 'active', Gio.SettingsBindFlags.DEFAULT); + + dorActionRow.add_suffix(dorCheckButton); + dorActionRow.activatable_widget = dorCheckButton; + + dorKeyboardPage.append(dorActionRow); + } + + const dorTouchpadPage = new Gtk.ListBox(); + dorTouchpadPage.set_selection_mode(Gtk.SelectionMode.NONE); + + for (let orientation in Orientation) { + let actionRowTitle = undefined; + let checkButtonBoolId = undefined; + + switch (orientation) { + case 'normal': + actionRowTitle = "Landscape"; + checkButtonBoolId = "dor-touchpad-landscape"; + break; + case 'left-up': + actionRowTitle = "Portrait (Left)"; + checkButtonBoolId = "dor-touchpad-portrait-left"; + break; + case 'bottom-up': + actionRowTitle = "Landscape Flipped"; + checkButtonBoolId = "dor-touchpad-landscape-flipped"; + break; + case 'right-up': + actionRowTitle = "Portrait (Right)"; + checkButtonBoolId = "dor-touchpad-portrait-right"; + break; + } + + const dorActionRow = new Adw.ActionRow({ + title: actionRowTitle + }); + + const dorCheckButton = new Gtk.CheckButton({ + active: window._settings.get_boolean(checkButtonBoolId), + valign: Gtk.Align.CENTER + }); + + window._settings.bind(checkButtonBoolId, + dorCheckButton, 'active', Gio.SettingsBindFlags.DEFAULT); + + dorActionRow.add_suffix(dorCheckButton); + dorActionRow.activatable_widget = dorCheckButton; + + dorTouchpadPage.append(dorActionRow); + } + + const dorKeyboardLabel = Gtk.Label.new('Keyboard'); + dorNotebook.append_page(dorKeyboardPage, dorKeyboardLabel); + + const dorTouchpadLabel = Gtk.Label.new('Touchpad'); + dorNotebook.append_page(dorTouchpadPage, dorTouchpadLabel) + + disableOnRotateGroup.add(dorNotebook); + const toggleLoggingSwitch = new Gtk.Switch({ active: window._settings.get_boolean('debug-logging'), valign: Gtk.Align.CENTER @@ -134,6 +284,18 @@ export default class MyExtensionPreferences extends ExtensionPreferences { window._settings.bind('hide-lock-rotate', hideLockRotateSwitch, 'active', Gio.SettingsBindFlags.DEFAULT); + window._settings.bind('landscape-osk', + landscapeOskCheckButton, 'active', Gio.SettingsBindFlags.DEFAULT); + + window._settings.bind('portrait-right-osk', + portraitRightOskCheckButton, 'active', Gio.SettingsBindFlags.DEFAULT); + + window._settings.bind('portrait-left-osk', + portraitLeftOskCheckButton, 'active', Gio.SettingsBindFlags.DEFAULT); + + window._settings.bind('landscape-flipped-osk', + landscapeFlippedOskCheckButton, 'active', Gio.SettingsBindFlags.DEFAULT); + window._settings.bind('debug-logging', toggleLoggingSwitch, 'active', Gio.SettingsBindFlags.DEFAULT); @@ -155,6 +317,18 @@ export default class MyExtensionPreferences extends ExtensionPreferences { hideLockRotateRow.add_suffix(hideLockRotateSwitch); hideLockRotateRow.activatable_widget = hideLockRotateSwitch; + landscapeOskRow.add_suffix(landscapeOskCheckButton); + landscapeOskRow.activatable_widget = landscapeOskCheckButton; + + portraitRightOskRow.add_suffix(portraitRightOskCheckButton); + portraitRightOskRow.activatable_widget = portraitRightOskCheckButton; + + portraitLeftOskRow.add_suffix(portraitLeftOskCheckButton); + portraitLeftOskRow.activatable_widget = portraitLeftOskCheckButton; + + landscapeFlippedOskRow.add_suffix(landscapeFlippedOskCheckButton); + landscapeFlippedOskRow.activatable_widget = landscapeFlippedOskCheckButton; + toggleLoggingRow.add_suffix(toggleLoggingSwitch); toggleLoggingRow.activatable_widget = toggleLoggingSwitch; } diff --git a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/rotator.js b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/rotator.js index 6a104ee..c2e3c57 100644 --- a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/rotator.js +++ b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/rotator.js @@ -17,11 +17,18 @@ */ import Gio from 'gi://Gio'; -import * as BusUtils from './busUtils.js'; +import { DisplayConfigState } from './displayConfigState.js' + const connection = Gio.DBus.session; -export function call_dbus_method(method, params = null, handler) { - if (handler != undefined || handler != null) { +export const Methods = Object.freeze({ + 'verify': 0, + 'temporary': 1, + 'persistent': 2 +}); + +export function call_dbus_method(method, handler, params = null) { + if (handler !== undefined || handler !== null) { connection.call( 'org.gnome.Mutter.DisplayConfig', '/org/gnome/Mutter/DisplayConfig', @@ -49,10 +56,10 @@ export function call_dbus_method(method, params = null, handler) { export function get_state() { return new Promise((resolve, reject) => { - call_dbus_method('GetCurrentState', null, (connection, res) => { + call_dbus_method('GetCurrentState', (conn, res) => { try { - let reply = connection.call_finish(res); - let configState = new BusUtils.DisplayConfigState(reply) + let reply = conn.call_finish(res); + let configState = new DisplayConfigState(reply) resolve(configState); } catch (err) { reject(err); @@ -65,13 +72,13 @@ export function get_state() { export function rotate_to(transform) { this.get_state().then(state => { let target_monitor = state.builtin_monitor; - if (target_monitor == undefined) { + if (target_monitor === undefined) { target_monitor = state.monitors[0] } let logical_monitor = state.get_logical_monitor_for(target_monitor.connector); logical_monitor.transform = transform; - let variant = state.pack_to_apply(BusUtils.Methods['temporary']); - call_dbus_method('ApplyMonitorsConfig', variant); + let variant = state.pack_to_apply(this.Methods['temporary']); + call_dbus_method('ApplyMonitorsConfig', null, variant); }).catch(err => { console.error(err); }) diff --git a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/schemas/gschemas.compiled b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/schemas/gschemas.compiled index 4e7e366..5404d4b 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/schemas/gschemas.compiled and b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/schemas/gschemas.compiled differ diff --git a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/schemas/org.gnome.shell.extensions.screen-rotate.gschema.xml b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/schemas/org.gnome.shell.extensions.screen-rotate.gschema.xml index 0eeb5f6..56fecdb 100644 --- a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/schemas/org.gnome.shell.extensions.screen-rotate.gschema.xml +++ b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/schemas/org.gnome.shell.extensions.screen-rotate.gschema.xml @@ -1,21 +1,3 @@ - false Enable a toggle in the GNOME Shell System Menu to manually flip between landscape and portrait. - + + false Hide the 'Auto Rotate' quick toggle. + + false + Enable the use of the On-Screen-Keyboard for the landscape orientation. + + + false + Enable the use of the On-Screen-Keyboard for the portrait (right) orientation. + + + false + Enable the use of the On-Screen-Keyboard for the portrait (left) orientation. + + + false + Enable the use of the On-Screen-Keyboard for the landscape (flipped) orientation. + + + false + Toggle disabling the keyboard when the orientation is landscape. + + + false + Toggle disabling the keyboard when the orientation is portrait left. + + + false + Toggle disabling the keyboard when the orientation is landscape-flipped. + + + false + Toggle disabling the keyboard when the orientation is portrait right. + + + false + Toggle disabling the touchpad when the orientation is landscape. + + + false + Toggle disabling the touchpad when the orientation is portrait left. + + + false + Toggle disabling the touchpad when the orientation is landscape-flipped. + + + false + Toggle disabling the touchpad when the orientation is portrait right. + false Toggle debug logging. diff --git a/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/sensorProxy.js b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/sensorProxy.js new file mode 100644 index 0000000..93c5505 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/screen-rotate@shyzus.github.io/sensorProxy.js @@ -0,0 +1,76 @@ +/* sensorProxy.js +* Copyright (C) 2024 kosmospredanie, shyzus +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* 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. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +import Gio from 'gi://Gio'; + +export class SensorProxy { + constructor(rotate_cb) { + this._rotate_cb = rotate_cb; + this._proxy = null; + this._enabled = false; + this._watcher_id = Gio.bus_watch_name( + Gio.BusType.SYSTEM, + 'net.hadess.SensorProxy', + Gio.BusNameWatcherFlags.NONE, + this.appeared.bind(this), + this.vanished.bind(this) + ); + } + + destroy() { + Gio.bus_unwatch_name(this._watcher_id); + if (this._enabled) this.disable(); + this._proxy = null; + } + + enable() { + this._enabled = true; + if (this._proxy === null) return; + this._proxy.call_sync('ClaimAccelerometer', null, Gio.DBusCallFlags.NONE, -1, null); + } + + disable() { + this._enabled = false; + if (this._proxy === null) return; + this._proxy.call_sync('ReleaseAccelerometer', null, Gio.DBusCallFlags.NONE, -1, null); + } + + appeared(_connection, _name, _name_owner) { + this._proxy = Gio.DBusProxy.new_for_bus_sync( + Gio.BusType.SYSTEM, Gio.DBusProxyFlags.NONE, null, + 'net.hadess.SensorProxy', '/net/hadess/SensorProxy', 'net.hadess.SensorProxy', + null); + this._proxy.connect('g-properties-changed', this.properties_changed.bind(this)); + if (this._enabled) { + this._proxy.call_sync('ClaimAccelerometer', null, Gio.DBusCallFlags.NONE, -1, null); + } + } + + vanished(_connection, _name) { + this._proxy = null; + } + + properties_changed(proxy, changed, _invalidated) { + if (!this._enabled) return; + let properties = changed.deep_unpack(); + for (let [name, value] of Object.entries(properties)) { + if (name !== 'AccelerometerOrientation') continue; + let target = value.unpack(); + this._rotate_cb(target); + } + } +} diff --git a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/CHANGELOG.md b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/CHANGELOG.md index 7a7be63..6289aff 100644 --- a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/CHANGELOG.md +++ b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/CHANGELOG.md @@ -29,7 +29,7 @@ other: Other ## [v3] - 2022-02-05 ### Added -- Add alernatives thresholds paths. +- Add alternatives thresholds paths. - Add available flag and the _init code is restructured according to this addition... Now the submenu is shown even if the thresholds are not available. ### Fixed - Fix _available function. The test whether the files exist points to the start file twice! @@ -240,7 +240,7 @@ other: Other ## [v36] - 2023-10-10 ### Fixed - Remove "this" in prefs.js (Thanks Just Perfection) -- Remove "run_dispose()" in driver.js and inicator.js (Thanks Just Perfection) +- Remove "run_dispose()" in driver.js and indicator.js (Thanks Just Perfection) ## [v37] - 2023-10-13 ### Performance @@ -275,4 +275,28 @@ other: Other ## [v44] - 2024-03-20 ### Added -- Gnome 46 support \ No newline at end of file +- Gnome 46 support + +## [v45] - 2024-05-18 +### Fixed +- Issue [#20](https://gitlab.com/marcosdalvarez/thinkpad-battery-threshold-extension/-/issues/20): On some models the start threshold 0 is not allowed, instead 95 is used (Ex: P14s Gen 2a) + +## [v46] - 2024-08-02 +### Added +- Automatic detection of start threshold value disabled +- Show a notification and different indicator if the current thresholds are not set (suggestion #21) +- Gnome 47 support + +## [v47] - 2024-08-03 +### Fixed +- Issue [#23](https://gitlab.com/marcosdalvarez/thinkpad-battery-threshold-extension/-/issues/23): Indicator mode NEVER does not work + +## [v48] - 2024-08-07 +### Other +- Update translations + +## [v49] - 2024-08-08 +### Fixed +- Issue [#24](https://gitlab.com/marcosdalvarez/thinkpad-battery-threshold-extension/-/issues/24): The "NEVER" indicator mode does not work properly +### Changed +- "Automatic threshold detection disabled" is not convenient (no way to know the status before it is disabled for the first time), we returns to "model detection mode" and keeps "manual mode" (user settings) \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/icons/threshold-active-warning-symbolic.svg b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/icons/threshold-active-warning-symbolic.svg new file mode 100644 index 0000000..e308010 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/icons/threshold-active-warning-symbolic.svg @@ -0,0 +1,53 @@ + + + + + + + + diff --git a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/icons/threshold-active-warning.svg b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/icons/threshold-active-warning.svg new file mode 100644 index 0000000..fd33df2 --- /dev/null +++ b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/icons/threshold-active-warning.svg @@ -0,0 +1,52 @@ + + + + + + + + diff --git a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/libs/driver.js b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/libs/driver.js index f19e4e0..a1dd52c 100644 --- a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/libs/driver.js +++ b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/libs/driver.js @@ -11,6 +11,14 @@ import GLib from 'gi://GLib'; import GObject from 'gi://GObject'; import Gio from 'gi://Gio'; +/* + * On some models the start threshold 0 is not allowed, instead 95 is used (Ex: E14 Gen 3) + * See issues: + * #8: https://gitlab.com/marcosdalvarez/thinkpad-battery-threshold-extension/-/issues/8 + * #20: https://gitlab.com/marcosdalvarez/thinkpad-battery-threshold-extension/-/issues/20 + */ +const ALTERNATIVE_DISABLED_START = /(Think[pP]ad) (E14 Gen 3|P14s Gen 2a)/; + // Driver constants const BASE_PATH = '/sys/class/power_supply'; const START_FILE_OLD = 'charge_start_threshold'; // kernel 4.17 and newer @@ -24,7 +32,7 @@ const END_FILE_NEW = 'charge_control_end_threshold'; // kernel 5.9 and newer * @param {string} path Path of file * @returns {string} File contents */ -const readFile = function(path) { +const readFile = function (path) { try { const f = Gio.File.new_for_path(path); const [, contents,] = f.load_contents(null); @@ -41,7 +49,7 @@ const readFile = function(path) { * @param {string} path Path of file * @returns {number|null} Return a integer or null */ -const readFileInt = function(path) { +const readFileInt = function (path) { try { const v = readFile(path); if (v) { @@ -52,15 +60,15 @@ const readFileInt = function(path) { } catch (e) { return null; } -} +} /** - * Test file/direcory exists + * Test file/directory exists * * @param {string} path File/directory path * @returns {boolean} */ -const fileExists = function(path) { +const fileExists = function (path) { try { const f = Gio.File.new_for_path(path); return f.query_exists(null); @@ -79,7 +87,7 @@ const Environment = GObject.registerClass({ get productVersion() { if (this._productVersion === undefined) { const tmp = readFile('/sys/class/dmi/id/product_version'); - if (tmp) { + if (tmp) { // Remove non-alphanumeric characters const sanitize = /([^ A-Za-z0-9])+/g; this._productVersion = tmp.replace(sanitize, ''); @@ -109,23 +117,23 @@ const Environment = GObject.registerClass({ get kernelMajorVersion() { if (this._kernelMajorVersion === undefined) { - [this._kernelMajorVersion , this._kernelMinorVersion] = this.kernelRelease.split('.', 2); + [this._kernelMajorVersion, this._kernelMinorVersion] = this.kernelRelease.split('.', 2); } return this._kernelMajorVersion; } get kernelMinorVersion() { if (this._kernelMinorVersion === undefined) { - [this._kernelMajorVersion , this._kernelMinorVersion] = this.kernelRelease.split('.', 2); + [this._kernelMajorVersion, this._kernelMinorVersion] = this.kernelRelease.split('.', 2); } return this._kernelMinorVersion; } checkMinKernelVersion(major, minor) { return ( - this.kernelMajorVersion > major || - (this,this.kernelMajorVersion === major && this.kernelMinorVersion >= minor) - ); + this.kernelMajorVersion > major || + (this.kernelMajorVersion === major && this.kernelMinorVersion >= minor) + ); } }); @@ -140,7 +148,7 @@ const Runnable = GObject.registerClass({ GTypeName: 'Runnable', Signals: { 'command-completed': { - param_types: [GObject.TYPE_JSOBJECT /* erro */] + param_types: [GObject.TYPE_JSOBJECT /* error */] } } }, class Runnable extends GObject.Object { @@ -167,8 +175,8 @@ const Runnable = GObject.registerClass({ try { GLib.spawn_check_exit_status(status); this.emit('command-completed', null); - } catch(e) { - if (e.code == 126) { + } catch (e) { + if (e.code == 126) { // Cancelled } else { logError(e); @@ -272,13 +280,6 @@ export const ThinkPadBattery = GObject.registerClass({ throw Error('Battery name not defined'); } - // Signals handlers IDs - this._monitorId = null; - this._settingStartId = null; - this._settingEndId = null; - this._startId = null; - this._endId = null; - // Battery directory this._baseDirectoryPath = `${BASE_PATH}/${this.name}`; this._baseDirectory = Gio.File.new_for_path(this._baseDirectoryPath); @@ -334,28 +335,29 @@ export const ThinkPadBattery = GObject.registerClass({ // Update flags on changes in threshold values this._startId = this.connect( 'notify::start-value', () => { - this.isActive = this._checkActive(); - this.isAvailable = this.startValue !== null || this.endValue !== null; - this.pendingChanges = this._checkPendingChanges(); + this._updateStatuses(); } ); this._endId = this.connect( 'notify::end-value', () => { - this.isActive = this._checkActive(); - this.isAvailable = this.startValue !== null || this.endValue !== null; - this.pendingChanges = this._checkPendingChanges(); + this._updateStatuses(); } ); - // Update pending changes flag on changes to setting values this._settingStartId = this.settings.connect( `changed::start-${this.name.toLowerCase()}`, () => { - this.pendingChanges = this._checkPendingChanges(); + this._updateStatuses(); } ); this._settingEndId = this.settings.connect( `changed::end-${this.name.toLowerCase()}`, () => { - this.pendingChanges = this._checkPendingChanges(); + this._updateStatuses(); + } + ); + + this._settingDisabledValueId = this.settings.connect( + `changed::disabled-start-${this.name.toLowerCase()}-value`, () => { + this._updateStatuses(); } ); @@ -366,33 +368,34 @@ export const ThinkPadBattery = GObject.registerClass({ } /** - * Check if thresholds is active - * - * @returns {boolean} Returns true if the battery has active thresholds + * Update the statuses */ - _checkActive() { - // RegExs - /* On some models the start threshold 0 is not allowed, instead 95 is used (Ex: E14 Gen 3) - * See issue #8: https://gitlab.com/marcosdalvarez/thinkpad-battery-threshold-extension/-/issues/8 - */ - const disableStart95 = /(Think[pP]ad) (E14 Gen 3)/; + _updateStatuses() { + // Check if is available + this.isAvailable = this.startValue !== null || this.endValue !== null; - if (this.environment.productVersion.search(disableStart95) >= 0) { - return (this.startValue !== 95 && this.startValue !== null) || (this.endValue !== 100 && this.endValue !== null); + // Check if thresholds is active + const disabledStartValue = this.settings.get_int(`disabled-start-${this.name.toLowerCase()}-value`); + if (disabledStartValue === -1) { + // Use model detection + if (this.environment.productVersion.search(ALTERNATIVE_DISABLED_START) >= 0) { + this.isActive = (this.startValue !== null && this.startValue !== 95) || (this.endValue !== null && this.endValue !== 100); + } else { + this.isActive = (this.startValue !== null && this.startValue !== 0) || (this.endValue !== null && this.endValue !== 100); + } } else { - return (this.startValue !== 0 && this.startValue !== null) || (this.endValue !== 100 && this.endValue !== null); + // Use user settings + this.isActive = (this.startValue !== null && this.startValue !== disabledStartValue) || (this.endValue !== null && this.endValue !== 100); } - } - /** - * Check if there are changes to the settings that need to be applied - * - * @returns {boolean} Returns true if there are changes to the settings that need to be applied - */ - _checkPendingChanges() { const startSetting = this.settings.get_int(`start-${this.name.toLowerCase()}`); const endSetting = this.settings.get_int(`end-${this.name.toLowerCase()}`); - return ((this.startValue != null && this.startValue !== startSetting) || (this.endValue != null && this.endValue !== endSetting)); + if (this.isActive) { + this.pendingChanges = (this.startValue !== null && this.startValue !== startSetting) || (this.endValue !== null && this.endValue !== endSetting); + } else { + this.pendingChanges = false; + } + } /** @@ -419,7 +422,7 @@ export const ThinkPadBattery = GObject.registerClass({ } } catch (e) { // Ignored - } + } return false; } @@ -446,12 +449,12 @@ export const ThinkPadBattery = GObject.registerClass({ } get isAvailable() { - return this._isAvaialble; + return this._isAvailable; } set isAvailable(value) { if (this.isAvailable !== value) { - this._isAvaialble = value; + this._isAvailable = value; this.notify('is-available'); } } @@ -627,6 +630,9 @@ export const ThinkPadBattery = GObject.registerClass({ if (this._settingEndId) { this.settings.disconnect(this._settingEndId); } + if (this._settingDisabledValueId) { + this.settings.disconnect(this._settingDisabledValueId); + } if (this._monitorId) { this._baseMonitor.disconnect(this._monitorId); } @@ -660,6 +666,13 @@ export const ThinkPad = GObject.registerClass({ GObject.ParamFlags.READABLE, false ), + 'pending-changes': GObject.ParamSpec.boolean( + 'pending-changes', + 'Pending changes', + 'Indicates if the current values do not match the configured values', + GObject.ParamFlags.READABLE, + false + ), 'batteries': GObject.ParamSpec.jsobject( 'batteries', 'Batteries', @@ -706,12 +719,12 @@ export const ThinkPad = GObject.registerClass({ this.batteries = [ new ThinkPadBattery({ 'environment': this.environment, - 'name': 'BAT0', + 'name': 'BAT0', 'settings': this.settings }), new ThinkPadBattery({ 'environment': this.environment, - 'name': 'BAT1', + 'name': 'BAT1', 'settings': this.settings }), ]; @@ -728,6 +741,11 @@ export const ThinkPad = GObject.registerClass({ this.isActive = this._checkActive(); } ); + const pendingChangesId = battery.connect( + 'notify::pending-changes', (bat) => { + this.pendingChanges = this._checkPendingChanges(); + } + ); const enableCompletedId = battery.connect( 'enable-completed', (bat, error) => { this.emit('enable-battery-completed', bat, error); @@ -744,6 +762,7 @@ export const ThinkPad = GObject.registerClass({ // Load initial values this.isAvailable = this._checkAvailable(); this.isActive = this._checkActive(); + this.pendingChanges = this._checkPendingChanges(); } get environment() { @@ -754,12 +773,12 @@ export const ThinkPad = GObject.registerClass({ } get isAvailable() { - return this._isAvaialble; + return this._isAvailable; } set isAvailable(value) { if (this.isAvailable !== value) { - this._isAvaialble = value; + this._isAvailable = value; this.notify('is-available'); } } @@ -775,6 +794,28 @@ export const ThinkPad = GObject.registerClass({ } } + get pendingChanges() { + return this._pendingChanges; + } + + set pendingChanges(value) { + if (this.pendingChanges !== value) { + this._pendingChanges = value; + this.notify('pending-changes'); + } + } + + /** + * Check if there are changes to the settings that need to be applied + * + * @returns {boolean} Returns true if there are changes to the settings that need to be applied + */ + _checkPendingChanges() { + return this.batteries.some(bat => { + return bat.pendingChanges; + }); + } + /** * Check if at least one battery has the thresholds active * @@ -817,7 +858,7 @@ export const ThinkPad = GObject.registerClass({ runnable.connect('command-completed', (obj, error) => { this.emit('enable-all-completed', error); }) - runnable.run(); + runnable.run(); } /** @@ -840,7 +881,7 @@ export const ThinkPad = GObject.registerClass({ runnable.connect('command-completed', (obj, error) => { this.emit('disable-all-completed', error); }) - runnable.run(); + runnable.run(); } destroy() { diff --git a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/libs/indicator.js b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/libs/indicator.js index 4e27e13..742e14d 100644 --- a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/libs/indicator.js +++ b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/libs/indicator.js @@ -37,9 +37,6 @@ const BatteryItem = GObject.registerClass({ this._settings = settings; this._battery = battery; - - // Flag to prevent the PopupImageMenuItem from being activated when the reload icon is clicked - this._reloading = false; const box = new St.BoxLayout({ 'opacity': 128, @@ -58,9 +55,8 @@ const BatteryItem = GObject.registerClass({ }); this._reload.connectObject( 'button-press-event', () => { - this._reloading = true; this._battery.enable(); - return true; // Does not prevent event propagation??? + return true; }, this ); @@ -91,10 +87,7 @@ const BatteryItem = GObject.registerClass({ // Menu item action this.connectObject( 'activate', () => { - if (!this._reloading) { - this._battery.toggle(); - } - this._reloading = false; + this._battery.toggle(); }, 'destroy', () => { this._settings.disconnectObject(this); @@ -123,7 +116,11 @@ const BatteryItem = GObject.registerClass({ if (this._battery.isActive) { // TRANSLATORS: %s is the name of the battery. this.label.text = _('Disable thresholds (%s)').format(this._battery.name); - this.setIcon(getIcon('threshold-active', colorMode)); + if (this._battery.pendingChanges) { + this.setIcon(getIcon('threshold-active-warning', colorMode)); + } else { + this.setIcon(getIcon('threshold-active', colorMode)); + } // Status text const showCurrentValues = this._settings.get_boolean('show-current-values'); if (showCurrentValues) { @@ -249,6 +246,9 @@ export const ThresholdIndicator = GObject.registerClass({ 'notify::is-active', () => { this._updateIndicator(); }, + 'notify::pending-changes', () => { + this._updateIndicator(); + }, 'enable-battery-completed', (driver, battery, error) => { if (!error) { this._notifyEnabled( @@ -330,6 +330,15 @@ export const ThresholdIndicator = GObject.registerClass({ this._driver = null; this._extension = null; }); + + // Pending changes alert + this._driver.batteries.every(battery => { + if (battery.pendingChanges && battery.isActive) { + this._notify(_('Battery Threshold'), _('The currently set thresholds do not match the configured ones'), 'threshold-active-warning', false); + return false; + } + return true; + }); } /** @@ -339,7 +348,11 @@ export const ThresholdIndicator = GObject.registerClass({ const colorMode = this._settings.get_boolean('color-mode'); if (this._driver.isAvailable) { if (this._driver.isActive) { - this._indicator.gicon = getIcon('threshold-active', colorMode); + if (this._driver.pendingChanges) { + this._indicator.gicon = getIcon('threshold-active-warning', colorMode); + } else { + this._indicator.gicon = getIcon('threshold-active', colorMode); + } } else { this._indicator.gicon = getIcon('threshold-inactive', colorMode); } @@ -352,14 +365,14 @@ export const ThresholdIndicator = GObject.registerClass({ case 0: // Active this._indicator.visible = this._driver.isActive; break; - case 1: // Inactive - this._indicator.visible = !this._driver.isActive; + case 1: // Inactive (or pending changes) + this._indicator.visible = !this._driver.isActive || this._driver.pendingChanges; break; case 2: // Always this._indicator.visible = true; break; - case 3: // Never - this._indicator.visible = false; + case 3: // Never (or pending changes) + this._indicator.visible = this._driver.pendingChanges; break; default: this._indicator.visible = true; @@ -368,15 +381,15 @@ export const ThresholdIndicator = GObject.registerClass({ } /** - * Show notificaion. + * Show notification. * * @param {string} msg Title * @param {string} details Message * @param {string} iconName Icon name + * @param {boolean} [transient=true] Transient notification */ - _notify(msg, details, iconName) { + _notify(msg, details, iconName, transient=true) { if (!this._settings.get_boolean('show-notifications')) return; - const colorMode = this._settings.get_boolean('color-mode'); if (SHELL_VERSION === 45) { const source = new MessageTray.Source(this._name); Main.messageTray.add(source); @@ -384,9 +397,9 @@ export const ThresholdIndicator = GObject.registerClass({ source, msg, details, - {gicon: getIcon(iconName, colorMode)} + {gicon: getIcon(iconName, true)} ); - notification.setTransient(true); + notification.setTransient(transient); source.showNotification(notification); } else { const source = new MessageTray.Source({'title': this._name}); @@ -395,8 +408,8 @@ export const ThresholdIndicator = GObject.registerClass({ source: source, title: msg, body: details, - isTransient: true, - gicon: getIcon(iconName, colorMode) + isTransient: transient, + gicon: getIcon(iconName, true) }); source.addNotification(notification); } @@ -408,7 +421,7 @@ export const ThresholdIndicator = GObject.registerClass({ * @param {string} message Message */ _notifyError(message) { - this._notify(_('Battery Threshold'), message, 'threshold-error'); + this._notify(_('Battery Threshold'), message, 'threshold-error', false); } /** diff --git a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/locale/es/LC_MESSAGES/thinkpad-battery-threshold@marcosdalvarez.org.mo b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/locale/es/LC_MESSAGES/thinkpad-battery-threshold@marcosdalvarez.org.mo index 8a8c663..7aae3ff 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/locale/es/LC_MESSAGES/thinkpad-battery-threshold@marcosdalvarez.org.mo and b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/locale/es/LC_MESSAGES/thinkpad-battery-threshold@marcosdalvarez.org.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/locale/pt_BR/LC_MESSAGES/thinkpad-battery-threshold@marcosdalvarez.org.mo b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/locale/pt_BR/LC_MESSAGES/thinkpad-battery-threshold@marcosdalvarez.org.mo index fc4192c..91b3059 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/locale/pt_BR/LC_MESSAGES/thinkpad-battery-threshold@marcosdalvarez.org.mo and b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/locale/pt_BR/LC_MESSAGES/thinkpad-battery-threshold@marcosdalvarez.org.mo differ diff --git a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/metadata.json b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/metadata.json index 3f2d6bf..e8ff14c 100644 --- a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/metadata.json +++ b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/metadata.json @@ -6,9 +6,10 @@ "settings-schema": "org.gnome.shell.extensions.thinkpad-battery-threshold", "shell-version": [ "45", - "46" + "46", + "47" ], "url": "https://gitlab.com/marcosdalvarez/thinkpad-battery-threshold-extension", "uuid": "thinkpad-battery-threshold@marcosdalvarez.org", - "version": 44 + "version": 49 } \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/preferences/about.js b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/preferences/about.js index d547b1a..db06944 100644 --- a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/preferences/about.js +++ b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/preferences/about.js @@ -7,6 +7,14 @@ import Gio from 'gi://Gio'; import Gtk from 'gi://Gtk'; import Gdk from 'gi://Gdk'; +// Links +const URLS = { + readme: 'https://gitlab.com/marcosdalvarez/thinkpad-battery-threshold-extension/', + bug_report: 'https://gitlab.com/marcosdalvarez/thinkpad-battery-threshold-extension/-/issues', + license: 'https://gitlab.com/marcosdalvarez/thinkpad-battery-threshold-extension/-/blob/main/LICENSE', + translate: 'https://hosted.weblate.org/engage/thinkpad-battery-threshold/', +}; + export const About = GObject.registerClass({ GTypeName: 'AboutPrefs', Template: GLib.Uri.resolve_relative(import.meta.url, '../ui/about.ui',GLib.UriFlags.NONE), @@ -14,6 +22,10 @@ export const About = GObject.registerClass({ 'app_icon_image', 'app_name_label', 'version_label', + 'open_readme', + 'open_bug_report', + 'open_license', + 'open_translate', ] }, class About extends Adw.PreferencesPage { constructor(window) { @@ -21,25 +33,29 @@ export const About = GObject.registerClass({ this._app_icon_image.gicon = Gio.icon_new_for_string(`${GLib.Uri.resolve_relative(import.meta.url, '../icons/threshold-active.svg',GLib.UriFlags.NONE)}`); this._app_name_label.label = window._metadata.name; - this._version_label.label = window._metadata.version.toString(); + this._version_label.label = window._metadata.version ? window._metadata.version.toString() : "0"; - // setup menu actions + // Setup actions const actionGroup = new Gio.SimpleActionGroup(); window.insert_action_group('prefs', actionGroup); - // a list of actions with their associated link + // A list of actions with their associated link const actions = [ { name: 'open-bug-report', - link: 'https://gitlab.com/marcosdalvarez/thinkpad-battery-threshold-extension/-/issues' + link: URLS.bug_report }, { name: 'open-readme', - link: 'https://gitlab.com/marcosdalvarez/thinkpad-battery-threshold-extension/' + link: URLS.readme }, { name: 'open-license', - link: 'https://gitlab.com/marcosdalvarez/thinkpad-battery-threshold-extension/-/blob/main/LICENSE' + link: URLS.license + }, + { + name: 'open-translate', + link: URLS.translate }, ]; @@ -51,5 +67,11 @@ export const About = GObject.registerClass({ ); actionGroup.add_action(act); }); + + // Set tooltips + this._open_readme.tooltip_text = URLS.readme; + this._open_license.tooltip_text = URLS.license; + this._open_bug_report.tooltip_text = URLS.bug_report; + this._open_translate.tooltip_text = URLS.translate; } }); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/preferences/thinkpad.js b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/preferences/thinkpad.js index 133ad85..30517b4 100644 --- a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/preferences/thinkpad.js +++ b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/preferences/thinkpad.js @@ -16,7 +16,11 @@ export const Thinkpad = GObject.registerClass({ 'reset', 'apply_bat0', 'apply_bat1', - 'reset_thresholds_dialog' + 'reset_thresholds_dialog', + 'disabled_start_bat0', + 'disabled_start_bat1', + 'warn_bat0', + 'warn_bat1' ], }, class Thinkpad extends Adw.PreferencesPage { constructor(window) { @@ -46,26 +50,48 @@ export const Thinkpad = GObject.registerClass({ 'value', Gio.SettingsBindFlags.DEFAULT ); + window._settings.bind( + 'disabled-start-bat0-value', + this._disabled_start_bat0, + 'value', + Gio.SettingsBindFlags.DEFAULT + ); + window._settings.bind( + 'disabled-start-bat1-value', + this._disabled_start_bat1, + 'value', + Gio.SettingsBindFlags.DEFAULT + ); window._settings.connect('changed::start-bat0', () => { if (this._start_bat0.value >= this._end_bat0.value) { this._end_bat0.value = this._start_bat0.value + 1; } + this._updateWarnings(); }); window._settings.connect('changed::end-bat0', () => { if (this._start_bat0.value >= this._end_bat0.value) { this._start_bat0.value = this._end_bat0.value - 1; } + this._updateWarnings(); }); window._settings.connect('changed::start-bat1', () => { if (this._start_bat1.value >= this._end_bat1.value) { this._end_bat1.value = this._start_bat1.value + 1; } + this._updateWarnings(); }); window._settings.connect('changed::end-bat1', () => { if (this._start_bat1.value >= this._end_bat1.value) { this._start_bat1.value = this._end_bat1.value - 1; } + this._updateWarnings(); + }); + window._settings.connect('changed::disabled-start-bat0-value', () => { + this._updateWarnings(); + }); + window._settings.connect('changed::disabled-start-bat1-value', () => { + this._updateWarnings(); }); const bat0 = window._driver.batteries.find(battery => battery.name === 'BAT0'); @@ -96,13 +122,17 @@ export const Thinkpad = GObject.registerClass({ this._apply_bat1.sensitive = bat1.pendingChanges; }); + this._updateWarnings(); + this._reset_thresholds_dialog.connect('response', (obj, response, data) => { if (response === 'reset') { const keys = [ 'start-bat0', 'end-bat0', 'start-bat1', - 'end-bat1' + 'end-bat1', + 'disabled-start-bat0-value', + 'disabled-start-bat1-value', ]; keys.forEach(key => { window._settings.reset(key); @@ -116,4 +146,9 @@ export const Thinkpad = GObject.registerClass({ this._reset_thresholds_dialog.present(); }); } + + _updateWarnings() { + this._warn_bat0.reveal_child = this._start_bat0.value === this._disabled_start_bat0.value && this._end_bat0.value === 100; + this._warn_bat1.reveal_child = this._start_bat1.value === this._disabled_start_bat1.value && this._end_bat1.value === 100; + } }); \ No newline at end of file diff --git a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/schemas/gschemas.compiled b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/schemas/gschemas.compiled index bb8abf8..8f06c78 100644 Binary files a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/schemas/gschemas.compiled and b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/schemas/gschemas.compiled differ diff --git a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/schemas/org.gnome.shell.extensions.battery-threshold.gschema.xml b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/schemas/org.gnome.shell.extensions.battery-threshold.gschema.xml index e9c4b22..d806fa8 100644 --- a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/schemas/org.gnome.shell.extensions.battery-threshold.gschema.xml +++ b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/schemas/org.gnome.shell.extensions.battery-threshold.gschema.xml @@ -13,7 +13,7 @@ - "ACTIVE" + "ALWAYS" Set when the Icon tray should appear in Gnome tray @@ -39,12 +39,28 @@ Stop charging when the level is above this value - 0 + 75 Start charging when the level is below this value - 100 + 80 Stop charging when the level is above this value + + true + Use autodetected disabled start value + + + -1 + Disabled start value instead of default value + + + true + Use autodetected disabled start value + + + -1 + Disabled start value instead of default value + diff --git a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/ui/about.ui b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/ui/about.ui index b0c116e..c529db3 100644 --- a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/ui/about.ui +++ b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/ui/about.ui @@ -53,8 +53,6 @@ Project site - - https://gitlab.com/marcosdalvarez/thinkpad-battery-threshold-extension/ prefs.open-readme true @@ -68,8 +66,6 @@ Bug report - - https://gitlab.com/marcosdalvarez/thinkpad-battery-threshold-extension/-/issues prefs.open-bug-report true @@ -83,8 +79,6 @@ License - - https://gitlab.com/marcosdalvarez/thinkpad-battery-threshold-extension/-/blob/main/LICENSE prefs.open-license true @@ -95,6 +89,19 @@ + + + Translate + prefs.open-translate + true + + + center + adw-external-link-symbolic + + + + diff --git a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/ui/thinkpad.ui b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/ui/thinkpad.ui index 1f1a30a..eeef868 100644 --- a/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/ui/thinkpad.ui +++ b/gnome/.local/share/gnome-shell/extensions/thinkpad-battery-threshold@marcosdalvarez.org/ui/thinkpad.ui @@ -29,16 +29,100 @@ Charging start value Start charging when the level is below this value - bat0_start_adjustment + true + if-valid + + + 5.0 + 1.0 + 99.0 + 0.0 + 75.0 + + Charging stop value Stop charging when the level is above this value - bat0_end_adjustment + true + if-valid + + + 5.0 + 1.0 + 100.0 + 1.0 + 80.0 + + + + + Start value considered disabled + The start threshold value that is considered disabled is not the same on all laptops (usually 0 or 95). We will try to automatically detect this value, but if you can't turn off the thresholds, try changing it manually (use -1 to automatically detect it) + true + if-valid + + + 5.0 + 1.0 + 99.0 + -1.0 + -1.0 + + + + + + + true + + + GTK_ORIENTATION_HORIZONTAL + 12 + 6 + 6 + 6 + 6 + + + dialog-warning + warning + GTK_ICON_SIZE_LARGE + + + + + GTK_ORIENTATION_VERTICAL + + + WARNING + warning + true + true + GTK_JUSTIFY_CENTER + + + + + + + + true + true + GTK_JUSTIFY_CENTER + The configured threshold values are equal to the values considered "disabled" + + + + + + + + @@ -66,16 +150,100 @@ Charging start value Start charging when the level is below this value - bat1_start_adjustment + true + if-valid + + + 5.0 + 1.0 + 99.0 + 0.0 + 75.0 + + Charging stop value Stop charging when the level is above this value - bat1_end_adjustment + true + if-valid + + + 5.0 + 1.0 + 100.0 + 1.0 + 80.0 + + + + + Start value considered disabled + The start threshold value that is considered disabled is not the same on all laptops (usually 0 or 95). We will try to automatically detect this value, but if you can't turn off the thresholds, try changing it manually (use -1 to automatically detect it) + true + if-valid + + + 5.0 + 1.0 + 99.0 + -1.0 + -1.0 + + + + + + + true + + + GTK_ORIENTATION_HORIZONTAL + 12 + 6 + 6 + 6 + 6 + + + dialog-warning + warning + GTK_ICON_SIZE_LARGE + + + + + GTK_ORIENTATION_VERTICAL + + + WARNING + warning + true + true + GTK_JUSTIFY_CENTER + + + + + + + + true + true + GTK_JUSTIFY_CENTER + The configured threshold values are equal to the values considered "disabled" + + + + + + + + @@ -116,33 +284,4 @@ Reset - - - 5.0 - 1.0 - 99.0 - 0.0 - 75.0 - - - 5.0 - 1.0 - 100.0 - 1.0 - 80.0 - - - 5.0 - 1.0 - 99.0 - 0.0 - 75.0 - - - 5.0 - 1.0 - 100.0 - 1.0 - 80.0 - \ No newline at end of file