Extract proximity detection from intellihide

This commit is contained in:
Charles Gagnon
2018-10-11 23:54:01 -04:00
parent ba4466463a
commit 563ede8135
6 changed files with 303 additions and 136 deletions

View File

@@ -2,7 +2,7 @@
UUID = dash-to-panel@jderose9.github.com
BASE_MODULES = extension.js stylesheet.css metadata.json COPYING README.md
EXTRA_MODULES = appIcons.js convenience.js panel.js panelManager.js intellihide.js panelStyle.js overview.js taskbar.js windowPreview.js prefs.js utils.js Settings.ui
EXTRA_MODULES = appIcons.js convenience.js panel.js panelManager.js proximity.js intellihide.js panelStyle.js overview.js taskbar.js windowPreview.js prefs.js utils.js Settings.ui
EXTRA_IMAGES = highlight_stacked_bg.svg
TOLOCALIZE = prefs.js appIcons.js
MSGSRC = $(wildcard po/*.po)

View File

@@ -3950,6 +3950,29 @@
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="dynamic_trans">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkListBox" id="dynamic_trans_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="selection_mode">none</property>
</object>
</child>
<child type="label_item">
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="position">1</property>

View File

@@ -27,6 +27,7 @@ const PointerWatcher = imports.ui.pointerWatcher;
const Tweener = imports.ui.tweener;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const Proximity = Me.imports.proximity;
const Utils = Me.imports.utils;
//timeout intervals
@@ -47,6 +48,7 @@ var Intellihide = new Lang.Class({
this._dtpPanel = dtpPanel;
this._dtpSettings = dtpPanel._dtpSettings;
this._panelBox = dtpPanel.panelBox;
this._proximityManager = dtpPanel.panelManager.proximityManager;
this._signalsHandler = new Utils.GlobalSignalsHandler();
this._timeoutsHandler = new Utils.TimeoutsHandler();
@@ -61,7 +63,6 @@ var Intellihide = new Lang.Class({
enable: function(reset) {
this._enabled = true;
this._monitor = this._dtpPanel.monitor;
this._focusedWindowInfo = null;
this._animationDestination = -1;
this._pendingUpdate = false;
this._dragging = false;
@@ -79,8 +80,15 @@ var Intellihide = new Lang.Class({
this._bindGeneralSignals();
if (this._dtpSettings.get_boolean('intellihide-hide-from-windows')) {
this._bindWindowSignals();
this._setFocusedWindow();
this._proximityWatchId = this._proximityManager.createWatch(
this._panelBox,
Proximity.Mode[this._dtpSettings.get_string('intellihide-behaviour')],
0,
overlap => {
this._windowOverlap = overlap;
this._queueUpdatePanelPosition();
}
);
}
this._setRevealMechanism();
@@ -92,8 +100,9 @@ var Intellihide = new Lang.Class({
this._dtpSettings.disconnect(this._intellihideChangedId);
}
this._proximityManager.removeWatch(this._proximityWatchId);
this._setTrackPanel(reset, false);
this._disconnectFocusedWindow();
this._signalsHandler.destroy();
this._timeoutsHandler.destroy();
@@ -145,15 +154,11 @@ var Intellihide = new Lang.Class({
'changed::panel-position',
'changed::panel-size',
'changed::intellihide-use-pressure',
'changed::intellihide-hide-from-windows'
'changed::intellihide-hide-from-windows',
'changed::intellihide-behaviour'
],
() => this._reset()
],
[
Utils.DisplayWrapper.getScreen(),
'restacked',
() => this._queueUpdatePanelPosition()
],
[
Main.layoutManager,
'monitors-changed',
@@ -188,32 +193,6 @@ var Intellihide = new Lang.Class({
);
},
_bindWindowSignals: function() {
this._signalsHandler.add(
[
global.display,
'notify::focus-window',
() => {
this._setFocusedWindow();
this._queueUpdatePanelPosition();
}
],
[
global.window_group,
[
'actor-added',
'actor-removed'
],
() => this._queueUpdatePanelPosition()
],
[
this._dtpSettings,
'changed::intellihide-behaviour',
() => this._queueUpdatePanelPosition()
]
);
},
_setTrackPanel: function(reset, enable) {
if (!reset) {
Main.layoutManager._untrackActor(this._panelBox);
@@ -283,66 +262,6 @@ var Intellihide = new Lang.Class({
}
},
_setFocusedWindow: function() {
this._disconnectFocusedWindow();
let focusedWindow = global.display.focus_window;
if (focusedWindow) {
let focusedWindowInfo = this._getFocusedWindowInfo(focusedWindow);
if (this._checkIfHandledWindowType(focusedWindowInfo.metaWindow)) {
focusedWindowInfo.id = focusedWindowInfo.window.connect('allocation-changed', () => this._queueUpdatePanelPosition())
this._focusedWindowInfo = focusedWindowInfo;
}
}
},
_getFocusedWindowInfo: function(focusedWindow) {
let focusedWindowInfo = { window: focusedWindow.get_compositor_private() };
focusedWindowInfo.metaWindow = focusedWindowInfo.window.get_meta_window();
if (focusedWindow.is_attached_dialog()) {
let mainMetaWindow = focusedWindow.get_transient_for();
if (focusedWindowInfo.metaWindow.get_frame_rect().height < mainMetaWindow.get_frame_rect().height) {
focusedWindowInfo.window = mainMetaWindow.get_compositor_private();
focusedWindowInfo.metaWindow = mainMetaWindow;
}
}
return focusedWindowInfo;
},
_disconnectFocusedWindow: function() {
if (this._focusedWindowInfo) {
this._focusedWindowInfo.window.disconnect(this._focusedWindowInfo.id);
this._focusedWindowInfo = null;
}
},
_getHandledWindows: function() {
return global.get_window_actors()
.map(w => w.get_meta_window())
.filter(mw => this._checkIfHandledWindow(mw));
},
_checkIfHandledWindow: function(metaWindow) {
return metaWindow && !metaWindow.minimized &&
metaWindow.get_workspace().index() == Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace_index() &&
metaWindow.get_monitor() == this._monitor.index &&
this._checkIfHandledWindowType(metaWindow);
},
_checkIfHandledWindowType: function(metaWindow) {
let metaWindowType = metaWindow.get_window_type();
//https://www.roojs.org/seed/gir-1.2-gtk-3.0/seed/Meta.WindowType.html
return metaWindowType <= Meta.WindowType.SPLASHSCREEN &&
metaWindowType != Meta.WindowType.DESKTOP;
},
_queueUpdatePanelPosition: function(fromRevealMechanism) {
if (!fromRevealMechanism && this._timeoutsHandler.getId(T2) && !Main.overview.visible) {
//unless this is a mouse interaction or entering/leaving the overview, limit the number
@@ -379,34 +298,7 @@ var Intellihide = new Lang.Class({
return this._panelBox.hover;
}
let behaviour = this._dtpSettings.get_string('intellihide-behaviour');
if (behaviour === 'FOCUSED_WINDOWS') {
return !(this._focusedWindowInfo &&
this._checkIfHandledWindow(this._focusedWindowInfo.metaWindow) &&
this._checkIfWindowObstructs(this._focusedWindowInfo.metaWindow));
}
let metaWindows = this._getHandledWindows();
if (behaviour === 'MAXIMIZED_WINDOWS') {
return !metaWindows.some(mw => mw.maximized_vertically && mw.maximized_horizontally);
} else { //ALL_WINDOWS
return !metaWindows.some(mw => this._checkIfWindowObstructs(mw));
}
},
_checkIfWindowObstructs: function(metaWindow) {
let windowRect = metaWindow.get_frame_rect();
if (this._panelAtTop) {
return windowRect.y <= this._monitor.y + this._panelBox.height;
}
let windowBottom = windowRect.y + windowRect.height;
let panelTop = this._monitor.y + this._monitor.height - this._panelBox.height;
return windowBottom >= panelTop;
return !this._windowOverlap;
},
_checkIfGrab: function() {
@@ -421,7 +313,8 @@ var Intellihide = new Lang.Class({
},
_adjustDynamicTransparency: function() {
this._invokeIfExists(this._dtpPanel.panel._updateSolidStyle);
if (this._dtpPanel.panel.hasOwnProperty('_updateSolidStyle'))
this._invokeIfExists(this._dtpPanel.panel._updateSolidStyle);
},
_revealPanel: function(immediate) {

View File

@@ -322,7 +322,6 @@ var dtpPanelWrapper = new Lang.Class({
if (!this.isSecondary) {
this.panel.actor.set_height(this._oldPanelHeight);
this.panelBox.set_anchor_point(0, 0);
Main.overview._panelGhost.set_height(this._oldPanelHeight);
this._setActivitiesButtonVisible(true);
@@ -506,7 +505,7 @@ var dtpPanelWrapper = new Lang.Class({
this._myPanelGhost.set_height(isTop ? 0 : size);
if(isTop) {
this.panelBox.set_anchor_point(0, 0);
this.panelBox.set_position(this.monitor.x, this.monitor.y);
this._removeTopLimit();
@@ -517,7 +516,7 @@ var dtpPanelWrapper = new Lang.Class({
if(!this.panel.actor.has_style_class_name('dashtopanelTop'))
this.panel.actor.add_style_class_name('dashtopanelTop');
} else {
this.panelBox.set_anchor_point(0,(-1)*(this.monitor.height-this.panelBox.height));
this.panelBox.set_position(this.monitor.x, this.monitor.y + this.monitor.height - this.panelBox.height);
if (!this._topLimit) {
this._topLimit = new St.BoxLayout({ name: 'topLimit', vertical: true });
@@ -780,12 +779,14 @@ var dtpSecondaryPanelBoxWrapper = new Lang.Class({
var dtpSecondaryPanel = new Lang.Class({
Name: 'DashToPanel.SecondaryPanel',
Extends: Panel.Panel,
Extends: St.Widget,
_init : function(settings, monitor) {
this.parent({ name: 'panel', reactive: true });
this._dtpSettings = settings;
this.actor = new Shell.GenericContainer({ name: 'panel', reactive: true });
this.actor = this;
this.actor._delegate = this;
this._sessionStyle = null;

View File

@@ -30,6 +30,7 @@
const Me = imports.misc.extensionUtils.getCurrentExtension();
const Overview = Me.imports.overview;
const Panel = Me.imports.panel;
const Proximity = Me.imports.proximity;
const Utils = Me.imports.utils;
const Clutter = imports.gi.Clutter;
@@ -53,10 +54,9 @@ var dtpPanelManager = new Lang.Class({
enable: function(reset) {
let dtpPrimaryMonitor = Main.layoutManager.monitors[(Main.layoutManager.primaryIndex + this._dtpSettings.get_int('primary-monitor')) % Main.layoutManager.monitors.length];
this.proximityManager = new Proximity.ProximityManager();
this.primaryPanel = new Panel.dtpPanelWrapper(this, dtpPrimaryMonitor, Main.panel, Main.layoutManager.panelBox);
Main.layoutManager.panelBox.set_position(dtpPrimaryMonitor.x, dtpPrimaryMonitor.y);
Main.layoutManager.panelBox.set_size(dtpPrimaryMonitor.width, -1);
this.primaryPanel.enable();
this.allPanels = [ this.primaryPanel ];
@@ -73,8 +73,6 @@ var dtpPanelManager = new Lang.Class({
let panel = new Panel.dtpSecondaryPanel(this._dtpSettings, monitor);
panelBox.add(panel.actor);
panelBox.set_position(monitor.x, monitor.y);
panelBox.set_size(monitor.width, -1);
let panelWrapper = new Panel.dtpPanelWrapper(this, monitor, panel, panelBox, true);
@@ -127,6 +125,7 @@ var dtpPanelManager = new Lang.Class({
disable: function(reset) {
this._overview.disable();
this.proximityManager.destroy();
this.allPanels.forEach(p => {
p.disable();

251
proximity.js Normal file
View File

@@ -0,0 +1,251 @@
/*
* This file is part of the Dash-To-Panel extension for Gnome 3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Layout = imports.ui.layout;
const Main = imports.ui.main;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const Utils = Me.imports.utils;
//timeout intervals
const MIN_UPDATE_MS = 200;
//timeout names
const T1 = 'limitUpdateTimeout';
var Mode = {
ALL_WINDOWS: 0,
FOCUSED_WINDOWS: 1,
MAXIMIZED_WINDOWS: 2
};
var ProximityWatch = new Lang.Class({
Name: 'DashToPanel.ProximityWatch',
_init: function(actor, mode, threshold, handler) {
this.actor = actor;
this.mode = mode;
this.threshold = threshold;
this.handler = handler;
this._allocationChangedId = actor.connect('allocation-changed', () => this._update());
this._update();
},
destroy: function() {
this.actor.disconnect(this._allocationChangedId);
},
_update: function() {
let [actorX, actorY] = this.actor.get_position();
this.actorX = actorX;
this.actorY = actorY;
this.monitorIndex = Main.layoutManager.findIndexForActor(this.actor);
this._updateWatchRect();
},
_updateWatchRect: function() {
this.rect = new Meta.Rectangle({
x: this.actorX - this.threshold,
y: this.actorY - this.threshold,
width: this.actor.width + this.threshold * 2,
height: this.actor.height + this.threshold * 2
});
},
});
var ProximityManager = new Lang.Class({
Name: 'DashToPanel.ProximityManager',
_init: function() {
this._counter = 1;
this._watches = {};
this._focusedWindowInfo = null;
this._signalsHandler = new Utils.GlobalSignalsHandler();
this._timeoutsHandler = new Utils.TimeoutsHandler();
this._bindSignals();
this._setFocusedWindow();
},
createWatch: function(actor, mode, threshold, handler) {
let watch = new ProximityWatch(actor, mode, threshold, handler);
this._watches[this._counter] = watch;
this.update();
return this._counter++;
},
removeWatch: function(id) {
if (this._watches[id]) {
this._watches[id].destroy();
delete this._watches[id];
}
},
update() {
this._queueUpdate(true);
},
destroy: function() {
this._signalsHandler.destroy();
this._timeoutsHandler.destroy();
this._disconnectFocusedWindow();
Object.keys(this._watches).forEach(id => this.removeWatch(id));
},
_bindSignals: function() {
this._signalsHandler.add(
[
Utils.DisplayWrapper.getScreen(),
'restacked',
() => this._queueUpdate()
],
[
global.display,
'notify::focus-window',
() => {
this._setFocusedWindow();
this._queueUpdate();
}
],
[
global.window_group,
[
'actor-added',
'actor-removed'
],
() => this._queueUpdate()
]
);
},
_setFocusedWindow: function() {
this._disconnectFocusedWindow();
let focusedWindow = global.display.focus_window;
if (focusedWindow) {
let focusedWindowInfo = this._getFocusedWindowInfo(focusedWindow);
if (this._checkIfHandledWindowType(focusedWindowInfo.metaWindow)) {
focusedWindowInfo.id = focusedWindowInfo.window.connect('allocation-changed', () => this._queueUpdate())
this._focusedWindowInfo = focusedWindowInfo;
}
}
},
_getFocusedWindowInfo: function(focusedWindow) {
let focusedWindowInfo = { window: focusedWindow.get_compositor_private() };
focusedWindowInfo.metaWindow = focusedWindowInfo.window.get_meta_window();
if (focusedWindow.is_attached_dialog()) {
let mainMetaWindow = focusedWindow.get_transient_for();
if (focusedWindowInfo.metaWindow.get_frame_rect().height < mainMetaWindow.get_frame_rect().height) {
focusedWindowInfo.window = mainMetaWindow.get_compositor_private();
focusedWindowInfo.metaWindow = mainMetaWindow;
}
}
return focusedWindowInfo;
},
_disconnectFocusedWindow: function() {
if (this._focusedWindowInfo) {
this._focusedWindowInfo.window.disconnect(this._focusedWindowInfo.id);
this._focusedWindowInfo = null;
}
},
_getHandledWindows: function() {
return global.get_window_actors()
.map(w => w.get_meta_window())
.filter(mw => this._checkIfHandledWindow(mw));
},
_checkIfHandledWindow: function(metaWindow) {
return metaWindow && !metaWindow.minimized &&
// metaWindow.get_workspace().index() == Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace_index() &&
// metaWindow.get_monitor() == this._monitor.index &&
this._checkIfHandledWindowType(metaWindow);
},
_checkIfHandledWindowType: function(metaWindow) {
let metaWindowType = metaWindow.get_window_type();
//https://www.roojs.org/seed/gir-1.2-gtk-3.0/seed/Meta.WindowType.html
return metaWindowType <= Meta.WindowType.SPLASHSCREEN &&
metaWindowType != Meta.WindowType.DESKTOP;
},
_queueUpdate: function(noDelay) {
if (!noDelay && this._timeoutsHandler.getId(T1)) {
//limit the number of updates
return this._pendingUpdate = true;
}
this._timeoutsHandler.add([T1, MIN_UPDATE_MS, () => this._endLimitUpdate()]);
let metaWindows = this._getHandledWindows();
Object.keys(this._watches).forEach(id => {
let watch = this._watches[id];
let overlap = this._update(watch, metaWindows);
if (overlap !== watch.overlap) {
watch.handler(overlap);
watch.overlap = overlap;
}
});
},
_endLimitUpdate: function() {
if (this._pendingUpdate) {
this._pendingUpdate = false;
this._queueUpdate();
}
},
_update: function(watch, metaWindows) {
if (watch.mode === Mode.FOCUSED_WINDOWS) {
return (this._focusedWindowInfo &&
this._checkIfHandledWindow(this._focusedWindowInfo.metaWindow) &&
this._checkProximity(this._focusedWindowInfo.metaWindow, watch));
}
if (watch.mode === Mode.MAXIMIZED_WINDOWS) {
return metaWindows.some(mw => mw.maximized_vertically && mw.maximized_horizontally &&
mw.get_monitor() == watch.monitorIndex);
} else if (watch.mode === Mode.ALL_WINDOWS) {
return metaWindows.some(mw => this._checkProximity(mw, watch));
}
},
_checkProximity: function(metaWindow, watch) {
return metaWindow.get_frame_rect().overlap(watch.rect);
},
});