From 3e707f08e1b8687abb093d020b78dc571c68df06 Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Thu, 8 May 2014 18:56:23 -0400 Subject: [PATCH] Add support for meta_restart() and MetaDisplay::restart Support was added to Mutter to allow it to trigger a restart to allow for restarts when switching in or out of stereo mode. Hook up to the new signals on MetaDisplay to show the restart message and reexec. Meta.is_restart() is used to suppress the startup animation. This also allows us to do 'Alt-F2 r' restarts more cleanly without a visual flash and animation. --- data/theme/gnome-shell.css | 5 ++ js/ui/layout.js | 115 +++++++++++++++++++++++++++------------------ js/ui/main.js | 36 ++++++++++++++ js/ui/modalDialog.js | 35 ++++++++------ js/ui/runDialog.js | 14 +++--- 5 files changed, 138 insertions(+), 67 deletions(-) diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css index f4ea781..66346a1 100644 --- a/data/theme/gnome-shell.css +++ b/data/theme/gnome-shell.css @@ -1920,6 +1920,11 @@ StScrollBar StButton#vhandle:active { color: #444444; } +/* Restart message */ +.restart-message { + font-size: 14pt; +} + /* ShellMountOperation Dialogs */ .shell-mount-operation-icon { icon-size: 48px; diff --git a/js/ui/layout.js b/js/ui/layout.js index 141eecc..223a0e2 100644 --- a/js/ui/layout.js +++ b/js/ui/layout.js @@ -560,56 +560,75 @@ const LayoutManager = new Lang.Class({ // so events don't get delivered to X11 windows (which are distorted by the animation) global.stage_input_mode = Shell.StageInputMode.FULLSCREEN; - if (Main.sessionMode.isGreeter) { - this.panelBox.translation_y = -this.panelBox.height; + let background; + if (Meta.is_restart()) { + // On restart, we don't do an animation, so start loading the primary + // background now. + this._createPrimaryBackground(); + background = this._bgManagers[this.primaryIndex].background; } else { - // We need to force an update of the regions now before we scale - // the UI group to get the coorect allocation for the struts. - this._updateRegions(); - - this.trayBox.hide(); - this.keyboardBox.hide(); - - let monitor = this.primaryMonitor; - let x = monitor.x + monitor.width / 2.0; - let y = monitor.y + monitor.height / 2.0; - - this.uiGroup.set_pivot_point(x / global.screen_width, - y / global.screen_height); - this.uiGroup.scale_x = this.uiGroup.scale_y = 0.5; - this.uiGroup.opacity = 0; - global.window_group.set_clip(monitor.x, monitor.y, monitor.width, monitor.height); - } - - this._systemBackground = new Background.SystemBackground(); - this._systemBackground.actor.hide(); - - global.stage.insert_child_below(this._systemBackground.actor, null); + if (Main.sessionMode.isGreeter) { + this.panelBox.translation_y = -this.panelBox.height; + } else { + // We need to force an update of the regions now before we scale + // the UI group to get the coorect allocation for the struts. + this._updateRegions(); + + this.trayBox.hide(); + this.keyboardBox.hide(); + + let monitor = this.primaryMonitor; + let x = monitor.x + monitor.width / 2.0; + let y = monitor.y + monitor.height / 2.0; + + this.uiGroup.set_pivot_point(x / global.screen_width, + y / global.screen_height); + this.uiGroup.scale_x = this.uiGroup.scale_y = 0.5; + this.uiGroup.opacity = 0; + global.window_group.set_clip(monitor.x, monitor.y, monitor.width, monitor.height); + } - let constraint = new Clutter.BindConstraint({ source: global.stage, - coordinate: Clutter.BindCoordinate.ALL }); - this._systemBackground.actor.add_constraint(constraint); + this._systemBackground = new Background.SystemBackground(); + this._systemBackground.actor.hide(); - let signalId = this._systemBackground.connect('loaded', - Lang.bind(this, function() { - this._systemBackground.disconnect(signalId); - this._systemBackground.actor.show(); - global.stage.show(); + global.stage.insert_child_below(this._systemBackground.actor, null); - this.emit('startup-prepared'); + let constraint = new Clutter.BindConstraint({ source: global.stage, + coordinate: Clutter.BindCoordinate.ALL }); + this._systemBackground.actor.add_constraint(constraint); + background = this._systemBackground; + } - // We're mostly prepared for the startup animation - // now, but since a lot is going on asynchronously - // during startup, let's defer the startup animation - // until the event loop is uncontended and idle. - // This helps to prevent us from running the animation - // when the system is bogged down - GLib.idle_add(GLib.PRIORITY_LOW, - Lang.bind(this, function() { - this._startupAnimation(); - return false; - })); - })); + let signalId = background.connect('loaded', + Lang.bind(this, function() { + background.disconnect(signalId); + if (this._systemBackground) + this._systemBackground.actor.show(); + global.stage.show(); + + this.emit('startup-prepared'); + + // We're mostly prepared for the startup animation + // now, but since a lot is going on asynchronously + // during startup, let's defer the startup animation + // until the event loop is uncontended and idle. + // This helps to prevent us from running the animation + // when the system is bogged down. Don't wait on + // restart, since it might take a long time for us + // to go idle, and we don't show an animation. Just + // finish immediately. + if (Meta.is_restart()) { + // Nothing else will do this reliably + this._queueUpdateRegions(); + this._startupAnimationComplete(); + } else { + GLib.idle_add(GLib.PRIORITY_LOW, + Lang.bind(this, function() { + this._startupAnimation(); + return false; + })); + } + })); }, _startupAnimation: function() { @@ -647,8 +666,10 @@ const LayoutManager = new Lang.Class({ global.stage_input_mode = Shell.StageInputMode.NORMAL; - this._systemBackground.actor.destroy(); - this._systemBackground = null; + if (this._systemBackground) { + this._systemBackground.actor.destroy(); + this._systemBackground = null; + } this._startingUp = false; diff --git a/js/ui/main.js b/js/ui/main.js index bd5dc47..a3b73f0 100644 --- a/js/ui/main.js +++ b/js/ui/main.js @@ -18,6 +18,7 @@ const ExtensionSystem = imports.ui.extensionSystem; const ExtensionDownloader = imports.ui.extensionDownloader; const Keyboard = imports.ui.keyboard; const MessageTray = imports.ui.messageTray; +const ModalDialog = imports.ui.modalDialog; const OsdWindow = imports.ui.osdWindow; const Overview = imports.ui.overview; const Panel = imports.ui.panel; @@ -176,6 +177,16 @@ function _initializeUI() { false, -1, 1); global.display.connect('overlay-key', Lang.bind(overview, overview.toggle)); + global.display.connect('show-restart-message', function(display, message) { + showRestartMessage(message); + return true; + }); + + global.display.connect('restart', function() { + global.reexec_self(); + return true; + }); + // Provide the bus object for gnome-session to // initiate logouts. EndSessionDialog.init(); @@ -800,3 +811,28 @@ function queueDeferredWork(workId) { }); } } + +const RestartMessage = new Lang.Class({ + Name: 'RestartMessage', + Extends: ModalDialog.ModalDialog, + + _init : function(message) { + this.parent({ shellReactive: true, + styleClass: 'restart-message', + shouldFadeIn: false, + destroyOnClose: true }); + + let label = new St.Label({ text: message }); + + this.contentLayout.add(label, { x_fill: false, + y_fill: false, + x_align: St.Align.MIDDLE, + y_align: St.Align.MIDDLE }); + this.buttonLayout.hide(); + } +}); + +function showRestartMessage(message) { + let restartMessage = new RestartMessage(message); + restartMessage.open(); +} diff --git a/js/ui/modalDialog.js b/js/ui/modalDialog.js index f770faf..aba7758 100644 --- a/js/ui/modalDialog.js +++ b/js/ui/modalDialog.js @@ -43,6 +43,7 @@ const ModalDialog = new Lang.Class({ parentActor: Main.uiGroup, keybindingMode: Shell.KeyBindingMode.SYSTEM_MODAL, shouldFadeIn: true, + shouldFadeOut: true, destroyOnClose: true }); this.state = State.CLOSED; @@ -50,6 +51,7 @@ const ModalDialog = new Lang.Class({ this._keybindingMode = params.keybindingMode; this._shellReactive = params.shellReactive; this._shouldFadeIn = params.shouldFadeIn; + this._shouldFadeOut = params.shouldFadeOut; this._destroyOnClose = params.destroyOnClose; this._group = new St.Widget({ visible: false, @@ -303,6 +305,15 @@ const ModalDialog = new Lang.Class({ return true; }, + _closeComplete: function() { + this.state = State.CLOSED; + this._group.hide(); + this.emit('closed'); + + if (this._destroyOnClose) + this.destroy(); + }, + close: function(timestamp) { if (this.state == State.CLOSED || this.state == State.CLOSING) return; @@ -311,20 +322,16 @@ const ModalDialog = new Lang.Class({ this.popModal(timestamp); this._savedKeyFocus = null; - Tweener.addTween(this._group, - { opacity: 0, - time: OPEN_AND_CLOSE_TIME, - transition: 'easeOutQuad', - onComplete: Lang.bind(this, - function() { - this.state = State.CLOSED; - this._group.hide(); - this.emit('closed'); - - if (this._destroyOnClose) - this.destroy(); - }) - }); + if (this._shouldFadeOut) + Tweener.addTween(this._group, + { opacity: 0, + time: OPEN_AND_CLOSE_TIME, + transition: 'easeOutQuad', + onComplete: Lang.bind(this, + this._closeComplete) + }) + else + this._closeComplete(); }, // Drop modal status without closing the dialog; this makes the diff --git a/js/ui/runDialog.js b/js/ui/runDialog.js index 7b753a7..1901296 100644 --- a/js/ui/runDialog.js +++ b/js/ui/runDialog.js @@ -50,14 +50,10 @@ const RunDialog = new Lang.Class({ Main.createLookingGlass().open(); }), - 'r': Lang.bind(this, function() { - global.reexec_self(); - }), + 'r': Lang.bind(this, this._restart), // Developer brain backwards compatibility - 'restart': Lang.bind(this, function() { - global.reexec_self(); - }), + 'restart': Lang.bind(this, this._restart), 'debugexit': Lang.bind(this, function() { Meta.quit(Meta.ExitCode.ERROR); @@ -267,6 +263,12 @@ const RunDialog = new Lang.Class({ } }, + _restart: function() { + this._shouldFadeOut = false; + this.close(); + Meta.restart('Restarting...'); + }, + open: function() { this._history.lastItem(); this._errorBox.hide(); -- 1.8.3.1