Change keyboard handling API to handle nested modal calls
Rename beginModal/endModal to pushModal/popModal. All of the current callers just want to ensure that we're in a modal state; they don't actually need to fail if we already are. These functions also now take the Clutter keyboard focus, while recording the previous focus. https://bugzilla.gnome.org/show_bug.cgi?id=595116
This commit is contained in:
parent
2ddc7cf00f
commit
8a2bfd0e55
@ -386,7 +386,7 @@ LookingGlass.prototype = {
|
|||||||
activatable: true,
|
activatable: true,
|
||||||
singleLineMode: true,
|
singleLineMode: true,
|
||||||
text: ''});
|
text: ''});
|
||||||
/* kind of a hack */
|
/* unmapping the edit box will un-focus it, undo that */
|
||||||
notebook.connect('selection', Lang.bind(this, function (nb, child) {
|
notebook.connect('selection', Lang.bind(this, function (nb, child) {
|
||||||
if (child == this._evalBox)
|
if (child == this._evalBox)
|
||||||
global.stage.set_key_focus(this._entry);
|
global.stage.set_key_focus(this._entry);
|
||||||
@ -548,9 +548,7 @@ LookingGlass.prototype = {
|
|||||||
|
|
||||||
Tweener.removeTweens(this.actor);
|
Tweener.removeTweens(this.actor);
|
||||||
|
|
||||||
if (!Main.beginModal())
|
Main.pushModal(this.actor);
|
||||||
return;
|
|
||||||
|
|
||||||
global.stage.set_key_focus(this._entry);
|
global.stage.set_key_focus(this._entry);
|
||||||
|
|
||||||
Tweener.addTween(this.actor, { time: 0.5,
|
Tweener.addTween(this.actor, { time: 0.5,
|
||||||
@ -567,7 +565,7 @@ LookingGlass.prototype = {
|
|||||||
this._open = false;
|
this._open = false;
|
||||||
Tweener.removeTweens(this.actor);
|
Tweener.removeTweens(this.actor);
|
||||||
|
|
||||||
Main.endModal();
|
Main.popModal(this.actor);
|
||||||
|
|
||||||
Tweener.addTween(this.actor, { time: 0.5,
|
Tweener.addTween(this.actor, { time: 0.5,
|
||||||
transition: "easeOutQuad",
|
transition: "easeOutQuad",
|
||||||
|
@ -30,7 +30,8 @@ let runDialog = null;
|
|||||||
let lookingGlass = null;
|
let lookingGlass = null;
|
||||||
let wm = null;
|
let wm = null;
|
||||||
let recorder = null;
|
let recorder = null;
|
||||||
let inModal = false;
|
let modalCount = 0;
|
||||||
|
let modalActorFocusStack = [];
|
||||||
|
|
||||||
function start() {
|
function start() {
|
||||||
// Add a binding for "global" in the global JS namespace; (gjs
|
// Add a binding for "global" in the global JS namespace; (gjs
|
||||||
@ -149,7 +150,7 @@ function _removeUnusedWorkspaces() {
|
|||||||
// should be asking Mutter to resolve the key into an action and then
|
// should be asking Mutter to resolve the key into an action and then
|
||||||
// base our handling based on the action.
|
// base our handling based on the action.
|
||||||
function _globalKeyPressHandler(actor, event) {
|
function _globalKeyPressHandler(actor, event) {
|
||||||
if (!inModal)
|
if (modalCount == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
let type = event.type();
|
let type = event.type();
|
||||||
@ -183,27 +184,88 @@ function _globalKeyPressHandler(actor, event) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to go into a mode where all keyboard and mouse input goes to
|
function _findModal(actor) {
|
||||||
// the stage. Returns true if we successfully grabbed the keyboard and
|
for (let i = 0; i < modalActorFocusStack.length; i++) {
|
||||||
// went modal, false otherwise
|
let [stackActor, stackFocus] = modalActorFocusStack[i];
|
||||||
function beginModal() {
|
if (stackActor == actor) {
|
||||||
let timestamp = global.screen.get_display().get_current_time();
|
return i;
|
||||||
|
}
|
||||||
if (!global.begin_modal(timestamp))
|
}
|
||||||
return false;
|
return -1;
|
||||||
global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
|
|
||||||
|
|
||||||
inModal = true;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function endModal() {
|
/**
|
||||||
|
* pushModal:
|
||||||
|
* @actor: #ClutterActor which will be given keyboard focus
|
||||||
|
*
|
||||||
|
* Ensure we are in a mode where all keyboard and mouse input goes to
|
||||||
|
* the stage. Multiple calls to this function act in a stacking fashion;
|
||||||
|
* the effect will be undone when an equal number of popModal() invocations
|
||||||
|
* have been made.
|
||||||
|
*
|
||||||
|
* Next, record the current Clutter keyboard focus on a stack. If the modal stack
|
||||||
|
* returns to this actor, reset the focus to the actor which was focused
|
||||||
|
* at the time pushModal() was invoked.
|
||||||
|
*/
|
||||||
|
function pushModal(actor) {
|
||||||
let timestamp = global.screen.get_display().get_current_time();
|
let timestamp = global.screen.get_display().get_current_time();
|
||||||
|
|
||||||
|
modalCount += 1;
|
||||||
|
actor.connect('destroy', function() {
|
||||||
|
let index = _findModal(actor);
|
||||||
|
if (index >= 0)
|
||||||
|
modalActorFocusStack.splice(index, 1);
|
||||||
|
});
|
||||||
|
let curFocus = global.stage.get_key_focus();
|
||||||
|
if (curFocus != null) {
|
||||||
|
curFocus.connect('destroy', function() {
|
||||||
|
let index = _findModal(actor);
|
||||||
|
if (index >= 0)
|
||||||
|
modalActorFocusStack[index][1] = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
modalActorFocusStack.push([actor, curFocus]);
|
||||||
|
|
||||||
|
if (modalCount > 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!global.begin_modal(timestamp)) {
|
||||||
|
log("pushModal: invocation of begin_modal failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* popModal:
|
||||||
|
* @actor: #ClutterActor passed to original invocation of pushModal().
|
||||||
|
*
|
||||||
|
* Reverse the effect of pushModal(). If this invocation is undoing
|
||||||
|
* the topmost invocation, then the focus will be restored to the
|
||||||
|
* previous focus at the time when pushModal() was invoked.
|
||||||
|
*/
|
||||||
|
function popModal(actor) {
|
||||||
|
let timestamp = global.screen.get_display().get_current_time();
|
||||||
|
|
||||||
|
modalCount -= 1;
|
||||||
|
let focusIndex = _findModal(actor);
|
||||||
|
if (focusIndex >= 0) {
|
||||||
|
if (focusIndex == modalActorFocusStack.length - 1) {
|
||||||
|
let [stackActor, stackFocus] = modalActorFocusStack[focusIndex];
|
||||||
|
global.stage.set_key_focus(stackFocus);
|
||||||
|
} else {
|
||||||
|
// Remove from the middle, shift the focus chain up
|
||||||
|
for (let i = focusIndex; i < modalActorFocusStack.length - 1; i++) {
|
||||||
|
modalActorFocusStack[i + 1][1] = modalActorFocusStack[i][1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
modalActorFocusStack.splice(focusIndex, 1);
|
||||||
|
}
|
||||||
|
if (modalCount > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
global.end_modal(timestamp);
|
global.end_modal(timestamp);
|
||||||
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
|
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
|
||||||
inModal = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createLookingGlass() {
|
function createLookingGlass() {
|
||||||
|
@ -277,8 +277,7 @@ Overview.prototype = {
|
|||||||
show : function() {
|
show : function() {
|
||||||
if (this.visible)
|
if (this.visible)
|
||||||
return;
|
return;
|
||||||
if (!Main.beginModal())
|
Main.pushModal(this._dash.actor);
|
||||||
return;
|
|
||||||
|
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
this.animationInProgress = true;
|
this.animationInProgress = true;
|
||||||
@ -437,7 +436,7 @@ Overview.prototype = {
|
|||||||
|
|
||||||
this._coverPane.lower_bottom();
|
this._coverPane.lower_bottom();
|
||||||
|
|
||||||
Main.endModal();
|
Main.popModal(this._dash.actor);
|
||||||
this.emit('hidden');
|
this.emit('hidden');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -43,8 +43,7 @@ RunDialog.prototype = {
|
|||||||
|
|
||||||
this._internalCommands = { 'lg':
|
this._internalCommands = { 'lg':
|
||||||
Lang.bind(this, function() {
|
Lang.bind(this, function() {
|
||||||
// Run in an idle to avoid recursive key grab problems
|
Main.createLookingGlass().open();
|
||||||
Mainloop.idle_add(function() { Main.createLookingGlass().open(); });
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
'r': Lang.bind(this, function() {
|
'r': Lang.bind(this, function() {
|
||||||
@ -182,12 +181,10 @@ RunDialog.prototype = {
|
|||||||
if (this._isOpen) // Already shown
|
if (this._isOpen) // Already shown
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!Main.beginModal())
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._isOpen = true;
|
this._isOpen = true;
|
||||||
this._group.show();
|
this._group.show();
|
||||||
|
|
||||||
|
Main.pushModal(this._group);
|
||||||
global.stage.set_key_focus(this._entry);
|
global.stage.set_key_focus(this._entry);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -203,7 +200,7 @@ RunDialog.prototype = {
|
|||||||
this._group.hide();
|
this._group.hide();
|
||||||
this._entry.text = '';
|
this._entry.text = '';
|
||||||
|
|
||||||
Main.endModal();
|
Main.popModal(this._group);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Signals.addSignalMethods(RunDialog.prototype);
|
Signals.addSignalMethods(RunDialog.prototype);
|
||||||
|
Loading…
Reference in New Issue
Block a user