From 4a62513b17d915afcae80b1adfb1b0cdcf86f748 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 5 Feb 2023 08:44:04 +0100 Subject: Adding upstream version 20230205. Signed-off-by: Daniel Baumann --- .../multi-monitors-add-on@spin83/mmpanel.js | 520 +++++++++++++++++++++ 1 file changed, 520 insertions(+) create mode 100644 extensions/multi-monitors-add-on/multi-monitors-add-on@spin83/mmpanel.js (limited to 'extensions/multi-monitors-add-on/multi-monitors-add-on@spin83/mmpanel.js') diff --git a/extensions/multi-monitors-add-on/multi-monitors-add-on@spin83/mmpanel.js b/extensions/multi-monitors-add-on/multi-monitors-add-on@spin83/mmpanel.js new file mode 100644 index 0000000..a381f15 --- /dev/null +++ b/extensions/multi-monitors-add-on/multi-monitors-add-on@spin83/mmpanel.js @@ -0,0 +1,520 @@ +/* +Copyright (C) 2014 spin83 + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, visit https://www.gnu.org/licenses/. +*/ + +const { St, Shell, Meta, Atk, Clutter, GObject } = imports.gi; + +const Main = imports.ui.main; +const Panel = imports.ui.panel; +const PopupMenu = imports.ui.popupMenu; +const PanelMenu = imports.ui.panelMenu; +const CtrlAltTab = imports.ui.ctrlAltTab; +const ExtensionSystem = imports.ui.extensionSystem; + +const ExtensionUtils = imports.misc.extensionUtils; +const CE = ExtensionUtils.getCurrentExtension(); +const MultiMonitors = CE.imports.extension; +const Convenience = CE.imports.convenience; +const MMCalendar = CE.imports.mmcalendar; + +const SHOW_ACTIVITIES_ID = 'show-activities'; +var SHOW_APP_MENU_ID = 'show-app-menu'; +const SHOW_DATE_TIME_ID = 'show-date-time'; +const AVAILABLE_INDICATORS_ID = 'available-indicators'; +const TRANSFER_INDICATORS_ID = 'transfer-indicators'; + +var StatusIndicatorsController = class StatusIndicatorsController { + constructor() { + this._transfered_indicators = []; + this._settings = Convenience.getSettings(); + + this._updatedSessionId = Main.sessionMode.connect('updated', this._updateSessionIndicators.bind(this)); + this._updateSessionIndicators(); + this._extensionStateChangedId = Main.extensionManager.connect('extension-state-changed', + this._extensionStateChanged.bind(this)); + + this._transferIndicatorsId = this._settings.connect('changed::'+TRANSFER_INDICATORS_ID, + this.transferIndicators.bind(this)); + } + + destroy() { + this._settings.disconnect(this._transferIndicatorsId); + Main.extensionManager.disconnect(this._extensionStateChangedId); + Main.sessionMode.disconnect(this._updatedSessionId); + this._settings.set_strv(AVAILABLE_INDICATORS_ID, []); + this._transferBack(this._transfered_indicators); + } + + transferBack(panel) { + let transfer_back = this._transfered_indicators.filter((element) => { + return element.monitor==panel.monitorIndex; + }); + + this._transferBack(transfer_back, panel); + } + + transferIndicators() { + let boxs = ['_leftBox', '_centerBox', '_rightBox']; + let transfers = this._settings.get_value(TRANSFER_INDICATORS_ID).deep_unpack(); + let show_app_menu = this._settings.get_value(SHOW_APP_MENU_ID); + + let transfer_back = this._transfered_indicators.filter((element) => { + return !transfers.hasOwnProperty(element.iname); + }); + + this._transferBack(transfer_back); + + for(let iname in transfers) { + if(transfers.hasOwnProperty(iname) && Main.panel.statusArea[iname]) { + let monitor = transfers[iname]; + + let indicator = Main.panel.statusArea[iname]; + let panel = this._findPanel(monitor); + boxs.forEach((box) => { + if(Main.panel[box].contains(indicator.container) && panel) { + global.log('a '+box+ " > " + iname + " : "+ monitor); + this._transfered_indicators.push({iname:iname, box:box, monitor:monitor}); + Main.panel[box].remove_child(indicator.container); + if (show_app_menu && box === '_leftBox') + panel[box].insert_child_at_index(indicator.container, 1); + else + panel[box].insert_child_at_index(indicator.container, 0); + } + }); + } + } + } + + _findPanel(monitor) { + for (let i = 0; i < Main.mmPanel.length; i++) { + if (Main.mmPanel[i].monitorIndex == monitor) { + return Main.mmPanel[i]; + } + } + return null; + } + + _transferBack(transfer_back, panel) { + transfer_back.forEach((element) => { + this._transfered_indicators.splice(this._transfered_indicators.indexOf(element)); + if(Main.panel.statusArea[element.iname]) { + let indicator = Main.panel.statusArea[element.iname]; + if(!panel) { + panel = this._findPanel(element.monitor); + } + if(panel[element.box].contains(indicator.container)) { + global.log("r "+element.box+ " > " + element.iname + " : "+ element.monitor); + panel[element.box].remove_child(indicator.container); + if (element.box === '_leftBox') + Main.panel[element.box].insert_child_at_index(indicator.container, 1); + else + Main.panel[element.box].insert_child_at_index(indicator.container, 0); + } + } + }); + } + + _extensionStateChanged() { + this._findAvailableIndicators(); + this.transferIndicators(); + } + + _updateSessionIndicators() { + let session_indicators = []; + session_indicators.push('MultiMonitorsAddOn'); + let sessionPanel = Main.sessionMode.panel; + for (let sessionBox in sessionPanel){ + sessionPanel[sessionBox].forEach((sesionIndicator) => { + session_indicators.push(sesionIndicator); + }); + } + this._session_indicators = session_indicators; + this._available_indicators = []; + + this._findAvailableIndicators(); + this.transferIndicators(); + } + + _findAvailableIndicators() { + let available_indicators = []; + let statusArea = Main.panel.statusArea; + for(let indicator in statusArea) { + if(statusArea.hasOwnProperty(indicator) && this._session_indicators.indexOf(indicator)<0){ + available_indicators.push(indicator); + } + } + if(available_indicators.length!=this._available_indicators.length) { + this._available_indicators = available_indicators; +// global.log(this._available_indicators); + this._settings.set_strv(AVAILABLE_INDICATORS_ID, this._available_indicators); + } + } +}; + +var MultiMonitorsAppMenuButton = (() => { + let MultiMonitorsAppMenuButton = class MultiMonitorsAppMenuButton extends PanelMenu.Button { + _init(panel) { + if (panel.monitorIndex==undefined) + this._monitorIndex = Main.layoutManager.primaryIndex; + else + this._monitorIndex = panel.monitorIndex; + this._actionOnWorkspaceGroupNotifyId = 0; + this._targetAppGroup = null; + this._lastFocusedWindow = null; + Panel.AppMenuButton.prototype._init.call(this, panel); + + this._windowEnteredMonitorId = global.display.connect('window-entered-monitor', + this._windowEnteredMonitor.bind(this)); + this._windowLeftMonitorId = global.display.connect('window-left-monitor', + this._windowLeftMonitor.bind(this)); + } + + _windowEnteredMonitor (metaScreen, monitorIndex, metaWin) { + if (monitorIndex == this._monitorIndex) { + switch(metaWin.get_window_type()){ + case Meta.WindowType.NORMAL: + case Meta.WindowType.DIALOG: + case Meta.WindowType.MODAL_DIALOG: + case Meta.WindowType.SPLASHSCREEN: + this._sync(); + break; + } + } + } + + _windowLeftMonitor (metaScreen, monitorIndex, metaWin) { + if (monitorIndex == this._monitorIndex) { + switch(metaWin.get_window_type()){ + case Meta.WindowType.NORMAL: + case Meta.WindowType.DIALOG: + case Meta.WindowType.MODAL_DIALOG: + case Meta.WindowType.SPLASHSCREEN: + this._sync(); + break; + } + } + } + + _findTargetApp() { + + if (this._actionOnWorkspaceGroupNotifyId) { + this._targetAppGroup.disconnect(this._actionOnWorkspaceGroupNotifyId); + this._actionOnWorkspaceGroupNotifyId = 0; + this._targetAppGroup = null; + } + let groupWindow = false; + let groupFocus = false; + + let workspaceManager = global.workspace_manager; + let workspace = workspaceManager.get_active_workspace(); + let tracker = Shell.WindowTracker.get_default(); + let focusedApp = tracker.focus_app; + if (focusedApp && focusedApp.is_on_workspace(workspace)){ + let windows = focusedApp.get_windows(); + for (let i = 0; i < windows.length; i++) { + let win = windows[i]; + if (win.located_on_workspace(workspace)){ + if (win.get_monitor() == this._monitorIndex){ + if (win.has_focus()){ + this._lastFocusedWindow = win; + // global.log(this._monitorIndex+": focus :"+win.get_title()+" : "+win.has_focus()); + return focusedApp; + } + else + groupWindow = true; + } + else { + if(win.has_focus()) + groupFocus = true; + } + if (groupFocus && groupWindow) { + if(focusedApp != this._targetApp){ + this._targetAppGroup = focusedApp; + this._actionOnWorkspaceGroupNotifyId = this._targetAppGroup.connect('notify::action-group', + this._sync.bind(this)); + // global.log(this._monitorIndex+": gConnect :"+win.get_title()+" : "+win.has_focus()); + } + break; + } + } + } + } + + for (let i = 0; i < this._startingApps.length; i++) + if (this._startingApps[i].is_on_workspace(workspace)){ + // global.log(this._monitorIndex+": newAppFocus"); + return this._startingApps[i]; + } + + if (this._lastFocusedWindow && this._lastFocusedWindow.located_on_workspace(workspace) && + this._lastFocusedWindow.get_monitor() == this._monitorIndex){ + // global.log(this._monitorIndex+": lastFocus :"+this._lastFocusedWindow.get_title()); + return tracker.get_window_app(this._lastFocusedWindow); + } + + let windows = global.display.get_tab_list(Meta.TabList.NORMAL_ALL, workspace); + + for (let i = 0; i < windows.length; i++) { + if(windows[i].get_monitor() == this._monitorIndex){ + this._lastFocusedWindow = windows[i]; + // global.log(this._monitorIndex+": appFind :"+windows[i].get_title()); + return tracker.get_window_app(windows[i]); + } + } + + return null; + } + + _sync() { + if (!this._switchWorkspaceNotifyId) + return; + Panel.AppMenuButton.prototype._sync.call(this); + } + + _onDestroy() { + if (this._actionGroupNotifyId) { + this._targetApp.disconnect(this._actionGroupNotifyId); + this._actionGroupNotifyId = 0; + } + + global.display.disconnect(this._windowEnteredMonitorId); + global.display.disconnect(this._windowLeftMonitorId); + + if (this._busyNotifyId) { + this._targetApp.disconnect(this._busyNotifyId); + this._busyNotifyId = 0; + } + + if (this.menu._windowsChangedId) { + this.menu._app.disconnect(this.menu._windowsChangedId); + this.menu._windowsChangedId = 0; + } + Panel.AppMenuButton.prototype._onDestroy.call(this); + } + }; + MultiMonitors.copyClass(Panel.AppMenuButton, MultiMonitorsAppMenuButton); + return GObject.registerClass({Signals: {'changed': {}},}, MultiMonitorsAppMenuButton); +})(); + +var MultiMonitorsActivitiesButton = (() => { + let MultiMonitorsActivitiesButton = class MultiMonitorsActivitiesButton extends PanelMenu.Button { + _init() { + super._init(0.0, null, true); + this.accessible_role = Atk.Role.TOGGLE_BUTTON; + + this.name = 'mmPanelActivities'; + + /* Translators: If there is no suitable word for "Activities" + in your language, you can use the word for "Overview". */ + this._label = new St.Label({ text: _("Activities"), + y_align: Clutter.ActorAlign.CENTER }); + this.add_actor(this._label); + + this.label_actor = this._label; + + this._showingId = Main.overview.connect('showing', () => { + this.add_style_pseudo_class('overview'); + this.add_accessible_state (Atk.StateType.CHECKED); + }); + this._hidingId = Main.overview.connect('hiding', () => { + this.remove_style_pseudo_class('overview'); + this.remove_accessible_state (Atk.StateType.CHECKED); + }); + + this._xdndTimeOut = 0; + } + + _onDestroy() { + Main.overview.disconnect(this._showingId); + Main.overview.disconnect(this._hidingId); + super._onDestroy(); + } + } + MultiMonitors.copyClass(Panel.ActivitiesButton, MultiMonitorsActivitiesButton); + return GObject.registerClass(MultiMonitorsActivitiesButton); +})(); + +const MULTI_MONITOR_PANEL_ITEM_IMPLEMENTATIONS = { + 'activities': MultiMonitorsActivitiesButton, + 'appMenu': MultiMonitorsAppMenuButton, + 'dateMenu': MMCalendar.MultiMonitorsDateMenuButton, +}; + +var MultiMonitorsPanel = (() => { + let MultiMonitorsPanel = class MultiMonitorsPanel extends St.Widget { + _init(monitorIndex, mmPanelBox) { + super._init({ name: 'panel', + reactive: true }); + + this.monitorIndex = monitorIndex; + + this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); + + this._sessionStyle = null; + + this.statusArea = {}; + + this.menuManager = new PopupMenu.PopupMenuManager(this); + + this._leftBox = new St.BoxLayout({ name: 'panelLeft' }); + this.add_child(this._leftBox); + this._centerBox = new St.BoxLayout({ name: 'panelCenter' }); + this.add_child(this._centerBox); + this._rightBox = new St.BoxLayout({ name: 'panelRight' }); + this.add_child(this._rightBox); + + this._showingId = Main.overview.connect('showing', () => { + this.add_style_pseudo_class('overview'); + }); + this._hidingId = Main.overview.connect('hiding', () => { + this.remove_style_pseudo_class('overview'); + }); + + mmPanelBox.panelBox.add(this); + Main.ctrlAltTabManager.addGroup(this, _("Top Bar"), 'focus-top-bar-symbolic', + { sortGroup: CtrlAltTab.SortGroup.TOP }); + + this._updatedId = Main.sessionMode.connect('updated', this._updatePanel.bind(this)); + + this._workareasChangedId = global.display.connect('workareas-changed', () => this.queue_relayout()); + this._updatePanel(); + + this._settings = Convenience.getSettings(); + this._showActivitiesId = this._settings.connect('changed::'+SHOW_ACTIVITIES_ID, + this._showActivities.bind(this)); + this._showActivities(); + + this._showAppMenuId = this._settings.connect('changed::'+SHOW_APP_MENU_ID, + this._showAppMenu.bind(this)); + this._showAppMenu(); + + this._showDateTimeId = this._settings.connect('changed::'+SHOW_DATE_TIME_ID, + this._showDateTime.bind(this)); + this._showDateTime(); + + this.connect('destroy', this._onDestroy.bind(this)); + } + + _onDestroy() { + global.display.disconnect(this._workareasChangedId); + Main.overview.disconnect(this._showingId); + Main.overview.disconnect(this._hidingId); + + this._settings.disconnect(this._showActivitiesId); + this._settings.disconnect(this._showAppMenuId); + this._settings.disconnect(this._showDateTimeId); + + Main.ctrlAltTabManager.removeGroup(this); + Main.sessionMode.disconnect(this._updatedId); + } + + _showActivities() { + let name = 'activities'; + if (this._settings.get_boolean(SHOW_ACTIVITIES_ID)) { + if (this.statusArea[name]) + this.statusArea[name].visible = true; + } + else { + if (this.statusArea[name]) + this.statusArea[name].visible = false; + } + } + + _showDateTime() { + let name = 'dateMenu'; + if (this._settings.get_boolean(SHOW_DATE_TIME_ID)) { + if (this.statusArea[name]) + this.statusArea[name].visible = true; + } + else { + if (this.statusArea[name]) + this.statusArea[name].visible = false; + } + } + + _showAppMenu() { + let name = 'appMenu'; + if (this._settings.get_boolean(SHOW_APP_MENU_ID)) { + if (!this.statusArea[name]) { + let indicator = new MultiMonitorsAppMenuButton(this); + this.statusArea[name] = indicator; + let box = this._leftBox; + this._addToPanelBox(name, indicator, box.get_n_children()+1, box); + } + } + else { + if (this.statusArea[name]) { + let indicator = this.statusArea[name]; + this.menuManager.removeMenu(indicator.menu); + indicator.destroy(); + delete this.statusArea[name]; + } + } + } + + vfunc_get_preferred_width(forHeight) { + if (Main.layoutManager.monitors.length>this.monitorIndex) + return [0, Main.layoutManager.monitors[this.monitorIndex].width]; + + return [0, 0]; + } + + _hideIndicators() { + for (let role in MULTI_MONITOR_PANEL_ITEM_IMPLEMENTATIONS) { + let indicator = this.statusArea[role]; + if (!indicator) + continue; + indicator.container.hide(); + } + } + + _ensureIndicator(role) { + let indicator = this.statusArea[role]; + if (indicator) { + indicator.container.show(); + return null; + } + else { + let constructor = MULTI_MONITOR_PANEL_ITEM_IMPLEMENTATIONS[role]; + if (!constructor) { + // This icon is not implemented (this is a bug) + return null; + } + indicator = new constructor(this); + this.statusArea[role] = indicator; + } + return indicator; + } + + _getDraggableWindowForPosition(stageX) { + let workspaceManager = global.workspace_manager; + const windows = workspaceManager.get_active_workspace().list_windows(); + const allWindowsByStacking = + global.display.sort_windows_by_stacking(windows).reverse(); + + return allWindowsByStacking.find(metaWindow => { + let rect = metaWindow.get_frame_rect(); + return metaWindow.get_monitor() == this.monitorIndex && + metaWindow.showing_on_its_workspace() && + metaWindow.get_window_type() != Meta.WindowType.DESKTOP && + metaWindow.maximized_vertically && + stageX > rect.x && stageX < rect.x + rect.width; + }); + }}; + + MultiMonitors.copyClass(Panel.Panel, MultiMonitorsPanel); + return GObject.registerClass(MultiMonitorsPanel); +})(); -- cgit v1.2.3