2017-01-19 18:52:18 +00:00
|
|
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
|
|
|
|
|
|
const Clutter = imports.gi.Clutter;
|
|
|
|
const Gio = imports.gi.Gio;
|
|
|
|
const GObject = imports.gi.GObject;
|
|
|
|
const Lang = imports.lang;
|
|
|
|
const Meta = imports.gi.Meta;
|
|
|
|
const Shell = imports.gi.Shell;
|
|
|
|
|
|
|
|
const Dialog = imports.ui.dialog;
|
|
|
|
const Main = imports.ui.main;
|
|
|
|
const Tweener = imports.ui.tweener;
|
|
|
|
|
2017-07-18 17:47:27 +00:00
|
|
|
var FROZEN_WINDOW_BRIGHTNESS = -0.3
|
|
|
|
var DIALOG_TRANSITION_TIME = 0.15
|
2017-01-19 18:52:18 +00:00
|
|
|
|
2017-07-18 17:41:25 +00:00
|
|
|
var CloseDialog = new Lang.Class({
|
2017-01-19 18:52:18 +00:00
|
|
|
Name: 'CloseDialog',
|
|
|
|
Extends: GObject.Object,
|
|
|
|
Implements: [ Meta.CloseDialog ],
|
|
|
|
Properties: {
|
|
|
|
'window': GObject.ParamSpec.override('window', Meta.CloseDialog)
|
|
|
|
},
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_init(window) {
|
2017-01-19 18:52:18 +00:00
|
|
|
this.parent();
|
|
|
|
this._window = window;
|
|
|
|
this._dialog = null;
|
|
|
|
},
|
|
|
|
|
|
|
|
get window() {
|
|
|
|
return this._window;
|
|
|
|
},
|
|
|
|
|
|
|
|
set window(window) {
|
|
|
|
this._window = window;
|
|
|
|
},
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_createDialogContent() {
|
2017-01-19 18:52:18 +00:00
|
|
|
let tracker = Shell.WindowTracker.get_default();
|
|
|
|
let windowApp = tracker.get_window_app(this._window);
|
|
|
|
|
|
|
|
/* Translators: %s is an application name */
|
|
|
|
let title = _("“%s” is not responding.").format(windowApp.get_name());
|
|
|
|
let subtitle = _("You may choose to wait a short while for it to " +
|
|
|
|
"continue or force the application to quit entirely.");
|
|
|
|
let icon = new Gio.ThemedIcon({ name: 'dialog-warning-symbolic' });
|
|
|
|
return new Dialog.MessageDialogContent({ icon, title, subtitle });
|
|
|
|
},
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_initDialog() {
|
2017-01-19 18:52:18 +00:00
|
|
|
if (this._dialog)
|
|
|
|
return;
|
|
|
|
|
|
|
|
let windowActor = this._window.get_compositor_private();
|
|
|
|
this._dialog = new Dialog.Dialog(windowActor, 'close-dialog');
|
|
|
|
this._dialog.width = windowActor.width;
|
|
|
|
this._dialog.height = windowActor.height;
|
|
|
|
|
|
|
|
this._dialog.addContent(this._createDialogContent());
|
|
|
|
this._dialog.addButton({ label: _('Force Quit'),
|
2017-12-02 00:27:35 +00:00
|
|
|
action: this._onClose.bind(this),
|
2017-01-19 18:52:18 +00:00
|
|
|
default: true });
|
|
|
|
this._dialog.addButton({ label: _('Wait'),
|
2017-12-02 00:27:35 +00:00
|
|
|
action: this._onWait.bind(this),
|
2017-01-19 18:52:18 +00:00
|
|
|
key: Clutter.Escape });
|
|
|
|
|
|
|
|
global.focus_manager.add_group(this._dialog);
|
|
|
|
},
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_addWindowEffect() {
|
2017-01-19 18:52:18 +00:00
|
|
|
// We set the effect on the surface actor, so the dialog itself
|
|
|
|
// (which is a child of the MetaWindowActor) does not get the
|
|
|
|
// effect applied itself.
|
|
|
|
let windowActor = this._window.get_compositor_private();
|
|
|
|
let surfaceActor = windowActor.get_first_child();
|
|
|
|
let effect = new Clutter.BrightnessContrastEffect();
|
|
|
|
effect.set_brightness(FROZEN_WINDOW_BRIGHTNESS);
|
|
|
|
surfaceActor.add_effect_with_name("gnome-shell-frozen-window", effect);
|
|
|
|
},
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_removeWindowEffect() {
|
2017-01-19 18:52:18 +00:00
|
|
|
let windowActor = this._window.get_compositor_private();
|
|
|
|
let surfaceActor = windowActor.get_first_child();
|
|
|
|
surfaceActor.remove_effect_by_name("gnome-shell-frozen-window");
|
|
|
|
},
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onWait() {
|
2017-01-19 18:52:18 +00:00
|
|
|
this.response(Meta.CloseDialogResponse.WAIT);
|
|
|
|
},
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onClose() {
|
2017-01-19 18:52:18 +00:00
|
|
|
this.response(Meta.CloseDialogResponse.FORCE_CLOSE);
|
|
|
|
},
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
vfunc_show() {
|
2017-01-19 18:52:18 +00:00
|
|
|
if (this._dialog != null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._addWindowEffect();
|
|
|
|
this._initDialog();
|
|
|
|
|
|
|
|
this._dialog.scale_y = 0;
|
|
|
|
this._dialog.set_pivot_point(0.5, 0.5);
|
|
|
|
|
|
|
|
Tweener.addTween(this._dialog,
|
|
|
|
{ scale_y: 1,
|
|
|
|
transition: 'linear',
|
|
|
|
time: DIALOG_TRANSITION_TIME,
|
2017-10-31 00:38:18 +00:00
|
|
|
onComplete: () => {
|
2017-01-19 18:52:18 +00:00
|
|
|
Main.layoutManager.trackChrome(this._dialog, { affectsInputRegion: true });
|
2017-10-31 00:38:18 +00:00
|
|
|
}
|
2017-01-19 18:52:18 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
vfunc_hide() {
|
2017-01-19 18:52:18 +00:00
|
|
|
if (this._dialog == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
let dialog = this._dialog;
|
|
|
|
this._dialog = null;
|
|
|
|
this._removeWindowEffect();
|
|
|
|
|
|
|
|
Tweener.addTween(dialog,
|
|
|
|
{ scale_y: 0,
|
|
|
|
transition: 'linear',
|
|
|
|
time: DIALOG_TRANSITION_TIME,
|
2017-10-31 00:38:18 +00:00
|
|
|
onComplete: () => {
|
2017-01-19 18:52:18 +00:00
|
|
|
dialog.destroy();
|
2017-10-31 00:38:18 +00:00
|
|
|
}
|
2017-01-19 18:52:18 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
vfunc_focus() {
|
2017-01-19 18:52:18 +00:00
|
|
|
if (this._dialog)
|
|
|
|
this._dialog.grab_key_focus();
|
|
|
|
}
|
|
|
|
});
|