From 20dab4b6fc07238c26d3e5fc17f2d21f7646f379 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Aug 27 2021 16:20:16 +0000 Subject: import gnome-shell-extensions-3.32.1-20.el8 --- diff --git a/SOURCES/0001-heads-up-display-Add-extension-for-showing-persisten.patch b/SOURCES/0001-heads-up-display-Add-extension-for-showing-persisten.patch new file mode 100644 index 0000000..d426940 --- /dev/null +++ b/SOURCES/0001-heads-up-display-Add-extension-for-showing-persisten.patch @@ -0,0 +1,885 @@ +From 131b1b81f8f28bf57d080487e121d332546f1ab1 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Tue, 24 Aug 2021 15:03:57 -0400 +Subject: [PATCH] heads-up-display: Add extension for showing persistent heads + up display message + +--- + extensions/heads-up-display/extension.js | 320 ++++++++++++++++++ + extensions/heads-up-display/headsUpMessage.js | 150 ++++++++ + extensions/heads-up-display/meson.build | 8 + + extensions/heads-up-display/metadata.json.in | 11 + + ...ll.extensions.heads-up-display.gschema.xml | 54 +++ + extensions/heads-up-display/prefs.js | 175 ++++++++++ + extensions/heads-up-display/stylesheet.css | 32 ++ + meson.build | 1 + + 8 files changed, 751 insertions(+) + create mode 100644 extensions/heads-up-display/extension.js + create mode 100644 extensions/heads-up-display/headsUpMessage.js + create mode 100644 extensions/heads-up-display/meson.build + create mode 100644 extensions/heads-up-display/metadata.json.in + create mode 100644 extensions/heads-up-display/org.gnome.shell.extensions.heads-up-display.gschema.xml + create mode 100644 extensions/heads-up-display/prefs.js + create mode 100644 extensions/heads-up-display/stylesheet.css + +diff --git a/extensions/heads-up-display/extension.js b/extensions/heads-up-display/extension.js +new file mode 100644 +index 0000000..e4ef9e8 +--- /dev/null ++++ b/extensions/heads-up-display/extension.js +@@ -0,0 +1,320 @@ ++/* exported init enable disable */ ++ ++ ++const Signals = imports.signals; ++ ++const { ++ Atk, Clutter, Gio, GLib, GObject, Gtk, Meta, Shell, St, ++} = imports.gi; ++ ++const ExtensionUtils = imports.misc.extensionUtils; ++const Me = ExtensionUtils.getCurrentExtension(); ++ ++const Main = imports.ui.main; ++const HeadsUpMessage = Me.imports.headsUpMessage; ++ ++const Gettext = imports.gettext.domain('gnome-shell-extensions'); ++const _ = Gettext.gettext; ++ ++class Extension { ++ constructor() { ++ ExtensionUtils.initTranslations(); ++ } ++ ++ enable() { ++ this._settings = ExtensionUtils.getSettings('org.gnome.shell.extensions.heads-up-display'); ++ this._idleTimeoutChangedId = this._settings.connect('changed::idle-timeout', this._onIdleTimeoutChanged.bind(this)); ++ this._settingsChangedId = this._settings.connect('changed', this._updateMessage.bind(this)); ++ ++ this._idleMonitor = Meta.IdleMonitor.get_core(); ++ this._messageInhibitedUntilIdle = false; ++ this._oldMapWindow = Main.wm._mapWindow; ++ Main.wm._mapWindow = this._mapWindow; ++ this._windowManagerMapId = global.window_manager.connect('map', this._onWindowMap.bind(this)); ++ ++ if (Main.layoutManager._startingUp) ++ this._startupCompleteId = Main.layoutManager.connect('startup-complete', this._onStartupComplete.bind(this)); ++ else ++ this._onStartupComplete(this); ++ } ++ ++ disable() { ++ this._dismissMessage(); ++ ++ if (this._idleWatchId) { ++ this._idleMonitor.remove_watch(this._idleWatchId); ++ this._idleWatchId = 0; ++ } ++ ++ if (this._sessionModeUpdatedId) { ++ Main.sessionMode.disconnect(this._sessionModeUpdatedId); ++ this._sessionModeUpdatedId = 0; ++ } ++ ++ if (this._overviewShowingId) { ++ Main.overview.disconnect(this._overviewShowingId); ++ this._overviewShowingId = 0; ++ } ++ ++ if (this._overviewHiddenId) { ++ Main.overview.disconnect(this._overviewHiddenId); ++ this._overviewHiddenId = 0; ++ } ++ ++ if (this._panelConnectionId) { ++ Main.layoutManager.panelBox.disconnect(this._panelConnectionId); ++ this._panelConnectionId = 0; ++ } ++ ++ if (this._oldMapWindow) { ++ Main.wm._mapWindow = this._oldMapWindow; ++ this._oldMapWindow = null; ++ } ++ ++ if (this._windowManagerMapId) { ++ global.window_manager.disconnect(this._windowManagerMapId); ++ this._windowManagerMapId = 0; ++ } ++ ++ if (this._startupCompleteId) { ++ Main.layoutManager.disconnect(this._startupCompleteId); ++ this._startupCompleteId = 0; ++ } ++ ++ if (this._settingsChangedId) { ++ this._settings.disconnect(this._settingsChangedId); ++ this._settingsChangedId = 0; ++ } ++ } ++ ++ _onWindowMap(shellwm, actor) { ++ let windowObject = actor.meta_window; ++ let windowType = windowObject.get_window_type(); ++ ++ if (windowType != Meta.WindowType.NORMAL) ++ return; ++ ++ if (!this._message || !this._message.visible) ++ return; ++ ++ let messageRect = new Meta.Rectangle({ x: this._message.x, y: this._message.y, width: this._message.width, height: this._message.height }); ++ let windowRect = windowObject.get_frame_rect(); ++ ++ if (windowRect.intersect(messageRect)) { ++ windowObject.move_frame(false, windowRect.x, this._message.y + this._message.height); ++ } ++ } ++ ++ _onStartupComplete() { ++ this._overviewShowingId = Main.overview.connect('showing', this._updateMessage.bind(this)); ++ this._overviewHiddenId = Main.overview.connect('hidden', this._updateMessage.bind(this)); ++ this._panelConnectionId = Main.layoutManager.panelBox.connect('notify::visible', this._updateMessage.bind(this)); ++ this._sessionModeUpdatedId = Main.sessionMode.connect('updated', this._onSessionModeUpdated.bind(this)); ++ ++ this._updateMessage(); ++ } ++ ++ _onSessionModeUpdated() { ++ if (!Main.sessionMode.hasWindows) ++ this._messageInhibitedUntilIdle = false; ++ this._updateMessage(); ++ } ++ ++ _onIdleTimeoutChanged() { ++ if (this._idleWatchId) { ++ this._idleMonitor.remove_watch(this._idleWatchId); ++ this._idleWatchId = 0; ++ } ++ this._messageInhibitedUntilIdle = false; ++ } ++ ++ _updateMessage() { ++ if (this._messageInhibitedUntilIdle) { ++ if (this._message) ++ this._dismissMessage(); ++ return; ++ } ++ ++ if (this._idleWatchId) { ++ this._idleMonitor.remove_watch(this._idleWatchId); ++ this._idleWatchId = 0; ++ } ++ ++ if (Main.sessionMode.hasOverview && Main.overview.visible) { ++ this._dismissMessage(); ++ return; ++ } ++ ++ if (!Main.layoutManager.panelBox.visible) { ++ this._dismissMessage(); ++ return; ++ } ++ ++ let supportedModes = []; ++ ++ if (this._settings.get_boolean('show-when-unlocked')) ++ supportedModes.push('user'); ++ ++ if (this._settings.get_boolean('show-when-unlocking')) ++ supportedModes.push('unlock-dialog'); ++ ++ if (this._settings.get_boolean('show-when-locked')) ++ supportedModes.push('lock-screen'); ++ ++ if (this._settings.get_boolean('show-on-login-screen')) ++ supportedModes.push('gdm'); ++ ++ if (!supportedModes.includes(Main.sessionMode.currentMode) && ++ !supportedModes.includes(Main.sessionMode.parentMode)) { ++ this._dismissMessage(); ++ return; ++ } ++ ++ let heading = this._settings.get_string('message-heading'); ++ let body = this._settings.get_string('message-body'); ++ ++ if (!heading && !body) { ++ this._dismissMessage(); ++ return; ++ } ++ ++ if (!this._message) { ++ this._message = new HeadsUpMessage.HeadsUpMessage(heading, body); ++ ++ this._message.connect('notify::allocation', this._adaptSessionForMessage.bind(this)); ++ this._message.connect('clicked', this._onMessageClicked.bind(this)); ++ } ++ ++ this._message.reactive = true; ++ this._message.track_hover = true; ++ ++ this._message.setHeading(heading); ++ this._message.setBody(body); ++ ++ if (!Main.sessionMode.hasWindows) { ++ this._message.track_hover = false; ++ this._message.reactive = false; ++ } ++ } ++ ++ _onMessageClicked() { ++ if (!Main.sessionMode.hasWindows) ++ return; ++ ++ if (this._idleWatchId) { ++ this._idleMonitor.remove_watch(this._idleWatchId); ++ this._idleWatchId = 0; ++ } ++ ++ let idleTimeout = this._settings.get_uint('idle-timeout'); ++ this._idleWatchId = this._idleMonitor.add_idle_watch(idleTimeout * 1000, this._onUserIdle.bind(this)); ++ this._messageInhibitedUntilIdle = true; ++ this._updateMessage(); ++ } ++ ++ _onUserIdle() { ++ this._messageInhibitedUntilIdle = false; ++ this._updateMessage(); ++ } ++ ++ _dismissMessage() { ++ if (!this._message) { ++ return; ++ } ++ ++ this._message.visible = false; ++ this._message.destroy(); ++ this._message = null; ++ this._resetMessageTray(); ++ this._resetLoginDialog(); ++ } ++ ++ _resetMessageTray() { ++ if (!Main.messageTray) ++ return; ++ ++ Main.messageTray.actor.set_translation(0, 0, 0); ++ } ++ ++ _alignMessageTray() { ++ if (!Main.messageTray) ++ return; ++ ++ if (!this._message || !this._message.visible) { ++ this._resetMessageTray() ++ return; ++ } ++ ++ let panelBottom = Main.layoutManager.panelBox.y + Main.layoutManager.panelBox.height; ++ let messageBottom = this._message.y + this._message.height; ++ ++ Main.messageTray.actor.set_translation(0, messageBottom - panelBottom, 0); ++ } ++ ++ _resetLoginDialog() { ++ if (!Main.sessionMode.isGreeter) ++ return; ++ ++ if (!Main.screenShield || !Main.screenShield._dialog) ++ return; ++ ++ let dialog = Main.screenShield._dialog; ++ ++ if (this._authPromptAllocatedId) { ++ dialog.disconnect(this._authPromptAllocatedId); ++ this._authPromptAllocatedId = 0; ++ } ++ ++ dialog.style = null; ++ dialog._bannerView.style = null; ++ } ++ ++ _adaptLoginDialogForMessage() { ++ if (!Main.sessionMode.isGreeter) ++ return; ++ ++ if (!Main.screenShield || !Main.screenShield._dialog) ++ return; ++ ++ if (!this._message || !this._message.visible) { ++ this._resetLoginDialog() ++ return; ++ } ++ ++ let dialog = Main.screenShield._dialog; ++ ++ let messageHeight = this._message.y + this._message.height; ++ if (dialog._logoBin.visible) ++ messageHeight -= dialog._logoBin.height; ++ ++ if (messageHeight <= 0) { ++ dialog.style = null; ++ dialog._bannerView.style = null; ++ } else { ++ dialog.style = `margin-top: ${messageHeight}px;`; ++ ++ let bannerOnSide = dialog._bannerView.x + dialog._bannerView.width < dialog._authPrompt.actor.x; ++ ++ if (bannerOnSide) ++ dialog._bannerView.style = `margin-bottom: ${messageHeight}px;`; ++ else ++ dialog._bannerView.style = `margin-top: ${messageHeight}px`; ++ } ++ } ++ ++ _adaptSessionForMessage() { ++ this._alignMessageTray(); ++ ++ if (Main.sessionMode.isGreeter) { ++ this._adaptLoginDialogForMessage(); ++ if (!this._authPromptAllocatedId) { ++ let dialog = Main.screenShield._dialog; ++ this._authPromptAllocatedId = dialog._authPrompt.actor.connect("notify::allocation", this._adaptLoginDialogForMessage.bind(this)); ++ } ++ } ++ } ++} ++ ++function init() { ++ return new Extension(); ++} +diff --git a/extensions/heads-up-display/headsUpMessage.js b/extensions/heads-up-display/headsUpMessage.js +new file mode 100644 +index 0000000..d828d8c +--- /dev/null ++++ b/extensions/heads-up-display/headsUpMessage.js +@@ -0,0 +1,150 @@ ++const { Atk, Clutter, GObject, Pango, St } = imports.gi; ++const Layout = imports.ui.layout; ++const Main = imports.ui.main; ++const Signals = imports.signals; ++ ++var HeadsUpMessageBodyLabel = GObject.registerClass({ ++}, class HeadsUpMessageBodyLabel extends St.Label { ++ _init(params) { ++ super._init(params); ++ ++ this.clutter_text.single_line_mode = false; ++ this.clutter_text.line_wrap = true; ++ } ++ ++ vfunc_get_preferred_width(forHeight) { ++ let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex); ++ ++ let [labelMinimumWidth, labelNaturalWidth] = super.vfunc_get_preferred_width(forHeight); ++ ++ labelMinimumWidth = Math.min(labelMinimumWidth, .75 * workArea.width); ++ labelNaturalWidth = Math.min(labelNaturalWidth, .75 * workArea.width); ++ ++ return [labelMinimumWidth, labelNaturalWidth]; ++ } ++ ++ vfunc_get_preferred_height(forWidth) { ++ let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex); ++ let labelHeightUpperBound = .25 * workArea.height; ++ ++ this.clutter_text.single_line_mode = true; ++ this.clutter_text.line_wrap = false; ++ let [lineHeight] = super.vfunc_get_preferred_height(-1); ++ let numberOfLines = Math.floor(labelHeightUpperBound / lineHeight); ++ numberOfLines = Math.max(numberOfLines, 1); ++ ++ let labelHeight = lineHeight * numberOfLines; ++ ++ this.clutter_text.single_line_mode = false; ++ this.clutter_text.line_wrap = true; ++ let [labelMinimumHeight, labelNaturalHeight] = super.vfunc_get_preferred_height(forWidth); ++ ++ labelMinimumHeight = Math.min(labelMinimumHeight, labelHeight); ++ labelNaturalHeight = Math.min(labelNaturalHeight, labelHeight); ++ ++ return [labelMinimumHeight, labelNaturalHeight]; ++ } ++ ++ vfunc_allocate(box, flags) { ++ if (!this.visible) ++ return; ++ ++ super.vfunc_allocate(box, flags); ++ } ++}); ++ ++var HeadsUpMessage = GObject.registerClass({ ++}, class HeadsUpMessage extends St.Button { ++ _init(heading, body) { ++ super._init({ ++ style_class: 'message', ++ accessible_role: Atk.Role.NOTIFICATION, ++ can_focus: false, ++ }); ++ ++ Main.layoutManager.addChrome(this, { affectsInputRegion: true }); ++ ++ this.add_style_class_name('heads-up-display-message'); ++ ++ this._panelAllocationId = Main.layoutManager.panelBox.connect ("notify::allocation", this._alignWithPanel.bind(this)); ++ this.connect("notify::allocation", this._alignWithPanel.bind(this)); ++ ++ this._messageTraySnappingId = Main.messageTray.connect ("notify::y", () => { ++ if (!this.visible) ++ return; ++ ++ if (!Main.messageTray.visible) ++ return; ++ ++ if (Main.messageTray.y >= this.y && Main.messageTray.y < this.y + this.height) ++ Main.messageTray.y = this.y + this.height; ++ }); ++ ++ ++ let contentsBox = new St.BoxLayout({ style_class: 'heads-up-message-content', ++ vertical: true, ++ x_align: Clutter.ActorAlign.CENTER }); ++ this.add_actor(contentsBox); ++ ++ this.headingLabel = new St.Label({ style_class: 'heads-up-message-heading', ++ x_expand: true, ++ x_align: Clutter.ActorAlign.CENTER }); ++ this.setHeading(heading); ++ contentsBox.add_actor(this.headingLabel); ++ this.contentsBox = contentsBox; ++ ++ this.bodyLabel = new HeadsUpMessageBodyLabel({ style_class: 'heads-up-message-body', ++ x_expand: true, ++ y_expand: true }); ++ contentsBox.add_actor(this.bodyLabel); ++ ++ this.setBody(body); ++ this.bodyLabel.clutter_text.label = this.bodyLabel; ++ } ++ ++ _alignWithPanel() { ++ if (!this.visible) ++ return; ++ ++ this.x = Main.panel.actor.x; ++ this.x += Main.panel.actor.width / 2; ++ this.x -= this.width / 2; ++ this.x = Math.floor(this.x); ++ this.y = Main.panel.actor.y + Main.panel.actor.height; ++ this.queue_relayout(); ++ } ++ ++ setHeading(text) { ++ if (text) { ++ let heading = text ? text.replace(/\n/g, ' ') : ''; ++ this.headingLabel.text = heading; ++ this.headingLabel.visible = true; ++ } else { ++ this.headingLabel.text = text; ++ this.headingLabel.visible = false; ++ } ++ } ++ ++ setBody(text) { ++ this.bodyLabel.text = text; ++ if (text) { ++ this.bodyLabel.visible = true; ++ } else { ++ this.bodyLabel.visible = false; ++ } ++ } ++ ++ destroy() { ++ if (this._panelAllocationId) { ++ Main.layoutManager.panelBox.disconnect(this._panelAllocationId); ++ this._panelAllocationId = 0; ++ } ++ ++ if (this._messageTraySnappingId) { ++ Main.messageTray.disconnect(this._messageTraySnappingId); ++ this._messageTraySnappingId = 0; ++ } ++ ++ super.destroy(); ++ } ++}); +diff --git a/extensions/heads-up-display/meson.build b/extensions/heads-up-display/meson.build +new file mode 100644 +index 0000000..40c3de0 +--- /dev/null ++++ b/extensions/heads-up-display/meson.build +@@ -0,0 +1,8 @@ ++extension_data += configure_file( ++ input: metadata_name + '.in', ++ output: metadata_name, ++ configuration: metadata_conf ++) ++ ++extension_sources += files('headsUpMessage.js', 'prefs.js') ++extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml') +diff --git a/extensions/heads-up-display/metadata.json.in b/extensions/heads-up-display/metadata.json.in +new file mode 100644 +index 0000000..e7ab71a +--- /dev/null ++++ b/extensions/heads-up-display/metadata.json.in +@@ -0,0 +1,11 @@ ++{ ++"extension-id": "@extension_id@", ++"uuid": "@uuid@", ++"gettext-domain": "@gettext_domain@", ++"name": "Heads-up Display Message", ++"description": "Add a message to be displayed on screen always above all windows and chrome.", ++"original-authors": [ "rstrode@redhat.com" ], ++"shell-version": [ "@shell_current@" ], ++"url": "@url@", ++"session-modes": [ "gdm", "lock-screen", "unlock-dialog", "user" ] ++} +diff --git a/extensions/heads-up-display/org.gnome.shell.extensions.heads-up-display.gschema.xml b/extensions/heads-up-display/org.gnome.shell.extensions.heads-up-display.gschema.xml +new file mode 100644 +index 0000000..ea1f377 +--- /dev/null ++++ b/extensions/heads-up-display/org.gnome.shell.extensions.heads-up-display.gschema.xml +@@ -0,0 +1,54 @@ ++ ++ ++ ++ 30 ++ Idle Timeout ++ ++ Number of seconds until message is reshown after user goes idle. ++ ++ ++ ++ "" ++ Message to show at top of display ++ ++ The top line of the heads up display message. ++ ++ ++ ++ "" ++ Banner message ++ ++ A message to always show at the top of the screen. ++ ++ ++ ++ true ++ Show on login screen ++ ++ Whether or not the message should display on the login screen ++ ++ ++ ++ false ++ Show on screen shield ++ ++ Whether or not the message should display when the screen is locked ++ ++ ++ ++ false ++ Show on unlock screen ++ ++ Whether or not the message should display on the unlock screen. ++ ++ ++ ++ false ++ Show in user session ++ ++ Whether or not the message should display when the screen is unlocked. ++ ++ ++ ++ +diff --git a/extensions/heads-up-display/prefs.js b/extensions/heads-up-display/prefs.js +new file mode 100644 +index 0000000..b4b6f94 +--- /dev/null ++++ b/extensions/heads-up-display/prefs.js +@@ -0,0 +1,175 @@ ++ ++/* Desktop Icons GNOME Shell extension ++ * ++ * Copyright (C) 2017 Carlos Soriano ++ * ++ * 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 { Gio, GObject, Gdk, Gtk } = imports.gi; ++const ExtensionUtils = imports.misc.extensionUtils; ++const Gettext = imports.gettext.domain('gnome-shell-extensions'); ++const _ = Gettext.gettext; ++const N_ = e => e; ++const cssData = ` ++ .no-border { ++ border: none; ++ } ++ ++ .border { ++ border: 1px solid; ++ border-radius: 3px; ++ border-color: #b6b6b3; ++ box-shadow: inset 0 0 0 1px rgba(74, 144, 217, 0); ++ background-color: white; ++ } ++ ++ .margins { ++ padding-left: 8px; ++ padding-right: 8px; ++ padding-bottom: 8px; ++ } ++ ++ .message-label { ++ font-weight: bold; ++ } ++`; ++ ++var settings; ++ ++function init() { ++ settings = ExtensionUtils.getSettings("org.gnome.shell.extensions.heads-up-display"); ++ let cssProvider = new Gtk.CssProvider(); ++ cssProvider.load_from_data(cssData); ++ ++ let screen = Gdk.Screen.get_default(); ++ Gtk.StyleContext.add_provider_for_screen(screen, cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); ++} ++ ++function buildPrefsWidget() { ++ ExtensionUtils.initTranslations(); ++ ++ let contents = new Gtk.Box({ ++ orientation: Gtk.Orientation.VERTICAL, ++ border_width: 20, ++ spacing: 10, ++ }); ++ ++ contents.add(buildSwitch('show-when-locked', _("Show message when screen is locked"))); ++ contents.add(buildSwitch('show-when-unlocking', _("Show message on unlock screen"))); ++ contents.add(buildSwitch('show-when-unlocked', _("Show message when screen is unlocked"))); ++ contents.add(buildSpinButton('idle-timeout', _("Seconds after user goes idle before reshowing message"))); ++ ++ let outerMessageBox = new Gtk.Box({ ++ orientation: Gtk.Orientation.VERTICAL, ++ border_width: 0, ++ spacing: 5, ++ }); ++ contents.add(outerMessageBox); ++ ++ let messageLabel = new Gtk.Label({ ++ label: 'Message', ++ halign: Gtk.Align.START, ++ }); ++ messageLabel.get_style_context().add_class("message-label"); ++ outerMessageBox.add(messageLabel); ++ ++ let innerMessageBox = new Gtk.Box({ ++ orientation: Gtk.Orientation.VERTICAL, ++ border_width: 0, ++ spacing: 0, ++ }); ++ innerMessageBox.get_style_context().add_class("border"); ++ outerMessageBox.add(innerMessageBox); ++ ++ innerMessageBox.add(buildEntry('message-heading', _("Message Heading"))); ++ innerMessageBox.add(buildTextView('message-body', _("Message Body"))); ++ contents.show_all(); ++ return contents; ++} ++ ++function buildTextView(key, labelText) { ++ let textView = new Gtk.TextView({ ++ accepts_tab: false, ++ wrap_mode: Gtk.WrapMode.WORD, ++ }); ++ settings.bind(key, textView.get_buffer(), 'text', Gio.SettingsBindFlags.DEFAULT); ++ ++ let scrolledWindow = new Gtk.ScrolledWindow({ ++ expand: true, ++ }); ++ let styleContext = scrolledWindow.get_style_context(); ++ styleContext.add_class("margins"); ++ ++ scrolledWindow.add(textView); ++ return scrolledWindow; ++} ++function buildEntry(key, labelText) { ++ let entry = new Gtk.Entry({ placeholder_text: labelText }); ++ let styleContext = entry.get_style_context(); ++ styleContext.add_class("no-border"); ++ settings.bind(key, entry, 'text', Gio.SettingsBindFlags.DEFAULT); ++ ++ entry.get_settings()['gtk-entry-select-on-focus'] = false; ++ ++ return entry; ++} ++ ++function buildSpinButton(key, labelText) { ++ let hbox = new Gtk.Box({ ++ orientation: Gtk.Orientation.HORIZONTAL, ++ spacing: 10, ++ }); ++ let label = new Gtk.Label({ ++ label: labelText, ++ xalign: 0, ++ }); ++ let adjustment = new Gtk.Adjustment({ ++ value: 0, ++ lower: 0, ++ upper: 2147483647, ++ step_increment: 1, ++ page_increment: 60, ++ page_size: 60, ++ }); ++ let spinButton = new Gtk.SpinButton({ ++ adjustment: adjustment, ++ climb_rate: 1.0, ++ digits: 0, ++ max_width_chars: 3, ++ width_chars: 3, ++ }); ++ settings.bind(key, spinButton, 'value', Gio.SettingsBindFlags.DEFAULT); ++ hbox.pack_start(label, true, true, 0); ++ hbox.add(spinButton); ++ return hbox; ++} ++ ++function buildSwitch(key, labelText) { ++ let hbox = new Gtk.Box({ ++ orientation: Gtk.Orientation.HORIZONTAL, ++ spacing: 10, ++ }); ++ let label = new Gtk.Label({ ++ label: labelText, ++ xalign: 0, ++ }); ++ let switcher = new Gtk.Switch({ ++ active: settings.get_boolean(key), ++ }); ++ settings.bind(key, switcher, 'active', Gio.SettingsBindFlags.DEFAULT); ++ hbox.pack_start(label, true, true, 0); ++ hbox.add(switcher); ++ return hbox; ++} +diff --git a/extensions/heads-up-display/stylesheet.css b/extensions/heads-up-display/stylesheet.css +new file mode 100644 +index 0000000..9303446 +--- /dev/null ++++ b/extensions/heads-up-display/stylesheet.css +@@ -0,0 +1,32 @@ ++.heads-up-display-message { ++ background-color: rgba(0.24, 0.24, 0.24, 0.80); ++ border: 1px solid black; ++ border-radius: 6px; ++ color: #eeeeec; ++ font-size: 11pt; ++ margin-top: 0.5em; ++ margin-bottom: 0.5em; ++ padding: 0.9em; ++} ++ ++.heads-up-display-message:insensitive { ++ background-color: rgba(0.24, 0.24, 0.24, 0.33); ++} ++ ++.heads-up-display-message:hover { ++ background-color: rgba(0.24, 0.24, 0.24, 0.2); ++ border: 1px solid rgba(0.0, 0.0, 0.0, 0.5); ++ color: #4d4d4d; ++ transition-duration: 250ms; ++} ++ ++.heads-up-message-heading { ++ height: 1.75em; ++ font-size: 1.25em; ++ font-weight: bold; ++ text-align: center; ++} ++ ++.heads-up-message-body { ++ text-align: center; ++} +diff --git a/meson.build b/meson.build +index 9e59729..84e161d 100644 +--- a/meson.build ++++ b/meson.build +@@ -17,60 +17,61 @@ modedir = join_paths(shelldir, 'modes') + themedir = join_paths(shelldir, 'theme') + + schemadir = join_paths(datadir, 'glib-2.0', 'schemas') + sessiondir = join_paths(datadir, 'gnome-session', 'sessions') + xsessiondir = join_paths(datadir, 'xsessions') + + js60 = find_program('js60', required: false) + + ver_arr = meson.project_version().split('.') + if ver_arr[1].to_int().is_even() + shell_version = '@0@.@1@'.format(ver_arr[0], ver_arr[1]) + else + shell_version = '.'.join(ver_arr) + endif + + uuid_suffix = '@gnome-shell-extensions.gcampax.github.com' + + classic_extensions = [ + 'apps-menu', + 'desktop-icons', + 'horizontal-workspaces', + 'places-menu', + 'launch-new-instance', + 'top-icons', + 'window-list' + ] + + default_extensions = classic_extensions + default_extensions += [ + 'drive-menu', ++ 'heads-up-display', + 'screenshot-window-sizer', + 'windowsNavigator', + 'workspace-indicator' + ] + + all_extensions = default_extensions + all_extensions += [ + 'auto-move-windows', + 'dash-to-dock', + 'disable-screenshield', + 'gesture-inhibitor', + 'native-window-placement', + 'no-hot-corner', + 'panel-favorites', + 'systemMonitor', + 'updates-dialog', + 'user-theme', + 'window-grouper' + ] + + enabled_extensions = get_option('enable_extensions') + + if enabled_extensions.length() == 0 + set = get_option('extension_set') + + if set == 'classic' + enabled_extensions += classic_extensions + elif set == 'default' + enabled_extensions += default_extensions + elif set == 'all' +-- +2.27.0 + diff --git a/SPECS/gnome-shell-extensions.spec b/SPECS/gnome-shell-extensions.spec index 15fa8bb..105fbe9 100644 --- a/SPECS/gnome-shell-extensions.spec +++ b/SPECS/gnome-shell-extensions.spec @@ -6,7 +6,7 @@ Name: gnome-shell-extensions Version: 3.32.1 -Release: 19%{?dist} +Release: 20%{?dist} Summary: Modify and extend GNOME Shell functionality and behavior Group: User Interface/Desktops @@ -45,6 +45,7 @@ Patch0016: 0001-general-launch-only-executable-files.patch Patch0017: desktop-icons-touch-support.patch Patch0018: 0001-Add-gesture-inhibitor-extension.patch Patch0019: 0001-top-icons-Don-t-use-wm_class-as-role.patch +Patch0020: 0001-heads-up-display-Add-extension-for-showing-persisten.patch %description GNOME Shell Extensions is a collection of extensions providing additional and @@ -57,6 +58,7 @@ Enabled extensions: * disable-screenshield * desktop-icons * gesture-inhibitor + * heads-up-display * horizontal-workspaces * drive-menu * launch-new-instance @@ -166,6 +168,17 @@ Requires: %{pkg_prefix}-common = %{version}-%{release} This GNOME Shell extension disabled the screen shield if screen locking is disabled. +%package -n %{pkg_prefix}-heads-up-display +Summary: Display persistent on-screen message +Group: User Interface/Desktops +License: GPLv3+ +Requires: %{pkg_prefix}-common = %{version}-%{release} + +%description -n %{pkg_prefix}-heads-up-display +This GNOME Shell extension displays a persistent message in the top middle of the screen. +This message can appear on the login screen, lock screen, or regular user session. + + %package -n %{pkg_prefix}-horizontal-workspaces Summary: Desktop icons support for the classic experience Group: User Interface/Desktops @@ -413,6 +426,11 @@ cp $RPM_SOURCE_DIR/gnome-classic.desktop $RPM_BUILD_ROOT%{_datadir}/xsessions %{_datadir}/gnome-shell/extensions/disable-screenshield*/ +%files -n %{pkg_prefix}-heads-up-display +%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.heads-up-display.gschema.xml +%{_datadir}/gnome-shell/extensions/heads-up-display*/ + + %files -n %{pkg_prefix}-horizontal-workspaces %{_datadir}/gnome-shell/extensions/horizontal-workspaces*/ @@ -494,6 +512,10 @@ cp $RPM_SOURCE_DIR/gnome-classic.desktop $RPM_BUILD_ROOT%{_datadir}/xsessions %changelog +* Thu Aug 26 2021 Ray Strode - 3.32.1-20 +- Add extension for displaying heads up message + Related: #1651378 + * Wed Jun 02 2021 Florian Müllner - 3.32.1-19 - Don't use status icon wm_class as top bar role Resolves: #1897932