Files
dash-to-panel/src/panelManager.js
2025-02-01 17:32:09 -05:00

962 lines
28 KiB
JavaScript
Executable File

/*
* This file is part of the Dash-To-Panel extension for Gnome 3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Credits:
* This file is based on code from the Dash to Dock extension by micheleg
* and code from the Taskbar extension by Zorin OS
*
* Code to re-anchor the panel was taken from Thoma5 BottomPanel:
* https://github.com/Thoma5/gnome-shell-extension-bottompanel
*
* Pattern for moving clock based on Frippery Move Clock by R M Yorston
* http://frippery.org/extensions/
*
* Some code was also adapted from the upstream Gnome Shell source code.
*/
import * as Overview from './overview.js'
import * as Panel from './panel.js'
import * as PanelSettings from './panelSettings.js'
import * as Proximity from './proximity.js'
import * as Utils from './utils.js'
import * as DesktopIconsIntegration from './desktopIconsIntegration.js'
import GLib from 'gi://GLib'
import GObject from 'gi://GObject'
import Clutter from 'gi://Clutter'
import Meta from 'gi://Meta'
import Shell from 'gi://Shell'
import St from 'gi://St'
import * as BoxPointer from 'resource:///org/gnome/shell/ui/boxpointer.js'
import * as LookingGlass from 'resource:///org/gnome/shell/ui/lookingGlass.js'
import * as Main from 'resource:///org/gnome/shell/ui/main.js'
import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js'
import * as Layout from 'resource:///org/gnome/shell/ui/layout.js'
import { InjectionManager } from 'resource:///org/gnome/shell/extensions/extension.js'
import { SETTINGS } from './extension.js'
import {
SecondaryMonitorDisplay,
WorkspacesView,
} from 'resource:///org/gnome/shell/ui/workspacesView.js'
export const PanelManager = class {
constructor() {
this.overview = new Overview.Overview()
this.panelsElementPositions = {}
this._injectionManager = new InjectionManager()
this._saveMonitors()
}
enable(reset) {
let dtpPrimaryIndex = SETTINGS.get_int('primary-monitor')
this.allPanels = []
this.dtpPrimaryMonitor =
Main.layoutManager.monitors[dtpPrimaryIndex] ||
Main.layoutManager.primaryMonitor
this.proximityManager = new Proximity.ProximityManager()
if (this.dtpPrimaryMonitor) {
this.primaryPanel = this._createPanel(
this.dtpPrimaryMonitor,
SETTINGS.get_boolean('stockgs-keep-top-panel'),
)
this.allPanels.push(this.primaryPanel)
this.overview.enable(this.primaryPanel)
this.setFocusedMonitor(this.dtpPrimaryMonitor)
}
if (SETTINGS.get_boolean('multi-monitors')) {
Main.layoutManager.monitors
.filter((m) => m != this.dtpPrimaryMonitor)
.forEach((m) => {
this.allPanels.push(this._createPanel(m, true))
})
}
global.dashToPanel.panels = this.allPanels
global.dashToPanel.emit('panels-created')
this.allPanels.forEach((p) => {
let panelPosition = p.getPosition()
let leftOrRight =
panelPosition == St.Side.LEFT || panelPosition == St.Side.RIGHT
p.panelBox.set_size(
leftOrRight ? -1 : p.geom.w + p.geom.lrPadding,
leftOrRight ? p.geom.h + p.geom.tbPadding : -1,
)
this._findPanelMenuButtons(p.panelBox).forEach((pmb) =>
this._adjustPanelMenuButton(pmb, p.monitor, panelPosition),
)
p.taskbar.iconAnimator.start()
})
this._setDesktopIconsMargins()
//in 3.32, BoxPointer now inherits St.Widget
if (BoxPointer.BoxPointer.prototype.vfunc_get_preferred_height) {
let panelManager = this
this._injectionManager.overrideMethod(
BoxPointer.BoxPointer.prototype,
'vfunc_get_preferred_height',
() =>
function (forWidth) {
let alloc = { min_size: 0, natural_size: 0 }
;[alloc.min_size, alloc.natural_size] =
this.vfunc_get_preferred_height(forWidth)
return panelManager._getBoxPointerPreferredHeight(this, alloc)
},
)
}
this._updatePanelElementPositions()
if (reset) return
this._desktopIconsUsableArea =
new DesktopIconsIntegration.DesktopIconsUsableAreaClass()
this._oldUpdatePanelBarrier = Main.layoutManager._updatePanelBarrier
Main.layoutManager._updatePanelBarrier = (panel) => {
let panelUpdates = panel ? [panel] : this.allPanels
panelUpdates.forEach((p) =>
newUpdatePanelBarrier.call(Main.layoutManager, p),
)
}
Main.layoutManager._updatePanelBarrier()
this._oldUpdateHotCorners = Main.layoutManager._updateHotCorners
Main.layoutManager._updateHotCorners = newUpdateHotCorners.bind(
Main.layoutManager,
)
Main.layoutManager._updateHotCorners()
Main.layoutManager.findIndexForActor = (actor) =>
'_dtpIndex' in actor
? actor._dtpIndex
: Layout.LayoutManager.prototype.findIndexForActor.call(
Main.layoutManager,
actor,
)
this._forceHotCornerId = SETTINGS.connect(
'changed::stockgs-force-hotcorner',
() => Main.layoutManager._updateHotCorners(),
)
if (Main.layoutManager._interfaceSettings) {
this._enableHotCornersId = Main.layoutManager._interfaceSettings.connect(
'changed::enable-hot-corners',
() => Main.layoutManager._updateHotCorners(),
)
}
this._oldUpdateWorkspacesViews =
Main.overview._overview._controls._workspacesDisplay._updateWorkspacesViews
Main.overview._overview._controls._workspacesDisplay._updateWorkspacesViews =
this._newUpdateWorkspacesViews.bind(
Main.overview._overview._controls._workspacesDisplay,
)
this._oldSetPrimaryWorkspaceVisible =
Main.overview._overview._controls._workspacesDisplay.setPrimaryWorkspaceVisible
Main.overview._overview._controls._workspacesDisplay.setPrimaryWorkspaceVisible =
this._newSetPrimaryWorkspaceVisible.bind(
Main.overview._overview._controls._workspacesDisplay,
)
LookingGlass.LookingGlass.prototype._oldResize =
LookingGlass.LookingGlass.prototype._resize
LookingGlass.LookingGlass.prototype._resize = _newLookingGlassResize
LookingGlass.LookingGlass.prototype._oldOpen =
LookingGlass.LookingGlass.prototype.open
LookingGlass.LookingGlass.prototype.open = _newLookingGlassOpen
this._signalsHandler = new Utils.GlobalSignalsHandler()
//listen settings
this._signalsHandler.add(
[
SETTINGS,
[
'changed::primary-monitor',
'changed::multi-monitors',
'changed::isolate-monitors',
'changed::panel-positions',
'changed::panel-lengths',
'changed::panel-anchors',
'changed::stockgs-keep-top-panel',
],
() => this._reset(),
],
[
SETTINGS,
'changed::panel-element-positions',
() => this._updatePanelElementPositions(),
],
[
SETTINGS,
'changed::intellihide-key-toggle-text',
() => this._setKeyBindings(true),
],
[
SETTINGS,
'changed::panel-sizes',
() => {
GLib.idle_add(GLib.PRIORITY_LOW, () => {
this._setDesktopIconsMargins()
return GLib.SOURCE_REMOVE
})
},
],
[
Utils.DisplayWrapper.getMonitorManager(),
'monitors-changed',
() => {
if (Main.layoutManager.primaryMonitor) {
this._saveMonitors()
this._reset()
}
},
],
)
Panel.panelBoxes.forEach((c) =>
this._signalsHandler.add([
Main.panel[c],
'child-added',
(parent, child) => {
this.primaryPanel &&
child instanceof St.Bin &&
this._adjustPanelMenuButton(
this._getPanelMenuButton(child.get_first_child()),
this.primaryPanel.monitor,
this.primaryPanel.getPosition(),
)
},
]),
)
this._setKeyBindings(true)
// keep GS overview.js from blowing away custom panel styles
if (!SETTINGS.get_boolean('stockgs-keep-top-panel'))
Object.defineProperty(Main.panel, 'style', {
configurable: true,
set() {},
})
}
disable(reset) {
this.primaryPanel && this.overview.disable()
this.proximityManager.destroy()
this.allPanels.forEach((p) => {
p.taskbar.iconAnimator.pause()
this._findPanelMenuButtons(p.panelBox).forEach((pmb) => {
if (pmb.menu._boxPointer._dtpGetPreferredHeightId) {
pmb.menu._boxPointer._container.disconnect(
pmb.menu._boxPointer._dtpGetPreferredHeightId,
)
}
pmb.menu._boxPointer.sourceActor = pmb.menu._boxPointer._dtpSourceActor
delete pmb.menu._boxPointer._dtpSourceActor
pmb.menu._boxPointer._userArrowSide = St.Side.TOP
})
this._removePanelBarriers(p)
p.disable()
let clipContainer = p.panelBox.get_parent()
Main.layoutManager._untrackActor(p.panelBox)
Main.layoutManager.removeChrome(clipContainer)
if (p.isStandalone) {
p.panelBox.destroy()
} else {
p.panelBox.remove_child(p)
p.remove_child(p.panel)
p.panelBox.add_child(p.panel)
p.panelBox.set_position(clipContainer.x, clipContainer.y)
clipContainer.remove_child(p.panelBox)
Main.layoutManager.addChrome(p.panelBox, {
affectsStruts: true,
trackFullscreen: true,
})
}
})
this._injectionManager.clear()
if (Main.layoutManager.primaryMonitor) {
Main.layoutManager.panelBox.set_position(
Main.layoutManager.primaryMonitor.x,
Main.layoutManager.primaryMonitor.y,
)
Main.layoutManager.panelBox.set_size(
Main.layoutManager.primaryMonitor.width,
-1,
)
}
if (reset) return
this._setKeyBindings(false)
this._signalsHandler.destroy()
Main.layoutManager._updateHotCorners = this._oldUpdateHotCorners
Main.layoutManager._updateHotCorners()
delete Main.layoutManager.findIndexForActor
SETTINGS.disconnect(this._forceHotCornerId)
if (this._enableHotCornersId) {
Main.layoutManager._interfaceSettings.disconnect(this._enableHotCornersId)
}
Main.layoutManager._updatePanelBarrier = this._oldUpdatePanelBarrier
Main.layoutManager._updatePanelBarrier()
Main.overview._overview._controls._workspacesDisplay._updateWorkspacesViews =
this._oldUpdateWorkspacesViews
Main.overview._overview._controls._workspacesDisplay.setPrimaryWorkspaceVisible =
this._oldSetPrimaryWorkspaceVisible
LookingGlass.LookingGlass.prototype._resize =
LookingGlass.LookingGlass.prototype._oldResize
delete LookingGlass.LookingGlass.prototype._oldResize
LookingGlass.LookingGlass.prototype.open =
LookingGlass.LookingGlass.prototype._oldOpen
delete LookingGlass.LookingGlass.prototype._oldOpen
delete Main.panel.style
this._desktopIconsUsableArea.destroy()
this._desktopIconsUsableArea = null
}
_setDesktopIconsMargins() {
this._desktopIconsUsableArea?.resetMargins()
this.allPanels.forEach((p) => {
switch (p.geom.position) {
case St.Side.TOP:
this._desktopIconsUsableArea?.setMargins(
p.monitor.index,
p.geom.h,
0,
0,
0,
)
break
case St.Side.BOTTOM:
this._desktopIconsUsableArea?.setMargins(
p.monitor.index,
0,
p.geom.h,
0,
0,
)
break
case St.Side.LEFT:
this._desktopIconsUsableArea?.setMargins(
p.monitor.index,
0,
0,
p.geom.w,
0,
)
break
case St.Side.RIGHT:
this._desktopIconsUsableArea?.setMargins(
p.monitor.index,
0,
0,
0,
p.geom.w,
)
break
}
})
}
setFocusedMonitor(monitor) {
this.focusedMonitorPanel = this.allPanels.find((p) => p.monitor == monitor)
if (!this.checkIfFocusedMonitor(monitor)) {
Main.overview._overview.clear_constraints()
Main.overview._overview.add_constraint(
new Layout.MonitorConstraint({ index: monitor.index }),
)
Main.overview._overview._controls._workspacesDisplay._primaryIndex =
monitor.index
// https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2395
// The overview allocation used to calculate its workarea based on the monitor where the overview
// was displayed, but it got changed back to always use the primary monitor. So now, temporarily assign
// the primary monitor to dtp focused monitor while recalculating the overview workarea
Main.layoutManager.primaryMonitor = monitor
Main.overview._overview._controls.layout_manager._updateWorkAreaBox()
Main.layoutManager.primaryMonitor =
Main.layoutManager.monitors[Main.layoutManager.primaryIndex]
}
}
_newSetPrimaryWorkspaceVisible(visible) {
if (this._primaryVisible === visible) return
this._primaryVisible = visible
const primaryIndex =
Main.overview._overview._controls._workspacesDisplay._primaryIndex
const primaryWorkspace = this._workspacesViews[primaryIndex]
if (primaryWorkspace) primaryWorkspace.visible = visible
}
_newUpdateWorkspacesViews() {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].destroy()
this._workspacesViews = []
let monitors = Main.layoutManager.monitors
for (let i = 0; i < monitors.length; i++) {
let view
if (i === this._primaryIndex) {
view = new WorkspacesView(
i,
this._controls,
this._scrollAdjustment,
this._fitModeAdjustment,
this._overviewAdjustment,
)
view.visible = this._primaryVisible
this.bind_property(
'opacity',
view,
'opacity',
GObject.BindingFlags.SYNC_CREATE,
)
this.add_child(view)
} else {
// No idea why atm, but we need the import at the top of this file and to use the
// full imports ns here, otherwise SecondaryMonitorDisplay can't be used ¯\_(ツ)_/¯
view = new SecondaryMonitorDisplay(
i,
this._controls,
this._scrollAdjustment,
this._fitModeAdjustment,
this._overviewAdjustment,
)
Main.layoutManager.overviewGroup.add_child(view)
}
this._workspacesViews.push(view)
}
}
_saveMonitors() {
//Mutter meta_monitor_manager_get_primary_monitor (global.display.get_primary_monitor()) doesn't return the same
//monitor as GDK gdk_screen_get_primary_monitor (imports.gi.Gdk.Screen.get_default().get_primary_monitor()).
//Since the Mutter function is what's used in gnome-shell and we can't access it from the settings dialog, store
//the monitors information in a setting so we can use the same monitor indexes as the ones in gnome-shell
let keyMonitors = 'available-monitors'
let keyPrimary = 'primary-monitor'
let primaryIndex = Main.layoutManager.primaryIndex
let newMonitors = [primaryIndex]
let savedMonitors = SETTINGS.get_value(keyMonitors).deep_unpack()
let dtpPrimaryIndex = SETTINGS.get_int(keyPrimary)
let newDtpPrimaryIndex = primaryIndex
Main.layoutManager.monitors
.filter((m) => m.index != primaryIndex)
.forEach((m) => newMonitors.push(m.index))
if (savedMonitors[0] != dtpPrimaryIndex) {
// dash to panel primary wasn't the gnome-shell primary (first index of available-monitors)
let savedIndex = savedMonitors.indexOf(dtpPrimaryIndex)
// default to primary if it was set to a monitor that is no longer available
newDtpPrimaryIndex = newMonitors[savedIndex]
newDtpPrimaryIndex =
newDtpPrimaryIndex == null ? primaryIndex : newDtpPrimaryIndex
}
SETTINGS.set_int(keyPrimary, newDtpPrimaryIndex)
SETTINGS.set_value(keyMonitors, new GLib.Variant('ai', newMonitors))
}
checkIfFocusedMonitor(monitor) {
return (
Main.overview._overview._controls._workspacesDisplay._primaryIndex ==
monitor.index
)
}
_createPanel(monitor, isStandalone) {
let panelBox
let panel
let clipContainer = new Clutter.Actor()
if (isStandalone) {
panelBox = new Utils.createBoxLayout({ name: 'panelBox' })
} else {
panelBox = Main.layoutManager.panelBox
Main.layoutManager._untrackActor(panelBox)
panelBox.remove_child(Main.panel)
Main.layoutManager.removeChrome(panelBox)
}
Main.layoutManager.addChrome(clipContainer, { affectsInputRegion: false })
clipContainer.add_child(panelBox)
Main.layoutManager.trackChrome(panelBox, {
trackFullscreen: true,
affectsStruts: true,
affectsInputRegion: true,
})
panel = new Panel.Panel(this, monitor, panelBox, isStandalone)
panelBox.add_child(panel)
panel.enable()
panelBox._dtpIndex = monitor.index
panelBox.set_position(0, 0)
return panel
}
_reset() {
this.disable(true)
this.allPanels = []
this.enable(true)
}
_updatePanelElementPositions() {
this.panelsElementPositions = PanelSettings.getSettingsJson(
SETTINGS,
'panel-element-positions',
)
this.allPanels.forEach((p) => p.updateElementPositions())
}
_adjustPanelMenuButton(button, monitor, arrowSide) {
if (button) {
button.menu._boxPointer._dtpSourceActor =
button.menu._boxPointer.sourceActor
button.menu._boxPointer.sourceActor = button
button.menu._boxPointer._userArrowSide = arrowSide
button.menu._boxPointer._dtpInPanel = 1
if (!button.menu._boxPointer.vfunc_get_preferred_height) {
button.menu._boxPointer._dtpGetPreferredHeightId =
button.menu._boxPointer._container.connect(
'get-preferred-height',
(actor, forWidth, alloc) => {
this._getBoxPointerPreferredHeight(
button.menu._boxPointer,
alloc,
monitor,
)
},
)
}
}
}
_getBoxPointerPreferredHeight(boxPointer, alloc, monitor) {
if (
boxPointer._dtpInPanel &&
boxPointer.sourceActor &&
SETTINGS.get_boolean('intellihide')
) {
monitor =
monitor ||
Main.layoutManager.findMonitorForActor(boxPointer.sourceActor)
let panel = Utils.find(
global.dashToPanel.panels,
(p) => p.monitor == monitor,
)
let excess = alloc.natural_size + panel.dtpSize + 10 - monitor.height // 10 is arbitrary
if (excess > 0) {
alloc.natural_size -= excess
}
}
return [alloc.min_size, alloc.natural_size]
}
_findPanelMenuButtons(container) {
let panelMenuButtons = []
let panelMenuButton
let find = (parent) =>
parent.get_children().forEach((c) => {
if ((panelMenuButton = this._getPanelMenuButton(c))) {
panelMenuButtons.push(panelMenuButton)
}
find(c)
})
find(container)
return panelMenuButtons
}
_removePanelBarriers(panel) {
if (panel.isStandalone && panel._rightPanelBarrier) {
panel._rightPanelBarrier.destroy()
}
if (panel._leftPanelBarrier) {
panel._leftPanelBarrier.destroy()
delete panel._leftPanelBarrier
}
}
_getPanelMenuButton(obj) {
return obj instanceof PanelMenu.Button && obj.menu?._boxPointer ? obj : 0
}
_setKeyBindings(enable) {
let keys = {
'intellihide-key-toggle': () =>
this.allPanels.forEach((p) => p.intellihide.toggle()),
}
Object.keys(keys).forEach((k) => {
Utils.removeKeybinding(k)
if (enable) {
Utils.addKeybinding(k, SETTINGS, keys[k], Shell.ActionMode.NORMAL)
}
})
}
}
// This class drives long-running icon animations, to keep them running in sync
// with each other.
export const IconAnimator = class {
constructor(actor) {
this._count = 0
this._started = false
this._animations = {
dance: [],
}
this._timeline = new Clutter.Timeline({
duration: 3000,
repeat_count: -1,
})
/* Just use the construction property when no need to support 3.36 */
if (this._timeline.set_actor) this._timeline.set_actor(actor)
this._timeline.connect('new-frame', () => {
const progress = this._timeline.get_progress()
const danceRotation =
progress < 1 / 6 ? 15 * Math.sin(progress * 24 * Math.PI) : 0
const dancers = this._animations.dance
for (let i = 0, iMax = dancers.length; i < iMax; i++) {
dancers[i].target.rotation_angle_z = danceRotation
}
})
}
destroy() {
this._timeline.stop()
this._timeline = null
for (let name in this._animations) {
const pairs = this._animations[name]
for (let i = 0, iMax = pairs.length; i < iMax; i++) {
const pair = pairs[i]
pair.target.disconnect(pair.targetDestroyId)
}
}
this._animations = null
}
pause() {
if (this._started && this._count > 0) {
this._timeline.stop()
}
this._started = false
}
start() {
if (!this._started && this._count > 0) {
this._timeline.start()
}
this._started = true
}
addAnimation(target, name) {
const targetDestroyId = target.connect('destroy', () =>
this.removeAnimation(target, name),
)
this._animations[name].push({
target: target,
targetDestroyId: targetDestroyId,
})
if (this._started && this._count === 0) {
this._timeline.start()
}
this._count++
}
removeAnimation(target, name) {
const pairs = this._animations[name]
for (let i = 0, iMax = pairs.length; i < iMax; i++) {
const pair = pairs[i]
if (pair.target === target) {
target.disconnect(pair.targetDestroyId)
pairs.splice(i, 1)
this._count--
if (this._started && this._count === 0) {
this._timeline.stop()
}
return
}
}
}
}
function newUpdateHotCorners() {
// destroy old hot corners
this.hotCorners.forEach(function (corner) {
if (corner) corner.destroy()
})
this.hotCorners = []
//global.settings is ubuntu specific setting to disable the hot corner (Tweak tool > Top Bar > Activities Overview Hot Corner)
//this._interfaceSettings is for the setting to disable the hot corner introduced in gnome-shell 3.34
if (
(global.settings.list_keys().indexOf('enable-hot-corners') >= 0 &&
!global.settings.get_boolean('enable-hot-corners')) ||
(this._interfaceSettings &&
!this._interfaceSettings.get_boolean('enable-hot-corners'))
) {
this.emit('hot-corners-changed')
return
}
// build new hot corners
for (let i = 0; i < this.monitors.length; i++) {
let panel = Utils.find(
global.dashToPanel.panels,
(p) => p.monitor.index == i,
)
let panelPosition = panel ? panel.getPosition() : St.Side.BOTTOM
let panelTopLeft =
panelPosition == St.Side.TOP || panelPosition == St.Side.LEFT
let monitor = this.monitors[i]
let cornerX = this._rtl ? monitor.x + monitor.width : monitor.x
let cornerY = monitor.y
let haveTopLeftCorner = true
// If the panel is on the bottom, unless this is explicitly forced, don't add a topleft
// hot corner unless it is actually a top left panel. Otherwise, it stops the mouse
// as you are dragging across. In the future, maybe we will automatically move the
// hotcorner to the bottom when the panel is positioned at the bottom
if (
i != this.primaryIndex ||
(!panelTopLeft && !SETTINGS.get_boolean('stockgs-force-hotcorner'))
) {
// Check if we have a top left (right for RTL) corner.
// I.e. if there is no monitor directly above or to the left(right)
let besideX = this._rtl ? monitor.x + 1 : cornerX - 1
let besideY = cornerY
let aboveX = cornerX
let aboveY = cornerY - 1
for (let j = 0; j < this.monitors.length; j++) {
if (i == j) continue
let otherMonitor = this.monitors[j]
if (
besideX >= otherMonitor.x &&
besideX < otherMonitor.x + otherMonitor.width &&
besideY >= otherMonitor.y &&
besideY < otherMonitor.y + otherMonitor.height
) {
haveTopLeftCorner = false
break
}
if (
aboveX >= otherMonitor.x &&
aboveX < otherMonitor.x + otherMonitor.width &&
aboveY >= otherMonitor.y &&
aboveY < otherMonitor.y + otherMonitor.height
) {
haveTopLeftCorner = false
break
}
}
}
if (haveTopLeftCorner) {
let corner = new Layout.HotCorner(this, monitor, cornerX, cornerY)
corner.setBarrierSize = (size) =>
Object.getPrototypeOf(corner).setBarrierSize.call(
corner,
Math.min(size, 32),
)
corner.setBarrierSize(panel ? panel.dtpSize : 32)
this.hotCorners.push(corner)
} else {
this.hotCorners.push(null)
}
}
this.emit('hot-corners-changed')
}
function newUpdatePanelBarrier(panel) {
let barriers = {
_rightPanelBarrier: [panel.isStandalone ? panel : this],
_leftPanelBarrier: [panel],
}
Object.keys(barriers).forEach((k) => {
let obj = barriers[k][0]
if (obj[k]) {
obj[k].destroy()
obj[k] = null
}
})
if (!this.primaryMonitor || !panel.panelBox.height) {
return
}
let barrierSize = Math.min(10, panel.panelBox.height)
let fixed1 = panel.monitor.y
let fixed2 = panel.monitor.y + barrierSize
if (panel.checkIfVertical()) {
barriers._rightPanelBarrier.push(
panel.monitor.y + panel.monitor.height,
Meta.BarrierDirection.NEGATIVE_Y,
)
barriers._leftPanelBarrier.push(
panel.monitor.y,
Meta.BarrierDirection.POSITIVE_Y,
)
} else {
barriers._rightPanelBarrier.push(
panel.monitor.x + panel.monitor.width,
Meta.BarrierDirection.NEGATIVE_X,
)
barriers._leftPanelBarrier.push(
panel.monitor.x,
Meta.BarrierDirection.POSITIVE_X,
)
}
switch (panel.getPosition()) {
//values are initialized as St.Side.TOP
case St.Side.BOTTOM:
fixed1 = panel.monitor.y + panel.monitor.height - barrierSize
fixed2 = panel.monitor.y + panel.monitor.height
break
case St.Side.LEFT:
fixed1 = panel.monitor.x + barrierSize
fixed2 = panel.monitor.x
break
case St.Side.RIGHT:
fixed1 = panel.monitor.x + panel.monitor.width - barrierSize
fixed2 = panel.monitor.x + panel.monitor.width
break
}
//remove left barrier if it overlaps one of the hotcorners
for (let k in this.hotCorners) {
let hc = this.hotCorners[k]
if (
hc &&
hc._monitor == panel.monitor &&
(fixed1 == hc._x || fixed2 == hc._x || fixed1 == hc._y || fixed2 == hc._y)
) {
delete barriers._leftPanelBarrier
break
}
}
Object.keys(barriers).forEach((k) => {
let barrierOptions = {
backend: global.backend,
directions: barriers[k][2],
}
barrierOptions[panel.varCoord.c1] = barrierOptions[panel.varCoord.c2] =
barriers[k][1]
barrierOptions[panel.fixedCoord.c1] = fixed1
barrierOptions[panel.fixedCoord.c2] = fixed2
barriers[k][0][k] = new Meta.Barrier(barrierOptions)
})
}
function _newLookingGlassResize() {
let primaryMonitorPanel = Utils.find(
global.dashToPanel.panels,
(p) => p.monitor == Main.layoutManager.primaryMonitor,
)
let topOffset =
primaryMonitorPanel.getPosition() == St.Side.TOP
? primaryMonitorPanel.dtpSize + 8
: 32
this._oldResize()
this._hiddenY = Main.layoutManager.primaryMonitor.y + topOffset - this.height
this._targetY = this._hiddenY + this.height
this.y = this._hiddenY
this._objInspector.set_position(
this.x + Math.floor(this.width * 0.1),
this._targetY + Math.floor(this.height * 0.1),
)
}
function _newLookingGlassOpen() {
if (this._open) return
this._resize()
this._oldOpen()
}