gnome-shell-extension-dash-.../gnome-shell-extension-just-perfection/usr/share/gnome-shell/extensions/just-perfection-desktop@just-perfection/lib/API.js
Ward from fusion-voyager-3 306bdcf078 add files
2024-08-27 21:32:05 +03:00

3227 lines
84 KiB
JavaScript
Executable File

/**
* API Library
*
* @author Javad Rahmatzadeh <j.rahmatzadeh@gmail.com>
* @copyright 2020-2024
* @license GPL-3.0-only
*/
const XY_POSITION = {
TOP_START: 0,
TOP_CENTER: 1,
TOP_END: 2,
BOTTOM_START: 3,
BOTTOM_CENTER: 4,
BOTTOM_END: 5,
CENTER_START: 6,
CENTER_CENTER: 7,
CENTER_END: 8,
};
const PANEL_POSITION = {
TOP: 0,
BOTTOM: 1,
};
const PANEL_BOX_POSITION = {
CENTER: 0,
RIGHT: 1,
LEFT: 2,
};
const PANEL_HIDE_MODE = {
ALL: 0,
DESKTOP: 1,
};
const SHELL_STATUS = {
NONE: 0,
OVERVIEW: 1,
};
const DASH_ICON_SIZES = [16, 22, 24, 32, 40, 48, 56, 64];
/**
* API to avoid calling GNOME Shell directly
* and make all parts compatible with different GNOME Shell versions
*/
export class API
{
/**
* Current shell version
*
* @type {number|null}
*/
#shellVersion = null;
/**
* Originals holder
*
* @type {object}
*/
#originals = {};
/**
* Timeout ids
*
* @type {object}
*/
#timeoutIds = {};
/**
* Class Constructor
*
* @param {Object} dependencies
* 'Main' reference to ui::main
* 'BackgroundMenu' reference to ui::backgroundMenu
* 'OverviewControls' reference to ui::overviewControls
* 'WorkspaceSwitcherPopup' reference to ui::workspaceSwitcherPopup
* 'SwitcherPopup' reference to ui::switcherPopup
* 'InterfaceSettings' reference to Gio::Settings for 'org.gnome.desktop.interface'
* 'Search' reference to ui::search
* 'SearchController' reference to ui::searchController
* 'WorkspaceThumbnail' reference to ui::workspaceThumbnail
* 'WorkspacesView' reference to ui::workspacesView
* 'Panel' reference to ui::panel
* 'PanelMenu' reference to ui::panelMenu
* 'WindowPreview' reference to ui::windowPreview
* 'Workspace' reference to ui::workspace
* 'LookingGlass' reference to ui::lookingGlass
* 'MessageTray' reference to ui::messageTray
* 'OSDWindow' reference to ui::osdTray
* 'WindowMenu' reference to ui::windowMenu
* 'AltTab' reference to ui::altTab
* 'St' reference to St
* 'GLib' reference to GLib
* 'Clutter' reference to Clutter
* 'Util' reference to misc::util
* 'Meta' reference to Meta
* 'GObject' reference to GObject
* @param {number} shellVersion float in major.minor format
*/
constructor(dependencies, shellVersion)
{
this._main = dependencies['Main'] || null;
this._backgroundMenu = dependencies['BackgroundMenu'] || null;
this._overviewControls = dependencies['OverviewControls'] || null;
this._workspaceSwitcherPopup = dependencies['WorkspaceSwitcherPopup'] || null;
this._switcherPopup = dependencies['SwitcherPopup'] || null;
this._interfaceSettings = dependencies['InterfaceSettings'] || null;
this._search = dependencies['Search'] || null;
this._searchController = dependencies['SearchController'] || null;
this._workspaceThumbnail = dependencies['WorkspaceThumbnail'] || null;
this._workspacesView = dependencies['WorkspacesView'] || null;
this._panel = dependencies['Panel'] || null;
this._panelMenu = dependencies['PanelMenu'] || null;
this._windowPreview = dependencies['WindowPreview'] || null;
this._workspace = dependencies['Workspace'] || null;
this._lookingGlass = dependencies['LookingGlass'] || null;
this._messageTray = dependencies['MessageTray'] || null;
this._osdWindow = dependencies['OSDWindow'] || null;
this._windowMenu = dependencies['WindowMenu'] || null;
this._altTab = dependencies['AltTab'] || null;
this._st = dependencies['St'] || null;
this._glib = dependencies['GLib'] || null;
this._clutter = dependencies['Clutter'] || null;
this._util = dependencies['Util'] || null;
this._meta = dependencies['Meta'] || null;
this._gobject = dependencies['GObject'] || null;
this.#shellVersion = shellVersion;
/**
* whether search entry is visible
*
* @member {boolean}
*/
this._searchEntryVisibility = true;
}
/**
* prepare everything needed for API
*
* @returns {void}
*/
open()
{
this.UIStyleClassAdd(this.#getAPIClassname('shell-version'));
}
/**
* remove everything from GNOME Shell been added by this class
*
* @returns {void}
*/
close()
{
this.UIStyleClassRemove(this.#getAPIClassname('shell-version'));
this.#startSearchSignal(false);
this.#computeWorkspacesBoxForStateSetDefault();
this.#altTabSizesSetDefault();
for (let [name, id] of Object.entries(this.#timeoutIds)) {
this._glib.source_remove(id);
delete(this.#timeoutIds[name]);
}
}
/**
* get x and y align for position
*
* @param int pos position
* see XY_POSITION
*
* @returns {array}
* - 0 Clutter.ActorAlign
* - 1 Clutter.ActorAlign
*/
#xyAlignGet(pos)
{
if (XY_POSITION.TOP_START === pos) {
return [this._clutter.ActorAlign.START, this._clutter.ActorAlign.START];
}
if (XY_POSITION.TOP_CENTER === pos) {
return [this._clutter.ActorAlign.CENTER, this._clutter.ActorAlign.START];
}
if (XY_POSITION.TOP_END === pos) {
return [this._clutter.ActorAlign.END, this._clutter.ActorAlign.START];
}
if (XY_POSITION.CENTER_START === pos) {
return [this._clutter.ActorAlign.START, this._clutter.ActorAlign.CENTER];
}
if (XY_POSITION.CENTER_CENTER === pos) {
return [this._clutter.ActorAlign.CENTER, this._clutter.ActorAlign.CENTER];
}
if (XY_POSITION.CENTER_END === pos) {
return [this._clutter.ActorAlign.END, this._clutter.ActorAlign.CENTER];
}
if (XY_POSITION.BOTTOM_START === pos) {
return [this._clutter.ActorAlign.START, this._clutter.ActorAlign.END];
}
if (XY_POSITION.BOTTOM_CENTER === pos) {
return [this._clutter.ActorAlign.CENTER, this._clutter.ActorAlign.END];
}
if (XY_POSITION.BOTTOM_END === pos) {
return [this._clutter.ActorAlign.END, this._clutter.ActorAlign.END];
}
}
/**
* add to animation duration
*
* @param {number} duration in milliseconds
*
* @returns {number}
*/
#addToAnimationDuration(duration)
{
let settings = this._st.Settings.get();
return (settings.enable_animations) ? settings.slow_down_factor * duration : 1;
}
/**
* get signal id of the event
*
* @param {Gtk.Widget} widget to find signal in
* @param {string} signalName signal name
*
* @returns {number}
*/
#getSignalId(widget, signalName)
{
return this._gobject.signal_handler_find(widget, {signalId: signalName});
}
/**
* get the css class name for API
*
* @param {string} type
*
* @returns {string}
*/
#getAPIClassname(type)
{
let starter = 'just-perfection-api-';
if (type === 'shell-version') {
let shellVerMajor = Math.trunc(this.#shellVersion);
return `${starter}gnome${shellVerMajor}`;
}
return `${starter}${type}`;
}
/**
* set panel size to default
*
* @returns {void}
*/
panelSetDefaultSize()
{
if (!this.#originals['panelHeight']) {
return;
}
this.panelSetSize(this.#originals['panelHeight'], false);
}
/**
* change panel size
*
* @param {number} size 0 to 100
* @param {boolean} fake true means it shouldn't change the last size,
* false otherwise
*
* @returns {void}
*/
panelSetSize(size, fake)
{
if (!this.#originals['panelHeight']) {
this.#originals['panelHeight'] = this._main.panel.height;
}
if (size > 100 || size < 0) {
return;
}
this._main.panel.height = size;
if (!fake) {
this._panelSize = size;
}
}
/**
* get the last size of the panel
*
* @returns {number}
*/
panelGetSize()
{
if (this._panelSize !== undefined) {
return this._panelSize;
}
if (this.#originals['panelHeight']) {
return this.#originals['panelHeight'];
}
return this._main.panel.height;
}
/**
* emit refresh styles
* this is useful when changed style doesn't emit change because doesn't have
* standard styles. for example, style with only `-natural-hpadding`
* won't notify any change. so you need to call this function
* to refresh that
*
* @returns {void}
*/
#emitRefreshStyles()
{
let classname = this.#getAPIClassname('refresh-styles');
this.UIStyleClassAdd(classname);
this.UIStyleClassRemove(classname);
}
/**
* show panel
*
* @returns {void}
*/
panelShow()
{
this._panelVisibility = true;
let classname = this.#getAPIClassname('no-panel');
if (!this.UIStyleClassContain(classname)) {
return;
}
// The class name should be removed before addChrome the panelBox
// removing after can cause `st_theme_node_lookup_shadow` crash
this.UIStyleClassRemove(classname);
let overview = this._main.overview;
let searchEntryParent = overview.searchEntry.get_parent();
let panelBox = this._main.layoutManager.panelBox;
panelBox.translation_y = 0;
this._main.layoutManager.overviewGroup.remove_child(panelBox);
this._main.layoutManager.addChrome(panelBox, {
affectsStruts: true,
trackFullscreen: true,
});
if (this._hidePanelWorkareasChangedSignal) {
global.display.disconnect(this._hidePanelWorkareasChangedSignal);
delete(this._hidePanelWorkareasChangedSignal);
}
if (this._hidePanelHeightSignal) {
panelBox.disconnect(this._hidePanelHeightSignal);
delete(this._hidePanelHeightSignal);
}
searchEntryParent.set_style(`margin-top: 0;`);
// hide and show can fix windows going under panel
panelBox.hide();
panelBox.show();
this.#fixLookingGlassPosition();
if (this.#timeoutIds.panelHide) {
this._glib.source_remove(this.#timeoutIds.panelHide);
delete(this.#timeoutIds.panelHide);
}
}
/**
* hide panel
*
* @param {mode} hide mode see PANEL_HIDE_MODE. defaults to hide all
* @param {boolean} force apply hide even if it is hidden
*
* @returns {void}
*/
panelHide(mode)
{
this._panelVisibility = false;
this._panelHideMode = mode;
let overview = this._main.overview;
let searchEntryParent = overview.searchEntry.get_parent();
let panelBox = this._main.layoutManager.panelBox;
let panelHeight = this._main.panel.height;
let panelPosition = this.panelGetPosition();
let direction = (panelPosition === PANEL_POSITION.BOTTOM) ? 1 : -1;
if (panelBox.get_parent() === this._main.layoutManager.uiGroup) {
this._main.layoutManager.removeChrome(panelBox);
this._main.layoutManager.overviewGroup.insert_child_at_index(panelBox, 0);
}
panelBox.translation_y = (mode === PANEL_HIDE_MODE.DESKTOP) ? 0 : panelHeight * direction;
if (panelPosition === PANEL_POSITION.TOP) {
// when panel is hidden the first element gets too close to the top,
// so we fix it with top margin in search entry
let marginTop = (mode === PANEL_HIDE_MODE.ALL) ? 15 : panelHeight;
searchEntryParent.set_style(`margin-top: ${marginTop}px;`);
} else {
searchEntryParent.set_style(`margin-top: 0;`);
}
// hide and show can fix windows going under panel
panelBox.hide();
panelBox.show();
this.#fixLookingGlassPosition();
if (this._hidePanelWorkareasChangedSignal) {
global.display.disconnect(this._hidePanelWorkareasChangedSignal);
delete(this._hidePanelWorkareasChangedSignal);
}
this._hidePanelWorkareasChangedSignal = global.display.connect(
'workareas-changed',
() => {
this.panelHide(this._panelHideMode);
}
);
if (!this._hidePanelHeightSignal) {
this._hidePanelHeightSignal = panelBox.connect(
'notify::height',
() => {
this.panelHide(this._panelHideMode);
}
);
}
let classname = this.#getAPIClassname('no-panel');
this.UIStyleClassAdd(classname);
// update hot corners since we need to make them available
// outside overview
this._main.layoutManager._updateHotCorners();
// Maximized windows will have bad maximized gap after unlock in Wayland
// This is a Mutter issue,
// See https://gitlab.gnome.org/GNOME/mutter/-/issues/1627
// TODO remove after the issue is fixed on Mutter
if (this._meta.is_wayland_compositor()) {
let duration = this.#addToAnimationDuration(180);
this.#timeoutIds.panelHide = this._glib.timeout_add(
this._glib.PRIORITY_DEFAULT,
duration,
() => {
panelBox.hide();
panelBox.show();
return this._glib.SOURCE_REMOVE;
}
);
}
}
/**
* check whether panel is visible
*
* @returns {boolean}
*/
isPanelVisible()
{
if (this._panelVisibility === undefined) {
return true;
}
return this._panelVisibility;
}
/**
* check whether dash is visible
*
* @returns {boolean}
*/
isDashVisible()
{
return this._dashVisibility === undefined || this._dashVisibility;
}
/**
* show dash
*
* @returns {void}
*/
dashShow()
{
if (!this._main.overview.dash || this.isDashVisible()) {
return;
}
this._dashVisibility = true;
this._main.overview.dash.show();
this._main.overview.dash.height = -1;
this._main.overview.dash.setMaxSize(-1, -1);
this.#updateWindowPreviewOverlap();
}
/**
* hide dash
*
* @returns {void}
*/
dashHide()
{
if (!this._main.overview.dash || !this.isDashVisible()) {
return;
}
this._dashVisibility = false;
this._main.overview.dash.hide();
this._main.overview.dash.height = 0;
this.#updateWindowPreviewOverlap();
}
/**
* update window preview overlap
*
* @returns {void}
*/
#updateWindowPreviewOverlap()
{
let wpp = this._windowPreview.WindowPreview.prototype;
if (this.isDashVisible() && wpp.overlapHeightsOld) {
wpp.overlapHeights = wpp.overlapHeightsOld;
delete(wpp.overlapHeightsOld);
return;
}
if (!this.isDashVisible()) {
wpp.overlapHeightsOld = wpp.overlapHeights;
wpp.overlapHeights = function () {
let [top, bottom] = this.overlapHeightsOld();
return [top + 24, bottom + 24];
};
}
}
/**
* add class name to the UI group
*
* @param {string} classname class name
*
* @returns {void}
*/
UIStyleClassAdd(classname)
{
this._main.layoutManager.uiGroup.add_style_class_name(classname);
}
/**
* remove class name from UI group
*
* @param {string} classname class name
*
* @returns {void}
*/
UIStyleClassRemove(classname)
{
this._main.layoutManager.uiGroup.remove_style_class_name(classname);
}
/**
* check whether UI group has class name
*
* @param {string} classname class name
*
* @returns {boolean}
*/
UIStyleClassContain(classname)
{
return this._main.layoutManager.uiGroup.has_style_class_name(classname);
}
/**
* enable background menu
*
* @returns {void}
*/
backgroundMenuEnable()
{
if (!this.#originals['backgroundMenuOpen']) {
return;
}
this._backgroundMenu.BackgroundMenu.prototype.open = this.#originals['backgroundMenuOpen'];
}
/**
* disable background menu
*
* @returns {void}
*/
backgroundMenuDisable()
{
let backgroundMenuProto = this._backgroundMenu.BackgroundMenu.prototype;
if (!this.#originals['backgroundMenuOpen']) {
this.#originals['backgroundMenuOpen'] = backgroundMenuProto.open;
}
backgroundMenuProto.open = () => {};
}
/**
* show search
*
* @param {boolean} fake true means it just needs to do the job but
* don't need to change the search visibility status
*
* @returns {void}
*/
searchEntryShow(fake)
{
let classname = this.#getAPIClassname('no-search');
if (!this.UIStyleClassContain(classname)) {
return;
}
this.UIStyleClassRemove(classname);
let searchEntry = this._main.overview.searchEntry;
let searchEntryParent = searchEntry.get_parent();
searchEntryParent.ease({
height: searchEntry.height,
opacity: 255,
mode: this._clutter.AnimationMode.EASE,
duration: 110,
onComplete: () => {
searchEntryParent.height = -1;
searchEntry.ease({
opacity: 255,
mode: this._clutter.AnimationMode.EASE,
duration: 700,
});
},
});
if (!fake) {
this._searchEntryVisibility = true;
}
this.#computeWorkspacesBoxForStateChanged();
}
/**
* hide search
*
* @param {boolean} fake true means it just needs to do the job
* but don't need to change the search visibility status
*
* @returns {void}
*/
searchEntryHide(fake)
{
this.UIStyleClassAdd(this.#getAPIClassname('no-search'));
let searchEntry = this._main.overview.searchEntry;
let searchEntryParent = searchEntry.get_parent();
searchEntry.ease({
opacity: 0,
mode: this._clutter.AnimationMode.EASE,
duration: 50,
});
searchEntryParent.ease({
height: 0,
opacity: 0,
mode: this._clutter.AnimationMode.EASE,
duration: 120,
});
if (!fake) {
this._searchEntryVisibility = false;
}
this.#computeWorkspacesBoxForStateChanged();
}
/**
* enable start search
*
* @returns {void}
*/
startSearchEnable()
{
this.#startSearchSignal(true);
if (!this.#originals['startSearch']) {
return;
}
this._searchController.SearchController.prototype.startSearch = this.#originals['startSearch'];
}
/**
* disable start search
*
* @returns {void}
*/
startSearchDisable()
{
this.#startSearchSignal(false);
if (!this.#originals['startSearch']) {
this.#originals['startSearch'] = this._searchController.SearchController.prototype.startSearch
}
this._searchController.SearchController.prototype.startSearch = () => {};
}
/**
* add search signals that needs to be show search entry when the
* search entry is hidden
*
* @param {boolean} add true means add the signal, false means remove
* the signal
*
* @returns {void}
*/
#startSearchSignal(add)
{
let controller
= this._main.overview.viewSelector ||
this._main.overview._overview.viewSelector ||
this._main.overview._overview.controls._searchController;
// remove
if (!add) {
if (this._searchActiveSignal) {
controller.disconnect(this._searchActiveSignal);
this._searchActiveSignal = null;
}
return;
}
// add
if (this._searchActiveSignal) {
return;
}
this._searchActiveSignal = controller.connect('notify::search-active', () => {
if (this._searchEntryVisibility) {
return;
}
let inSearch = controller.searchActive;
if (inSearch) {
this.UIStyleClassAdd(this.#getAPIClassname('type-to-search'));
this.searchEntryShow(true);
} else {
this.UIStyleClassRemove(this.#getAPIClassname('type-to-search'));
this.searchEntryHide(true);
}
});
}
/**
* Set maximum displayed search result to default value
*
* @returns {void}
*/
setMaxDisplayedSearchResultToDefault()
{
if (!this.#originals['searchGetMaxDisplayedResults']) {
return;
}
let ListSearchResultsProto = this._search.ListSearchResults.prototype;
ListSearchResultsProto._getMaxDisplayedResults = this.#originals['searchGetMaxDisplayedResults'];
}
/**
* Set maximum displayed search result
*
* @param {number} items max items
*
* @returns {void}
*/
setMaxDisplayedSearchResult(items)
{
let ListSearchResultsProto = this._search.ListSearchResults.prototype;
if (!this.#originals['searchGetMaxDisplayedResults']) {
this.#originals['searchGetMaxDisplayedResults'] = ListSearchResultsProto._getMaxDisplayedResults;
}
ListSearchResultsProto._getMaxDisplayedResults = () => {
return items;
}
}
/**
* enable OSD
*
* @returns {void}
*/
OSDEnable()
{
if (!this.#originals['osdWindowManagerShow']) {
return;
}
this._main.osdWindowManager.show = this.#originals['osdWindowManagerShow'];
}
/**
* disable OSD
*
* @returns {void}
*/
OSDDisable()
{
if (!this.#originals['osdWindowManagerShow']) {
this.#originals['osdWindowManagerShow']
= this._main.osdWindowManager.show;
}
this._main.osdWindowManager.show = () => {};
}
/**
* enable workspace popup
*
* @returns {void}
*/
workspacePopupEnable()
{
if (!this.#originals['workspaceSwitcherPopupDisplay']) {
return;
}
this._workspaceSwitcherPopup.WorkspaceSwitcherPopup.prototype.display
= this.#originals['workspaceSwitcherPopupDisplay']
}
/**
* disable workspace popup
*
* @returns {void}
*/
workspacePopupDisable()
{
if (!this.#originals['workspaceSwitcherPopupDisplay']) {
this.#originals['workspaceSwitcherPopupDisplay']
= this._workspaceSwitcherPopup.WorkspaceSwitcherPopup.prototype.display;
}
this._workspaceSwitcherPopup.WorkspaceSwitcherPopup.prototype.display = function (index) {
this.destroy();
};
}
/**
* show workspace switcher
*
* @returns {void}
*/
workspaceSwitcherShow()
{
this.UIStyleClassRemove(this.#getAPIClassname('no-workspace'));
this.#workspaceSwitcherShouldShowSetToLast();
}
/**
* hide workspace switcher
*
* @returns {void}
*/
workspaceSwitcherHide()
{
this.workspaceSwitcherShouldShow(false, true);
// should be after `this.workspaceSwitcherShouldShow()`
// since it checks whether it's visible or not
this.UIStyleClassAdd(this.#getAPIClassname('no-workspace'));
}
/**
* check whether workspace switcher is visible
*
* @returns {boolean}
*/
isWorkspaceSwitcherVisible()
{
return !this.UIStyleClassContain(this.#getAPIClassname('no-workspace'));
}
/**
* set workspace switcher to its default size
*
* @returns {void}
*/
workspaceSwitcherSetDefaultSize()
{
let thumbnailsBox = this._main.overview._overview._controls._thumbnailsBox;
let ThumbnailsBoxProto = this._workspaceThumbnail.ThumbnailsBox.prototype;
if (!ThumbnailsBoxProto._initOld) {
return;
}
ThumbnailsBoxProto._init = ThumbnailsBoxProto._initOld;
delete(ThumbnailsBoxProto._initOld);
thumbnailsBox._maxThumbnailScale = this._workspaceThumbnail.MAX_THUMBNAIL_SCALE;
}
/**
* set workspace switcher size
*
* @param {number} size in float
*
* @returns {void}
*/
workspaceSwitcherSetSize(size)
{
let thumbnailsBox = this._main.overview._overview._controls._thumbnailsBox;
let ThumbnailsBoxProto = this._workspaceThumbnail.ThumbnailsBox.prototype;
thumbnailsBox._maxThumbnailScale = size;
if (!ThumbnailsBoxProto._initOld) {
ThumbnailsBoxProto._initOld = ThumbnailsBoxProto._init;
}
ThumbnailsBoxProto._init = function(...params) {
this._maxThumbnailScale = size;
this._initOld(...params);
};
}
/**
* add element to stage
*
* @param {St.Widget} element widget
*
* @returns {void}
*/
chromeAdd(element)
{
this._main.layoutManager.addChrome(element, {
affectsInputRegion : true,
affectsStruts : false,
trackFullscreen : true,
});
}
/**
* remove element from stage
*
* @param {St.Widget} element widget
*
* @returns {void}
*/
chromeRemove(element)
{
this._main.layoutManager.removeChrome(element);
}
/**
* show activities button
*
* @returns {void}
*/
activitiesButtonShow()
{
let activities = this._main.panel.statusArea.activities;
if (!this.isLocked() && activities) {
activities.container.show();
}
}
/**
* hide activities button
*
* @returns {void}
*/
activitiesButtonHide()
{
let activities = this._main.panel.statusArea.activities;
if (activities) {
activities.container.hide();
}
}
/**
* show date menu
*
* @returns {void}
*/
dateMenuShow()
{
if (!this.isLocked()) {
this._main.panel.statusArea.dateMenu.container.show();
}
}
/**
* hide date menu
*
* @returns {void}
*/
dateMenuHide()
{
this._main.panel.statusArea.dateMenu.container.hide();
}
/**
* show keyboard layout
*
* @returns {void}
*/
keyboardLayoutShow()
{
this._main.panel.statusArea.keyboard.container.show();
}
/**
* hide keyboard layout
*
* @returns {void}
*/
keyboardLayoutHide()
{
this._main.panel.statusArea.keyboard.container.hide();
}
/**
* show accessibility menu
*
* @returns {void}
*/
accessibilityMenuShow()
{
this._main.panel.statusArea.a11y?.container.show();
}
/**
* hide accessibility menu
*
* @returns {void}
*/
accessibilityMenuHide()
{
this._main.panel.statusArea.a11y?.container.hide();
}
/**
* show quick settings menu
*
* @returns {void}
*/
quickSettingsMenuShow()
{
this._main.panel.statusArea.quickSettings.container.show();
}
/**
* hide quick settings menu
*
* @returns {void}
*/
quickSettingsMenuHide()
{
this._main.panel.statusArea.quickSettings.container.hide();
}
/**
* check whether lock dialog is currently showing
*
* @returns {boolean}
*/
isLocked()
{
return this._main.sessionMode.isLocked;
}
/**
* enable window picker icon
*
* @returns {void}
*/
windowPickerIconEnable()
{
this.UIStyleClassRemove(this.#getAPIClassname('no-window-picker-icon'));
}
/**
* disable window picker icon
*
* @returns {void}
*/
windowPickerIconDisable()
{
this.UIStyleClassAdd(this.#getAPIClassname('no-window-picker-icon'));
}
/**
* show power icon
*
* @returns {void}
*/
powerIconShow()
{
this.UIStyleClassRemove(this.#getAPIClassname('no-power-icon'));
}
/**
* hide power icon
*
* @returns {void}
*/
powerIconHide()
{
this.UIStyleClassAdd(this.#getAPIClassname('no-power-icon'));
}
/**
* get primary monitor information
*
* @returns {false|Object} false when monitor does not exist | object
* x: int
* y: int
* width: int
* height: int
* geometryScale: float
*/
monitorGetInfo()
{
let pMonitor = this._main.layoutManager.primaryMonitor;
if (!pMonitor) {
return false;
}
return {
'x': pMonitor.x,
'y': pMonitor.y,
'width': pMonitor.width,
'height': pMonitor.height,
'geometryScale': pMonitor.geometry_scale,
};
}
/**
* get panel position
*
* @returns {number} see PANEL_POSITION
*/
panelGetPosition()
{
if (this._panelPosition === undefined) {
return PANEL_POSITION.TOP;
}
return this._panelPosition;
}
/**
* move panel position
*
* @param {number} position see PANEL_POSITION
* @param {boolean} force allow to set even when the current position
* is the same
*
* @returns {void}
*/
panelSetPosition(position, force = false)
{
let monitorInfo = this.monitorGetInfo();
let panelBox = this._main.layoutManager.panelBox;
if (!force && position === this.panelGetPosition()) {
return;
}
if (position === PANEL_POSITION.TOP) {
this._panelPosition = PANEL_POSITION.TOP;
if (this._workareasChangedSignal) {
global.display.disconnect(this._workareasChangedSignal);
this._workareasChangedSignal = null;
}
if (this._panelHeightSignal) {
panelBox.disconnect(this._panelHeightSignal);
this._panelHeightSignal = null;
}
let topX = (monitorInfo) ? monitorInfo.x : 0;
let topY = (monitorInfo) ? monitorInfo.y : 0;
panelBox.set_position(topX, topY);
this.UIStyleClassRemove(this.#getAPIClassname('bottom-panel'));
this.#fixPanelMenuSide(this._st.Side.TOP);
this.#fixLookingGlassPosition();
return;
}
this._panelPosition = PANEL_POSITION.BOTTOM;
// only change it when a monitor detected
// 'workareas-changed' signal will do the job on next monitor detection
if (monitorInfo) {
let BottomX = monitorInfo.x;
let BottomY = monitorInfo.y + monitorInfo.height - this.panelGetSize();
panelBox.set_position(BottomX, BottomY);
this.UIStyleClassAdd(this.#getAPIClassname('bottom-panel'));
}
if (!this._workareasChangedSignal) {
this._workareasChangedSignal
= global.display.connect('workareas-changed', () => {
this.panelSetPosition(PANEL_POSITION.BOTTOM, true);
});
}
if (!this._panelHeightSignal) {
this._panelHeightSignal = panelBox.connect('notify::height', () => {
this.panelSetPosition(PANEL_POSITION.BOTTOM, true);
});
}
this.#fixPanelMenuSide(this._st.Side.BOTTOM);
this.#fixLookingGlassPosition();
}
/**
* fix panel menu opening side based on panel position
*
* @param {number} position St.Side value
* is the same
*
* @returns {void}
*/
#fixPanelMenuSide(position)
{
let PanelMenuButton = this._panelMenu.Button;
let PanelMenuButtonProto = PanelMenuButton.prototype;
// Set Instances
let findPanelMenus = (widget) => {
if (widget instanceof PanelMenuButton && widget.menu?._boxPointer) {
widget.menu._boxPointer._userArrowSide = position;
}
widget.get_children().forEach(subWidget => {
findPanelMenus(subWidget)
});
}
let panelBoxes = [
this._main.panel._centerBox,
this._main.panel._rightBox,
this._main.panel._leftBox,
];
panelBoxes.forEach(panelBox => findPanelMenus(panelBox));
// Set Prototypes
if (position === this._st.Side.TOP) {
// reset to default since GNOME Shell panel is top by default
if (PanelMenuButtonProto._setMenuOld) {
PanelMenuButtonProto.setMenu = PanelMenuButtonProto._setMenuOld;
}
return;
}
if (!PanelMenuButtonProto._setMenuOld) {
PanelMenuButtonProto._setMenuOld = PanelMenuButtonProto.setMenu;
}
PanelMenuButtonProto.setMenu = function (menu) {
this._setMenuOld(menu);
if (menu) {
menu._boxPointer._userArrowSide = position;
}
}
}
/**
* fix looking glass position
*
* @returns {void}
*/
#fixLookingGlassPosition()
{
let lookingGlassProto = this._lookingGlass.LookingGlass.prototype;
if (this.#originals['lookingGlassResize'] === undefined) {
this.#originals['lookingGlassResize'] = lookingGlassProto._resize;
}
if (this.panelGetPosition() === PANEL_POSITION.TOP && this.isPanelVisible()) {
lookingGlassProto._resize = this.#originals['lookingGlassResize'];
delete(lookingGlassProto._oldResizeMethod);
delete(this.#originals['lookingGlassResize']);
return;
}
if (lookingGlassProto._oldResizeMethod === undefined) {
lookingGlassProto._oldResizeMethod = this.#originals['lookingGlassResize'];
const Main = this._main;
lookingGlassProto._resize = function () {
let panelHeight = Main.layoutManager.panelBox.height;
this._oldResizeMethod();
this._targetY -= panelHeight;
this._hiddenY -= panelHeight;
};
}
}
/**
* enable panel notification icon
*
* @returns {void}
*/
panelNotificationIconEnable()
{
this.UIStyleClassRemove(this.#getAPIClassname('no-panel-notification-icon'));
}
/**
* disable panel notification icon
*
* @returns {void}
*/
panelNotificationIconDisable()
{
this.UIStyleClassAdd(this.#getAPIClassname('no-panel-notification-icon'));
}
/**
* disconnect all clock menu position signals
*
* @returns {void}
*/
#disconnectClockMenuPositionSignals()
{
let panelBoxes = [
this._main.panel._centerBox,
this._main.panel._rightBox,
this._main.panel._leftBox,
];
if (this._clockMenuPositionSignals) {
for (let i = 0; i <= 2; i++) {
panelBoxes[i].disconnect(this._clockMenuPositionSignals[i]);
}
delete(this._clockMenuPositionSignals);
}
}
/**
* set the clock menu position to default
*
* @returns {void}
*/
clockMenuPositionSetDefault()
{
this.clockMenuPositionSet(0, 0);
this.#disconnectClockMenuPositionSignals();
}
/**
* set the clock menu position
*
* @param {number} pos see PANEL_BOX_POSITION
* @param {number} offset starts from 0
*
* @returns {void}
*/
clockMenuPositionSet(pos, offset)
{
let dateMenu = this._main.panel.statusArea.dateMenu;
let panelBoxes = [
this._main.panel._centerBox,
this._main.panel._rightBox,
this._main.panel._leftBox,
];
this.#disconnectClockMenuPositionSignals();
let fromPos = -1;
let fromIndex = -1;
let toIndex = -1;
let childLength = 0;
for (let i = 0; i <= 2; i++) {
let child = panelBoxes[i].get_children();
let childIndex = child.indexOf(dateMenu.container);
if (childIndex !== -1) {
fromPos = i;
fromIndex = childIndex;
childLength = panelBoxes[pos].get_children().length;
toIndex = (offset > childLength) ? childLength : offset;
break;
}
}
// couldn't find the from and to position because it has been removed
if (fromPos === -1 || fromIndex === -1 || toIndex === -1) {
return;
}
if (pos === fromPos && toIndex === fromIndex) {
return;
}
panelBoxes[fromPos].remove_child(dateMenu.container);
panelBoxes[pos].insert_child_at_index(dateMenu.container, toIndex);
if (this.isLocked()) {
this.dateMenuHide();
}
if (!this._clockMenuPositionSignals) {
this._clockMenuPositionSignals = [null, null, null];
for (let i = 0; i <= 2; i++) {
this._clockMenuPositionSignals[i] = panelBoxes[i].connect(
(this.#shellVersion >= 46) ? 'child-added' : 'actor-added',
() => {
this.clockMenuPositionSet(pos, offset);
}
);
}
}
}
/**
* enable show apps button
*
* @returns {void}
*/
showAppsButtonEnable()
{
this.UIStyleClassRemove(this.#getAPIClassname('no-show-apps-button'));
}
/**
* disable show apps button
*
* @returns {void}
*/
showAppsButtonDisable()
{
this.UIStyleClassAdd(this.#getAPIClassname('no-show-apps-button'));
}
/**
* set animation speed as default
*
* @returns {void}
*/
animationSpeedSetDefault()
{
if (this.#originals['StSlowDownFactor'] === undefined) {
return;
}
this._st.Settings.get().slow_down_factor = this.#originals['StSlowDownFactor'];
}
/**
* change animation speed
*
* @param {number} factor in float. bigger number means slower
*
* @returns {void}
*/
animationSpeedSet(factor)
{
if (this.#originals['StSlowDownFactor'] === undefined) {
this.#originals['StSlowDownFactor']
= this._st.Settings.get().slow_down_factor;
}
this._st.Settings.get().slow_down_factor = factor;
}
/**
* set the enable animation as default
*
* @returns {void}
*/
enableAnimationsSetDefault()
{
if (this.#originals['enableAnimations'] === undefined) {
return;
}
let status = this.#originals['enableAnimations'];
this._interfaceSettings.set_boolean('enable-animations', status);
}
/**
* set the enable animation status
*
* @param {boolean} status true to enable, false otherwise
*
* @returns {void}
*/
enableAnimationsSet(status)
{
if (this.#originals['enableAnimations'] === undefined) {
this.#originals['enableAnimations']
= this._interfaceSettings.get_boolean('enable-animations');
}
this._interfaceSettings.set_boolean('enable-animations', status);
}
/**
* enable focus when window demands attention happens
*
* @returns {void}
*/
windowDemandsAttentionFocusEnable()
{
if (
this._displayWindowDemandsAttentionSignal ||
this._displayWindowMarkedUrgentSignal
) {
return;
}
let display = global.display;
let demandFunction = (display, window) => {
if (!window || window.has_focus() || window.is_skip_taskbar()) {
return;
}
this._main.activateWindow(window);
};
this._displayWindowDemandsAttentionSignal
= display.connect('window-demands-attention', demandFunction);
this._displayWindowMarkedUrgentSignal
= display.connect('window-marked-urgent', demandFunction);
// since removing '_windowDemandsAttentionId' doesn't have any effect
// we remove the original signal and re-connect it on disable
let signalId = this.#getSignalId(global.display, 'window-demands-attention');
let signalId2 = this.#getSignalId(global.display, 'window-marked-urgent');
display.disconnect(signalId);
display.disconnect(signalId2);
}
/**
* disable focus when window demands attention happens
*
* @returns {void}
*/
windowDemandsAttentionFocusDisable()
{
if (
!this._displayWindowDemandsAttentionSignal ||
!this._displayWindowMarkedUrgentSignal
) {
return;
}
let display = global.display;
display.disconnect(this._displayWindowDemandsAttentionSignal);
display.disconnect(this._displayWindowMarkedUrgentSignal);
this._displayWindowDemandsAttentionSignal = null;
this._displayWindowMarkedUrgentSignal = null;
let wah = this._main.windowAttentionHandler;
wah._windowDemandsAttentionId = display.connect(
'window-demands-attention',
wah._onWindowDemandsAttention.bind(wah)
);
wah._windowDemandsAttentionId = display.connect(
'window-marked-urgent',
wah._onWindowDemandsAttention.bind(wah)
);
}
/**
* enable maximizing windows on creation
*
* @returns {void}
*/
windowMaximizedOnCreateEnable()
{
if (this._displayWindowCreatedSignal) {
return;
}
let display = global.display;
let createdFunction = (display, window) => {
if (window.can_maximize()) {
window.maximize(this._meta.MaximizeFlags.HORIZONTAL | this._meta.MaximizeFlags.VERTICAL);
}
};
this._displayWindowCreatedSignal = display.connect('window-created', createdFunction);
}
/**
* disable maximizing windows on creation
*
* @returns {void}
*/
windowMaximizedOnCreateDisable()
{
if (!this._displayWindowCreatedSignal) {
return;
}
let display = global.display;
display.disconnect(this._displayWindowCreatedSignal);
delete(this._displayWindowCreatedSignal);
}
/**
* set startup status
*
* @param {number} status see SHELL_STATUS for available status
*
* @returns {void}
*/
startupStatusSet(status)
{
let sessionMode = this._main.sessionMode;
let layoutManager = this._main.layoutManager;
if (!layoutManager._startingUp) {
return;
}
if (this.#originals['sessionModeHasOverview'] === undefined) {
this.#originals['sessionModeHasOverview'] = sessionMode.hasOverview;
}
let ControlsState = this._overviewControls.ControlsState;
let Controls = this._main.overview._overview.controls;
switch (status) {
case SHELL_STATUS.NONE:
sessionMode.hasOverview = false;
layoutManager.startInOverview = false;
Controls._stateAdjustment.value = ControlsState.HIDDEN;
break;
case SHELL_STATUS.OVERVIEW:
default:
sessionMode.hasOverview = true;
layoutManager.startInOverview = true;
break;
}
if (!this._startupCompleteSignal) {
this._startupCompleteSignal
= layoutManager.connect('startup-complete', () => {
sessionMode.hasOverview = this.#originals['sessionModeHasOverview'];
});
}
}
/**
* set startup status to default
*
* @returns {void}
*/
startupStatusSetDefault()
{
if (this.#originals['sessionModeHasOverview'] === undefined) {
return;
}
if (this._startupCompleteSignal) {
this._main.layoutManager.disconnect(this._startupCompleteSignal);
}
}
/**
* set dash icon size to default
*
* @returns {void}
*/
dashIconSizeSetDefault()
{
let classnameStarter = this.#getAPIClassname('dash-icon-size');
DASH_ICON_SIZES.forEach(size => {
this.UIStyleClassRemove(classnameStarter + size);
});
}
/**
* set dash icon size
*
* @param {number} size in pixels
* see DASH_ICON_SIZES for available sizes
*
* @returns {void}
*/
dashIconSizeSet(size)
{
this.dashIconSizeSetDefault();
if (!DASH_ICON_SIZES.includes(size)) {
return;
}
let classnameStarter = this.#getAPIClassname('dash-icon-size');
this.UIStyleClassAdd(classnameStarter + size);
}
/**
* change ControlsManagerLayout._computeWorkspacesBoxForState
* base on the current state
*
* @returns {void}
*/
#computeWorkspacesBoxForStateChanged()
{
let controlsLayout = this._main.overview._overview._controls.layout_manager;
if (!this.#originals['computeWorkspacesBoxForState']) {
this.#originals['computeWorkspacesBoxForState']
= controlsLayout._computeWorkspacesBoxForState;
}
controlsLayout._computeWorkspacesBoxForState = (state, box, searchHeight, ...args) => {
let inAppGrid = state === this._overviewControls.ControlsState.APP_GRID;
if (inAppGrid && !this._searchEntryVisibility) {
// We need some spacing on top of workspace box in app grid
// when the search entry is not visible.
searchHeight = 40;
}
box = this.#originals['computeWorkspacesBoxForState'].call(
controlsLayout, state, box, searchHeight, ...args);
if (inAppGrid && this._workspacesInAppGridHeight !== undefined) {
box.set_size(
box.get_width(),
this._workspacesInAppGridHeight
);
}
return box;
};
// Since workspace background has shadow around it, it can cause
// unwanted shadows in app grid when the workspace height is 0.
// so we are removing the shadow when we are in app grid
if (!this._appButtonForComputeWorkspacesSignal) {
this._appButtonForComputeWorkspacesSignal =
this._main.overview.dash.showAppsButton.connect(
'notify::checked',
() => {
let checked = this._main.overview.dash.showAppsButton.checked;
let classname = this.#getAPIClassname('no-workspaces-in-app-grid');
if (checked) {
this.UIStyleClassAdd(classname);
} else {
this.UIStyleClassRemove(classname);
}
}
);
}
}
/**
* change ControlsManagerLayout._computeWorkspacesBoxForState to its default
*
* @returns {void}
*/
#computeWorkspacesBoxForStateSetDefault()
{
if (!this.#originals['computeWorkspacesBoxForState']) {
return;
}
let controlsLayout = this._main.overview._overview._controls.layout_manager;
controlsLayout._computeWorkspacesBoxForState
= this.#originals['computeWorkspacesBoxForState'];
if (this._appButtonForComputeWorkspacesSignal) {
let showAppsButton = this._main.overview.dash.showAppsButton;
showAppsButton.disconnect(this._appButtonForComputeWorkspacesSignal);
delete(this._appButtonForComputeWorkspacesSignal);
this.UIStyleClassRemove(this.#getAPIClassname('no-workspaces-in-app-grid'));
}
}
/**
* disable workspaces in app grid
*
* @returns {void}
*/
workspacesInAppGridDisable()
{
this._workspacesInAppGridHeight = 0;
this.#computeWorkspacesBoxForStateChanged();
}
/**
* enable workspaces in app grid
*
* @returns {void}
*/
workspacesInAppGridEnable()
{
if (this._workspacesInAppGridHeight === undefined) {
return;
}
delete(this._workspacesInAppGridHeight);
this.#computeWorkspacesBoxForStateChanged();
}
/**
* change notification banner position
*
* @param {number} pos
* see XY_POSITION for available positions
*
* @returns {void}
*/
notificationBannerPositionSet(pos)
{
let messageTray = this._main.messageTray;
let bannerBin = messageTray._bannerBin;
if (this.#originals['bannerAlignmentX'] === undefined) {
this.#originals['bannerAlignmentX'] = messageTray.bannerAlignment;
}
if (this.#originals['bannerAlignmentY'] === undefined) {
this.#originals['bannerAlignmentY'] = bannerBin.get_y_align();
}
if (this.#originals['hideNotification'] === undefined) {
this.#originals['hideNotification'] = messageTray._hideNotification;
}
// TOP
messageTray._hideNotification = this.#originals['hideNotification'];
bannerBin.set_y_align(this._clutter.ActorAlign.START);
if (pos === XY_POSITION.TOP_START) {
messageTray.bannerAlignment = this._clutter.ActorAlign.START;
return;
}
if (pos === XY_POSITION.TOP_END) {
messageTray.bannerAlignment = this._clutter.ActorAlign.END;
return;
}
if (pos === XY_POSITION.TOP_CENTER) {
messageTray.bannerAlignment = this._clutter.ActorAlign.CENTER;
return;
}
// BOTTOM
// >>
// This block is going to fix the animation when the notification is
// in bottom area
// this is the same function from (ui.messageTray.messageTray._hideNotification)
// with clutter animation mode set to EASE.
// because the EASE_OUT_BACK (original code) causes glitch when
// the tray is on bottom
const State = this._messageTray.State;
const ANIMATION_TIME = this._messageTray.ANIMATION_TIME;
const Clutter = this._clutter;
messageTray._hideNotification = function (animate) {
this._notificationFocusGrabber.ungrabFocus();
this._banner.disconnectObject(this);
this._resetNotificationLeftTimeout();
this._bannerBin.remove_all_transitions();
if (animate) {
this._notificationState = State.HIDING;
this._bannerBin.ease({
opacity: 0,
duration: ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE,
});
this._bannerBin.ease({
opacity: 0,
y: this._bannerBin.height,
duration: ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE,
onComplete: () => {
this._notificationState = State.HIDDEN;
this._hideNotificationCompleted();
this._updateState();
},
});
} else {
this._bannerBin.y = this._bannerBin.height;
this._bannerBin.opacity = 0;
this._notificationState = State.HIDDEN;
this._hideNotificationCompleted();
}
}
// <<
bannerBin.set_y_align(this._clutter.ActorAlign.END);
if (pos === XY_POSITION.BOTTOM_START) {
messageTray.bannerAlignment = this._clutter.ActorAlign.START;
return;
}
if (pos === XY_POSITION.BOTTOM_END) {
messageTray.bannerAlignment = this._clutter.ActorAlign.END;
return;
}
if (pos === XY_POSITION.BOTTOM_CENTER) {
messageTray.bannerAlignment = this._clutter.ActorAlign.CENTER;
return;
}
}
/**
* set notification banner position to default position
*
* @returns {void}
*/
notificationBannerPositionSetDefault()
{
if (this.#originals['bannerAlignmentX'] === undefined ||
this.#originals['bannerAlignmentY'] === undefined ||
this.#originals['hideNotification'] === undefined
) {
return;
}
let messageTray = this._main.messageTray;
let bannerBin = messageTray._bannerBin;
messageTray.bannerAlignment = this.#originals['bannerAlignmentX'];
bannerBin.set_y_align(this.#originals['bannerAlignmentY']);
messageTray._hideNotification = this.#originals['hideNotification'];
}
/**
* set the workspace switcher to always/never show
*
* @param {boolean} show true for always show, false for never show
* @param {boolean} fake true means set the current should show status
*
* @returns {void}
*/
workspaceSwitcherShouldShow(shouldShow = true, fake = false)
{
if (!fake) {
this._shouldShow = shouldShow;
}
if (!this.isWorkspaceSwitcherVisible()) {
return;
}
let ThumbnailsBoxProto = this._workspaceThumbnail.ThumbnailsBox.prototype;
if (!this.#originals['updateShouldShow']) {
this.#originals['updateShouldShow'] = ThumbnailsBoxProto._updateShouldShow;
}
ThumbnailsBoxProto._updateShouldShow = function () {
if (this._shouldShow === shouldShow) {
return;
}
this._shouldShow = shouldShow;
this.notify('should-show');
};
}
/**
* set the always show workspace switcher status to last real status
*
* @returns {void}
*/
#workspaceSwitcherShouldShowSetToLast()
{
if (this._shouldShow === undefined) {
this.workspaceSwitcherShouldShowSetDefault();
return;
}
this.workspaceSwitcherShouldShow(this._shouldShow);
}
/**
* set the always show workspace switcher status to default
*
* @returns {void}
*/
workspaceSwitcherShouldShowSetDefault()
{
if (!this.#originals['updateShouldShow'] || !this.isWorkspaceSwitcherVisible()) {
return;
}
let ThumbnailsBoxProto = this._workspaceThumbnail.ThumbnailsBox.prototype;
ThumbnailsBoxProto._updateShouldShow = this.#originals['updateShouldShow'];
delete(this.#originals['updateShouldShow']);
delete(this._shouldShow);
}
/**
* set panel button hpadding to default
*
* @returns {void}
*/
panelButtonHpaddingSetDefault()
{
if (this._panelButtonHpaddingSize === undefined) {
return;
}
let classnameStarter = this.#getAPIClassname('panel-button-padding-size');
this.UIStyleClassRemove(classnameStarter + this._panelButtonHpaddingSize);
this.#emitRefreshStyles();
delete this._panelButtonHpaddingSize;
}
/**
* set panel button hpadding size
*
* @param {number} size in pixels (0 - 60)
*
* @returns {void}
*/
panelButtonHpaddingSizeSet(size)
{
this.panelButtonHpaddingSetDefault();
if (size < 0 || size > 60) {
return;
}
this._panelButtonHpaddingSize = size;
let classnameStarter = this.#getAPIClassname('panel-button-padding-size');
this.UIStyleClassAdd(classnameStarter + size);
this.#emitRefreshStyles();
}
/**
* set panel indicator padding to default
*
* @returns {void}
*/
panelIndicatorPaddingSetDefault()
{
if (this._panelIndicatorPaddingSize === undefined) {
return;
}
let classnameStarter = this.#getAPIClassname('panel-indicator-padding-size');
this.UIStyleClassRemove(classnameStarter + this._panelIndicatorPaddingSize);
this.#emitRefreshStyles();
delete this._panelIndicatorPaddingSize;
}
/**
* set panel indicator padding size
*
* @param {number} size in pixels (0 - 60)
*
* @returns {void}
*/
panelIndicatorPaddingSizeSet(size)
{
this.panelIndicatorPaddingSetDefault();
if (size < 0 || size > 60) {
return;
}
this._panelIndicatorPaddingSize = size;
let classnameStarter = this.#getAPIClassname('panel-indicator-padding-size');
this.UIStyleClassAdd(classnameStarter + size);
this.#emitRefreshStyles();
}
/**
* get window preview prototype
*
* @returns {Object}
*/
#windowPreviewGetPrototype()
{
return this._windowPreview.WindowPreview.prototype;
}
/**
* enable window preview caption
*
* @returns {void}
*/
windowPreviewCaptionEnable()
{
if (!this.#originals['windowPreviewGetCaption']) {
return;
}
let windowPreviewProto = this.#windowPreviewGetPrototype();
windowPreviewProto._getCaption = this.#originals['windowPreviewGetCaption'];
this.UIStyleClassRemove(this.#getAPIClassname('no-window-caption'));
}
/**
* disable window preview caption
*
* @returns {void}
*/
windowPreviewCaptionDisable()
{
let windowPreviewProto = this.#windowPreviewGetPrototype();
if (!this.#originals['windowPreviewGetCaption']) {
this.#originals['windowPreviewGetCaption'] = windowPreviewProto._getCaption;
}
windowPreviewProto._getCaption = () => {
return '';
};
this.UIStyleClassAdd(this.#getAPIClassname('no-window-caption'));
}
/**
* set workspace background border radius to default size
*
* @returns {void}
*/
workspaceBackgroundRadiusSetDefault()
{
if (this._workspaceBackgroundRadiusSize === undefined) {
return;
}
let workspaceBackgroundProto = this._workspace.WorkspaceBackground.prototype;
workspaceBackgroundProto._updateBorderRadius
= this.#originals['workspaceBackgroundUpdateBorderRadius'];
let classnameStarter = this.#getAPIClassname('workspace-background-radius-size');
this.UIStyleClassRemove(classnameStarter + this._workspaceBackgroundRadiusSize);
delete this._workspaceBackgroundRadiusSize;
}
/**
* set workspace background border radius size
*
* @param {number} size in pixels (0 - 60)
*
* @returns {void}
*/
workspaceBackgroundRadiusSet(size)
{
if (size < 0 || size > 60) {
return;
}
this.workspaceBackgroundRadiusSetDefault();
let workspaceBackgroundProto = this._workspace.WorkspaceBackground.prototype;
if (!this.#originals['workspaceBackgroundUpdateBorderRadius']) {
this.#originals['workspaceBackgroundUpdateBorderRadius']
= workspaceBackgroundProto._updateBorderRadius;
}
const Util = this._util;
const St = this._st;
workspaceBackgroundProto._updateBorderRadius = function () {
const {scaleFactor} = St.ThemeContext.get_for_stage(global.stage);
const cornerRadius = scaleFactor * size;
const backgroundContent = this._bgManager.backgroundActor.content;
backgroundContent.rounded_clip_radius =
Util.lerp(0, cornerRadius, this._stateAdjustment.value);
}
this._workspaceBackgroundRadiusSize = size;
let classnameStarter = this.#getAPIClassname('workspace-background-radius-size');
this.UIStyleClassAdd(classnameStarter + size);
}
/**
* enable workspace wraparound
*
* @returns {void}
*/
workspaceWraparoundEnable()
{
let metaWorkspaceProto = this._meta.Workspace.prototype;
if (!this.#originals['metaWorkspaceGetNeighbor']) {
this.#originals['metaWorkspaceGetNeighbor']
= metaWorkspaceProto.get_neighbor;
}
const Meta = this._meta;
metaWorkspaceProto.get_neighbor = function (dir) {
let index = this.index();
let lastIndex = global.workspace_manager.n_workspaces - 1;
let neighborIndex;
if (dir === Meta.MotionDirection.UP || dir === Meta.MotionDirection.LEFT) {
// prev
neighborIndex = (index > 0) ? index - 1 : lastIndex;
} else {
// next
neighborIndex = (index < lastIndex) ? index + 1 : 0;
}
return global.workspace_manager.get_workspace_by_index(neighborIndex);
};
}
/**
* disable workspace wraparound
*
* @returns {void}
*/
workspaceWraparoundDisable()
{
if (!this.#originals['metaWorkspaceGetNeighbor']) {
return;
}
let metaWorkspaceProto = this._meta.Workspace.prototype;
metaWorkspaceProto.get_neighbor = this.#originals['metaWorkspaceGetNeighbor'];
}
/**
* enable window preview close button
*
* @returns {void}
*/
windowPreviewCloseButtonEnable()
{
this.UIStyleClassRemove(this.#getAPIClassname('no-window-close'));
}
/**
* disable window preview close button
*
* @returns {void}
*/
windowPreviewCloseButtonDisable()
{
this.UIStyleClassAdd(this.#getAPIClassname('no-window-close'));
}
/**
* enable ripple box
*
* @returns {void}
*/
rippleBoxEnable()
{
this.UIStyleClassRemove(this.#getAPIClassname('no-ripple-box'));
}
/**
* disable ripple box
*
* @returns {void}
*/
rippleBoxDisable()
{
this.UIStyleClassAdd(this.#getAPIClassname('no-ripple-box'));
}
/**
* unblock overlay key
*
* @returns {void}
*/
unblockOverlayKey()
{
if (!this._overlayKeyOldSignalId) {
return;
}
this._gobject.signal_handler_unblock(
global.display,
this._overlayKeyOldSignalId
);
delete(this._overlayKeyOldSignalId);
}
/**
* block overlay key
*
* @returns {void}
*/
blockOverlayKey()
{
this._overlayKeyOldSignalId = this.#getSignalId(global.display, 'overlay-key');
if (!this._overlayKeyOldSignalId) {
return;
}
this._gobject.signal_handler_block(global.display, this._overlayKeyOldSignalId);
}
/**
* enable double super press to toggle app grid
*
* @returns {void}
*/
doubleSuperToAppGridEnable()
{
if (this._isDoubleSuperToAppGrid === true) {
return;
}
if (!this._overlayKeyNewSignalId) {
return;
}
global.display.disconnect(this._overlayKeyNewSignalId);
delete(this._overlayKeyNewSignalId);
this.unblockOverlayKey();
this._isDoubleSuperToAppGrid = true;
}
/**
* disable double super press to toggle app grid
*
* @returns {void}
*/
doubleSuperToAppGridDisable()
{
if (this._isDoubleSuperToAppGrid === false) {
return;
}
this.blockOverlayKey();
this._overlayKeyNewSignalId = global.display.connect('overlay-key', () => {
this._main.overview.toggle();
});
this._isDoubleSuperToAppGrid = false;
}
/**
* disable the removal of switcher popup delay
*
* @returns {void}
*/
switcherPopupDelaySetDefault()
{
let SwitcherPopupProto = this._switcherPopup.SwitcherPopup.prototype;
if (!SwitcherPopupProto.showOld) {
return;
}
SwitcherPopupProto.show = SwitcherPopupProto.showOld;
delete(SwitcherPopupProto.showOld);
}
/**
* enable the removal of switcher popup delay
*
* @returns {void}
*/
removeSwitcherPopupDelay()
{
let SwitcherPopupProto = this._switcherPopup.SwitcherPopup.prototype;
SwitcherPopupProto.showOld = SwitcherPopupProto.show;
SwitcherPopupProto.show = function (...args) {
let res = this.showOld(...args);
if (res) {
this._showImmediately();
}
return res;
};
}
/**
* set default OSD position
*
* @returns {void}
*/
osdPositionSetDefault()
{
if (!this.#originals['osdWindowShow']) {
return;
}
let osdWindowProto = this._osdWindow.OsdWindow.prototype;
osdWindowProto.show = this.#originals['osdWindowShow'];
delete(osdWindowProto._oldShow);
delete(this.#originals['osdWindowShow']);
if (
this.#originals['osdWindowXAlign'] !== undefined &&
this.#originals['osdWindowYAlign'] !== undefined
) {
let osdWindows = this._main.osdWindowManager._osdWindows;
osdWindows.forEach(osdWindow => {
osdWindow.x_align = this.#originals['osdWindowXAlign'];
osdWindow.y_align = this.#originals['osdWindowYAlign'];
});
delete(this.#originals['osdWindowXAlign']);
delete(this.#originals['osdWindowYAlign']);
}
this.UIStyleClassRemove(this.#getAPIClassname('osd-position-top'));
this.UIStyleClassRemove(this.#getAPIClassname('osd-position-bottom'));
this.UIStyleClassRemove(this.#getAPIClassname('osd-position-center'));
}
/**
* set OSD position
*
* @param int pos position XY_POSITION
*
* @returns {void}
*/
osdPositionSet(pos)
{
let osdWindowProto = this._osdWindow.OsdWindow.prototype;
if (!this.#originals['osdWindowShow']) {
this.#originals['osdWindowShow'] = osdWindowProto.show;
}
if (
this.#originals['osdWindowXAlign'] === undefined ||
this.#originals['osdWindowYAlign'] === undefined
) {
let osdWindows = this._main.osdWindowManager._osdWindows;
this.#originals['osdWindowXAlign'] = osdWindows[0].x_align;
this.#originals['osdWindowYAlign'] = osdWindows[0].y_align;
}
if (osdWindowProto._oldShow === undefined) {
osdWindowProto._oldShow = this.#originals['osdWindowShow'];
}
let [xAlign, yAlign] = this.#xyAlignGet(pos);
osdWindowProto.show = function () {
this.x_align = xAlign;
this.y_align = yAlign;
this._oldShow();
};
if (
pos === XY_POSITION.TOP_START ||
pos === XY_POSITION.TOP_CENTER ||
pos === XY_POSITION.TOP_END
) {
this.UIStyleClassAdd(this.#getAPIClassname('osd-position-top'));
}
if (
pos === XY_POSITION.BOTTOM_START ||
pos === XY_POSITION.BOTTOM_CENTER ||
pos === XY_POSITION.BOTTOM_END
) {
this.UIStyleClassAdd(this.#getAPIClassname('osd-position-bottom'));
}
if (
pos === XY_POSITION.CENTER_START ||
pos === XY_POSITION.CENTER_CENTER ||
pos === XY_POSITION.CENTER_END
) {
this.UIStyleClassAdd(this.#getAPIClassname('osd-position-center'));
}
}
/**
* show weather in date menu
*
* @returns {void}
*/
weatherShow()
{
this.UIStyleClassRemove(this.#getAPIClassname('no-weather'));
}
/**
* hide weather in date menu
*
* @returns {void}
*/
weatherHide()
{
this.UIStyleClassAdd(this.#getAPIClassname('no-weather'));
}
/**
* show world clocks in date menu
*
* @returns {void}
*/
worldClocksShow()
{
if (!this.#originals['clocksItemSync']) {
return;
}
let clocksItem = this._main.panel.statusArea.dateMenu._clocksItem;
clocksItem._sync = this.#originals['clocksItemSync'];
delete(this.#originals['clocksItemSync']);
if (this._clocksItemShowSignal) {
clocksItem.disconnect(this._clocksItemShowSignal);
delete(this._clocksItemShowSignal);
}
clocksItem._sync();
}
/**
* hide world clocks in date menu
*
* @returns {void}
*/
worldClocksHide()
{
let clocksItem = this._main.panel.statusArea.dateMenu._clocksItem;
if (!this.#originals['clocksItemSync']) {
this.#originals['clocksItemSync'] = clocksItem._sync;
}
clocksItem._sync = function () {
this.visible = false;
};
if (!this._clocksItemShowSignal) {
this._clocksItemShowSignal = clocksItem.connect('show', () => {
clocksItem._sync();
});
}
clocksItem._sync();
}
/**
* show events button in date menu
*
* @returns {void}
*/
eventsButtonShow()
{
this.UIStyleClassRemove(this.#getAPIClassname('no-events-button'));
}
/**
* hide events button in date menu
*
* @returns {void}
*/
eventsButtonHide()
{
this.UIStyleClassAdd(this.#getAPIClassname('no-events-button'));
}
/**
* show calendar in date menu
*
* @returns {void}
*/
calendarShow()
{
this._main.panel.statusArea.dateMenu._calendar.show();
}
/**
* hide calendar in date menu
*
* @returns {void}
*/
calendarHide()
{
this._main.panel.statusArea.dateMenu._calendar.hide();
}
/**
* set default panel icon size
*
* @returns {void}
*/
panelIconSetDefaultSize()
{
if (this._panelIconSize === undefined || !this.#originals['panelIconSize']) {
return;
}
let classnameStarter = this.#getAPIClassname('panel-icon-size');
this.UIStyleClassRemove(classnameStarter + this._panelIconSize);
this.#emitRefreshStyles();
let defaultSize = this.#originals['panelIconSize'];
this.#changeDateMenuIndicatorIconSize(defaultSize);
delete(this._panelIconSize);
}
/**
* set panel icon size
*
* @param {number} size 1-60
*
* @returns {void}
*/
panelIconSetSize(size)
{
if (size < 1 || size > 60) {
return;
}
if (!this.#originals['panelIconSize']) {
this.#originals['panelIconSize'] = this._panel.PANEL_ICON_SIZE;
}
let classnameStarter = this.#getAPIClassname('panel-icon-size');
this.UIStyleClassRemove(classnameStarter + this.panelIconGetSize());
this.UIStyleClassAdd(classnameStarter + size);
this.#emitRefreshStyles();
this.#changeDateMenuIndicatorIconSize(size);
this._panelIconSize = size;
}
/**
* change date menu indicator icon size
*
* @param {number} size
*
* @returns {void}
*/
#changeDateMenuIndicatorIconSize(size)
{
let dateMenu = this._main.panel.statusArea.dateMenu;
// we get set_icon_size is not a function in some setups
// in case the date menu has been removed or not created
if (
dateMenu &&
dateMenu._indicator &&
dateMenu._indicator.set_icon_size
) {
dateMenu._indicator.set_icon_size(size);
}
}
/**
* get panel icon size
*
* @returns {void}
*/
panelIconGetSize()
{
if (this._panelIconSize !== undefined) {
return this._panelIconSize;
}
return this._panel.PANEL_ICON_SIZE;
}
/**
* show dash separator
*
* @returns {void}
*/
dashSeparatorShow()
{
this.UIStyleClassRemove(this.#getAPIClassname('no-dash-separator'));
}
/**
* hide dash separator
*
* @returns {void}
*/
dashSeparatorHide()
{
this.UIStyleClassAdd(this.#getAPIClassname('no-dash-separator'));
}
/**
* get looking glass size
*
* @returns {array}
* width: int
* height: int
*/
#lookingGlassGetSize()
{
let lookingGlass = this._main.createLookingGlass();
return [lookingGlass.width, lookingGlass.height];
}
/**
* set default looking glass size
*
* @returns {void}
*/
lookingGlassSetDefaultSize()
{
if (!this._lookingGlassShowSignal) {
return;
}
this._main.lookingGlass.disconnect(this._lookingGlassShowSignal);
delete(this._lookingGlassShowSignal);
delete(this._lookingGlassOriginalSize);
delete(this._monitorsChangedSignal);
}
/**
* set looking glass size
*
* @param {number} width in float
* @param {number} height in float
*
* @returns {void}
*/
lookingGlassSetSize(width, height)
{
let lookingGlass = this._main.createLookingGlass();
if (!this._lookingGlassOriginalSize) {
this._lookingGlassOriginalSize = this.#lookingGlassGetSize();
}
if (this._lookingGlassShowSignal) {
lookingGlass.disconnect(this._lookingGlassShowSignal);
delete(this._lookingGlassShowSignal);
}
this._lookingGlassShowSignal = lookingGlass.connect('show', () => {
let [, currentHeight] = this.#lookingGlassGetSize();
let [originalWidth, originalHeight] = this._lookingGlassOriginalSize;
let monitorInfo = this.monitorGetInfo();
let dialogWidth
= (width !== null)
? monitorInfo.width * width
: originalWidth;
let x = monitorInfo.x + (monitorInfo.width - dialogWidth) / 2;
lookingGlass.set_x(x);
let keyboardHeight = this._main.layoutManager.keyboardBox.height;
let availableHeight = monitorInfo.height - keyboardHeight;
let dialogHeight
= (height !== null)
? Math.min(monitorInfo.height * height, availableHeight * 0.9)
: originalHeight;
let hiddenY = lookingGlass._hiddenY + currentHeight - dialogHeight;
lookingGlass.set_y(hiddenY);
lookingGlass._hiddenY = hiddenY;
lookingGlass.set_size(dialogWidth, dialogHeight);
});
if (!this._monitorsChangedSignal) {
this._monitorsChangedSignal = this._main.layoutManager.connect('monitors-changed',
() => {
this.lookingGlassSetSize(width, height);
});
}
}
/**
* show screenshot in window menu
*
* @returns {void}
*/
screenshotInWindowMenuShow()
{
let windowMenuProto = this._windowMenu.WindowMenu.prototype;
if (windowMenuProto._oldBuildMenu === undefined) {
return;
}
windowMenuProto._buildMenu = this.#originals['WindowMenubuildMenu'];
delete(windowMenuProto._oldBuildMenu);
}
/**
* hide screenshot in window menu
*
* @returns {void}
*/
screenshotInWindowMenuHide()
{
let windowMenuProto = this._windowMenu.WindowMenu.prototype;
if (!this.#originals['WindowMenubuildMenu']) {
this.#originals['WindowMenubuildMenu'] = windowMenuProto._buildMenu;
}
if (windowMenuProto._oldBuildMenu === undefined) {
windowMenuProto._oldBuildMenu = this.#originals['WindowMenubuildMenu'];
}
windowMenuProto._buildMenu = function (window) {
this._oldBuildMenu(window);
this.firstMenuItem.hide();
};
}
/**
* set all alt tab sizes to default
*
* @returns {void}
*/
#altTabSizesSetDefault()
{
let WindowIconProto = this._altTab.WindowIcon.prototype;
if (WindowIconProto._initOld) {
WindowIconProto._init = WindowIconProto._initOld;
delete(WindowIconProto._initOld);
}
delete(this._altTabAPP_ICON_SIZE);
delete(this._altTabAPP_ICON_SIZE_SMALL);
delete(this._altTabWINDOW_PREVIEW_SIZE);
}
/**
* set alt tab sizes
*
* @param {number|null} appIconSize
* @param {number|null} appIconSizeSmall
* @param {number|null} windowPreviewSize
*
* @returns {void}
*/
#altTabSizesSet(appIconSize, appIconSizeSmall, windowPreviewSize)
{
let WindowIconProto = this._altTab.WindowIcon.prototype;
if (!WindowIconProto._initOld) {
WindowIconProto._initOld = WindowIconProto._init;
}
this._altTabAPP_ICON_SIZE ||= this._altTab.APP_ICON_SIZE;
this._altTabAPP_ICON_SIZE_SMALL ||= this._altTab.APP_ICON_SIZE_SMALL;
this._altTabWINDOW_PREVIEW_SIZE ||= this._altTab.WINDOW_PREVIEW_SIZE;
const APP_ICON_SIZE = appIconSize || this._altTabAPP_ICON_SIZE;
const APP_ICON_SIZE_SMALL = appIconSizeSmall || this._altTabAPP_ICON_SIZE_SMALL;
const WINDOW_PREVIEW_SIZE = windowPreviewSize || this._altTabWINDOW_PREVIEW_SIZE;
WindowIconProto._init = function(window, mode) {
this._initOld(window, mode);
}
}
/**
* set default alt tab window preview size
*
* @returns {void}
*/
altTabWindowPreviewSetDefaultSize()
{
if (!this.#originals['altTabWindowPreviewSize']) {
return;
}
this.#altTabSizesSet(null, null, this.#originals['altTabWindowPreviewSize']);
}
/**
* set alt tab window preview size
*
* @param {number} size 1-512
*
* @returns {void}
*/
altTabWindowPreviewSetSize(size)
{
if (size < 1 || size > 512) {
return;
}
if (!this.#originals['altTabWindowPreviewSize']) {
this.#originals['altTabWindowPreviewSize'] = this._altTab.WINDOW_PREVIEW_SIZE;
}
this.#altTabSizesSet(null, null, size);
}
/**
* set default alt tab small icon size
*
* @returns {void}
*/
altTabSmallIconSetDefaultSize()
{
if (!this.#originals['altTabAppIconSizeSmall']) {
return;
}
this.#altTabSizesSet(null, this.#originals['altTabAppIconSizeSmall'], null);
}
/**
* set alt tab small icon size
*
* @param {number} size 1-512
*
* @returns {void}
*/
altTabSmallIconSetSize(size)
{
if (size < 1 || size > 512) {
return;
}
if (!this.#originals['altTabAppIconSizeSmall']) {
this.#originals['altTabAppIconSizeSmall'] = this._altTab.APP_ICON_SIZE_SMALL;
}
this.#altTabSizesSet(null, size, null);
}
/**
* set default alt tab icon size
*
* @returns {void}
*/
altTabIconSetDefaultSize()
{
if (!this.#originals['altTabAppIconSize']) {
return;
}
this.#altTabSizesSet(this.#originals['altTabAppIconSize'], null, null);
}
/**
* set alt tab icon size
*
* @param {number} size 1-512
*
* @returns {void}
*/
altTabIconSetSize(size)
{
if (size < 1 || size > 512) {
return;
}
if (!this.#originals['altTabAppIconSize']) {
this.#originals['altTabAppIconSize'] = this._altTab.APP_ICON_SIZE;
}
this.#altTabSizesSet(size, null, null);
}
/**
* enable screen sharing indicator
*
* @returns {void}
*/
screenSharingIndicatorEnable()
{
this.UIStyleClassRemove(this.#getAPIClassname('no-screen-sharing-indicator'));
}
/**
* disable screen sharing indicator
*
* @returns {void}
*/
screenSharingIndicatorDisable()
{
this.UIStyleClassAdd(this.#getAPIClassname('no-screen-sharing-indicator'));
}
/**
* enable screen recording indicator
*
* @returns {void}
*/
screenRecordingIndicatorEnable()
{
this.UIStyleClassRemove(this.#getAPIClassname('no-screen-recording-indicator'));
}
/**
* disable screen recording indicator
*
* @returns {void}
*/
screenRecordingIndicatorDisable()
{
this.UIStyleClassAdd(this.#getAPIClassname('no-screen-recording-indicator'));
}
/**
* set controls manager spacing to default
*
* @returns {void}
*/
controlsManagerSpacingSetDefault()
{
if (this._controlsManagerSpacingSize === undefined) {
return;
}
let classnameStarter = this.#getAPIClassname('controls-manager-spacing-size');
this.UIStyleClassRemove(classnameStarter + this._controlsManagerSpacingSize);
delete this._controlsManagerSpacingSize;
}
/**
* set controls manager spacing size
*
* @param {number} size in pixels (0 - 150)
*
* @returns {void}
*/
controlsManagerSpacingSizeSet(size)
{
this.controlsManagerSpacingSetDefault();
if (size < 0 || size > 150) {
return;
}
this._controlsManagerSpacingSize = size;
let classnameStarter = this.#getAPIClassname('controls-manager-spacing-size');
this.UIStyleClassAdd(classnameStarter + size);
}
/**
* set workspaces view spacing to default
*
* @returns {void}
*/
workspacesViewSpacingSetDefault()
{
let wsvp = this._workspacesView.WorkspacesView.prototype;
if (wsvp._getSpacingOld === undefined) {
return;
}
wsvp._getSpacing = wsvp._getSpacingOld;
delete wsvp._getSpacingOld;
}
/**
* set workspaces view spacing size
*
* @param {number} size in pixels (0 - 500)
*
* @returns {void}
*/
workspacesViewSpacingSizeSet(size)
{
if (size < 0 || size > 500) {
return;
}
let wsvp = this._workspacesView.WorkspacesView.prototype;
if (wsvp._getSpacingOld === undefined) {
wsvp._getSpacingOld = wsvp._getSpacing;
}
wsvp._getSpacing = function (box, fitMode, vertical) {
if (fitMode === 0) {
return size;
}
return this._getSpacingOld(box, fitMode, vertical);
};
}
/**
* show dash app running dot
*
* @returns {void}
*/
dashAppRunningDotShow()
{
this.UIStyleClassRemove(this.#getAPIClassname('no-dash-app-running-dot'));
}
/**
* hide dash app running dot
*
* @returns {void}
*/
dashAppRunningDotHide()
{
this.UIStyleClassAdd(this.#getAPIClassname('no-dash-app-running-dot'));
}
/**
* show dark style toggle button in quick settings
*
* @returns {void}
*/
quickSettingsDarkStyleToggleShow()
{
this.#onQuickSettingsPropertyCall('_darkMode', (darkMode) => {
darkMode.quickSettingsItems[0].show();
});
}
/**
* hide dark style toggle button in quick settings
*
* @returns {void}
*/
quickSettingsDarkStyleToggleHide()
{
this.#onQuickSettingsPropertyCall('_darkMode', (darkMode) => {
darkMode.quickSettingsItems[0].hide();
});
}
/**
* set workspaces view spacing size
*
* @param {string} propertyName
* @param {Function} func function to call when the property is available
*
* @returns {void}
*/
#onQuickSettingsPropertyCall(propertyName, func)
{
const quickSettings = this._main.panel.statusArea.quickSettings;
this._glib.idle_add(this._glib.PRIORITY_DEFAULT_IDLE, () => {
if (!quickSettings[propertyName]) {
return this._glib.SOURCE_CONTINUE;
}
func(quickSettings[propertyName]);
return this._glib.SOURCE_REMOVE;
});
}
}