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/boxpointer.js</file>
|
||||||
<file>ui/calendar.js</file>
|
<file>ui/calendar.js</file>
|
||||||
<file>ui/checkBox.js</file>
|
<file>ui/checkBox.js</file>
|
||||||
|
<file>ui/closeDialog.js</file>
|
||||||
<file>ui/ctrlAltTab.js</file>
|
<file>ui/ctrlAltTab.js</file>
|
||||||
<file>ui/dash.js</file>
|
<file>ui/dash.js</file>
|
||||||
<file>ui/dateMenu.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 WindowMenu = imports.ui.windowMenu;
|
||||||
const PadOsd = imports.ui.padOsd;
|
const PadOsd = imports.ui.padOsd;
|
||||||
const EdgeDragAction = imports.ui.edgeDragAction;
|
const EdgeDragAction = imports.ui.edgeDragAction;
|
||||||
|
const CloseDialog = imports.ui.closeDialog;
|
||||||
|
|
||||||
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
||||||
const MINIMIZE_WINDOW_ANIMATION_TIME = 0.2;
|
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('destroy', Lang.bind(this, this._destroyWindow));
|
||||||
this._shellwm.connect('filter-keybinding', Lang.bind(this, this._filterKeybinding));
|
this._shellwm.connect('filter-keybinding', Lang.bind(this, this._filterKeybinding));
|
||||||
this._shellwm.connect('confirm-display-change', Lang.bind(this, this._confirmDisplayChange));
|
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));
|
global.screen.connect('restacked', Lang.bind(this, this._syncStacking));
|
||||||
|
|
||||||
this._workspaceSwitcherPopup = null;
|
this._workspaceSwitcherPopup = null;
|
||||||
@ -1971,6 +1973,10 @@ const WindowManager = new Lang.Class({
|
|||||||
dialog.open();
|
dialog.open();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_createCloseDialog: function (shellwm, window) {
|
||||||
|
return new CloseDialog.CloseDialog(window);
|
||||||
|
},
|
||||||
|
|
||||||
_showResizePopup: function(display, show, rect, displayW, displayH) {
|
_showResizePopup: function(display, show, rect, displayW, displayH) {
|
||||||
if (show) {
|
if (show) {
|
||||||
if (!this._resizePopup)
|
if (!this._resizePopup)
|
||||||
|
@ -17,6 +17,7 @@ js/ui/appFavorites.js
|
|||||||
js/ui/audioDeviceSelection.js
|
js/ui/audioDeviceSelection.js
|
||||||
js/ui/backgroundMenu.js
|
js/ui/backgroundMenu.js
|
||||||
js/ui/calendar.js
|
js/ui/calendar.js
|
||||||
|
js/ui/closeDialog.js
|
||||||
js/ui/components/automountManager.js
|
js/ui/components/automountManager.js
|
||||||
js/ui/components/autorunManager.js
|
js/ui/components/autorunManager.js
|
||||||
js/ui/components/keyring.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 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_TYPE_SHELL_PLUGIN (gnome_shell_plugin_get_type ())
|
||||||
#define GNOME_SHELL_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_SHELL_PLUGIN, GnomeShellPlugin))
|
#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->confirm_display_change = gnome_shell_plugin_confirm_display_change;
|
||||||
|
|
||||||
plugin_class->plugin_info = gnome_shell_plugin_plugin_info;
|
plugin_class->plugin_info = gnome_shell_plugin_plugin_info;
|
||||||
|
|
||||||
|
plugin_class->create_close_dialog = gnome_shell_plugin_create_close_dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -425,3 +429,10 @@ MetaPluginInfo *gnome_shell_plugin_plugin_info (MetaPlugin *plugin)
|
|||||||
|
|
||||||
return &info;
|
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);
|
void _shell_wm_confirm_display_change (ShellWM *wm);
|
||||||
|
|
||||||
|
MetaCloseDialog * _shell_wm_create_close_dialog (ShellWM *wm,
|
||||||
|
MetaWindow *window);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __SHELL_WM_PRIVATE_H__ */
|
#endif /* __SHELL_WM_PRIVATE_H__ */
|
||||||
|
@ -33,6 +33,7 @@ enum
|
|||||||
SHOW_WINDOW_MENU,
|
SHOW_WINDOW_MENU,
|
||||||
FILTER_KEYBINDING,
|
FILTER_KEYBINDING,
|
||||||
CONFIRM_DISPLAY_CHANGE,
|
CONFIRM_DISPLAY_CHANGE,
|
||||||
|
CREATE_CLOSE_DIALOG,
|
||||||
|
|
||||||
LAST_SIGNAL
|
LAST_SIGNAL
|
||||||
};
|
};
|
||||||
@ -168,6 +169,22 @@ shell_wm_class_init (ShellWMClass *klass)
|
|||||||
0,
|
0,
|
||||||
NULL, NULL, NULL,
|
NULL, NULL, NULL,
|
||||||
G_TYPE_NONE, 0);
|
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
|
void
|
||||||
@ -386,6 +403,17 @@ _shell_wm_confirm_display_change (ShellWM *wm)
|
|||||||
g_signal_emit (wm, shell_wm_signals[CONFIRM_DISPLAY_CHANGE], 0);
|
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:
|
* shell_wm_new:
|
||||||
* @plugin: the #MetaPlugin
|
* @plugin: the #MetaPlugin
|
||||||
|
Loading…
Reference in New Issue
Block a user