ui: Implement "window doesn't respond" dialog on gnome-shell
This does allow us to use ClutterActors instead of lousy legacy tools meant for shell scripting. https://bugzilla.gnome.org/show_bug.cgi?id=762083
This commit is contained in:
parent
593b4318a3
commit
d220e353e0
@ -44,6 +44,7 @@
|
||||
<file>ui/boxpointer.js</file>
|
||||
<file>ui/calendar.js</file>
|
||||
<file>ui/checkBox.js</file>
|
||||
<file>ui/closeDialog.js</file>
|
||||
<file>ui/ctrlAltTab.js</file>
|
||||
<file>ui/dash.js</file>
|
||||
<file>ui/dateMenu.js</file>
|
||||
|
138
js/ui/closeDialog.js
Normal file
138
js/ui/closeDialog.js
Normal file
@ -0,0 +1,138 @@
|
||||
// -*- 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;
|
||||
|
||||
const FROZEN_WINDOW_BRIGHTNESS = -0.3
|
||||
const DIALOG_TRANSITION_TIME = 0.15
|
||||
|
||||
const CloseDialog = new Lang.Class({
|
||||
Name: 'CloseDialog',
|
||||
Extends: GObject.Object,
|
||||
Implements: [ Meta.CloseDialog ],
|
||||
Properties: {
|
||||
'window': GObject.ParamSpec.override('window', Meta.CloseDialog)
|
||||
},
|
||||
|
||||
_init: function (window) {
|
||||
this.parent();
|
||||
this._window = window;
|
||||
this._dialog = null;
|
||||
},
|
||||
|
||||
get window() {
|
||||
return this._window;
|
||||
},
|
||||
|
||||
set window(window) {
|
||||
this._window = window;
|
||||
},
|
||||
|
||||
_createDialogContent: function () {
|
||||
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 });
|
||||
},
|
||||
|
||||
_initDialog: function () {
|
||||
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'),
|
||||
action: Lang.bind(this, this._onClose),
|
||||
default: true });
|
||||
this._dialog.addButton({ label: _('Wait'),
|
||||
action: Lang.bind(this, this._onWait),
|
||||
key: Clutter.Escape });
|
||||
|
||||
global.focus_manager.add_group(this._dialog);
|
||||
},
|
||||
|
||||
_addWindowEffect: function () {
|
||||
// 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);
|
||||
},
|
||||
|
||||
_removeWindowEffect: function () {
|
||||
let windowActor = this._window.get_compositor_private();
|
||||
let surfaceActor = windowActor.get_first_child();
|
||||
surfaceActor.remove_effect_by_name("gnome-shell-frozen-window");
|
||||
},
|
||||
|
||||
_onWait: function () {
|
||||
this.response(Meta.CloseDialogResponse.WAIT);
|
||||
},
|
||||
|
||||
_onClose: function () {
|
||||
this.response(Meta.CloseDialogResponse.FORCE_CLOSE);
|
||||
},
|
||||
|
||||
vfunc_show: function () {
|
||||
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,
|
||||
onComplete: Lang.bind(this, function () {
|
||||
Main.layoutManager.trackChrome(this._dialog, { affectsInputRegion: true });
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
vfunc_hide: function () {
|
||||
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,
|
||||
onComplete: Lang.bind(this, function () {
|
||||
dialog.destroy();
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
vfunc_focus: function () {
|
||||
if (this._dialog)
|
||||
this._dialog.grab_key_focus();
|
||||
}
|
||||
});
|
@ -20,6 +20,7 @@ const Tweener = imports.ui.tweener;
|
||||
const WindowMenu = imports.ui.windowMenu;
|
||||
const PadOsd = imports.ui.padOsd;
|
||||
const EdgeDragAction = imports.ui.edgeDragAction;
|
||||
const CloseDialog = imports.ui.closeDialog;
|
||||
|
||||
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
||||
const MINIMIZE_WINDOW_ANIMATION_TIME = 0.2;
|
||||
@ -710,6 +711,7 @@ const WindowManager = new Lang.Class({
|
||||
this._shellwm.connect('destroy', Lang.bind(this, this._destroyWindow));
|
||||
this._shellwm.connect('filter-keybinding', Lang.bind(this, this._filterKeybinding));
|
||||
this._shellwm.connect('confirm-display-change', Lang.bind(this, this._confirmDisplayChange));
|
||||
this._shellwm.connect('create-close-dialog', Lang.bind(this, this._createCloseDialog));
|
||||
global.screen.connect('restacked', Lang.bind(this, this._syncStacking));
|
||||
|
||||
this._workspaceSwitcherPopup = null;
|
||||
@ -1971,6 +1973,10 @@ const WindowManager = new Lang.Class({
|
||||
dialog.open();
|
||||
},
|
||||
|
||||
_createCloseDialog: function (shellwm, window) {
|
||||
return new CloseDialog.CloseDialog(window);
|
||||
},
|
||||
|
||||
_showResizePopup: function(display, show, rect, displayW, displayH) {
|
||||
if (show) {
|
||||
if (!this._resizePopup)
|
||||
|
@ -17,6 +17,7 @@ js/ui/appFavorites.js
|
||||
js/ui/audioDeviceSelection.js
|
||||
js/ui/backgroundMenu.js
|
||||
js/ui/calendar.js
|
||||
js/ui/closeDialog.js
|
||||
js/ui/components/automountManager.js
|
||||
js/ui/components/autorunManager.js
|
||||
js/ui/components/keyring.js
|
||||
|
@ -88,6 +88,8 @@ static void gnome_shell_plugin_confirm_display_change (MetaPlugin *plugin);
|
||||
|
||||
static const MetaPluginInfo *gnome_shell_plugin_plugin_info (MetaPlugin *plugin);
|
||||
|
||||
static MetaCloseDialog * gnome_shell_plugin_create_close_dialog (MetaPlugin *plugin,
|
||||
MetaWindow *window);
|
||||
|
||||
#define GNOME_TYPE_SHELL_PLUGIN (gnome_shell_plugin_get_type ())
|
||||
#define GNOME_SHELL_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_SHELL_PLUGIN, GnomeShellPlugin))
|
||||
@ -149,6 +151,8 @@ gnome_shell_plugin_class_init (GnomeShellPluginClass *klass)
|
||||
plugin_class->confirm_display_change = gnome_shell_plugin_confirm_display_change;
|
||||
|
||||
plugin_class->plugin_info = gnome_shell_plugin_plugin_info;
|
||||
|
||||
plugin_class->create_close_dialog = gnome_shell_plugin_create_close_dialog;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -425,3 +429,10 @@ MetaPluginInfo *gnome_shell_plugin_plugin_info (MetaPlugin *plugin)
|
||||
|
||||
return &info;
|
||||
}
|
||||
|
||||
static MetaCloseDialog *
|
||||
gnome_shell_plugin_create_close_dialog (MetaPlugin *plugin,
|
||||
MetaWindow *window)
|
||||
{
|
||||
return _shell_wm_create_close_dialog (get_shell_wm (), window);
|
||||
}
|
||||
|
@ -52,6 +52,9 @@ gboolean _shell_wm_filter_keybinding (ShellWM *wm,
|
||||
|
||||
void _shell_wm_confirm_display_change (ShellWM *wm);
|
||||
|
||||
MetaCloseDialog * _shell_wm_create_close_dialog (ShellWM *wm,
|
||||
MetaWindow *window);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SHELL_WM_PRIVATE_H__ */
|
||||
|
@ -33,6 +33,7 @@ enum
|
||||
SHOW_WINDOW_MENU,
|
||||
FILTER_KEYBINDING,
|
||||
CONFIRM_DISPLAY_CHANGE,
|
||||
CREATE_CLOSE_DIALOG,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
@ -168,6 +169,22 @@ shell_wm_class_init (ShellWMClass *klass)
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
/**
|
||||
* ShellWM::create-close-dialog:
|
||||
* @wm: The WM
|
||||
* @window: The window to create the dialog for
|
||||
*
|
||||
* Creates a close dialog for the given window.
|
||||
*
|
||||
* Returns: (transfer full): The close dialog instance.
|
||||
*/
|
||||
shell_wm_signals[CREATE_CLOSE_DIALOG] =
|
||||
g_signal_new ("create-close-dialog",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
META_TYPE_CLOSE_DIALOG, 1, META_TYPE_WINDOW);
|
||||
}
|
||||
|
||||
void
|
||||
@ -386,6 +403,17 @@ _shell_wm_confirm_display_change (ShellWM *wm)
|
||||
g_signal_emit (wm, shell_wm_signals[CONFIRM_DISPLAY_CHANGE], 0);
|
||||
}
|
||||
|
||||
MetaCloseDialog *
|
||||
_shell_wm_create_close_dialog (ShellWM *wm,
|
||||
MetaWindow *window)
|
||||
{
|
||||
MetaCloseDialog *dialog;
|
||||
|
||||
g_signal_emit (wm, shell_wm_signals[CREATE_CLOSE_DIALOG], 0, window, &dialog);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_wm_new:
|
||||
* @plugin: the #MetaPlugin
|
||||
|
Loading…
Reference in New Issue
Block a user