summaryrefslogtreecommitdiffstats
path: root/extensions/multi-monitors-add-on/multi-monitors-add-on@spin83/mmpanel.js
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/multi-monitors-add-on/multi-monitors-add-on@spin83/mmpanel.js')
-rw-r--r--extensions/multi-monitors-add-on/multi-monitors-add-on@spin83/mmpanel.js520
1 files changed, 520 insertions, 0 deletions
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);
+})();