From 80bf68c4844e32109ae38fdbbcbe53c7fe090fb1 Mon Sep 17 00:00:00 2001 From: goodwillcoding Date: Mon, 15 Jun 2020 07:52:13 +0000 Subject: [PATCH] On-demand scheduling with topbar button and keybinding --- Makefile | 1 + src/compat.js | 42 ++++++ src/modules/SettingsManager.js | 11 ++ src/modules/Timer.js | 4 + src/modules/TimerOndemand.js | 120 ++++++++++++++++++ src/preferences/Schedule.js | 75 ++++++++++- ....extensions.nightthemeswitcher.gschema.xml | 15 +++ 7 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 src/compat.js create mode 100644 src/modules/TimerOndemand.js diff --git a/Makefile b/Makefile index 99efa37..a9e0996 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,7 @@ build: build-clean mkdir -p ./build gnome-extensions pack \ --extra-source=../LICENSE \ + --extra-source=./compat.js \ --extra-source=./config.js \ --extra-source=./convenience.js \ --extra-source=./utils.js \ diff --git a/src/compat.js b/src/compat.js new file mode 100644 index 0000000..a3cf22b --- /dev/null +++ b/src/compat.js @@ -0,0 +1,42 @@ +/* +Night Theme Switcher Gnome Shell extension + +Copyright (C) 2020 Romain Vigier + +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 . +*/ + +const Meta = imports.gi.Meta; + +const shell_minor_version = parseInt(imports.misc.config.PACKAGE_VERSION.split('.')[1]); + + +function key_binding_auto_repeat() { + // if version is less then 3.30 the keybinding flags are NONE + if (shell_minor_version < 30) { + return Meta.KeyBindingFlags.NONE; + } + else { + return Meta.KeyBindingFlags.IGNORE_AUTOREPEAT; + } +}; + + +function get_actor(subject) { + if (shell_minor_version > 34) { + return subject; + } + else { + return subject.actor; + } +}; diff --git a/src/modules/SettingsManager.js b/src/modules/SettingsManager.js index 358ac4e..7c2cbd9 100644 --- a/src/modules/SettingsManager.js +++ b/src/modules/SettingsManager.js @@ -296,6 +296,17 @@ var SettingsManager = class { } } + get ondemand_time() { + return this._extensionsSettings.get_string('ondemand-time'); + } + + set ondemand_time(value) { + if ( value !== this.ondemand_time ) { + this._extensionsSettings.set_string('ondemand-time', value); + log_debug(`The on-demand time has been set to ${value}.`); + } + } + get schedule_sunrise() { return this._extensionsSettings.get_double('schedule-sunrise'); } diff --git a/src/modules/Timer.js b/src/modules/Timer.js index e5695b9..f511242 100644 --- a/src/modules/Timer.js +++ b/src/modules/Timer.js @@ -26,6 +26,7 @@ const { log_debug } = Me.imports.utils; const { TimerNightlight } = Me.imports.modules.TimerNightlight; const { TimerLocation } = Me.imports.modules.TimerLocation; const { TimerSchedule } = Me.imports.modules.TimerSchedule; +const { TimerOndemand } = Me.imports.modules.TimerOndemand; /** @@ -112,6 +113,9 @@ var Timer = class { case 'schedule': this._source = new TimerSchedule(); break; + case 'ondemand': + this._source = new TimerOndemand(); + break; } } diff --git a/src/modules/TimerOndemand.js b/src/modules/TimerOndemand.js new file mode 100644 index 0000000..cf1bc7e --- /dev/null +++ b/src/modules/TimerOndemand.js @@ -0,0 +1,120 @@ +/* +Night Theme Switcher Gnome Shell extension + +Copyright (C) 2020 Romain Vigier + +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 . +*/ + +const { GLib, Shell, St } = imports.gi; +const { extensionUtils } = imports.misc; +const Signals = imports.signals; + +const { main, panelMenu } = imports.ui; + +const Me = extensionUtils.getCurrentExtension(); + +const e = Me.imports.extension; +const { log_debug } = Me.imports.utils; +const { key_binding_auto_repeat, get_actor } = Me.imports.compat; + +/** + * The On-demand Timer allows the user to manually switch between the day and + * night variants with a button in the top bar and a keybinding. + * + * The user can change the key combination in the extension's preferences. + */ +var TimerOndemand = class { + + constructor() { + this._button = null; + this._icon = null; + } + + enable() { + log_debug('Enabling On-demand Timer ...'); + this._add_keybinding(); + this._add_button(); + log_debug('On-demand Timer enabled.'); + } + + disable() { + log_debug('Disabling On-demand Timer ...'); + this._remove_keybinding(); + this._remove_button(); + log_debug('On-demand Timer disabled.'); + } + + + get time() { + return e.settingsManager.ondemand_time; + } + + _add_keybinding() { + log_debug('Adding On-demand Timer keybinding...'); + // add our own keybinging handler + main.wm.addKeybinding( + 'nightthemeswitcher-ondemand-keybinding', + e.settingsManager._extensionsSettings, + key_binding_auto_repeat(), + Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW, + this._toggle_time.bind(this) + ); + log_debug('Added On-demand Timer keybinding.'); + } + + _remove_keybinding() { + log_debug('Removing On-demand Timer keybinding...'); + main.wm.removeKeybinding('nightthemeswitcher-ondemand-keybinding'); + log_debug('Removed On-demand Timer keybinding.'); + } + + _add_button() { + log_debug('Adding On-demand Timer button...'); + + this._icon = new St.Icon({ + icon_name: this._get_icon_name_for_current_time(), + style_class: 'system-status-icon' + }); + + this._button = new panelMenu.Button(0.0); + let button_actor = get_actor(this._button); + button_actor.add_actor(this._icon); + this._button.connect( + 'button-press-event', + this._toggle_time.bind(this) + ); + main.panel.addToStatusArea('NightThemeSwitcherButton', this._button); + + log_debug('Added On-demand Timer button.'); + } + + _remove_button() { + log_debug('Removing On-demand Timer button...'); + this._button.destroy(); + log_debug('Removed On-demand Timer button.'); + } + + _toggle_time() { + e.settingsManager.ondemand_time = e.timer.time === 'day' ? 'night' : 'day'; + this.emit('time-changed', this.time); + this._icon.icon_name = this._get_icon_name_for_current_time(); + + } + + _get_icon_name_for_current_time() { + return e.timer.time === 'day' ? 'weather-clear-symbolic' : 'weather-clear-night-symbolic'; + } + +} +Signals.addSignalMethods(TimerOndemand.prototype); diff --git a/src/preferences/Schedule.js b/src/preferences/Schedule.js index 07bd3d0..becd1c5 100644 --- a/src/preferences/Schedule.js +++ b/src/preferences/Schedule.js @@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -const { Gio, Gtk } = imports.gi; +const { Gio, GObject, Gtk } = imports.gi; const { extensionUtils } = imports.misc; const Me = extensionUtils.getCurrentExtension(); @@ -42,6 +42,7 @@ var SchedulePreferences = class { content.add_row(new SettingsListRow(_('Manual time source'), new ManualTimeSourceControl())); content.add_row(new SettingsListRow(_('Time source'), new TimeSourceControl())); + content.add_row(new SettingsListRow(_('Shortcut'), new KeyBindingControl())); content.add_row(new SettingsListRow(_('Sunrise'), new SuntimeControl('sunrise'))); content.add_row(new SettingsListRow(_('Sunset'), new SuntimeControl('sunset'))); @@ -51,6 +52,61 @@ var SchedulePreferences = class { } +class KeyBindingControl { + + constructor() { + const settings = extensionUtils.getSettings(); + const KEYBINDING_KEY = 'nightthemeswitcher-ondemand-keybinding'; + const COLUMN_KEY = 0; + const COLUMN_MODS = 1; + + const list_store = new Gtk.ListStore(); + list_store.set_column_types([GObject.TYPE_INT, GObject.TYPE_INT]); + const tree_view = new Gtk.TreeView({model: list_store}); + tree_view.set_headers_visible(false); + + const renderer = new Gtk.CellRendererAccel({ editable: true}); + const column = new Gtk.TreeViewColumn(); + const iter = list_store.append(); + + const update_shortcut_row = (accel) => { + const [key, mods] = accel ? Gtk.accelerator_parse(accel) : [0, 0]; + list_store.set(iter, [COLUMN_KEY, COLUMN_MODS], [key, mods]); + }; + + renderer.connect('accel-edited', (renderer, path, key, mods) => { + const accel = Gtk.accelerator_name(key, mods); + update_shortcut_row(accel); + settings.set_strv(KEYBINDING_KEY, [accel]); + }); + + renderer.connect('accel-cleared', () => { + update_shortcut_row(null); + settings.set_strv(KEYBINDING_KEY, []); + }); + + settings.connect(`changed::${KEYBINDING_KEY}`, () => { + update_shortcut_row(settings.get_strv(KEYBINDING_KEY)[0]); + }); + + column.pack_start(renderer, true); + column.add_attribute(renderer, 'accel-key', COLUMN_KEY); + column.add_attribute(renderer, 'accel-mods', COLUMN_MODS); + + tree_view.append_column(column); + update_shortcut_row(settings.get_strv(KEYBINDING_KEY)[0]); + + const update_treeview_sensitivity = (tree_view) => { + tree_view.set_sensitive(!!(settings.get_string('time-source') === 'ondemand')); + } + settings.connect('changed::time-source', () => update_treeview_sensitivity(tree_view)); + update_treeview_sensitivity(tree_view) + + return tree_view; + } + +} + class ManualTimeSourceControl { constructor() { @@ -132,6 +188,23 @@ class TimeSourceControl { }); box.pack_start(schedule_radio, false, false, 0); + const ondemand_radio = new Gtk.RadioButton({ + label: _('On-demand'), + group: nightlight_radio, + active: (settings.get_string('time-source') === 'ondemand') + }); + settings.bind( + 'manual-time-source', + ondemand_radio, + 'sensitive', + Gio.SettingsBindFlags.DEFAULT + ); + ondemand_radio.connect('toggled', () => { + settings.set_string('time-source', 'ondemand') + }); + box.pack_start(ondemand_radio, false, false, 0); + + return box; } diff --git a/src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml b/src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml index 457418d..25e97ed 100644 --- a/src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml +++ b/src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml @@ -86,11 +86,26 @@ + "schedule" Time source The source used to check current time + + + + + + "day" + On-demand time + The current time used in on-demand mode + + + t']]]> + Key combination to toggle time + The key combination that will toggle time in on-demand mode + false Use manual time source