summaryrefslogtreecommitdiffstats
path: root/extensions/vertical-workspaces/lib/dash.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--extensions/vertical-workspaces/lib/dash.js (renamed from extensions/vertical-workspaces/dash.js)565
1 files changed, 461 insertions, 104 deletions
diff --git a/extensions/vertical-workspaces/dash.js b/extensions/vertical-workspaces/lib/dash.js
index c4e3101..bf832bd 100644
--- a/extensions/vertical-workspaces/dash.js
+++ b/extensions/vertical-workspaces/lib/dash.js
@@ -1,5 +1,5 @@
/**
- * Vertical Workspaces
+ * V-Shell (Vertical Workspaces)
* dash.js
*
* @author GdH <G-dH@github.com>
@@ -8,7 +8,7 @@
* modified dash module of https://github.com/RensAlthuis/vertical-overview extension
*/
-const { Clutter, GLib, GObject, Graphene, Meta, Shell, St } = imports.gi;
+const { Clutter, GObject, St, Shell, Meta } = imports.gi;
const AppDisplay = imports.ui.appDisplay;
const AppFavorites = imports.ui.appFavorites;
const DND = imports.ui.dnd;
@@ -16,42 +16,54 @@ const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const Overview = imports.ui.overview;
const Dash = imports.ui.dash;
-const { DashIcon, DashItemContainer, getAppFromSource, DragPlaceholderItem } = imports.ui.dash;
+const PopupMenu = imports.ui.popupMenu;
+const { AppMenu } = imports.ui.appMenu;
+const BoxPointer = imports.ui.boxpointer;
+const AltTab = imports.ui.altTab;
const Me = imports.misc.extensionUtils.getCurrentExtension();
-const Util = Me.imports.util;
-const _ = Me.imports.settings._;
+const Util = Me.imports.lib.util;
+const _ = Me.imports.lib.settings._;
-let verticalOverrides = {};
+const shellVersion = Util.shellVersion;
let _origWorkId;
let _newWorkId;
let _showAppsIconBtnPressId;
-// added values to achieve better ability to scale down according the available space
+// added values to achieve a better ability to scale down according to available space
var BaseIconSizes = [16, 24, 32, 40, 44, 48, 56, 64, 72, 80, 96, 112, 128];
-const RecentFilesSearchProviderPrefix = Me.imports.recentFilesSearchProvider.prefix;
-const WindowSearchProviderPrefix = Me.imports.windowSearchProvider.prefix;
+const RecentFilesSearchProviderPrefix = Me.imports.lib.recentFilesSearchProvider.prefix;
+const WindowSearchProviderPrefix = Me.imports.lib.windowSearchProvider.prefix;
let _overrides;
+let opt;
+let _firstRun = true;
const DASH_ITEM_LABEL_SHOW_TIME = 150;
-let opt;
-
function update(reset = false) {
- if (_overrides) {
+ opt = Me.imports.lib.settings.opt;
+ const moduleEnabled = opt.get('dashModule', true);
+ reset = reset || !moduleEnabled;
+
+ // don't even touch this module if disabled
+ if (_firstRun && reset)
+ return;
+
+ _firstRun = false;
+
+ if (_overrides)
_overrides.removeAll();
- }
-
- opt = Me.imports.settings.opt;
+
+
const dash = Main.overview._overview._controls.layoutManager._dash;
setToHorizontal();
- dash.remove_style_class_name("vertical-overview");
- dash.remove_style_class_name("vertical-overview-left");
- dash.remove_style_class_name("vertical-overview-right");
+ dash.remove_style_class_name('vertical');
+ dash.remove_style_class_name('vertical-left');
+ dash.remove_style_class_name('vertical-right');
if (reset) {
_moveDashAppGridIcon(reset);
@@ -60,6 +72,7 @@ function update(reset = false) {
_updateRecentFilesIcon(false);
dash.visible = true;
dash._background.opacity = 255;
+ dash._background.remove_style_class_name('v-shell-dash-background');
_overrides = null;
opt = null;
return;
@@ -67,13 +80,15 @@ function update(reset = false) {
_overrides = new Util.Overrides();
- _overrides.addOverride('DashItemContainer', Dash.DashItemContainer.prototype, DashItemContainerOverride);
- _overrides.addOverride('DashCommon', Dash.Dash.prototype, DashCommonOverride);
+ _overrides.addOverride('DashItemContainer', Dash.DashItemContainer.prototype, DashItemContainerCommon);
+ _overrides.addOverride('DashCommon', Dash.Dash.prototype, DashCommon);
+ _overrides.addOverride('AppIcon', AppDisplay.AppIcon.prototype, AppIconCommon);
+ _overrides.addOverride('DashIcon', Dash.DashIcon.prototype, DashIconCommon);
if (opt.DASH_VERTICAL) {
_overrides.addOverride('Dash', Dash.Dash.prototype, DashOverride);
setToVertical();
- dash.add_style_class_name("vertical-overview");
+ dash.add_style_class_name('vertical');
if (!_newWorkId) {
_origWorkId = dash._workId;
@@ -93,14 +108,15 @@ function update(reset = false) {
_moveDashAppGridIcon();
_connectShowAppsIcon();
- if (dash._showWindowsIcon && !dash._showWindowsIconClickedId) {
+ if (dash._showWindowsIcon && !dash._showWindowsIconClickedId)
dash._showWindowsIconClickedId = dash._showWindowsIcon.toggleButton.connect('clicked', (a, c) => c && Util.activateSearchProvider(WindowSearchProviderPrefix));
- }
- if (dash._recentFilesIcon && !dash._recentFilesIconClickedId) {
+
+ if (dash._recentFilesIcon && !dash._recentFilesIconClickedId)
dash._recentFilesIconClickedId = dash._recentFilesIcon.toggleButton.connect('clicked', (a, c) => c && Util.activateSearchProvider(RecentFilesSearchProviderPrefix));
- }
- Main.overview.dash._redisplay();
- Main.overview._overview._controls.layoutManager._dash.visible = opt.DASH_VISIBLE;
+
+ dash.visible = opt.DASH_VISIBLE;
+ dash._background.add_style_class_name('v-shell-dash-background');
+ dash._redisplay();
}
function setToVertical() {
@@ -128,13 +144,13 @@ function setToVertical() {
dash._queueRedisplay();
dash._adjustIconSize();
- dash.add_style_class_name(opt.DASH_LEFT ? 'vertical-overview-left' : 'vertical-overview-right');
+ dash.add_style_class_name(opt.DASH_LEFT ? 'vertical-left' : 'vertical-right');
}
function setToHorizontal() {
let dash = Main.overview._overview._controls.layoutManager._dash;
if (_origWorkId)
- dash._workId = _origWorkId; //pretty sure this is a leak, but there no provided way to disconnect these...
+ dash._workId = _origWorkId; // pretty sure this is a leak, but there no provided way to disconnect these...
dash._box.layout_manager.orientation = Clutter.Orientation.HORIZONTAL;
dash._dashContainer.layout_manager.orientation = Clutter.Orientation.HORIZONTAL;
dash._dashContainer.y_expand = true;
@@ -173,7 +189,7 @@ function _moveDashAppGridIcon(reset = false) {
const index = dash._dashContainer.get_children().length - 1;
dash._dashContainer.set_child_at_index(dash._showAppsIcon, index);
}
- if (!reset && appIconPosition === 2) {// 2 - hide
+ if (!reset && appIconPosition === 2) { // 2 - hide
const style = opt.DASH_VERTICAL ? 'show-apps-icon-vertical-hide' : 'show-apps-icon-horizontal-hide';
dash._showAppsIcon.add_style_class_name(style);
// for some reason even if the icon height in vertical mode should be set to 0 by the style, it stays visible in full size returning height 1px
@@ -191,29 +207,27 @@ function _connectShowAppsIcon(reset = false) {
Main.overview.dash._showAppsIcon.reactive = true;
_showAppsIconBtnPressId = Main.overview.dash._showAppsIcon.connect('button-press-event', (actor, event) => {
const button = event.get_button();
- if (button === Clutter.BUTTON_MIDDLE) {
+ if (button === Clutter.BUTTON_MIDDLE)
Util.openPreferences();
- } else if (button === Clutter.BUTTON_SECONDARY) {
+ else if (button === Clutter.BUTTON_SECONDARY)
Util.activateSearchProvider(WindowSearchProviderPrefix);
- } else {
+ else
return Clutter.EVENT_PROPAGATE;
- }
+ return Clutter.EVENT_STOP;
});
- } else {
- if (_showAppsIconBtnPressId) {
- Main.overview.dash._showAppsIcon.disconnect(_showAppsIconBtnPressId);
- _showAppsIconBtnPressId = 0;
- Main.overview.dash._showAppsIcon.reactive = false;
- }
+ } else if (_showAppsIconBtnPressId) {
+ Main.overview.dash._showAppsIcon.disconnect(_showAppsIconBtnPressId);
+ _showAppsIconBtnPressId = 0;
+ Main.overview.dash._showAppsIcon.reactive = false;
}
}
-var DashOverride = {
- handleDragOver: function (source, actor, _x, y, _time) {
- let app = getAppFromSource(source);
+const DashOverride = {
+ handleDragOver(source, actor, _x, y, _time) {
+ let app = Dash.getAppFromSource(source);
// Don't allow favoriting of transient apps
- if (app == null || app.is_window_backed())
+ if (app === null || app.is_window_backed())
return DND.DragMotionResult.NO_DROP;
if (!global.settings.is_writable('favorite-apps'))
@@ -257,7 +271,7 @@ var DashOverride = {
this._dragPlaceholderPos = pos;
// Don't allow positioning before or after self
- if (favPos != -1 && (pos == favPos || pos == favPos + 1)) {
+ if (favPos !== -1 && (pos === favPos || pos === favPos + 1)) {
this._clearDragPlaceholder();
return DND.DragMotionResult.CONTINUE;
}
@@ -273,7 +287,7 @@ var DashOverride = {
fadeIn = true;
}
- this._dragPlaceholder = new DragPlaceholderItem();
+ this._dragPlaceholder = new Dash.DragPlaceholderItem();
this._dragPlaceholder.child.set_width(this.iconSize / 2);
this._dragPlaceholder.child.set_height(this.iconSize);
this._box.insert_child_at_index(this._dragPlaceholder,
@@ -284,7 +298,7 @@ var DashOverride = {
if (!this._dragPlaceholder)
return DND.DragMotionResult.NO_DROP;
- let srcIsFavorite = favPos != -1;
+ let srcIsFavorite = favPos !== -1;
if (srcIsFavorite)
return DND.DragMotionResult.MOVE_DROP;
@@ -292,7 +306,7 @@ var DashOverride = {
return DND.DragMotionResult.COPY_DROP;
},
- _redisplay: function () {
+ _redisplay() {
let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
let running = this._appSystem.get_running();
@@ -343,7 +357,7 @@ var DashOverride = {
let newApp = newApps.length > newIndex ? newApps[newIndex] : null;
// No change at oldIndex/newIndex
- if (oldApp == newApp) {
+ if (oldApp === newApp) {
oldIndex++;
newIndex++;
continue;
@@ -361,7 +375,7 @@ var DashOverride = {
addedItems.push({
app: newApp,
item: this._createAppItem(newApp),
- pos: newIndex
+ pos: newIndex,
});
newIndex++;
continue;
@@ -370,10 +384,10 @@ var DashOverride = {
// App moved
let nextApp = newApps.length > newIndex + 1
? newApps[newIndex + 1] : null;
- let insertHere = nextApp && nextApp == oldApp;
+ let insertHere = nextApp && nextApp === oldApp;
let alreadyRemoved = removedActors.reduce((result, actor) => {
let removedApp = actor.child._delegate.app;
- return result || removedApp == newApp;
+ return result || removedApp === newApp;
}, false);
if (insertHere || alreadyRemoved) {
@@ -381,7 +395,7 @@ var DashOverride = {
addedItems.push({
app: newApp,
item: newItem,
- pos: newIndex + removedActors.length
+ pos: newIndex + removedActors.length,
});
newIndex++;
} else {
@@ -439,10 +453,10 @@ var DashOverride = {
width: this.iconSize,
height: 1,
});
- this._box.add_child(this._separator)
+ this._box.add_child(this._separator);
}
- //FIXME: separator placement is broken (also in original dash)
+ // FIXME: separator placement is broken (also in original dash)
let pos = nFavorites;
if (this._dragPlaceholder)
pos++;
@@ -456,8 +470,8 @@ var DashOverride = {
this._box.queue_relayout();
},
- _createAppItem: function (app) {
- let appIcon = new DashIcon(app);
+ _createAppItem(app) {
+ let appIcon = new Dash.DashIcon(app);
let indicator = appIcon._dot;
indicator.x_align = opt.DASH_LEFT ? Clutter.ActorAlign.START : Clutter.ActorAlign.END;
@@ -468,7 +482,7 @@ var DashOverride = {
this._itemMenuStateChanged(item, opened);
});
- let item = new DashItemContainer();
+ let item = new Dash.DashItemContainer();
item.setChild(appIcon);
// Override default AppIcon label_actor, now the
@@ -480,12 +494,12 @@ var DashOverride = {
this._hookUpLabel(item, appIcon);
return item;
- }
-}
+ },
+};
-var DashItemContainerOverride = {
+const DashItemContainerCommon = {
// move labels according dash position
- showLabel: function() {
+ showLabel() {
if (!this._labelText)
return;
@@ -500,7 +514,7 @@ var DashItemContainerOverride = {
const labelWidth = this.label.get_width();
const labelHeight = this.label.get_height();
- const xOffset = Math.floor((itemWidth - labelWidth) / 2);
+ let xOffset = Math.floor((itemWidth - labelWidth) / 2);
let x = Math.clamp(stageX + xOffset, 0, global.stage.width - labelWidth);
let node = this.label.get_theme_node();
@@ -509,23 +523,18 @@ var DashItemContainerOverride = {
if (opt.DASH_TOP) {
const yOffset = itemHeight - labelHeight + 3 * node.get_length('-y-offset');
y = stageY + yOffset;
-
} else if (opt.DASH_BOTTOM) {
const yOffset = node.get_length('-y-offset');
y = stageY - this.label.height - yOffset;
-
} else if (opt.DASH_RIGHT) {
const yOffset = Math.floor((itemHeight - labelHeight) / 2);
-
- const xOffset = 4;
+ xOffset = 4;
x = stageX - xOffset - this.label.width;
y = Math.clamp(stageY + yOffset, 0, global.stage.height - labelHeight);
-
- } if (opt.DASH_LEFT) {
+ } else if (opt.DASH_LEFT) {
const yOffset = Math.floor((itemHeight - labelHeight) / 2);
-
- const xOffset = 4;
+ xOffset = 4;
x = stageX + this.width + xOffset;
y = Math.clamp(stageY + yOffset, 0, global.stage.height - labelHeight);
@@ -544,11 +553,17 @@ var DashItemContainerOverride = {
duration: DASH_ITEM_LABEL_SHOW_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
});
- }
-}
+ },
+};
+
+const DashCommon = {
+ // use custom BaseIconSizes and add support for custom icons
+ _adjustIconSize() {
+ // if a user launches multiple apps at once, this function may be called again before the previous call has finished
+ // as a result, new icons will not reach their full size, or will be missing, if adding a new icon and changing the dash size due to lack of space at the same time
+ if (this._adjustingInProgress)
+ return;
-var DashCommonOverride = {
- _adjustIconSize: function () {
// For the icon size, we only consider children which are "proper"
// icons (i.e. ignoring drag placeholders) and which are not
// animating out (which means they will be destroyed at the end of
@@ -560,18 +575,19 @@ var DashCommonOverride = {
!actor.animatingOut;
});
- // add new custom icons into the calculation
- if (this._showAppsIcon.visible) {
+ // add new custom icons to the list
+ if (this._showAppsIcon.visible)
iconChildren.push(this._showAppsIcon);
- }
- if (this._showWindowsIcon) {
+
+ if (this._showWindowsIcon)
iconChildren.push(this._showWindowsIcon);
- }
- if (this._recentFilesIcon) {
+
+ if (this._recentFilesIcon)
iconChildren.push(this._recentFilesIcon);
- }
- if (!iconChildren.length) return;
+
+ if (!iconChildren.length)
+ return;
if (this._maxWidth === -1 || this._maxHeight === -1)
return;
@@ -593,12 +609,14 @@ var DashCommonOverride = {
let firstButton = iconChildren[0].child;
let firstIcon = firstButton._delegate.icon;
- if (!firstIcon.icon) return;
+ if (!firstIcon.icon)
+ return;
// Enforce valid spacings during the size request
firstIcon.icon.ensure_style();
const [, , iconWidth, iconHeight] = firstIcon.icon.get_preferred_size();
const [, , buttonWidth, buttonHeight] = firstButton.get_preferred_size();
+ let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
let availWidth, availHeight, maxIconSize;
if (dashHorizontal) {
@@ -614,7 +632,7 @@ var DashCommonOverride = {
availHeight -= themeNode.get_vertical_padding();
availHeight -= buttonHeight - iconHeight;
- maxIconSize = Math.min(availWidth / iconChildren.length, availHeight, opt.MAX_ICON_SIZE);
+ maxIconSize = Math.min(availWidth / iconChildren.length, availHeight, opt.MAX_ICON_SIZE * scaleFactor);
} else {
availWidth = this._maxWidth;
availWidth -= this._background.get_theme_node().get_horizontal_padding();
@@ -626,10 +644,9 @@ var DashCommonOverride = {
(iconChildren.length - 1) * spacing +
2 * this._background.get_theme_node().get_vertical_padding();
- maxIconSize = Math.min(availWidth, availHeight / iconChildren.length, opt.MAX_ICON_SIZE);
+ maxIconSize = Math.min(availWidth, availHeight / iconChildren.length, opt.MAX_ICON_SIZE * scaleFactor);
}
- let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
let iconSizes = BaseIconSizes.map(s => s * scaleFactor);
let newIconSize = BaseIconSizes[0];
@@ -638,8 +655,11 @@ var DashCommonOverride = {
newIconSize = BaseIconSizes[i];
}
- /*if (newIconSize == this.iconSize)
- return;*/
+ if (newIconSize === this.iconSize)
+ return;
+
+ // set the in-progress state here after all the possible cancels
+ this._adjustingInProgress = true;
let oldIconSize = this.iconSize;
this.iconSize = newIconSize;
@@ -665,7 +685,7 @@ var DashCommonOverride = {
// Scale the icon's texture to the previous size and
// tween to the new size
icon.icon.set_size(icon.icon.width * scale,
- icon.icon.height * scale);
+ icon.icon.height * scale);
icon.icon.ease({
width: targetWidth,
@@ -683,23 +703,351 @@ var DashCommonOverride = {
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
});
}
+
+ this._adjustingInProgress = false;
+ },
+};
+
+const DashIconCommon = {
+ after__init() {
+ if (opt.DASH_ICON_SCROLL) {
+ this._scrollConId = this.connect('scroll-event', _onScrollEvent.bind(this));
+ this._leaveConId = this.connect('leave-event', _onLeaveEvent.bind(this));
+ }
},
+};
+
+function _onScrollEvent(source, event) {
+ if ((this.app && !opt.DASH_ICON_SCROLL) || (this._isSearchWindowsIcon && !opt.SEARCH_WINDOWS_ICON_SCROLL)) {
+ if (this._scrollConId)
+ this.disconnect(this._scrollConId);
+ if (this._leaveConId)
+ this.disconnect(this._leaveConId);
+ return Clutter.EVENT_PROPAGATE;
+ }
+
+ let direction = Util.getScrollDirection(event);
+ if (direction === Clutter.ScrollDirection.UP)
+ direction = 1;
+ else if (direction === Clutter.ScrollDirection.DOWN)
+ direction = -1;
+ else
+ return Clutter.EVENT_STOP;
+
+ // avoid uncontrollable switching if smooth scroll wheel or trackpad is used
+ if (this._lastScroll && Date.now() - this._lastScroll < 160)
+ return Clutter.EVENT_STOP;
+
+ this._lastScroll = Date.now();
+
+ _switchWindow.bind(this)(direction);
+ return Clutter.EVENT_STOP;
}
-function _updateSearchWindowsIcon(show = opt.SHOW_WINDOWS_ICON) {
+function _onLeaveEvent() {
+ if (!this._selectedMetaWin || this.has_pointer || this.toggleButton?.has_pointer)
+ return;
+
+ this._selectedPreview._activateSelected = false;
+ this._selectedMetaWin = null;
+ this._scrolledWindows = null;
+ _showWindowPreview.bind(this)(null);
+}
+
+function _switchWindow(direction) {
+ if (!this._scrolledWindows) {
+ // source is app icon
+ if (this.app) {
+ this._scrolledWindows = this.app.get_windows();
+ const wsList = [];
+ this._scrolledWindows.forEach(w => {
+ const ws = w.get_workspace();
+ if (!wsList.includes(ws))
+ wsList.push(ws);
+ });
+ // sort windows by workspaces in MRU order
+ this._scrolledWindows.sort((a, b) => wsList.indexOf(a.get_workspace()) > wsList.indexOf(b.get_workspace()));
+ // source is Search Windows icon
+ } else if (this._isSearchWindowsIcon) {
+ if (opt.SEARCH_WINDOWS_ICON_SCROLL === 1) // all windows
+ this._scrolledWindows = AltTab.getWindows(null);
+ else
+ this._scrolledWindows = AltTab.getWindows(global.workspace_manager.get_active_workspace());
+ }
+ }
+ let windows = this._scrolledWindows;
+
+ if (!windows.length)
+ return;
+
+ // if window selection is in the process, the previewed window must be the current one
+ let currentWin = this._selectedMetaWin ? this._selectedMetaWin : windows[0];
+
+ const currentIdx = windows.indexOf(currentWin);
+ let targetIdx = currentIdx + direction;
+
+ if (targetIdx > windows.length - 1)
+ targetIdx = 0;
+ else if (targetIdx < 0)
+ targetIdx = windows.length - 1;
+
+ const metaWin = windows[targetIdx];
+ _showWindowPreview.bind(this)(metaWin);
+ this._selectedMetaWin = metaWin;
+}
+
+function _showWindowPreview(metaWin) {
+ const views = Main.overview._overview.controls._workspacesDisplay._workspacesViews;
+ const viewsIter = [views[0]];
+ // secondary monitors use different structure
+ views.forEach(v => {
+ if (v._workspacesView)
+ viewsIter.push(v._workspacesView);
+ });
+
+ viewsIter.forEach(view => {
+ // if workspaces are on primary monitor only
+ if (!view || !view._workspaces)
+ return;
+
+ view._workspaces.forEach(ws => {
+ ws._windows.forEach(windowPreview => {
+ // metaWin === null resets opacity
+ let opacity = metaWin ? 50 : 255;
+ windowPreview._activateSelected = false;
+
+ // minimized windows are invisible if windows are not exposed (WORKSPACE_MODE === 0)
+ if (!windowPreview.opacity)
+ windowPreview.opacity = 255;
+
+ // app windows set to lower opacity, so they can be recognized
+ if (this._scrolledWindows && this._scrolledWindows.includes(windowPreview.metaWindow)) {
+ if (opt.DASH_ICON_SCROLL === 2)
+ opacity = 254;
+ }
+ if (windowPreview.metaWindow === metaWin) {
+ if (metaWin && metaWin.get_workspace() !== global.workspace_manager.get_active_workspace())
+ Main.wm.actionMoveWorkspace(metaWin.get_workspace());
+
+ windowPreview.get_parent().set_child_above_sibling(windowPreview, null);
+
+ opacity = 255;
+ this._selectedPreview = windowPreview;
+ windowPreview._activateSelected = true;
+ }
+
+ // if windows are exposed, highlight selected using opacity
+ if ((opt.OVERVIEW_MODE && opt.WORKSPACE_MODE) || !opt.OVERVIEW_MODE) {
+ if (metaWin && opacity === 255)
+ windowPreview.showOverlay(true);
+ else
+ windowPreview.hideOverlay(true);
+ windowPreview.ease({
+ duration: 200,
+ opacity,
+ mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+ });
+ }
+ });
+ });
+ });
+}
+
+const AppIconCommon = {
+ activate(button) {
+ const event = Clutter.get_current_event();
+ const state = event ? event.get_state() : 0;
+ const isMiddleButton = button && button === Clutter.BUTTON_MIDDLE;
+ const isCtrlPressed = Util.isCtrlPressed(state);
+ const isShiftPressed = Util.isShiftPressed(state);
+ const openNewWindow = (this.app.can_open_new_window() &&
+ this.app.state === Shell.AppState.RUNNING &&
+ (isCtrlPressed || isMiddleButton) && !opt.DASH_CLICK_ACTION === 2) ||
+ (opt.DASH_CLICK_ACTION === 2 && !this._selectedMetaWin && !isMiddleButton);
+
+ const currentWS = global.workspace_manager.get_active_workspace();
+ const appRecentWorkspace = _getAppRecentWorkspace(this.app);
+ // this feature shouldn't affect search results, dash icons don't have labels, so we use them as a condition
+ const showWidowsBeforeActivation = opt.DASH_CLICK_ACTION === 1 && !this.icon.label;
+
+ let targetWindowOnCurrentWs = false;
+ if (opt.DASH_FOLLOW_RECENT_WIN) {
+ targetWindowOnCurrentWs = appRecentWorkspace === currentWS;
+ } else {
+ this.app.get_windows().forEach(
+ w => {
+ targetWindowOnCurrentWs = targetWindowOnCurrentWs || (w.get_workspace() === currentWS);
+ }
+ );
+ }
+
+ if ((this.app.state === Shell.AppState.STOPPED || openNewWindow) && !isShiftPressed)
+ this.animateLaunch();
+
+ if (openNewWindow) {
+ this.app.open_new_window(-1);
+ // if DASH_CLICK_ACTION == "SHOW_WINS_BEFORE", the app has more than one window and has no window on the current workspace,
+ // don't activate the app immediately, only move the overview to the workspace with the app's recent window
+ } else if (showWidowsBeforeActivation && !isShiftPressed && this.app.get_n_windows() > 1 && !targetWindowOnCurrentWs/* && !(opt.OVERVIEW_MODE && !opt.WORKSPACE_MODE)*/) {
+ // this._scroll = true;
+ // this._scrollTime = Date.now();
+ Main.wm.actionMoveWorkspace(appRecentWorkspace);
+ Main.overview.dash.showAppsButton.checked = false;
+ return;
+ } else if (this._selectedMetaWin) {
+ this._selectedMetaWin.activate(global.get_current_time());
+ } else if (showWidowsBeforeActivation && opt.OVERVIEW_MODE && !opt.WORKSPACE_MODE && !isShiftPressed && this.app.get_n_windows() > 1) {
+ // expose windows
+ Main.overview._overview._controls._thumbnailsBox._activateThumbnailAtPoint(0, 0, global.get_current_time(), true);
+ return;
+ } else if (opt.DASH_SHIFT_CLICK_MV && isShiftPressed && this.app.get_windows().length) {
+ this._moveAppToCurrentWorkspace();
+ return;
+ } else if (isShiftPressed) {
+ return;
+ } else {
+ this.app.activate();
+ }
+
+ Main.overview.hide();
+ },
+
+ _moveAppToCurrentWorkspace() {
+ this.app.get_windows().forEach(w => w.change_workspace(global.workspace_manager.get_active_workspace()));
+ },
+
+ popupMenu(side = St.Side.LEFT) {
+ if (shellVersion >= 42)
+ this.setForcedHighlight(true);
+ this._removeMenuTimeout();
+ this.fake_release();
+
+ if (!this._getWindowsOnCurrentWs) {
+ this._getWindowsOnCurrentWs = function () {
+ const winList = [];
+ this.app.get_windows().forEach(w => {
+ if (w.get_workspace() === global.workspace_manager.get_active_workspace())
+ winList.push(w);
+ });
+ return winList;
+ };
+
+ this._windowsOnOtherWs = function () {
+ return (this.app.get_windows().length - this._getWindowsOnCurrentWs().length) > 0;
+ };
+ }
+
+ if (!this._menu) {
+ this._menu = new AppMenu(this, side, {
+ favoritesSection: true,
+ showSingleWindows: true,
+ });
+
+ this._menu.setApp(this.app);
+ this._openSigId = this._menu.connect('open-state-changed', (menu, isPoppedUp) => {
+ if (!isPoppedUp)
+ this._onMenuPoppedDown();
+ });
+ // Main.overview.connectObject('hiding',
+ this._hidingSigId = Main.overview.connect('hiding',
+ () => this._menu.close(), this);
+
+ Main.uiGroup.add_actor(this._menu.actor);
+ this._menuManager.addMenu(this._menu);
+ }
+
+ // once the menu is created, it stays unchanged and we need to modify our items based on current situation
+ if (this._addedMenuItems && this._addedMenuItems.length)
+ this._addedMenuItems.forEach(i => i.destroy());
+
+
+ const popupItems = [];
+
+ const separator = new PopupMenu.PopupSeparatorMenuItem();
+ this._menu.addMenuItem(separator);
+
+ if (this.app.get_n_windows()) {
+ // if (/* opt.APP_MENU_FORCE_QUIT*/true) {}
+ popupItems.push([_('Force Quit'), () => {
+ this.app.get_windows()[0].kill();
+ }]);
+
+ // if (opt.APP_MENU_CLOSE_WS) {}
+ const nWin = this._getWindowsOnCurrentWs().length;
+ if (nWin) {
+ popupItems.push([_(`Close ${nWin} Windows on Current Workspace`), () => {
+ const windows = this._getWindowsOnCurrentWs();
+ let time = global.get_current_time();
+ for (let win of windows) {
+ // increase time by 1 ms for each window to avoid errors from GS
+ win.delete(time++);
+ }
+ }]);
+ }
+
+ if (/* opt.APP_MENU_MV_TO_WS && */this._windowsOnOtherWs())
+ popupItems.push([_('Move App to Current Workspace ( Shift + Click )'), this._moveAppToCurrentWorkspace]);
+ }
+
+ this._addedMenuItems = [];
+ this._addedMenuItems.push(separator);
+ popupItems.forEach(i => {
+ let item = new PopupMenu.PopupMenuItem(i[0]);
+ this._menu.addMenuItem(item);
+ item.connect('activate', i[1].bind(this));
+ this._addedMenuItems.push(item);
+ });
+
+ this.emit('menu-state-changed', true);
+
+ this._menu.open(BoxPointer.PopupAnimation.FULL);
+ this._menuManager.ignoreRelease();
+ this.emit('sync-tooltip');
+
+ return false;
+ },
+};
+
+function _getWindowApp(metaWin) {
+ const tracker = Shell.WindowTracker.get_default();
+ return tracker.get_window_app(metaWin);
+}
+
+function _getAppLastUsedWindow(app) {
+ let recentWin;
+ global.display.get_tab_list(Meta.TabList.NORMAL_ALL, null).forEach(metaWin => {
+ const winApp = _getWindowApp(metaWin);
+ if (!recentWin && winApp === app)
+ recentWin = metaWin;
+ });
+ return recentWin;
+}
+
+function _getAppRecentWorkspace(app) {
+ const recentWin = _getAppLastUsedWindow(app);
+ if (recentWin)
+ return recentWin.get_workspace();
+
+ return null;
+}
+
+function _updateSearchWindowsIcon(show = opt.SHOW_WINDOWS_ICON) {
const dash = Main.overview._overview._controls.layoutManager._dash;
const dashContainer = dash._dashContainer;
if (dash._showWindowsIcon) {
dashContainer.remove_child(dash._showWindowsIcon);
- dash._showWindowsIconClickedId && dash._showWindowsIcon.toggleButton.disconnect(dash._showWindowsIconClickedId);
+ if (dash._showWindowsIconClickedId)
+ dash._showWindowsIcon.toggleButton.disconnect(dash._showWindowsIconClickedId);
dash._showWindowsIconClickedId = undefined;
- dash._showWindowsIcon && dash._showWindowsIcon.destroy();
+ if (dash._showWindowsIcon)
+ dash._showWindowsIcon.destroy();
dash._showWindowsIcon = undefined;
}
- if (!show || !opt.WINDOW_SEARCH_PROVIDER_ENABLED) return;
+ if (!show || !opt.WINDOW_SEARCH_PROVIDER_ENABLED)
+ return;
if (!dash._showWindowsIcon) {
dash._showWindowsIcon = new ShowWindowsIcon();
@@ -708,22 +1056,23 @@ function _updateSearchWindowsIcon(show = opt.SHOW_WINDOWS_ICON) {
dash._hookUpLabel(dash._showWindowsIcon);
}
- dash._showWindowsIcon.icon.setIconSize(opt.MAX_ICON_SIZE);
+ dash._showWindowsIcon.icon.setIconSize(dash.iconSize);
if (opt.SHOW_WINDOWS_ICON === 1) {
dashContainer.set_child_at_index(dash._showWindowsIcon, 0);
} else if (opt.SHOW_WINDOWS_ICON === 2) {
- index = dashContainer.get_children().length - 1;
+ const index = dashContainer.get_children().length - 1;
dashContainer.set_child_at_index(dash._showWindowsIcon, index);
}
Main.overview._overview._controls.layoutManager._dash._adjustIconSize();
}
-var ShowWindowsIcon = GObject.registerClass(
+const ShowWindowsIcon = GObject.registerClass(
class ShowWindowsIcon extends Dash.DashItemContainer {
_init() {
super._init();
+ this._isSearchWindowsIcon = true;
this._labelText = _('Search Open Windows (Hotkey: Space)');
this.toggleButton = new St.Button({
style_class: 'show-apps',
@@ -744,6 +1093,12 @@ class ShowWindowsIcon extends Dash.DashItemContainer {
this.toggleButton._delegate = this;
this.setChild(this.toggleButton);
+
+ if (opt.SEARCH_WINDOWS_ICON_SCROLL) {
+ this.reactive = true;
+ this._scrollConId = this.connect('scroll-event', _onScrollEvent.bind(this));
+ this._leaveConId = this.connect('leave-event', _onLeaveEvent.bind(this));
+ }
}
_createIcon(size) {
@@ -758,19 +1113,21 @@ class ShowWindowsIcon extends Dash.DashItemContainer {
});
function _updateRecentFilesIcon(show = opt.SHOW_RECENT_FILES_ICON) {
-
const dash = Main.overview._overview._controls.layoutManager._dash;
const dashContainer = dash._dashContainer;
if (dash._recentFilesIcon) {
dashContainer.remove_child(dash._recentFilesIcon);
- dash._recentFilesIconClickedId && dash._recentFilesIcon.toggleButton.disconnect(dash._recentFilesIconClickedId);
+ if (dash._recentFilesIconClickedId)
+ dash._recentFilesIcon.toggleButton.disconnect(dash._recentFilesIconClickedId);
dash._recentFilesIconClickedId = undefined;
- dash._recentFilesIcon && dash._recentFilesIcon.destroy();
+ if (dash._recentFilesIcon)
+ dash._recentFilesIcon.destroy();
dash._recentFilesIcon = undefined;
}
- if (!show || !opt.RECENT_FILES_SEARCH_PROVIDER_ENABLED) return;
+ if (!show || !opt.RECENT_FILES_SEARCH_PROVIDER_ENABLED)
+ return;
if (!dash._recentFilesIcon) {
dash._recentFilesIcon = new ShowRecentFilesIcon();
@@ -779,18 +1136,18 @@ function _updateRecentFilesIcon(show = opt.SHOW_RECENT_FILES_ICON) {
dash._hookUpLabel(dash._recentFilesIcon);
}
- dash._recentFilesIcon.icon.setIconSize(opt.MAX_ICON_SIZE);
+ dash._recentFilesIcon.icon.setIconSize(dash.iconSize);
if (opt.SHOW_RECENT_FILES_ICON === 1) {
dashContainer.set_child_at_index(dash._recentFilesIcon, 0);
} else if (opt.SHOW_RECENT_FILES_ICON === 2) {
- index = dashContainer.get_children().length - 1;
+ const index = dashContainer.get_children().length - 1;
dashContainer.set_child_at_index(dash._recentFilesIcon, index);
}
Main.overview._overview._controls.layoutManager._dash._adjustIconSize();
}
-var ShowRecentFilesIcon = GObject.registerClass(
+const ShowRecentFilesIcon = GObject.registerClass(
class ShowRecentFilesIcon extends Dash.DashItemContainer {
_init() {
super._init();