layout: Merge Chrome and LayoutManager

The two classes have been gaining each other's functionality for a little
while, adding the new code wherever it was more convenient. Rather than
have a clear delineation between "This Manages Shell Chrome" and "This
Manages Shell Layout", I think it's better off if we just accept that
the responsibilities are pretty much the same.

https://bugzilla.gnome.org/show_bug.cgi?id=692677
This commit is contained in:
Jasper St. Pierre 2013-01-27 23:34:33 -05:00
parent 72405cd43f
commit 8e231cb2ec

View File

@ -95,6 +95,12 @@ const MonitorConstraint = new Lang.Class({
} }
}); });
const defaultParams = {
trackFullscreen: false,
affectsStruts: false,
affectsInputRegion: true
};
const LayoutManager = new Lang.Class({ const LayoutManager = new Lang.Class({
Name: 'LayoutManager', Name: 'LayoutManager',
@ -110,7 +116,10 @@ const LayoutManager = new Lang.Class({
this._rightPanelBarrier = 0; this._rightPanelBarrier = 0;
this._trayBarrier = 0; this._trayBarrier = 0;
this._chrome = new Chrome(this); this._inOverview = false;
this._updateRegionIdle = 0;
this._trackedActors = [];
this.screenShieldGroup = new St.Widget({ name: 'screenShieldGroup', this.screenShieldGroup = new St.Widget({ name: 'screenShieldGroup',
visible: false, visible: false,
@ -136,22 +145,40 @@ const LayoutManager = new Lang.Class({
this.addChrome(this.keyboardBox); this.addChrome(this.keyboardBox);
this._keyboardHeightNotifyId = 0; this._keyboardHeightNotifyId = 0;
// Need to update struts on new workspaces when they are added
global.screen.connect('notify::n-workspaces',
Lang.bind(this, this._queueUpdateRegions));
global.screen.connect('restacked',
Lang.bind(this, this._windowsRestacked));
global.screen.connect('monitors-changed', global.screen.connect('monitors-changed',
Lang.bind(this, this._monitorsChanged)); Lang.bind(this, this._monitorsChanged));
this._monitorsChanged(); this._monitorsChanged();
this._chrome.connect('primary-fullscreen-changed', Lang.bind(this, function(chrome, state) {
this.emit('primary-fullscreen-changed', state);
}));
}, },
// This is called by Main after everything else is constructed; // This is called by Main after everything else is constructed;
// Chrome.init() needs access to Main.overview, which didn't exist // it needs access to Main.overview, which didn't exist
// yet when the LayoutManager was constructed. // yet when the LayoutManager was constructed.
init: function() { init: function() {
this._chrome.init(); Main.overview.connect('showing', Lang.bind(this, this._overviewShowing));
Main.overview.connect('hidden', Lang.bind(this, this._overviewHidden));
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
},
this._startupAnimation(); _overviewShowing: function() {
this._inOverview = true;
this._updateVisibility();
this._queueUpdateRegions();
},
_overviewHidden: function() {
this._inOverview = false;
this._updateVisibility();
this._queueUpdateRegions();
},
_sessionUpdated: function() {
this._updateVisibility();
this._queueUpdateRegions();
}, },
_updateMonitors: function() { _updateMonitors: function() {
@ -230,7 +257,7 @@ const LayoutManager = new Lang.Class({
let corner = new HotCorner(); let corner = new HotCorner();
this._hotCorners.push(corner); this._hotCorners.push(corner);
corner.actor.set_position(cornerX, cornerY); corner.actor.set_position(cornerX, cornerY);
this._chrome.addActor(corner.actor); this.addChrome(corner.actor);
} }
}, },
@ -287,6 +314,9 @@ const LayoutManager = new Lang.Class({
this._updateMonitors(); this._updateMonitors();
this._updateBoxes(); this._updateBoxes();
this._updateHotCorners(); this._updateHotCorners();
this._updateFullscreen();
this._updateVisibility();
this._queueUpdateRegions();
this.emit('monitors-changed'); this.emit('monitors-changed');
}, },
@ -321,11 +351,11 @@ const LayoutManager = new Lang.Class({
global.stage_input_mode == Shell.StageInputMode.FULLSCREEN) { global.stage_input_mode == Shell.StageInputMode.FULLSCREEN) {
let focusActor = global.stage.key_focus; let focusActor = global.stage.key_focus;
if (focusActor) if (focusActor)
i = this._chrome.findIndexForActor(focusActor); i = this.findIndexForActor(focusActor);
} else { } else {
let focusWindow = global.display.focus_window; let focusWindow = global.display.focus_window;
if (focusWindow) if (focusWindow)
i = this._chrome.findIndexForWindow(focusWindow); i = this.findIndexForWindow(focusWindow);
} }
return i; return i;
@ -374,8 +404,7 @@ const LayoutManager = new Lang.Class({
}, },
_fadeBackgroundComplete: function() { _fadeBackgroundComplete: function() {
// Don't animate the strut this._freezeUpdateRegions();
this._chrome.freezeUpdateRegions();
if (this._background != null) { if (this._background != null) {
this._background.destroy(); this._background.destroy();
@ -393,7 +422,7 @@ const LayoutManager = new Lang.Class({
_startupAnimationComplete: function() { _startupAnimationComplete: function() {
this.emit('panel-box-changed'); this.emit('panel-box-changed');
this._chrome.thawUpdateRegions(); this._thawUpdateRegions();
}, },
showKeyboard: function () { showKeyboard: function () {
@ -420,7 +449,7 @@ const LayoutManager = new Lang.Class({
_showKeyboardComplete: function() { _showKeyboardComplete: function() {
// Poke Chrome to update the input shape; it doesn't notice // Poke Chrome to update the input shape; it doesn't notice
// anchor point changes // anchor point changes
this._chrome.updateRegions(); this._updateRegions();
this._keyboardHeightNotifyId = this.keyboardBox.connect('notify::height', Lang.bind(this, function () { this._keyboardHeightNotifyId = this.keyboardBox.connect('notify::height', Lang.bind(this, function () {
this.keyboardBox.anchor_y = this.keyboardBox.height; this.keyboardBox.anchor_y = this.keyboardBox.height;
@ -454,7 +483,7 @@ const LayoutManager = new Lang.Class({
}, },
_hideKeyboardComplete: function() { _hideKeyboardComplete: function() {
this._chrome.updateRegions(); this._updateRegions();
}, },
// addChrome: // addChrome:
@ -477,7 +506,8 @@ const LayoutManager = new Lang.Class({
// monitor (it will be hidden whenever a fullscreen window is visible, // monitor (it will be hidden whenever a fullscreen window is visible,
// and shown otherwise) // and shown otherwise)
addChrome: function(actor, params) { addChrome: function(actor, params) {
this._chrome.addActor(actor, params); Main.uiGroup.add_actor(actor);
this._trackActor(actor, params);
}, },
// trackChrome: // trackChrome:
@ -492,83 +522,6 @@ const LayoutManager = new Lang.Class({
// though some possibilities don't make sense. By default, @actor has // though some possibilities don't make sense. By default, @actor has
// the same params as its chrome ancestor. // the same params as its chrome ancestor.
trackChrome: function(actor, params) { trackChrome: function(actor, params) {
this._chrome.trackActor(actor, params);
},
// untrackChrome:
// @actor: an actor previously tracked via trackChrome()
//
// Undoes the effect of trackChrome()
untrackChrome: function(actor) {
this._chrome.untrackActor(actor);
},
// removeChrome:
// @actor: a chrome actor
//
// Removes @actor from the chrome
removeChrome: function(actor) {
this._chrome.removeActor(actor);
},
findMonitorForActor: function(actor) {
return this.monitors[this._chrome.findIndexForActor(actor)];
},
findMonitorForWindow: function(window) {
return this.monitors[this._chrome.findIndexForWindow(window)];
},
});
Signals.addSignalMethods(LayoutManager.prototype);
// This manages the shell "chrome"; the UI that's visible in the
// normal mode (ie, outside the Overview), that surrounds the main
// workspace content.
const defaultParams = {
trackFullscreen: false,
affectsStruts: false,
affectsInputRegion: true
};
const Chrome = new Lang.Class({
Name: 'Chrome',
_init: function(layoutManager) {
this._layoutManager = layoutManager;
this._monitors = [];
this._inOverview = false;
this._updateRegionIdle = 0;
this._freezeUpdateCount = 0;
this._trackedActors = [];
this._layoutManager.connect('monitors-changed',
Lang.bind(this, this._relayout));
global.screen.connect('restacked',
Lang.bind(this, this._windowsRestacked));
// Need to update struts on new workspaces when they are added
global.screen.connect('notify::n-workspaces',
Lang.bind(this, this._queueUpdateRegions));
this._relayout();
},
init: function() {
Main.overview.connect('showing', Lang.bind(this, this._overviewShowing));
Main.overview.connect('hidden', Lang.bind(this, this._overviewHidden));
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
},
addActor: function(actor, params) {
Main.uiGroup.add_actor(actor);
this._trackActor(actor, params);
},
trackActor: function(actor, params) {
let ancestor = actor.get_parent(); let ancestor = actor.get_parent();
let index = this._findActor(ancestor); let index = this._findActor(ancestor);
while (ancestor && index == -1) { while (ancestor && index == -1) {
@ -591,11 +544,19 @@ const Chrome = new Lang.Class({
this._trackActor(actor, params); this._trackActor(actor, params);
}, },
untrackActor: function(actor) { // untrackChrome:
// @actor: an actor previously tracked via trackChrome()
//
// Undoes the effect of trackChrome()
untrackChrome: function(actor) {
this._untrackActor(actor); this._untrackActor(actor);
}, },
removeActor: function(actor) { // removeChrome:
// @actor: a chrome actor
//
// Removes @actor from the chrome
removeChrome: function(actor) {
Main.uiGroup.remove_actor(actor); Main.uiGroup.remove_actor(actor);
this._untrackActor(actor); this._untrackActor(actor);
}, },
@ -673,46 +634,19 @@ const Chrome = new Lang.Class({
} }
}, },
_overviewShowing: function() {
this._inOverview = true;
this._updateVisibility();
this._queueUpdateRegions();
},
_overviewHidden: function() {
this._inOverview = false;
this._updateVisibility();
this._queueUpdateRegions();
},
_sessionUpdated: function() {
this._updateVisibility();
this._queueUpdateRegions();
},
_relayout: function() {
this._monitors = this._layoutManager.monitors;
this._primaryIndex = this._layoutManager.primaryIndex;
this._primaryMonitor = this._layoutManager.primaryMonitor;
this._updateFullscreen();
this._updateVisibility();
this._queueUpdateRegions();
},
_findMonitorForRect: function(x, y, w, h) { _findMonitorForRect: function(x, y, w, h) {
// First look at what monitor the center of the rectangle is at // First look at what monitor the center of the rectangle is at
let cx = x + w/2; let cx = x + w/2;
let cy = y + h/2; let cy = y + h/2;
for (let i = 0; i < this._monitors.length; i++) { for (let i = 0; i < this.monitors.length; i++) {
let monitor = this._monitors[i]; let monitor = this.monitors[i];
if (cx >= monitor.x && cx < monitor.x + monitor.width && if (cx >= monitor.x && cx < monitor.x + monitor.width &&
cy >= monitor.y && cy < monitor.y + monitor.height) cy >= monitor.y && cy < monitor.y + monitor.height)
return i; return i;
} }
// If the center is not on a monitor, return the first overlapping monitor // If the center is not on a monitor, return the first overlapping monitor
for (let i = 0; i < this._monitors.length; i++) { for (let i = 0; i < this.monitors.length; i++) {
let monitor = this._monitors[i]; let monitor = this.monitors[i];
if (x + w > monitor.x && x < monitor.x + monitor.width && if (x + w > monitor.x && x < monitor.x + monitor.width &&
y + h > monitor.y && y < monitor.y + monitor.height) y + h > monitor.y && y < monitor.y + monitor.height)
return i; return i;
@ -726,7 +660,7 @@ const Chrome = new Lang.Class({
let i = this._findMonitorForRect(rect.x, rect.y, rect.width, rect.height); let i = this._findMonitorForRect(rect.x, rect.y, rect.width, rect.height);
if (i >= 0) if (i >= 0)
return i; return i;
return this._primaryIndex; // Not on any monitor, pretend its on the primary return this.primaryIndex; // Not on any monitor, pretend its on the primary
}, },
// This call guarantees that we return some monitor to simplify usage of it // This call guarantees that we return some monitor to simplify usage of it
@ -737,35 +671,35 @@ const Chrome = new Lang.Class({
let i = this._findMonitorForRect(x, y, w, h); let i = this._findMonitorForRect(x, y, w, h);
if (i >= 0) if (i >= 0)
return i; return i;
return this._primaryIndex; // Not on any monitor, pretend its on the primary return this.primaryIndex; // Not on any monitor, pretend its on the primary
}, },
findMonitorForWindow: function(window) { findMonitorForWindow: function(window) {
let rect = window.get_input_rect(); let rect = window.get_input_rect();
let i = this._findMonitorForRect(rect.x, rect.y, rect.width, rect.height); let i = this._findMonitorForRect(rect.x, rect.y, rect.width, rect.height);
if (i >= 0) if (i >= 0)
return this._monitors[i]; return this.monitors[i];
else else
return null; return null;
}, },
findMonitorForActor: function(actor) { findMonitorForActor: function(actor) {
return this._monitors[this.findIndexForActor(actor)]; return this.monitors[this.findIndexForActor(actor)];
}, },
_queueUpdateRegions: function() { _queueUpdateRegions: function() {
if (!this._updateRegionIdle && !this._freezeUpdateCount) if (!this._updateRegionIdle && !this._freezeUpdateCount)
this._updateRegionIdle = Mainloop.idle_add(Lang.bind(this, this.updateRegions), this._updateRegionIdle = Mainloop.idle_add(Lang.bind(this, this._updateRegions),
Meta.PRIORITY_BEFORE_REDRAW); Meta.PRIORITY_BEFORE_REDRAW);
}, },
freezeUpdateRegions: function() { _freezeUpdateRegions: function() {
if (this._updateRegionIdle) if (this._updateRegionIdle)
this.updateRegions(); this._updateRegions();
this._freezeUpdateCount++; this._freezeUpdateCount++;
}, },
thawUpdateRegions: function() { _thawUpdateRegions: function() {
this._freezeUpdateCount--; this._freezeUpdateCount--;
this._queueUpdateRegions(); this._queueUpdateRegions();
}, },
@ -774,8 +708,8 @@ const Chrome = new Lang.Class({
let windows = Main.getWindowActorsForWorkspace(global.screen.get_active_workspace_index()); let windows = Main.getWindowActorsForWorkspace(global.screen.get_active_workspace_index());
// Reset all monitors to not fullscreen // Reset all monitors to not fullscreen
for (let i = 0; i < this._monitors.length; i++) for (let i = 0; i < this.monitors.length; i++)
this._monitors[i].inFullscreen = false; this.monitors[i].inFullscreen = false;
// Ordinary chrome should be visible unless there is a window // Ordinary chrome should be visible unless there is a window
// with layer FULLSCREEN, or a window with layer // with layer FULLSCREEN, or a window with layer
@ -811,8 +745,8 @@ const Chrome = new Lang.Class({
window.height == global.screen_height); window.height == global.screen_height);
if (isScreenSized) { if (isScreenSized) {
for (let i = 0; i < this._monitors.length; i++) for (let i = 0; i < this.monitors.length; i++)
this._monitors[i].inFullscreen = true; this.monitors[i].inFullscreen = true;
} }
// Or whether it is monitor sized // Or whether it is monitor sized
@ -830,16 +764,16 @@ const Chrome = new Lang.Class({
_windowsRestacked: function() { _windowsRestacked: function() {
let wasInFullscreen = []; let wasInFullscreen = [];
for (let i = 0; i < this._monitors.length; i++) for (let i = 0; i < this.monitors.length; i++)
wasInFullscreen[i] = this._monitors[i].inFullscreen; wasInFullscreen[i] = this.monitors[i].inFullscreen;
let primaryWasInFullscreen = this._primaryMonitor.inFullscreen; let primaryWasInFullscreen = this.primaryMonitor.inFullscreen;
this._updateFullscreen(); this._updateFullscreen();
let changed = false; let changed = false;
for (let i = 0; i < wasInFullscreen.length; i++) { for (let i = 0; i < wasInFullscreen.length; i++) {
if (wasInFullscreen[i] != this._monitors[i].inFullscreen) { if (wasInFullscreen[i] != this.monitors[i].inFullscreen) {
changed = true; changed = true;
break; break;
} }
@ -850,12 +784,12 @@ const Chrome = new Lang.Class({
this._queueUpdateRegions(); this._queueUpdateRegions();
} }
if (primaryWasInFullscreen != this._primaryMonitor.inFullscreen) { if (primaryWasInFullscreen != this.primaryMonitor.inFullscreen) {
this.emit('primary-fullscreen-changed', this._primaryMonitor.inFullscreen); this.emit('primary-fullscreen-changed', this.primaryMonitor.inFullscreen);
} }
}, },
updateRegions: function() { _updateRegions: function() {
let rects = [], struts = [], i; let rects = [], struts = [], i;
if (this._updateRegionIdle) { if (this._updateRegionIdle) {
@ -908,7 +842,7 @@ const Chrome = new Lang.Class({
// the width/height across the middle of the screen, then // the width/height across the middle of the screen, then
// we don't create a strut for it at all. // we don't create a strut for it at all.
let side; let side;
let primary = this._primaryMonitor; let primary = this.primaryMonitor;
if (x1 <= primary.x && x2 >= primary.x + primary.width) { if (x1 <= primary.x && x2 >= primary.x + primary.width) {
if (y1 <= primary.y) if (y1 <= primary.y)
side = Meta.Side.TOP; side = Meta.Side.TOP;
@ -967,8 +901,7 @@ const Chrome = new Lang.Class({
return false; return false;
} }
}); });
Signals.addSignalMethods(LayoutManager.prototype);
Signals.addSignalMethods(Chrome.prototype);
// HotCorner: // HotCorner: