From ebe89ed971a9768962b1f42d6df6d02decd0c382 Mon Sep 17 00:00:00 2001 From: JosephMcc Date: Wed, 27 Nov 2024 13:06:30 -0800 Subject: [PATCH] endSession: Restyle the end session dialog --- .../theme/cinnamon-sass/widgets/_dialogs.scss | 68 ++-- js/ui/cinnamonDBus.js | 4 +- js/ui/dialog.js | 122 +++++++ js/ui/endSessionDialog.js | 319 +++++++----------- js/ui/main.js | 25 +- 5 files changed, 292 insertions(+), 246 deletions(-) diff --git a/data/theme/cinnamon-sass/widgets/_dialogs.scss b/data/theme/cinnamon-sass/widgets/_dialogs.scss index 64f1411d30..f6fadf9fe6 100644 --- a/data/theme/cinnamon-sass/widgets/_dialogs.scss +++ b/data/theme/cinnamon-sass/widgets/_dialogs.scss @@ -27,47 +27,49 @@ } } -// endSessionDialog.js -.end-session-dialog { - width: 40em; - transition-duration: 100ms; +// List in dialogs +.dialog-list { + spacing: $base_padding * 3; - .dialog-content-box { - spacing: $base_margin * 3; - width: 30em; - } + .dialog-list-title { + @extend %heading; + text-align: center; + } - .end-session-dialog-inhibitor-list-frame { - background-color: $light_bg_color; - border-radius: $base_border_radius; - border: 1px solid $borders_color; - padding-left: 5px; - padding-right: 5px; - padding-top: 2px; - padding-bottom: 2px; - } + .dialog-list-scrollview { max-height: 200px; } + .dialog-list-box { + spacing: 1em; - .end-session-dialog-inhibitor-list { - spacing-rows: 5px; - spacing-columns: 20px; - padding: 2px; - } + .dialog-list-item { + spacing: 1em; - .end-session-dialog-inhibitor-list-reason { - width: 25em; + .dialog-list-item-title { font-weight: bold; } + .dialog-list-item-description { + @extend %caption; + color: darken($fg_color, 5%); + } } + } +} + +// end session dialog + +.end-session-dialog { + width: 36em; + + .dialog-content-box { spacing: 0; } - .end-session-dialog-progress-bar { - min-width: 160px; - -barlevel-height: 6px; - -barlevel-background-color: $base_color; - -barlevel-active-background-color: $fg_color; - -barlevel-amplify-color: $warning_color; - -barlevel-amplify-separator-width: $base_padding * 0.5; + .dialog-list { + spacing: 0; - &:ltr { margin-right: $base_padding; } - &:rtl { margin-left: $base_padding; } + .dialog-list-title { + color: $warning_color; + background-color: tranparentize($warning_color, 0.9); + padding: $base_padding * 1.5; + border-radius: $base_border_radius; + margin: $base_margin 0; } + } } // message dialog diff --git a/js/ui/cinnamonDBus.js b/js/ui/cinnamonDBus.js index 69ecb6169b..9fde31f5c9 100644 --- a/js/ui/cinnamonDBus.js +++ b/js/ui/cinnamonDBus.js @@ -521,13 +521,13 @@ CinnamonDBus.prototype = { ShowEndSessionDialog(mode) { GLib.idle_add(GLib.PRIORITY_DEFAULT, () => { - Main.show_end_session_dialog(mode); + Main.endSessionDialog.open(mode); return GLib.SOURCE_REMOVE; }); }, CloseEndSessionDialog() { - Main.close_end_session_dialog(); + Main.endSessionDialog.close(); }, CinnamonVersion: Config.PACKAGE_VERSION diff --git a/js/ui/dialog.js b/js/ui/dialog.js index 2e8fdcfdc0..0dad0d156a 100644 --- a/js/ui/dialog.js +++ b/js/ui/dialog.js @@ -205,6 +205,7 @@ var MessageDialogContent = GObject.registerClass({ style_class: 'message-dialog-content', x_expand: true, vertical: true, + important: true, }; super._init(Object.assign(defaultParams, params)); @@ -270,3 +271,124 @@ var MessageDialogContent = GObject.registerClass({ this.notify('description'); } }); + +var ListSection = GObject.registerClass({ + Properties: { + 'title': GObject.ParamSpec.string( + 'title', 'title', 'title', + GObject.ParamFlags.READWRITE | + GObject.ParamFlags.CONSTRUCT, + null), + }, +}, class ListSection extends St.BoxLayout { + _init(params) { + this._title = new St.Label({ style_class: 'dialog-list-title' }); + + this.list = new St.BoxLayout({ + style_class: 'dialog-list-box', + vertical: true, + }); + + this._listScrollView = new St.ScrollView({ + style_class: 'dialog-list-scrollview', + hscrollbar_policy: St.PolicyType.NEVER, + }); + this._listScrollView.add_actor(this.list); + + super._init({ + style_class: 'dialog-list', + x_expand: true, + vertical: true, + important: true, + ...params, + }); + + this.label_actor = this._title; + this.add_child(this._title); + this.add_child(this._listScrollView); + } + + get title() { + return this._title.text; + } + + set title(title) { + _setLabel(this._title, title); + this.notify('title'); + } +}); + +var ListSectionItem = GObject.registerClass({ + Properties: { + 'icon-actor': GObject.ParamSpec.object( + 'icon-actor', 'icon-actor', 'Icon actor', + GObject.ParamFlags.READWRITE, + Clutter.Actor.$gtype), + 'title': GObject.ParamSpec.string( + 'title', 'title', 'title', + GObject.ParamFlags.READWRITE | + GObject.ParamFlags.CONSTRUCT, + null), + 'description': GObject.ParamSpec.string( + 'description', 'description', 'description', + GObject.ParamFlags.READWRITE | + GObject.ParamFlags.CONSTRUCT, + null), + }, +}, class ListSectionItem extends St.BoxLayout{ + _init(params) { + this._iconActorBin = new St.Bin(); + + let textLayout = new St.BoxLayout({ + vertical: true, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + }); + + this._title = new St.Label({ style_class: 'dialog-list-item-title' }); + + this._description = new St.Label({ + style_class: 'dialog-list-item-description', + }); + + textLayout.add_child(this._title); + textLayout.add_child(this._description); + + super._init({ + style_class: 'dialog-list-item', + ...params, + }); + + + this.label_actor = this._title; + this.add_child(this._iconActorBin); + this.add_child(textLayout); + } + + get iconActor() { + return this._iconActorBin.get_child(); + } + + set iconActor(actor) { + this._iconActorBin.set_child(actor); + this.notify('icon-actor'); + } + + get title() { + return this._title.text; + } + + set title(title) { + _setLabel(this._title, title); + this.notify('title'); + } + + get description() { + return this._description.text; + } + + set description(description) { + _setLabel(this._description, description); + this.notify('description'); + } +}); diff --git a/js/ui/endSessionDialog.js b/js/ui/endSessionDialog.js index d0303c8185..0aa08accc6 100644 --- a/js/ui/endSessionDialog.js +++ b/js/ui/endSessionDialog.js @@ -8,9 +8,8 @@ const St = imports.gi.St; const Dialog = imports.ui.dialog; const Main = imports.ui.main; +const ModalDialog = imports.ui.modalDialog; const Layout = imports.ui.layout; -const {BarLevel} = imports.ui.barLevel; -const {Separator} = imports.ui.separator; const SessionDialogInterface = " \ @@ -52,212 +51,186 @@ const ResponseCode = { NONE: 9 } -const DIALOG_WIDTH = 800; -const DIALOG_HEIGHT = 300; +var EndSessionDialog = GObject.registerClass( +class EndSessionDialog extends ModalDialog.ModalDialog { + _init() { + super._init({ + styleClass: 'end-session-dialog', + }); -var EndSessionDialog = class { - constructor(mode) { - this._mode = mode; + this._mode = null; this._inhibited = false; this._settings = new Gio.Settings({ schema_id: 'org.cinnamon.SessionManager' }); - this._delay_duration = this._settings.get_int("quit-time-delay"); - this._current_time = this._delay_duration; - this._progress_timer_id = 0; - this._default_action = null; - - // persistent actors - this._dialog = null; - this._inhibitor_table = null; - this._progress_label = null; - this._progress_bar = null; - - this._dialog = new Dialog.Dialog(Main.uiGroup, 'end-session-dialog'); - global.focus_manager.add_group(this._dialog); - Main.layoutManager.trackChrome(this._dialog); - - - this._dialog_proxy = new Gio.DBusProxy( - { - g_connection: Gio.DBus.session, - g_interface_name: "org.cinnamon.SessionManager.EndSessionDialog", - g_interface_info: SessionDialogInfo, - g_name: 'org.gnome.SessionManager', - g_object_path: '/org/gnome/SessionManager', - g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START - } - ); + this._delayDuration = this._settings.get_int("quit-time-delay"); + this._currentTime = this._delayDuration; + this._progressTimerId = 0; + this._defaultAction = null; + + this._messageDialogContent = new Dialog.MessageDialogContent(); + this.contentLayout.add_child(this._messageDialogContent); + + this._applicationsSection = new Dialog.ListSection({ + title: _("Some applications are busy or have unsaved work"), + }); + this.contentLayout.add_child(this._applicationsSection); + this._applicationsSection.visible = false; + + this._dialogProxy = new Gio.DBusProxy({ + g_connection: Gio.DBus.session, + g_interface_name: "org.cinnamon.SessionManager.EndSessionDialog", + g_interface_info: SessionDialogInfo, + g_name: 'org.gnome.SessionManager', + g_object_path: '/org/gnome/SessionManager', + g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START + }); - this._dialog_proxy.init(null); + this._dialogProxy.init(null); - this._dialog_proxy.connect("g-signal", this._proxy_signal_received.bind(this)); - this._dialog_proxy.GetCapabilitiesRemote(this._get_capabilities_cb.bind(this)); + this._dialogProxy.connect("g-signal", this._proxySignalReceived.bind(this)); } - _proxy_signal_received(proxy, sender, signal, params) { + _proxySignalReceived(proxy, sender, signal, params) { if (signal === "InhibitorsChanged") { const inhibitors = params.deep_unpack()[0]; if (inhibitors && inhibitors.length > 0) { this._inhibited = true; - this._present_inhibitor_info(inhibitors); + this._presentInhibitorInfo(inhibitors); } else { if (this._inhibited) { - this._dialog_proxy.IgnoreInhibitorsRemote(); + this._dialogProxy.IgnoreInhibitorsRemote(); } } } } - _add_cancel() { - this._dialog.addButton({ + _addCancel() { + this.addButton({ label: _("Cancel"), action: () => { - this._dialog_proxy.CancelRemote(); + this._dialogProxy.CancelRemote(); }, key: Clutter.KEY_Escape }); } - _get_capabilities_cb(result, error) { + _getCapabilities(result, error) { if (error) { global.logError('Error getting capabilities: ' + error.message); return; } - var [can_switch_user, can_stop, can_restart, can_hybrid_sleep, can_suspend, can_hibernate, can_logout] = result[0]; - var content = null; + this.clearButtons(); + + var [canSwitchUser, canStop, canRestart, canHybridSleep, canSuspend, canHibernate, canLogout] = result[0]; switch(this._mode) { case DialogMode.LOGOUT: - if (can_switch_user) { - this._dialog.addButton({ + this._addCancel(); + + if (canSwitchUser) { + this.addButton({ label: _("Switch User"), - action: this._dialog_proxy.SwitchUserRemote.bind(this._dialog_proxy) + action: this._dialogProxy.SwitchUserRemote.bind(this._dialogProxy) }); } - this._add_cancel() - - this._default_action = this._dialog_proxy.LogoutRemote.bind(this._dialog_proxy); - this._dialog.addButton({ + this._defaultAction = this._dialogProxy.LogoutRemote.bind(this._dialogProxy); + this.addButton({ label: _("Log Out"), - action: this._default_action, + action: this._defaultAction, destructive_action: true, default: true }); - content = new Dialog.MessageDialogContent({ - title: _("Log out of this system now?") - }); + this._messageDialogContent.title = _("Log out"); break; case DialogMode.SHUTDOWN: - if (can_suspend) { - this._dialog.addButton({ + this._addCancel(); + + if (canSuspend) { + this.addButton({ label: _("Suspend"), - action: this._dialog_proxy.SuspendRemote.bind(this._dialog_proxy) + action: this._dialogProxy.SuspendRemote.bind(this._dialogProxy) }); } - if (can_hibernate) { - this._dialog.addButton({ + if (canHibernate) { + this.addButton({ label: _("Hibernate"), - action: this._dialog_proxy.HibernateRemote.bind(this._dialog_proxy) + action: this._dialogProxy.HibernateRemote.bind(this._dialogProxy) }); } - - this._add_cancel(); - - if (can_restart) { - this._dialog.addButton({ + if (canRestart) { + this.addButton({ label: _("Restart"), - action: this._dialog_proxy.RestartRemote.bind(this._dialog_proxy), + action: this._dialogProxy.RestartRemote.bind(this._dialogProxy), }); } - if (can_stop) { - this._default_action = this._dialog_proxy.ShutdownRemote.bind(this._dialog_proxy); - this._dialog.addButton({ + if (canStop) { + this._defaultAction = this._dialogProxy.ShutdownRemote.bind(this._dialogProxy); + this.addButton({ label: _("Shut Down"), - action: this._default_action, + action: this._defaultAction, destructive_action: true, default: true, }); } - content = new Dialog.MessageDialogContent({ - title: _("Shut down this system now?") - }); + this._messageDialogContent.title = _("Shut down"); break; case DialogMode.REBOOT: - if (!can_restart) { + this._addCancel(); + + if (!canRestart) { global.logError("Restart not available"); - this._dialog_proxy.CancelRemote(); - this.destroy(); + this._dialogProxy.CancelRemote(); + this.close(); return; } - this._add_cancel(); - - this._default_action = this._dialog_proxy.RestartRemote.bind(this._dialog_proxy); - this._dialog.addButton({ + this._defaultAction = this._dialogProxy.RestartRemote.bind(this._dialogProxy); + this.addButton({ label: _("Restart"), - action: this._default_action, + action: this._defaultAction, destructive_action: true, default: true }); - content = new Dialog.MessageDialogContent({ - title: _("Restart this system now?") - }); + this._messageDialogContent.title = _("Restart"); - break + break; } - this._dialog.contentLayout.add_child(content); - if (this._settings.get_boolean("quit-delay-toggle")) { - this._add_delay_timer(); + this._addDelayTimer(); } - - this._position_dialog(); - } - - _position_dialog() { - const monitor = Main.layoutManager.currentMonitor; - - this._dialog.set_position( - monitor.x + Math.floor((monitor.width - this._dialog.width) / 2), - monitor.y + Math.floor((monitor.height - this._dialog.height) / 2) - ); } - _add_delay_timer() { - this._progress_label = new St.Label(); - this._dialog.contentLayout.add_child(this._progress_label); - - this._progress_bar = new BarLevel({ style_class: "end-session-dialog-progress-bar", value: 1.0, maximum_value: 1.0 }); - this._dialog.contentLayout.add_child(this._progress_bar); - - this._update_progress(); - - this._progress_timer_id = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, this._update_progress.bind(this)); + _addDelayTimer() { + this._updateProgress(); + this._progressTimerId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, + 1000, this._updateProgress.bind(this)); } - _remove_delay_timer() { - if (this._progress_timer_id) { - GLib.source_remove(this._progress_timer_id); - this._progress_timer_id = 0; + _removeDelayTimer() { + if (this._progressTimerId) { + GLib.source_remove(this._progressTimerId); + this._progressTimerId = 0; } - } - _update_progress() { - this._progress_bar.value = (this._current_time / this._delay_duration); + // reset the delay timeout + this._currentTime = this._delayDuration; + this._messageDialogContent.description = null; + } - if (this._current_time == 0) { - if (this._default_action != null) { - this._default_action(); + _updateProgress() { + if (this._currentTime == 0) { + if (this._defaultAction != null) { + this._defaultAction(); } + this._progressTimerId = 0; - this._progress_timer_id = 0; return GLib.SOURCE_REMOVE; } @@ -268,113 +241,79 @@ var EndSessionDialog = class { text = ngettext( "You will be automatically logged out in %d second.", "You will be logged out in %d seconds.", - this._current_time).format(this._current_time); + this._currentTime).format(this._currentTime); break; case DialogMode.SHUTDOWN: text = ngettext( "This system will be automatically shut down in %d second.", "This system will be shut down in %d seconds.", - this._current_time).format(this._current_time); + this._currentTime).format(this._currentTime); break; case DialogMode.REBOOT: text = ngettext( "This system will be automatically restarted in %d second.", "This system will be restarted in %d seconds.", - this._current_time).format(this._current_time); + this._currentTime).format(this._currentTime); break; } - this._progress_label.set_text(text); - - this._current_time--; + this._messageDialogContent.description = text; + this._currentTime--; return GLib.SOURCE_CONTINUE; } - _present_inhibitor_info(inhibitor_infos) { - this._remove_delay_timer(); - - this._dialog.clearButtons(); - this._dialog.contentLayout.remove_all_children(); + _presentInhibitorInfo(inhibitorInfos) { + this._applicationsSection.list.remove_all_children(); + this.clearButtons(); - const content = new Dialog.MessageDialogContent({ - title: _("Some programs are still running"), - description: _("Waiting for programs to finish. Interrupting these programs may cause you to lose work.") - }); - this._dialog.contentLayout.add_child(content); - - const bin = new St.Bin({ style_class: "end-session-dialog-inhibitor-list-frame" }); - this._dialog.contentLayout.add_child(bin); - - this._inhibitor_table = new St.Table({ style_class: "end-session-dialog-inhibitor-list" }); - bin.set_child(this._inhibitor_table); - - let row = 0; - - - const infos = inhibitor_infos; + const infos = inhibitorInfos; for (let i = 0; i < infos.length; i++) { const info = infos[i]; - const [name_str, gicon_str, reason_str, id] = info; - try { - const name = (name_str == "none") ? _("Unknown") : name_str; - const app = new St.Label({ text: name }); + const [nameStr, giconStr, reasonStr, id] = info; - const reason = new St.Label({ text: reason_str, style_class: "end-session-dialog-inhibitor-list-reason" }); - reason.clutter_text.line_wrap = true; - - const gicon = Gio.Icon.new_for_string(gicon_str); + try { + const name = (nameStr == 'none') ? _('Unknown') : nameStr; + const iconName = (giconStr == 'none') ? ('image-missing') : giconStr; + const gicon = Gio.Icon.new_for_string(iconName); const icon = new St.Icon({ gicon: gicon }); - this._inhibitor_table.add(app, { - row: row, - col: 0, - col_span: 1, - x_align: St.Align.START - }); - - this._inhibitor_table.add(reason, { - row: row, - col: 1, - col_span: 1, - x_expand: true, + let listItem = new Dialog.ListSectionItem({ + icon_actor: icon, + title: name, + description: reasonStr, }); - row++; - - if (i < infos.length - 1) { - this._inhibitor_table.add(new Separator().actor, { - row: row, - col: 0, - col_span: 2, - x_expand: true - }); - - row++; - } + this._applicationsSection.list.add_child(listItem); + this._applicationsSection.visible = true; } catch (e) { global.logError(e); } } - this._add_cancel(); + this._addCancel(); - this._dialog.addButton({ + this.addButton({ label: _("Ignore and continue"), - action: this._dialog_proxy.IgnoreInhibitorsRemote.bind(this._dialog_proxy), + action: this._dialogProxy.IgnoreInhibitorsRemote.bind(this._dialogProxy), destructive_action: true, default: true }); } - destroy() { - this._remove_delay_timer() + open(mode) { + this._mode = mode; + this._dialogProxy.GetCapabilitiesRemote(this._getCapabilities.bind(this)); + this._applicationsSection.visible = false; - this._dialog_proxy = null; - this._dialog.destroy(); - this._dialog = null; + super.open(); } -}; + close() { + super.close(); + + this._removeDelayTimer(); + } +}); diff --git a/js/ui/main.js b/js/ui/main.js index 023100579a..eb8e178a5b 100644 --- a/js/ui/main.js +++ b/js/ui/main.js @@ -102,6 +102,7 @@ const MessageTray = imports.ui.messageTray; const OsdWindow = imports.ui.osdWindow; const Overview = imports.ui.overview; const Expo = imports.ui.expo; +const EndSessionDialog = imports.ui.endSessionDialog; const Panel = imports.ui.panel; const PlacesManager = imports.ui.placesManager; const PolkitAuthenticationAgent = imports.ui.polkitAuthenticationAgent; @@ -130,7 +131,6 @@ const ScreenRecorder = imports.ui.screenRecorder; const {GesturesManager} = imports.ui.gestures.gesturesManager; const {MonitorLabeler} = imports.ui.monitorLabeler; const {CinnamonPortalHandler} = imports.misc.portalHandlers; -const {EndSessionDialog} = imports.ui.endSessionDialog;; var LAYOUT_TRADITIONAL = "traditional"; var LAYOUT_FLIPPED = "flipped"; @@ -147,6 +147,7 @@ var panelManager = null; var osdWindowManager = null; var overview = null; var expo = null; +var endSessionDialog = null; var runDialog = null; var lookingGlass = null; var lookingGlassUpdateID = 0; @@ -195,8 +196,6 @@ var popup_rendering_actor = null; var xlet_startup_error = false; -var end_session_dialog = null; - var gpuOffloadHelper = null; var gpu_offload_supported = false; @@ -417,6 +416,8 @@ function start() { overview = new Overview.Overview(); expo = new Expo.Expo(); + endSessionDialog = new EndSessionDialog.EndSessionDialog(); + statusIconDispatcher = new StatusIconDispatcher.StatusIconDispatcher(); layoutManager._updateBoxes(); @@ -1582,21 +1583,3 @@ function restartCinnamon(showOsd = false) { global.reexec_self(); } - -function show_end_session_dialog(mode) { - if (end_session_dialog != null) { - global.logWarning("End session dialog already exists"); - return; - } - - end_session_dialog = new EndSessionDialog(mode); -} - -function close_end_session_dialog() { - if (end_session_dialog == null) { - return; - } - - end_session_dialog.destroy(); - end_session_dialog = null; -}