From 707ad97c48dc45a4da15f7dbd07c65e9ab8dfe0b Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Wed, 21 Sep 2022 21:18:50 +1000 Subject: [PATCH] Version 43 (#184) * fixes for extensions.gnome.org review --- buildzip.sh | 10 ++++-- carousel.js | 49 +++++++++++++++++++++------- extension.js | 69 +++++++++++++++++++++++++++++++--------- locale/BingWallpaper.pot | 34 ++++++++++---------- metadata.json | 4 +-- prefs.js | 67 +++++++++++++++++++++++--------------- 6 files changed, 159 insertions(+), 74 deletions(-) diff --git a/buildzip.sh b/buildzip.sh index 3348dd6e..57c28b02 100755 --- a/buildzip.sh +++ b/buildzip.sh @@ -1,5 +1,9 @@ #!/bin/bash +# Missing the below tools won't break the zip build, but this does prevent translatons +# & schemas being rebuilt (if there are changes). Releases should always be built with +# the tools, but test builds in VMs it (generally) should be ok + glib-compile-schemas schemas/ intltool-extract --type=gettext/glade ui/Settings.ui intltool-extract --type=gettext/glade ui/Settings4.ui @@ -7,10 +11,12 @@ intltool-extract --type=gettext/glade ui/carousel.ui intltool-extract --type=gettext/glade ui/carousel4.ui xgettext -k -k_ -kN_ --omit-header -o locale/BingWallpaper.pot ui/Settings.ui.h ui/Settings4.ui.h ui/carousel.ui.h ui/carousel4.ui.h extension.js prefs.js blur.js utils.js convenience.js --from-code=UTF-8 -echo "Translation status" > translations.txt +DATE=`date +"%F"` +echo "# Translation status of statements as at $DATE:" > translations.txt +MSGCOUNT=`cat locale/BingWallpaper.pot | grep -c -e msgid` for D in locale/*; do if [ -d "${D}" ]; then - msgfmt --template=BingWallpaper.pot --statistics --verbose -o "${D}/LC_MESSAGES/BingWallpaper.mo" "${D}/LC_MESSAGES/BingWallpaper.po" 2>> translations.txt + msgfmt --template=BingWallpaper.pot --statistics --verbose -o "${D}/LC_MESSAGES/BingWallpaper.mo" "${D}/LC_MESSAGES/BingWallpaper.po" 2>&1 | cat >> translations.txt # your processing here fi done diff --git a/carousel.js b/carousel.js index fc86b2af..7bfed477 100644 --- a/carousel.js +++ b/carousel.js @@ -27,10 +27,9 @@ var Carousel = class Carousel { this.flowBox = null; this.window = null; this.imageList = Utils.imageListSortByDate(Utils.getImageList(this.settings)).reverse(); // get images and reverse order + this.log('create carousel...'); - // disable the button - //if (this.button) - // this.button.set_sensitive(false); + if (!prefs_flowbox) { [this.window, this.flowBox] = this._create_gallery_window(_('Bing Wallpaper Gallery'), default_dimensions); if (Gtk.get_major_version() < 4) @@ -60,8 +59,10 @@ var Carousel = class Carousel { let buildable = new Gtk.Builder(); let win = new Gtk.Window(); let flowBox; + win.set_default_size(dimensions[2], dimensions[3]); win.set_title(title); + if (Gtk.get_major_version() < 4) { buildable.add_objects_from_file(Me.dir.get_path() + '/ui/carousel.ui', ['carouselScrollable']); flowBox = buildable.get_object('carouselFlowBox'); @@ -83,6 +84,7 @@ var Carousel = class Carousel { else this.flowBox.insert(item, -1); }); + this.imageList.forEach((image) => { let item = this._create_gallery_item(image); if (Gtk.get_major_version() < 4) @@ -94,17 +96,21 @@ var Carousel = class Carousel { _create_gallery_item(image) { let buildable = new Gtk.Builder(); - if (Gtk.get_major_version() < 4) // grab appropriate object from UI file + + // grab appropriate object from UI file + if (Gtk.get_major_version() < 4) buildable.add_objects_from_file(Me.dir.get_path() + '/ui/carousel.ui', ["flowBoxChild"]); else buildable.add_objects_from_file(Me.dir.get_path() + '/ui/carousel4.ui', ["flowBoxChild"]); + + // assign variables to the UI objects we've just loaded let galleryImage = buildable.get_object('galleryImage'); - // let imageLabel = buildable.get_object('imageLabel'); let filename = Utils.imageToFilename(this.settings, image); let viewButton = buildable.get_object('viewButton'); let applyButton = buildable.get_object('applyButton'); let infoButton = buildable.get_object('infoButton'); let deleteButton = buildable.get_object('deleteButton'); + try { this._load_image(galleryImage, filename); } @@ -118,20 +124,24 @@ var Carousel = class Carousel { galleryImage.set_icon_size = 2; // Gtk.GTK_ICON_SIZE_LARGE; this.log('create_gallery_image: '+e); } + galleryImage.set_tooltip_text(image.copyright); - /*imageLabel.set_width_chars(60); - imageLabel.set_label(Utils.shortenName(Utils.getImageTitle(image), 60));*/ + + // set up actions for when a image button is clicked viewButton.connect('clicked', () => { Utils.openInSystemViewer(filename); }); + applyButton.connect('clicked', () => { this.settings.set_string('selected-image', Utils.getImageUrlBase(image)); this.log('gallery selected '+Utils.getImageUrlBase(image)); }); + infoButton.connect('clicked', () => { Utils.openInSystemViewer(image.copyrightlink, false); this.log('info page link opened '+image.copyrightlink); }); + deleteButton.connect('clicked', (widget) => { this.log('Delete requested for '+filename); Utils.deleteImage(filename); @@ -140,19 +150,22 @@ var Carousel = class Carousel { if (this.callbackfunc) this.callbackfunc(); }); - //deleteButton.set_sensitive(false); + let item = buildable.get_object('flowBoxChild'); return item; } _create_random_item(seconds, title) { let buildable = new Gtk.Builder(); - if (Gtk.get_major_version() < 4) {// grab appropriate object from UI file {} + + // grab appropriate object from UI file + if (Gtk.get_major_version() < 4) { buildable.add_objects_from_file(Me.dir.get_path() + '/ui/carousel.ui', ["flowBoxRandom"]); } else { buildable.add_objects_from_file(Me.dir.get_path() + '/ui/carousel4.ui', ["flowBoxRandom"]); } + let randomLabel = buildable.get_object('randomLabel'); randomLabel.set_text(title); let filename = 'random'; @@ -163,6 +176,7 @@ var Carousel = class Carousel { this.settings.set_int('random-interval', seconds); this.log('gallery selected random with interval '+seconds); }); + let item = buildable.get_object('flowBoxRandom'); return item; } @@ -170,7 +184,9 @@ var Carousel = class Carousel { _create_placeholder_item() { let buildable = new Gtk.Builder(); this.flowBox.set_max_children_per_line(1); - if (Gtk.get_major_version() >= 4) {// grab appropriate object from UI file {} + + // grab appropriate object from UI file + if (Gtk.get_major_version() >= 4) { buildable.add_objects_from_file(Me.dir.get_path() + '/ui/carousel4.ui', ["flowBoxPlaceholder"]); } else { @@ -184,6 +200,7 @@ var Carousel = class Carousel { this.flowBox.set_max_children_per_line(2); this._create_gallery(); }); + let item = buildable.get_object('flowBoxPlaceholder'); return item; } @@ -192,26 +209,34 @@ var Carousel = class Carousel { let thumb_path = Utils.getWallpaperDir(this.settings)+'.thumbs/'; let thumb_dir = Gio.file_new_for_path(thumb_path); let save_thumbs = !this.settings.get_boolean('delete-previous') && this.settings.get_boolean('create-thumbs'); // create thumbs only if not deleting previous and thumbs are enabled + if (!thumb_dir.query_exists(null)) { thumb_dir.make_directory_with_parents(null); } + let image_file = Gio.file_new_for_path(filename); + + // load gallery image or create new thumbnail if it doesn't if (!image_file.query_exists(null)){ this._set_blank_image(galleryImage); } else { let image_thumb_path = thumb_path + image_file.get_basename(); let image_thumb = Gio.file_new_for_path(image_thumb_path); + try { let pixbuf; - if (image_thumb.query_exists(null)) { // use thumbnail if available + + // use thumbnail if available + if (image_thumb.query_exists(null)) { pixbuf = GdkPixbuf.Pixbuf.new_from_file(image_thumb_path); } - else { // significantly speeds up gallery loading, but costs some addtional disk space + else { // save changed thumbnail significantly speeds up gallery loading, but costs some addtional disk space pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(filename, GALLERY_THUMB_WIDTH, GALLERY_THUMB_HEIGHT); if (save_thumbs) pixbuf.savev(image_thumb_path,'jpeg',['quality'], ['90']); } + if (Gtk.get_major_version() < 4) { galleryImage.set_from_pixbuf(pixbuf); } diff --git a/extension.js b/extension.js index 788a664a..2761f419 100644 --- a/extension.js +++ b/extension.js @@ -7,8 +7,6 @@ // See the GNU General Public License, version 3 or later for details. // Based on GNOME shell extension NASA APOD by Elia Argentieri https://github.com/Elinvention/gnome-shell-extension-nasa-apod -imports.gi.versions.Soup = "2.4"; - const {St, Soup, Gio, GObject, GLib, Clutter, Cogl, Gdk} = imports.gi; const Main = imports.ui.main; const MessageTray = imports.ui.messageTray; @@ -43,12 +41,10 @@ const ICON_PLAY_MODE_BUTTON = 'media-playback-start-symbolic'; const ICON_REFRESH = 'view-refresh-symbolic'; -let autores; // automatically selected resolution let bingWallpaperIndicator = null; let blur = null; let blur_brightness = 0.55; let blur_strength = 30; -let carousel = null; // remove this when dropping support for < 3.33, see https://github.com/OttoAllmendinger/ const getActorCompat = (obj) => @@ -324,15 +320,16 @@ class BingWallpaperIndicator extends PanelMenu.Button { // set a timer on when the current image is going to expire _restartTimeoutFromLongDate(longdate) { - // all bing times are in UTC (+0) + // all Bing times are in UTC (+0) let refreshDue = Utils.dateFromLongDate(longdate, 86400).to_local(); let now = GLib.DateTime.new_now_local(); let difference = refreshDue.difference(now) / 1000000; - log('Next refresh due ' + difference + ' seconds from now'); + if (difference < 60 || difference > 86400) // clamp to a reasonable range difference = 60; - difference = difference + 300; // 5 minute fudge offset in case of inaccurate local clock + + log('Next refresh due ' + difference + ' seconds from now'); this._restartTimeout(difference); } @@ -378,6 +375,7 @@ class BingWallpaperIndicator extends PanelMenu.Button { x_expand: true, y_expand: true }); + if (position) { getActorCompat(parent).insert_child_at_index(iconBtn, position); } @@ -392,12 +390,17 @@ class BingWallpaperIndicator extends PanelMenu.Button { // set menu thumbnail _setThumbnailImage() { let pixbuf = this.thumbnail.pixbuf; + let scale_factor = St.ThemeContext.get_for_stage(global.stage).scale_factor; + if (pixbuf == null) return; + const {width, height} = pixbuf; + if (height == 0) { return; } + const image = new Clutter.Image(); const success = image.set_data( pixbuf.get_pixels(), @@ -406,6 +409,7 @@ class BingWallpaperIndicator extends PanelMenu.Button { height, pixbuf.get_rowstride() ); + if (!success) { throw Error("error creating Clutter.Image()"); } @@ -413,7 +417,7 @@ class BingWallpaperIndicator extends PanelMenu.Button { getActorCompat(this.thumbnailItem).hexpand = false; getActorCompat(this.thumbnailItem).vexpand = false; getActorCompat(this.thumbnailItem).content = image; - let scale_factor = St.ThemeContext.get_for_stage(global.stage).scale_factor; + log('scale factor: ' + scale_factor); getActorCompat(this.thumbnailItem).set_size(480*scale_factor, 270*scale_factor); this.thumbnailItem.setSensitive(true); @@ -439,10 +443,12 @@ class BingWallpaperIndicator extends PanelMenu.Button { _togglePause() { this._settings.set_boolean('revert-to-current-image', !this._settings.get_boolean('revert-to-current-image')); getActorCompat(this.controlItem.remove_child(this.modeBtn)); + this.modeBtn = this._newMenuIcon( this._settings.get_boolean('revert-to-current-image') ? ICON_PLAY_MODE_BUTTON : ICON_PAUSE_MODE_BUTTON, this.controlItem, this._togglePause); + log('switched mode to ' + this._settings.get_boolean('revert-to-current-image')); } @@ -453,27 +459,34 @@ class BingWallpaperIndicator extends PanelMenu.Button { else { this._settings.set_string('selected-image', 'random'); } + getActorCompat(this.controlItem.remove_child(this.randomBtn)); + this.randomBtn = this._newMenuIcon( this._settings.get_string('selected-image') == 'random'? ICON_SHUFFLE_BUTTON: ICON_CONSEC_BUTTON, this.controlItem, this._toggleShuffle, 6); + log('switched mode to ' + this._settings.get_boolean('revert-to-current-image')); } _gotoImage(relativePos) { let imageList = Utils.getImageList(this._settings); let curIndex = 0; + if (this.selected_image == 'random') return; - if (this.selected_image == 'current') { + + if (this.selected_image == 'current') { curIndex = Utils.getCurrentImageIndex(imageList); } else { curIndex = Utils.imageIndex(imageList, this.selected_image); } + let newImage = Utils.getImageByIndex(imageList, curIndex + relativePos); + if (newImage) this._settings.set_string('selected-image', newImage.urlbase.replace('/th?id=OHR.', '')); } @@ -481,6 +494,7 @@ class BingWallpaperIndicator extends PanelMenu.Button { _getCurrentImage() { let imageList = Utils.getImageList(this._settings); let curIndex = Utils.getCurrentImageIndex(imageList); + return Utils.getImageByIndex(imageList, curIndex); } @@ -532,8 +546,10 @@ class BingWallpaperIndicator extends PanelMenu.Button { let data = (Soup.MAJOR_VERSION >= 3) ? ByteArray.toString(this.httpSession.send_and_read_finish(message).get_data()): // Soup3 message.response_body.data; // Soup 2 + log('Recieved ' + data.length + ' bytes'); this._parseData(data); + if (this.selected_image != 'random') this._selectImage(); } @@ -548,8 +564,10 @@ class BingWallpaperIndicator extends PanelMenu.Button { _restartTimeout(seconds = null) { if (this._timeout) GLib.source_remove(this._timeout); + if (seconds == null) seconds = TIMEOUT_SECONDS; + this._timeout = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, seconds, this._refresh.bind(this)); let localTime = GLib.DateTime.new_now_local().add_seconds(seconds); this.refreshdue = localTime; @@ -559,8 +577,10 @@ class BingWallpaperIndicator extends PanelMenu.Button { _restartShuffleTimeout(seconds = null) { if (this._shuffleTimeout) GLib.source_remove(this._shuffleTimeout); + if (seconds == null) seconds = this._settings.get_int('random-interval'); + this._shuffleTimeout = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, seconds, this._selectImage.bind(this)); log('next shuffle in ' + seconds + ' seconds'); } @@ -578,15 +598,19 @@ class BingWallpaperIndicator extends PanelMenu.Button { let parsed = JSON.parse(data); let datamarket = parsed.market.mkt; let prefmarket = this._settings.get_string('market'); + let newImages = Utils.mergeImageLists(this._settings, parsed.images); + if (datamarket != prefmarket && prefmarket != 'auto') log('WARNING: Bing returning market data for ' + datamarket + ' rather than selected ' + prefmarket); - let newImages = Utils.mergeImageLists(this._settings, parsed.images); + Utils.purgeImages(this._settings); // delete older images if enabled Utils.cleanupImageList(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'); } + if (this._settings.get_boolean('notify')) { newImages.forEach((image, index) => { log('New image to notify: ' + Utils.getImageTitle(image)); @@ -623,6 +647,7 @@ class BingWallpaperIndicator extends PanelMenu.Button { let imageList = JSON.parse(this._settings.get_string('bing-json')); let image = null; // special values, 'current' is most recent (default mode), 'random' picks one at random, anything else should be filename + if (this.selected_image == 'random' || force_shuffle) { this.imageIndex = Utils.getRandomInt(imageList.length); image = imageList[this.imageIndex]; @@ -637,10 +662,15 @@ class BingWallpaperIndicator extends PanelMenu.Button { image = Utils.getCurrentImage(imageList); this.imageIndex = Utils.imageIndex(imageList, image.urlbase); } + if (!image) return; // could force, image = imageList[0] or perhaps force refresh if (image.url != '') { + let resolution = Utils.getResolution(this._settings, image); + let BingWallpaperDir = Utils.getWallpaperDir(this._settings); + + // set current image details at extension scope this.title = image.copyright.replace(/\s*[\(\(].*?[\)\)]\s*/g, ''); this.explanation = _('Bing Wallpaper of the Day for') + ' ' + this._localeDate(image.startdate); if (this._settings.get_boolean('show-count-in-image-title')) @@ -648,8 +678,6 @@ class BingWallpaperIndicator extends PanelMenu.Button { this.copyright = image.copyright.match(/[\(\(]([^)]+)[\)\)]/)[1].replace('\*\*', ''); // Japan locale uses () rather than () this.longstartdate = image.fullstartdate; this.imageinfolink = image.copyrightlink.replace(/^http:\/\//i, 'https://'); - let resolution = Utils.getResolution(this._settings, image); - let BingWallpaperDir = Utils.getWallpaperDir(this._settings); this.imageURL = BingURL + image.urlbase + '_' + resolution + '.jpg'; // generate image url for user's resolution this.filename = toFilename(BingWallpaperDir, image.startdate, image.urlbase, resolution); @@ -663,7 +691,8 @@ class BingWallpaperIndicator extends PanelMenu.Button { dir.make_directory_with_parents(null); } this._downloadImage(this.imageURL, file); - } else { + } + else { this._setBackground(); this._updatePending = false; } @@ -674,6 +703,7 @@ class BingWallpaperIndicator extends PanelMenu.Button { this.filename = ""; this._updatePending = false; } + this._setMenuText(); this._storeState(); } @@ -685,6 +715,7 @@ class BingWallpaperIndicator extends PanelMenu.Button { longstartdate: this.longstartdate, imageinfolink: this.imageinfolink, imageURL: this.imageURL, filename: this.filename}; let stateJSON = JSON.stringify(state); + log('Storing state as JSON: ' + stateJSON); this._settings.set_string('state', stateJSON); } @@ -692,12 +723,13 @@ class BingWallpaperIndicator extends PanelMenu.Button { _reStoreState() { try { - log('restoring state...'); // 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', '~')); let stateJSON = this._settings.get_string('state'); let state = JSON.parse(stateJSON); let maxLongDate = null; + + log('restoring state...'); maxLongDate = state.maxlongdate ? state.maxlongdate : null; this.title = state.title; this.explanation = state.explanation; @@ -707,12 +739,15 @@ class BingWallpaperIndicator extends PanelMenu.Button { this.imageURL = state.imageURL; this.filename = state.filename; this._selected_image = this._settings.get_string('selected-image'); + // update menus and thumbnail this._setMenuText(); this._setBackground(); + if (!maxLongDate) { this._restartTimeout(60); return; } + if (this.selected_image == 'random') { this._setRandom(); this._restartTimeoutFromLongDate(maxLongDate); @@ -720,6 +755,7 @@ class BingWallpaperIndicator extends PanelMenu.Button { else { this._restartTimeoutFromLongDate(maxLongDate); } + return; } catch (error) { @@ -794,8 +830,10 @@ class BingWallpaperIndicator extends PanelMenu.Button { stop() { if (this._timeout) GLib.source_remove(this._timeout); + if (this._shuffleTimeout) GLib.source_remove(this._shuffleTimeout); + this._timeout = undefined; this._shuffleTimeout = undefined; this.menu.removeAll(); @@ -809,13 +847,14 @@ function init(extensionMeta) { function enable() { bingWallpaperIndicator = new BingWallpaperIndicator(); Main.panel.addToStatusArea(IndicatorName, bingWallpaperIndicator); - autores = "UHD"; // remove monitor size checks } function disable() { bingWallpaperIndicator.stop(); bingWallpaperIndicator.destroy(); bingWallpaperIndicator = null; + + // disable blur override and cleanup blur._disable(); blur = null; } diff --git a/locale/BingWallpaper.pot b/locale/BingWallpaper.pot index 755efa04..da9040af 100644 --- a/locale/BingWallpaper.pot +++ b/locale/BingWallpaper.pot @@ -10,7 +10,7 @@ msgstr "" msgid "Enable desktop notifications" msgstr "" -#: ui/Settings.ui.h:4 ui/Settings4.ui.h:5 extension.js:135 +#: ui/Settings.ui.h:4 ui/Settings4.ui.h:5 extension.js:131 msgid "Set background image" msgstr "" @@ -46,7 +46,7 @@ msgstr "" msgid "Bing locale" msgstr "" -#: ui/Settings.ui.h:13 ui/Settings4.ui.h:12 extension.js:138 +#: ui/Settings.ui.h:13 ui/Settings4.ui.h:12 extension.js:134 msgid "Settings" msgstr "" @@ -248,63 +248,63 @@ msgstr "" msgid "Load image gallery" msgstr "" -#: extension.js:122 +#: extension.js:118 msgid "" msgstr "" -#: extension.js:125 extension.js:127 extension.js:130 +#: extension.js:121 extension.js:123 extension.js:126 msgid "Awaiting refresh..." msgstr "" -#: extension.js:132 +#: extension.js:128 msgid "Copy image to clipboard" msgstr "" -#: extension.js:133 +#: extension.js:129 msgid "Copy image URL to clipboard" msgstr "" -#: extension.js:134 +#: extension.js:130 msgid "Open image folder" msgstr "" -#: extension.js:136 +#: extension.js:132 msgid "Set lock screen image" msgstr "" -#: extension.js:137 +#: extension.js:133 msgid "Refresh Now" msgstr "" -#: extension.js:258 +#: extension.js:254 msgid "Next refresh" msgstr "" -#: extension.js:259 +#: extension.js:255 msgid "Last refresh" msgstr "" -#: extension.js:615 extension.js:645 +#: extension.js:639 extension.js:675 msgid "Bing Wallpaper of the Day for" msgstr "" -#: extension.js:672 +#: extension.js:701 msgid "No wallpaper available" msgstr "" -#: extension.js:673 +#: extension.js:702 msgid "No picture for today." msgstr "" -#: prefs.js:170 +#: prefs.js:177 msgid "Select folder" msgstr "" -#: prefs.js:229 +#: prefs.js:245 msgid "Most recent image" msgstr "" -#: prefs.js:230 +#: prefs.js:246 msgid "Random image" msgstr "" diff --git a/metadata.json b/metadata.json index 2aa5da51..caa2ca91 100644 --- a/metadata.json +++ b/metadata.json @@ -1,10 +1,10 @@ { "uuid": "BingWallpaper@ineffable-gmail.com", - "shell-version": ["3.36", "3.38", "40", "41", "42", "43", "43.beta", "43.rc"], + "shell-version": ["3.36", "3.38", "40", "41", "42", "43"], "name": "Bing Wallpaper", "settings-schema": "org.gnome.shell.extensions.bingwallpaper", "description": "Sync your wallpaper to today's Microsoft Bing image of the day (the image you see when you visit Bing.com).\n\n *Disclaimer*: this extension is unofficial and not affiliated with Bing or Microsoft in any way. Images are protected by copyright and are licensed only for use as wallpapers.\n\nFeatures:\n* UHD resolution wallpapers\n* Automatically fetches current Bing wallpaper of the day and sets as both lock screen and desktop wallpaper (user selectable on GNOME versions that support it)\n* Doesn't poll continuously - only once per day and on startup (schedules a refresh when Bing is due to update)\n * random mode (from previously downloaded wallpapers)\n *NEW: select/cycle wallpaper through previously downloaded images\n* 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 (ni), Swedish (sv), Arabic (ar), Hungarian (hu) and Japanese (ja) - a HUGE thanks to the translators\n\nThis extension was forked from the NASA APOD extension by Elinvention (https://github.com/Elinvention) and inspired by Bing Desktop Wallpaper Changer by Utkarsh Gupta (https://github.com/UtkarshGpta).\n\nAlways restart GNOME after manually updating extensions. Please report bugs to the GitHub page below:", - "version": "42", + "version": "43", "url": "https://github.com/neffo/bing-wallpaper-gnome-extension", "gettext-domain": "BingWallpaper" } diff --git a/prefs.js b/prefs.js index cc8208c0..9c34a71b 100644 --- a/prefs.js +++ b/prefs.js @@ -7,7 +7,7 @@ // See the GNU General Public License, version 3 or later for details. // Based on GNOME shell extension NASA APOD by Elia Argentieri https://github.com/Elinvention/gnome-shell-extension-nasa-apod -imports.gi.versions.Soup = "2.4"; +imports.gi.versions.Soup = "2.4"; // force single version of Soup, not sure if there is a way to force latest version const {Gtk, Gdk, GdkPixbuf, Gio, GLib, Soup} = imports.gi; const ExtensionUtils = imports.misc.extensionUtils; @@ -18,17 +18,6 @@ const Gettext = imports.gettext.domain('BingWallpaper'); const _ = Gettext.gettext; const Carousel = Me.imports.carousel; -let settings; -let desktop_settings; - -let marketDescription = null; -let icon_image = null; -let lastreq = null; -let provider = new Gtk.CssProvider(); - -let carousel = null; -let httpSession = null; - const BingImageURL = Utils.BingImageURL; var DESKTOP_SCHEMA = 'org.gnome.desktop.background'; @@ -41,6 +30,21 @@ function init() { } function buildPrefsWidget() { + // formally globals + let settings = ExtensionUtils.getSettings(Utils.BING_SCHEMA); + let desktop_settings = ExtensionUtils.getSettings(Utils.DESKTOP_SCHEMA); + + let icon_image = null; + let provider = new Gtk.CssProvider(); + + let carousel = null; + let httpSession = null; + + let log = (msg) => { // avoids need for globals + if (settings.get_boolean('debug-logging')) + print("BingWallpaper extension: " + msg); // disable to keep the noise down in journal + } + // Prepare labels and controls let buildable = new Gtk.Builder(); if (Gtk.get_major_version() == 4) { // GTK4 removes some properties, and builder breaks when it sees them @@ -58,7 +62,6 @@ function buildPrefsWidget() { let box = buildable.get_object('prefs_widget'); // fix size of prefs window in GNOME shell 40+ (but super racy, so is unreliable) - if (Convenience.currentVersionGreaterEqual('40')) { box.connect('realize', () => { let window = box.get_root(); @@ -70,6 +73,7 @@ function buildPrefsWidget() { buildable.get_object('extension_version').set_text(Me.metadata.version.toString()); buildable.get_object('extension_name').set_text(Me.metadata.name.toString()); + // assign variables to UI objects we've loaded let hideSwitch = buildable.get_object('hide'); let iconEntry = buildable.get_object('icon'); let notifySwitch = buildable.get_object('notify'); @@ -83,7 +87,6 @@ function buildPrefsWidget() { let historyEntry = buildable.get_object('history'); let galleryButton = buildable.get_object('button_open_gallery'); let deleteSwitch = buildable.get_object('delete_previous'); - marketDescription = buildable.get_object('market_description'); icon_image = buildable.get_object('icon_image'); let overrideSwitch = buildable.get_object('lockscreen_override'); let strengthEntry = buildable.get_object('entry_strength'); @@ -93,7 +96,6 @@ function buildPrefsWidget() { let unsafeSwitch = buildable.get_object('unsafe_switch'); let randomIntervalEntry = buildable.get_object('entry_random_interval'); let change_log = buildable.get_object('change_log'); - let buttonGDMdefault = buildable.get_object('button_default_gnome'); let buttonnoblur = buildable.get_object('button_no_blur'); let buttonslightblur = buildable.get_object('button_slight_blur'); @@ -102,8 +104,6 @@ function buildPrefsWidget() { let switchAlwaysExport = buildable.get_object('always_export_switch'); let carouselFlowBox = (Gtk.get_major_version() == 4) ? buildable.get_object('carouselFlowBox'): null; - settings = ExtensionUtils.getSettings(Utils.BING_SCHEMA); - desktop_settings = ExtensionUtils.getSettings(Utils.DESKTOP_SCHEMA); try { httpSession = new Soup.Session(); httpSession.user_agent = 'User-Agent: Mozilla/5.0 (X11; GNOME Shell/' + imports.misc.config.PACKAGE_VERSION + '; Linux x86_64; +https://github.com/neffo/bing-wallpaper-gnome-extension ) BingWallpaper Gnome Extension/' + Me.metadata.version; @@ -120,16 +120,19 @@ function buildPrefsWidget() { settings.bind('hide', hideSwitch, 'active', Gio.SettingsBindFlags.DEFAULT); settings.bind('notify', notifySwitch, 'active', Gio.SettingsBindFlags.DEFAULT); - Utils.icon_list.forEach((iconname, index) => { // add markets to dropdown list (aka a GtkComboText) + // add markets to dropdown list (aka a GtkComboText) + Utils.icon_list.forEach((iconname, index) => { iconEntry.append(iconname, iconname); }); - settings.bind('icon-name', iconEntry, 'active_id', Gio.SettingsBindFlags.DEFAULT); + // user selectable indicator icons + settings.bind('icon-name', iconEntry, 'active_id', Gio.SettingsBindFlags.DEFAULT); settings.connect('changed::icon-name', () => { Utils.validate_icon(settings, icon_image); }); iconEntry.set_active_id(settings.get_string('icon-name')); + // connect switches to settings changes settings.bind('set-background', bgSwitch, 'active', Gio.SettingsBindFlags.DEFAULT); settings.bind('debug-logging', debugSwitch, 'active', Gio.SettingsBindFlags.DEFAULT); settings.bind('revert-to-current-image', revertSwitch, 'active', Gio.SettingsBindFlags.DEFAULT); @@ -137,9 +140,12 @@ function buildPrefsWidget() { settings.bind('random-interval', randomIntervalEntry, 'value', Gio.SettingsBindFlags.DEFAULT); settings.bind('always-export-bing-json', switchAlwaysExport, 'active', Gio.SettingsBindFlags.DEFAULT); + // button opens Nautilus at our image folder folderOpenBtn.connect('clicked', (widget) => { Utils.openImageFolder(settings); }); + + // open image carousel (gallery) window (gtk3, gnome <40) or populate the tab (gtk4+, gnome 40+) if (Gtk.get_major_version() == 4) { carousel = new Carousel.Carousel(settings, null, null, carouselFlowBox); // auto load carousel } @@ -149,7 +155,8 @@ function buildPrefsWidget() { }); } - + // this is intended for migrating image folders between computers (or even sharing) or backups + // we export the Bing JSON data to the image directory, so this folder becomes portable buttonImportData.connect('clicked', () => { Utils.importBingJSON(settings); }); @@ -170,6 +177,7 @@ function buildPrefsWidget() { fileChooser.set_accept_label(_('Select folder')); fileChooser.show(); }); + fileChooser.connect('response', (widget, response) => { if (response !== Gtk.ResponseType.ACCEPT) { return; @@ -180,6 +188,7 @@ function buildPrefsWidget() { Utils.moveImagesToNewFolder(settings, Utils.getWallpaperDir(settings), fileURI); Utils.setWallpaperDir(settings, fileURI); }); + // in Gtk 4 instead we use a DropDown, but we need to treat it a bit special let market_grid = buildable.get_object('market_grid'); marketEntry = Gtk.DropDown.new_from_strings(Utils.marketName); @@ -190,9 +199,11 @@ function buildPrefsWidget() { settings.set_string('market', Utils.markets[id]); log('dropdown selected '+id+' = '+Utils.markets[id]+" - "+Utils.marketName[id]); }); + settings.connect('changed::market', () => { marketEntry.set_selected(Utils.markets.indexOf(settings.get_string('market'))); }); + settings.connect('changed::download-folder', () => { fileChooserBtn.set_label(Utils.getWallpaperDir(settings)); }); @@ -200,16 +211,19 @@ function buildPrefsWidget() { else { // Gtk 3 fileChooserBtn.set_filename(Utils.getWallpaperDir(settings)); log("fileChooser filename/dirname set to '"+fileChooserBtn.get_filename()+"' setting is '"+settings.get_string('download-folder')+"'"); + fileChooserBtn.add_shortcut_folder_uri("file://" + GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES)+"/BingWallpaper"); fileChooserBtn.connect('file-set', (widget) => { Utils.moveImagesToNewFolder(settings, settings.get_string('download-folder'), widget.get_filename()); Utils.setWallpaperDir(settings, widget.get_filename()); }); + Utils.markets.forEach((bingmarket, index) => { // add markets to dropdown list (aka a GtkComboText) marketEntry.append(bingmarket, bingmarket+": "+Utils.marketName[index]); }); settings.bind('market', marketEntry, 'active_id', Gio.SettingsBindFlags.DEFAULT); + settings.connect('changed::download-folder', () => { fileChooserBtn.set_filename(Utils.getWallpaperDir(settings)); }); @@ -219,7 +233,9 @@ function buildPrefsWidget() { Utils.resolutions.forEach((res) => { // add res to dropdown list (aka a GtkComboText) resolutionEntry.append(res, res); }); + settings.bind('resolution', resolutionEntry, 'active_id', Gio.SettingsBindFlags.DEFAULT); + settings.connect('changed::resolution', () => { Utils.validate_resolution(settings); }); @@ -228,9 +244,12 @@ function buildPrefsWidget() { let imageList = Utils.getImageList(settings); historyEntry.append('current', _('Most recent image')); historyEntry.append('random', _('Random image')); + imageList.forEach((image) => { historyEntry.append(image.urlbase.replace('/th?id=OHR.', ''), Utils.shortenName(Utils.getImageTitle(image), 50)); }); + + // selected image can also be changed through the menu or even dconf settings.bind('selected-image', historyEntry, 'active_id', Gio.SettingsBindFlags.DEFAULT); settings.connect('changed::selected-image', () => { Utils.validate_imagename(settings); @@ -248,6 +267,8 @@ function buildPrefsWidget() { 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); + + // add a couple of preset buttons buttonGDMdefault.connect('clicked', (widget) => { Utils.set_blur_preset(settings, Utils.PRESET_GNOME_DEFAULT); }); @@ -265,13 +286,7 @@ function buildPrefsWidget() { // fetch if (httpSession) Utils.fetch_change_log(Me.metadata.version.toString(), change_log, httpSession); - lastreq = GLib.DateTime.new_now_utc(); return box; } -function log(msg) { - if (settings.get_boolean('debug-logging')) - print("BingWallpaper extension: " + msg); // disable to keep the noise down in journal -} -