831 lines
30 KiB
JavaScript
831 lines
30 KiB
JavaScript
import Clutter from 'gi://Clutter';
|
|
import GLib from 'gi://GLib';
|
|
import GObject from 'gi://GObject';
|
|
import Graphene from 'gi://Graphene';
|
|
import Shell from 'gi://Shell';
|
|
import St from 'gi://St';
|
|
|
|
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
|
import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
|
|
import * as PointerWatcher from 'resource:///org/gnome/shell/ui/pointerWatcher.js';
|
|
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
|
|
import * as SystemActions from 'resource:///org/gnome/shell/misc/systemActions.js';
|
|
|
|
import {ArcMenuManager} from './arcmenuManager.js';
|
|
import * as Constants from './constants.js';
|
|
import * as LayoutHandler from './menulayouts/layoutHandler.js';
|
|
import * as MW from './menuWidgets.js';
|
|
import * as Utils from './utils.js';
|
|
|
|
import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
|
|
|
|
class MenuButtonWidget extends St.BoxLayout {
|
|
static {
|
|
GObject.registerClass(this);
|
|
}
|
|
|
|
constructor() {
|
|
super({
|
|
style_class: 'panel-status-menu-box',
|
|
});
|
|
|
|
this._icon = new St.Icon({
|
|
style_class: 'arcmenu-menu-button',
|
|
track_hover: true,
|
|
reactive: true,
|
|
});
|
|
this._label = new St.Label({
|
|
text: _('Apps'),
|
|
y_expand: true,
|
|
style_class: 'arcmenu-menu-button',
|
|
y_align: Clutter.ActorAlign.CENTER,
|
|
});
|
|
|
|
this.add_child(this._icon);
|
|
this.add_child(this._label);
|
|
}
|
|
|
|
addStylePseudoClass(style) {
|
|
this._icon.add_style_pseudo_class(style);
|
|
this._label.add_style_pseudo_class(style);
|
|
}
|
|
|
|
removeStylePseudoClass(style) {
|
|
this._icon.remove_style_pseudo_class(style);
|
|
this._label.remove_style_pseudo_class(style);
|
|
}
|
|
|
|
showIcon() {
|
|
this._icon.show();
|
|
this._label.hide();
|
|
|
|
this.set_child_at_index(this._icon, 0);
|
|
}
|
|
|
|
showText() {
|
|
this._icon.hide();
|
|
this._label.show();
|
|
|
|
this.set_child_at_index(this._label, 0);
|
|
}
|
|
|
|
showIconText() {
|
|
this._icon.show();
|
|
this._label.show();
|
|
|
|
this.set_child_at_index(this._icon, 0);
|
|
}
|
|
|
|
showTextIcon() {
|
|
this._icon.show();
|
|
this._label.show();
|
|
|
|
this.set_child_at_index(this._label, 0);
|
|
}
|
|
|
|
getPanelLabel() {
|
|
return this._label;
|
|
}
|
|
|
|
getPanelIcon() {
|
|
return this._icon;
|
|
}
|
|
|
|
setLabelStyle(style) {
|
|
this._label.style = style;
|
|
}
|
|
}
|
|
|
|
export const MenuButton = GObject.registerClass(
|
|
class ArcMenuMenuButton extends PanelMenu.Button {
|
|
_init(panelInfo, monitorIndex) {
|
|
super._init(0.5, null, true);
|
|
|
|
this.set({
|
|
x_expand: false,
|
|
});
|
|
|
|
this.add_style_class_name('arcmenu-panel-menu');
|
|
|
|
// Link search providers to this menu
|
|
this.searchProviderDisplayId = `ArcMenu_${monitorIndex}`;
|
|
|
|
this._panel = panelInfo.panel;
|
|
this._panelBox = panelInfo.panelBox;
|
|
this._panelParent = panelInfo.panelParent;
|
|
this._monitorIndex = monitorIndex;
|
|
|
|
this.menu.destroy();
|
|
this.menu = null;
|
|
|
|
this.tooltipShowing = false;
|
|
this.tooltipShowingID = null;
|
|
this.tooltip = new MW.Tooltip(this);
|
|
|
|
this._dtpNeedsRelease = false;
|
|
|
|
// Create Main Menus - ArcMenu and ArcMenu's context menu
|
|
this.arcMenu = new ArcMenu(this, 0.5, St.Side.TOP);
|
|
this.arcMenu.connectObject('open-state-changed', this._onOpenStateChanged.bind(this), this);
|
|
|
|
this.arcMenuContextMenu = new ArcMenuContextMenu(this, 0.5, St.Side.TOP);
|
|
this.arcMenuContextMenu.connectObject('open-state-changed', this._onOpenStateChanged.bind(this), this);
|
|
|
|
this.menuManager = new PopupMenu.PopupMenuManager();
|
|
this.menuManager._changeMenu = () => {};
|
|
this.menuManager.addMenu(this.arcMenu);
|
|
this.menuManager.addMenu(this.arcMenuContextMenu);
|
|
|
|
// Context Menus for applications and other menu items
|
|
this.contextMenuManager = new PopupMenu.PopupMenuManager();
|
|
this.contextMenuManager._changeMenu = () => {};
|
|
|
|
// Sub Menu Manager - Control all other popup menus
|
|
this.subMenuManager = new PopupMenu.PopupMenuManager();
|
|
this.subMenuManager._changeMenu = () => {};
|
|
|
|
this.menuButtonWidget = new MenuButtonWidget();
|
|
this.add_child(this.menuButtonWidget);
|
|
}
|
|
|
|
initiate() {
|
|
this._dtp = Main.extensionManager.lookup(Constants.DASH_TO_PANEL_UUID);
|
|
|
|
if (this._dtp?.state === Utils.ExtensionState.ACTIVE && global.dashToPanel)
|
|
this.syncWithDashToPanel();
|
|
|
|
Main.layoutManager.connectObject('monitors-changed', () => this.updateHeight(), this);
|
|
Main.layoutManager.connectObject('startup-complete', () => this.updateHeight(), this);
|
|
|
|
this.setMenuPositionAlignment();
|
|
this.createMenuLayout();
|
|
}
|
|
|
|
syncWithDashToPanel() {
|
|
const dtp = Extension.lookupByUUID(Constants.DASH_TO_PANEL_UUID);
|
|
this._dtpSettings = dtp.getSettings('org.gnome.shell.extensions.dash-to-panel');
|
|
this._dtpActive = true;
|
|
|
|
const side = this._panelParent.getPosition();
|
|
this.updateArrowSide(side);
|
|
|
|
this._dtpSettings.connectObject('changed::panel-positions', () => {
|
|
const newSide = this._panelParent.getPosition();
|
|
this.updateArrowSide(newSide);
|
|
}, this);
|
|
}
|
|
|
|
createMenuLayout() {
|
|
this._clearTooltipShowingId();
|
|
this._clearTooltip();
|
|
|
|
this._destroyMenuLayout();
|
|
|
|
const layout = ArcMenuManager.settings.get_enum('menu-layout');
|
|
|
|
this._menuLayout = LayoutHandler.createMenuLayout(this, layout);
|
|
|
|
if (this._menuLayout) {
|
|
this.arcMenu.box.add_child(this._menuLayout);
|
|
this.setMenuPositionAlignment();
|
|
this.forceMenuLocation();
|
|
this.updateHeight();
|
|
}
|
|
}
|
|
|
|
setMenuPositionAlignment() {
|
|
const layout = ArcMenuManager.settings.get_enum('menu-layout');
|
|
const arrowAlignment = 1 - (ArcMenuManager.settings.get_int('menu-position-alignment') / 100);
|
|
const panelPosition = ArcMenuManager.settings.get_enum('position-in-panel');
|
|
|
|
if (layout !== Constants.MenuLayout.RUNNER) {
|
|
if (panelPosition === Constants.MenuPosition.CENTER) {
|
|
this.arcMenuContextMenu._arrowAlignment = arrowAlignment;
|
|
this.arcMenu._arrowAlignment = arrowAlignment;
|
|
this.arcMenuContextMenu._boxPointer.setSourceAlignment(.5);
|
|
this.arcMenu._boxPointer.setSourceAlignment(.5);
|
|
} else if (this._dtpActive) {
|
|
const side = this._panelParent.getPosition();
|
|
this.updateArrowSide(side, false);
|
|
} else {
|
|
this.updateArrowSide(St.Side.TOP, false);
|
|
}
|
|
} else {
|
|
this.updateArrowSide(St.Side.TOP, false);
|
|
if (panelPosition === Constants.MenuPosition.CENTER) {
|
|
this.arcMenuContextMenu._arrowAlignment = arrowAlignment;
|
|
this.arcMenuContextMenu._boxPointer.setSourceAlignment(.5);
|
|
}
|
|
}
|
|
}
|
|
|
|
updateArrowSide(side, setAlignment = true) {
|
|
let arrowAlignment;
|
|
if (side === St.Side.RIGHT || side === St.Side.LEFT)
|
|
arrowAlignment = 1.0;
|
|
else
|
|
arrowAlignment = 0.5;
|
|
|
|
const menus = [this.arcMenu, this.arcMenuContextMenu];
|
|
for (const menu of menus) {
|
|
menu._arrowSide = side;
|
|
menu._boxPointer._arrowSide = side;
|
|
menu._boxPointer._userArrowSide = side;
|
|
menu._boxPointer.setSourceAlignment(arrowAlignment);
|
|
menu._arrowAlignment = arrowAlignment;
|
|
menu._boxPointer._border.queue_repaint();
|
|
}
|
|
|
|
if (setAlignment)
|
|
this.setMenuPositionAlignment();
|
|
}
|
|
|
|
_getDashToPanelGeom() {
|
|
if (!this._dtpActive || !this._panelParent.intellihide?.enabled)
|
|
return {width: 0, height: 0};
|
|
|
|
const dtpPostion = this._panelParent.getPosition();
|
|
const menuLocation = ArcMenuManager.settings.get_enum('force-menu-location');
|
|
|
|
const width = this._panelParent.geom?.w ?? 0;
|
|
const height = this._panelParent.geom?.h ?? 0;
|
|
|
|
const {MenuLocation} = Constants;
|
|
const topLocations = [MenuLocation.TOP_CENTERED, MenuLocation.TOP_LEFT, MenuLocation.TOP_RIGHT];
|
|
const bottomLocations = [MenuLocation.BOTTOM_CENTERED, MenuLocation.BOTTOM_LEFT, MenuLocation.BOTTOM_RIGHT];
|
|
const leftLocations = [MenuLocation.BOTTOM_LEFT, MenuLocation.TOP_LEFT, MenuLocation.LEFT_CENTERED];
|
|
const rightLocations = [MenuLocation.BOTTOM_RIGHT, MenuLocation.TOP_RIGHT, MenuLocation.RIGHT_CENTERED];
|
|
const xCenterLocations = [MenuLocation.BOTTOM_CENTERED, MenuLocation.TOP_CENTERED];
|
|
const yCenterLocations = [MenuLocation.LEFT_CENTERED, MenuLocation.RIGHT_CENTERED];
|
|
|
|
const needsTopAdjustment = topLocations.includes(menuLocation) || yCenterLocations.includes(menuLocation);
|
|
const needsBottomAdjustment = bottomLocations.includes(menuLocation) || yCenterLocations.includes(menuLocation);
|
|
const needsLeftAdjustment = leftLocations.includes(menuLocation) || xCenterLocations.includes(menuLocation);
|
|
const needsRightAdjustment = rightLocations.includes(menuLocation) || xCenterLocations.includes(menuLocation);
|
|
|
|
if (dtpPostion === St.Side.TOP && needsTopAdjustment)
|
|
return {width: 0, height};
|
|
if (dtpPostion === St.Side.BOTTOM && needsBottomAdjustment)
|
|
return {width: 0, height};
|
|
if (dtpPostion === St.Side.LEFT && needsLeftAdjustment)
|
|
return {width, height: 0};
|
|
if (dtpPostion === St.Side.RIGHT && needsRightAdjustment)
|
|
return {width, height: 0};
|
|
|
|
return {width: 0, height: 0};
|
|
}
|
|
|
|
forceMenuLocation() {
|
|
const layout = ArcMenuManager.settings.get_enum('menu-layout');
|
|
if (layout === Constants.MenuLayout.RUNNER ||
|
|
layout === Constants.MenuLayout.RAVEN ||
|
|
layout === Constants.MenuLayout.GNOME_OVERVIEW)
|
|
return;
|
|
|
|
this.arcMenu.actor.remove_style_class_name('bottomOfScreenMenu');
|
|
|
|
const newMenuLocation = ArcMenuManager.settings.get_enum('force-menu-location');
|
|
if (this._menuLocation !== newMenuLocation) {
|
|
this._menuLocation = newMenuLocation;
|
|
|
|
if (newMenuLocation === Constants.MenuLocation.OFF) {
|
|
this.arcMenu.sourceActor = this.arcMenu.focusActor = this;
|
|
this.arcMenu._boxPointer.setPosition(this, 0.5);
|
|
this.setMenuPositionAlignment();
|
|
return;
|
|
}
|
|
|
|
this.arcMenu.sourceActor = this.arcMenu.focusActor = Main.layoutManager.dummyCursor;
|
|
this.arcMenu._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0.5);
|
|
this.arcMenu._boxPointer.setSourceAlignment(0.5);
|
|
this.arcMenu._arrowAlignment = 0.5;
|
|
}
|
|
|
|
if (newMenuLocation === Constants.MenuLocation.OFF)
|
|
return;
|
|
|
|
const monitor = Main.layoutManager.findMonitorForActor(this);
|
|
const workArea = Main.layoutManager.getWorkAreaForMonitor(this._monitorIndex);
|
|
const menuHeight = ArcMenuManager.settings.get_int('menu-height');
|
|
|
|
// Offset width and height of DtP when intellihide is enabled.
|
|
const {width: dtpWidth, height: dtpHeight} = this._getDashToPanelGeom();
|
|
|
|
const xLeft = workArea.x + dtpWidth;
|
|
const xRight = workArea.x + workArea.width - 1 - dtpWidth;
|
|
const yTop = workArea.y + dtpHeight;
|
|
const yBottom = workArea.y + workArea.height - 1 - dtpHeight;
|
|
const xCentered = Math.round(monitor.x + (monitor.width / 2));
|
|
const yCentered = Math.round(monitor.y + (monitor.height / 2) - (menuHeight / 2));
|
|
let x, y;
|
|
let side = St.Side.TOP;
|
|
|
|
if (newMenuLocation === Constants.MenuLocation.TOP_CENTERED) {
|
|
x = xCentered;
|
|
y = yTop;
|
|
} else if (newMenuLocation === Constants.MenuLocation.TOP_LEFT) {
|
|
side = St.Side.LEFT;
|
|
x = xLeft;
|
|
y = yTop;
|
|
} else if (newMenuLocation === Constants.MenuLocation.TOP_RIGHT) {
|
|
side = St.Side.RIGHT;
|
|
x = xRight;
|
|
y = yTop;
|
|
} else if (newMenuLocation === Constants.MenuLocation.BOTTOM_CENTERED) {
|
|
x = xCentered;
|
|
y = yBottom;
|
|
this.arcMenu.actor.add_style_class_name('bottomOfScreenMenu');
|
|
} else if (newMenuLocation === Constants.MenuLocation.BOTTOM_LEFT) {
|
|
side = St.Side.LEFT;
|
|
x = xLeft;
|
|
y = yBottom;
|
|
this.arcMenu.actor.add_style_class_name('bottomOfScreenMenu');
|
|
} else if (newMenuLocation === Constants.MenuLocation.BOTTOM_RIGHT) {
|
|
side = St.Side.RIGHT;
|
|
x = xRight;
|
|
y = yBottom;
|
|
this.arcMenu.actor.add_style_class_name('bottomOfScreenMenu');
|
|
} else if (newMenuLocation === Constants.MenuLocation.LEFT_CENTERED) {
|
|
x = xLeft;
|
|
y = yCentered;
|
|
} else if (newMenuLocation === Constants.MenuLocation.RIGHT_CENTERED) {
|
|
x = xRight;
|
|
y = yCentered;
|
|
} else if (newMenuLocation === Constants.MenuLocation.MONITOR_CENTERED) {
|
|
x = xCentered;
|
|
y = yCentered;
|
|
}
|
|
|
|
this.updateArrowSide(side, false);
|
|
Main.layoutManager.setDummyCursorGeometry(x, y, 0, 0);
|
|
}
|
|
|
|
vfunc_event(event) {
|
|
if (event.type() === Clutter.EventType.BUTTON_PRESS) {
|
|
const clickAction = this._getClickActionForButton(event.get_button());
|
|
if (clickAction === Constants.MenuButtonClickAction.ARCMENU)
|
|
this.toggleMenu();
|
|
else if (clickAction === Constants.MenuButtonClickAction.CONTEXT_MENU)
|
|
this.arcMenuContextMenu.toggle();
|
|
} else if (event.type() === Clutter.EventType.TOUCH_BEGIN) {
|
|
this.toggleMenu();
|
|
}
|
|
return Clutter.EVENT_PROPAGATE;
|
|
}
|
|
|
|
_getClickActionForButton(button) {
|
|
if (button === Clutter.BUTTON_PRIMARY)
|
|
return ArcMenuManager.settings.get_enum('menu-button-left-click-action');
|
|
else if (button === Clutter.BUTTON_SECONDARY)
|
|
return ArcMenuManager.settings.get_enum('menu-button-right-click-action');
|
|
else if (button === Clutter.BUTTON_MIDDLE)
|
|
return ArcMenuManager.settings.get_enum('menu-button-middle-click-action');
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
closeOtherMenus() {
|
|
if (this.contextMenuManager.activeMenu)
|
|
this.contextMenuManager.activeMenu.toggle();
|
|
if (this.subMenuManager.activeMenu)
|
|
this.subMenuManager.activeMenu.toggle();
|
|
}
|
|
|
|
closeContextMenu() {
|
|
if (this.arcMenuContextMenu.isOpen)
|
|
this.arcMenuContextMenu.toggle();
|
|
}
|
|
|
|
toggleMenu() {
|
|
this.closeOtherMenus();
|
|
|
|
const layout = ArcMenuManager.settings.get_enum('menu-layout');
|
|
if (layout === Constants.MenuLayout.GNOME_OVERVIEW) {
|
|
if (ArcMenuManager.settings.get_boolean('gnome-dash-show-applications'))
|
|
Main.overview._overview._controls._toggleAppsPage();
|
|
else
|
|
Main.overview.toggle();
|
|
return;
|
|
}
|
|
|
|
if (!this.arcMenu.isOpen) {
|
|
if (this._menuLayout?.updateLocation)
|
|
this._menuLayout.updateLocation();
|
|
|
|
if (this._menuLayout?.updateStyle)
|
|
this._menuLayout.updateStyle();
|
|
|
|
this._maybeShowPanel();
|
|
}
|
|
|
|
this.arcMenu.toggle();
|
|
|
|
if (this.arcMenu.isOpen) {
|
|
this._menuLayout?.grab_key_focus();
|
|
this.forceMenuLocation();
|
|
}
|
|
}
|
|
|
|
updateHeight() {
|
|
if (!this._menuLayout)
|
|
return;
|
|
|
|
const layout = ArcMenuManager.settings.get_enum('menu-layout');
|
|
if (layout === Constants.MenuLayout.RUNNER || layout === Constants.MenuLayout.RAVEN) {
|
|
this._menuLayout.style = '';
|
|
return;
|
|
}
|
|
|
|
const height = ArcMenuManager.settings.get_int('menu-height');
|
|
this._menuLayout.style = `height: ${height}px;`;
|
|
}
|
|
|
|
updateWidth() {
|
|
if (this._menuLayout?.updateWidth)
|
|
this._menuLayout.updateWidth(true);
|
|
}
|
|
|
|
_clearTooltipShowingId() {
|
|
if (this.tooltipShowingID) {
|
|
GLib.source_remove(this.tooltipShowingID);
|
|
this.tooltipShowingID = null;
|
|
}
|
|
}
|
|
|
|
_clearTooltip() {
|
|
this.tooltipShowing = false;
|
|
if (this.tooltip) {
|
|
this.tooltip.hide();
|
|
this.tooltip.sourceActor = null;
|
|
}
|
|
}
|
|
|
|
_onDestroy() {
|
|
this._stopTrackingMouse();
|
|
Main.layoutManager.disconnectObject(this);
|
|
this._clearTooltipShowingId();
|
|
|
|
if (this._dtpSettings) {
|
|
this._dtpSettings.disconnectObject(this);
|
|
this._dtpSettings = null;
|
|
}
|
|
|
|
if (this.dtp)
|
|
this.dtp = null;
|
|
|
|
this._destroyMenuLayout();
|
|
|
|
this.tooltip?.destroy();
|
|
this.tooltip = null;
|
|
this.arcMenu?.destroy();
|
|
this.arcMenu = null;
|
|
this.arcMenuContextMenu?.destroy();
|
|
this.arcMenuContextMenu = null;
|
|
|
|
this.menuManager = null;
|
|
this.contextMenuManager = null;
|
|
this.subMenuManager = null;
|
|
|
|
this.menuButtonWidget.destroy();
|
|
this.menuButtonWidget = null;
|
|
|
|
this._panel.statusArea['ArcMenu'] = null;
|
|
this._panel = null;
|
|
this._panelBox = null;
|
|
this._panelParent = null;
|
|
|
|
super._onDestroy();
|
|
}
|
|
|
|
_destroyMenuLayout() {
|
|
if (this._menuLayout) {
|
|
this._menuLayout.destroy();
|
|
this._menuLayout = null;
|
|
}
|
|
}
|
|
|
|
updateLocation() {
|
|
if (this._menuLayout && this._menuLayout.updateLocation)
|
|
this._menuLayout.updateLocation();
|
|
}
|
|
|
|
getActiveCategoryType() {
|
|
return this._menuLayout?.activeCategoryType;
|
|
}
|
|
|
|
reloadApplications() {
|
|
this._menuLayout?.reloadApplications();
|
|
}
|
|
|
|
displayPinnedApps() {
|
|
this._menuLayout?.displayPinnedApps();
|
|
}
|
|
|
|
loadPinnedApps() {
|
|
this._menuLayout?.loadPinnedApps();
|
|
}
|
|
|
|
setDefaultMenuView() {
|
|
if (!this._menuLayout)
|
|
return;
|
|
|
|
if (!this._menuLayout.reloadQueued)
|
|
this._menuLayout.setDefaultMenuView();
|
|
}
|
|
|
|
_onOpenStateChanged(_menu, open) {
|
|
if (open) {
|
|
this.menuButtonWidget.addStylePseudoClass('active');
|
|
this.add_style_pseudo_class('active');
|
|
|
|
if (Main.panel.menuManager && Main.panel.menuManager.activeMenu)
|
|
Main.panel.menuManager.activeMenu.toggle();
|
|
|
|
if (!this._dtpNeedsRelease && this._panelParent.intellihide?.enabled)
|
|
this._dtpNeedsRelease = true;
|
|
} else {
|
|
if (!this.arcMenu.isOpen) {
|
|
this._clearTooltipShowingId();
|
|
this._clearTooltip();
|
|
}
|
|
|
|
if (!this.arcMenu.isOpen && !this.arcMenuContextMenu.isOpen) {
|
|
this.menuButtonWidget.removeStylePseudoClass('active');
|
|
this.remove_style_pseudo_class('active');
|
|
|
|
if (this._dtpNeedsRelease && !this._panelNeedsHiding) {
|
|
this._dtpNeedsRelease = false;
|
|
const hidePanel = () => this._panelParent.intellihide?.release(1);
|
|
|
|
const isMouseOnPanel = this._isMouseOnPanel();
|
|
if (isMouseOnPanel)
|
|
this._startTrackingMouse(hidePanel);
|
|
else
|
|
hidePanel();
|
|
}
|
|
if (this._panelNeedsHiding) {
|
|
this._panelNeedsHiding = false;
|
|
// Hide panel if monitor inFullscreen, else show it
|
|
const hidePanel = () => {
|
|
const monitor = Main.layoutManager.findMonitorForActor(this);
|
|
this._panelBox.visible = !(global.window_group.visible &&
|
|
monitor &&
|
|
monitor.inFullscreen);
|
|
};
|
|
|
|
const isMouseOnPanel = this._isMouseOnPanel();
|
|
if (isMouseOnPanel)
|
|
this._startTrackingMouse(hidePanel);
|
|
else
|
|
hidePanel();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
_maybeShowPanel() {
|
|
if (this._panelParent.intellihide && this._panelParent.intellihide.enabled) {
|
|
this._panelParent.intellihide._revealPanel(true);
|
|
this._panelParent.intellihide.revealAndHold(1);
|
|
} else if (!this._panelBox.visible) {
|
|
this._panelBox.visible = true;
|
|
this._panelNeedsHiding = true;
|
|
}
|
|
}
|
|
|
|
_isMouseOnPanel() {
|
|
const [x, y] = global.get_pointer();
|
|
|
|
const mouseOnPanel = this._panelHasMousePointer(x, y);
|
|
if (mouseOnPanel)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
_panelHasMousePointer(x, y) {
|
|
const panelBoxRect = this._panelBox.get_transformed_extents();
|
|
const cursorLocation = new Graphene.Point({x, y});
|
|
|
|
return panelBoxRect.contains_point(cursorLocation);
|
|
}
|
|
|
|
_startTrackingMouse(callback) {
|
|
if (this._pointerWatch)
|
|
return;
|
|
|
|
this._pointerWatch = PointerWatcher.getPointerWatcher().addWatch(500, (pX, pY) => {
|
|
if (!this._panelHasMousePointer(pX, pY)) {
|
|
callback();
|
|
this._stopTrackingMouse();
|
|
}
|
|
});
|
|
}
|
|
|
|
_stopTrackingMouse() {
|
|
if (this._pointerWatch) {
|
|
PointerWatcher.getPointerWatcher()._removeWatch(this._pointerWatch);
|
|
this._pointerWatch = null;
|
|
}
|
|
}
|
|
});
|
|
|
|
export const ArcMenu = class ArcMenuArcMenu extends PopupMenu.PopupMenu {
|
|
constructor(sourceActor, arrowAlignment, arrowSide, parent) {
|
|
super(sourceActor, arrowAlignment, arrowSide);
|
|
this._menuButton = parent || sourceActor;
|
|
Main.uiGroup.add_child(this.actor);
|
|
this.actor.add_style_class_name('panel-menu arcmenu-menu');
|
|
this.actor.hide();
|
|
this._menuClosedID = this.connect('menu-closed', () => this._menuButton.setDefaultMenuView());
|
|
|
|
this.actor.connectObject('captured-event', this._onCapturedEvent.bind(this), this);
|
|
|
|
this._dimEffect = new Clutter.BrightnessContrastEffect({
|
|
enabled: false,
|
|
});
|
|
this._boxPointer.add_effect_with_name('dim', this._dimEffect);
|
|
}
|
|
|
|
_onCapturedEvent(actor, event) {
|
|
if (Main.keyboard.maybeHandleEvent(event))
|
|
return Clutter.EVENT_STOP;
|
|
|
|
return Clutter.EVENT_PROPAGATE;
|
|
}
|
|
|
|
open(animate) {
|
|
if (!this.isOpen) {
|
|
this._menuButton.arcMenu.actor._muteInput = false;
|
|
this._menuButton.arcMenu.actor._muteKeys = false;
|
|
}
|
|
super.open(animate);
|
|
}
|
|
|
|
close(animate) {
|
|
if (this.isOpen)
|
|
this._menuButton?.closeOtherMenus();
|
|
|
|
super.close(animate);
|
|
}
|
|
|
|
destroy() {
|
|
this._boxPointer.remove_effect_by_name('dim');
|
|
if (this._menuClosedID) {
|
|
this.disconnect(this._menuClosedID);
|
|
this._menuClosedID = null;
|
|
}
|
|
super.destroy();
|
|
this._dimEffect = null;
|
|
this._menuButton = null;
|
|
}
|
|
};
|
|
|
|
var ArcMenuContextMenu = class ArcMenuArcMenuContextMenu extends PopupMenu.PopupMenu {
|
|
constructor(sourceActor, arrowAlignment, arrowSide) {
|
|
super(sourceActor, arrowAlignment, arrowSide);
|
|
this._systemActions = SystemActions.getDefault();
|
|
|
|
this.actor.add_style_class_name('panel-menu app-menu');
|
|
Main.uiGroup.add_child(this.actor);
|
|
this.actor.hide();
|
|
|
|
ArcMenuManager.settings.connectObject('changed::context-menu-items',
|
|
() => this.populateMenuItems(), this);
|
|
|
|
this.populateMenuItems();
|
|
}
|
|
|
|
destroy() {
|
|
this.disconnectPowerOptions();
|
|
ArcMenuManager.settings.disconnectObject(this);
|
|
|
|
this._systemActions = null;
|
|
super.destroy();
|
|
}
|
|
|
|
populateMenuItems() {
|
|
this.disconnectPowerOptions();
|
|
this.removeAll();
|
|
|
|
const contextMenuShortcuts = ArcMenuManager.settings.get_value('context-menu-items').deep_unpack();
|
|
|
|
for (let i = 0; i < contextMenuShortcuts.length; i++) {
|
|
const {name, id} = contextMenuShortcuts[i];
|
|
|
|
if (id.endsWith('.desktop')) {
|
|
this.addSettingsAction(name, id);
|
|
} else if (id === Constants.ShortcutCommands.SEPARATOR) {
|
|
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
|
} else if (id === Constants.ShortcutCommands.SETTINGS) {
|
|
this.addAction(_('ArcMenu Settings'), () => ArcMenuManager.extension.openPreferences());
|
|
} else if (id.includes(Constants.ShortcutCommands.SETTINGS)) {
|
|
const settingsPage = id.replace(Constants.ShortcutCommands.SETTINGS, '');
|
|
if (settingsPage === 'About')
|
|
this.addArcMenuSettingsItem(name, Constants.SettingsPage.ABOUT);
|
|
else if (settingsPage === 'Menu')
|
|
this.addArcMenuSettingsItem(name, Constants.SettingsPage.CUSTOMIZE_MENU);
|
|
else if (settingsPage === 'Layout')
|
|
this.addArcMenuSettingsItem(name, Constants.SettingsPage.MENU_LAYOUT);
|
|
else if (settingsPage === 'Button')
|
|
this.addArcMenuSettingsItem(name, Constants.SettingsPage.BUTTON_APPEARANCE);
|
|
else if (settingsPage === 'Theme')
|
|
this.addArcMenuSettingsItem(name, Constants.SettingsPage.MENU_THEME);
|
|
} else if (id === Constants.ShortcutCommands.OVERVIEW) {
|
|
this.addAction(_('Activities Overview'), () => Main.overview.toggle());
|
|
} else if (id === Constants.ShortcutCommands.POWER_OPTIONS) {
|
|
this.addPowerOptionsMenuItem();
|
|
} else if (id === Constants.ShortcutCommands.SHOW_DESKTOP) {
|
|
this.addShowDekstopItem();
|
|
} else if (id === Constants.ShortcutCommands.PANEL_EXTENSION_SETTINGS) {
|
|
this.addExtensionSettings();
|
|
}
|
|
}
|
|
}
|
|
|
|
addArcMenuSettingsItem(title, prefsVisiblePage) {
|
|
const item = new PopupMenu.PopupMenuItem(_(title));
|
|
item.connect('activate', () => {
|
|
ArcMenuManager.settings.set_int('prefs-visible-page', prefsVisiblePage);
|
|
ArcMenuManager.extension.openPreferences();
|
|
});
|
|
this.addMenuItem(item);
|
|
}
|
|
|
|
disconnectPowerOptions() {
|
|
if (this.canSuspendId)
|
|
this._systemActions.disconnect(this.canSuspendId);
|
|
if (this.canSwitchUserId)
|
|
this._systemActions.disconnect(this.canSwitchUserId);
|
|
|
|
this.canSuspendId = null;
|
|
this.canSwitchUserId = null;
|
|
}
|
|
|
|
addShowDekstopItem() {
|
|
this.addAction(_('Show Desktop'), () => {
|
|
const currentWorkspace = global.workspace_manager.get_active_workspace();
|
|
let windows = currentWorkspace.list_windows().filter(w => {
|
|
return w.showing_on_its_workspace() && !w.skip_taskbar;
|
|
});
|
|
windows = global.display.sort_windows_by_stacking(windows);
|
|
|
|
windows.forEach(w => {
|
|
w.minimize();
|
|
});
|
|
});
|
|
}
|
|
|
|
addPowerOptionsMenuItem() {
|
|
const powerOptionsItem = new PopupMenu.PopupSubMenuMenuItem(_('Power Off / Log Out'));
|
|
|
|
const suspendItem = powerOptionsItem.menu.addAction(_('Suspend'),
|
|
() => this._systemActions.activateSuspend());
|
|
suspendItem.visible = this._systemActions.canSuspend;
|
|
powerOptionsItem.menu.addAction(_('Restart...'), () => this._systemActions.activateRestart());
|
|
powerOptionsItem.menu.addAction(_('Power Off...'), () => this._systemActions.activatePowerOff());
|
|
|
|
powerOptionsItem.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
|
|
|
powerOptionsItem.menu.addAction(_('Lock'), () => this._systemActions.activateLockScreen());
|
|
powerOptionsItem.menu.addAction(_('Log Out...'), () => this._systemActions.activateLogout());
|
|
const switchUserItem = powerOptionsItem.menu.addAction(_('Switch User'),
|
|
() => this._systemActions.activateSwitchUser());
|
|
switchUserItem.visible = this._systemActions.canSwitchUser;
|
|
|
|
this.canSuspendId = this._systemActions.connect('notify::can-suspend',
|
|
() => (suspendItem.visible = this._systemActions.canSuspend));
|
|
this.canSwitchUserId = this._systemActions.connect('notify::can-switch-user',
|
|
() => (switchUserItem.visible = this._systemActions.canSwitchUser));
|
|
|
|
this.addMenuItem(powerOptionsItem);
|
|
}
|
|
|
|
addSettingsAction(title, desktopFile) {
|
|
const app = Shell.AppSystem.get_default().lookup_app(desktopFile);
|
|
if (!app)
|
|
return;
|
|
|
|
if (!title)
|
|
title = app.get_name();
|
|
|
|
|
|
super.addSettingsAction(title, desktopFile);
|
|
}
|
|
|
|
addExtensionSettings() {
|
|
const dashToPanel = Main.extensionManager.lookup(Constants.DASH_TO_PANEL_UUID);
|
|
const azTaskbar = Main.extensionManager.lookup(Constants.AZTASKBAR_UUID);
|
|
|
|
if (dashToPanel?.state === Utils.ExtensionState.ACTIVE && global.dashToPanel) {
|
|
const item = new PopupMenu.PopupMenuItem(_('Dash to Panel Settings'));
|
|
item.connect('activate', () => Utils.openPrefs(Constants.DASH_TO_PANEL_UUID));
|
|
this.addMenuItem(item);
|
|
} else if (azTaskbar?.state === Utils.ExtensionState.ACTIVE && global.azTaskbar) {
|
|
const item = new PopupMenu.PopupMenuItem(_('App Icons Taskbar Settings'));
|
|
item.connect('activate', () => Utils.openPrefs(Constants.AZTASKBAR_UUID));
|
|
this.addMenuItem(item);
|
|
}
|
|
}
|
|
};
|