dot/.local/share/gnome-shell/extensions/workspaces-to-dock@passingt.../dockedWorkspaces.js

2600 lines
110 KiB
JavaScript
Raw Normal View History

2020-05-11 09:16:27 +00:00
/* ========================================================================================================
* dockedWorkspaces.js - dock object that holds the workspaces thumbnailsBox
* --------------------------------------------------------------------------------------------------------
* CREDITS: This code was copied from the dash-to-dock extension https://github.com/micheleg/dash-to-dock
* and modified to create a workspaces dock. Many thanks to michele_g for a great extension.
*
* Part of this code also comes from gnome-shell-extensions:
* http://git.gnome.org/browse/gnome-shell-extensions/
* ========================================================================================================
*/
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const GObject = imports.gi.GObject;
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
const Meta = imports.gi.Meta;
const Params = imports.misc.params;
const Main = imports.ui.main;
const WorkspacesView = imports.ui.workspacesView;
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
const WorkspaceSwitcherPopup = imports.ui.workspaceSwitcherPopup;
const Overview = imports.ui.overview;
const OverviewControls = imports.ui.overviewControls;
const Layout = imports.ui.layout;
const AppDisplay = imports.ui.appDisplay;
const ExtensionUtils = imports.misc.extensionUtils;
const Config = imports.misc.config;
const Me = ExtensionUtils.getCurrentExtension();
const Extension = Me.imports.extension;
const Convenience = Me.imports.convenience;
const MyWorkspaceThumbnail = Me.imports.myWorkspaceThumbnail;
const ShortcutsPanel = Me.imports.shortcutsPanel;
const MyWorkspaceSwitcher = Me.imports.myWorkspaceSwitcher;
const MyPressureBarrier = Me.imports.myPressureBarrier;
const DashToDock_UUID = "dash-to-dock@micxgx.gmail.com";
let DashToDockExtension = null;
let DashToDock = null;
const DOCK_EDGE_VISIBLE_WIDTH = 5;
const DOCK_EDGE_VISIBLE_OVERVIEW_WIDTH = 32;
const PRESSURE_TIMEOUT = 1000;
let GSFunctions = {};
const IntellihideAction = {
SHOW_FULL: 0,
SHOW_PARTIAL: 1,
SHOW_PARTIAL_FIXED: 2
};
const OverviewAction = {
SHOW_FULL: 0, // Dock is always visible
HIDE: 1, // Dock is always invisible. Visible on mouse hover
SHOW_PARTIAL: 2 // Dock partially hidden. Visible on mouse hover
};
const DockState = {
HIDDEN: 0,
SHOWING: 1,
SHOWN: 2,
HIDING: 3
};
// Return the actual position reverseing left and right in rtl
function getPosition(settings) {
let position = settings.get_enum('dock-position');
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) {
if (position == St.Side.LEFT)
position = St.Side.RIGHT;
else if (position == St.Side.RIGHT)
position = St.Side.LEFT;
}
return position;
}
function getDockStateDesc(state) {
let desc = "";
switch (state) {
case DockState.HIDDEN:
desc = "HIDDEN";
break;
case DockState.SHOWING:
desc = "SHOWING";
break;
case DockState.SHOWN:
desc = "SHOWN";
break;
case DockState.HIDING:
desc = "HIDING";
break;
}
return desc;
}
var MyThumbnailsSlider = GObject.registerClass({
Properties: {
'side': GObject.ParamSpec.enum(
'side', 'side', 'side',
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
St.Side, St.Side.RIGHT),
'slidex': GObject.ParamSpec.double(
'slidex', 'slidex', 'slidex',
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT,
0, 1, 1),
'slideout-size': GObject.ParamSpec.double(
'slideout-size', 'slideout-size', 'slideout-size',
GObject.ParamFlags.READWRITE,
0, Infinity, 1),
'partial-slideout-size': GObject.ParamSpec.double(
'partial-slideout-size', 'partial-slideout-size', 'partial-slideout-size',
GObject.ParamFlags.READWRITE,
0, Infinity, DOCK_EDGE_VISIBLE_OVERVIEW_WIDTH + 1)
}
}, class WorkspacesToDock_MyThumbnailsSlider extends St.Bin {
_init(params = {}) {
// slide parameter: 1 = visible, 0 = hidden.
this._side = params.side;
this._slidex = params.slidex;
this._slideoutSize = 1;
this._partialSlideoutSize = DOCK_EDGE_VISIBLE_OVERVIEW_WIDTH + 1;
super._init(params);
}
vfunc_allocate(box, flags) {
this.set_allocation(box, flags);
if (this.child == null)
return;
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
let [minChildWidth, minChildHeight, natChildWidth, natChildHeight] =
this.child.get_preferred_size();
let childWidth = natChildWidth;
let childHeight = natChildHeight;
let childBox = new Clutter.ActorBox();
let slideoutSize = this._slideoutSize;
if (this._side == St.Side.LEFT) {
childBox.x1 = (this._slidex -1) * (childWidth - slideoutSize);
childBox.x2 = slideoutSize + this._slidex * (childWidth - slideoutSize);
childBox.y1 = 0;
childBox.y2 = childBox.y1 + childHeight;
} else if ((this._side == St.Side.RIGHT) || (this._side == St.Side.BOTTOM)) {
childBox.x1 = 0;
childBox.x2 = childWidth;
childBox.y1 = 0;
childBox.y2 = childBox.y1 + childHeight;
} else if (this._side == St.Side.TOP) {
childBox.x1 = 0;
childBox.x2 = childWidth;
childBox.y1 = (this._slidex -1) * (childHeight - slideoutSize);
childBox.y2 = slideoutSize + this._slidex * (childHeight - slideoutSize);
}
this.child.allocate(childBox, flags);
this.child.set_clip(-childBox.x1, -childBox.y1,
-childBox.x1+availWidth, -childBox.y1 + availHeight);
}
// Just the child width but taking into account the slided out part
vfunc_get_preferred_width(forHeight) {
let slideoutSize = this._slideoutSize;
let [minWidth, natWidth] = this.child.get_preferred_width(forHeight);
if (this._side == St.Side.LEFT || this._side == St.Side.RIGHT) {
minWidth = (minWidth) * this._slidex + slideoutSize;
natWidth = (natWidth) * this._slidex + slideoutSize;
}
return [minWidth, natWidth];
}
// Just the child height but taking into account the slided out part
vfunc_get_preferred_height(forWidth) {
let slideoutSize = this._slideoutSize;
let [minHeight, natHeight] = this.child.get_preferred_height(forWidth);
if (this._side == St.Side.TOP || this._side == St.Side.BOTTOM) {
minHeight = (minHeight) * this._slidex + slideoutSize;
natHeight = (natHeight) * this._slidex + slideoutSize;
}
return [minHeight, natHeight];
}
set slidex(value) {
if (this._slidex == value)
return;
this._slidex = value;
this.notify('slidex');
this.queue_relayout();
}
get slidex() {
return this._slidex;
}
set slideoutSize(value) {
if (this._slideoutSize == value)
return;
this._slideoutSize = value;
this.notify('slideout-size');
}
get slideoutSize() {
return this._slideoutSize;
}
set partialSlideoutSize(value) {
if (this._partialSlideoutSize == value)
return;
this._partialSlideoutSize = value;
this.notify('partial-slideout-size');
}
get partialSlideoutSize() {
return this._partialSlideoutSize;
}
});
var DockedWorkspaces = class WorkspacesToDock_DockedWorkspaces {
constructor() {
this._gsCurrentVersion = Config.PACKAGE_VERSION.split('.');
this._settings = Convenience.getSettings('org.gnome.shell.extensions.workspaces-to-dock');
this._signalHandler = new Convenience.globalSignalHandler();
// Temporarily disable redisplay until initialized
// NOTE: This prevents connected signals from trying to update dock visibility
this._disableRedisplay = true;
this._refreshThumbnailsOnRegionUpdate = true;
// set RTL value
this._rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL;
// Load settings
this._bindSettingsChanges();
// Set position of dock
this._position = getPosition(this._settings);
this._isHorizontal = (this._position == St.Side.TOP ||
this._position == St.Side.BOTTOM);
// Authohide current status. Not to be confused with autohide enable/disagle global (g)settings
// Initially set to null - will be set during first enable/disable autohide
this._autohideStatus = null;
// Initialize dock state
this._dockState = DockState.HIDDEN;
// Initialize popup menu flag
this._popupMenuShowing = false;
// Initialize colors with generic values
this._defaultBackground = {red:0, green:0, blue:0, alpha:0};
this._customBackground = {red:0, green:0, blue:0, alpha:0};
this._defaultBorder = {red:0, green:0, blue:0, alpha:0};
this._customBorder = {red:0, green:0, blue:0, alpha:0};
this._cssStylesheet = null;
// Initialize pressure barrier variables
this._canUsePressure = false;
this._pressureSensed = false;
this._pressureBarrier = null;
this._barrier = null;
this._removeBarrierTimeoutId = 0;
// Override Gnome Shell functions
this._overrideGnomeShellFunctions();
// Set the _monitor property to the primary monitor
this._monitor = Main.layoutManager.primaryMonitor;
// Create a new thumbnailsbox object
this._workspaceAdjustment = Main.overview._overview._controls._workspaceAdjustment;
this._thumbnailsBox = new MyWorkspaceThumbnail.MyThumbnailsBox(this._workspaceAdjustment, this);
// Create a shortcuts panel object
this._shortcutsPanel = new ShortcutsPanel.ShortcutsPanel(this);
this._shortcutsPanel.connect("update-favorite-apps", this._onShortcutsPanelUpdated.bind(this));
this._shortcutsPanel.connect("update-running-apps", this._onShortcutsPanelUpdated.bind(this));
// Create custom workspace switcher
this._workspaceSwitcher = null;
if (this._isHorizontal && this._settings.get_boolean('horizontal-workspace-switching'))
this._workspaceSwitcher = new MyWorkspaceSwitcher.WorkspaceSwitcher();
// Create position styles for dock container
let positionStyleClass = ['top', 'right', 'bottom', 'left'];
let styleClass = positionStyleClass[this._position];
if (this._settings.get_boolean('dock-fixed')
|| (this._settings.get_boolean('intellihide') && this._settings.get_enum('intellihide-action') == IntellihideAction.SHOW_PARTIAL_FIXED)) {
styleClass += " fixed";
}
let shortcutsPanelOrientation = this._settings.get_enum('shortcuts-panel-orientation');
if (this._settings.get_boolean('show-shortcuts-panel')) {
if (shortcutsPanelOrientation == 1) {
styleClass += " inside";
} else {
styleClass += " outside";
}
}
if (this._settings.get_boolean('customize-height') && this._settings.get_int('customize-height-option') == 1) {
if (this._settings.get_double('top-margin') == 0 || this._settings.get_double('bottom-margin') == 0) {
styleClass += " fullheight";
}
}
// Set _extendContainer property
if (this._settings.get_boolean('customize-height') && this._settings.get_int('customize-height-option') == 1) {
this._extendContainer = true;
} else {
this._extendContainer = false;
}
// Set _centerContainer property
if (this._settings.get_boolean('customize-height') && this._settings.get_boolean('center-thumbnails-on-dock')) {
this._centerContainer = true;
} else {
this._centerContainer = false;
}
// Set _centerPanelsIndependently property
if (this._centerContainer && this._settings.get_int('center-thumbnails-option') == 0) {
this._centerPanelsIndependently = true;
} else {
this._centerPanelsIndependently = false;
}
// Initialize alignment and box packing variables
let align;
let packStart;
let packVertical = this._isHorizontal? true : false;
if (this._position == St.Side.TOP || this._position == St.Side.LEFT) {
align = Clutter.ActorAlign.START;
packStart = true;
} else {
align = Clutter.ActorAlign.END;
packStart = false;
}
// Create the main dock and container
this._dock = new St.BoxLayout({
name: 'workspacestodockDock',
reactive: true,
track_hover: true,
vertical: packVertical,
pack_start: !packStart,
style_class: styleClass
});
this._dockContainer = new St.BoxLayout({
name: 'workspacestodockDockContainer',
reactive: false,
track_hover: false,
vertical: packVertical
});
// Create the panels and container
this._panels = new St.BoxLayout({
name: 'workspacestodockPanels',
reactive: false,
track_hover: false,
vertical: packVertical,
pack_start: !packStart,
x_align: (this._centerContainer) ? Clutter.ActorAlign.CENTER : Clutter.ActorAlign.START,
y_align: (this._centerContainer) ? Clutter.ActorAlign.CENTER : Clutter.ActorAlign.START
});
this._panelsContainer = new St.BoxLayout({
name: 'workspacestodockPanelsContainer',
reactive: false,
track_hover: false,
vertical: packVertical,
pack_start: packStart,
x_align: (this._centerContainer) ? Clutter.ActorAlign.CENTER : Clutter.ActorAlign.START,
y_align: (this._centerContainer) ? Clutter.ActorAlign.CENTER : Clutter.ActorAlign.START
});
this._panels.add_actor(this._panelsContainer);
this._dockContainer.add_actor(this._panels);
// Initialize keyboard toggle timeout
this._toggleWithKeyboardTimeoutId = 0;
// Connect the _dock hover, scroll and button release events
this._checkHoverStatusId = 0;
this._scrollWorkspaceSwitchDeadTimeId = 0;
this._dock.connect("notify::hover", this._hoverChanged.bind(this));
this._dock.connect("scroll-event", this._onScrollEvent.bind(this));
this._dock.connect("button-release-event", this._onDockClicked.bind(this));
// Add workspaces, and shortcuts panel to dock container based on dock position
// and shortcuts panel orientation
if (shortcutsPanelOrientation == 1) {
this._panelsContainer.add_actor(this._shortcutsPanel.actor);
this._panelsContainer.add_actor(this._thumbnailsBox);
} else {
this._panelsContainer.add_actor(this._thumbnailsBox);
this._panelsContainer.add_actor(this._shortcutsPanel.actor);
}
// Create the sliding actor whose allocation is to be tracked for input regions
//let slideoutSize = this._settings.get_boolean('dock-edge-visible') ? this._triggerWidth + DOCK_EDGE_VISIBLE_WIDTH : this._triggerWidth;
//this._slider = new MyThumbnailsSlider({side: this._position, slideout-size: slideoutSize});
// Slider alignment
let xAlign, yAlign;
if (this._isHorizontal) {
xAlign = Clutter.ActorAlign.CENTER;
if (this._position == St.Side.TOP) {
yAlign = Clutter.ActorAlign.START;
} else {
yAlign = Clutter.ActorAlign.END;
}
} else {
if (this._position == St.Side.LEFT) {
xAlign = Clutter.ActorAlign.START;
} else {
xAlign = Clutter.ActorAlign.END;
}
yAlign = Clutter.ActorAlign.CENTER;
}
this._slider = new MyThumbnailsSlider({
side: this._position,
x_align: xAlign,
y_align: yAlign,
});
// Create the dock main actor
this.actor = new St.Bin({
name: 'workspacestodockMainActor',
reactive: false,
x_align: align,
y_align: align
});
this.actor._delegate = this;
this._showId = this.actor.connect('show', this._initialize.bind(this));
// Add the dock to slider and then to the main container actor
this._dock.add_actor(this._dockContainer);
this._slider.set_child(this._dock);
this.actor.set_child(this._slider);
// Connect global signals
let workspaceManager = global.workspace_manager;
this._signalHandler.push(
[
this._thumbnailsBox,
'notify::width',
this._thumbnailsBoxResized.bind(this)
],
[
this._thumbnailsBox,
'notify::height',
this._thumbnailsBoxResized.bind(this)
],
[
Main.layoutManager,
'monitors-changed',
this._onMonitorsChanged.bind(this)
],
[
St.ThemeContext.get_for_stage(global.stage),
'changed',
this._onThemeChanged.bind(this)
],
[
Main.extensionManager,
'extension-state-changed',
this._onExtensionSystemStateChanged.bind(this)
],
[
Main.overview.viewSelector,
'notify::y',
this._updateYPosition.bind(this)
],
[
global.display,
'in-fullscreen-changed',
this._updateBarrier.bind(this)
],
[
workspaceManager,
'workspace-added',
this._onWorkspaceAdded.bind(this)
],
[
workspaceManager,
'workspace-removed',
this._onWorkspaceRemoved.bind(this)
]
);
// Bind keyboard shortcuts
if (this._settings.get_boolean('toggle-dock-with-keyboard-shortcut'))
this._bindDockKeyboardShortcut();
// Connect DashToDock hover signal if the extension is already loaded and enabled
this._hoveringDash = false;
DashToDockExtension = Main.extensionManager.lookup(DashToDock_UUID);
if (DashToDockExtension) {
if (DashToDockExtension.state == ExtensionUtils.ExtensionState.ENABLED) {
DashToDock = DashToDockExtension.imports.extension;
if (DashToDock) {
DashToDockExtension.hasDockPositionKey = false;
if (DashToDock.dockManager) {
DashToDockExtension.hasDockPositionKey = true;
} else {
var keys = DashToDock.dock._settings.list_keys();
if (keys.indexOf('dock-position') > -1) {
DashToDockExtension.hasDockPositionKey = true;
}
}
this._connectDashToDockSignals();
}
}
}
// Intialize trigger spacing
// We use this space to trigger the dock (show/hide) if the pressure barrier is not present (or disabled)
// We also use this space for scrolling when the dock is hidden
this._triggerWidth = 1;
this._updateTriggerWidth();
// Hide the dock while initializing and setting position
// But since we need to access its width, we use opacity
this.actor.set_opacity(0);
// Since the actor is not a topLevel child and its parent is now not added to the Chrome,
// the allocation change of the parent container (slide in and slideout) doesn't trigger
// anymore an update of the input regions. Force the update manually.
this.actor.connect('notify::allocation',
Main.layoutManager._queueUpdateRegions.bind(Main.layoutManager));
// Create struts actor for tracking workspace region of fixed dock or partially fixed dock
this._struts = new St.Bin({ reactive: false });
if (this._settings.get_boolean('dock-fixed')
|| (this._settings.get_boolean('intellihide') && this._settings.get_enum('intellihide-action') == IntellihideAction.SHOW_PARTIAL_FIXED)) {
Main.uiGroup.add_child(this._struts);
Main.layoutManager.uiGroup.set_child_below_sibling(this._struts, Main.layoutManager.modalDialogGroup);
Main.layoutManager._trackActor(this._struts, {affectsStruts: true, trackFullscreen: true});
// Force region update to update workspace area
Main.layoutManager._queueUpdateRegions();
}
// Add aligning container without tracking it for input region (old affectsinputRegion: false that was removed).
// The public method trackChrome requires the actor to be child of a tracked actor. Since I don't want the parent
// to be tracked I use the private internal _trackActor instead.
Main.uiGroup.add_child(this.actor);
Main.layoutManager.uiGroup.set_child_below_sibling(this.actor, Main.layoutManager.modalDialogGroup);
if (this._settings.get_boolean('dock-fixed')
|| (this._settings.get_boolean('intellihide') && this._settings.get_enum('intellihide-action') == IntellihideAction.SHOW_PARTIAL_FIXED)) {
Main.layoutManager._trackActor(this._slider, {trackFullscreen: true});
} else {
if (this._settings.get_boolean('autohide-in-fullscreen')) {
Main.layoutManager._trackActor(this._slider);
} else {
Main.layoutManager._trackActor(this._slider, {trackFullscreen: true});
}
}
}
_initialize() {
if(this._showId > 0){
this.actor.disconnect(this._showId);
this._showId = 0;
}
// Show the thumbnailsBox. We need it to calculate the width of the dock.
this._thumbnailsBox._createThumbnails();
// Set shortcuts panel visibility
if (this._settings.get_boolean('show-shortcuts-panel')) {
this._shortcutsPanel.actor.show();
} else {
this._shortcutsPanel.actor.hide();
}
// Set initial position and opacity
this._resetPosition();
this.actor.set_opacity(255);
this._disableRedisplay = false;
// Now that the dock is on the stage and custom themes are loaded
// retrieve background color and set background opacity
this._updateAppearancePreferences();
// Setup pressure barrier (GS38+ only)
this._updatePressureBarrier();
this._updateBarrier();
// NOTE: GS3.14+ thumbnailsBox width signal triggers ealier so now we need this.
this._redisplay();
}
destroy() {
// Disconnect global signals first to prevent calls to functions during
// the destroy process
this._signalHandler.disconnect();
// Restore normal Gnome Shell functions
this._restoreGnomeShellFunctions();
this._shortcutsPanel.destroy();
if (this._workspaceSwitcher)
this._workspaceSwitcher.destroy();
// Unbind keyboard shortcuts
if (this._settings.get_boolean('toggle-dock-with-keyboard-shortcut'))
this._unbindDockKeyboardShortcut();
// Remove existing barrier
this._removeBarrier();
if (this._pressureBarrier) {
this._pressureBarrier.destroy();
this._pressureBarrier = null;
}
// Destroy thumbnailsBox
this._thumbnailsBox.destroy();
this._slider.destroy();
this._struts.destroy();
// Destroy main clutter actor: this should be sufficient
// From clutter documentation:
// If the actor is inside a container, the actor will be removed.
// When you destroy a container, its children will be destroyed as well.
this.actor.destroy();
// Disconnect GSettings signals
// We wait until after _restoreGnomeShellFunctions because we needed
// settings to determine how to restore the dash
this._settings.run_dispose();
this._settings = null;
}
// function called during init to override gnome shell 3.4/3.6/3.8
_overrideGnomeShellFunctions() {
let self = this;
// Hide normal Dash
if (this._settings.get_boolean('hide-dash')) {
// Hide normal dash
Main.overview.dash.hide();
Main.overview.dash.set_width(1);
}
// Change source of swarm animation to shortcuts panel apps button
if (self._settings.get_boolean('show-shortcuts-panel') && self._settings.get_boolean('shortcuts-panel-appsbutton-animation')) {
GSFunctions['BaseAppView_doSpringAnimation'] = AppDisplay.BaseAppView.prototype._doSpringAnimation;
AppDisplay.BaseAppView.prototype._doSpringAnimation = function(animationDirection){
this._grid.opacity = 255;
this._grid.animateSpring(
animationDirection,
self._shortcutsPanel._appsButton);
};
}
// Hide normal workspaces thumbnailsBox
Main.overview._overview._controls._thumbnailsSlider.opacity = 0;
// Override WorkspaceSwitcherPopup _show function to prevent popup from showing when disabled
GSFunctions['WorkspaceSwitcherPopup_show'] = WorkspaceSwitcherPopup.WorkspaceSwitcherPopup.prototype._show;
WorkspaceSwitcherPopup.WorkspaceSwitcherPopup.prototype._show = function() {
if (self._settings.get_boolean('hide-workspace-switcher-popup')) {
return false;
} else {
let ret = GSFunctions['WorkspaceSwitcherPopup_show'].call(this);
return ret;
}
};
// Extend LayoutManager _updateRegions function to destroy/create workspace thumbnails when completed.
// NOTE1: needed because 'monitors-changed' signal doesn't wait for queued regions to update.
// We need to wait so that the screen workspace workarea is adjusted before creating workspace thumbnails.
// Otherwise when we move the primary workspace to another monitor, the workspace thumbnails won't adjust for the top panel.
// NOTE2: also needed when dock-fixed is enabled/disabled to adjust for workspace area change
GSFunctions['LayoutManager_updateRegions'] = Layout.LayoutManager.prototype._updateRegions;
Layout.LayoutManager.prototype._updateRegions = function() {
let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
let ret = GSFunctions['LayoutManager_updateRegions'].call(this);
// SANITY CHECK:
if (self._refreshThumbnailsOnRegionUpdate) {
self._refreshThumbnailsOnRegionUpdate = false;
if (this._settings)
self._refreshThumbnails();
} else {
if (self._workAreaWidth) {
let widthTolerance = workArea.width * .01;
let heightTolerance = workArea.height * .01;
if (self._workAreaWidth < workArea.width-widthTolerance || self._workAreaWidth > workArea.width+widthTolerance) {
self._refreshThumbnails();
} else if (self._workAreaHeight < workArea.height-heightTolerance || self._workAreaHeight > workArea.height+heightTolerance) {
self._refreshThumbnails();
}
} else {
self._refreshThumbnails();
}
}
return ret;
};
// Override geometry calculations of activities overview to use workspaces-to-dock instead of the default thumbnailsbox.
// NOTE: This is needed for when the dock is positioned on a secondary monitor and also for when the shortcuts panel is visible
// causing the dock to be wider than normal.
GSFunctions['WorkspacesDisplay_updateWorkspacesActualGeometry'] = WorkspacesView.WorkspacesDisplay.prototype._updateWorkspacesActualGeometry;
WorkspacesView.WorkspacesDisplay.prototype._updateWorkspacesActualGeometry = function() {
if (!this._workspacesViews.length)
return;
let [x, y] = this.get_transformed_position();
let allocation = this.allocation;
let width = allocation.x2 - allocation.x1;
let height = allocation.y2 - allocation.y1;
let spacing = Main.overview._overview._controls.get_theme_node().get_length('spacing');
let monitors = Main.layoutManager.monitors;
// Get Dash monitor index
let dashMonitorIndex = this._primaryIndex;
let dashMultiMonitor = false;
if (DashToDock) {
if (DashToDock.dockManager) {
dashMonitorIndex = DashToDock.dockManager._preferredMonitorIndex;
dashMultiMonitor = DashToDock.dockManager._settings.get_boolean('multi-monitor');
} else {
dashMonitorIndex = DashToDock.dock._settings.get_int('preferred-monitor');
if (dashMonitorIndex < 0 || dashMonitorIndex >= Main.layoutManager.monitors.length) {
dashMonitorIndex = this._primaryIndex;
}
}
}
// Get thumbnails monitor index
let preferredMonitorIndex = self._settings.get_int('preferred-monitor');
let thumbnailsMonitorIndex = (Main.layoutManager.primaryIndex + preferredMonitorIndex) % Main.layoutManager.monitors.length ;
// Iterate through monitors
for (let i = 0; i < monitors.length; i++) {
let geometry = { x: monitors[i].x, y: monitors[i].y, width: monitors[i].width, height: monitors[i].height };
// Adjust index to point to correct dock
// Only needed when using DashToDock.dockManager
let idx;
if (i == dashMonitorIndex || dashMultiMonitor) {
idx = 0;
} else if (i < dashMonitorIndex) {
idx = i + 1;
}
// Adjust width for dash
let dashWidth = 0;
let dashHeight = 0;
let monitorHasDashDock = false;
if (DashToDock) {
if (DashToDock.dockManager) {
if (DashToDock.dockManager._allDocks[0]) {
if (i == dashMonitorIndex || dashMultiMonitor) {
monitorHasDashDock = true;
if (DashToDock.dockManager._allDocks[idx]._position == St.Side.LEFT ||
DashToDock.dockManager._allDocks[idx]._position == St.Side.RIGHT) {
dashWidth = DashToDock.dockManager._allDocks[idx]._box.width + spacing;
}
if (DashToDock.dockManager._allDocks[idx]._position == St.Side.TOP ||
DashToDock.dockManager._allDocks[idx]._position == St.Side.BOTTOM) {
dashHeight = DashToDock.dockManager._allDocks[idx]._box.height + spacing;
}
}
}
} else {
if (i == dashMonitorIndex) {
monitorHasDashDock = true;
if (DashToDockExtension.hasDockPositionKey) {
if (DashToDock.dock._position == St.Side.LEFT ||
DashToDock.dock._position == St.Side.RIGHT) {
dashWidth = DashToDock.dock._box.width + spacing;
}
if (DashToDock.dock._position == St.Side.TOP ||
DashToDock.dock._position == St.Side.BOTTOM) {
dashHeight = DashToDock.dock._box.height + spacing;
}
} else {
dashWidth = DashToDock.dock._box.width + spacing;
}
}
}
} else {
if (!self._settings.get_boolean('hide-dash') &&
i == this._primaryIndex) {
dashWidth = Main.overview._overview._controls._dashSlider.getVisibleWidth() + spacing;
}
}
// Adjust width for workspaces thumbnails
let thumbnailsWidth = 0;
let thumbnailsHeight = 0;
let monitorHasThumbnailsDock = false;
if (i == thumbnailsMonitorIndex) {
monitorHasThumbnailsDock = true;
let fixedPosition = self._settings.get_boolean('dock-fixed');
let overviewAction = self._settings.get_enum('overview-action');
let visibleEdge = self._triggerWidth;
if (self._settings.get_boolean('dock-edge-visible')) {
visibleEdge = self._triggerWidth + DOCK_EDGE_VISIBLE_WIDTH;
}
if (self._position == St.Side.LEFT ||
self._position == St.Side.RIGHT) {
if (fixedPosition) {
thumbnailsWidth = self.actor.get_width() + spacing;
} else {
if (overviewAction == OverviewAction.HIDE) {
thumbnailsWidth = visibleEdge;
} else if (overviewAction == OverviewAction.SHOW_PARTIAL) {
thumbnailsWidth = self._slider.partialSlideoutSize;
} else {
thumbnailsWidth = self.actor.get_width() + spacing;
}
}
}
if (self._position == St.Side.TOP ||
self._position == St.Side.BOTTOM) {
if (fixedPosition) {
thumbnailsHeight = self.actor.get_height() + spacing;
} else {
if (overviewAction == OverviewAction.HIDE) {
thumbnailsHeight = visibleEdge;
} else if (overviewAction == OverviewAction.SHOW_PARTIAL) {
thumbnailsHeight = self._slider.partialSlideoutSize;
} else {
thumbnailsHeight = self.actor.get_height() + spacing;
}
}
}
}
// Adjust x and width for workspacesView geometry
let controlsWidth = dashWidth + thumbnailsWidth;
if (DashToDock && DashToDockExtension.hasDockPositionKey) {
if (DashToDock.dockManager) {
if (DashToDock.dockManager._allDocks[0]) {
// What if dash and thumbnailsbox are both on the same side?
if ((monitorHasDashDock && DashToDock.dockManager._allDocks[idx]._position == St.Side.LEFT) &&
(monitorHasThumbnailsDock && self._position == St.Side.LEFT)) {
controlsWidth = Math.max(dashWidth, thumbnailsWidth);
geometry.x += controlsWidth;
} else {
if (monitorHasDashDock && DashToDock.dockManager._allDocks[idx]._position == St.Side.LEFT) {
geometry.x += dashWidth;
}
if (monitorHasThumbnailsDock && self._position == St.Side.LEFT) {
geometry.x += thumbnailsWidth;
}
}
if ((monitorHasDashDock && DashToDock.dockManager._allDocks[idx]._position == St.Side.RIGHT) &&
(monitorHasThumbnailsDock && self._position == St.Side.RIGHT)) {
controlsWidth = Math.max(dashWidth, thumbnailsWidth);
}
}
} else {
// What if dash and thumbnailsbox are both on the same side?
if ((monitorHasDashDock && DashToDock.dock._position == St.Side.LEFT) &&
(monitorHasThumbnailsDock && self._position == St.Side.LEFT)) {
controlsWidth = Math.max(dashWidth, thumbnailsWidth);
geometry.x += controlsWidth;
} else {
if (monitorHasDashDock && DashToDock.dock._position == St.Side.LEFT) {
geometry.x += dashWidth;
}
if (monitorHasThumbnailsDock && self._position == St.Side.LEFT) {
geometry.x += thumbnailsWidth;
}
}
if ((monitorHasDashDock && DashToDock.dock._position == St.Side.RIGHT) &&
(monitorHasThumbnailsDock && self._position == St.Side.RIGHT)) {
controlsWidth = Math.max(dashWidth, thumbnailsWidth);
}
}
} else {
if (this.get_text_direction() == Clutter.TextDirection.LTR) {
if (monitorHasThumbnailsDock && self._position == St.Side.LEFT) {
controlsWidth = Math.max(dashWidth, thumbnailsWidth);
geometry.x += controlsWidth;
} else {
geometry.x += dashWidth;
}
} else {
if (monitorHasThumbnailsDock && self._position == St.Side.RIGHT) {
controlsWidth = Math.max(dashWidth, thumbnailsWidth);
} else {
geometry.x += thumbnailsWidth;
}
}
}
geometry.width -= controlsWidth;
// Adjust y and height for workspacesView geometry for primary monitor (top panel, etc.)
if (i == this._primaryIndex) {
geometry.y = y;
if (height > 0)
geometry.height = height;
}
// What if dash and thumbnailsBox are not on the primary monitor?
let controlsHeight = dashHeight + thumbnailsHeight;
if (DashToDock && DashToDockExtension.hasDockPositionKey) {
if (DashToDock.dockManager) {
if (DashToDock.dockManager._allDocks[0]) {
if ((monitorHasDashDock && DashToDock.dockManager._allDocks[idx]._position == St.Side.TOP) &&
(monitorHasThumbnailsDock && self._position == St.Side.TOP)) {
controlsHeight = Math.max(dashHeight, thumbnailsHeight);
geometry.y += controlsHeight;
} else {
if (monitorHasDashDock && DashToDock.dockManager._allDocks[idx]._position == St.Side.TOP) {
geometry.y += dashHeight;
}
if (monitorHasThumbnailsDock && self._position == St.Side.TOP) {
geometry.y += thumbnailsHeight;
}
}
if ((monitorHasDashDock && DashToDock.dockManager._allDocks[idx]._position == St.Side.BOTTOM) &&
(monitorHasThumbnailsDock && self._position == St.Side.BOTTOM)) {
controlsHeight = Math.max(dashHeight, thumbnailsHeight);
}
}
} else {
if ((monitorHasDashDock && DashToDock.dock._position == St.Side.TOP) &&
(monitorHasThumbnailsDock && self._position == St.Side.TOP)) {
controlsHeight = Math.max(dashHeight, thumbnailsHeight);
geometry.y += controlsHeight;
} else {
if (monitorHasDashDock && DashToDock.dock._position == St.Side.TOP) {
geometry.y += dashHeight;
}
if (monitorHasThumbnailsDock && self._position == St.Side.TOP) {
geometry.y += thumbnailsHeight;
}
}
if ((monitorHasDashDock && DashToDock.dock._position == St.Side.BOTTOM) &&
(monitorHasThumbnailsDock && self._position == St.Side.BOTTOM)) {
controlsHeight = Math.max(dashHeight, thumbnailsHeight);
}
}
} else {
if (monitorHasThumbnailsDock && self._position == St.Side.TOP) {
geometry.y += thumbnailsHeight;
}
}
geometry.height -= controlsHeight;
this._workspacesViews[i].setMyActualGeometry(geometry);
}
};
// This override is needed to prevent calls from updateWorkspacesActualGeometry bound to the workspacesDisplay object
// without destroying and recreating Main.overview.viewSelector._workspacesDisplay.
// We replace this function with a new setMyActualGeometry function (see below)
// TODO: This is very hackish. We need to find a better way to accomplish this
GSFunctions['WorkspacesViewBase_setActualGeometry'] = WorkspacesView.WorkspacesViewBase.prototype.setActualGeometry;
WorkspacesView.WorkspacesViewBase.prototype.setActualGeometry = function(geom) {
//GSFunctions['WorkspacesView_setActualGeometry'].call(this, geom);
return;
};
// This additional function replaces the WorkspacesView setActualGeometry function above.
// TODO: This is very hackish. We need to find a better way to accomplish this
WorkspacesView.WorkspacesViewBase.prototype.setMyActualGeometry = function(geom) {
this._actualGeometry = geom;
this._syncActualGeometry();
};
this._overrideComplete = true;
}
// function called during destroy to restore gnome shell 3.4/3.6/3.8
_restoreGnomeShellFunctions() {
// Restore normal Dash
if (this._settings.get_boolean('hide-dash')) {
if (!DashToDock) {
// Show normal dash (if no dash-to-dock)
Main.overview.dash.show();
Main.overview.dash.set_width(-1);
// This forces the recalculation of the icon size
Main.overview.dash._maxHeight = -1;
}
}
// Restore source of swarm animation to normal apps button
if (GSFunctions['BaseAppView_doSpringAnimation']) {
AppDisplay.BaseAppView.prototype._doSpringAnimation = GSFunctions['BaseAppView_doSpringAnimation'];
}
// Show normal workspaces thumbnailsBox
Main.overview._overview._controls._thumbnailsSlider.opacity = 255;
// Restore normal WorkspaceSwitcherPopup_show function
WorkspaceSwitcherPopup.WorkspaceSwitcherPopup.prototype._show = GSFunctions['WorkspaceSwitcherPopup_show'];
// Restore normal LayoutManager _updateRegions function
Layout.LayoutManager.prototype._updateRegions = GSFunctions['LayoutManager_updateRegions'];
// Restore normal WorkspacesDisplay _updateworksapgesActualGeometray function
WorkspacesView.WorkspacesDisplay.prototype._updateWorkspacesActualGeometry = GSFunctions['WorkspacesDisplay_updateWorkspacesActualGeometry'];
// Restore normal WorkspacesView _setActualGeometry function
WorkspacesView.WorkspacesViewBase.prototype.setActualGeometry = GSFunctions['WorkspacesViewBase_setActualGeometry'];
WorkspacesView.WorkspacesViewBase.prototype.setMyActualGeometry = null;
}
// handler for when shortcuts panel is updated
_onShortcutsPanelUpdated() {
this._updateSize();
this._redisplay();
}
// handler for when thumbnailsBox is resized
_thumbnailsBoxResized() {
this._updateSize();
this._redisplay();
}
// handler for when dock y position is updated
_updateYPosition() {
this._updateSize();
}
// handler for when workspaces are added
_onWorkspaceAdded() {
this._updateSize();
this._redisplay();
}
// handler for when workspaces are removed
_onWorkspaceRemoved() {
this._updateSize();
this._redisplay();
}
_updateTriggerWidth(force) {
// Calculate and set triggerWidth
let previousTriggerWidth = this._triggerWidth;
if (this._settings.get_boolean('dock-fixed')) {
this._triggerWidth = 0;
} else if (this._settings.get_boolean('intellihide') && this._settings.get_enum('intellihide-action') == IntellihideAction.SHOW_PARTIAL_FIXED) {
this._triggerWidth = 1;
} else {
if (!this._settings.get_boolean('dock-edge-visible') &&
this._settings.get_boolean('require-pressure-to-show') &&
this._settings.get_boolean('disable-scroll')) {
if (this._pressureSensed) {
this._triggerWidth = 1;
} else if (this._dockState == DockState.SHOWN) {
this._triggerWidth = 1;
} else {
this._triggerWidth = 0;
}
} else {
this._triggerWidth = 1;
}
}
if (previousTriggerWidth == this._triggerWidth && !force)
return;
if (!this._disableRedisplay)
this._updateSize();
}
// handler for when dock height is updated
_updateHeight() {
this._updateSize();
}
// handler to bind settings when preferences changed
_bindSettingsChanges() {
this._settings.connect('changed::opaque-background', () => {
this._updateBackgroundOpacity();
});
this._settings.connect('changed::background-opacity', () => {
this._updateBackgroundOpacity();
});
this._settings.connect('changed::straight-corners', () => {
this._updateStraightCorners();
});
this._settings.connect('changed::autohide', () => {
this.emit('box-changed');
this._updateBarrier();
});
this._settings.connect('changed::preferred-monitor', () => {
this._resetPosition();
this._redisplay();
});
this._settings.connect('changed::hide-dash', () => {
if (this._settings.get_boolean('hide-dash')) {
Main.overview.dash.hide();
Main.overview.dash.set_width(1);
} else {
if (!DashToDock) {
// Show normal dash (if no dash-to-dock)
Main.overview.dash.show();
Main.overview.dash.set_width(-1);
// This forces the recalculation of the icon size
Main.overview.dash._maxHeight = -1;
}
}
});
this._settings.connect('changed::show-shortcuts-panel', () => {
let shortcutsPanelOrientation = this._settings.get_enum('shortcuts-panel-orientation');
if (this._settings.get_boolean('show-shortcuts-panel')) {
if (shortcutsPanelOrientation == 1) {
this._dock.add_style_class_name('inside');
}
this._shortcutsPanel.actor.show();
} else {
if (shortcutsPanelOrientation == 1) {
this._dock.remove_style_class_name('inside');
}
this._shortcutsPanel.actor.hide();
}
this._updateSize();
this._redisplay();
});
this._settings.connect('changed::shortcuts-panel-icon-size', () => {
this._shortcutsPanel.refresh();
this._updateSize();
this._redisplay();
});
this._settings.connect('changed::shortcuts-panel-show-running', () => {
this._shortcutsPanel.refresh();
this._updateSize();
this._redisplay();
});
this._settings.connect('changed::shortcuts-panel-show-places', () => {
this._shortcutsPanel.refresh();
this._updateSize();
this._redisplay();
});
this._settings.connect('changed::dock-edge-visible', () => {
this._updateTriggerWidth(true);
this._redisplay();
});
this._settings.connect('changed::require-pressure-to-show', () => {
this._updateTriggerWidth(true);
this._redisplay();
});
this._settings.connect('changed::pressure-threshold', () => {
this._updatePressureBarrier();
this._updateBarrier();
});
this._settings.connect('changed::use-pressure-speed-limit', () => {
this._updatePressureBarrier();
this._updateBarrier();
});
this._settings.connect('changed::pressure-speed-limit', () => {
this._updatePressureBarrier();
this._updateBarrier();
});
this._settings.connect('changed::disable-scroll', () => {
this._updateTriggerWidth(true);
this._redisplay();
});
this._settings.connect('changed::screen-edge-padding', () => {
this._updateSize();
this._redisplay();
});
this._settings.connect('changed::customize-thumbnail', () => {
// hide and show thumbnailsBox to resize thumbnails
this._refreshThumbnails();
});
this._settings.connect('changed::thumbnail-size', () => {
// hide and show thumbnailsBox to resize thumbnails
this._refreshThumbnails();
});
this._settings.connect('changed::customize-thumbnail-visible-width', () => {
this._updateTriggerWidth(true);
this._redisplay();
});
this._settings.connect('changed::thumbnail-visible-width', () => {
this._updateTriggerWidth(true);
this._redisplay();
});
this._settings.connect('changed::workspace-captions', () => {
// hide and show thumbnailsBox to reset workspace apps in caption
this._refreshThumbnails();
});
this._settings.connect('changed::workspace-caption-position', () => {
// hide and show thumbnailsBox to reset workspace apps in caption
this._refreshThumbnails();
});
this._settings.connect('changed::workspace-caption-height', () => {
// hide and show thumbnailsBox to reset workspace apps in caption
this._refreshThumbnails();
});
this._settings.connect('changed::workspace-caption-items', () => {
// hide and show thumbnailsBox to reset workspace apps in caption
this._refreshThumbnails();
});
this._settings.connect('changed::workspace-caption-windowcount-image', () => {
// hide and show thumbnailsBox to reset workspace apps in caption
this._refreshThumbnails();
});
this._settings.connect('changed::workspace-caption-taskbar-icon-size', () => {
// hide and show thumbnailsBox to reset workspace apps in caption
this._refreshThumbnails();
});
this._settings.connect('changed::top-margin', () => {
// Add or remove addtional style class when workspace is fixed and set to full height
if (this._settings.get_boolean('customize-height') && this._settings.get_int('customize-height-option') == 1) {
if (this._settings.get_double('top-margin') == 0 || this._settings.get_double('bottom-margin') == 0) {
this._dock.add_style_class_name('fullheight');
} else {
this._dock.remove_style_class_name('fullheight');
}
} else {
this._dock.remove_style_class_name('fullheight');
}
this._updateSize();
});
this._settings.connect('changed::bottom-margin', () => {
// Add or remove addtional style class when workspace is fixed and set to full height
if (this._settings.get_boolean('customize-height') && this._settings.get_int('customize-height-option') == 1) {
if (this._settings.get_double('top-margin') == 0 || this._settings.get_double('bottom-margin') == 0) {
this._dock.add_style_class_name('fullheight');
} else {
this._dock.remove_style_class_name('fullheight');
}
} else {
this._dock.remove_style_class_name('fullheight');
}
this._updateSize();
});
this._settings.connect('changed::toggle-dock-with-keyboard-shortcut', () =>{
if (this._settings.get_boolean('toggle-dock-with-keyboard-shortcut'))
this._bindDockKeyboardShortcut();
else
this._unbindDockKeyboardShortcut();
});
}
_updatePressureBarrier() {
let self = this;
this._canUsePressure = global.display.supports_extended_barriers();
let pressureThreshold = this._settings.get_double('pressure-threshold');
let speedLimit;
if (this._settings.get_boolean('use-pressure-speed-limit'))
speedLimit = this._settings.get_double('pressure-speed-limit');
// Remove existing pressure barrier
if (this._pressureBarrier) {
this._pressureBarrier.destroy();
this._pressureBarrier = null;
}
// Create new pressure barrier based on pressure threshold setting
if (this._canUsePressure) {
this._pressureBarrier = new MyPressureBarrier.MyPressureBarrier(pressureThreshold, speedLimit, PRESSURE_TIMEOUT,
Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW);
this._pressureBarrier.connect('trigger', function(barrier){
self._onPressureSensed();
});
this._pressureBarrier.connect('speed-exceeded', function(barrier){
self._onSpeedExceeded();
});
}
}
_bindDockKeyboardShortcut() {
Main.wm.addKeybinding('dock-keyboard-shortcut', this._settings, Meta.KeyBindingFlags.NONE, Shell.ActionMode.NORMAL, () => {
if (this._autohideStatus) {
if (this._dockState == DockState.HIDDEN || this._dockState == DockState.HIDING) {
this._toggleWithKeyboard(true);
} else {
this._toggleWithKeyboard(false);
}
} else {
if (this._dockState == DockState.SHOWN || this._dockState == DockState.SHOWING) {
this._toggleWithKeyboard(false);
} else {
this._toggleWithKeyboard(true);
}
}
});
}
_toggleWithKeyboard(show) {
// Clear keyboard toggle timeout
if (this._toggleWithKeyboardTimeoutId > 0) {
GLib.source_remove(this._toggleWithKeyboardTimeoutId);
this._toggleWithKeyboardTimeoutId = 0;
}
// Hide dock after timeout
if (show) {
this._show();
let timeout = this._settings.get_double('keyboard-toggle-timeout') * 1000;
this._toggleWithKeyboardTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, timeout, () => {
this._toggleWithKeyboard(false);
});
} else {
this._hide();
}
}
_unbindDockKeyboardShortcut() {
Main.wm.removeKeybinding('dock-keyboard-shortcut');
}
// Determine if mouse is hovering dock container
_isHovering() {
if (this._dock.hover) {
return true;
} else {
return false;
}
}
// handler for mouse hover events
_hoverChanged() {
if (this._settings.get_boolean('dock-fixed')) {
return;
}
if (this._canUsePressure && this._settings.get_boolean('require-pressure-to-show') && this._barrier) {
if (this._pressureSensed == false && this._dockState != DockState.SHOWN) {
if (this._isHovering()) {
return;
}
}
}
if (this._dockState == DockState.SHOWING) {
// Prevent dock from getting stuck animated in when mouse is no longer hovering
if (this._checkHoverStatusId > 0) {
GLib.source_remove(this._checkHoverStatusId);
this._checkHoverStatusId = 0;
}
this._checkHoverStatusId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 100, this._checkHoverStatus.bind(this));
return;
}
if (this._settings.get_boolean('require-click-to-show')) {
// check if metaWin is maximized
let workspaceManager = global.workspace_manager;
let activeWorkspace = workspaceManager.get_active_workspace();
let maximized = false;
let windows = global.get_window_actors();
for (let i = windows.length-1; i >= 0; i--) {
let metaWin = windows[i].get_meta_window();
if (metaWin.get_workspace() == activeWorkspace) {
if (metaWin.appears_focused && metaWin.maximized_horizontally) {
maximized = true;
break;
}
}
}
// set hovering flag if maximized
// used by the _onDockClicked function (hover+click)
if (maximized) {
if (this._isHovering()) {
this._hovering = true;
if (this._dockState != DockState.SHOWN) {
return;
}
} else {
this._hovering = false;
}
} else {
this._hovering = false;
}
}
//Skip if dock is not in autohide mode for instance because it is shown by intellihide
if (this._settings.get_boolean('autohide')) {
if (this._isHovering()) {
this._show();
} else {
this._hide();
}
} else {
this._hide();
}
}
_checkHoverStatus() {
if (this._checkHoverStatusId > 0) {
GLib.source_remove(this._checkHoverStatusId);
this._checkHoverStatusId = 0;
}
if (Extension.intellihide._toggledOverviewOnDrag == false) {
if (this._toggleWithKeyboardTimeoutId == 0) {
this._hoverChanged();
}
}
}
// handler for mouse click events - works in conjuction with hover event to show dock for maxmized windows
_onDockClicked(actor, event) {
// Show overview if button is right click
if (this._settings.get_boolean('toggle-overview')) {
let button = event.get_button();
if (button == 3) { //right click
if (Main.overview.visible) {
Main.overview.hide(); // force normal mode
} else {
Main.overview.show(); // force overview mode
}
// pass right-click event on allowing it to bubble up
return Clutter.EVENT_PROPAGATE;
}
}
if (this._settings.get_boolean('require-click-to-show')) {
if (this._hovering) {
//Skip if dock is not in autohide mode for instance because it is shown by intellihide
if (this._settings.get_boolean('autohide') && this._autohideStatus) {
if (this._isHovering()) {
this._show();
} else {
this._hide();
}
}
this._hovering = false;
}
}
return Clutter.EVENT_STOP;
}
_onSpeedExceeded() {
// FIX ISSUE: #23
// Remove barrier so that mouse pointer can access monitors on other side of dock quickly
// --------------
// CONTINUE IF
// dock NOT in single monitor config
// dock NOT on first monitor && in left position
// dock NOT on last monitor && in right position
if (this._settings.get_boolean('use-pressure-speed-limit')) {
if ((Main.layoutManager.monitors.length > 1) &&
!(this._monitor == 0 && this._position == St.Side.LEFT) &&
!(this._monitor == Main.layoutManager.monitors.length-1 && this._position == St.Side.RIGHT)) {
// Remove barrier immediately
this._removeBarrier();
// Restore barrier after short timeout
if (this._restoreBarrierTimeoutId > 0) {
GLib.source_remove(this._restoreBarrierTimeoutId);
this._restoreBarrierTimeoutId = 0;
}
this._restoreBarrierTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500, this._updateBarrier.bind(this));
}
}
}
// handler for mouse pressure sensed (GS38+ only)
_onPressureSensed() {
this._pressureSensed = true;
this._updateTriggerWidth();
this._hoverChanged();
}
_onDashToDockShowing() {
//Skip if dock is not in dashtodock hover mode
if (this._settings.get_boolean('dashtodock-hover')) {
if (DashToDock && Main.overview.visible == false) {
if (DashToDock.dockManager) {
if (DashToDock.dockManager._allDocks[0]._box.hover) {
this._hoveringDash = true;
this._show();
}
} else {
if (DashToDock.dock._box.hover) {
this._hoveringDash = true;
this._show();
}
}
}
}
}
_onDashToDockHiding() {
//Skip if dock is not in dashtodock hover mode
if (this._settings.get_boolean('dashtodock-hover')) {
if (DashToDock) {
this._hoveringDash = false;
this._hide();
}
}
}
_onDashToDockLeave() {
// NOTE: Causing workspaces-to-dock to hide when switching workspaces in Gnome 3.14.
// Remove until a workaround can be found.
// this._hoveringDash = false;
}
// handler for DashToDock hover events
_onDashToDockHoverChanged() {
//Skip if dock is not in dashtodock hover mode
if (this._settings.get_boolean('dashtodock-hover')) {
if (DashToDock) {
if (DashToDock.dockManager) {
if (DashToDock.dockManager._allDocks[0]._box.hover) {
if (Main.overview.visible == false) {
this._hoveringDash = true;
this._show();
}
} else {
this._hoveringDash = false;
this._hide();
}
} else {
if (DashToDock.dock._box.hover) {
if (Main.overview.visible == false) {
this._hoveringDash = true;
this._show();
}
} else {
this._hoveringDash = false;
this._hide();
}
}
}
}
}
_onDashToDockToggled() {
this._hoveringDash = false;
this._disconnectDashToDockSignals();
this._connectDashToDockSignals();
}
_onDashToDockBoxDestroy() {
this._hoveringDash = false;
this._disconnectDashToDockSignals();
// Restore dock if still enabled
if (this._checkDashToDockStatusId > 0) {
GLib.source_remove(this._checkDashToDockStatusId);
this._checkDashToDockStatusId = 0;
}
this._checkDashToDockStatusId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500, this._checkDashToDockStatus.bind(this));
}
_checkDashToDockStatus() {
if (DashToDock)
this._connectDashToDockSignals();
this._checkDashToDockStatusId = 0;
}
_disconnectDashToDockSignals() {
this._signalHandler.disconnectWithLabel('DashToDockBoxHoverSignal');
this._signalHandler.disconnectWithLabel('DashToDockManagerSignal');
}
_connectDashToDockSignals() {
if (DashToDock) {
// Connect DashToDock hover signal
if (DashToDock.dockManager) {
if (DashToDock.dockManager._allDocks[0]) {
this._signalHandler.pushWithLabel(
'DashToDockBoxHoverSignal',
[
DashToDock.dockManager._allDocks[0]._box,
'destroy',
this._onDashToDockBoxDestroy.bind(this)
],
[
DashToDock.dockManager._allDocks[0]._box,
'notify::hover',
this._onDashToDockHoverChanged.bind(this)
],
[
DashToDock.dockManager._allDocks[0]._box,
'leave-event',
this._onDashToDockLeave.bind(this)
]
);
this._signalHandler.pushWithLabel(
'DashToDockManagerSignal',
[
DashToDock.dockManager._allDocks[0],
'showing',
this._onDashToDockShowing.bind(this)
],
[
DashToDock.dockManager._allDocks[0],
'hiding',
this._onDashToDockHiding.bind(this)
],
[
DashToDock.dockManager,
'toggled',
this._onDashToDockToggled.bind(this)
]
);
}
}
}
}
// handler for extensionSystem state changes
_onExtensionSystemStateChanged(source, extension) {
// Only looking for DashToDock state changes
if (extension.uuid == DashToDock_UUID) {
DashToDockExtension = extension;
if (DashToDockExtension.state == ExtensionUtils.ExtensionState.ENABLED) {
DashToDock = DashToDockExtension.imports.extension;
if (DashToDock) {
DashToDockExtension.hasDockPositionKey = false;
if (DashToDock.dockManager) {
DashToDockExtension.hasDockPositionKey = true;
} else {
var keys = DashToDock.dock._settings.list_keys();
if (keys.indexOf('dock-position') > -1) {
DashToDockExtension.hasDockPositionKey = true;
}
}
this._connectDashToDockSignals();
}
} else if (extension.state == ExtensionUtils.ExtensionState.DISABLED || extension.state == ExtensionUtils.ExtensionState.UNINSTALLED) {
DashToDock = null;
this._hoveringDash = false;
this._disconnectDashToDockSignals();
}
}
}
// handler for mouse scroll events
// Switches workspace by scrolling over the dock
// This comes from desktop-scroller@obsidien.github.com
_onScrollEvent(actor, event) {
if (this._settings.get_boolean('disable-scroll') &&
this._autohideStatus &&
this._slider.slidex == 0 && // Need to check the slidex for partially showing dock
(this._dockState == DockState.HIDDEN || this._dockState == DockState.HIDING))
return Clutter.EVENT_STOP;
let workspaceManager = global.workspace_manager;
let activeWs = workspaceManager.get_active_workspace();
let direction;
switch (event.get_scroll_direction()) {
case Clutter.ScrollDirection.UP:
if (this._isHorizontal && this._settings.get_boolean('horizontal-workspace-switching')) {
direction = Meta.MotionDirection.LEFT;
} else {
direction = Meta.MotionDirection.UP;
}
break;
case Clutter.ScrollDirection.DOWN:
if (this._isHorizontal && this._settings.get_boolean('horizontal-workspace-switching')) {
direction = Meta.MotionDirection.RIGHT;
} else {
direction = Meta.MotionDirection.DOWN;
}
break;
case Clutter.ScrollDirection.LEFT:
if (this._isHorizontal && this._settings.get_boolean('horizontal-workspace-switching')) {
direction = Meta.MotionDirection.LEFT;
}
break;
case Clutter.ScrollDirection.RIGHT:
if (this._isHorizontal && this._settings.get_boolean('horizontal-workspace-switching')) {
direction = Meta.MotionDirection.RIGHT;
}
break;
}
if (direction) {
if (this._settings.get_boolean('scroll-with-touchpad')) {
// passingthru67: copied from dash-to-dock
// Prevent scroll events from triggering too many workspace switches
// by adding a 250ms deadtime between each scroll event.
// Usefull on laptops when using a touchpad.
// During the deadtime do nothing
if(this._scrollWorkspaceSwitchDeadTimeId > 0)
return false;
else {
this._scrollWorkspaceSwitchDeadTimeId =
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 250, () => {
this._scrollWorkspaceSwitchDeadTimeId = 0;
});
}
}
let ws = activeWs.get_neighbor(direction);
if (Main.wm._workspaceSwitcherPopup == null) {
Main.wm._workspaceSwitcherPopup = new WorkspaceSwitcherPopup.WorkspaceSwitcherPopup();
}
// Set the workspaceSwitcherPopup actor to non reactive,
// to prevent it from grabbing focus away from the dock
Main.wm._workspaceSwitcherPopup.reactive = false;
Main.wm._workspaceSwitcherPopup.connect('destroy', function() {
Main.wm._workspaceSwitcherPopup = null;
});
// Do not show wokspaceSwitcher in overview
if (!Main.overview.visible)
Main.wm._workspaceSwitcherPopup.display(direction, ws.index());
Main.wm.actionMoveWorkspace(ws);
}
return Clutter.EVENT_STOP;
}
// autohide function to show dock
_show() {
// Only show if dock hidden, is hiding, or is partially shown/hidden
if (this._dockState == DockState.HIDDEN || this._dockState == DockState.HIDING || this._slider.slidex < 1) {
this._removeAnimations();
// If the dock is hidden, wait this._settings.get_double('show-delay') before showing it;
// otherwise show it immediately.
let delay = 0;
if (this._dockState == DockState.HIDDEN)
delay = this._settings.get_double('show-delay');
this._animateIn(this._settings.get_double('animation-time'), delay, true);
}
}
// autohide function to hide dock
_hide() {
this._updateTriggerWidth();
if (this._settings.get_boolean('dock-fixed')) {
return;
}
if (this._isHovering() || (this._hoveringDash && !Main.overview._shown)) {
return;
}
let intellihideAction = this._settings.get_enum('intellihide-action');
if (!Main.overview._shown && intellihideAction == IntellihideAction.SHOW_FULL && !this._autohideStatus) {
return;
}
let overviewAction = this._settings.get_enum('overview-action');
if (Main.overview._shown && overviewAction == OverviewAction.SHOW_FULL && !this._autohideStatus) {
return;
}
// Only hide if dock is shown, is showing, or is partially shown
if (this._dockState == DockState.SHOWN || this._dockState == DockState.SHOWING || this._slider.slidex > 0) {
this._removeAnimations();
// If the dock is shown, wait this._settings.get_double('show-delay') before hiding it;
// otherwise hide it immediately.
let delay = 0;
if (this._dockState == DockState.SHOWN)
delay = this._settings.get_double('hide-delay');
if (Main.overview._shown && Main.overview.viewSelector._activePage == Main.overview.viewSelector._workspacesPage) {
this._animateOut(this._settings.get_double('animation-time'), delay, false);
} else {
this._animateOut(this._settings.get_double('animation-time'), delay, this._autohideStatus);
}
}
}
setPopupMenuFlag(showing) {
this._popupMenuShowing = showing;
if (!showing) {
if (this._isHovering()) {
this._dock.sync_hover();
} else {
this._hide();
}
}
}
// autohide function to animate the show dock process
_animateIn(time, delay, force) {
let sliderVariable = 1;
let fixedPosition = this._settings.get_boolean('dock-fixed')
let overviewAction = this._settings.get_enum('overview-action');
let intellihideAction = this._settings.get_enum('intellihide-action');
let intellihide = this._settings.get_boolean('intellihide')
if (!force && !fixedPosition) {
if ((Main.overview._shown && overviewAction == OverviewAction.SHOW_PARTIAL)
|| (!Main.overview._shown && intellihide && (intellihideAction == IntellihideAction.SHOW_PARTIAL || intellihideAction == IntellihideAction.SHOW_PARTIAL_FIXED))) {
if (this._slider.partialSlideoutSize) {
let fullsize;
if (this._isHorizontal) {
fullsize = this._dock.height;
} else {
fullsize = this._dock.width;
}
if (this._settings.get_boolean('dock-edge-visible')) {
let triggerWidth = 1; // We need trigger width to always be set to 1
let slideoutSize = DOCK_EDGE_VISIBLE_WIDTH - triggerWidth;
sliderVariable = (this._slider.partialSlideoutSize - slideoutSize) / fullsize;
} else {
sliderVariable = this._slider.partialSlideoutSize / fullsize;
}
}
} else {
this._dockState = DockState.SHOWING;
}
} else {
this._dockState = DockState.SHOWING;
}
this._slider.ease_property('slidex', sliderVariable, {
duration: time * 1000,
delay: delay * 1000,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
if (!force && !fixedPosition) {
if ((Main.overview._shown && overviewAction == OverviewAction.SHOW_PARTIAL)
|| (!Main.overview._shown && (intellihideAction == IntellihideAction.SHOW_PARTIAL || intellihideAction == IntellihideAction.SHOW_PARTIAL_FIXED))) {
this._updateBarrier();
} else {
this._dockState = DockState.SHOWN;
// Remove barrier so that mouse pointer is released and can access monitors on other side of dock
// NOTE: Delay needed to keep mouse from moving past dock and re-hiding dock immediately. This
// gives users an opportunity to hover over the dock
if (this._removeBarrierTimeoutId > 0) {
GLib.source_remove(this._removeBarrierTimeoutId);
this._removeBarrierTimeoutId = 0;
}
this._removeBarrierTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 100, this._removeBarrier.bind(this));
this._updateTriggerWidth();
}
} else {
this._dockState = DockState.SHOWN;
// Remove barrier so that mouse pointer is released and can access monitors on other side of dock
// NOTE: Delay needed to keep mouse from moving past dock and re-hiding dock immediately. This
// gives users an opportunity to hover over the dock
if (this._removeBarrierTimeoutId > 0) {
GLib.source_remove(this._removeBarrierTimeoutId);
this._removeBarrierTimeoutId = 0;
}
this._removeBarrierTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 100, this._removeBarrier.bind(this));
this._updateTriggerWidth();
}
// Prevent dock from getting stuck animated in when mouse is no longer hovering
if (this._checkHoverStatusId > 0) {
GLib.source_remove(this._checkHoverStatusId);
this._checkHoverStatusId = 0;
}
this._checkHoverStatusId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 100, this._checkHoverStatus.bind(this));
}
});
}
// autohide function to animate the hide dock process
_animateOut(time, delay, force) {
if (this._popupMenuShowing)
return;
this._dockState = DockState.HIDING;
let sliderVariable = 0;
let fixedPosition = this._settings.get_boolean('dock-fixed')
let overviewAction = this._settings.get_enum('overview-action');
let intellihideAction = this._settings.get_enum('intellihide-action');
let intellihide = this._settings.get_boolean('intellihide')
if (!force && !fixedPosition) {
if ((Main.overview._shown && overviewAction == OverviewAction.SHOW_PARTIAL)
|| (!Main.overview._shown && intellihide && (intellihideAction == IntellihideAction.SHOW_PARTIAL || intellihideAction == IntellihideAction.SHOW_PARTIAL_FIXED))) {
if (this._slider.partialSlideoutSize) {
let fullsize;
if (this._isHorizontal) {
fullsize = this._dock.height;
} else {
fullsize = this._dock.width;
}
if (this._settings.get_boolean('dock-edge-visible')) {
let triggerWidth = 1; // We need trigger width to always be set to 1
let slideoutSize = DOCK_EDGE_VISIBLE_WIDTH - triggerWidth;
sliderVariable = (this._slider.partialSlideoutSize - slideoutSize) / fullsize;
} else {
sliderVariable = this._slider.partialSlideoutSize / fullsize;
}
}
}
}
this._slider.ease_property('slidex', sliderVariable, {
duration: time * 1000,
delay: delay * 1000,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
this._dockState = DockState.HIDDEN;
this._updateBarrier();
}
});
}
// autohide function to remove show-hide animations
_removeAnimations() {
this._slider.remove_all_transitions();
}
// autohide function to fade out opaque background
_fadeOutBackground(time, delay) {
// CSS time is in ms
this._thumbnailsBox.set_style('transition-duration:' + time*1000 + ';' +
'transition-delay:' + delay*1000 + ';' +
'background-color: rgba(0,0,0,0);' +
'border-color:' + this._defaultBorder);
this._shortcutsPanel.actor.set_style('transition-duration:' + time*1000 + ';' +
'transition-delay:' + delay*1000 + ';' +
'background-color: rgba(0,0,0,0);' +
'border-color:' + this._defaultBorder);
this._dockContainer.set_style('transition-duration:' + time*1000 + ';' +
'transition-delay:' + delay*1000 + ';' +
'background-color:' + this._defaultBackground + ';' +
'border-color:' + this._defaultBorder);
}
// autohide function to fade in opaque background
_fadeInBackground(time, delay) {
// CSS time is in ms
this._thumbnailsBox.set_style('transition-duration:' + time*1000 + ';' +
'transition-delay:' + delay*1000 + ';' +
'background-color: rgba(0,0,0,0);' +
'border-color:' + this._customBorder);
this._shortcutsPanel.actor.set_style('transition-duration:' + time*1000 + ';' +
'transition-delay:' + delay*1000 + ';' +
'background-color: rgba(0,0,0,0);' +
'border-color:' + this._customBorder);
this._dockContainer.set_style('transition-duration:' + time*1000 + ';' +
'transition-delay:' + delay*1000 + ';' +
'background-color:' + this._customBackground + ';' +
'border-color:' + this._customBorder);
}
// This function handles hiding the dock when dock is in stationary-fixed
// position but overlapped by gnome panel menus or meta popup windows
fadeOutDock(time, delay) {
if (Main.layoutManager._inOverview) {
// Hide fixed dock when in overviewmode applications view
this.actor.opacity = 0;
}
// Make thumbnail windowclones non-reactive
// NOTE: Need this for when in overviewmode applications view and dock is in fixed mode.
// Fixed dock has opacity set to 0 but is still reactive.
this._dock.reactive = false;
this._shortcutsPanel.setReactiveState(false);
this._thumbnailsBox.reactive = false;
for (let i = 0; i < this._thumbnailsBox._thumbnails.length; i++) {
let thumbnail = this._thumbnailsBox._thumbnails[i];
thumbnail.setCaptionReactiveState(false);
thumbnail.setWindowClonesReactiveState(false);
}
}
// This function handles showing the dock when dock is stationary-fixed
// position but overlapped by gnome panel menus or meta popup windows
fadeInDock(time, delay) {
this.actor.opacity = 255;
// Return thumbnail windowclones to reactive state
this._dock.reactive = true;
this._shortcutsPanel.setReactiveState(true);
this._thumbnailsBox.reactive = true;
for (let i = 0; i < this._thumbnailsBox._thumbnails.length; i++) {
let thumbnail = this._thumbnailsBox._thumbnails[i];
thumbnail.setCaptionReactiveState(true);
thumbnail.setWindowClonesReactiveState(true);
}
// if (!this._workAreaHeight || !this._workAreaWidth) {
// this._refreshThumbnailsOnRegionUpdate = true;
// Main.layoutManager._queueUpdateRegions();
// }
}
// retrieve default background color
_getBackgroundColor() {
// Remove custom style
let oldStyle = this._thumbnailsBox.get_style();
this._thumbnailsBox.set_style(null);
// Prevent shell crash if the actor is not on the stage
// It happens enabling/disabling repeatedly the extension
if (!this._thumbnailsBox.get_stage())
return null;
let themeNode = this._thumbnailsBox.get_theme_node();
this._thumbnailsBox.set_style(oldStyle);
// Just in case the theme has different border colors ..
// We want to find the inside border-color of the dock because it is
// the side most visible to the user. We do this by finding the side
// opposite the position
let side = this._position + 2;
if (side > 3)
side = Math.abs(side - 4);
let backgroundColor = themeNode.get_background_color();
let borderColor = themeNode.get_border_color(side);
return [backgroundColor, borderColor];
}
_updateAppearancePreferences() {
this._updateStraightCorners();
this._updateBackgroundOpacity();
}
_updateStraightCorners() {
if (this._settings.get_boolean('straight-corners')) {
this._dock.add_style_class_name('straight-corners');
} else {
this._dock.remove_style_class_name('straight-corners');
}
}
// update background opacity based on preferences
_updateBackgroundOpacity() {
let [backgroundColor, borderColor] = this._getBackgroundColor();
if (backgroundColor) {
// We check the background alpha for a minimum of .001 to prevent
// division by 0 errors when calculating borderAlpha later
let backgroundAlpha = Math.max(Math.round(backgroundColor.alpha/2.55)/100, .001);
let newAlpha = this._settings.get_double('background-opacity');
this._defaultBackground = "rgba(" + backgroundColor.red + "," + backgroundColor.green + "," + backgroundColor.blue + "," + backgroundAlpha + ")";
this._customBackground = "rgba(" + backgroundColor.red + "," + backgroundColor.green + "," + backgroundColor.blue + "," + newAlpha + ")";
if (borderColor) {
// The border and background alphas should remain in sync
// We also limit the borderAlpha to a maximum of 1 (full opacity)
let borderAlpha = Math.round(borderColor.alpha/2.55)/100;
borderAlpha = Math.min((borderAlpha/backgroundAlpha)*newAlpha, 1);
this._defaultBorder = "rgba(" + borderColor.red + "," + borderColor.green + "," + borderColor.blue + "," + Math.round(borderColor.alpha/2.55)/100 + ")";
this._customBorder = "rgba(" + borderColor.red + "," + borderColor.green + "," + borderColor.blue + "," + borderAlpha + ")";
}
if (this._settings.get_boolean('opaque-background')) {
this._fadeInBackground(this._settings.get_double('animation-time'), 0);
} else {
this._fadeOutBackground(this._settings.get_double('animation-time'), 0);
}
}
}
// handler for theme changes
_onThemeChanged() {
this._changeStylesheet();
if (!this._disableRedisplay)
this._updateAppearancePreferences();
}
// function to change stylesheets
_changeStylesheet() {
// Get css filename
let filename = "workspaces-to-dock.css";
// Get new theme stylesheet
let themeStylesheet = Main._getDefaultStylesheet();
if (Main.getThemeStylesheet())
themeStylesheet = Main.getThemeStylesheet();
// Get theme directory
let themeDirectory = themeStylesheet.get_path() ? GLib.path_get_dirname(themeStylesheet.get_path()) : "";
// Test for workspacesToDock stylesheet
let newStylesheet = null;
if (themeDirectory != "")
newStylesheet = Gio.file_new_for_path(themeDirectory + '/extensions/workspaces-to-dock/' + filename);
if (!newStylesheet || !newStylesheet.query_exists(null)) {
let defaultStylesheet = Gio.File.new_for_path(Me.path + "/themes/default/" + filename);
if (defaultStylesheet.query_exists(null)) {
newStylesheet = defaultStylesheet;
} else {
throw new Error(_("No Workspaces-To-Dock stylesheet found") + " (extension.js).");
}
}
if (Extension.workspacesToDockStylesheet && Extension.workspacesToDockStylesheet.equal(newStylesheet)) {
return false;
}
// Change workspacesToDock stylesheet by updating theme
let themeContext = St.ThemeContext.get_for_stage(global.stage);
if (!themeContext)
return false;
let theme = themeContext.get_theme();
if (!theme)
return false;
let customStylesheets = theme.get_custom_stylesheets();
if (!customStylesheets)
return false;
let previousStylesheet = Extension.workspacesToDockStylesheet;
Extension.workspacesToDockStylesheet = newStylesheet;
// let newTheme = new St.Theme ({ application_stylesheet: themeStylesheet,
// default_stylesheet: Main._defaultCssStylesheet });
let newTheme = new St.Theme ({ application_stylesheet: themeStylesheet });
for (let i = 0; i < customStylesheets.length; i++) {
if (!customStylesheets[i].equal(previousStylesheet)) {
newTheme.load_stylesheet(customStylesheets[i]);
}
}
newTheme.load_stylesheet(Extension.workspacesToDockStylesheet);
themeContext.set_theme (newTheme);
if (!this._disableRedisplay) {
this._refreshThumbnails();
}
return true;
}
// resdiplay dock called if size-position changed due to dock resizing
_redisplay() {
if (this._disableRedisplay)
return
// Initial display of dock .. sets autohideStatus
if (this._autohideStatus == null) {
if (this._settings.get_boolean('dock-fixed')) {
this._autohideStatus = false;
this.fadeInDock(this._settings.get_double('animation-time'), 0);
} else {
// Initial animation is out .. intellihide will animate in if its needed
this._removeAnimations();
this._animateOut(0, 0);
this._autohideStatus = true;
}
} else {
// Redisplay dock by animating back in .. necessary if thumbnailsBox size changed
// even if dock is fixed
if (this._autohideStatus) {
if (!this._isHovering() && !(this._hoveringDash && !Main.overview._shown)) {
this._removeAnimations();
this._animateOut(0, 0, true);
}
this._autohideStatus = true;
} else {
if (!this._isHovering() && !(this._hoveringDash && !Main.overview._shown)) {
// had to comment out because GS3.4 fixed-dock isn't fully faded in yet when redisplay occurs again
//this._removeAnimations();
this._animateIn(this._settings.get_double('animation-time'), 0);
}
this._autohideStatus = false;
}
}
this._updateAppearancePreferences();
this._updateBarrier();
}
// update the dock size and position
_updateSize() {
// Accommodate shortcuts panel in calculations
let shortcutsPanelThickness = 0;
if (this._settings.get_boolean('show-shortcuts-panel')) {
if (this._isHorizontal) {
shortcutsPanelThickness = this._shortcutsPanel.actor.height;
} else {
shortcutsPanelThickness = this._shortcutsPanel.actor.width;
}
}
// Get workspace area
// This takes into account primary monitor and any additional extensions
// that may affect width and height calculations
let workArea = Main.layoutManager.getWorkAreaForMonitor(this._monitor.index);
// get the scale factor
let scale_factor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
// Get screen edge padding from preferences and multiply it by scale_factor for HiDPI monitors
let screenEdgePadding = this._settings.get_double('screen-edge-padding') * scale_factor;
let x, y, width, height, anchorPoint;
if (this._isHorizontal) {
// Get x position and width
if (this._settings.get_boolean('customize-height')) {
let leftMargin = Math.floor(this._settings.get_double('top-margin') * this._monitor.width);
let rightMargin = Math.floor(this._settings.get_double('bottom-margin') * this._monitor.width);
x = workArea.x + leftMargin;
width = workArea.width - leftMargin - rightMargin;
} else {
let margin = this._monitor.width * .1;
x = this._monitor.x + margin;
width = this._monitor.width - (margin * 2);
}
// Get y position, height, and anchorpoint
height = this._thumbnailsBox._thumbnailsBoxHeight + shortcutsPanelThickness + screenEdgePadding;
if (this._position == St.Side.TOP) {
y = this._monitor.y;
anchorPoint = Clutter.Gravity.NORTH_WEST;
} else {
y = this._monitor.y + this._monitor.height;
anchorPoint = Clutter.Gravity.SOUTH_WEST;
}
} else {
// Get x position, width, and anchorpoint
width = this._thumbnailsBox._thumbnailsBoxWidth + shortcutsPanelThickness + screenEdgePadding;
if (this._position == St.Side.LEFT) {
x = this._monitor.x;
anchorPoint = Clutter.Gravity.NORTH_WEST;
} else {
x = this._monitor.x + this._monitor.width;
anchorPoint = Clutter.Gravity.NORTH_EAST;
}
// Get y position and height
if (this._settings.get_boolean('customize-height')) {
let topMargin = Math.floor(this._settings.get_double('top-margin') * this._monitor.height);
let bottomMargin = Math.floor(this._settings.get_double('bottom-margin') * this._monitor.height);
y = workArea.y + topMargin;
height = workArea.height - topMargin - bottomMargin;
} else {
let controlsTop = 45;
y = this._monitor.y + Main.panel.height + controlsTop + Main.overview.searchEntry.height;
height = this._monitor.height - (y + Main.overview.searchEntry.height);
}
}
//// skip updating if size is same ??
//if ((this.actor.y == y) && (this.actor.width == this._thumbnailsBox._thumbnailsBoxWidth + shortcutsPanelThickness) && (this.actor.height == height)) {
//return;
//}
// Update position of main actor (used to detect window overlaps)
this.actor.set_position(x, y);
this._struts.set_position(x, y);
// Update size of the main actor as well as the _dock & _panels inside
// NOTE: Rather than rely on the builtin box layout mechanics, we control
// both width and height based on the thumbnail & shortcuts panels. This
// allows us to control the trigger space for showing/hiding and scrolling
if (this._isHorizontal) {
if (this._settings.get_boolean('customize-height')) {
let [minThumbnailsBoxWidth, minThumbnailsBoxHeight, natThumbnailsBoxWidth, natThumbnailsBoxHeight] = this._thumbnailsBox.get_preferred_size();
let minShortcutsPanelWidth = 0, minShortcutsPanelHeight = 0, natShortcutsPanelWidth = 0, natShortcutsPanelHeight = 0;
if (this._settings.get_boolean('show-shortcuts-panel')) {
[minShortcutsPanelWidth, minShortcutsPanelHeight, natShortcutsPanelWidth, natShortcutsPanelHeight] = this._shortcutsPanel.actor.get_preferred_size();
}
let containerWidth = natThumbnailsBoxWidth > natShortcutsPanelWidth ? natThumbnailsBoxWidth : natShortcutsPanelWidth;
if (containerWidth > width) {
containerWidth = width;
}
this._panelsContainer.set_size(containerWidth, height);
this._panels.set_size(containerWidth, height);
if (this._extendContainer) {
this._dockContainer.set_size(width, height);
this._dock.set_size(width, height + this._triggerWidth);
this.actor.set_size(width, height + this._triggerWidth);
} else {
this._dockContainer.set_size(containerWidth, height);
this._dock.set_size(containerWidth, height + this._triggerWidth);
this.actor.set_size(containerWidth, height + this._triggerWidth);
if (this._centerContainer) {
if (width > containerWidth) {
let xMiddle = x + Math.round((width - containerWidth) / 2);
this.actor.set_position(xMiddle, y);
}
}
}
} else {
this._panelsContainer.set_size(width, height);
this._panels.set_size(width, height);
this._dockContainer.set_size(width, height);
this._dock.set_size(width, height + this._triggerWidth);
this.actor.set_size(width, height + this._triggerWidth);
}
} else {
if (this._settings.get_boolean('customize-height')) {
let [minThumbnailsBoxWidth, minThumbnailsBoxHeight, natThumbnailsBoxWidth, natThumbnailsBoxHeight] = this._thumbnailsBox.get_preferred_size();
let minShortcutsPanelWidth = 0, minShortcutsPanelHeight = 0, natShortcutsPanelWidth = 0, natShortcutsPanelHeight = 0;
if (this._settings.get_boolean('show-shortcuts-panel')) {
[minShortcutsPanelWidth, minShortcutsPanelHeight, natShortcutsPanelWidth, natShortcutsPanelHeight] = this._shortcutsPanel.actor.get_preferred_size();
}
let containerHeight = natThumbnailsBoxHeight > natShortcutsPanelHeight ? natThumbnailsBoxHeight : natShortcutsPanelHeight;
if (containerHeight > height) {
containerHeight = height;
}
this._panelsContainer.set_size(width, containerHeight);
this._panels.set_size(width, containerHeight);
if (this._extendContainer) {
this._dockContainer.set_size(width, height);
this._dock.set_size(width + this._triggerWidth, height);
this.actor.set_size(width + this._triggerWidth, height);
} else {
this._dockContainer.set_size(width, containerHeight);
this._dock.set_size(width + this._triggerWidth, containerHeight);
this.actor.set_size(width + this._triggerWidth, containerHeight);
if (this._centerContainer) {
if (height > containerHeight) {
let yMiddle = y + Math.round((height - containerHeight) / 2);
this.actor.set_position(x, yMiddle);
}
}
}
} else {
this._panelsContainer.set_size(width, height);
this._panels.set_size(width, height);
this._dockContainer.set_size(width, height);
this._dock.set_size(width + this._triggerWidth, height);
this.actor.set_size(width + this._triggerWidth, height);
}
}
// Set anchor points
this.actor.move_anchor_point_from_gravity(anchorPoint);
this._struts.move_anchor_point_from_gravity(anchorPoint);
// Update slider slideout width
let slideoutSize = this._settings.get_boolean('dock-edge-visible') ? this._triggerWidth + DOCK_EDGE_VISIBLE_WIDTH : this._triggerWidth;
this._slider.slideoutSize = slideoutSize;
// Update slider partial width
// NOTE: only effects slider width when dock is set to partially hide in overview
let slidePartialVisibleWidth = this._triggerWidth + DOCK_EDGE_VISIBLE_OVERVIEW_WIDTH;
if (this._settings.get_boolean('show-shortcuts-panel')
&& this._settings.get_enum('shortcuts-panel-orientation') == 1) {
if (this._isHorizontal) {
slidePartialVisibleWidth = this._shortcutsPanel.actor.height;
} else {
slidePartialVisibleWidth = this._shortcutsPanel.actor.width;
}
} else {
// NOTE: Gnome css top panel height is 1.86em
if (this._settings.get_boolean('customize-thumbnail-visible-width')) {
slidePartialVisibleWidth = this._settings.get_double('thumbnail-visible-width');
} else {
let themeVisibleWidth = this._thumbnailsBox.get_theme_node().get_length('visible-width');
if (themeVisibleWidth > 0)
slidePartialVisibleWidth = themeVisibleWidth;
}
}
this._slider.partialSlideoutSize = slidePartialVisibleWidth;
// Set struts size
if (!this._settings.get_boolean('dock-fixed')
&& (this._settings.get_boolean('intellihide') && this._settings.get_enum('intellihide-action') == IntellihideAction.SHOW_PARTIAL_FIXED)) {
if (this._isHorizontal) {
this._struts.set_size(width, slidePartialVisibleWidth);
} else {
this._struts.set_size(slidePartialVisibleWidth, height);
}
} else {
this._struts.set_size(this.actor.width, this.actor.height);
}
}
// 'Hard' reset dock positon: called on start and when monitor changes
_resetPosition() {
this._monitor = this._getMonitor();
this._updateSize();
this._updateAppearancePreferences();
this._updateBarrier();
}
_onMonitorsChanged() {
// Reset the dock position and redisplay
this._resetPosition();
this._redisplay();
// this._refreshThumbnailsOnRegionUpdate = true;
// Main.layoutManager._queueUpdateRegions();
}
_refreshThumbnails() {
let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
this._workAreaWidth = workArea.width;
this._workAreaHeight = workArea.height;
if (this._thumbnailsBox) {
this._thumbnailsBox._destroyThumbnails();
this._thumbnailsBox._createThumbnails();
}
// NOTE: restarting Gnome Shell with the dock height extended leaves the top of the dock hidden
// under the shell's top bar. Resetting the position after a thumbnail refresh (during Region Updates)
// fixes this issue.
this._resetPosition();
}
// Retrieve the preferred monitor
_getMonitor() {
// We are using Gdk in settings prefs which sets the primary monitor to 0
// The shell can assign a different number (Main.layoutManager.primaryMonitor)
// This ensures that the indexing in the settings (Gdk) and in the shell are matched,
// i.e. that we start counting from the primaryMonitorIndex
let preferredMonitorIndex = this._settings.get_int('preferred-monitor');
let monitorIndex = (Main.layoutManager.primaryIndex + preferredMonitorIndex) % Main.layoutManager.monitors.length ;
let monitor = Main.layoutManager.monitors[monitorIndex];
return monitor;
}
// Remove pressure barrier (GS38+ only)
_removeBarrier() {
if (this._barrier) {
if (this._pressureBarrier) {
this._pressureBarrier.removeBarrier(this._barrier);
}
this._barrier.destroy();
this._barrier = null;
}
// Remove barrier timeout
if (this._removeBarrierTimeoutId > 0) {
GLib.source_remove(this._removeBarrierTimeoutId);
this._removeBarrierTimeoutId = 0;
}
return false;
}
// Update pressure barrier size (GS38+ only)
_updateBarrier() {
// Remove existing barrier
this._removeBarrier();
// Manually reset pressure barrier
// This is necessary because we remove the pressure barrier when it is triggered to show the dock
if (this._pressureBarrier) {
this._pressureBarrier._reset();
this._pressureBarrier._isTriggered = false;
}
// Create new barrier
// Note: dock in fixed possition doesn't use pressure barrier
if (this.actor.visible && this._canUsePressure && this._settings.get_boolean('autohide')
&& this._settings.get_boolean('require-pressure-to-show')
&& !this._settings.get_boolean('dock-fixed')) {
let x1, x2, y1, y2, direction;
if(this._position==St.Side.LEFT){
x1 = this._monitor.x;
x2 = this._monitor.x;
y1 = this.actor.y;
y2 = this.actor.y + this.actor.height;
direction = Meta.BarrierDirection.POSITIVE_X;
} else if(this._position==St.Side.RIGHT) {
x1 = this._monitor.x + this._monitor.width;
x2 = this._monitor.x + this._monitor.width;
y1 = this.actor.y;
y2 = this.actor.y + this.actor.height;
direction = Meta.BarrierDirection.NEGATIVE_X;
} else if(this._position==St.Side.TOP) {
let hotCornerPadding = 1;
x1 = this.actor.x + hotCornerPadding;
x2 = this.actor.x + hotCornerPadding + this.actor.width;
y1 = this._monitor.y;
y2 = this._monitor.y;
direction = Meta.BarrierDirection.POSITIVE_Y;
} else if (this._position==St.Side.BOTTOM) {
x1 = this.actor.x;
x2 = this.actor.x + this.actor.width;
y1 = this._monitor.y + this._monitor.height;
y2 = this._monitor.y + this._monitor.height;
direction = Meta.BarrierDirection.NEGATIVE_Y;
}
this._barrier = new Meta.Barrier({display: global.display,
x1: x1, x2: x2,
y1: y1, y2: y2,
directions: direction});
if (this._pressureBarrier) {
this._pressureBarrier.addBarrier(this._barrier);
}
}
// Reset pressureSensed flag
if (!this._isHovering() && this._dockState != DockState.SHOWN) {
this._pressureSensed = false;
this._updateTriggerWidth();
}
}
// Disable autohide effect, thus show workspaces
disableAutoHide(force) {
// NOTE: default functionality is to not force complete animateIn
this._autohideStatus = false;
if (this._dockState == DockState.HIDING || this._dockState == DockState.HIDDEN) {
this._removeAnimations();
if (force) {
this._animateIn(this._settings.get_double('animation-time'), 0, true);
} else {
this._animateIn(this._settings.get_double('animation-time'), 0);
}
}
}
// Enable autohide effect, hide workspaces
enableAutoHide(dontforce) {
// NOTE: default functionality is to force complete animateOut
// autohide status shouldn't change if not completely animating out
if (dontforce) {
this._autohideStatus = false;
} else {
this._autohideStatus = true;
}
if (this._isHovering()) {
this._dock.sync_hover();
}
let delay = 0; // immediately fadein background if hide is blocked by mouseover, otherwise start fadein when dock is already hidden.
if (this._settings.get_boolean('autohide')) {
if (!this._isHovering() && !(this._hoveringDash && !Main.overview._shown)) {
this._removeAnimations();
if (dontforce) {
this._animateOut(this._settings.get_double('animation-time'), 0, false);
} else {
if (Main.overview._shown && Main.overview.viewSelector._activePage == Main.overview.viewSelector._workspacesPage) {
this._animateOut(this._settings.get_double('animation-time'), 0, false);
} else {
this._animateOut(this._settings.get_double('animation-time'), 0, true);
}
}
delay = this._settings.get_double('animation-time');
}
} else {
this._removeAnimations();
if (dontforce) {
this._animateOut(this._settings.get_double('animation-time'), 0, false);
} else {
if (Main.overview._shown && Main.overview.viewSelector._activePage == Main.overview.viewSelector._workspacesPage) {
this._animateOut(this._settings.get_double('animation-time'), 0, false);
} else {
this._animateOut(this._settings.get_double('animation-time'), 0, true);
}
}
delay = this._settings.get_double('animation-time');
}
}
};
Signals.addSignalMethods(DockedWorkspaces.prototype);