Add a confirmation dialog for display changes
Unfortunately, display configuration can and does fail, due to unspecified HW constraints, drivers bugs, unsupported exotic configurations or just bad luck. So when the user makes a change in the control center, show a dialog asking him if it looks OK, and revert back after 20 seconds otherwise. https://bugzilla.gnome.org/show_bug.cgi?id=706208
This commit is contained in:
parent
c37c4d8c6d
commit
02224bb5fe
@ -6,12 +6,14 @@ const Gio = imports.gi.Gio;
|
|||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
|
const Pango = imports.gi.Pango;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
|
|
||||||
const AltTab = imports.ui.altTab;
|
const AltTab = imports.ui.altTab;
|
||||||
const WorkspaceSwitcherPopup = imports.ui.workspaceSwitcherPopup;
|
const WorkspaceSwitcherPopup = imports.ui.workspaceSwitcherPopup;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
||||||
@ -20,6 +22,107 @@ const DIM_BRIGHTNESS = -0.3;
|
|||||||
const DIM_TIME = 0.500;
|
const DIM_TIME = 0.500;
|
||||||
const UNDIM_TIME = 0.250;
|
const UNDIM_TIME = 0.250;
|
||||||
|
|
||||||
|
const DISPLAY_REVERT_TIMEOUT = 20; // in seconds - keep in sync with mutter
|
||||||
|
const ONE_SECOND = 1000; // in ms
|
||||||
|
|
||||||
|
const DisplayChangeDialog = new Lang.Class({
|
||||||
|
Name: 'DisplayChangeDialog',
|
||||||
|
Extends: ModalDialog.ModalDialog,
|
||||||
|
|
||||||
|
_init: function(wm) {
|
||||||
|
this.parent({ styleClass: 'prompt-dialog' });
|
||||||
|
|
||||||
|
this._wm = wm;
|
||||||
|
|
||||||
|
let mainContentBox = new St.BoxLayout({ style_class: 'prompt-dialog-main-layout',
|
||||||
|
vertical: false });
|
||||||
|
this.contentLayout.add(mainContentBox,
|
||||||
|
{ x_fill: true,
|
||||||
|
y_fill: true });
|
||||||
|
|
||||||
|
let icon = new St.Icon({ icon_name: 'preferences-desktop-display-symbolic' });
|
||||||
|
mainContentBox.add(icon,
|
||||||
|
{ x_fill: true,
|
||||||
|
y_fill: false,
|
||||||
|
x_align: St.Align.END,
|
||||||
|
y_align: St.Align.START });
|
||||||
|
|
||||||
|
let messageBox = new St.BoxLayout({ style_class: 'prompt-dialog-message-layout',
|
||||||
|
vertical: true });
|
||||||
|
mainContentBox.add(messageBox,
|
||||||
|
{ expand: true, y_align: St.Align.START });
|
||||||
|
|
||||||
|
let subjectLabel = new St.Label({ style_class: 'prompt-dialog-headline',
|
||||||
|
text: _("Do you want to keep these display settings?") });
|
||||||
|
messageBox.add(subjectLabel,
|
||||||
|
{ y_fill: false,
|
||||||
|
y_align: St.Align.START });
|
||||||
|
|
||||||
|
this._countDown = DISPLAY_REVERT_TIMEOUT;
|
||||||
|
let message = this._formatCountDown();
|
||||||
|
this._descriptionLabel = new St.Label({ style_class: 'prompt-dialog-description',
|
||||||
|
text: this._formatCountDown() });
|
||||||
|
this._descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
|
this._descriptionLabel.clutter_text.line_wrap = true;
|
||||||
|
|
||||||
|
messageBox.add(this._descriptionLabel,
|
||||||
|
{ y_fill: true,
|
||||||
|
y_align: St.Align.START });
|
||||||
|
|
||||||
|
/* Translators: this and the following message should be limited in lenght,
|
||||||
|
to avoid ellipsizing the labels.
|
||||||
|
*/
|
||||||
|
this._cancelButton = this.addButton({ label: _("Revert Settings"),
|
||||||
|
action: Lang.bind(this, this._onFailure),
|
||||||
|
key: Clutter.Escape },
|
||||||
|
{ expand: true, x_fill: false, x_align: St.Align.START });
|
||||||
|
this._okButton = this.addButton({ label: _("Keep Changes"),
|
||||||
|
action: Lang.bind(this, this._onSuccess),
|
||||||
|
default: true },
|
||||||
|
{ expand: false, x_fill: false, x_align: St.Align.END });
|
||||||
|
|
||||||
|
this._timeoutId = Mainloop.timeout_add(ONE_SECOND, Lang.bind(this, this._tick));
|
||||||
|
},
|
||||||
|
|
||||||
|
close: function(timestamp) {
|
||||||
|
if (this._timeoutId > 0) {
|
||||||
|
Mainloop.source_remove(this._timeoutId);
|
||||||
|
this._timeoutId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parent(timestamp);
|
||||||
|
},
|
||||||
|
|
||||||
|
_formatCountDown: function() {
|
||||||
|
let fmt = ngettext("Settings changes will revert in %d second",
|
||||||
|
"Settings changes will revert in %d seconds");
|
||||||
|
return fmt.format(this._countDown);
|
||||||
|
},
|
||||||
|
|
||||||
|
_tick: function() {
|
||||||
|
this._countDown--;
|
||||||
|
|
||||||
|
if (this._countDown == 0) {
|
||||||
|
/* mutter already takes care of failing at timeout */
|
||||||
|
this._timeoutId = 0;
|
||||||
|
this.close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._descriptionLabel.text = this._formatCountDown();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onFailure: function() {
|
||||||
|
this._wm.complete_display_change(false);
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onSuccess: function() {
|
||||||
|
this._wm.complete_display_change(true);
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const WindowDimmer = new Lang.Class({
|
const WindowDimmer = new Lang.Class({
|
||||||
Name: 'WindowDimmer',
|
Name: 'WindowDimmer',
|
||||||
@ -306,6 +409,7 @@ const WindowManager = new Lang.Class({
|
|||||||
this._shellwm.connect('map', Lang.bind(this, this._mapWindow));
|
this._shellwm.connect('map', Lang.bind(this, this._mapWindow));
|
||||||
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._workspaceSwitcherPopup = null;
|
this._workspaceSwitcherPopup = null;
|
||||||
this.setCustomKeybindingHandler('switch-to-workspace-left',
|
this.setCustomKeybindingHandler('switch-to-workspace-left',
|
||||||
@ -1056,4 +1160,9 @@ const WindowManager = new Lang.Class({
|
|||||||
workspace.activate_with_focus (window, global.get_current_time());
|
workspace.activate_with_focus (window, global.get_current_time());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_confirmDisplayChange: function() {
|
||||||
|
let dialog = new DisplayChangeDialog(this._shellwm);
|
||||||
|
dialog.open();
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
@ -75,6 +75,9 @@ static gboolean gnome_shell_plugin_xevent_filter (MetaPlugin *plugi
|
|||||||
|
|
||||||
static gboolean gnome_shell_plugin_keybinding_filter (MetaPlugin *plugin,
|
static gboolean gnome_shell_plugin_keybinding_filter (MetaPlugin *plugin,
|
||||||
MetaKeyBinding *binding);
|
MetaKeyBinding *binding);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
@ -132,6 +135,9 @@ gnome_shell_plugin_class_init (GnomeShellPluginClass *klass)
|
|||||||
|
|
||||||
plugin_class->xevent_filter = gnome_shell_plugin_xevent_filter;
|
plugin_class->xevent_filter = gnome_shell_plugin_xevent_filter;
|
||||||
plugin_class->keybinding_filter = gnome_shell_plugin_keybinding_filter;
|
plugin_class->keybinding_filter = gnome_shell_plugin_keybinding_filter;
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,6 +405,12 @@ gnome_shell_plugin_keybinding_filter (MetaPlugin *plugin,
|
|||||||
return _shell_wm_filter_keybinding (get_shell_wm (), binding);
|
return _shell_wm_filter_keybinding (get_shell_wm (), binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gnome_shell_plugin_confirm_display_change (MetaPlugin *plugin)
|
||||||
|
{
|
||||||
|
_shell_wm_confirm_display_change (get_shell_wm ());
|
||||||
|
}
|
||||||
|
|
||||||
static const
|
static const
|
||||||
MetaPluginInfo *gnome_shell_plugin_plugin_info (MetaPlugin *plugin)
|
MetaPluginInfo *gnome_shell_plugin_plugin_info (MetaPlugin *plugin)
|
||||||
{
|
{
|
||||||
|
@ -38,6 +38,8 @@ void _shell_wm_kill_switch_workspace (ShellWM *wm);
|
|||||||
gboolean _shell_wm_filter_keybinding (ShellWM *wm,
|
gboolean _shell_wm_filter_keybinding (ShellWM *wm,
|
||||||
MetaKeyBinding *binding);
|
MetaKeyBinding *binding);
|
||||||
|
|
||||||
|
void _shell_wm_confirm_display_change (ShellWM *wm);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __SHELL_WM_PRIVATE_H__ */
|
#endif /* __SHELL_WM_PRIVATE_H__ */
|
||||||
|
@ -27,6 +27,7 @@ enum
|
|||||||
KILL_SWITCH_WORKSPACE,
|
KILL_SWITCH_WORKSPACE,
|
||||||
KILL_WINDOW_EFFECTS,
|
KILL_WINDOW_EFFECTS,
|
||||||
FILTER_KEYBINDING,
|
FILTER_KEYBINDING,
|
||||||
|
CONFIRM_DISPLAY_CHANGE,
|
||||||
|
|
||||||
LAST_SIGNAL
|
LAST_SIGNAL
|
||||||
};
|
};
|
||||||
@ -124,6 +125,13 @@ shell_wm_class_init (ShellWMClass *klass)
|
|||||||
g_signal_accumulator_true_handled, NULL, NULL,
|
g_signal_accumulator_true_handled, NULL, NULL,
|
||||||
G_TYPE_BOOLEAN, 1,
|
G_TYPE_BOOLEAN, 1,
|
||||||
META_TYPE_KEY_BINDING);
|
META_TYPE_KEY_BINDING);
|
||||||
|
shell_wm_signals[CONFIRM_DISPLAY_CHANGE] =
|
||||||
|
g_signal_new ("confirm-display-change",
|
||||||
|
G_TYPE_FROM_CLASS (klass),
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
0,
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
G_TYPE_NONE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -219,6 +227,20 @@ shell_wm_completed_destroy (ShellWM *wm,
|
|||||||
meta_plugin_destroy_completed (wm->plugin, actor);
|
meta_plugin_destroy_completed (wm->plugin, actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shell_wm_complete_display_change:
|
||||||
|
* @wm: the ShellWM
|
||||||
|
* @ok: if the new configuration was OK
|
||||||
|
*
|
||||||
|
* The plugin must call this after the user responded to the confirmation dialog.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
shell_wm_complete_display_change (ShellWM *wm,
|
||||||
|
gboolean ok)
|
||||||
|
{
|
||||||
|
meta_plugin_complete_display_change (wm->plugin, ok);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_shell_wm_kill_switch_workspace (ShellWM *wm)
|
_shell_wm_kill_switch_workspace (ShellWM *wm)
|
||||||
{
|
{
|
||||||
@ -287,6 +309,12 @@ _shell_wm_filter_keybinding (ShellWM *wm,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_shell_wm_confirm_display_change (ShellWM *wm)
|
||||||
|
{
|
||||||
|
g_signal_emit (wm, shell_wm_signals[CONFIRM_DISPLAY_CHANGE], 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* shell_wm_new:
|
* shell_wm_new:
|
||||||
* @plugin: the #MetaPlugin
|
* @plugin: the #MetaPlugin
|
||||||
|
@ -39,6 +39,9 @@ void shell_wm_completed_destroy (ShellWM *wm,
|
|||||||
MetaWindowActor *actor);
|
MetaWindowActor *actor);
|
||||||
void shell_wm_completed_switch_workspace (ShellWM *wm);
|
void shell_wm_completed_switch_workspace (ShellWM *wm);
|
||||||
|
|
||||||
|
void shell_wm_complete_display_change (ShellWM *wm,
|
||||||
|
gboolean ok);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __SHELL_WM_H__ */
|
#endif /* __SHELL_WM_H__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user