diff --git a/Makefile b/Makefile
index 13ca75e..6b05729 100644
--- a/Makefile
+++ b/Makefile
@@ -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)
diff --git a/Settings.ui b/Settings.ui
index 6d50d03..a6e31fa 100644
--- a/Settings.ui
+++ b/Settings.ui
@@ -3950,6 +3950,29 @@
1
+
+
+
+ False
+ True
+ 2
+
+
1
diff --git a/intellihide.js b/intellihide.js
index 3a609e2..a2e55e1 100644
--- a/intellihide.js
+++ b/intellihide.js
@@ -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) {
diff --git a/panel.js b/panel.js
index 721ff06..419e4eb 100644
--- a/panel.js
+++ b/panel.js
@@ -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;
diff --git a/panelManager.js b/panelManager.js
index 3485140..9ebabdf 100644
--- a/panelManager.js
+++ b/panelManager.js
@@ -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();
diff --git a/proximity.js b/proximity.js
new file mode 100644
index 0000000..5122ad8
--- /dev/null
+++ b/proximity.js
@@ -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 .
+ */
+
+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);
+ },
+});
\ No newline at end of file