prefs.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. // Bing Wallpaper GNOME extension
  2. // Copyright (C) 2017-2023 Michael Carroll
  3. // This extension is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU Lesser General Public License as published by
  5. // the Free Software Foundation, either version 3 of the License, or
  6. // (at your option) any later version.
  7. // See the GNU General Public License, version 3 or later for details.
  8. // Based on GNOME shell extension NASA APOD by Elia Argentieri https://github.com/Elinvention/gnome-shell-extension-nasa-apod
  9. import Gtk from 'gi://Gtk';
  10. import Gdk from 'gi://Gdk';
  11. import Gio from 'gi://Gio';
  12. import Soup from 'gi://Soup';
  13. import Adw from 'gi://Adw';
  14. import {ExtensionPreferences, gettext as _} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
  15. import * as Config from 'resource:///org/gnome/Shell/Extensions/js/misc/config.js';
  16. import * as Utils from './utils.js';
  17. import Carousel from './carousel.js';
  18. const BingImageURL = Utils.BingImageURL;
  19. var DESKTOP_SCHEMA = 'org.gnome.desktop.background';
  20. var PREFS_DEFAULT_WIDTH = 950;
  21. var PREFS_DEFAULT_HEIGHT = 950;
  22. export default class BingWallpaperExtensionPreferences extends ExtensionPreferences {
  23. fillPreferencesWindow(window) {
  24. // formally globals
  25. let settings = this.getSettings(Utils.BING_SCHEMA);
  26. let desktop_settings = this.getSettings(Utils.DESKTOP_SCHEMA);
  27. window.set_default_size(PREFS_DEFAULT_WIDTH, PREFS_DEFAULT_HEIGHT);
  28. let icon_image = null;
  29. let provider = new Gtk.CssProvider();
  30. let carousel = null;
  31. let httpSession = null;
  32. let log = (msg) => { // avoids need for globals
  33. if (settings.get_boolean('debug-logging'))
  34. console.log("BingWallpaper extension: " + msg); // disable to keep the noise down in journal
  35. }
  36. // Prepare labels and controls
  37. let buildable = new Gtk.Builder();
  38. // GTK4 removes some properties, and builder breaks when it sees them
  39. buildable.add_from_file( this.dir.get_path() + '/ui/Settings4.ui' );
  40. provider.load_from_path(this.dir.get_path() + '/ui/prefs.css');
  41. Gtk.StyleContext.add_provider_for_display(
  42. Gdk.Display.get_default(),
  43. provider,
  44. Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
  45. let box = buildable.get_object('prefs_widget');
  46. // fix size of prefs window in GNOME shell 40+ (but super racy, so is unreliable)
  47. buildable.get_object('extension_version').set_text(this.metadata.version.toString());
  48. buildable.get_object('extension_name').set_text(this.metadata.name.toString());
  49. // assign variables to UI objects we've loaded
  50. let hideSwitch = buildable.get_object('hide');
  51. let iconEntry = buildable.get_object('icon');
  52. let notifySwitch = buildable.get_object('notify');
  53. let bgSwitch = buildable.get_object('background');
  54. let styleEntry = buildable.get_object('background_style');
  55. let fileChooserBtn = buildable.get_object('download_folder');
  56. let fileChooser = buildable.get_object('file_chooser'); // this should only exist on Gtk4
  57. let folderOpenBtn = buildable.get_object('button_open_download_folder');
  58. let marketEntry = buildable.get_object('market');
  59. let resolutionEntry = buildable.get_object('resolution');
  60. let historyEntry = buildable.get_object('history');
  61. icon_image = buildable.get_object('icon_image');
  62. let overrideSwitch = buildable.get_object('lockscreen_override');
  63. let strengthEntry = buildable.get_object('entry_strength');
  64. let brightnessEntry = buildable.get_object('entry_brightness');
  65. let debugSwitch = buildable.get_object('debug_switch');
  66. let revertSwitch = buildable.get_object('revert_switch');
  67. let unsafeSwitch = buildable.get_object('unsafe_switch');
  68. let randomIntervalEntry = buildable.get_object('entry_random_interval');
  69. let change_log = buildable.get_object('change_log');
  70. let buttonGDMdefault = buildable.get_object('button_default_gnome');
  71. let buttonnoblur = buildable.get_object('button_no_blur');
  72. let buttonslightblur = buildable.get_object('button_slight_blur');
  73. let buttonImportData = buildable.get_object('button_json_import');
  74. let buttonExportData = buildable.get_object('button_json_export');
  75. let switchAlwaysExport = buildable.get_object('always_export_switch');
  76. let switchEnableShuffle = buildable.get_object('shuffle_enabled_switch');
  77. let entryShuffleMode = buildable.get_object('shuffle_mode_combo');
  78. let carouselFlowBox = (Gtk.get_major_version() == 4) ? buildable.get_object('carouselFlowBox'): null;
  79. try {
  80. httpSession = new Soup.Session();
  81. httpSession.user_agent = 'User-Agent: Mozilla/5.0 (X11; GNOME Shell/' + Config.PACKAGE_VERSION + '; Linux x86_64; +https://github.com/neffo/bing-wallpaper-gnome-extension ) BingWallpaper Gnome Extension/' + this.metadata.version;
  82. }
  83. catch (e) {
  84. log("Error creating httpSession: " + e);
  85. }
  86. // check that these are valid (can be edited through dconf-editor)
  87. Utils.validate_resolution(settings);
  88. Utils.validate_icon(settings, this.path, icon_image);
  89. // Indicator & notifications
  90. settings.bind('hide', hideSwitch, 'active', Gio.SettingsBindFlags.DEFAULT);
  91. settings.bind('notify', notifySwitch, 'active', Gio.SettingsBindFlags.DEFAULT);
  92. // add markets to dropdown list (aka a GtkComboText)
  93. Utils.icon_list.forEach((iconname, index) => {
  94. iconEntry.append(iconname, iconname);
  95. });
  96. // user selectable indicator icons
  97. settings.bind('icon-name', iconEntry, 'active_id', Gio.SettingsBindFlags.DEFAULT);
  98. settings.connect('changed::icon-name', () => {
  99. Utils.validate_icon(settings, this.path, icon_image);
  100. });
  101. iconEntry.set_active_id(settings.get_string('icon-name'));
  102. // connect switches to settings changes
  103. settings.bind('set-background', bgSwitch, 'active', Gio.SettingsBindFlags.DEFAULT);
  104. settings.bind('debug-logging', debugSwitch, 'active', Gio.SettingsBindFlags.DEFAULT);
  105. settings.bind('revert-to-current-image', revertSwitch, 'active', Gio.SettingsBindFlags.DEFAULT);
  106. settings.bind('override-unsafe-wayland', unsafeSwitch, 'active', Gio.SettingsBindFlags.DEFAULT);
  107. settings.bind('random-interval', randomIntervalEntry, 'value', Gio.SettingsBindFlags.DEFAULT);
  108. settings.bind('always-export-bing-json', switchAlwaysExport, 'active', Gio.SettingsBindFlags.DEFAULT);
  109. // button opens Nautilus at our image folder
  110. folderOpenBtn.connect('clicked', (widget) => {
  111. Utils.openImageFolder(settings);
  112. });
  113. // we populate the tab (gtk4+, gnome 40+), this was previously a button to open a new window in gtk3
  114. carousel = new Carousel(settings, null, null, carouselFlowBox, this.dir.get_path()); // auto load carousel
  115. // this is intended for migrating image folders between computers (or even sharing) or backups
  116. // we export the Bing JSON data to the image directory, so this folder becomes portable
  117. buttonImportData.connect('clicked', () => {
  118. Utils.importBingJSON(settings);
  119. });
  120. buttonExportData.connect('clicked', () => {
  121. Utils.exportBingJSON(settings);
  122. });
  123. //download folder
  124. fileChooserBtn.set_label(Utils.getWallpaperDir(settings));
  125. fileChooserBtn.connect('clicked', (widget) => {
  126. let parent = widget.get_root();
  127. let curWallpaperDir = Gio.File.new_for_path(Utils.getWallpaperDir(settings));
  128. fileChooser.set_current_folder(curWallpaperDir.get_parent());
  129. fileChooser.set_action(Gtk.FileChooserAction.SELECT_FOLDER);
  130. fileChooser.set_transient_for(parent);
  131. fileChooser.set_accept_label(_('Select folder'));
  132. fileChooser.show();
  133. });
  134. fileChooser.connect('response', (widget, response) => {
  135. if (response !== Gtk.ResponseType.ACCEPT) {
  136. return;
  137. }
  138. let fileURI = fileChooser.get_file().get_path().replace('file://', '');
  139. fileChooserBtn.set_label(fileURI);
  140. Utils.moveImagesToNewFolder(settings, Utils.getWallpaperDir(settings), fileURI);
  141. Utils.setWallpaperDir(settings, fileURI);
  142. });
  143. // in Gtk 4 instead we use a DropDown, but we need to treat it a bit special
  144. let market_grid = buildable.get_object('market_grid');
  145. marketEntry = Gtk.DropDown.new_from_strings(Utils.marketName);
  146. marketEntry.set_selected(Utils.markets.indexOf(settings.get_string('market')));
  147. market_grid.attach(marketEntry, 1, 0, 1, 2);
  148. marketEntry.connect('notify::selected-item', () => {
  149. let id = marketEntry.get_selected();
  150. settings.set_string('market', Utils.markets[id]);
  151. });
  152. settings.connect('changed::market', () => {
  153. marketEntry.set_selected(Utils.markets.indexOf(settings.get_string('market')));
  154. });
  155. settings.connect('changed::download-folder', () => {
  156. fileChooserBtn.set_label(Utils.getWallpaperDir(settings));
  157. });
  158. // Resolution
  159. Utils.resolutions.forEach((res) => { // add res to dropdown list (aka a GtkComboText)
  160. resolutionEntry.append(res, res);
  161. });
  162. settings.bind('resolution', resolutionEntry, 'active_id', Gio.SettingsBindFlags.DEFAULT);
  163. settings.connect('changed::resolution', () => {
  164. Utils.validate_resolution(settings);
  165. });
  166. // shuffle modes
  167. settings.bind('random-mode-enabled', switchEnableShuffle, 'active', Gio.SettingsBindFlags.DEFAULT);
  168. Utils.randomIntervals.forEach((x) => {
  169. entryShuffleMode.append(x.value, _(x.title));
  170. });
  171. settings.bind('random-interval-mode', entryShuffleMode, 'active_id', Gio.SettingsBindFlags.DEFAULT);
  172. // selected image can no longer be changed through a dropdown (didn't scale)
  173. settings.bind('selected-image', historyEntry, 'label', Gio.SettingsBindFlags.DEFAULT);
  174. settings.connect('changed::selected-image', () => {
  175. Utils.validate_imagename(settings);
  176. });
  177. // background styles (e.g. zoom or span)
  178. Utils.backgroundStyle.forEach((style) => {
  179. styleEntry.append(style, style);
  180. });
  181. desktop_settings.bind('picture-options', styleEntry, 'active_id', Gio.SettingsBindFlags.DEFAULT);
  182. // GDM3 lockscreen blur override
  183. settings.bind('override-lockscreen-blur', overrideSwitch, 'active', Gio.SettingsBindFlags.DEFAULT);
  184. settings.bind('lockscreen-blur-strength', strengthEntry, 'value', Gio.SettingsBindFlags.DEFAULT);
  185. settings.bind('lockscreen-blur-brightness', brightnessEntry, 'value', Gio.SettingsBindFlags.DEFAULT);
  186. // add a couple of preset buttons
  187. buttonGDMdefault.connect('clicked', (widget) => {
  188. Utils.set_blur_preset(settings, Utils.PRESET_GNOME_DEFAULT);
  189. });
  190. buttonnoblur.connect('clicked', (widget) => {
  191. Utils.set_blur_preset(settings, Utils.PRESET_NO_BLUR);
  192. });
  193. buttonslightblur.connect('clicked', (widget) => {
  194. Utils.set_blur_preset(settings, Utils.PRESET_SLIGHT_BLUR);
  195. });
  196. // fetch
  197. if (httpSession)
  198. Utils.fetch_change_log(this.metadata.version.toString(), change_log, httpSession);
  199. const page = new Adw.PreferencesPage();
  200. const group = new Adw.PreferencesGroup();
  201. group.add(box);
  202. page.add(group);
  203. window.add(page);
  204. }
  205. }