1
0
Fork 0

Updating 44/vertical-workspaces to version 37+20231208 [0d82192].

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-03-24 19:42:07 +01:00
parent 975b88c6bb
commit 07381ac119
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
37 changed files with 9559 additions and 4338 deletions

View file

@ -1,4 +1,100 @@
## Changelog:
### v45.2 for GNOME 45.2+, v44.10 for GNOME 42-44 (2023-12-02)
**Added:**
- *Dash* option *Isolate Workspaces* on *Behavior* tab
- *Brightness for Search View* option allows adjusting background wallpaper brightness in overview search view
- *Extensions Search Provider* module allows to search for extensions from the overview, open their settings and enable or disable them
### v45.1 for GNOME 45.1+ (EGO 2023-11-25) v44.9 for GNOME 42-44 (not released)
**Added:**
- *Window Thumbnail - PIP* option in app icon menu and as an click actions for Window Preview
- Workspace switcher options *Wraparound* and *Ignore Last (empty)*
- *Overlay key (Super)* and *Hot Corner* actions offer different overview modes independent on global *Overview Mode*
- Workspace thumbnails background without wallpaper is now semi-transparent to match other overview elements
- App Grid sorting options allow alphabetical order with folders
**Fixed:**
- App grid has less rows than it should
- Many minor fixes that reflect gnome-shell development and backports
- Centered app folder position on multi-monitor system
- Window can't be activated using touchscreen
- Setting background wallpaper too early on startup can crash Wayland session
**Other changes:**
- Since GNOME 45 V-Shell has 2 versions - one for GS 45 and the second for GS 42-44. Versioning no longer depends on EGO's upload counter
- Dash light style background opacity is not limited
- Refactored Recent Files Search Provider and other modules
- Settings window - ComboBox replaced with (finally fixed) DropDown
### v37 (2023-07-01)
**Fixed:**
- False detections of conflicting extensions
### v36 (2023-07-01) (35/34/33/32/31 skipped due to issues with extensions.gnome.org)
**Added:**
- Option *Fix New Windows Not In Focus* on *Misc* tab
**Fixed:**
- Improved compatibility with Dash to Dock extension - hidden dock in the overview, broken layout after startup
- Compatibility with Hide Top Bar extension
- App search provider ignores non-localized app names
- App folders grid dimensions wrong if set to *Adaptive* and folder icon is set to a fixed size
- Dash and active app folder icons running indicator position
- Blur/Brightness transitions in static overview mode
- Hot corner edge barrier can be active even if hot corner is disabled
- Disabling dash module does not reset dash position to default
**Other changes:**
- Removed css class reducing Quick Settings buttons height in GNOME 44
### v30 (2023-06-09)
**Added:**
- Dash option - Click Behavior: *Prefer Current Workspace* - opens a new window if app not present on the active workspace
- Window search provider sorting options
- Esc key behavior options
- Window preview - middle and secondary mouse button behavior options, close button can be hidden
- GNOME 3 vertical dash style is now optional
- Window preview title position option
- Light dash background option
- Remove app folder button in folder dialog
- *Updating V-Shell* banner appears during updating V-Shell settings when settings window is irresponsive
- Dutch translation by @Vistaus
**Fixed:**
- Dash icon scroll action conflicts with Dash to Dock
- Open new window by middle click on app icon or Ctrl+Enter doesn't work
- Dash icon label can extend to the adjacent display
- WindowPreview module not updated when "always-activate-selected-window" changed
- App folder dialog position if secondary monitor connected
- App folder dialog sizing and positioning
- Background brightness in search view reduced independently to avoid unreadable text and consistent style
- Compatibility with Burn My Windows - freeze after screen unlocked, or extensions re-enabled
- Window and Recent files search providers modes not isolated well from results of other providers
- Recent file search provider results sorting
- App grid icons with multi-line label move on hover when label expands
- Search view animation skipped id triggered from app grid state
- DING desktop icons not visible during static background workspace animation
**Other changes:**
- Added `unlock-dialog` session mode to avoid unnecessary system load when using screen lock
- App Grid refactored, added transparent app folder dialogs on clean background
- Search view transparency and fixed background brightness in classic overview
- Search view in static workspace overview with full opacity and close to default style
- Settings window - Profiles tab moved at first position, Dash icons position options moved back to layout
- Updated default profiles
### v29 (2023-04-11)
**Fixed:**
- Window switcher/highlighter logic when scrolling over an dash icon
- Unhandled promise rejection warnings on GS 43+
### v28 (2023-04-06)
**Added:**
- App Grid - vertical app folder orientation

View file

@ -2,7 +2,7 @@
A GNOME Shell extension that lets you customize your GNOME Shell UX to suit your workflow, whether you like horizontally or vertically stacked workspaces.
Currently supported GNOME versions: 42, 43, 44
Currently supported GNOME versions: 42 - 45
[<img alt="" height="100" src="https://raw.githubusercontent.com/andyholmes/gnome-shell-extensions-badge/master/get-it-on-ego.svg?sanitize=true">](https://extensions.gnome.org/extension/5177/vertical-workspaces/)
@ -17,6 +17,7 @@ Currently supported GNOME versions: 42, 43, 44
- Support for secondary monitors, workspace thumbnails can be placed on the opposite side than on the primary monitor
- Wallpaper background with adjustable blur effect and brightness in the overview
- Custom Dash icon size and on-click/scroll behavior
- Optional workspace isolated Dash
- Dash background transparency and corner radius adjustments
- Adjustable app grid icon size, number of columns and rows, content, optional active and draggable icons in folder preview in optional 3x3 grid
- Custom search view width, app results icons size and number of result lists rows, improved app search
@ -26,12 +27,14 @@ Currently supported GNOME versions: 42, 43, 44
- Control over transition animations, including speed
- Window search provider with *Space* hotkey allows quick window navigation
- Recent files search provider with *Ctrl + Space* hotkey
- Extensions search provider with *Ctrl + Shift + Space* hotkey allows to search for extensions, open their settings and enable or disable them
- Reorder workspaces in overview using *Shift + Scroll* or *Shift + Page Up/Down*
- Adds *Force Quit*, *Close Windows on Current Workspace* and *Move Windows to Current Workspace* items to app icon menu. The latter action can be activated using *Shift + click* on app icon
- Change notification banners and OSD popups position
- Window attention handler options can activate the attention-demanding window immediately or silence its notification
- Optional position of the hot corner that can follow the dash and expand to hot edge
- Super key double-press options
- Window thumbnail (PIP) options allows you to create scaled down clone of the window by clicking on its preview in the overview (secondary mouse buttons or window preview icon)
## Changelog
[CHANGELOG.md](CHANGELOG.md)
@ -51,14 +54,23 @@ Install the extension (`--force` switch needs to be used only if some version of
gnome-extensions install --force vertical-workspaces@G-dH.github.com.zip
### Installation from GitHub repository
The most recent version in the repository is the one I'm currently using and developing on my own systems, problems may occur, but usually nothing serious. The repository version may change often and doesn't updates automatically on your system, but once the stable release shows up on extensions.gnome.org, it should be updated automatically from there. If you want to help me, use this latest version and report bugs.
You may need to install `git`, `gettext` and `glib2.0` for successful installation.
The most recent version in the repository is the one I'm currently using and developing on my own systems, problems may occur, but usually nothing serious. The repository version may change often and doesn't updates automatically on your system. If you want to help me, use this latest version and report bugs.
You may need to install `git`, `make`, `gettext` and `glib2.0` for successful installation.
Navigate to the directory you want to download the source code and execute following commands in the terminal:
GNOME 45:
git clone https://github.com/G-dH/vertical-workspaces.git
cd vertical-workspaces
make install
GNOME 42 - 44:
git clone https://github.com/G-dH/vertical-workspaces.git
cd vertical-workspaces
git checkout gnome-42-44
make install
If you get `Can't recursively copy directory` error, take a look at issue #51.
### Enabling the extension

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -10,45 +10,63 @@
'use strict';
const { Shell } = imports.gi;
const AppFavorites = imports.ui.appFavorites;
const Main = imports.ui.main;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const _Util = Me.imports.lib.util;
let Me;
let opt;
let _overrides;
let _firstRun = true;
function update(reset = false) {
opt = Me.imports.lib.settings.opt;
const moduleEnabled = opt.get('appFavoritesModule', true);
reset = reset || !moduleEnabled;
var AppFavoritesModule = class {
constructor(me) {
Me = me;
opt = Me.opt;
// don't even touch this module if disabled
if (_firstRun && reset)
return;
_firstRun = false;
if (_overrides)
_overrides.removeAll();
// if notifications are enabled no override is needed
if (reset || opt.SHOW_FAV_NOTIFICATION) {
_overrides = null;
opt = null;
return;
this._firstActivation = true;
this.moduleEnabled = false;
this._overrides = null;
}
_overrides = new _Util.Overrides();
cleanGlobals() {
Me = null;
opt = null;
}
// AppFavorites.AppFavorites is const, first access returns undefined
const dummy = AppFavorites.AppFavorites;
_overrides.addOverride('AppFavorites', AppFavorites.AppFavorites.prototype, AppFavoritesCommon);
}
update(reset) {
this.moduleEnabled = opt.get('appFavoritesModule');
// if notifications are enabled no override is needed
reset = reset || !this.moduleEnabled || opt.SHOW_FAV_NOTIFICATION;
// don't touch original code if module disabled
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation) {
this.moduleEnabled = false;
console.debug(' AppFavoritesModule - Keeping untouched');
}
}
_activateModule() {
if (!this._overrides)
this._overrides = new Me.Util.Overrides();
// use actual instance instead of prototype
this._overrides.addOverride('AppFavorites', AppFavorites.getAppFavorites(), AppFavoritesCommon);
console.debug(' AppFavoritesModule - Activated');
}
_disableModule() {
if (this._overrides)
this._overrides.removeAll();
this._overrides = null;
console.debug(' AppFavoritesModule - Deactivated');
}
};
const AppFavoritesCommon = {
addFavoriteAtPos(appId, pos) {

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,423 @@
/**
* V-Shell (Vertical Workspaces)
* extensionsSearchProvider.js
*
* @author GdH <G-dH@github.com>
* @copyright 2022 - 2023
* @license GPL-3.0
*/
'use strict';
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Clutter = imports.gi.Clutter;
const GObject = imports.gi.GObject;
const Main = imports.ui.main;
const ExtensionState = {
1: 'ENABLED',
2: 'DISABLED',
3: 'ERROR',
4: 'INCOMPATIBLE',
5: 'DOWNLOADING',
6: 'INITIALIZED',
7: 'DISABLING',
8: 'ENABLING',
};
let Me;
let opt;
// gettext
let _;
let _toggleTimeout;
// prefix helps to eliminate results from other search providers
// so it needs to be something less common
// needs to be accessible from vw module
const PREFIX = 'eq//';
var ExtensionsSearchProviderModule = class {
// export for other modules
static _PREFIX = PREFIX;
constructor(me) {
Me = me;
opt = Me.opt;
_ = Me.gettext;
this._firstActivation = true;
this.moduleEnabled = false;
this._extensionsSearchProvider = null;
this._enableTimeoutId = 0;
}
cleanGlobals() {
Me = null;
opt = null;
_ = null;
}
update(reset) {
if (_toggleTimeout)
GLib.source_remove(_toggleTimeout);
this.moduleEnabled = opt.get('extensionsSearchProviderModule');
reset = reset || !this.moduleEnabled;
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation)
console.debug(' ExtensionsSearchProviderModule - Keeping untouched');
}
_activateModule() {
// delay because Fedora had problem to register a new provider soon after Shell restarts
this._enableTimeoutId = GLib.timeout_add(
GLib.PRIORITY_DEFAULT,
2000,
() => {
if (!this._extensionsSearchProvider) {
this._extensionsSearchProvider = new extensionsSearchProvider(opt);
this._getOverviewSearchResult()._registerProvider(this._extensionsSearchProvider);
}
this._enableTimeoutId = 0;
return GLib.SOURCE_REMOVE;
}
);
console.debug(' ExtensionsSearchProviderModule - Activated');
}
_disableModule() {
if (this._enableTimeoutId) {
GLib.source_remove(this._enableTimeoutId);
this._enableTimeoutId = 0;
}
if (this._extensionsSearchProvider) {
this._getOverviewSearchResult()._unregisterProvider(this._extensionsSearchProvider);
this._extensionsSearchProvider = null;
}
console.debug(' ExtensionsSearchProviderModule - Disabled');
}
_getOverviewSearchResult() {
return Main.overview._overview.controls._searchController._searchResults;
}
};
class extensionsSearchProvider {
constructor() {
this.id = 'extensions';
const appSystem = Shell.AppSystem.get_default();
let appInfo = appSystem.lookup_app('com.matjakeman.ExtensionManager.desktop')?.get_app_info();
if (!appInfo)
appInfo = appSystem.lookup_app('org.gnome.Extensions.desktop')?.get_app_info();
if (!appInfo)
appInfo = Gio.AppInfo.create_from_commandline('/usr/bin/gnome-extensions-app', 'Extensions', null);
appInfo.get_description = () => _('Search extensions');
appInfo.get_name = () => _('Extensions');
appInfo.get_id = () => 'org.gnome.Extensions.desktop';
appInfo.get_icon = () => Gio.icon_new_for_string('application-x-addon');
appInfo.should_show = () => true;
this.appInfo = appInfo;
this.canLaunchSearch = true;
this.isRemoteProvider = false;
}
getInitialResultSet(terms, callback /* , cancellable = null*/) {
// In GS 43 callback arg has been removed
/* if (Me.shellVersion >= 43)
cancellable = callback; */
const extensions = {};
Main.extensionManager._extensions.forEach(
e => {
extensions[e.uuid] = e;
}
);
this.extensions = extensions;
if (Me.shellVersion >= 43)
return new Promise(resolve => resolve(this._getResultSet(terms)));
else
callback(this._getResultSet(terms));
return null;
}
_getResultSet(terms) {
// do not modify original terms
let termsCopy = [...terms];
// search for terms without prefix
termsCopy[0] = termsCopy[0].replace(PREFIX, '');
const candidates = this.extensions;
const _terms = [].concat(termsCopy);
const term = _terms.join(' ');
const results = [];
let m;
for (let id in candidates) {
const extension = this.extensions[id];
const text = extension.metadata.name + (extension.state === 1 ? 'enabled' : '') + ([6, 2].includes(extension.state) ? 'disabled' : '');
if (opt.SEARCH_FUZZY)
m = Me.Util.fuzzyMatch(term, text);
else
m = Me.Util.strictMatch(term, text);
if (m !== -1)
results.push({ weight: m, id });
}
// sort alphabetically
results.sort((a, b) => this.extensions[a.id].metadata.name.localeCompare(this.extensions[b.id].metadata.name));
// enabled first
// results.sort((a, b) => this.extensions[a.id].state !== 1 && this.extensions[b.id].state === 1);
// incompatible last
results.sort((a, b) => this.extensions[a.id].state === 4 && this.extensions[b.id].state !== 4);
this.resultIds = results.map(item => item.id);
return this.resultIds;
}
getResultMetas(resultIds, callback = null) {
const metas = resultIds.map(id => this.getResultMeta(id));
if (Me.shellVersion >= 43)
return new Promise(resolve => resolve(metas));
else if (callback)
callback(metas);
return null;
}
getResultMeta(resultId) {
const result = this.extensions[resultId];
const versionName = result.metadata['version-name'] ?? '';
let version = result.metadata['version'] ?? '';
version = versionName && version ? `/${version}` : version;
const versionStr = `${versionName}${version}`;
return {
'id': resultId,
'name': `${result.metadata.name}`,
'version': versionStr,
'description': versionStr, // description will be updated in result object
'createIcon': size => {
let icon = this.getIcon(result, size);
return icon;
},
};
}
getIcon(extension, size) {
let opacity = 0;
let iconName = 'process-stop-symbolic';
switch (extension.state) {
case 1:
if (extension.hasUpdate)
iconName = 'software-update-available'; // 'software-update-available-symbolic';
else
iconName = 'object-select';// 'object-select-symbolic';
opacity = 255;
break;
case 3:
if (Main.extensionManager._enabledExtensions.includes(extension.uuid))
iconName = 'emblem-ok-symbolic';
else
iconName = 'dialog-error';
opacity = 100;
break;
case 4:
iconName = 'software-update-urgent'; // 'software-update-urgent-symbolic';
opacity = 100;
break;
}
if (extension.hasUpdate) {
iconName = 'software-update-available'; // 'software-update-available-symbolic';
opacity = 100;
}
const icon = new St.Icon({ icon_name: iconName, icon_size: size });
icon.set({
reactive: true,
opacity,
});
return icon;
}
createResultObject(meta) {
return new ListSearchResult(this, meta, this.extensions[meta.id]);
}
launchSearch(terms, timeStamp) {
this.appInfo.launch([], global.create_app_launch_context(timeStamp, -1), null);
}
activateResult(resultId/* terms, timeStamp*/) {
const extension = this.extensions[resultId];
if (Me.Util.isShiftPressed())
this._toggleExtension(extension);
else if (extension.hasPrefs)
Me.Util.openPreferences(extension.metadata);
}
filterResults(results /* , maxResults*/) {
// return results.slice(0, maxResults);
return results;
}
getSubsearchResultSet(previousResults, terms, callback) {
if (Me.shellVersion < 43) {
this.getSubsearchResultSet42(terms, callback);
return null;
}
return this.getInitialResultSet(terms);
}
getSubsearchResultSet42(terms, callback) {
callback(this._getResultSet(terms));
}
}
const ListSearchResult = GObject.registerClass(
class ListSearchResult extends St.Button {
_init(provider, metaInfo, extension) {
this.provider = provider;
this.metaInfo = metaInfo;
this.extension = extension;
super._init({
reactive: true,
can_focus: true,
track_hover: true,
});
this.style_class = 'list-search-result';
let content = new St.BoxLayout({
style_class: 'list-search-result-content',
vertical: false,
x_align: Clutter.ActorAlign.START,
x_expand: true,
y_expand: true,
});
this.set_child(content);
let titleBox = new St.BoxLayout({
style_class: 'list-search-result-title',
y_align: Clutter.ActorAlign.CENTER,
});
content.add_child(titleBox);
// An icon for, or thumbnail of, content
let icon = this.metaInfo['createIcon'](this.ICON_SIZE);
let iconBox = new St.Button();
iconBox.set_child(icon);
titleBox.add(iconBox);
iconBox.set_style('border: 1px solid rgba(200,200,200,0.2); padding: 2px; border-radius: 8px;');
this._iconBox = iconBox;
this.icon = icon;
iconBox.connect('clicked', () => {
this._toggleExtension();
return Clutter.EVENT_STOP;
});
let title = new St.Label({
text: this.metaInfo['name'],
y_align: Clutter.ActorAlign.CENTER,
opacity: extension.hasPrefs ? 255 : 150,
});
titleBox.add_child(title);
this.label_actor = title;
this._descriptionLabel = new St.Label({
style_class: 'list-search-result-description',
y_align: Clutter.ActorAlign.CENTER,
});
content.add_child(this._descriptionLabel);
this._highlightTerms();
this.connect('destroy', () => {
if (_toggleTimeout) {
GLib.source_remove(_toggleTimeout);
_toggleTimeout = 0;
}
});
}
_toggleExtension() {
const state = this.extension.state;
if (![1, 2, 6, 3].includes(state) || this.extension.metadata.uuid.includes('vertical-workspaces'))
return;
if ([2, 6].includes(state))
Main.extensionManager.enableExtension(this.extension.uuid);
else if ([1, 3].includes(state))
Main.extensionManager.disableExtension(this.extension.uuid);
if (_toggleTimeout)
GLib.source_remove(_toggleTimeout);
_toggleTimeout = GLib.timeout_add(GLib.PRIORITY_LOW, 200,
() => {
if ([7, 8].includes(this.extension.state))
return GLib.SOURCE_CONTINUE;
this.icon?.destroy();
this.icon = this.metaInfo['createIcon'](this.ICON_SIZE);
this._iconBox.set_child(this.icon);
this._highlightTerms();
_toggleTimeout = 0;
return GLib.SOURCE_REMOVE;
}
);
}
get ICON_SIZE() {
return 24;
}
_highlightTerms() {
const extension = this.extension;
const state = extension.state === 4 ? ExtensionState[this.extension.state] : '';
const error = extension.state === 3 ? ` ERROR: ${this.extension.error}` : '';
const update = extension.hasUpdate ? ' | UPDATE PENDING' : '';
const text = `${this.metaInfo.version} ${state}${error}${update}`;
let markup = text;// this.metaInfo['description'].split('\n')[0];
this._descriptionLabel.clutter_text.set_markup(markup);
}
vfunc_clicked() {
this.activate();
}
activate() {
this.provider.activateResult(this.metaInfo.id);
if (this.metaInfo.clipboardText) {
St.Clipboard.get_default().set_text(
St.ClipboardType.CLIPBOARD, this.metaInfo.clipboardText);
}
Main.overview.toggle();
}
});

View file

@ -9,11 +9,13 @@
*/
'use strict';
const { GLib, St, Meta } = imports.gi;
const St = imports.gi.St;
const IconGrid = imports.ui.iconGrid;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const _Util = Me.imports.lib.util;
const shellVersion = _Util.shellVersion;
let Me;
let opt;
// added sizes for better scaling
const IconSize = {
@ -29,47 +31,58 @@ const IconSize = {
LARGE: 96,
80: 80,
64: 64,
48: 48,
TINY: 32,
TINY: 48,
};
const PAGE_WIDTH_CORRECTION = 100;
let opt;
let _overrides;
let _firstRun = true;
var IconGridModule = class {
constructor(me) {
Me = me;
opt = Me.opt;
function update(reset = false) {
opt = Me.imports.lib.settings.opt;
const moduleEnabled = opt.get('appDisplayModule', true);
reset = reset || !moduleEnabled;
this._firstActivation = true;
this.moduleEnabled = false;
this._overrides = null;
}
// don't even touch this module if disabled
if (_firstRun && reset)
return;
_firstRun = false;
if (_overrides)
_overrides.removeAll();
if (reset) {
_overrides = null;
cleanGlobals() {
Me = null;
opt = null;
return;
}
_overrides = new _Util.Overrides();
update(reset) {
this.moduleEnabled = opt.get('appDisplayModule');
// if notifications are enabled no override is needed
reset = reset || !this.moduleEnabled;
if (shellVersion < 43 && IconGridCommon._findBestModeForSize) {
IconGridCommon['findBestModeForSize'] = IconGridCommon._findBestModeForSize;
IconGridCommon['_findBestModeForSize'] = undefined;
// don't touch original code if module disabled
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
}
_overrides.addOverride('IconGrid', IconGrid.IconGrid.prototype, IconGridCommon);
_overrides.addOverride('IconGridLayout', IconGrid.IconGridLayout.prototype, IconGridLayoutCommon);
}
// workaround - silence page -2 error on gnome 43 while cleaning app grid
_activateModule() {
if (!this._overrides)
this._overrides = new Me.Util.Overrides();
if (Me.shellVersion < 43 && IconGridCommon._findBestModeForSize) {
IconGridCommon['findBestModeForSize'] = IconGridCommon._findBestModeForSize;
delete IconGridCommon['_findBestModeForSize'];
}
this._overrides.addOverride('IconGrid', IconGrid.IconGrid.prototype, IconGridCommon);
this._overrides.addOverride('IconGridLayout', IconGrid.IconGridLayout.prototype, IconGridLayoutCommon);
}
_disableModule() {
if (this._overrides)
this._overrides.removeAll();
this._overrides = null;
}
};
const IconGridCommon = {
getItemsAtPage(page) {
@ -87,7 +100,7 @@ const IconGridCommon = {
return;
const { pagePadding } = this.layout_manager;
const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage);
const iconPadding = 53 * scaleFactor;
const iconPadding = 51 * scaleFactor;
// provided width is usually about 100px wider in horizontal orientation with prev/next page indicators
const pageIndicatorCompensation = opt.ORIENTATION ? 0 : PAGE_WIDTH_CORRECTION;
@ -99,8 +112,13 @@ const IconGridCommon = {
this.layoutManager._gridWidth = width;
this.layoutManager._gridHeight = height;
width -= 80; // compensation for default padding
height -= 80;
const spacing = opt.APP_GRID_SPACING;
const iconSize = (opt.APP_GRID_ICON_SIZE > 0 ? opt.APP_GRID_ICON_SIZE : opt.APP_GRID_ICON_SIZE_DEFAULT) * scaleFactor;
// set the icon size as fixed to avoid changes in size later
const iconSize = opt.APP_GRID_ICON_SIZE > 0 ? opt.APP_GRID_ICON_SIZE : opt.APP_GRID_ICON_SIZE_DEFAULT;
const itemSize = iconSize * scaleFactor + iconPadding;
// if this._gridModes.length === 1, custom grid should be used
// if (iconSize > 0 && this._gridModes.length > 1) {
let columns = opt.APP_GRID_COLUMNS;
@ -109,17 +127,20 @@ const IconGridCommon = {
let unusedSpaceH = -1;
let unusedSpaceV = -1;
if (!columns) {
columns = Math.floor(width / (iconSize + iconPadding)) + 1;
// calculate #columns + 1 without spacing
columns = Math.floor(width / itemSize) + 1;
// check if columns with spacing fits the available width
// and reduce the number until it fits
while (unusedSpaceH < 0) {
columns -= 1;
unusedSpaceH = width - columns * (iconSize + iconPadding) - (columns - 1) * spacing;
unusedSpaceH = width - columns * itemSize - (columns - 1) * spacing;
}
}
if (!rows) {
rows = Math.floor(height / (iconSize + iconPadding)) + 1;
rows = Math.floor(height / itemSize) + 1;
while (unusedSpaceV < 0) {
rows -= 1;
unusedSpaceV = height - rows * (iconSize + iconPadding) - (rows - 1) * spacing;
unusedSpaceV = height - rows * itemSize - ((rows - 1) * spacing);
}
}
@ -135,9 +156,16 @@ const IconGridLayoutCommon = {
const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage);
const nColumns = this.columnsPerPage;
const nRows = this.rowsPerPage;
// if grid is not defined return default icon size
if (nColumns < 1 && nRows < 1) {
return this._isFolder
? opt.APP_GRID_FOLDER_ICON_SIZE_DEFAULT : opt.APP_GRID_ICON_SIZE_DEFAULT;
}
const columnSpacingPerPage = opt.APP_GRID_SPACING * (nColumns - 1);
const rowSpacingPerPage = opt.APP_GRID_SPACING * (nRows - 1);
const iconPadding = 53 * scaleFactor;
const iconPadding = 55 * scaleFactor;
const paddingH = this._isFolder ? this.pagePadding.left + this.pagePadding.right : 0;
const paddingV = this._isFolder ? this.pagePadding.top + this.pagePadding.bottom : 0;
@ -156,10 +184,14 @@ const IconGridLayoutCommon = {
return opt.APP_GRID_ICON_SIZE_DEFAULT;*/
let iconSizes = Object.values(IconSize).sort((a, b) => b - a);
// limit max icon size for folders, the whole range is for the main grid with active folders
if (this._isFolder)
// limit max icon size for folders and fully adaptive folder grids, the whole range is for the main grid with active folders
if (this._isFolder && opt.APP_GRID_FOLDER_ADAPTIVE && opt.APP_GRID_FOLDER_ICON_SIZE < 0)
iconSizes = iconSizes.slice(iconSizes.indexOf(opt.APP_GRID_FOLDER_ICON_SIZE_DEFAULT), -1);
else if (this._isFolder)
iconSizes = iconSizes.slice(iconSizes.indexOf(IconSize.LARGE), -1);
else if (opt.APP_GRID_ADAPTIVE && opt.APP_GRID_ICON_SIZE < 0)
iconSizes = iconSizes.slice(iconSizes.indexOf(opt.APP_GRID_ICON_SIZE_DEFAULT), -1);
let sizeInvalid = false;
for (const size of iconSizes) {
@ -167,10 +199,9 @@ const IconGridLayoutCommon = {
if (firstItem) {
firstItem.icon.setIconSize(size);
const [firstItemWidth, firstItemHeight] =
firstItem.get_preferred_size();
const [firstItemWidth] = firstItem.get_preferred_size();
const itemSize = Math.max(firstItemWidth, firstItemHeight);
const itemSize = firstItemWidth;
if (itemSize < size)
sizeInvalid = true;
@ -199,7 +230,7 @@ const IconGridLayoutCommon = {
removeItem(item) {
if (!this._items.has(item)) {
log(`Item ${item} is not part of the IconGridLayout`);
console.error(`Item ${item} is not part of the IconGridLayout`);
return;
// throw new Error(`Item ${item} is not part of the IconGridLayout`);
}
@ -215,13 +246,13 @@ const IconGridLayoutCommon = {
addItem(item, page = -1, index = -1) {
if (this._items.has(item)) {
log(`iconGrid: Item ${item} already added to IconGridLayout`);
console.error(`iconGrid: Item ${item} already added to IconGridLayout`);
return;
// throw new Error(`Item ${item} already added to IconGridLayout`);
}
if (page > this._pages.length) {
log(`iconGrid: Cannot add ${item} to page ${page}`);
console.error(`iconGrid: Cannot add ${item} to page ${page}`);
page = -1;
index = -1;
// throw new Error(`Cannot add ${item} to page ${page}`);
@ -240,7 +271,7 @@ const IconGridLayoutCommon = {
moveItem(item, newPage, newPosition) {
if (!this._items.has(item)) {
log(`iconGrid: Item ${item} is not part of the IconGridLayout`);
console.error(`iconGrid: Item ${item} is not part of the IconGridLayout`);
return;
// throw new Error(`Item ${item} is not part of the IconGridLayout`);
}

View file

@ -10,67 +10,107 @@
'use strict';
const { Meta, GLib, Shell, Clutter, GObject } = imports.gi;
const GLib = imports.gi.GLib;
const Meta = imports.gi.Meta;
const Gio = imports.gi.Gio;
const Main = imports.ui.main;
const Layout = imports.ui.layout;
const Ripples = imports.ui.ripples;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const _Util = Me.imports.lib.util;
let _overrides;
let _timeouts;
let Me;
let opt;
let _firstRun = true;
let _originalUpdateHotCorners;
function update(reset = false) {
opt = Me.imports.lib.settings.opt;
const moduleEnabled = opt.get('layoutModule', true);
const conflict = _Util.getEnabledExtensions('custom-hot-corners').length ||
_Util.getEnabledExtensions('dash-to-panel').length;
reset = reset || !moduleEnabled;
let _timeouts;
// don't even touch this module if disabled or in conflict
if (_firstRun && (reset || conflict))
return;
var LayoutModule = class {
constructor(me) {
Me = me;
opt = Me.opt;
_timeouts = {};
_firstRun = false;
if (!_originalUpdateHotCorners)
_originalUpdateHotCorners = Layout.LayoutManager.prototype._updateHotCorners;
if (_overrides)
_overrides.removeAll();
if (_timeouts) {
Object.values(_timeouts).forEach(t => {
if (t)
GLib.source_remove(t);
});
this._firstActivation = true;
this.moduleEnabled = false;
this._overrides = null;
this._originalUpdateHotCorners = null;
}
if (reset) {
_overrides = null;
cleanGlobals() {
Me = null;
opt = null;
_timeouts = null;
Main.layoutManager._updateHotCorners = _originalUpdateHotCorners;
Main.layoutManager._updateHotCorners();
return;
}
_timeouts = {};
update(reset) {
this._removeTimeouts();
_overrides = new _Util.Overrides();
_overrides.addOverride('LayoutManager', Layout.LayoutManager.prototype, LayoutManagerCommon);
this.moduleEnabled = opt.get('layoutModule');
const conflict = Me.Util.getEnabledExtensions('custom-hot-corners').length ||
Me.Util.getEnabledExtensions('dash-to-panel').length;
Main.layoutManager._updateHotCorners = LayoutManagerCommon._updateHotCorners.bind(Main.layoutManager);
if (conflict && !reset)
console.warn(`[${Me.metadata.name}] Warning: "Layout" module disabled due to potential conflict with another extension`);
Main.layoutManager._updatePanelBarrier();
Main.layoutManager._updateHotCorners();
}
reset = reset || !this.moduleEnabled || conflict;
// don't touch the original code if module disabled
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation)
console.debug(' LayoutModule - Keeping untouched');
}
_activateModule() {
if (!this._overrides)
this._overrides = new Me.Util.Overrides();
_timeouts = {};
this._overrides.addOverride('LayoutManager', Main.layoutManager, LayoutManagerCommon);
this._overrides.addOverride('HotCorner', Layout.HotCorner.prototype, HotCornerCommon);
Main.layoutManager._updatePanelBarrier();
Main.layoutManager._updateHotCorners();
if (!this._hotCornersEnabledConId) {
this._interfaceSettings = new Gio.Settings({
schema_id: 'org.gnome.desktop.interface',
});
this._hotCornersEnabledConId = this._interfaceSettings.connect('changed::enable-hot-corners',
() => Main.layoutManager._updateHotCorners());
}
console.debug(' LayoutModule - Activated');
}
_disableModule() {
if (this._overrides)
this._overrides.removeAll();
this._overrides = null;
Main.layoutManager._updateHotCorners();
if (this._hotCornersEnabledConId) {
this._interfaceSettings.disconnect(this._hotCornersEnabledConId);
this._hotCornersEnabledConId = 0;
this._interfaceSettings = null;
}
console.debug(' LayoutModule - Disabled');
}
_removeTimeouts() {
if (_timeouts) {
Object.values(_timeouts).forEach(t => {
if (t)
GLib.source_remove(t);
});
_timeouts = null;
}
}
};
const LayoutManagerCommon = {
_updatePanelBarrier() {
@ -84,7 +124,7 @@ const LayoutManagerCommon = {
this._leftPanelBarrier = null;
}
if (!this.primaryMonitor || !opt)
if (!this.primaryMonitor || !opt || Me.Util.getEnabledExtensions('hidetopbar'))
return;
if (this.panelBox.height) {
@ -113,6 +153,7 @@ const LayoutManagerCommon = {
// avoid errors if called from foreign override
if (!opt)
return;
// destroy old hot corners
this.hotCorners.forEach(corner => corner?.destroy());
this.hotCorners = [];
@ -122,7 +163,7 @@ const LayoutManagerCommon = {
return;
}
let size = this.panelBox.height;
let size = this.panelBox.height ? this.panelBox.height : 27;
// position 0 - default, 1-TL, 2-TR, 3-BL, 4-BR
const position = opt.HOT_CORNER_POSITION;
@ -181,8 +222,8 @@ const LayoutManagerCommon = {
}
if (haveCorner) {
let corner = new HotCorner(this, monitor, cornerX, cornerY);
corner.setBarrierSize(size);
let corner = new Layout.HotCorner(this, monitor, cornerX, cornerY);
corner.setBarrierSize(size, false);
this.hotCorners.push(corner);
} else {
this.hotCorners.push(null);
@ -193,11 +234,8 @@ const LayoutManagerCommon = {
},
};
var HotCorner = GObject.registerClass(
class HotCorner extends Layout.HotCorner {
_init(layoutManager, monitor, x, y) {
super._init(layoutManager, monitor, x, y);
const HotCornerCommon = {
after__init() {
let angle = 0;
switch (opt.HOT_CORNER_POSITION) {
case 2:
@ -214,9 +252,14 @@ class HotCorner extends Layout.HotCorner {
this._ripples._ripple1.rotation_angle_z = angle;
this._ripples._ripple2.rotation_angle_z = angle;
this._ripples._ripple3.rotation_angle_z = angle;
}
},
setBarrierSize(size, notMyCall = true) {
// ignore calls from the original _updateHotCorners() callback to avoid building barriers outside screen
if (notMyCall && size > 0) {
return;
}
setBarrierSize(size) {
if (this._verticalBarrier) {
this._pressureBarrier.removeBarrier(this._verticalBarrier);
this._verticalBarrier.destroy();
@ -232,8 +275,8 @@ class HotCorner extends Layout.HotCorner {
if (size > 0) {
const primaryMonitor = global.display.get_primary_monitor();
const monitor = this._monitor;
const extendV = opt && opt.HOT_CORNER_EDGE && opt.DASH_VERTICAL && monitor.index === primaryMonitor;
const extendH = opt && opt.HOT_CORNER_EDGE && !opt.DASH_VERTICAL && monitor.index === primaryMonitor;
const extendV = opt && opt.HOT_CORNER_ACTION && opt.HOT_CORNER_EDGE && opt.DASH_VERTICAL && monitor.index === primaryMonitor;
const extendH = opt && opt.HOT_CORNER_ACTION && opt.HOT_CORNER_EDGE && !opt.DASH_VERTICAL && monitor.index === primaryMonitor;
if (opt.HOT_CORNER_POSITION <= 1) {
this._verticalBarrier = new Meta.Barrier({
@ -284,25 +327,52 @@ class HotCorner extends Layout.HotCorner {
this._pressureBarrier.addBarrier(this._verticalBarrier);
this._pressureBarrier.addBarrier(this._horizontalBarrier);
}
}
},
_toggleOverview() {
if (!opt.HOT_CORNER_ACTION || (!opt.HOT_CORNER_FULLSCREEN && this._monitor.inFullscreen && !Main.overview.visible))
return;
if (Main.overview.shouldToggleByCornerOrButton()) {
if ((opt.HOT_CORNER_ACTION === 1 && !_Util.isCtrlPressed()) || (opt.HOT_CORNER_ACTION === 2 && _Util.isCtrlPressed()))
if (Main.overview._shown) {
this._toggleWindowPicker(true);
else if ((opt.HOT_CORNER_ACTION === 2 && !_Util.isCtrlPressed()) || (opt.HOT_CORNER_ACTION === 1 && _Util.isCtrlPressed()) || (opt.HOT_CORNER_ACTION === 3 && _Util.isCtrlPressed()))
} else if ((opt.HOT_CORNER_ACTION === 2 && !Me.Util.isCtrlPressed()) || ([3, 4, 5, 6].includes(opt.HOT_CORNER_ACTION) && Me.Util.isCtrlPressed())) {
// Default overview
opt.OVERVIEW_MODE = 0;
opt.OVERVIEW_MODE2 = false;
opt.WORKSPACE_MODE = 1;
this._toggleWindowPicker(true, true);
} else if (opt.HOT_CORNER_ACTION === 1) {
Main.overview.resetOverviewMode();
this._toggleWindowPicker(true, true);
} else if ((opt.HOT_CORNER_ACTION === 3 && !Me.Util.isCtrlPressed()) || (opt.HOT_CORNER_ACTION === 2 && Me.Util.isCtrlPressed()) || (opt.HOT_CORNER_ACTION === 6 && Me.Util.isCtrlPressed())) {
// Applications
this._toggleApplications(true);
else if (opt.HOT_CORNER_ACTION === 3 && !_Util.isCtrlPressed())
} else if (opt.HOT_CORNER_ACTION === 4 && !Me.Util.isCtrlPressed()) {
// Overview - static ws preview
opt.OVERVIEW_MODE = 1;
opt.OVERVIEW_MODE2 = false;
opt.WORKSPACE_MODE = 0;
this._toggleWindowPicker(true, true);
} else if (opt.HOT_CORNER_ACTION === 5 && !Me.Util.isCtrlPressed()) {
// Overview - static ws
opt.OVERVIEW_MODE = 2;
opt.OVERVIEW_MODE2 = true;
opt.WORKSPACE_MODE = 0;
this._toggleWindowPicker(true, true);
} else if (opt.HOT_CORNER_ACTION === 6 && !Me.Util.isCtrlPressed()) {
// Window search provider
opt.OVERVIEW_MODE = 2;
opt.OVERVIEW_MODE2 = true;
opt.WORKSPACE_MODE = 0;
this._toggleWindowSearchProvider();
}
if (opt.HOT_CORNER_RIPPLES && Main.overview.animationInProgress)
this._ripples.playAnimation(this._x, this._y);
}
}
},
_toggleWindowPicker(leaveOverview = false) {
_toggleWindowPicker(leaveOverview = false, customOverviewMode = false) {
if (Main.overview._shown && (leaveOverview || !Main.overview.dash.showAppsButton.checked)) {
Main.overview.hide();
} else if (Main.overview.dash.showAppsButton.checked) {
@ -320,17 +390,17 @@ class HotCorner extends Layout.HotCorner {
// delay cannot be too short
200,
() => {
Main.overview.show();
Main.overview.show(1, customOverviewMode);
_timeouts.releaseKeyboardTimeoutId = 0;
return GLib.SOURCE_REMOVE;
}
);
} else {
Main.overview.show();
Main.overview.show(1, customOverviewMode);
}
}
}
},
_toggleApplications(leaveOverview = false) {
if ((leaveOverview && Main.overview._shown) || Main.overview.dash.showAppsButton.checked) {
@ -360,12 +430,15 @@ class HotCorner extends Layout.HotCorner {
Main.overview.show(2); // 2 for App Grid
}
}
}
},
_toggleWindowSearchProvider() {
if (!Main.overview._overview._controls._searchController._searchActive) {
this._toggleWindowPicker();
const prefix = 'wq// ';
opt.OVERVIEW_MODE = 2;
opt.OVERVIEW_MODE2 = true;
opt.WORKSPACE_MODE = 0;
this._toggleWindowPicker(false, true);
const prefix = Me.WSP_PREFIX;
const position = prefix.length;
const searchEntry = Main.overview.searchEntry;
searchEntry.set_text(prefix);
@ -376,5 +449,5 @@ class HotCorner extends Layout.HotCorner {
// Main.overview.searchEntry.text = '';
Main.overview.hide();
}
}
});
},
};

View file

@ -10,58 +10,82 @@
'use strict';
const { Clutter } = imports.gi;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const Clutter = imports.gi.Clutter;
const Main = imports.ui.main;
let Me;
let opt;
let _firstRun = true;
function update(reset = false) {
opt = Me.imports.lib.settings.opt;
const moduleEnabled = opt.get('messageTrayModule', true);
reset = reset || !moduleEnabled;
var MessageTrayModule = class {
constructor(me) {
Me = me;
opt = Me.opt;
// don't even touch this module if disabled
if (_firstRun && reset)
return;
this._firstActivation = true;
this.moduleEnabled = false;
}
_firstRun = false;
if (reset) {
cleanGlobals() {
Me = null;
opt = null;
setNotificationPosition(1);
return;
}
setNotificationPosition(opt.NOTIFICATION_POSITION);
}
update(reset) {
this.moduleEnabled = opt.get('messageTrayModule');
const conflict = false;
function setNotificationPosition(position) {
switch (position) {
case 0:
Main.messageTray._bannerBin.x_align = Clutter.ActorAlign.START;
Main.messageTray._bannerBin.y_align = Clutter.ActorAlign.START;
break;
case 1:
Main.messageTray._bannerBin.x_align = Clutter.ActorAlign.CENTER;
Main.messageTray._bannerBin.y_align = Clutter.ActorAlign.START;
break;
case 2:
Main.messageTray._bannerBin.x_align = Clutter.ActorAlign.END;
Main.messageTray._bannerBin.y_align = Clutter.ActorAlign.START;
break;
case 3:
Main.messageTray._bannerBin.x_align = Clutter.ActorAlign.START;
Main.messageTray._bannerBin.y_align = Clutter.ActorAlign.END;
break;
case 4:
Main.messageTray._bannerBin.x_align = Clutter.ActorAlign.CENTER;
Main.messageTray._bannerBin.y_align = Clutter.ActorAlign.END;
break;
case 5:
Main.messageTray._bannerBin.x_align = Clutter.ActorAlign.END;
Main.messageTray._bannerBin.y_align = Clutter.ActorAlign.END;
break;
reset = reset || !this.moduleEnabled || conflict;
// don't touch the original code if module disabled
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation)
console.debug(' MessageTrayModule - Keeping untouched');
}
}
_activateModule() {
this._setNotificationPosition(opt.NOTIFICATION_POSITION);
console.debug(' MessageTrayModule - Activated');
}
_disableModule() {
this._setNotificationPosition(1);
console.debug(' MessageTrayModule - Disabled');
}
_setNotificationPosition(position) {
switch (position) {
case 0:
Main.messageTray._bannerBin.x_align = Clutter.ActorAlign.START;
Main.messageTray._bannerBin.y_align = Clutter.ActorAlign.START;
break;
case 1:
Main.messageTray._bannerBin.x_align = Clutter.ActorAlign.CENTER;
Main.messageTray._bannerBin.y_align = Clutter.ActorAlign.START;
break;
case 2:
Main.messageTray._bannerBin.x_align = Clutter.ActorAlign.END;
Main.messageTray._bannerBin.y_align = Clutter.ActorAlign.START;
break;
case 3:
Main.messageTray._bannerBin.x_align = Clutter.ActorAlign.START;
Main.messageTray._bannerBin.y_align = Clutter.ActorAlign.END;
break;
case 4:
Main.messageTray._bannerBin.x_align = Clutter.ActorAlign.CENTER;
Main.messageTray._bannerBin.y_align = Clutter.ActorAlign.END;
break;
case 5:
Main.messageTray._bannerBin.x_align = Clutter.ActorAlign.END;
Main.messageTray._bannerBin.y_align = Clutter.ActorAlign.END;
break;
}
}
};

View file

@ -9,41 +9,35 @@
'use strict';
const { Gtk, Gio, GObject } = imports.gi;
const Adw = imports.gi.Adw;
const Gtk = imports.gi.Gtk;
const Gio = imports.gi.Gio;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Settings = Me.imports.lib.settings;
const shellVersion = Settings.shellVersion;
let Me;
// gettext
const _ = Settings._;
let _; // = Settings._;
const ProfileNames = [
_('GNOME 3'),
_('GNOME 40+ - Bottom Hot Edge'),
_('Hot Corner Centric - Top Left Hot Corner'),
_('Dock Overview - Bottom Hot Edge'),
];
function init(me) {
Me = me;
_ = Me.gettext;
}
// libadwaita is available starting with GNOME Shell 42.
let Adw = null;
try {
Adw = imports.gi.Adw;
} catch (e) {}
function cleanGlobals() {
Me = null;
_ = null;
}
function _newImageFromIconName(name) {
return Gtk.Image.new_from_icon_name(name);
}
var ItemFactory = class ItemFactory {
constructor(gOptions) {
this._gOptions = gOptions;
this._settings = this._gOptions._gsettings;
constructor() {
this._settings = Me.Opt._gsettings;
}
getRowWidget(text, caption, widget, variable, options = []) {
getRowWidget(text, caption, widget, variable, options = [], dependsOn) {
let item = [];
let label;
if (widget) {
@ -81,8 +75,8 @@ var ItemFactory = class ItemFactory {
let key;
if (variable && this._gOptions.options[variable]) {
const opt = this._gOptions.options[variable];
if (variable && Me.Opt.options[variable]) {
const opt = Me.Opt.options[variable];
key = opt[1];
}
@ -95,6 +89,11 @@ var ItemFactory = class ItemFactory {
this._connectComboBox(widget, key, variable, options);
else if (widget._isDropDown)
this._connectDropDown(widget, key, variable, options);
if (dependsOn) {
const dKey = Me.Opt.options[dependsOn][1];
this._settings.bind(dKey, widget, 'sensitive', Gio.SettingsBindFlags.GET);
}
}
return item;
@ -111,7 +110,7 @@ var ItemFactory = class ItemFactory {
_connectComboBox(widget, key, variable, options) {
let model = widget.get_model();
widget._comboMap = {};
const currentValue = this._gOptions.get(variable);
const currentValue = Me.Opt.get(variable);
for (const [label, value] of options) {
let iter;
model.set(iter = model.append(), [0, 1], [label, value]);
@ -120,8 +119,8 @@ var ItemFactory = class ItemFactory {
widget._comboMap[value] = iter;
}
this._gOptions.connect(`changed::${key}`, () => {
widget.set_active_iter(widget._comboMap[this._gOptions.get(variable, true)]);
Me.Opt.connect(`changed::${key}`, () => {
widget.set_active_iter(widget._comboMap[Me.Opt.get(variable, true)]);
});
widget.connect('changed', () => {
const [success, iter] = widget.get_active_iter();
@ -129,17 +128,17 @@ var ItemFactory = class ItemFactory {
if (!success)
return;
this._gOptions.set(variable, model.get_value(iter, 1));
Me.Opt.set(variable, model.get_value(iter, 1));
});
}
_connectDropDown(widget, key, variable, options) {
const model = widget.get_model();
const currentValue = this._gOptions.get(variable);
const currentValue = Me.Opt.get(variable);
for (let i = 0; i < options.length; i++) {
const text = options[i][0];
const id = options[i][1];
model.append(new DropDownItem({ text, id }));
model.append(new DropDownItemVW({ text, id }));
if (id === currentValue)
widget.set_selected(i);
}
@ -157,11 +156,11 @@ var ItemFactory = class ItemFactory {
widget.connect('notify::selected-item', dropDown => {
const item = dropDown.get_selected_item();
this._gOptions.set(variable, item.id);
Me.Opt.set(variable, item.id);
});
this._gOptions.connect(`changed::${key}`, () => {
const newId = this._gOptions.get(variable, true);
Me.Opt.connect(`changed::${key}`, () => {
const newId = Me.Opt.get(variable, true);
for (let i = 0; i < options.length; i++) {
const id = options[i][1];
if (id === newId)
@ -214,7 +213,7 @@ var ItemFactory = class ItemFactory {
newDropDown() {
const dropDown = new Gtk.DropDown({
model: new Gio.ListStore({
item_type: DropDownItem,
item_type: DropDownItemVW,
}),
halign: Gtk.Align.END,
valign: Gtk.Align.CENTER,
@ -255,11 +254,11 @@ var ItemFactory = class ItemFactory {
newLinkButton(uri) {
const linkBtn = new Gtk.LinkButton({
label: shellVersion < 42 ? 'Click Me!' : '',
uri,
halign: Gtk.Align.END,
valign: Gtk.Align.CENTER,
hexpand: true,
icon_name: 'emblem-symbolic-link',
});
return linkBtn;
}
@ -298,18 +297,23 @@ var ItemFactory = class ItemFactory {
entry.set_text(opt.get(`profileName${profileIndex}`));
entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, 'edit-clear-symbolic');
entry.set_icon_activatable(Gtk.EntryIconPosition.SECONDARY, true);
entry.connect('icon-press', e => e.set_text(''));
entry.connect('changed', e => opt.set(`profileName${profileIndex}`, e.get_text()));
const resetProfile = this.newButton();
resetProfile.set({
tooltip_text: _('Reset profile to defaults'),
icon_name: 'edit-delete-symbolic',
icon_name: 'document-revert-symbolic',
hexpand: false,
css_classes: ['destructive-action'],
});
function setName() {
const ProfileNames = [
_('GNOME 3'),
_('GNOME 40+ - Bottom Hot Edge'),
_('Hot Corner Centric - Top Left Hot Corner'),
_('Dock Overview - Bottom Hot Edge'),
];
let name = opt.get(`profileName${profileIndex}`, true);
if (!name)
name = ProfileNames[profileIndex - 1];
@ -317,6 +321,10 @@ var ItemFactory = class ItemFactory {
}
setName();
entry.connect('icon-press', e => e.set_text(''));
entry.connect('changed', e => opt.set(`profileName${profileIndex}`, e.get_text()));
resetProfile.connect('clicked', () => {
reset(profileIndex);
setName();
@ -366,7 +374,7 @@ var ItemFactory = class ItemFactory {
valign: Gtk.Align.CENTER,
hexpand: true,
css_classes: ['destructive-action'],
icon_name: 'edit-delete-symbolic',
icon_name: 'document-revert-symbolic',
});
btn.connect('clicked', () => {
@ -382,7 +390,7 @@ var ItemFactory = class ItemFactory {
var AdwPrefs = class {
constructor(gOptions) {
this._gOptions = gOptions;
Me.Opt = gOptions;
}
getFilledWindow(window, pages) {
@ -457,158 +465,9 @@ var AdwPrefs = class {
}
};
var LegacyPrefs = class {
constructor(gOptions) {
this._gOptions = gOptions;
}
getPrefsWidget(pages) {
const prefsWidget = new Gtk.Box({
orientation: Gtk.Orientation.VERTICAL,
});
const stack = new Gtk.Stack({
hexpand: true,
});
const stackSwitcher = new Gtk.StackSwitcher({
halign: Gtk.Align.CENTER,
hexpand: true,
});
const context = stackSwitcher.get_style_context();
context.add_class('caption');
stackSwitcher.set_stack(stack);
stack.set_transition_duration(300);
stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT);
const pageProperties = {
hscrollbar_policy: Gtk.PolicyType.NEVER,
vscrollbar_policy: Gtk.PolicyType.AUTOMATIC,
vexpand: true,
hexpand: true,
visible: true,
};
const pagesBtns = [];
for (let page of pages) {
const name = page.name;
const title = page.title;
const iconName = page.iconName;
const optionList = page.optionList;
stack.add_named(this._getLegacyPage(optionList, pageProperties), name);
pagesBtns.push(
[new Gtk.Label({ label: title }), _newImageFromIconName(iconName, Gtk.IconSize.BUTTON)]
);
}
let stBtn = stackSwitcher.get_first_child ? stackSwitcher.get_first_child() : null;
for (let i = 0; i < pagesBtns.length; i++) {
const box = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, spacing: 6, visible: true });
const icon = pagesBtns[i][1];
icon.margin_start = 30;
icon.margin_end = 30;
box.append(icon);
box.append(pagesBtns[i][0]);
if (stackSwitcher.get_children) {
stBtn = stackSwitcher.get_children()[i];
stBtn.add(box);
} else {
stBtn.set_child(box);
stBtn.visible = true;
stBtn = stBtn.get_next_sibling();
}
}
if (stack.show_all)
stack.show_all();
if (stackSwitcher.show_all)
stackSwitcher.show_all();
prefsWidget.append(stack);
if (prefsWidget.show_all)
prefsWidget.show_all();
prefsWidget._stackSwitcher = stackSwitcher;
return prefsWidget;
}
_getLegacyPage(optionList, pageProperties) {
const page = new Gtk.ScrolledWindow(pageProperties);
const mainBox = new Gtk.Box({
orientation: Gtk.Orientation.VERTICAL,
spacing: 5,
homogeneous: false,
margin_start: 30,
margin_end: 30,
margin_top: 12,
margin_bottom: 12,
});
let context = page.get_style_context();
context.add_class('background');
let frame;
let frameBox;
for (let item of optionList) {
// label can be plain text for Section Title
// or GtkBox for Option
const option = item[0];
const widget = item[1];
if (!widget) {
const lbl = new Gtk.Label({
label: option,
xalign: 0,
margin_bottom: 4,
});
context = lbl.get_style_context();
context.add_class('heading');
mainBox.append(lbl);
frame = new Gtk.Frame({
margin_bottom: 16,
});
frameBox = new Gtk.ListBox({
selection_mode: null,
});
mainBox.append(frame);
frame.set_child(frameBox);
continue;
}
const grid = new Gtk.Grid({
column_homogeneous: false,
column_spacing: 20,
margin_start: 8,
margin_end: 8,
margin_top: 8,
margin_bottom: 8,
hexpand: true,
});
grid.attach(option, 0, 0, 5, 1);
if (widget)
grid.attach(widget, 5, 0, 2, 1);
frameBox.append(grid);
}
page.set_child(mainBox);
return page;
}
};
const DropDownItem = GObject.registerClass({
GTypeName: 'DropdownItem',
const { GObject } = imports.gi;
const DropDownItemVW = GObject.registerClass({
GTypeName: 'DropDownItemVW',
Properties: {
'text': GObject.ParamSpec.string(
'text',
@ -622,10 +481,11 @@ const DropDownItem = GObject.registerClass({
'Id',
'Item id stored in settings',
GObject.ParamFlags.READWRITE,
0, 100, 0
// min, max, default
-2147483648, 2147483647, 0
),
},
}, class DropDownItem extends GObject.Object {
}, class DropDownItemVW extends GObject.Object {
get text() {
return this._text;
}
@ -641,5 +501,4 @@ const DropDownItem = GObject.registerClass({
set id(id) {
this._id = id;
}
}
);
});

View file

@ -10,79 +10,104 @@
'use strict';
const { Clutter } = imports.gi;
const Clutter = imports.gi.Clutter;
const Main = imports.ui.main;
const OsdWindow = imports.ui.osdWindow;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const _Util = Me.imports.lib.util;
const OsdPositions = {
1: {
x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.START,
},
2: {
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.START,
},
3: {
x_align: Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.START,
},
4: {
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER,
},
5: {
x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.END,
},
6: {
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.END,
},
7: {
x_align: Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.END,
},
};
let _overrides;
let Me;
let opt;
let _firstRun = true;
function update(reset = false) {
opt = Me.imports.lib.settings.opt;
const moduleEnabled = opt.get('osdWindowModule', true);
reset = reset || !moduleEnabled;
let OsdPositions;
// don't even touch this module if disabled
if (_firstRun && reset)
return;
var OsdWindowModule = class {
constructor(me) {
Me = me;
opt = Me.opt;
_firstRun = false;
this._firstActivation = true;
this.moduleEnabled = false;
this._overrides = null;
if (_overrides)
_overrides.removeAll();
if (reset || !moduleEnabled) {
updateExistingOsdWindows(6);
_overrides = null;
opt = null;
return;
OsdPositions = {
1: {
x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.START,
},
2: {
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.START,
},
3: {
x_align: Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.START,
},
4: {
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER,
},
5: {
x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.END,
},
6: {
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.END,
},
7: {
x_align: Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.END,
},
};
}
_overrides = new _Util.Overrides();
_overrides.addOverride('osdWindow', OsdWindow.OsdWindow.prototype, OsdWindowCommon);
}
cleanGlobals() {
Me = null;
opt = null;
OsdPositions = null;
}
function updateExistingOsdWindows(position) {
position = position ? position : opt.OSD_POSITION;
Main.osdWindowManager._osdWindows.forEach(osd => {
osd.set(OsdPositions[position]);
});
}
update(reset) {
this.moduleEnabled = opt.get('osdWindowModule');
const conflict = false;
reset = reset || !this.moduleEnabled || conflict;
// don't touch the original code if module disabled
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation)
console.debug(' OsdWindowModule - Keeping untouched');
}
_activateModule() {
if (!this._overrides)
this._overrides = new Me.Util.Overrides();
this._overrides.addOverride('osdWindow', OsdWindow.OsdWindow.prototype, OsdWindowCommon);
console.debug(' OsdWindowModule - Activated');
}
_disableModule() {
if (this._overrides)
this._overrides.removeAll();
this._overrides = null;
this._updateExistingOsdWindows(6);
console.debug(' WorkspaceSwitcherPopupModule - Disabled');
}
_updateExistingOsdWindows(position) {
position = position ? position : opt.OSD_POSITION;
Main.osdWindowManager._osdWindows.forEach(osd => {
osd.set(OsdPositions[position]);
});
}
};
const OsdWindowCommon = {
after_show() {

View file

@ -9,81 +9,94 @@
*/
'use strict';
const { GObject, Gio, GLib, Meta, St } = imports.gi;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Meta = imports.gi.Meta;
const St = imports.gi.St;
const Main = imports.ui.main;
const Overview = imports.ui.overview;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const _Util = Me.imports.lib.util;
const _ = Me.imports.lib.settings._;
const shellVersion = _Util.shellVersion;
const WIN_SEARCH_PREFIX = Me.imports.lib.windowSearchProvider.prefix;
const RECENT_FILES_PREFIX = Me.imports.lib.recentFilesSearchProvider.prefix;
const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
let Me;
let opt;
let _firstRun = true;
let _originalOverlayKeyHandlerId;
let _overlayKeyHandlerId;
var OverlayKeyModule = class {
constructor(me) {
Me = me;
opt = Me.opt;
function update(reset = false) {
opt = Me.imports.lib.settings.opt;
const moduleEnabled = opt.get('overlayKeyModule', true);
reset = reset || (!_firstRun && !moduleEnabled);
this._firstActivation = true;
this.moduleEnabled = false;
this._originalOverlayKeyHandlerId = 0;
this._overlayKeyHandlerId = 0;
}
// don't even touch this module if disabled
if (_firstRun && !moduleEnabled)
return;
_firstRun = false;
if (reset) {
_updateOverlayKey(reset);
cleanGlobals() {
Me = null;
opt = null;
return;
}
_updateOverlayKey();
}
update(reset) {
this.moduleEnabled = opt.get('overlayKeyModule');
const conflict = false;
function _updateOverlayKey(reset = false) {
if (reset) {
_restoreOverlayKeyHandler();
} else if (!_originalOverlayKeyHandlerId) {
_originalOverlayKeyHandlerId = GObject.signal_handler_find(global.display, { signalId: 'overlay-key' });
if (_originalOverlayKeyHandlerId !== null)
global.display.block_signal_handler(_originalOverlayKeyHandlerId);
_connectOverlayKey.bind(Main.overview._overview.controls)();
}
}
reset = reset || !this.moduleEnabled || conflict;
function _restoreOverlayKeyHandler() {
// Disconnect modified overlay key handler
if (_overlayKeyHandlerId !== null) {
global.display.disconnect(_overlayKeyHandlerId);
_overlayKeyHandlerId = null;
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation)
console.debug(' OverlayKeyModule - Keeping untouched');
}
// Unblock original overlay key handler
if (_originalOverlayKeyHandlerId !== null) {
global.display.unblock_signal_handler(_originalOverlayKeyHandlerId);
_originalOverlayKeyHandlerId = null;
_activateModule() {
if (!this._originalOverlayKeyHandlerId) {
this._originalOverlayKeyHandlerId = GObject.signal_handler_find(global.display, { signalId: 'overlay-key' });
if (this._originalOverlayKeyHandlerId !== null) {
global.display.block_signal_handler(this._originalOverlayKeyHandlerId);
this._connectOverlayKey();
}
}
console.debug(' OverlayKeyModule - Activated');
}
}
function _connectOverlayKey() {
this._a11ySettings = new Gio.Settings({ schema_id: A11Y_SCHEMA });
_disableModule() {
this._restoreOverlayKeyHandler();
this._lastOverlayKeyTime = 0;
_overlayKeyHandlerId = global.display.connect('overlay-key', () => {
console.debug(' OverlayKeyModule - Disabled');
}
_restoreOverlayKeyHandler() {
// Disconnect modified overlay key handler
if (this._overlayKeyHandlerId) {
global.display.disconnect(this._overlayKeyHandlerId);
this._overlayKeyHandlerId = 0;
}
// Unblock original overlay key handler
if (this._originalOverlayKeyHandlerId) {
global.display.unblock_signal_handler(this._originalOverlayKeyHandlerId);
this._originalOverlayKeyHandlerId = 0;
}
}
_connectOverlayKey() {
if (this._overlayKeyHandlerId)
return;
this._overlayKeyHandlerId = global.display.connect('overlay-key', this._onOverlayKeyPressed.bind(Main.overview._overview.controls));
}
_onOverlayKeyPressed() {
if (this._a11ySettings.get_boolean('stickykeys-enable'))
return;
const { initialState, finalState, transitioning } =
this._stateAdjustment.getStateTransitionParams();
this._stateAdjustment.getStateTransitionParams();
const time = GLib.get_monotonic_time() / 1000;
const timeDiff = time - this._lastOverlayKeyTime;
@ -95,14 +108,61 @@ function _connectOverlayKey() {
const mode = opt.OVERLAY_KEY_SECONDARY;
if (shouldShift) {
if (mode === 1)
Me.Util.activateSearchProvider('');
if (mode === 1) {
this._shiftState(Meta.MotionDirection.UP);
else if (mode === 2)
_Util.activateSearchProvider(WIN_SEARCH_PREFIX);
else if (mode === 3)
_Util.activateSearchProvider(RECENT_FILES_PREFIX);
} else if (mode === 2) {
Me.Util.activateSearchProvider(Me.WSP_PREFIX);
} else if (mode === 3) {
// Changing the overview mode automatically changes the overview transition
opt.OVERVIEW_MODE = 0;
opt.OVERVIEW_MODE2 = false;
opt.WORKSPACE_MODE = 1;
}
} else {
Main.overview.toggle();
if (Main.overview._shown) {
Main.overview.hide();
return;
}
switch (opt.OVERLAY_KEY_PRIMARY) {
case 0: // Disabled
return;
case 1: // Follow global overview mode
Main.overview.resetOverviewMode();
break;
case 2: // Default overview
opt.OVERVIEW_MODE = 0;
opt.OVERVIEW_MODE2 = false;
opt.WORKSPACE_MODE = 1;
break;
case 3: // Default overview
if (Main.overview._shown)
Main.overview.hide();
else
Main.overview.show(2);
return;
case 4: // Static WS preview
opt.OVERVIEW_MODE = 1;
opt.OVERVIEW_MODE2 = false;
if (!Main.overview._shown)
opt.WORKSPACE_MODE = 0;
break;
case 5: // Static WS
opt.OVERVIEW_MODE = 2;
opt.OVERVIEW_MODE2 = true;
opt.WORKSPACE_MODE = 0;
break;
case 6: // Window Search
opt.OVERVIEW_MODE = 2;
opt.OVERVIEW_MODE2 = true;
if (!Main.overview._shown)
opt.WORKSPACE_MODE = 0;
break;
}
const customOverviewMode = !Main.overview._shown;
Main.overview.toggle(customOverviewMode);
if (opt.OVERLAY_KEY_PRIMARY === 6)
Me.Util.activateSearchProvider(Me.WSP_PREFIX);
}
});
}
}
};

View file

@ -10,43 +10,113 @@
'use strict';
const Main = imports.ui.main;
const Overview = imports.ui.overview;
const OverviewControls = imports.ui.overviewControls;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const _Util = Me.imports.lib.util;
let _overrides;
let Me;
let opt;
function update(reset = false) {
if (_overrides)
_overrides.removeAll();
var OverviewModule = class {
constructor(me) {
Me = me;
opt = Me.opt;
if (reset) {
_overrides = null;
opt = null;
return;
this._firstActivation = true;
this.moduleEnabled = false;
this._overrides = null;
}
opt = Me.imports.lib.settings.opt;
_overrides = new _Util.Overrides();
cleanGlobals() {
Me = null;
opt = null;
}
_overrides.addOverride('Overview', Overview.Overview.prototype, OverviewCommon);
}
update(reset) {
this.moduleEnabled = true;
const conflict = false;
reset = reset || !this.moduleEnabled || conflict;
// don't touch the original code if module disabled
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation)
console.debug(' OverviewModule - Keeping untouched');
}
_activateModule() {
if (!this._overrides)
this._overrides = new Me.Util.Overrides();
this._overrides.addOverride('Overview', Overview.Overview.prototype, OverviewCommon);
console.debug(' OverviewModule - Activated');
}
_disableModule() {
if (this._overrides)
this._overrides.removeAll();
this._overrides = null;
console.debug(' OverviewModule - Disabled');
}
};
const OverviewCommon = {
show(state = OverviewControls.ControlsState.WINDOW_PICKER, customOverviewMode) {
if (!customOverviewMode)
this.resetOverviewMode();
if (state === OverviewControls.ControlsState.HIDDEN)
throw new Error('Invalid state, use hide() to hide');
if (this.isDummy)
return;
if (this._shown)
return;
this._shown = true;
if (!this._syncGrab())
return;
Main.layoutManager.showOverview();
this._animateVisible(state);
},
toggle(customOverviewMode) {
if (this.isDummy)
return;
if (this._visible)
this.hide();
else
this.show(OverviewControls.ControlsState.WINDOW_PICKER, customOverviewMode);
},
resetOverviewMode() {
// reset Overview Mode do default
opt.OVERVIEW_MODE = opt.get('overviewMode');
opt.OVERVIEW_MODE2 = opt.OVERVIEW_MODE === 2;
opt.WORKSPACE_MODE = opt.OVERVIEW_MODE > 0 ? 0 : 1;
},
_showDone() {
this._animationInProgress = false;
this._coverPane.hide();
this.emit('shown');
if (Me.shellVersion < 44)
this.emit('shown');
else if (this._shownState !== 'SHOWN')
this._changeShownState('SHOWN');
// Handle any calls to hide* while we were showing
if (!this._shown)
this._animateNotVisible();
this._syncGrab();
// if user activates overview during startup animation, transition needs to be shifted to the state 2 here
const controls = this._overview._controls;
if (controls._searchController._searchActive && controls._stateAdjustment.value === 1) {
@ -55,5 +125,41 @@ const OverviewCommon = {
else if (!opt.OVERVIEW_MODE2)
controls._stateAdjustment.value = 2;
}
this._syncGrab();
},
// Workaround - should probably be fixed elsewhere in the upstream code
// If a new window is opened from the overview
// and is realized before the overview animation is complete,
// the new window will not get focus
after__hideDone() {
if (!opt.FIX_NEW_WINDOW_FOCUS)
return;
const workspace = global.workspace_manager.get_active_workspace();
const recentDesktopWin = global.display.get_tab_list(1, workspace)[0];
let recentNormalWin = null;
const tabList = global.display.get_tab_list(0, workspace);
for (let i = 0; i < tabList.length; i++) {
if (tabList[i].minimized === false) {
recentNormalWin = tabList[i];
break;
}
}
let recentWin = recentNormalWin;
if (recentNormalWin && recentDesktopWin) {
recentWin = recentNormalWin.get_user_time() > recentDesktopWin.get_user_time()
? recentNormalWin
: recentDesktopWin;
}
const focusedWin = global.display.focus_window;
if (recentWin && focusedWin !== recentWin)
recentWin.activate(global.get_current_time());
},
};

File diff suppressed because it is too large Load diff

View file

@ -10,188 +10,247 @@
'use strict';
const { GLib } = imports.gi;
const Clutter = imports.gi.Clutter;
const Main = imports.ui.main;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const _Util = Me.imports.lib.util;
const ANIMATION_TIME = imports.ui.overview.ANIMATION_TIME;
const Overview = imports.ui.overview;
const Panel = imports.ui.panel;
let Me;
let opt;
let _firstRun = true;
let _showingOverviewConId;
let _hidingOverviewConId;
let _styleChangedConId;
const ANIMATION_TIME = Overview.ANIMATION_TIME;
function update(reset = false) {
opt = Me.imports.lib.settings.opt;
const moduleEnabled = opt.get('panelModule', true);
// Avoid conflict with other extensions
const conflict = _Util.getEnabledExtensions('dash-to-panel').length ||
_Util.getEnabledExtensions('hidetopbar').length;
reset = reset || (!_firstRun && !moduleEnabled);
var PanelModule = class {
constructor(me) {
Me = me;
opt = Me.opt;
// don't even touch this module if disabled or in potential conflict
if (_firstRun && (reset || conflict))
return;
this._firstActivation = true;
this.moduleEnabled = false;
this._overrides = null;
_firstRun = false;
const panelBox = Main.layoutManager.panelBox;
if (reset || !moduleEnabled) {
// _disconnectPanel();
reset = true;
_setPanelPosition(reset);
_updateOverviewConnection(reset);
_reparentPanel(false);
_updateStyleChangedConnection(reset);
panelBox.translation_y = 0;
Main.panel.opacity = 255;
_setPanelStructs(true);
return;
this._showingOverviewConId = 0;
this._hidingOverviewConId = 0;
this._styleChangedConId = 0;
}
_setPanelPosition();
_updateStyleChangedConnection();
cleanGlobals() {
Me = null;
opt = null;
}
if (opt.PANEL_MODE === 0) {
_updateOverviewConnection(true);
_reparentPanel(false);
panelBox.translation_y = 0;
Main.panel.opacity = 255;
_setPanelStructs(true);
} else if (opt.PANEL_MODE === 1) {
if (opt.SHOW_WS_PREVIEW_BG) {
_reparentPanel(true);
if (opt.OVERVIEW_MODE2) {
// in OM2 if the panel has been moved to the overviewGroup move panel above all
Main.layoutManager.overviewGroup.set_child_above_sibling(panelBox, null);
_updateOverviewConnection();
update(reset) {
this.moduleEnabled = opt.get('panelModule');
const conflict = Me.Util.getEnabledExtensions('dash-to-panel').length ||
Me.Util.getEnabledExtensions('hidetopbar').length;
if (conflict && !reset)
console.warn(`[${Me.metadata.name}] Warning: "Panel" module disabled due to potential conflict with another extension`);
reset = reset || !this.moduleEnabled || conflict || Main.sessionMode.isLocked;
// don't touch original code if module disabled
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation)
console.debug(' PanelModule - Keeping untouched');
}
_activateModule() {
if (!this._overrides)
this._overrides = new Me.Util.Overrides();
const panelBox = Main.layoutManager.panelBox;
this._setPanelPosition();
this._updateStyleChangedConnection();
if (opt.PANEL_MODE === 0) {
this._updateOverviewConnection(true);
this._reparentPanel(false);
panelBox.translation_y = 0;
Main.panel.opacity = 255;
this._setPanelStructs(true);
} else if (opt.PANEL_MODE === 1) {
if (opt.SHOW_WS_PREVIEW_BG) {
this._reparentPanel(true);
if (opt.OVERVIEW_MODE2) {
// in OM2 if the panel has been moved to the overviewGroup move panel above all
Main.layoutManager.overviewGroup.set_child_above_sibling(panelBox, null);
this._updateOverviewConnection();
} else {
// otherwise move the panel below overviewGroup so it can get below workspacesDisplay
Main.layoutManager.overviewGroup.set_child_below_sibling(panelBox, Main.overview._overview);
this._updateOverviewConnection(true);
}
this._showPanel(true);
} else {
// otherwise move the panel below overviewGroup so it can get below workspacesDisplay
Main.layoutManager.overviewGroup.set_child_below_sibling(panelBox, Main.overview._overview);
_updateOverviewConnection(true);
// if ws preview bg is disabled, panel can stay in uiGroup
this._reparentPanel(false);
this._showPanel(false);
this._updateOverviewConnection();
}
_showPanel(true);
} else {
// if ws preview bg is disabled, panel can stay in uiGroup
_reparentPanel(false);
_showPanel(false);
_updateOverviewConnection();
// _connectPanel();
} else if (opt.PANEL_MODE === 2) {
this._updateOverviewConnection(true);
this._reparentPanel(false);
this._showPanel(false);
// _connectPanel();
}
// _connectPanel();
} else if (opt.PANEL_MODE === 2) {
_updateOverviewConnection(true);
_reparentPanel(false);
_showPanel(false);
// _connectPanel();
this._setPanelStructs(opt.PANEL_MODE === 0);
Main.layoutManager._updateHotCorners();
this._overrides.addOverride('ActivitiesButton', Panel.ActivitiesButton.prototype, ActivitiesButton);
console.debug(' PanelModule - Activated');
}
_setPanelStructs(opt.PANEL_MODE === 0);
Main.layoutManager._updateHotCorners();
}
function _setPanelPosition(reset = false) {
const geometry = global.display.get_monitor_geometry(global.display.get_primary_monitor());
const panelBox = Main.layoutManager.panelBox;
const panelHeight = Main.panel.height; // panelBox height can be 0 after shell start
_disableModule() {
const reset = true;
this._setPanelPosition(reset);
this._updateOverviewConnection(reset);
this._reparentPanel(false);
if (opt.PANEL_POSITION_TOP || reset)
panelBox.set_position(geometry.x, geometry.y);
else
panelBox.set_position(geometry.x, geometry.y + geometry.height - panelHeight);
}
this._updateStyleChangedConnection(reset);
function _updateStyleChangedConnection(reset = false) {
if (reset) {
if (_styleChangedConId) {
Main.panel.disconnect(_styleChangedConId);
_styleChangedConId = 0;
}
} else if (!_styleChangedConId) {
Main.panel.connect('style-changed', () => {
if (opt.PANEL_MODE === 1)
Main.panel.add_style_pseudo_class('overview');
else if (opt.OVERVIEW_MODE2)
Main.panel.remove_style_pseudo_class('overview');
});
}
}
function _updateOverviewConnection(reset = false) {
if (reset) {
if (_hidingOverviewConId) {
Main.overview.disconnect(_hidingOverviewConId);
_hidingOverviewConId = 0;
}
if (_showingOverviewConId) {
Main.overview.disconnect(_showingOverviewConId);
_showingOverviewConId = 0;
}
} else {
if (!_hidingOverviewConId) {
_hidingOverviewConId = Main.overview.connect('hiding', () => {
if (!opt.SHOW_WS_PREVIEW_BG || opt.OVERVIEW_MODE2)
_showPanel(false);
});
}
if (!_showingOverviewConId) {
_showingOverviewConId = Main.overview.connect('showing', () => {
if (!opt.SHOW_WS_PREVIEW_BG || opt.OVERVIEW_MODE2 || Main.layoutManager.panelBox.translation_y)
_showPanel(true);
});
}
}
}
function _reparentPanel(reparent = false) {
const panel = Main.layoutManager.panelBox;
if (reparent && panel.get_parent() === Main.layoutManager.uiGroup) {
Main.layoutManager.uiGroup.remove_child(panel);
Main.layoutManager.overviewGroup.add_child(panel);
} else if (!reparent && panel.get_parent() === Main.layoutManager.overviewGroup) {
Main.layoutManager.overviewGroup.remove_child(panel);
// return the panel at default position, panel shouldn't cover objects that should be above
Main.layoutManager.uiGroup.insert_child_at_index(panel, 4);
}
}
function _setPanelStructs(state) {
Main.layoutManager._trackedActors.forEach(a => {
if (a.actor === Main.layoutManager.panelBox)
a.affectsStruts = state;
});
// workaround to force maximized windows to resize after removing affectsStruts
// simulation of minimal swipe gesture to the opposite direction
// todo - needs better solution!!!!!!!!!!!
// const direction = _getAppGridAnimationDirection() === 2 ? 1 : -1;
// Main.overview._swipeTracker._beginTouchSwipe(null, global.get_current_time(), 1, 1);
// Main.overview._swipeTracker._updateGesture(null, global.get_current_time(), direction, 1);
// GLib.timeout_add(0, 50, () => Main.overview._swipeTracker._endGesture(global.get_current_time(), 1, true));*/
}
function _showPanel(show = true) {
if (show) {
const panelBox = Main.layoutManager.panelBox;
panelBox.translation_y = 0;
Main.panel.opacity = 255;
Main.layoutManager.panelBox.ease({
duration: ANIMATION_TIME,
translation_y: 0,
onComplete: () => {
_setPanelStructs(opt.PANEL_MODE === 0);
},
});
} else {
const panelHeight = Main.panel.height;
Main.layoutManager.panelBox.ease({
duration: ANIMATION_TIME,
translation_y: opt.PANEL_POSITION_TOP ? -panelHeight + 1 : panelHeight - 1,
onComplete: () => {
Main.panel.opacity = 0;
_setPanelStructs(opt.PANEL_MODE === 0);
},
});
this._setPanelStructs(true);
if (this._overrides)
this._overrides.removeAll();
this._overrides = null;
console.debug(' PanelModule - Disabled');
}
}
_setPanelPosition(reset = false) {
const geometry = global.display.get_monitor_geometry(global.display.get_primary_monitor());
const panelBox = Main.layoutManager.panelBox;
const panelHeight = Main.panel.height; // panelBox height can be 0 after shell start
if (opt.PANEL_POSITION_TOP || reset)
panelBox.set_position(geometry.x, geometry.y);
else
panelBox.set_position(geometry.x, geometry.y + geometry.height - panelHeight);
}
_updateStyleChangedConnection(reset = false) {
if (reset) {
if (this._styleChangedConId) {
Main.panel.disconnect(this._styleChangedConId);
this._styleChangedConId = 0;
}
} else if (!this._styleChangedConId) {
this._styleChangedConId = Main.panel.connect('style-changed', () => {
if (opt.PANEL_MODE === 1 && !opt.OVERVIEW_MODE2)
Main.panel.add_style_pseudo_class('overview');
else if (opt.OVERVIEW_MODE2)
Main.panel.remove_style_pseudo_class('overview');
});
}
}
_updateOverviewConnection(reset = false) {
if (reset) {
if (this._hidingOverviewConId) {
Main.overview.disconnect(this._hidingOverviewConId);
this._hidingOverviewConId = 0;
}
if (this._showingOverviewConId) {
Main.overview.disconnect(this._showingOverviewConId);
this._showingOverviewConId = 0;
}
} else {
if (!this._hidingOverviewConId) {
this._hidingOverviewConId = Main.overview.connect('hiding', () => {
if (!opt.SHOW_WS_PREVIEW_BG || opt.OVERVIEW_MODE2)
this._showPanel(false);
});
}
if (!this._showingOverviewConId) {
this._showingOverviewConId = Main.overview.connect('showing', () => {
if (Main.layoutManager._startingUp)
return;
if (!opt.SHOW_WS_PREVIEW_BG || opt.OVERVIEW_MODE2 || Main.layoutManager.panelBox.translation_y)
this._showPanel(true);
});
}
}
}
_reparentPanel(reparent = false) {
const panel = Main.layoutManager.panelBox;
if (reparent && panel.get_parent() === Main.layoutManager.uiGroup) {
Main.layoutManager.uiGroup.remove_child(panel);
Main.layoutManager.overviewGroup.add_child(panel);
} else if (!reparent && panel.get_parent() === Main.layoutManager.overviewGroup) {
Main.layoutManager.overviewGroup.remove_child(panel);
// return the panel at default position, panel shouldn't cover objects that should be above
Main.layoutManager.uiGroup.insert_child_at_index(panel, 4);
}
}
_setPanelStructs(state) {
Main.layoutManager._trackedActors.forEach(a => {
if (a.actor === Main.layoutManager.panelBox)
a.affectsStruts = state;
});
// workaround to force maximized windows to resize after removing affectsStruts
// simulation of minimal swipe gesture to the opposite direction
// todo - needs better solution!!!!!!!!!!!
// const direction = _getAppGridAnimationDirection() === 2 ? 1 : -1;
// Main.overview._swipeTracker._beginTouchSwipe(null, global.get_current_time(), 1, 1);
// Main.overview._swipeTracker._updateGesture(null, global.get_current_time(), direction, 1);
// GLib.timeout_add(0, 50, () => Main.overview._swipeTracker._endGesture(global.get_current_time(), 1, true));*/
}
_showPanel(show = true) {
if (show) {
Main.panel.opacity = 255;
Main.layoutManager.panelBox.ease({
duration: ANIMATION_TIME,
translation_y: 0,
onComplete: () => {
this._setPanelStructs(opt.PANEL_MODE === 0);
},
});
} else {
const panelHeight = Main.panel.height;
Main.layoutManager.panelBox.ease({
duration: ANIMATION_TIME,
translation_y: opt.PANEL_POSITION_TOP ? -panelHeight + 1 : panelHeight - 1,
onComplete: () => {
Main.panel.opacity = 0;
this._setPanelStructs(opt.PANEL_MODE === 0);
},
});
}
}
};
const ActivitiesButton = {
vfunc_event(event) {
if (event.type() === Clutter.EventType.TOUCH_END ||
event.type() === Clutter.EventType.BUTTON_RELEASE) {
if (Main.overview.shouldToggleByCornerOrButton()) {
if (event.get_button() === Clutter.BUTTON_SECONDARY && !Main.overview.dash.showAppsButton.checked) {
Main.overview.show(2);
Main.overview.dash.showAppsButton.checked = true;
} else {
Main.overview.toggle();
}
}
} else if (event.type() === Clutter.EventType.SCROLL) {
Main.wm.handleWorkspaceScroll(event);
}
return Clutter.EVENT_PROPAGATE;
},
};

View file

@ -1,5 +1,5 @@
/**
* Vertical Workspaces
* V-Shell (Vertical Workspaces)
* recentFilesSearchProvider.js
*
* @author GdH <G-dH@github.com>
@ -9,116 +9,146 @@
'use strict';
const { GLib, Gio, Meta, St, Shell, Gtk } = imports.gi;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const RecentManager = imports.gi.Gtk.RecentManager;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Main = imports.ui.main;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Settings = Me.imports.lib.settings;
const _Util = Me.imports.lib.util;
let Me;
let opt;
// gettext
const _ = Settings._;
const shellVersion = Settings.shellVersion;
const ModifierType = imports.gi.Clutter.ModifierType;
let recentFilesSearchProvider;
let _enableTimeoutId = 0;
let _;
// prefix helps to eliminate results from other search providers
// so it needs to be something less common
// needs to be accessible from vw module
var prefix = 'fq//';
const PREFIX = 'fq//';
var opt;
var RecentFilesSearchProviderModule = class {
// export for other modules
static _PREFIX = PREFIX;
constructor(me) {
Me = me;
opt = Me.opt;
_ = Me.gettext;
function getOverviewSearchResult() {
return Main.overview._overview.controls._searchController._searchResults;
}
this._firstActivation = true;
this.moduleEnabled = false;
this._recentFilesSearchProvider = null;
this._enableTimeoutId = 0;
}
function update(reset = false) {
opt = Me.imports.lib.settings.opt;
if (!reset && opt.RECENT_FILES_SEARCH_PROVIDER_ENABLED && !recentFilesSearchProvider) {
enable();
} else if (reset || !opt.RECENT_FILES_SEARCH_PROVIDER_ENABLED) {
disable();
cleanGlobals() {
Me = null;
opt = null;
_ = null;
}
}
function enable() {
// delay because Fedora had problem to register a new provider soon after Shell restarts
_enableTimeoutId = GLib.timeout_add(
GLib.PRIORITY_DEFAULT,
2000,
() => {
if (!recentFilesSearchProvider) {
recentFilesSearchProvider = new RecentFilesSearchProvider(opt);
getOverviewSearchResult()._registerProvider(recentFilesSearchProvider);
}
_enableTimeoutId = 0;
return GLib.SOURCE_REMOVE;
update(reset) {
this.moduleEnabled = opt.get('recentFilesSearchProviderModule');
reset = reset || !this.moduleEnabled;
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
);
}
function disable() {
if (recentFilesSearchProvider) {
getOverviewSearchResult()._unregisterProvider(recentFilesSearchProvider);
recentFilesSearchProvider = null;
if (reset && this._firstActivation)
console.debug(' RecentFilesSearchProviderModule - Keeping untouched');
}
if (_enableTimeoutId) {
GLib.source_remove(_enableTimeoutId);
_enableTimeoutId = 0;
_activateModule() {
// delay because Fedora had problem to register a new provider soon after Shell restarts
this._enableTimeoutId = GLib.timeout_add(
GLib.PRIORITY_DEFAULT,
2000,
() => {
if (!this._recentFilesSearchProvider) {
this._recentFilesSearchProvider = new RecentFilesSearchProvider(opt);
this._getOverviewSearchResult()._registerProvider(this._recentFilesSearchProvider);
}
this._enableTimeoutId = 0;
return GLib.SOURCE_REMOVE;
}
);
console.debug(' RecentFilesSearchProviderModule - Activated');
}
}
function makeResult(window, i) {
const app = Shell.WindowTracker.get_default().get_window_app(window);
const appName = app ? app.get_name() : 'Unknown';
const windowTitle = window.get_title();
const wsIndex = window.get_workspace().index();
_disableModule() {
if (this._recentFilesSearchProvider) {
this._getOverviewSearchResult()._unregisterProvider(this._recentFilesSearchProvider);
this._recentFilesSearchProvider = null;
}
if (this._enableTimeoutId) {
GLib.source_remove(this._enableTimeoutId);
this._enableTimeoutId = 0;
}
return {
'id': i,
// convert all accented chars to their basic form and lower case for search
'name': `${wsIndex + 1}: ${windowTitle} ${appName}`.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase(),
appName,
windowTitle,
window,
};
}
console.debug(' RecentFilesSearchProviderModule - Disabled');
}
const closeSelectedRegex = /^\/x!$/;
const closeAllResultsRegex = /^\/xa!$/;
const moveToWsRegex = /^\/m[0-9]+$/;
const moveAllToWsRegex = /^\/ma[0-9]+$/;
_getOverviewSearchResult() {
return Main.overview._overview.controls._searchController._searchResults;
}
};
const RecentFilesSearchProvider = class RecentFilesSearchProvider {
class RecentFilesSearchProvider {
constructor() {
this.id = 'org.gnome.Nautilus.desktop';
this.appInfo = Gio.AppInfo.create_from_commandline('/usr/bin/nautilus -ws recent:///', 'Recent Files', null);
// this.appInfo = Shell.AppSystem.get_default().lookup_app('org.gnome.Nautilus.desktop').appInfo;
this.appInfo.get_description = () => _('Search recent files');
this.appInfo.get_name = () => _('Recent Files');
this.appInfo.get_id = () => this.id;
this.appInfo.get_icon = () => Gio.icon_new_for_string('document-open-recent-symbolic');
this.appInfo.should_show = () => true;
this.id = 'recent-files';
const appSystem = Shell.AppSystem.get_default();
let appInfo = appSystem.lookup_app('org.gnome.Nautilus.desktop')?.get_app_info();
if (!appInfo)
appInfo = Gio.AppInfo.create_from_commandline('/usr/bin/nautilus -w', _('Recent Files'), null);
appInfo.get_description = () => _('Search recent files');
appInfo.get_name = () => _('Recent Files');
appInfo.get_id = () => 'org.gnome.Nautilus.desktop';
appInfo.get_icon = () => Gio.icon_new_for_string('document-open-recent-symbolic');
appInfo.should_show = () => true;
this.appInfo = appInfo;
this.canLaunchSearch = true;
this.isRemoteProvider = false;
}
getInitialResultSet(terms, callback /* , cancellable = null*/) {
// In GS 43 callback arg has been removed
/* if (Me.shellVersion >= 43)
cancellable = callback; */
const filesDict = {};
let files = [];
if (terms[0].startsWith(PREFIX))
files = RecentManager.get_default().get_items();
// Detect whether time stamps are in int, or in GLib.DateTime object
this._timeNeedsConversion = files[0]?.get_modified().to_unix;
for (let file of files)
filesDict[file.get_uri()] = file;
this.files = filesDict;
if (Me.shellVersion >= 43)
return new Promise(resolve => resolve(this._getResultSet(terms)));
else
callback(this._getResultSet(terms));
return null;
}
_getResultSet(terms) {
if (!terms[0].startsWith(prefix))
if (!terms[0].startsWith(PREFIX))
return [];
// do not modify original terms
let termsCopy = [...terms];
// search for terms without prefix
termsCopy[0] = termsCopy[0].replace(prefix, '');
termsCopy[0] = termsCopy[0].replace(PREFIX, '');
const candidates = this.files;
const _terms = [].concat(termsCopy);
@ -135,15 +165,18 @@ const RecentFilesSearchProvider = class RecentFilesSearchProvider {
const file = this.files[id];
const name = `${file.get_age()}d: ${file.get_display_name()} ${file.get_uri_display().replace(`/${file.get_display_name()}`, '')}`;
if (opt.SEARCH_FUZZY)
m = _Util.fuzzyMatch(term, name);
m = Me.Util.fuzzyMatch(term, name);
else
m = _Util.strictMatch(term, name);
m = Me.Util.strictMatch(term, name);
if (m !== -1)
results.push({ weight: m, id });
}
results.sort((a, b) => this.files[a.id].get_visited() < this.files[b.id].get_visited());
if (this._timeNeedsConversion)
results.sort((a, b) => this.files[a.id].get_modified().to_unix() < this.files[b.id].get_modified().to_unix());
else
results.sort((a, b) => this.files[a.id].get_modified() < this.files[b.id].get_modified());
this.resultIds = results.map(item => item.id);
return this.resultIds;
@ -151,7 +184,7 @@ const RecentFilesSearchProvider = class RecentFilesSearchProvider {
getResultMetas(resultIds, callback = null) {
const metas = resultIds.map(id => this.getResultMeta(id));
if (shellVersion >= 43)
if (Me.shellVersion >= 43)
return new Promise(resolve => resolve(metas));
else if (callback)
callback(metas);
@ -172,89 +205,54 @@ const RecentFilesSearchProvider = class RecentFilesSearchProvider {
}
getIcon(result, size) {
let file = Gio.File.new_for_uri(result.get_uri());
let info = file.query_info(Gio.FILE_ATTRIBUTE_THUMBNAIL_PATH,
Gio.FileQueryInfoFlags.NONE, null);
let path = info.get_attribute_byte_string(
Gio.FILE_ATTRIBUTE_THUMBNAIL_PATH);
let icon, gicon;
if (path) {
gicon = Gio.FileIcon.new(Gio.File.new_for_path(path));
} else {
const appInfo = Gio.AppInfo.get_default_for_type(result.get_mime_type(), false);
if (appInfo)
gicon = appInfo.get_icon();
}
const appInfo = Gio.AppInfo.get_default_for_type(result.get_mime_type(), false);
if (appInfo)
gicon = appInfo.get_icon();
if (gicon)
icon = new St.Icon({ gicon, icon_size: size });
else
icon = new St.Icon({ icon_name: 'icon-missing', icon_size: size });
return icon;
}
launchSearch(/* terms, timeStamp */) {
this._openNautilus('recent:///');
launchSearch(terms, timeStamp) {
const appInfo = Gio.AppInfo.create_from_commandline('/usr/bin/nautilus -w recent:///', 'Nautilus', null);
appInfo.launch([], global.create_app_launch_context(timeStamp, -1));
}
_openNautilus(uri) {
try {
GLib.spawn_command_line_async(`nautilus -ws ${uri}`);
} catch (e) {
log(e);
}
}
activateResult(resultId /* , terms, timeStamp */) {
const file = this.files[resultId];
if (_Util.isShiftPressed()) {
activateResult(resultId, terms, timeStamp) {
const uri = resultId;
const context = global.create_app_launch_context(timeStamp, -1);
if (Me.Util.isShiftPressed()) {
Main.overview.toggle();
this._openNautilus(file.get_uri());
this.appInfo.launch_uris([uri], context);
} else if (Gio.app_info_launch_default_for_uri(uri, context)) {
// update recent list after (hopefully) successful activation
const recentManager = RecentManager.get_default();
recentManager.add_item(resultId);
} else {
const appInfo = Gio.AppInfo.get_default_for_type(file.get_mime_type(), false);
if (!(appInfo && appInfo.launch_uris([file.get_uri()], null)))
this._openNautilus(file.get_uri());
this.appInfo.launch_uris([uri], context);
}
}
getInitialResultSet(terms, callback /* , cancellable = null*/) {
// In GS 43 callback arg has been removed
/* if (shellVersion >= 43)
cancellable = callback; */
const filesDict = {};
const files = Gtk.RecentManager.get_default().get_items().filter(f => f.exists());
for (let file of files)
filesDict[file.get_uri()] = file;
this.files = filesDict;
if (shellVersion >= 43)
return new Promise(resolve => resolve(this._getResultSet(terms)));
else
callback(this._getResultSet(terms));
return null;
}
filterResults(results, maxResults) {
return results.slice(0, 20);
filterResults(results /* , maxResults*/) {
// return results.slice(0, maxResults);
return results.slice(0, 20);
}
getSubsearchResultSet(previousResults, terms, callback /* , cancellable*/) {
// if we return previous results, quick typers get non-actual results
getSubsearchResultSet(previousResults, terms, callback) {
if (Me.shellVersion < 43) {
this.getSubsearchResultSet42(terms, callback);
return null;
}
return this.getInitialResultSet(terms);
}
getSubsearchResultSet42(terms, callback) {
callback(this._getResultSet(terms));
}
/* createResultObject(resultMeta) {
return this.files[resultMeta.id];
}*/
};
}

View file

@ -9,92 +9,137 @@
*/
'use strict';
const { Shell, Gio, St, Clutter } = imports.gi;
const Main = imports.ui.main;
const Clutter = imports.gi.Clutter;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const AppDisplay = imports.ui.appDisplay;
const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const Search = imports.ui.search;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const _Util = Me.imports.lib.util;
const _ = Me.imports.lib.settings._;
const shellVersion = _Util.shellVersion;
let Me;
// gettext
let _;
let opt;
let _overrides;
let _firstRun = true;
let SEARCH_MAX_WIDTH;
function update(reset = false) {
opt = Me.imports.lib.settings.opt;
const moduleEnabled = opt.get('searchModule', true);
reset = reset || !moduleEnabled;
var SearchModule = class {
constructor(me) {
Me = me;
opt = Me.opt;
_ = Me.gettext;
// don't even touch this module if disabled
if (_firstRun && reset)
return;
this._firstActivation = true;
this.moduleEnabled = false;
this._overrides = null;
}
_firstRun = false;
if (_overrides)
_overrides.removeAll();
_updateSearchViewWidth(reset);
if (reset) {
Main.overview._overview._controls.layoutManager._searchController.y_align = Clutter.ActorAlign.FILL;
cleanGlobals() {
Me = null;
opt = null;
_overrides = null;
return;
_ = null;
}
_overrides = new _Util.Overrides();
update(reset) {
this.moduleEnabled = opt.get('searchModule');
const conflict = false;
_overrides.addOverride('AppSearchProvider', AppDisplay.AppSearchProvider.prototype, AppSearchProvider);
_overrides.addOverride('SearchResult', Search.SearchResult.prototype, SearchResult);
_overrides.addOverride('SearchResultsView', Search.SearchResultsView.prototype, SearchResultsView);
reset = reset || !this.moduleEnabled || conflict;
// Don't expand the search view vertically and align it to the top
// this is important in the static workspace mode when the search view bg is not transparent
// also the "Searching..." and "No Results" notifications will be closer to the search entry, with the distance given by margin-top in the stylesheet
Main.overview._overview._controls.layoutManager._searchController.y_align = Clutter.ActorAlign.START;
}
function _updateSearchViewWidth(reset = false) {
const searchContent = Main.overview._overview._controls.layoutManager._searchController._searchResults._content;
if (!SEARCH_MAX_WIDTH) { // just store original value;
const themeNode = searchContent.get_theme_node();
const width = themeNode.get_max_width();
SEARCH_MAX_WIDTH = width;
// don't touch the original code if module disabled
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation)
console.debug(' SearchModule - Keeping untouched');
}
if (reset) {
searchContent.set_style('');
} else {
let width = Math.round(SEARCH_MAX_WIDTH * opt.SEARCH_VIEW_SCALE);
searchContent.set_style(`max-width: ${width}px;`);
_activateModule() {
this._updateSearchViewWidth();
if (!this._overrides)
this._overrides = new Me.Util.Overrides();
this._overrides.addOverride('AppSearchProvider', AppDisplay.AppSearchProvider.prototype, AppSearchProvider);
this._overrides.addOverride('SearchResult', Search.SearchResult.prototype, SearchResult);
this._overrides.addOverride('SearchResultsView', Search.SearchResultsView.prototype, SearchResultsView);
this._overrides.addOverride('ProviderInfo', Search.ProviderInfo.prototype, ProviderInfo);
// Don't expand the search view vertically and align it to the top
// this is important in the static workspace mode when the search view bg is not transparent
// also the "Searching..." and "No Results" notifications will be closer to the search entry, with the distance given by margin-top in the stylesheet
Main.overview._overview._controls.layoutManager._searchController.y_align = Clutter.ActorAlign.START;
console.debug(' SearchModule - Activated');
}
}
_disableModule() {
const reset = true;
this._updateSearchViewWidth(reset);
if (this._overrides)
this._overrides.removeAll();
this._overrides = null;
Main.overview._overview._controls.layoutManager._searchController.y_align = Clutter.ActorAlign.FILL;
console.debug(' WorkspaceSwitcherPopupModule - Disabled');
}
_updateSearchViewWidth(reset = false) {
const searchContent = Main.overview._overview._controls.layoutManager._searchController._searchResults._content;
if (!SEARCH_MAX_WIDTH) { // just store original value;
const themeNode = searchContent.get_theme_node();
const width = themeNode.get_max_width();
SEARCH_MAX_WIDTH = width;
}
if (reset) {
searchContent.set_style('');
} else {
let width = Math.round(SEARCH_MAX_WIDTH * opt.SEARCH_VIEW_SCALE);
searchContent.set_style(`max-width: ${width}px;`);
}
}
};
// AppDisplay.AppSearchProvider
const AppSearchProvider = {
getInitialResultSet(terms, callback, _cancellable) {
getInitialResultSet(terms, callback, cancellable) {
// Defer until the parental controls manager is initialized, so the
// results can be filtered correctly.
if (!this._parentalControlsManager.initialized) {
let initializedId = this._parentalControlsManager.connect('app-filter-changed', () => {
if (this._parentalControlsManager.initialized) {
this._parentalControlsManager.disconnect(initializedId);
this.getInitialResultSet(terms, callback, _cancellable);
}
});
return;
if (Me.shellVersion < 43) {
let initializedId = this._parentalControlsManager.connect('app-filter-changed', () => {
if (this._parentalControlsManager.initialized) {
this._parentalControlsManager.disconnect(initializedId);
this.getInitialResultSet(terms, callback, cancellable);
}
});
return null;
} else {
// callback has been removed in 43
cancellable = callback;
return new Promise(resolve => {
let initializedId = this._parentalControlsManager.connect('app-filter-changed', async () => {
if (this._parentalControlsManager.initialized) {
this._parentalControlsManager.disconnect(initializedId);
resolve(await this.getInitialResultSet(terms, cancellable));
}
});
});
}
}
const pattern = terms.join(' ');
let appInfoList = Shell.AppSystem.get_default().get_installed();
let weightList = {};
@ -113,22 +158,25 @@ const AppSearchProvider = {
shouldShow = appInfo.should_show() && this._parentalControlsManager.shouldShowApp(appInfo);
if (shouldShow) {
let id = appInfo.get_id().split('.');
id = id[id.length - 2] || '';
let baseName = appInfo.get_string('Name') || '';
let dispName = appInfo.get_display_name() || '';
let gName = appInfo.get_generic_name() || '';
let description = appInfo.get_description() || '';
let categories = appInfo.get_string('Categories') || '';
let keywords = appInfo.get_string('Keywords') || '';
name = dispName;
string = `${dispName} ${gName} ${description} ${categories} ${keywords}`;
name = `${dispName} ${id}`;
string = `${dispName} ${gName} ${baseName} ${description} ${categories} ${keywords} ${id}`;
}
}
let m = -1;
if (shouldShow && opt.SEARCH_FUZZY) {
m = _Util.fuzzyMatch(pattern, name);
m = (m + _Util.strictMatch(pattern, string)) / 2;
m = Me.Util.fuzzyMatch(pattern, name);
m = (m + Me.Util.strictMatch(pattern, string)) / 2;
} else if (shouldShow) {
m = _Util.strictMatch(pattern, string);
m = Me.Util.strictMatch(pattern, string);
}
if (m !== -1)
@ -143,16 +191,18 @@ const AppSearchProvider = {
// sort apps by usage list
appInfoList.sort((a, b) => usage.compare(a.get_id(), b.get_id()));
// prefer apps where any word in their name starts with the pattern
appInfoList.sort((a, b) => _Util.isMoreRelevant(a.get_display_name(), b.get_display_name(), pattern));
appInfoList.sort((a, b) => Me.Util.isMoreRelevant(a.get_display_name(), b.get_display_name(), pattern));
let results = appInfoList.map(app => app.get_id());
results = results.concat(this._systemActions.getMatchingActions(terms));
if (shellVersion < 43)
if (Me.shellVersion < 43) {
callback(results);
else
return null;
} else {
return new Promise(resolve => resolve(results));
}
},
// App search result size
@ -181,12 +231,69 @@ const SearchResult = {
St.ClipboardType.CLIPBOARD, this.metaInfo.clipboardText);
}
// don't close overview if Shift key is pressed - Shift moves windows to the workspace
if (!_Util.isShiftPressed())
if (!Me.Util.isShiftPressed())
Main.overview.toggle();
},
};
const SearchResultsView = {
_doSearch() {
if (!this._doProviderSearch) {
this._doSearchLegacy();
return;
}
this._startingSearch = false;
let previousResults = this._results;
this._results = {};
this._providers.forEach(provider => {
const onlyVShellProviders = this._terms.includes('wq//') || this._terms.includes('fq//');
if (!onlyVShellProviders || (onlyVShellProviders && (provider.id.includes('open-windows') || provider.id.includes('recent-files')))) {
let previousProviderResults = previousResults[provider.id];
this._doProviderSearch(provider, previousProviderResults);
}
});
this._updateSearchProgress();
this._clearSearchTimeout();
},
_doSearchLegacy() {
this._startingSearch = false;
let previousResults = this._results;
this._results = {};
this._providers.forEach(provider => {
const onlyVShellProviders = this._terms.includes('wq//') || this._terms.includes('fq//');
if (!onlyVShellProviders || (onlyVShellProviders && (provider.id.includes('open-windows') || provider.id.includes('recent-files')))) {
provider.searchInProgress = true;
let previousProviderResults = previousResults[provider.id];
if (this._isSubSearch && previousProviderResults) {
provider.getSubsearchResultSet(previousProviderResults,
this._terms,
results => {
this._gotResults(results, provider);
},
this._cancellable);
} else {
provider.getInitialResultSet(this._terms,
results => {
this._gotResults(results, provider);
},
this._cancellable);
}
}
});
this._updateSearchProgress();
this._clearSearchTimeout();
},
_updateSearchProgress() {
let haveResults = this._providers.some(provider => {
let display = provider.display;
@ -204,3 +311,13 @@ const SearchResultsView = {
}
},
};
// fixes app is null error if search provider id is not a desktop app id.
const ProviderInfo = {
animateLaunch() {
let appSys = Shell.AppSystem.get_default();
let app = appSys.lookup_app(this.provider.appInfo.get_id());
if (app && app.state === Shell.AppState.STOPPED)
IconGrid.zoomOutActor(this._content);
},
};

View file

@ -0,0 +1,94 @@
/**
* V-Shell (Vertical Workspaces)
* searchController.js
*
* @author GdH <G-dH@github.com>
* @copyright 2022 - 2023
* @license GPL-3.0
*
*/
'use strict';
const Clutter = imports.gi.Clutter;
const Main = imports.ui.main;
let Me;
let opt;
var SearchControllerModule = class {
constructor(me) {
Me = me;
opt = Me.opt;
this._firstActivation = true;
this.moduleEnabled = false;
this._originalOnStageKeyPress = null;
}
cleanGlobals() {
Me = null;
opt = null;
}
update(reset) {
this.moduleEnabled = opt.get('searchControllerModule');
const conflict = false;
reset = reset || !this.moduleEnabled || conflict;
// don't touch the original code if module disabled
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation)
console.debug(' SearchControllerModule - Keeping untouched');
}
_activateModule() {
if (!this._originalOnStageKeyPress)
this._originalOnStageKeyPress = Main.overview._overview.controls._searchController._onStageKeyPress;
Main.overview._overview.controls._searchController._onStageKeyPress = SearchControllerCommon._onStageKeyPress;
console.debug(' SearchControllerModule - Activated');
}
_disableModule() {
if (this._originalOnStageKeyPress)
Main.overview._overview.controls._searchController._onStageKeyPress = this._originalOnStageKeyPress;
this._originalOnStageKeyPress = null;
console.debug(' SearchControlerModule - Disabled');
}
};
// if opt.ESC_BEHAVIOR > 0 force close the overview
const SearchControllerCommon = {
_onStageKeyPress(actor, event) {
// Ignore events while anything but the overview has
// pushed a modal (system modals, looking glass, ...)
if (Main.modalCount > 1)
return Clutter.EVENT_PROPAGATE;
let symbol = event.get_key_symbol();
if (symbol === Clutter.KEY_Escape) {
if (this._searchActive && !opt.ESC_BEHAVIOR) {
this.reset();
} else if (this._showAppsButton.checked && !opt.ESC_BEHAVIOR) {
this._showAppsButton.checked = false;
} else {
this.reset();
Main.overview.hide();
}
return Clutter.EVENT_STOP;
} else if (this._shouldTriggerSearch(symbol)) {
this.startSearch(event);
}
return Clutter.EVENT_PROPAGATE;
},
};

View file

@ -9,25 +9,15 @@
'use strict';
const { GLib } = imports.gi;
const GLib = imports.gi.GLib;
const Config = imports.misc.config;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
var shellVersion = parseFloat(Config.PACKAGE_VERSION);
const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']);
var _ = Gettext.gettext;
const _schema = Me.metadata['settings-schema'];
// common instance of Options accessible from all modules
var opt;
let Me;
var Options = class Options {
constructor() {
this._gsettings = ExtensionUtils.getSettings(_schema);
constructor(me) {
Me = me;
this._gsettings = Me.gSettings;
this._connectionIds = [];
this._writeTimeoutId = 0;
this._gsettings.delay();
@ -51,8 +41,8 @@ var Options = class Options {
wsMaxSpacing: ['int', 'ws-max-spacing'],
wsPreviewScale: ['int', 'ws-preview-scale'],
secWsPreviewScale: ['int', 'secondary-ws-preview-scale'],
secWsPreviewShift: ['bool', 'secondary-ws-preview-shift'],
wsThumbnailsFull: ['bool', 'ws-thumbnails-full'],
secWsPreviewShift: ['boolean', 'secondary-ws-preview-shift'],
wsThumbnailsFull: ['boolean', 'ws-thumbnails-full'],
secWsThumbnailsPosition: ['int', 'secondary-ws-thumbnails-position'],
dashPosition: ['int', 'dash-position'],
dashPositionAdjust: ['int', 'dash-position-adjust'],
@ -64,6 +54,7 @@ var Options = class Options {
dashMaxIconSize: ['int', 'dash-max-icon-size'],
dashShowWindowsIcon: ['int', 'dash-show-windows-icon'],
dashShowRecentFilesIcon: ['int', 'dash-show-recent-files-icon'],
dashShowExtensionsIcon: ['int', 'dash-show-extensions-icon'],
centerDashToWs: ['boolean', 'center-dash-to-ws'],
showAppsIconPosition: ['int', 'show-app-icon-position'],
wsThumbnailScale: ['int', 'ws-thumbnail-scale'],
@ -73,13 +64,17 @@ var Options = class Options {
centerSearch: ['boolean', 'center-search'],
centerAppGrid: ['boolean', 'center-app-grid'],
dashBgOpacity: ['int', 'dash-bg-opacity'],
dashBgColor: ['int', 'dash-bg-color'],
dashBgRadius: ['int', 'dash-bg-radius'],
dashBgGS3Style: ['boolean', 'dash-bg-gs3-style'],
runningDotStyle: ['int', 'running-dot-style'],
enablePageShortcuts: ['boolean', 'enable-page-shortcuts'],
showWsSwitcherBg: ['boolean', 'show-ws-switcher-bg'],
showWsPreviewBg: ['boolean', 'show-ws-preview-bg'],
wsPreviewBgRadius: ['int', 'ws-preview-bg-radius'],
showBgInOverview: ['boolean', 'show-bg-in-overview'],
overviewBgBrightness: ['int', 'overview-bg-brightness'],
searchBgBrightness: ['int', 'search-bg-brightness'],
overviewBgBlurSigma: ['int', 'overview-bg-blur-sigma'],
appGridBgBlurSigma: ['int', 'app-grid-bg-blur-sigma'],
smoothBlurTransitions: ['boolean', 'smooth-blur-transitions'],
@ -87,9 +82,8 @@ var Options = class Options {
searchViewAnimation: ['int', 'search-view-animation'],
workspaceAnimation: ['int', 'workspace-animation'],
animationSpeedFactor: ['int', 'animation-speed-factor'],
fixUbuntuDock: ['boolean', 'fix-ubuntu-dock'],
winPreviewIconSize: ['int', 'win-preview-icon-size'],
alwaysShowWinTitles: ['boolean', 'always-show-win-titles'],
winTitlePosition: ['int', 'win-title-position'],
startupState: ['int', 'startup-state'],
overviewMode: ['int', 'overview-mode'],
workspaceSwitcherAnimation: ['int', 'workspace-switcher-animation'],
@ -105,17 +99,18 @@ var Options = class Options {
appGridContent: ['int', 'app-grid-content'],
appGridIncompletePages: ['boolean', 'app-grid-incomplete-pages'],
appGridOrder: ['int', 'app-grid-order'],
appFolderOrder: ['int', 'app-folder-order'],
appGridNamesMode: ['int', 'app-grid-names'],
appGridActivePreview: ['boolean', 'app-grid-active-preview'],
appGridFolderCenter: ['boolean', 'app-grid-folder-center'],
appGridPageWidthScale: ['int', 'app-grid-page-width-scale'],
appGridSpacing: ['int', 'app-grid-spacing'],
searchWindowsEnable: ['boolean', 'search-windows-enable'],
searchRecentFilesEnable: ['boolean', 'search-recent-files-enable'],
searchWindowsOrder: ['int', 'search-windows-order'],
searchFuzzy: ['boolean', 'search-fuzzy'],
searchMaxResultsRows: ['int', 'search-max-results-rows'],
dashShowWindowsBeforeActivation: ['int', 'dash-show-windows-before-activation'],
dashIconScroll: ['int', 'dash-icon-scroll'],
dashIsolateWorkspaces: ['boolean', 'dash-isolate-workspaces'],
searchWindowsIconScroll: ['int', 'search-windows-icon-scroll'],
panelVisibility: ['int', 'panel-visibility'],
panelPosition: ['int', 'panel-position'],
@ -123,6 +118,8 @@ var Options = class Options {
wsSwPopupHPosition: ['int', 'ws-sw-popup-h-position'],
wsSwPopupVPosition: ['int', 'ws-sw-popup-v-position'],
wsSwPopupMode: ['int', 'ws-sw-popup-mode'],
wsSwitcherWraparound: ['boolean', 'ws-switcher-wraparound'],
wsSwitcherIgnoreLast: ['boolean', 'ws-switcher-ignore-last'],
favoritesNotify: ['int', 'favorites-notify'],
notificationPosition: ['int', 'notification-position'],
osdPosition: ['int', 'osd-position'],
@ -131,17 +128,26 @@ var Options = class Options {
hotCornerFullscreen: ['boolean', 'hot-corner-fullscreen'],
hotCornerRipples: ['boolean', 'hot-corner-ripples'],
alwaysActivateSelectedWindow: ['boolean', 'always-activate-selected-window'],
windowIconClickSearch: ['boolean', 'window-icon-click-search'],
winPreviewSecBtnAction: ['int', 'win-preview-sec-mouse-btn-action'],
winPreviewMidBtnAction: ['int', 'win-preview-mid-mouse-btn-action'],
winPreviewShowCloseButton: ['boolean', 'win-preview-show-close-button'],
windowIconClickAction: ['int', 'window-icon-click-action'],
overlayKeyPrimary: ['int', 'overlay-key-primary'],
overlayKeySecondary: ['int', 'overlay-key-secondary'],
overviewEscBehavior: ['int', 'overview-esc-behavior'],
newWindowFocusFix: ['boolean', 'new-window-focus-fix'],
appGridPerformance: ['boolean', 'app-grid-performance'],
windowThumbnailScale: ['int', 'window-thumbnail-scale'],
workspaceThumbnailsModule: ['boolean', 'workspace-thumbnails-module'],
workspaceSwitcherPopupModule: ['boolean', 'workspace-switcher-popup-module'],
workspaceAnimationModule: ['boolean', 'workspace-animation-module'],
workspaceModule: ['boolean', 'workspace-module'],
windowManagerModule: ['boolean', 'window-manager-module'],
windowPreviewModule: ['boolean', 'window-preview-module'],
winAttentionHandlerModule: ['boolean', 'win-attention-handler-module'],
windowAttentionHandlerModule: ['boolean', 'win-attention-handler-module'],
windowThumbnailModule: ['boolean', 'window-thumbnail-module'],
swipeTrackerModule: ['boolean', 'swipe-tracker-module'],
searchControllerModule: ['boolean', 'search-controller-module'],
searchModule: ['boolean', 'search-module'],
panelModule: ['boolean', 'panel-module'],
overlayKeyModule: ['boolean', 'overlay-key-module'],
@ -151,6 +157,9 @@ var Options = class Options {
dashModule: ['boolean', 'dash-module'],
appFavoritesModule: ['boolean', 'app-favorites-module'],
appDisplayModule: ['boolean', 'app-display-module'],
windowSearchProviderModule: ['boolean', 'window-search-provider-module'],
recentFilesSearchProviderModule: ['boolean', 'recent-files-search-provider-module'],
extensionsSearchProviderModule: ['boolean', 'extensions-search-provider-module'],
profileName1: ['string', 'profile-name-1'],
profileName2: ['string', 'profile-name-2'],
@ -158,9 +167,10 @@ var Options = class Options {
profileName4: ['string', 'profile-name-4'],
};
this.cachedOptions = {};
}
this.shellVersion = shellVersion;
// this.storeProfile(0);
cleanGlobals() {
Me = null;
}
connect(name, callback) {
@ -183,7 +193,7 @@ var Options = class Options {
get(option, updateCache = false) {
if (!this.options[option]) {
log(`[${Me.metadata.name}] Error: Option ${option} is undefined.`);
console.error(`[${Me.metadata.name}] Error: Option ${option} is undefined.`);
return null;
}
@ -195,7 +205,6 @@ var Options = class Options {
else
gSettings = this._gsettings;
this.cachedOptions[option] = gSettings.get_value(key).deep_unpack();
}
@ -242,7 +251,8 @@ var Options = class Options {
storeProfile(index) {
const profile = {};
Object.keys(this.options).forEach(v => {
profile[v] = this.get(v).toString();
if (!v.startsWith('profileName'))
profile[v] = this.get(v).toString();
});
this._gsettings.set_value(`profile-data-${index}`, new GLib.Variant('a{ss}', profile));
@ -250,8 +260,14 @@ var Options = class Options {
loadProfile(index) {
const options = this._gsettings.get_value(`profile-data-${index}`).deep_unpack();
// set the aaa-loading-data so extension.js doesn't reset V-Shell after each profile item
// delayed gsettings writes are processed alphabetically, so this key will be processed first
this._gsettings.set_boolean('aaa-loading-profile', !this._gsettings.get_boolean('aaa-loading-profile'));
for (let o of Object.keys(options)) {
if (!this.options[o]) {
console.error(`[${Me.metadata.name}] Error: "${o}" is not a valid profile key -> Update your profile`);
continue;
}
const [type] = this.options[o];
let value = options[o];
switch (type) {
@ -275,7 +291,14 @@ var Options = class Options {
}
_updateSettings() {
this.DASH_POSITION = this.get('dashPosition', true);
this._updateCachedSettings();
this.DASH_BG_ALPHA = this.get('dashBgOpacity') / 100;
this.DASH_BG_OPACITY = this.get('dashBgOpacity') * 2.5;
this.DASH_BG_COLOR = this.get('dashBgColor');
this.DASH_BG_RADIUS = this.get('dashBgRadius');
this.DASH_BG_LIGHT = this.DASH_BG_COLOR === 1;
this.DASH_BG_GS3_STYLE = this.get('dashBgGS3Style');
this.DASH_POSITION = this.get('dashModule') ? this.get('dashPosition') : 2;
this.DASH_TOP = this.DASH_POSITION === 0;
this.DASH_RIGHT = this.DASH_POSITION === 1;
this.DASH_BOTTOM = this.DASH_POSITION === 2;
@ -284,26 +307,35 @@ var Options = class Options {
this.DASH_VISIBLE = this.DASH_POSITION !== 4; // 4 - disable
this.DASH_FOLLOW_RECENT_WIN = false;
this.DASH_CLICK_ACTION = this.get('dashShowWindowsBeforeActivation', true);
this.DASH_ICON_SCROLL = this.get('dashIconScroll', true);
this.DASH_ISOLATE_WS = this.get('dashIsolateWorkspaces');
this.DASH_CLICK_ACTION = this.get('dashShowWindowsBeforeActivation');
this.DASH_CLICK_SWITCH_BEFORE_ACTIVATION = this.DASH_CLICK_ACTION === 1;
this.DASH_CLICK_OPEN_NEW_WIN = this.DASH_CLICK_ACTION === 2;
this.DASH_CLICK_PREFER_WORKSPACE = this.DASH_CLICK_ACTION === 3;
this.DASH_ICON_SCROLL = this.get('dashIconScroll');
this.DASH_SHIFT_CLICK_MV = true;
this.SEARCH_WINDOWS_ICON_SCROLL = this.get('searchWindowsIconScroll', true);
this.RUNNING_DOT_STYLE = this.get('runningDotStyle');
this.DASH_POSITION_ADJUSTMENT = this.get('dashPositionAdjust', true);
this.SEARCH_WINDOWS_ICON_SCROLL = this.get('searchWindowsIconScroll');
this.DASH_POSITION_ADJUSTMENT = this.get('dashPositionAdjust');
this.DASH_POSITION_ADJUSTMENT = this.DASH_POSITION_ADJUSTMENT * -1 / 100; // range 1 to -1
this.CENTER_DASH_WS = this.get('centerDashToWs', true);
this.CENTER_DASH_WS = this.get('centerDashToWs');
this.MAX_ICON_SIZE = 64; // updates from main module
this.SHOW_WINDOWS_ICON = this.get('dashShowWindowsIcon', true);
this.SHOW_RECENT_FILES_ICON = this.get('dashShowRecentFilesIcon', true);
this.MAX_ICON_SIZE = this.get('dashMaxIconSize');
this.SHOW_WINDOWS_ICON = this.get('dashShowWindowsIcon');
this.SHOW_RECENT_FILES_ICON = this.get('dashShowRecentFilesIcon');
this.SHOW_EXTENSIONS_ICON = this.get('dashShowExtensionsIcon');
this.WS_TMB_POSITION = this.get('workspaceThumbnailsPosition', true);
this.WS_TMB_POSITION = this.get('workspaceThumbnailsPosition');
this.ORIENTATION = this.WS_TMB_POSITION > 4 ? 0 : 1;
this.WORKSPACE_MAX_SPACING = this.get('wsMaxSpacing', true);
this.WORKSPACE_MAX_SPACING = this.get('wsMaxSpacing');
// ORIENTATION || DASH_LEFT || DASH_RIGHT ? 350 : 80;
this.SHOW_WS_TMB = ![4, 9].includes(this.WS_TMB_POSITION); // 4, 9 - disable
this.WS_TMB_FULL = this.get('wsThumbnailsFull', true);
this.WS_TMB_FULL = this.get('wsThumbnailsFull');
// translate ws tmb position to 0 top, 1 right, 2 bottom, 3 left
// 0L 1R, 2LF, 3RF, 4DV, 5T, 6B, 7TF, 8BF, 9DH
this.WS_TMB_POSITION = [3, 1, 3, 1, 4, 0, 2, 0, 2, 8][this.WS_TMB_POSITION];
@ -311,81 +343,104 @@ var Options = class Options {
this.WS_TMB_RIGHT = this.WS_TMB_POSITION === 1;
this.WS_TMB_BOTTOM = this.WS_TMB_POSITION === 2;
this.WS_TMB_LEFT = this.WS_TMB_POSITION === 3;
this.WS_TMB_POSITION_ADJUSTMENT = this.get('wsTmbPositionAdjust', true) * -1 / 100; // range 1 to -1
this.SEC_WS_TMB_POSITION = this.get('secWsThumbnailsPosition', true);
this.WS_TMB_POSITION_ADJUSTMENT = this.get('wsTmbPositionAdjust') * -1 / 100; // range 1 to -1
this.SEC_WS_TMB_POSITION = this.get('secWsThumbnailsPosition');
this.SHOW_SEC_WS_TMB = this.SEC_WS_TMB_POSITION !== 3 && this.SHOW_WS_TMB;
this.SEC_WS_TMB_TOP = (this.SEC_WS_TMB_POSITION === 0 && !this.ORIENTATION) || (this.SEC_WS_TMB_POSITION === 2 && this.WS_TMB_TOP);
this.SEC_WS_TMB_RIGHT = (this.SEC_WS_TMB_POSITION === 1 && this.ORIENTATION) || (this.SEC_WS_TMB_POSITION === 2 && this.WS_TMB_RIGHT);
this.SEC_WS_TMB_BOTTOM = (this.SEC_WS_TMB_POSITION === 1 && !this.ORIENTATION) || (this.SEC_WS_TMB_POSITION === 2 && this.WS_TMB_BOTTOM);
this.SEC_WS_TMB_LEFT = (this.SEC_WS_TMB_POSITION === 0 && this.ORIENTATION) || (this.SEC_WS_TMB_POSITION === 2 && this.WS_TMB_LEFT);
this.SEC_WS_TMB_POSITION_ADJUSTMENT = this.get('secWsTmbPositionAdjust', true) * -1 / 100; // range 1 to -1
this.SEC_WS_PREVIEW_SHIFT = this.get('secWsPreviewShift', true);
this.SHOW_WST_LABELS = this.get('showWsTmbLabels', true);
this.SHOW_WST_LABELS_ON_HOVER = this.get('showWsTmbLabelsOnHover', true);
this.CLOSE_WS_BUTTON_MODE = this.get('closeWsButtonMode', true);
this.SEC_WS_TMB_POSITION_ADJUSTMENT = this.get('secWsTmbPositionAdjust') * -1 / 100; // range 1 to -1
this.SEC_WS_PREVIEW_SHIFT = this.get('secWsPreviewShift');
this.SHOW_WST_LABELS = this.get('showWsTmbLabels');
this.SHOW_WST_LABELS_ON_HOVER = this.get('showWsTmbLabelsOnHover');
this.CLOSE_WS_BUTTON_MODE = this.get('closeWsButtonMode');
this.MAX_THUMBNAIL_SCALE = this.get('wsThumbnailScale', true) / 100;
this.MAX_THUMBNAIL_SCALE_APPGRID = this.get('wsThumbnailScaleAppGrid', true) / 100;
if (this.MAX_THUMBNAIL_SCALE_APPGRID === 0)
this.MAX_THUMBNAIL_SCALE_APPGRID = this.MAX_THUMBNAIL_SCALE;
this.MAX_THUMBNAIL_SCALE = this.get('wsThumbnailScale') / 100;
if (this.MAX_THUMBNAIL_SCALE === 0) {
this.MAX_THUMBNAIL_SCALE = 0.01;
this.SHOW_WS_TMB = false;
}
this.MAX_THUMBNAIL_SCALE_APPGRID = this.get('wsThumbnailScaleAppGrid') / 100;
this.SHOW_WS_TMB_APPGRID = true;
if (this.MAX_THUMBNAIL_SCALE_APPGRID === 0) {
this.MAX_THUMBNAIL_SCALE_APPGRID = 0.01;
this.SHOW_WS_TMB_APPGRID = false;
}
this.MAX_THUMBNAIL_SCALE_STABLE = this.MAX_THUMBNAIL_SCALE === this.MAX_THUMBNAIL_SCALE_APPGRID;
this.SEC_MAX_THUMBNAIL_SCALE = this.get('secWsThumbnailScale', true) / 100;
this.WS_PREVIEW_SCALE = this.get('wsPreviewScale', true) / 100;
this.SEC_WS_PREVIEW_SCALE = this.get('secWsPreviewScale', true) / 100;
this.SEC_MAX_THUMBNAIL_SCALE = this.get('secWsThumbnailScale') / 100;
if (this.SEC_MAX_THUMBNAIL_SCALE === 0) {
this.SEC_MAX_THUMBNAIL_SCALE = 0.01;
this.SHOW_SEC_WS_TMB = false;
}
this.WS_PREVIEW_SCALE = this.get('wsPreviewScale') / 100;
this.SEC_WS_PREVIEW_SCALE = this.get('secWsPreviewScale') / 100;
// calculate number of possibly visible neighbor previews according to ws scale
this.NUMBER_OF_VISIBLE_NEIGHBORS = Math.round(1 + (1 - this.WS_PREVIEW_SCALE) / 4);
this.SHOW_WS_TMB_BG = this.get('showWsSwitcherBg', true) && this.SHOW_WS_TMB;
this.WS_PREVIEW_BG_RADIUS = this.get('wsPreviewBgRadius', true);
this.SHOW_WS_PREVIEW_BG = this.get('showWsPreviewBg', true);
this.SHOW_WS_TMB_BG = this.get('showWsSwitcherBg') && this.SHOW_WS_TMB;
this.WS_PREVIEW_BG_RADIUS = this.get('wsPreviewBgRadius');
this.SHOW_WS_PREVIEW_BG = this.get('showWsPreviewBg');
this.CENTER_APP_GRID = this.get('centerAppGrid', true);
this.CENTER_APP_GRID = this.get('centerAppGrid');
this.SHOW_SEARCH_ENTRY = this.get('showSearchEntry', true);
this.CENTER_SEARCH_VIEW = this.get('centerSearch', true);
this.APP_GRID_ANIMATION = this.get('appGridAnimation', true);
this.SHOW_SEARCH_ENTRY = this.get('showSearchEntry');
this.CENTER_SEARCH_VIEW = this.get('centerSearch');
this.APP_GRID_ANIMATION = this.get('appGridAnimation');
if (this.APP_GRID_ANIMATION === 4)
this.APP_GRID_ANIMATION = this._getAnimationDirection();
this.SEARCH_VIEW_ANIMATION = this.get('searchViewAnimation', true);
this.SEARCH_VIEW_ANIMATION = this.get('searchViewAnimation');
if (this.SEARCH_VIEW_ANIMATION === 4)
this.SEARCH_VIEW_ANIMATION = 3;
this.WS_ANIMATION = this.get('workspaceAnimation', true);
this.WS_ANIMATION = this.get('workspaceAnimation');
this.WIN_PREVIEW_ICON_SIZE = [64, 48, 32, 22, 8][this.get('winPreviewIconSize', true)];
this.ALWAYS_SHOW_WIN_TITLES = this.get('alwaysShowWinTitles', true);
this.WIN_PREVIEW_ICON_SIZE = [64, 48, 32, 22, 8][this.get('winPreviewIconSize')];
this.WIN_TITLES_POSITION = this.get('winTitlePosition');
this.ALWAYS_SHOW_WIN_TITLES = this.WIN_TITLES_POSITION === 1;
this.STARTUP_STATE = this.get('startupState', true);
this.SHOW_BG_IN_OVERVIEW = this.get('showBgInOverview', true);
this.OVERVIEW_BG_BRIGHTNESS = this.get('overviewBgBrightness', true) / 100;
this.OVERVIEW_BG_BLUR_SIGMA = this.get('overviewBgBlurSigma', true);
this.APP_GRID_BG_BLUR_SIGMA = this.get('appGridBgBlurSigma', true);
this.SMOOTH_BLUR_TRANSITIONS = this.get('smoothBlurTransitions', true);
this.STARTUP_STATE = this.get('startupState');
this.SHOW_BG_IN_OVERVIEW = this.get('showBgInOverview');
this.OVERVIEW_BG_BRIGHTNESS = this.get('overviewBgBrightness') / 100;
this.SEARCH_BG_BRIGHTNESS = this.get('searchBgBrightness') / 100;
this.OVERVIEW_BG_BLUR_SIGMA = this.get('overviewBgBlurSigma');
this.APP_GRID_BG_BLUR_SIGMA = this.get('appGridBgBlurSigma');
this.SMOOTH_BLUR_TRANSITIONS = this.get('smoothBlurTransitions');
this.OVERVIEW_MODE = this.get('overviewMode', true);
this.OVERVIEW_MODE = this.get('overviewMode');
this.OVERVIEW_MODE2 = this.OVERVIEW_MODE === 2;
this.WORKSPACE_MODE = this.OVERVIEW_MODE ? 0 : 1;
this.STATIC_WS_SWITCHER_BG = this.get('workspaceSwitcherAnimation', true);
this.STATIC_WS_SWITCHER_BG = this.get('workspaceSwitcherAnimation');
this.ANIMATION_TIME_FACTOR = this.get('animationSpeedFactor', true) / 100;
this.ANIMATION_TIME_FACTOR = this.get('animationSpeedFactor') / 100;
this.SEARCH_ICON_SIZE = this.get('searchIconSize', true);
this.SEARCH_VIEW_SCALE = this.get('searchViewScale', true) / 100;
this.SEARCH_MAX_ROWS = this.get('searchMaxResultsRows', true);
this.SEARCH_FUZZY = this.get('searchFuzzy', true);
this.SEARCH_ICON_SIZE = this.get('searchIconSize');
this.SEARCH_VIEW_SCALE = this.get('searchViewScale') / 100;
this.SEARCH_MAX_ROWS = this.get('searchMaxResultsRows');
this.SEARCH_FUZZY = this.get('searchFuzzy');
this.APP_GRID_ALLOW_INCOMPLETE_PAGES = this.get('appGridIncompletePages', true);
this.APP_GRID_ICON_SIZE = this.get('appGridIconSize', true);
this.APP_GRID_COLUMNS = this.get('appGridColumns', true);
this.APP_GRID_ROWS = this.get('appGridRows', true);
this.APP_GRID_ALLOW_INCOMPLETE_PAGES = this.get('appGridIncompletePages');
this.APP_GRID_ICON_SIZE = this.get('appGridIconSize');
this.APP_GRID_COLUMNS = this.get('appGridColumns');
this.APP_GRID_ROWS = this.get('appGridRows');
this.APP_GRID_ADAPTIVE = !this.APP_GRID_COLUMNS && !this.APP_GRID_ROWS;
this.APP_GRID_ORDER = this.get('appGridOrder', true);
this.APP_GRID_INCLUDE_DASH = this.get('appGridContent', true);
this.APP_GRID_ORDER = this.get('appGridOrder');
this.APP_GRID_ALPHABET = [1, 2].includes(this.APP_GRID_ORDER);
this.APP_GRID_FOLDERS_FIRST = this.APP_GRID_ORDER === 1;
this.APP_GRID_FOLDERS_LAST = this.APP_GRID_ORDER === 2;
this.APP_GRID_USAGE = this.APP_GRID_ORDER === 3;
this.APP_FOLDER_ORDER = this.get('appFolderOrder');
this.APP_FOLDER_ALPHABET = this.APP_FOLDER_ORDER === 1;
this.APP_FOLDER_USAGE = this.APP_FOLDER_ORDER === 2;
this.APP_GRID_INCLUDE_DASH = this.get('appGridContent');
/* APP_GRID_INCLUDE_DASH
0 - Include All
1 - Include All - Favorites and Runnings First
@ -397,46 +452,50 @@ var Options = class Options {
this.APP_GRID_EXCLUDE_RUNNING = this.APP_GRID_INCLUDE_DASH === 3 || this.APP_GRID_INCLUDE_DASH === 4;
this.APP_GRID_DASH_FIRST = this.APP_GRID_INCLUDE_DASH === 1;
this.APP_GRID_NAMES_MODE = this.get('appGridNamesMode', true);
this.APP_GRID_NAMES_MODE = this.get('appGridNamesMode');
this.APP_GRID_FOLDER_ICON_SIZE = this.get('appGridFolderIconSize', true);
this.APP_GRID_FOLDER_ICON_GRID = this.get('appGridFolderIconGrid', true);
this.APP_GRID_FOLDER_COLUMNS = this.get('appGridFolderColumns', true);
this.APP_GRID_FOLDER_ROWS = this.get('appGridFolderRows', true);
this.APP_GRID_SPACING = this.get('appGridSpacing', true);
this.APP_GRID_FOLDER_ICON_SIZE = this.get('appGridFolderIconSize');
this.APP_GRID_FOLDER_ICON_GRID = this.get('appGridFolderIconGrid');
this.APP_GRID_FOLDER_COLUMNS = this.get('appGridFolderColumns');
this.APP_GRID_FOLDER_ROWS = this.get('appGridFolderRows');
this.APP_GRID_SPACING = this.get('appGridSpacing');
this.APP_GRID_FOLDER_DEFAULT = this.APP_GRID_FOLDER_ROWS === 3 && this.APP_GRID_FOLDER_COLUMNS === 3;
this.APP_GRID_ACTIVE_PREVIEW = this.get('appGridActivePreview', true);
this.APP_GRID_FOLDER_CENTER = this.get('appGridFolderCenter', true);
this.APP_GRID_PAGE_WIDTH_SCALE = this.get('appGridPageWidthScale', true) / 100;
this.APP_GRID_FOLDER_ADAPTIVE = !this.APP_GRID_FOLDER_COLUMNS && !this.APP_GRID_FOLDER_ROWS;
this.APP_GRID_ACTIVE_PREVIEW = this.get('appGridActivePreview');
this.APP_GRID_FOLDER_CENTER = this.get('appGridFolderCenter');
this.APP_GRID_PAGE_WIDTH_SCALE = this.get('appGridPageWidthScale') / 100;
this.APP_GRID_ICON_SIZE_DEFAULT = this.APP_GRID_ACTIVE_PREVIEW && !this.APP_GRID_ORDER ? 176 : 96;
this.APP_GRID_ICON_SIZE_DEFAULT = this.APP_GRID_ACTIVE_PREVIEW && !this.APP_GRID_USAGE ? 176 : 96;
this.APP_GRID_FOLDER_ICON_SIZE_DEFAULT = 96;
this.WINDOW_SEARCH_PROVIDER_ENABLED = this.get('searchWindowsEnable', true);
this.RECENT_FILES_SEARCH_PROVIDER_ENABLED = this.get('searchRecentFilesEnable', true);
this.APP_GRID_PERFORMANCE = this.get('appGridPerformance');
this.PANEL_POSITION_TOP = this.get('panelPosition', true) === 0;
this.PANEL_MODE = this.get('panelVisibility', true);
this.WINDOW_SEARCH_ORDER = this.get('searchWindowsOrder');
this.PANEL_POSITION_TOP = this.get('panelPosition') === 0;
this.PANEL_MODE = this.get('panelVisibility');
this.PANEL_DISABLED = this.PANEL_MODE === 2;
this.PANEL_OVERVIEW_ONLY = this.PANEL_MODE === 1;
this.START_Y_OFFSET = 0; // set from main module
this.FIX_UBUNTU_DOCK = this.get('fixUbuntuDock', true);
this.WINDOW_ATTENTION_MODE = this.get('windowAttentionMode', true);
this.WINDOW_ATTENTION_MODE = this.get('windowAttentionMode');
this.WINDOW_ATTENTION_DISABLE_NOTIFICATIONS = this.WINDOW_ATTENTION_MODE === 1;
this.WINDOW_ATTENTION_FOCUS_IMMEDIATELY = this.WINDOW_ATTENTION_MODE === 2;
this.WS_SW_POPUP_H_POSITION = this.get('wsSwPopupHPosition', true) / 100;
this.WS_SW_POPUP_V_POSITION = this.get('wsSwPopupVPosition', true) / 100;
this.WS_SW_POPUP_MODE = this.get('wsSwPopupMode', true);
this.WS_SW_POPUP_H_POSITION = this.get('wsSwPopupHPosition') / 100;
this.WS_SW_POPUP_V_POSITION = this.get('wsSwPopupVPosition') / 100;
this.WS_SW_POPUP_MODE = this.get('wsSwPopupMode');
this.SHOW_FAV_NOTIFICATION = this.get('favoritesNotify', true);
this.NOTIFICATION_POSITION = this.get('notificationPosition', true);
this.WS_WRAPAROUND = this.get('wsSwitcherWraparound');
this.WS_IGNORE_LAST = this.get('wsSwitcherIgnoreLast');
this.OSD_POSITION = this.get('osdPosition', true);
this.SHOW_FAV_NOTIFICATION = this.get('favoritesNotify');
this.NOTIFICATION_POSITION = this.get('notificationPosition');
this.HOT_CORNER_ACTION = this.get('hotCornerAction', true);
this.HOT_CORNER_POSITION = this.get('hotCornerPosition', true);
this.OSD_POSITION = this.get('osdPosition');
this.HOT_CORNER_ACTION = this.get('hotCornerAction');
this.HOT_CORNER_POSITION = this.get('hotCornerPosition');
if (this.HOT_CORNER_POSITION === 6 && this.DASH_VISIBLE)
this.HOT_CORNER_EDGE = true;
else
@ -451,13 +510,24 @@ var Options = class Options {
else
this.HOT_CORNER_POSITION = 0;
}
this.HOT_CORNER_FULLSCREEN = this.get('hotCornerFullscreen', true);
this.HOT_CORNER_RIPPLES = this.get('hotCornerRipples', true);
this.HOT_CORNER_FULLSCREEN = this.get('hotCornerFullscreen');
this.HOT_CORNER_RIPPLES = this.get('hotCornerRipples');
this.ALWAYS_ACTIVATE_SELECTED_WINDOW = this.get('alwaysActivateSelectedWindow', true);
this.WINDOW_ICON_CLICK_SEARCH = this.get('windowIconClickSearch', true);
this.ALWAYS_ACTIVATE_SELECTED_WINDOW = this.get('alwaysActivateSelectedWindow');
this.WIN_PREVIEW_SEC_BTN_ACTION = this.get('winPreviewSecBtnAction');
this.WIN_PREVIEW_MID_BTN_ACTION = this.get('winPreviewMidBtnAction');
this.SHOW_CLOSE_BUTTON = this.get('winPreviewShowCloseButton');
this.WINDOW_ICON_CLICK_ACTION = this.get('windowIconClickAction');
this.OVERLAY_KEY_SECONDARY = this.get('overlayKeySecondary', true);
this.OVERLAY_KEY_PRIMARY = this.get('overlayKeyPrimary');
this.OVERLAY_KEY_SECONDARY = this.get('overlayKeySecondary');
this.ESC_BEHAVIOR = this.get('overviewEscBehavior');
this.WINDOW_THUMBNAIL_ENABLED = this.get('windowThumbnailModule');
this.WINDOW_THUMBNAIL_SCALE = this.get('windowThumbnailScale') / 100;
this.FIX_NEW_WINDOW_FOCUS = this.get('newWindowFocusFix');
}
_getAnimationDirection() {

View file

@ -10,61 +10,90 @@
'use strict';
const { Clutter, GObject } = imports.gi;
const Clutter = imports.gi.Clutter;
const GObject = imports.gi.GObject;
const Main = imports.ui.main;
const SwipeTracker = imports.ui.swipeTracker;
const Me = imports.misc.extensionUtils.getCurrentExtension();
let Me;
let opt;
let _firstRun = true;
let _vwGestureUpdateId;
let _originalGestureUpdateId;
var SwipeTrackerModule = class {
constructor(me) {
Me = me;
opt = Me.opt;
function update(reset = false) {
opt = Me.imports.lib.settings.opt;
const moduleEnabled = opt.get('swipeTrackerModule', true);
reset = reset || !moduleEnabled;
// don't even touch this module if disabled
if (_firstRun && reset)
return;
_firstRun = false;
if (reset || !opt.ORIENTATION) { // 1-VERTICAL, 0-HORIZONTAL
// original swipeTrackers' orientation and updateGesture function
Main.overview._swipeTracker.orientation = Clutter.Orientation.VERTICAL;
Main.wm._workspaceAnimation._swipeTracker.orientation = Clutter.Orientation.HORIZONTAL;
Main.overview._swipeTracker._updateGesture = SwipeTracker.SwipeTracker.prototype._updateGesture;
if (_vwGestureUpdateId) {
Main.overview._swipeTracker._touchpadGesture.disconnect(_vwGestureUpdateId);
_vwGestureUpdateId = 0;
}
if (_originalGestureUpdateId) {
Main.overview._swipeTracker._touchpadGesture.unblock_signal_handler(_originalGestureUpdateId);
_originalGestureUpdateId = 0;
}
opt = null;
return;
this._firstActivation = true;
this.moduleEnabled = false;
}
if (opt.ORIENTATION) { // 1-VERTICAL, 0-HORIZONTAL
cleanGlobals() {
Me = null;
opt = null;
}
update(reset) {
this.moduleEnabled = opt.get('swipeTrackerModule');
const conflict = false;
reset = reset || !this.moduleEnabled || conflict;
// don't touch the original code if module disabled
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation)
console.debug(' SwipeTrackerModule - Keeping untouched');
}
_activateModule() {
if (opt.ORIENTATION) { // 1-VERTICAL, 0-HORIZONTAL
this._setVertical();
} else {
this._setHorizontal();
}
console.debug(' SwipeTrackerModule - Activated');
}
_disableModule() {
this._setHorizontal();
console.debug(' SwipeTrackerModule - Disabled');
}
_setVertical() {
// reverse swipe gestures for enter/leave overview and ws switching
Main.overview._swipeTracker.orientation = Clutter.Orientation.HORIZONTAL;
Main.wm._workspaceAnimation._swipeTracker.orientation = Clutter.Orientation.VERTICAL;
// overview's updateGesture() function should reflect ws tmb position to match appGrid/ws animation direction
// function in connection cannot be overridden in prototype of its class because connected is actually another copy of the original function
if (!_originalGestureUpdateId) {
_originalGestureUpdateId = GObject.signal_handler_find(Main.overview._swipeTracker._touchpadGesture, { signalId: 'update' });
Main.overview._swipeTracker._touchpadGesture.block_signal_handler(_originalGestureUpdateId);
if (!this._originalGestureUpdateId) {
this._originalGestureUpdateId = GObject.signal_handler_find(Main.overview._swipeTracker._touchpadGesture, { signalId: 'update' });
Main.overview._swipeTracker._touchpadGesture.block_signal_handler(this._originalGestureUpdateId);
Main.overview._swipeTracker._updateGesture = SwipeTrackerVertical._updateGesture;
_vwGestureUpdateId = Main.overview._swipeTracker._touchpadGesture.connect('update', SwipeTrackerVertical._updateGesture.bind(Main.overview._swipeTracker));
this._vwGestureUpdateId = Main.overview._swipeTracker._touchpadGesture.connect('update', SwipeTrackerVertical._updateGesture.bind(Main.overview._swipeTracker));
}
}
}
_setHorizontal() {
// original swipeTrackers' orientation and updateGesture function
Main.overview._swipeTracker.orientation = Clutter.Orientation.VERTICAL;
Main.wm._workspaceAnimation._swipeTracker.orientation = Clutter.Orientation.HORIZONTAL;
Main.overview._swipeTracker._updateGesture = SwipeTracker.SwipeTracker.prototype._updateGesture;
if (this._vwGestureUpdateId) {
Main.overview._swipeTracker._touchpadGesture.disconnect(this._vwGestureUpdateId);
this._vwGestureUpdateId = 0;
}
if (this._originalGestureUpdateId) {
Main.overview._swipeTracker._touchpadGesture.unblock_signal_handler(this._originalGestureUpdateId);
this._originalGestureUpdateId = 0;
}
}
};
const SwipeTrackerVertical = {
_updateGesture(gesture, time, delta, distance) {

View file

@ -10,16 +10,27 @@
'use strict';
const Clutter = imports.gi.Clutter;
const Meta = imports.gi.Meta;
const Gi = imports._gi;
const { Shell, Meta, Clutter } = imports.gi;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Shell = imports.gi.Shell;
const Config = imports.misc.config;
const Main = imports.ui.main;
const Main = imports.ui.main;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
let Me;
var shellVersion = parseFloat(Config.PACKAGE_VERSION);
let _installedExtensions;
function init(me) {
Me = me;
}
function cleanGlobals() {
Me = null;
_installedExtensions = null;
}
var Overrides = class {
constructor() {
@ -27,8 +38,13 @@ var Overrides = class {
}
addOverride(name, prototype, overrideList) {
const backup = this.overrideProto(prototype, overrideList, name);
// don't update originals when override's just refreshing, keep initial content
let originals = this._overrides[name]?.originals;
if (!originals)
originals = backup;
this._overrides[name] = {
originals: this.overrideProto(prototype, overrideList),
originals,
prototype,
};
}
@ -38,15 +54,15 @@ var Overrides = class {
if (!override)
return false;
this.overrideProto(override.prototype, override.originals);
this._overrides[name] = undefined;
this.overrideProto(override.prototype, override.originals, name);
delete this._overrides[name];
return true;
}
removeAll() {
for (let name in this._overrides) {
this.removeOverride(name);
this._overrides[name] = undefined;
delete this._overrides[name];
}
}
@ -54,13 +70,17 @@ var Overrides = class {
proto[Gi.hook_up_vfunc_symbol](symbol, func);
}
overrideProto(proto, overrides) {
overrideProto(proto, overrides, name) {
const backup = {};
const originals = this._overrides[name]?.originals;
for (let symbol in overrides) {
if (symbol.startsWith('after_')) {
const actualSymbol = symbol.slice('after_'.length);
const fn = proto[actualSymbol];
let fn;
if (originals && originals[actualSymbol])
fn = originals[actualSymbol];
else
fn = proto[actualSymbol];
const afterFn = overrides[symbol];
proto[actualSymbol] = function (...args) {
args = Array.prototype.slice.call(args);
@ -72,11 +92,11 @@ var Overrides = class {
} else {
backup[symbol] = proto[symbol];
if (symbol.startsWith('vfunc')) {
if (shellVersion < 42)
if (Me.shellVersion < 42)
this.hookVfunc(proto, symbol.slice(6), overrides[symbol]);
else
this.hookVfunc(proto[Gi.gobject_prototype_symbol], symbol.slice(6), overrides[symbol]);
} else {
} else if (overrides[symbol] !== null) {
proto[symbol] = overrides[symbol];
}
}
@ -85,87 +105,21 @@ var Overrides = class {
}
};
function getOverviewTranslations(opt, dash, tmbBox, searchEntryBin) {
// const tmbBox = Main.overview._overview._controls._thumbnailsBox;
let searchTranslationY = 0;
if (searchEntryBin.visible) {
const offset = (dash.visible && (!opt.DASH_VERTICAL ? dash.height + 12 : 0)) +
(opt.WS_TMB_TOP ? tmbBox.height + 12 : 0);
searchTranslationY = -searchEntryBin.height - offset - 30;
}
let tmbTranslationX = 0;
let tmbTranslationY = 0;
let offset;
if (tmbBox.visible) {
switch (opt.WS_TMB_POSITION) {
case 3: // left
offset = 10 + (dash?.visible && opt.DASH_LEFT ? dash.width : 0);
tmbTranslationX = -tmbBox.width - offset;
tmbTranslationY = 0;
break;
case 1: // right
offset = 10 + (dash?.visible && opt.DASH_RIGHT ? dash.width : 0);
tmbTranslationX = tmbBox.width + offset;
tmbTranslationY = 0;
break;
case 0: // top
offset = 10 + (dash?.visible && opt.DASH_TOP ? dash.height : 0) + Main.panel.height;
tmbTranslationX = 0;
tmbTranslationY = -tmbBox.height - offset;
break;
case 2: // bottom
offset = 10 + (dash?.visible && opt.DASH_BOTTOM ? dash.height : 0) + Main.panel.height; // just for case the panel is at bottom
tmbTranslationX = 0;
tmbTranslationY = tmbBox.height + offset;
break;
}
}
let dashTranslationX = 0;
let dashTranslationY = 0;
let position = opt.DASH_POSITION;
// if DtD replaced the original Dash, read its position
if (dashIsDashToDock())
position = dash._position;
if (dash?.visible) {
switch (position) {
case 0: // top
dashTranslationX = 0;
dashTranslationY = -dash.height - dash.margin_bottom - Main.panel.height;
break;
case 1: // right
dashTranslationX = dash.width;
dashTranslationY = 0;
break;
case 2: // bottom
dashTranslationX = 0;
dashTranslationY = dash.height + dash.margin_bottom + Main.panel.height;
break;
case 3: // left
dashTranslationX = -dash.width;
dashTranslationY = 0;
break;
}
}
return [tmbTranslationX, tmbTranslationY, dashTranslationX, dashTranslationY, searchTranslationY];
}
function openPreferences() {
function openPreferences(metadata) {
if (!metadata)
metadata = Me.metadata;
const windows = global.display.get_tab_list(Meta.TabList.NORMAL_ALL, null);
let tracker = Shell.WindowTracker.get_default();
let metaWin, isVW = null;
for (let win of windows) {
const app = tracker.get_window_app(win);
if (win.get_title().includes(Me.metadata.name) && app.get_name() === 'Extensions') {
if (win.get_title()?.includes(metadata.name) && app.get_name() === 'Extensions') {
// this is our existing window
metaWin = win;
isVW = true;
break;
} else if (win.wm_class.includes('org.gnome.Shell.Extensions')) {
} else if (win.wm_class?.includes('org.gnome.Shell.Extensions')) {
// this is prefs window of another extension
metaWin = win;
isVW = false;
@ -182,17 +136,20 @@ function openPreferences() {
}
if (!metaWin || (metaWin && !isVW)) {
try {
Main.extensionManager.openExtensionPrefs(Me.metadata.uuid, '', {});
} catch (e) {
log(e);
}
GLib.idle_add(GLib.PRIORITY_LOW, () => {
try {
Main.extensionManager.openExtensionPrefs(metadata.uuid, '', {});
} catch (e) {
console.error(e);
}
});
}
}
function activateSearchProvider(prefix = '') {
const searchEntry = Main.overview.searchEntry;
if (!searchEntry.get_text() || !searchEntry.get_text().startsWith(prefix)) {
const searchEntryText = searchEntry.get_text();
if (!searchEntryText || (searchEntryText && !searchEntry.get_text().startsWith(prefix))) {
prefix = `${prefix} `;
const position = prefix.length;
searchEntry.set_text(prefix);
@ -220,9 +177,16 @@ function reorderWorkspace(direction = 0) {
global.workspace_manager.reorder_workspace(activeWs, targetIdx);
}
function activateKeyboardForWorkspaceView() {
Main.ctrlAltTabManager._items.forEach(i => {
if (i.sortGroup === 1 && i.name === 'Windows')
Main.ctrlAltTabManager.focusGroup(i);
});
}
function exposeWindows(adjustment, activateKeyboard) {
// expose windows for static overview modes
if (!adjustment.value && !Main.overview._animationInProgress) {
if (!adjustment.value/* && !Main.overview._animationInProgress*/) {
if (adjustment.value === 0) {
adjustment.value = 0;
adjustment.ease(1, {
@ -330,13 +294,48 @@ function isMoreRelevant(stringA, stringB, pattern) {
return !aAny && bAny;
}
function getEnabledExtensions(uuid = '') {
let extensions = [];
Main.extensionManager._extensions.forEach(e => {
if (e.state === 1 && e.uuid.includes(uuid))
extensions.push(e);
});
return extensions;
function getEnabledExtensions(pattern = '') {
let result = [];
// extensionManager is unreliable at startup (if not all extensions were loaded)
// but gsettings key can contain removed extensions...
// therefore we have to look into filesystem, what's really installed
if (!_installedExtensions) {
const extensionFiles = [...collectFromDatadirs('extensions', true)];
_installedExtensions = extensionFiles.map(({ info }) => {
let fileType = info.get_file_type();
if (fileType !== Gio.FileType.DIRECTORY)
return null;
const uuid = info.get_name();
return uuid;
});
}
const enabled = Main.extensionManager._enabledExtensions;
result = _installedExtensions.filter(ext => enabled.includes(ext));
return result.filter(uuid => uuid !== null && uuid.includes(pattern));
}
function* collectFromDatadirs(subdir, includeUserDir) {
let dataDirs = GLib.get_system_data_dirs();
if (includeUserDir)
dataDirs.unshift(GLib.get_user_data_dir());
for (let i = 0; i < dataDirs.length; i++) {
let path = GLib.build_filenamev([dataDirs[i], 'gnome-shell', subdir]);
let dir = Gio.File.new_for_path(path);
let fileEnum;
try {
fileEnum = dir.enumerate_children('standard::name,standard::type',
Gio.FileQueryInfoFlags.NONE, null);
} catch (e) {
fileEnum = null;
}
if (fileEnum !== null) {
let info;
while ((info = fileEnum.next_file(null)))
yield { dir: fileEnum.get_child(info), info };
}
}
}
function getScrollDirection(event) {

View file

@ -0,0 +1,525 @@
/**
* V-Shell (Vertical Workspaces)
* WinTmb
*
* @author GdH <G-dH@github.com>
* @copyright 2021-2023
* @license GPL-3.0
*/
'use strict';
const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Meta = imports.gi.Meta;
const St = imports.gi.St;
const AltTab = imports.ui.altTab;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
let Me;
let opt;
const SCROLL_ICON_OPACITY = 240;
const DRAG_OPACITY = 200;
const CLOSE_BTN_OPACITY = 240;
var WinTmbModule = class {
constructor(me) {
Me = me;
opt = Me.opt;
this._firstActivation = true;
this.moduleEnabled = false;
}
cleanGlobals() {
Me = null;
opt = null;
}
update(reset) {
this._removeTimeouts();
this.moduleEnabled = opt.get('windowThumbnailModule');
reset = reset || !this.moduleEnabled;
// don't touch the original code if module disabled
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation)
console.debug(' WinTmb - Keeping untouched');
}
_activateModule() {
this._timeouts = {};
if (!this._windowThumbnails)
this._windowThumbnails = [];
Main.overview.connectObject('hidden', () => this.showThumbnails(), this);
console.debug(' WinTmb - Activated');
}
_disableModule() {
Main.overview.disconnectObject(this);
this._disconnectStateAdjustment();
this.removeAllThumbnails();
console.debug(' WinTmb - Disabled');
}
_removeTimeouts() {
if (this._timeouts) {
Object.values(this._timeouts).forEach(t => {
if (t)
GLib.source_remove(t);
});
this._timeouts = null;
}
}
createThumbnail(metaWin) {
const thumbnail = new WindowThumbnail(metaWin, {
'height': Math.floor(opt.WINDOW_THUMBNAIL_SCALE * global.display.get_monitor_geometry(global.display.get_current_monitor()).height),
'thumbnailsOnScreen': this._windowThumbnails.length,
});
this._windowThumbnails.push(thumbnail);
thumbnail.connect('removed', tmb => {
this._windowThumbnails.splice(this._windowThumbnails.indexOf(tmb), 1);
tmb.destroy();
if (!this._windowThumbnails.length)
this._disconnectStateAdjustment();
});
if (!this._stateAdjustmentConId) {
this._stateAdjustmentConId = Main.overview._overview.controls._stateAdjustment.connectObject('notify::value', () => {
if (!this._thumbnailsHidden && (!opt.OVERVIEW_MODE2 || opt.WORKSPACE_MODE))
this.hideThumbnails();
}, this);
}
}
hideThumbnails() {
this._windowThumbnails.forEach(tmb => {
tmb.ease({
opacity: 0,
duration: 200,
mode: Clutter.AnimationMode.LINEAR,
onComplete: () => tmb.hide(),
});
});
this._thumbnailsHidden = true;
}
showThumbnails() {
this._windowThumbnails.forEach(tmb => {
tmb.show();
tmb.ease({
opacity: 255,
duration: 100,
mode: Clutter.AnimationMode.LINEAR,
});
});
this._thumbnailsHidden = false;
}
removeAllThumbnails() {
this._windowThumbnails.forEach(tmb => tmb.remove());
this._windowThumbnails = [];
}
_disconnectStateAdjustment() {
Main.overview._overview.controls._stateAdjustment.disconnectObject(this);
}
};
const WindowThumbnail = GObject.registerClass({
Signals: { 'removed': {} },
}, class WindowThumbnail extends St.Widget {
_init(metaWin, args) {
this._hoverShowsPreview = false;
this._customOpacity = 255;
this._initTmbHeight = args.height;
this._minimumHeight = Math.floor(5 / 100 * global.display.get_monitor_geometry(global.display.get_current_monitor()).height);
this._scrollTimeout = 100;
this._positionOffset = args.thumbnailsOnScreen;
this._reverseTmbWheelFunc = false;
this._click_count = 1;
this._prevBtnPressTime = 0;
this.w = metaWin;
super._init({
layout_manager: new Clutter.BinLayout(),
visible: true,
reactive: true,
can_focus: true,
track_hover: true,
});
this.connect('button-release-event', this._onBtnReleased.bind(this));
this.connect('scroll-event', this._onScrollEvent.bind(this));
// this.connect('motion-event', this._onMouseMove.bind(this)); // may be useful in the future..
this._delegate = this;
this._draggable = DND.makeDraggable(this, { dragActorOpacity: DRAG_OPACITY });
this._draggable.connect('drag-end', this._end_drag.bind(this));
this._draggable.connect('drag-cancelled', this._end_drag.bind(this));
this._draggable._animateDragEnd = eventTime => {
this._draggable._animationInProgress = true;
this._draggable._onAnimationComplete(this._draggable._dragActor, eventTime);
this.opacity = this._customOpacity;
};
this.clone = new Clutter.Clone({ reactive: true });
Main.layoutManager.addChrome(this);
this.window = this.w.get_compositor_private();
this.clone.set_source(this.window);
this.add_child(this.clone);
this._addCloseButton();
this._addScrollModeIcon();
this.connect('enter-event', () => {
global.display.set_cursor(Meta.Cursor.POINTING_HAND);
this._closeButton.opacity = CLOSE_BTN_OPACITY;
this._scrollModeBin.opacity = SCROLL_ICON_OPACITY;
if (this._hoverShowsPreview && !Main.overview._shown) {
this._closeButton.opacity = 50;
this._showWindowPreview(false, true);
}
});
this.connect('leave-event', () => {
global.display.set_cursor(Meta.Cursor.DEFAULT);
this._closeButton.opacity = 0;
this._scrollModeBin.opacity = 0;
if (this._winPreview)
this._destroyWindowPreview();
});
this._setSize(true);
this.set_position(...this._getInitialPosition());
this.show();
this.window_id = this.w.get_id();
this.tmbRedrawDirection = true;
// remove thumbnail content and hide thumbnail if its window is destroyed
this.windowConnect = this.window.connect('destroy', () => {
if (this)
this.remove();
});
}
_getInitialPosition() {
const offset = 20;
let monitor = Main.layoutManager.monitors[global.display.get_current_monitor()];
let x = Math.min(monitor.x + monitor.width - (this.window.width * this.scale) - offset);
let y = Math.min(monitor.y + monitor.height - (this.window.height * this.scale) - offset - ((this._positionOffset * this._initTmbHeight) % (monitor.height - this._initTmbHeight)));
return [x, y];
}
_setSize(resetScale = false) {
if (resetScale)
this.scale = Math.min(1.0, this._initTmbHeight / this.window.height);
const width = this.window.width * this.scale;
const height = this.window.height * this.scale;
this.set_size(width, height);
if (this.icon) {
this.icon.scale_x = this.scale;
this.icon.scale_y = this.scale;
}
// when the scale of this. actor change, this.clone resize accordingly,
// but the reactive area of the actor doesn't change until the actor is redrawn
// this updates the actor's input region area:
Main.layoutManager._queueUpdateRegions();
}
/* _onMouseMove(actor, event) {
let [pos_x, pos_y] = event.get_coords();
let state = event.get_state();
if (this._ctrlPressed(state)) {
}
}*/
_onBtnReleased(actor, event) {
// Clutter.Event.click_count property in no longer available, since GS42
if ((event.get_time() - this._prevBtnPressTime) < Clutter.Settings.get_default().double_click_time)
this._click_count += 1;
else
this._click_count = 1;
this._prevBtnPressTime = event.get_time();
if (this._click_count === 2 && event.get_button() === Clutter.BUTTON_PRIMARY)
this.w.activate(global.get_current_time());
const button = event.get_button();
const state = event.get_state();
switch (button) {
case Clutter.BUTTON_PRIMARY:
if (this._ctrlPressed(state)) {
this._setSize();
} else {
this._reverseTmbWheelFunc = !this._reverseTmbWheelFunc;
this._scrollModeBin.set_child(this._reverseTmbWheelFunc ? this._scrollModeSourceIcon : this._scrollModeResizeIcon);
}
return Clutter.EVENT_STOP;
case Clutter.BUTTON_SECONDARY:
if (this._ctrlPressed(state)) {
this.remove();
} else {
this._hoverShowsPreview = !this._hoverShowsPreview;
this._showWindowPreview();
}
return Clutter.EVENT_STOP;
case Clutter.BUTTON_MIDDLE:
if (this._ctrlPressed(state))
this.w.delete(global.get_current_time());
return Clutter.EVENT_STOP;
default:
return Clutter.EVENT_PROPAGATE;
}
}
_onScrollEvent(actor, event) {
let direction = Me.Util.getScrollDirection(event);
if (this._actionTimeoutActive())
return Clutter.EVENT_PROPAGATE;
let state = event.get_state();
switch (direction) {
case Clutter.ScrollDirection.UP:
if (this._shiftPressed(state)) {
this.opacity = Math.min(255, this.opacity + 24);
this._customOpacity = this.opacity;
} else if (this._reverseTmbWheelFunc !== this._ctrlPressed(state)) {
this._switchSourceWin(-1);
} else if (this._reverseTmbWheelFunc === this._ctrlPressed(state)) {
this.scale = Math.max(0.05, this.scale - 0.025);
}
break;
case Clutter.ScrollDirection.DOWN:
if (this._shiftPressed(state)) {
this.opacity = Math.max(48, this.opacity - 24);
this._customOpacity = this.opacity;
} else if (this._reverseTmbWheelFunc !== this._ctrlPressed(state)) {
this._switchSourceWin(+1);
} else if (this._reverseTmbWheelFunc === this._ctrlPressed(state)) {
this.scale = Math.min(1, this.scale + 0.025);
}
break;
default:
return Clutter.EVENT_PROPAGATE;
}
this._setSize();
return Clutter.EVENT_STOP;
}
remove() {
if (this.clone) {
this.window.disconnect(this.windowConnect);
this.clone.set_source(null);
}
if (this._winPreview)
this._destroyWindowPreview();
this.emit('removed');
}
_end_drag() {
this.set_position(this._draggable._dragOffsetX + this._draggable._dragX, this._draggable._dragOffsetY + this._draggable._dragY);
this._setSize();
}
_ctrlPressed(state) {
return (state & Clutter.ModifierType.CONTROL_MASK) !== 0;
}
_shiftPressed(state) {
return (state & Clutter.ModifierType.SHIFT_MASK) !== 0;
}
_switchSourceWin(direction) {
let windows = global.display.get_tab_list(Meta.TabList.NORMAL_ALL, null);
windows = windows.filter(w => !(w.skip_taskbar || w.minimized));
let idx = -1;
for (let i = 0; i < windows.length; i++) {
if (windows[i] === this.w) {
idx = i + direction;
break;
}
}
idx = idx >= windows.length ? 0 : idx;
idx = idx < 0 ? windows.length - 1 : idx;
let w = windows[idx];
let win = w.get_compositor_private();
this.clone.set_source(win);
this.window.disconnect(this.windowConnect);
// the new thumbnail should be the same height as the previous one
this.scale = (this.scale * this.window.height) / win.height;
this.window = win;
this.windowConnect = this.window.connect('destroy', () => {
if (this)
this.remove();
});
this.w = w;
if (this._winPreview)
this._showWindowPreview(true);
}
_actionTimeoutActive() {
const timeout = this._reverseTmbWheelFunc ? this._scrollTimeout : this._scrollTimeout / 4;
if (!this._lastActionTime || Date.now() - this._lastActionTime > timeout) {
this._lastActionTime = Date.now();
return false;
}
return true;
}
/* _setIcon() {
let tracker = Shell.WindowTracker.get_default();
let app = tracker.get_window_app(this.w);
let icon = app
? app.create_icon_texture(this.height)
: new St.Icon({ icon_name: 'icon-missing', icon_size: this.height });
icon.x_expand = icon.y_expand = true;
if (this.icon)
this.icon.destroy();
this.icon = icon;
}*/
_addCloseButton() {
const closeButton = new St.Button({
opacity: 0,
style_class: 'window-close',
child: new St.Icon({ icon_name: 'preview-close-symbolic' }),
x_align: Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.START,
x_expand: true,
y_expand: true,
});
closeButton.set_style(`
margin: 3px;
background-color: rgba(200, 0, 0, 0.9);
`);
closeButton.connect('clicked', () => {
this.remove();
return Clutter.EVENT_STOP;
});
this._closeButton = closeButton;
this.add_child(this._closeButton);
}
_addScrollModeIcon() {
this._scrollModeBin = new St.Bin({
x_expand: true,
y_expand: true,
});
this._scrollModeResizeIcon = new St.Icon({
icon_name: 'view-fullscreen-symbolic',
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.END,
x_expand: true,
y_expand: true,
opacity: SCROLL_ICON_OPACITY,
style_class: 'icon-dropshadow',
scale_x: 0.5,
scale_y: 0.5,
});
this._scrollModeResizeIcon.set_style(`
margin: 13px;
color: rgb(255, 255, 255);
box-shadow: 0 0 40px 40px rgba(0,0,0,0.7);
`);
this._scrollModeSourceIcon = new St.Icon({
icon_name: 'media-skip-forward-symbolic',
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.END,
x_expand: true,
y_expand: true,
opacity: SCROLL_ICON_OPACITY,
style_class: 'icon-dropshadow',
scale_x: 0.5,
scale_y: 0.5,
});
this._scrollModeSourceIcon.set_style(`
margin: 13px;
color: rgb(255, 255, 255);
box-shadow: 0 0 40px 40px rgba(0,0,0,0.7);
`);
this._scrollModeBin.set_child(this._scrollModeResizeIcon);
this.add_child(this._scrollModeBin);
this._scrollModeBin.opacity = 0;
}
_showWindowPreview(update = false, dontDestroy = false) {
if (this._winPreview && !dontDestroy) {
this._destroyWindowPreview();
this._previewCreationTime = 0;
this._closeButton.opacity = CLOSE_BTN_OPACITY;
if (!update)
return;
}
if (!this._winPreview) {
this._winPreview = new AltTab.CyclerHighlight();
global.window_group.add_actor(this._winPreview);
[this._winPreview._xPointer, this._winPreview._yPointer] = global.get_pointer();
}
if (!update) {
this._winPreview.opacity = 0;
this._winPreview.ease({
opacity: 255,
duration: 70,
mode: Clutter.AnimationMode.LINEAR,
/* onComplete: () => {
this._closeButton.opacity = 50;
},*/
});
this.ease({
opacity: Math.min(50, this._customOpacity),
duration: 70,
mode: Clutter.AnimationMode.LINEAR,
onComplete: () => {
},
});
} else {
this._winPreview.opacity = 255;
}
this._winPreview.window = this.w;
this._winPreview._window = this.w;
global.window_group.set_child_above_sibling(this._winPreview, null);
}
_destroyWindowPreview() {
if (this._winPreview) {
this._winPreview.ease({
opacity: 0,
duration: 100,
mode: Clutter.AnimationMode.LINEAR,
onComplete: () => {
this._winPreview.destroy();
this._winPreview = null;
this.opacity = this._customOpacity;
},
});
}
}
});

View file

@ -11,47 +11,69 @@
'use strict';
const Main = imports.ui.main;
const WindowAttentionHandler = imports.ui.windowAttentionHandler;
const MessageTray = imports.ui.messageTray;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const _Util = Me.imports.lib.util;
const WindowAttentionHandler = imports.ui.windowAttentionHandler;
let Me;
let opt;
let _firstRun = false;
function update(reset = false) {
opt = Me.imports.lib.settings.opt;
const moduleEnabled = opt.get('winAttentionHandlerModule', true);
reset = reset || !moduleEnabled;
var WindowAttentionHandlerModule = class {
constructor(me) {
Me = me;
opt = Me.opt;
if (_firstRun && reset)
return;
_firstRun = false;
if (reset) {
reset = true;
_updateConnections(reset);
opt = null;
return;
this._firstActivation = true;
this.moduleEnabled = false;
this._overrides = null;
}
_updateConnections();
}
cleanGlobals() {
Me = null;
opt = null;
}
function _updateConnections(reset) {
global.display.disconnectObject(Main.windowAttentionHandler);
update(reset) {
this.moduleEnabled = opt.get('windowAttentionHandlerModule');
const conflict = false;
const handlerFnc = reset
? Main.windowAttentionHandler._onWindowDemandsAttention
: WindowAttentionHandlerCommon._onWindowDemandsAttention;
reset = reset || !this.moduleEnabled || conflict;
global.display.connectObject(
'window-demands-attention', handlerFnc.bind(Main.windowAttentionHandler),
'window-marked-urgent', handlerFnc.bind(Main.windowAttentionHandler),
Main.windowAttentionHandler);
}
// don't touch the original code if module disabled
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation)
console.debug(' WindowAttentionHandlerModule - Keeping untouched');
}
_activateModule() {
this._updateConnections();
console.debug(' WindowAttentionHandlerModule - Activated');
}
_disableModule() {
const reset = true;
this._updateConnections(reset);
console.debug(' WindowAttentionHandlerModule - Disabled');
}
_updateConnections(reset) {
global.display.disconnectObject(Main.windowAttentionHandler);
const handlerFnc = reset
? Main.windowAttentionHandler._onWindowDemandsAttention
: WindowAttentionHandlerCommon._onWindowDemandsAttention;
global.display.connectObject(
'window-demands-attention', handlerFnc.bind(Main.windowAttentionHandler),
'window-marked-urgent', handlerFnc.bind(Main.windowAttentionHandler),
Main.windowAttentionHandler);
}
};
const WindowAttentionHandlerCommon = {
_onWindowDemandsAttention(display, window) {

View file

@ -10,81 +10,101 @@
'use strict';
const { GObject, Clutter, Meta } = imports.gi;
const Clutter = imports.gi.Clutter;
const GObject = imports.gi.GObject;
const Meta = imports.gi.Meta;
const Main = imports.ui.main;
const WindowManager = imports.ui.windowManager;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const _Util = Me.imports.lib.util;
let _overrides;
const MINIMIZE_WINDOW_ANIMATION_TIME = WindowManager.MINIMIZE_WINDOW_ANIMATION_TIME;
const MINIMIZE_WINDOW_ANIMATION_MODE = WindowManager.MINIMIZE_WINDOW_ANIMATION_MODE;
let Me;
let opt;
let _firstRun = true;
function update(reset = false) {
opt = Me.imports.lib.settings.opt;
const moduleEnabled = opt.get('windowManagerModule', true);
reset = reset || !moduleEnabled;
var WindowManagerModule = class {
constructor(me) {
Me = me;
opt = Me.opt;
// don't even touch this module if disabled
if (_firstRun && reset)
return;
this._firstActivation = true;
this.moduleEnabled = false;
this._overrides = null;
_firstRun = false;
this._originalMinimizeSigId = 0;
this._minimizeSigId = 0;
this._originalUnminimizeSigId = 0;
this._unminimizeSigId = 0;
}
if (_overrides)
_overrides.removeAll();
_replaceMinimizeFunction(reset);
if (reset) {
_overrides = null;
cleanGlobals() {
Me = null;
opt = null;
return;
}
_overrides = new _Util.Overrides();
update(reset) {
this.moduleEnabled = opt.get('windowManagerModule');
const conflict = false;
_overrides.addOverride('WindowManager', WindowManager.WindowManager.prototype, WindowManagerCommon);
}
reset = reset || !this.moduleEnabled || conflict;
// ------------- Fix and adapt minimize/unminimize animations --------------------------------------
let _originalMinimizeSigId;
let _minimizeSigId;
let _originalUnminimizeSigId;
let _unminimizeSigId;
function _replaceMinimizeFunction(reset = false) {
if (reset) {
Main.wm._shellwm.disconnect(_minimizeSigId);
_minimizeSigId = 0;
Main.wm._shellwm.unblock_signal_handler(_originalMinimizeSigId);
_originalMinimizeSigId = 0;
Main.wm._shellwm.disconnect(_unminimizeSigId);
_unminimizeSigId = 0;
Main.wm._shellwm.unblock_signal_handler(_originalUnminimizeSigId);
_originalUnminimizeSigId = 0;
} else if (!_minimizeSigId) {
_originalMinimizeSigId = GObject.signal_handler_find(Main.wm._shellwm, { signalId: 'minimize' });
if (_originalMinimizeSigId) {
Main.wm._shellwm.block_signal_handler(_originalMinimizeSigId);
_minimizeSigId = Main.wm._shellwm.connect('minimize', WindowManagerCommon._minimizeWindow.bind(Main.wm));
}
_originalUnminimizeSigId = GObject.signal_handler_find(Main.wm._shellwm, { signalId: 'unminimize' });
if (_originalUnminimizeSigId) {
Main.wm._shellwm.block_signal_handler(_originalUnminimizeSigId);
_unminimizeSigId = Main.wm._shellwm.connect('unminimize', WindowManagerCommon._unminimizeWindow.bind(Main.wm));
// don't even touch the original code if module disabled
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation)
console.debug(' WindowManagerModule - Keeping untouched');
}
}
_activateModule() {
if (!this._overrides)
this._overrides = new Me.Util.Overrides();
this._overrides.addOverride('WindowManager', WindowManager.WindowManager.prototype, WindowManagerCommon);
if (!this._minimizeSigId) {
this._originalMinimizeSigId = GObject.signal_handler_find(Main.wm._shellwm, { signalId: 'minimize' });
if (this._originalMinimizeSigId) {
Main.wm._shellwm.block_signal_handler(this._originalMinimizeSigId);
this._minimizeSigId = Main.wm._shellwm.connect('minimize', WindowManagerCommon._minimizeWindow.bind(Main.wm));
}
this._originalUnminimizeSigId = GObject.signal_handler_find(Main.wm._shellwm, { signalId: 'unminimize' });
if (this._originalUnminimizeSigId) {
Main.wm._shellwm.block_signal_handler(this._originalUnminimizeSigId);
this._unminimizeSigId = Main.wm._shellwm.connect('unminimize', WindowManagerCommon._unminimizeWindow.bind(Main.wm));
}
}
console.debug(' WindowManagerModule - Activated');
}
_disableModule() {
if (this._overrides)
this._overrides.removeAll();
this._overrides = null;
if (this._minimizeSigId) {
Main.wm._shellwm.disconnect(this._minimizeSigId);
this._minimizeSigId = 0;
}
if (this._originalMinimizeSigId) {
Main.wm._shellwm.unblock_signal_handler(this._originalMinimizeSigId);
this._originalMinimizeSigId = 0;
}
if (this._unminimizeSigId) {
Main.wm._shellwm.disconnect(this._unminimizeSigId);
this._unminimizeSigId = 0;
}
if (this._originalUnminimizeSigId) {
Main.wm._shellwm.unblock_signal_handler(this._originalUnminimizeSigId);
this._originalUnminimizeSigId = 0;
}
console.debug(' WindowManagerModule - Disabled');
}
};
// fix for mainstream bug - fullscreen windows should minimize using opacity transition
// but its being applied directly on window actor and that doesn't work
@ -109,8 +129,8 @@ const WindowManagerCommon = {
/* if (actor.meta_window.is_monitor_sized()) {
actor.get_first_child().ease({
opacity: 0,
duration: MINIMIZE_WINDOW_ANIMATION_TIME,
mode: MINIMIZE_WINDOW_ANIMATION_MODE,
duration: WindowManager.MINIMIZE_WINDOW_ANIMATION_TIME,
mode: WindowManager.MINIMIZE_WINDOW_ANIMATION_MODE,
onStopped: () => this._minimizeWindowDone(shellwm, actor),
});
} else { */
@ -140,8 +160,8 @@ const WindowManagerCommon = {
scale_y: yScale,
x: xDest,
y: yDest,
duration: MINIMIZE_WINDOW_ANIMATION_TIME,
mode: MINIMIZE_WINDOW_ANIMATION_MODE,
duration: WindowManager.MINIMIZE_WINDOW_ANIMATION_TIME,
mode: WindowManager.MINIMIZE_WINDOW_ANIMATION_MODE,
onStopped: () => this._minimizeWindowDone(shellwm, actor),
});
// }
@ -176,8 +196,8 @@ const WindowManagerCommon = {
actor.set_scale(1.0, 1.0);
actor.ease({
opacity: 255,
duration: MINIMIZE_WINDOW_ANIMATION_TIME,
mode: MINIMIZE_WINDOW_ANIMATION_MODE,
duration: WindowManager.MINIMIZE_WINDOW_ANIMATION_TIME,
mode: WindowManager.MINIMIZE_WINDOW_ANIMATION_MODE,
onStopped: () => this._unminimizeWindowDone(shellwm, actor),
});
} else { */
@ -208,8 +228,8 @@ const WindowManagerCommon = {
scale_y: 1,
x: xDest,
y: yDest,
duration: MINIMIZE_WINDOW_ANIMATION_TIME,
mode: MINIMIZE_WINDOW_ANIMATION_MODE,
duration: WindowManager.MINIMIZE_WINDOW_ANIMATION_TIME,
mode: WindowManager.MINIMIZE_WINDOW_ANIMATION_MODE,
onStopped: () => this._unminimizeWindowDone(shellwm, actor),
});
// }

View file

@ -10,103 +10,372 @@
'use strict';
const { Clutter, GLib, GObject, Graphene, Meta, Shell, St } = imports.gi;
const Clutter = imports.gi.Clutter;
const Atk = imports.gi.Atk;
const GLib = imports.gi.GLib;
const Graphene = imports.gi.Graphene;
const Meta = imports.gi.Meta;
const Pango = imports.gi.Pango;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
const OverviewControls = imports.ui.overviewControls;
const WindowPreview = imports.ui.windowPreview;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const _Util = Me.imports.lib.util;
const shellVersion = _Util.shellVersion;
let _overrides;
const WINDOW_SCALE_TIME = imports.ui.windowPreview.WINDOW_SCALE_TIME;
const WINDOW_ACTIVE_SIZE_INC = imports.ui.windowPreview.WINDOW_ACTIVE_SIZE_INC;
const WINDOW_OVERLAY_FADE_TIME = imports.ui.windowPreview.WINDOW_OVERLAY_FADE_TIME;
const SEARCH_WINDOWS_PREFIX = Me.imports.lib.windowSearchProvider.prefix;
const ControlsState = imports.ui.overviewControls.ControlsState;
let Me;
let opt;
let _firstRun = true;
function update(reset = false) {
opt = Me.imports.lib.settings.opt;
const moduleEnabled = opt.get('windowPreviewModule', true);
reset = reset || !moduleEnabled;
const WINDOW_SCALE_TIME = 200;
const WINDOW_ACTIVE_SIZE_INC = 5;
const WINDOW_OVERLAY_FADE_TIME = 200;
const WINDOW_DND_SIZE = 256;
const DRAGGING_WINDOW_OPACITY = 100;
// don't even touch this module if disabled
if (_firstRun && reset)
return;
const ControlsState = OverviewControls.ControlsState;
_firstRun = false;
var WindowPreviewModule = class {
constructor(me) {
Me = me;
opt = Me.opt;
if (_overrides)
_overrides.removeAll();
if (reset) {
_overrides = null;
opt = null;
WindowPreview.WINDOW_OVERLAY_IDLE_HIDE_TIMEOUT = 750;
return;
this._firstActivation = true;
this.moduleEnabled = false;
this._overrides = null;
}
_overrides = new _Util.Overrides();
cleanGlobals() {
Me = null;
opt = null;
}
_overrides.addOverride('WindowPreview', WindowPreview.WindowPreview.prototype, WindowPreviewCommon);
// A shorter timeout allows user to quickly cancel the selection by leaving the preview with the mouse pointer
if (opt.ALWAYS_ACTIVATE_SELECTED_WINDOW)
WindowPreview.WINDOW_OVERLAY_IDLE_HIDE_TIMEOUT = 150;
}
update(reset) {
this.moduleEnabled = opt.get('windowPreviewModule');
const conflict = false;
const WindowPreviewCommon = {
// injection to _init()
after__init() {
const ICON_OVERLAP = 0.7;
reset = reset || !this.moduleEnabled || conflict;
if (opt.WIN_PREVIEW_ICON_SIZE < 64) {
this.remove_child(this._icon);
this._icon.destroy();
const tracker = Shell.WindowTracker.get_default();
const app = tracker.get_window_app(this.metaWindow);
this._icon = app.create_icon_texture(opt.WIN_PREVIEW_ICON_SIZE);
this._icon.add_style_class_name('icon-dropshadow');
this._icon.set({
reactive: true,
pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }),
});
this._icon.add_constraint(new Clutter.BindConstraint({
source: this.windowContainer,
coordinate: Clutter.BindCoordinate.POSITION,
}));
this._icon.add_constraint(new Clutter.AlignConstraint({
source: this.windowContainer,
align_axis: Clutter.AlignAxis.X_AXIS,
factor: 0.5,
}));
this._icon.add_constraint(new Clutter.AlignConstraint({
source: this.windowContainer,
align_axis: Clutter.AlignAxis.Y_AXIS,
pivot_point: new Graphene.Point({ x: -1, y: ICON_OVERLAP }),
factor: 1,
}));
this.add_child(this._icon);
if (opt.WIN_PREVIEW_ICON_SIZE < 22) {
// disable app icon
this._icon.hide();
}
this._iconSize = opt.WIN_PREVIEW_ICON_SIZE;
// don't touch the original code if module disabled
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation)
console.debug(' WindowPreviewModule - Keeping untouched');
}
_activateModule() {
if (!this._overrides)
this._overrides = new Me.Util.Overrides();
this._overrides.addOverride('WindowPreview', WindowPreview.WindowPreview.prototype, WindowPreviewCommon);
// A shorter timeout allows user to quickly cancel the selection by leaving the preview with the mouse pointer
if (opt.ALWAYS_ACTIVATE_SELECTED_WINDOW)
WindowPreview.WINDOW_OVERLAY_IDLE_HIDE_TIMEOUT = 150;
console.debug(' WindowPreviewModule - Activated');
}
_disableModule() {
// If WindowPreview._init was injected by another extension (like Burn My Windows)
// which enables/disables before V-Shell
// don't restore the original if it's not injected,
// because it would restore injected _init and recursion would freeze GS when extensions are enabled again.
// This can happen when all extension re-enabled, not only when screen is locked/unlocked
// If _init doesn't include "fn.apply(this, args)" when reset === true, some extension already restored the original
const skipReset = WindowPreview.WindowPreview.prototype._init.toString().includes('fn.apply(this, args)');
if (this._overrides && skipReset) {
// skip restoring original _init()
this._overrides['_init'] = null;
}
if (this._overrides)
this._overrides.removeAll();
this._overrides = null;
console.debug(' WindowPreviewModule - Disabled');
}
};
const WindowPreviewCommon = {
_init(metaWindow, workspace, overviewAdjustment) {
this.metaWindow = metaWindow;
this.metaWindow._delegate = this;
this._windowActor = metaWindow.get_compositor_private();
this._workspace = workspace;
this._overviewAdjustment = overviewAdjustment;
const ICON_SIZE = opt.WIN_PREVIEW_ICON_SIZE;
const ICON_OVERLAP = 0.7;
Shell.WindowPreview.prototype._init.bind(this)({
reactive: true,
can_focus: true,
accessible_role: Atk.Role.PUSH_BUTTON,
offscreen_redirect: Clutter.OffscreenRedirect.AUTOMATIC_FOR_OPACITY,
});
const windowContainer = new Clutter.Actor({
pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }),
});
this.window_container = windowContainer;
windowContainer.connect('notify::scale-x',
() => this._adjustOverlayOffsets());
// gjs currently can't handle setting an actors layout manager during
// the initialization of the actor if that layout manager keeps track
// of its container, so set the layout manager after creating the
// container
windowContainer.layout_manager = new Shell.WindowPreviewLayout();
this.add_child(windowContainer);
this._addWindow(metaWindow);
this._delegate = this;
this._stackAbove = null;
this._cachedBoundingBox = {
x: windowContainer.layout_manager.bounding_box.x1,
y: windowContainer.layout_manager.bounding_box.y1,
width: windowContainer.layout_manager.bounding_box.get_width(),
height: windowContainer.layout_manager.bounding_box.get_height(),
};
windowContainer.layout_manager.connect(
'notify::bounding-box', layout => {
this._cachedBoundingBox = {
x: layout.bounding_box.x1,
y: layout.bounding_box.y1,
width: layout.bounding_box.get_width(),
height: layout.bounding_box.get_height(),
};
// A bounding box of 0x0 means all windows were removed
if (layout.bounding_box.get_area() > 0)
this.emit('size-changed');
});
this._windowActor.connectObject('destroy', () => this.destroy(), this);
this._updateAttachedDialogs();
let clickAction = new Clutter.ClickAction();
clickAction.connect('clicked', act => {
const button = act.get_button();
if (button === Clutter.BUTTON_SECONDARY) {
if (opt.WIN_PREVIEW_SEC_BTN_ACTION === 1) {
this._closeWinAction();
return Clutter.EVENT_STOP;
} else if (opt.WIN_PREVIEW_SEC_BTN_ACTION === 2) {
this._searchAppWindowsAction();
return Clutter.EVENT_STOP;
} else if (opt.WIN_PREVIEW_SEC_BTN_ACTION === 3 && opt.WINDOW_THUMBNAIL_ENABLED) {
this._removeLaters();
Me.Modules.winTmbModule.createThumbnail(metaWindow);
return Clutter.EVENT_STOP;
}
} else if (button === Clutter.BUTTON_MIDDLE) {
if (opt.WIN_PREVIEW_MID_BTN_ACTION === 1) {
this._closeWinAction();
return Clutter.EVENT_STOP;
} else if (opt.WIN_PREVIEW_MID_BTN_ACTION === 2) {
this._searchAppWindowsAction();
return Clutter.EVENT_STOP;
} else if (opt.WIN_PREVIEW_MID_BTN_ACTION === 3 && opt.WINDOW_THUMBNAIL_ENABLED) {
this._removeLaters();
Me.Modules.winTmbModule.createThumbnail(metaWindow);
return Clutter.EVENT_STOP;
}
}
return this._activate();
});
if (this._onLongPress) {
clickAction.connect('long-press', this._onLongPress.bind(this));
} else {
clickAction.connect('long-press', (action, actor, state) => {
if (state === Clutter.LongPressState.ACTIVATE)
this.showOverlay(true);
return true;
});
}
this.connect('destroy', this._onDestroy.bind(this));
this._draggable = DND.makeDraggable(this, {
restoreOnSuccess: true,
manualMode: !!this._onLongPress,
dragActorMaxSize: WINDOW_DND_SIZE,
dragActorOpacity: DRAGGING_WINDOW_OPACITY,
});
// _draggable.addClickAction is new in GS45
if (this._draggable.addClickAction)
this._draggable.addClickAction(clickAction);
else
this.add_action(clickAction);
this._draggable.connect('drag-begin', this._onDragBegin.bind(this));
this._draggable.connect('drag-cancelled', this._onDragCancelled.bind(this));
this._draggable.connect('drag-end', this._onDragEnd.bind(this));
this.inDrag = false;
this._selected = false;
this._overlayEnabled = true;
this._overlayShown = false;
this._closeRequested = false;
this._idleHideOverlayId = 0;
const tracker = Shell.WindowTracker.get_default();
const app = tracker.get_window_app(this.metaWindow);
this._icon = app.create_icon_texture(ICON_SIZE);
this._icon.add_style_class_name('icon-dropshadow');
this._icon.set({
reactive: true,
pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }),
});
this._icon.add_constraint(new Clutter.BindConstraint({
source: windowContainer,
coordinate: Clutter.BindCoordinate.POSITION,
}));
this._icon.add_constraint(new Clutter.AlignConstraint({
source: windowContainer,
align_axis: Clutter.AlignAxis.X_AXIS,
factor: 0.5,
}));
this._icon.add_constraint(new Clutter.AlignConstraint({
source: windowContainer,
align_axis: Clutter.AlignAxis.Y_AXIS,
pivot_point: new Graphene.Point({ x: -1, y: ICON_OVERLAP }),
factor: 1,
}));
if (opt.WINDOW_ICON_CLICK_ACTION) {
const iconClickAction = new Clutter.ClickAction();
iconClickAction.connect('clicked', act => {
if (act.get_button() === Clutter.BUTTON_PRIMARY) {
if (opt.WINDOW_ICON_CLICK_ACTION === 1) {
this._searchAppWindowsAction();
return Clutter.EVENT_STOP;
} else if (opt.WINDOW_ICON_CLICK_ACTION === 2 && opt.WINDOW_THUMBNAIL_ENABLED) {
this._removeLaters();
Me.Modules.winTmbModule.createThumbnail(metaWindow);
return Clutter.EVENT_STOP;
}
} /* else if (act.get_button() === Clutter.BUTTON_SECONDARY) {
return Clutter.EVENT_STOP;
}*/
return Clutter.EVENT_PROPAGATE;
});
this._icon.add_action(iconClickAction);
}
const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage);
const iconOverlap = opt.WIN_PREVIEW_ICON_SIZE * ICON_OVERLAP;
// we cannot get proper title height before it gets to the stage, so 35 is estimated height + spacing
this._title.get_constraints()[1].offset = scaleFactor * (-iconOverlap - 35);
this.set_child_above_sibling(this._title, null);
this._title = new St.Label({
visible: false,
style_class: 'window-caption',
text: this._getCaption(),
reactive: true,
});
this._title.clutter_text.single_line_mode = true;
this._title.add_constraint(new Clutter.BindConstraint({
source: windowContainer,
coordinate: Clutter.BindCoordinate.X,
}));
let offset;
if (opt.WIN_TITLES_POSITION < 2) {
// we cannot get proper title height before it gets to the stage, so 35 is estimated height + spacing
offset = -scaleFactor * (ICON_SIZE * ICON_OVERLAP + 35);
} else {
offset = scaleFactor * (ICON_SIZE * (1 - ICON_OVERLAP) + 4);
}
this._title.add_constraint(new Clutter.BindConstraint({
source: windowContainer,
coordinate: Clutter.BindCoordinate.Y,
offset,
}));
this._title.add_constraint(new Clutter.AlignConstraint({
source: windowContainer,
align_axis: Clutter.AlignAxis.X_AXIS,
factor: 0.5,
}));
this._title.add_constraint(new Clutter.AlignConstraint({
source: windowContainer,
align_axis: Clutter.AlignAxis.Y_AXIS,
pivot_point: new Graphene.Point({ x: -1, y: 0 }),
factor: 1,
}));
this._title.clutter_text.ellipsize = Pango.EllipsizeMode.END;
this.label_actor = this._title;
this.metaWindow.connectObject(
'notify::title', () => (this._title.text = this._getCaption()),
this);
const layout = Meta.prefs_get_button_layout();
this._closeButtonSide =
layout.left_buttons.includes(Meta.ButtonFunction.CLOSE)
? St.Side.LEFT : St.Side.RIGHT;
if (Me.shellVersion < 43) {
this._closeButton = new St.Button({
visible: false,
style_class: 'window-close',
child: new St.Icon({ icon_name: 'preview-close-symbolic' }),
});
} else {
this._closeButton = new St.Button({
visible: false,
style_class: 'window-close',
icon_name: 'preview-close-symbolic',
});
}
this._closeButton.add_constraint(new Clutter.BindConstraint({
source: windowContainer,
coordinate: Clutter.BindCoordinate.POSITION,
}));
this._closeButton.add_constraint(new Clutter.AlignConstraint({
source: windowContainer,
align_axis: Clutter.AlignAxis.X_AXIS,
pivot_point: new Graphene.Point({ x: 0.5, y: -1 }),
factor: this._closeButtonSide === St.Side.LEFT ? 0 : 1,
}));
this._closeButton.add_constraint(new Clutter.AlignConstraint({
source: windowContainer,
align_axis: Clutter.AlignAxis.Y_AXIS,
pivot_point: new Graphene.Point({ x: -1, y: 0.5 }),
factor: 0,
}));
this._closeButton.connect('clicked', () => this._deleteAll());
this.add_child(this._title);
this.add_child(this._icon);
this.add_child(this._closeButton);
this._overviewAdjustment.connectObject(
'notify::value', () => this._updateIconScale(), this);
this._updateIconScale();
this.connect('notify::realized', () => {
if (!this.realized)
return;
this._title.ensure_style();
this._icon.ensure_style();
});
if (ICON_SIZE < 22) {
// disable app icon
this._icon.hide();
} else {
this._updateIconScale();
}
// if window is created while the overview is shown, icon and title should be visible immediately
if (Main.overview._overview._controls._stateAdjustment.value < 1) {
this._icon.scale_x = 0;
@ -124,9 +393,9 @@ const WindowPreviewCommon = {
if (global.get_pointer()[0] === opt.showingPointerX || Main.overview._overview._controls._stateAdjustment.value < 1)
return;
const adjustment = this._workspace._background._stateAdjustment;
opt.WORKSPACE_MODE = 1;
_Util.exposeWindows(adjustment, false);
const view = this._workspace.get_parent();
view.exposeWindows(this._workspace.metaWorkspace.index());
this.disconnect(this._wsStateConId);
});
}
@ -136,53 +405,39 @@ const WindowPreviewCommon = {
this._stateAdjustmentSigId = this._workspace.stateAdjustment.connect('notify::value', this._updateIconScale.bind(this));
}
// replace click action with custom one
const action = this.get_actions()[0];
const handlerId = GObject.signal_handler_find(action, { signalId: 'clicked' });
if (handlerId)
action.disconnect(handlerId);
action.connect('clicked', act => {
const button = act.get_button();
if (button === Clutter.BUTTON_PRIMARY) {
this._activate();
return Clutter.EVENT_STOP;
} else if (button === Clutter.BUTTON_SECONDARY) {
// this action cancels long-press event and the 'long-press-cancel' event is used by the Shell to actually initiate DnD
// so the dnd initiation needs to be removed
if (this._longPressLater) {
if (shellVersion >= 44) {
const laters = global.compositor.get_laters();
laters.remove(this._longPressLater);
} else {
Meta.later_remove(this._longPressLater);
delete this._longPressLater;
}
}
const tracker = Shell.WindowTracker.get_default();
const appName = tracker.get_window_app(this.metaWindow).get_name();
_Util.activateSearchProvider(`${SEARCH_WINDOWS_PREFIX} ${appName}`);
return Clutter.EVENT_STOP;
}
return Clutter.EVENT_PROPAGATE;
});
if (opt.WINDOW_ICON_CLICK_SEARCH) {
const iconClickAction = new Clutter.ClickAction();
iconClickAction.connect('clicked', act => {
if (act.get_button() === Clutter.BUTTON_PRIMARY) {
const tracker = Shell.WindowTracker.get_default();
const appName = tracker.get_window_app(this.metaWindow).get_name();
_Util.activateSearchProvider(`${SEARCH_WINDOWS_PREFIX} ${appName}`);
return Clutter.EVENT_STOP;
}
return Clutter.EVENT_PROPAGATE;
});
this._icon.add_action(iconClickAction);
const metaWin = this.metaWindow;
if (opt.DASH_ISOLATE_WS && !metaWin._wsChangedConId) {
metaWin._wsChangedConId = metaWin.connect('workspace-changed',
() => Main.overview.dash._queueRedisplay());
} else if (!opt.DASH_ISOLATE_WS && metaWin._wsChangedConId) {
metaWin.disconnect(metaWin._wsChangedConId);
}
},
_closeWinAction() {
this.hide();
this._deleteAll();
},
_removeLaters() {
// this action cancels long-press event and the 'long-press-cancel' event is used by the Shell to actually initiate DnD
// so the dnd initiation needs to be removed
if (this._longPressLater) {
if (Meta.later_remove)
Meta.later_remove(this._longPressLater);
else
global.compositor.get_laters().remove(this._longPressLater);
delete this._longPressLater;
}
},
_searchAppWindowsAction() {
this._removeLaters();
const tracker = Shell.WindowTracker.get_default();
const appName = tracker.get_window_app(this.metaWindow).get_name();
Me.Util.activateSearchProvider(`${Me.WSP_PREFIX} ${appName}`);
},
_updateIconScale() {
let { currentState, initialState, finalState } =
this._overviewAdjustment.getStateTransitionParams();
@ -192,7 +447,7 @@ const WindowPreviewCommon = {
const visible =
(initialState > ControlsState.HIDDEN || finalState > ControlsState.HIDDEN) &&
!(finalState === ControlsState.APP_GRID && primaryMonitor);
!(finalState === ControlsState.APP_GRID && opt.WS_ANIMATION && primaryMonitor);
let scale = 0;
if (visible)
@ -210,7 +465,6 @@ const WindowPreviewCommon = {
else if (primaryMonitor && currentState > ControlsState.WINDOW_PICKER)
scale = 0;
// in static workspace mode show icon and title on windows expose
if (opt.OVERVIEW_MODE) {
if (currentState === 1)
@ -219,29 +473,32 @@ const WindowPreviewCommon = {
return;
}
if (!opt.WS_ANIMATION && (Main.overview._overview.controls._searchController.searchActive ||
((initialState === ControlsState.WINDOW_PICKER && finalState === ControlsState.APP_GRID) ||
(initialState === ControlsState.APP_GRID && finalState === ControlsState.WINDOW_PICKER)))
)
return;
// if titles are in 'always show' mode, we need to add transition between visible/invisible state
// but the transition is quite expensive,
// showing the titles at the end of the transition is good enough and workspace preview transition is much smoother
if (scale === 1) {
this._icon.ease({
duration: 50,
scale_x: scale,
scale_y: scale,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
this._icon.set({
scale_x: 1,
scale_y: 1,
});
this._title.ease({
duration: 100,
opacity: 255,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
});
} else if (this._icon.scale_x !== 0) {
this._icon.set({
scale_x: 0,
scale_y: 0,
});
} else {
this._title.opacity = 0;
this._icon.set({
scale_x: scale,
scale_y: scale,
});
}
// if titles are in 'always show' mode, we need to add transition between visible/invisible state
// but the transition is quite expensive,
// showing the titles at the end of the transition is good enough and workspace preview transition is much smoother
},
showOverlay(animate) {
@ -252,7 +509,7 @@ const WindowPreviewCommon = {
return;
this._overlayShown = true;
if (!opt.ALWAYS_ACTIVATE_SELECTED_WINDOW)
if (opt.WIN_TITLES_POSITION === 2)
this._restack();
// If we're supposed to animate and an animation in our direction
@ -263,7 +520,7 @@ const WindowPreviewCommon = {
ongoingTransition.get_interval().peek_final_value() === 255)
return;
const toShow = this._windowCanClose()
const toShow = this._windowCanClose() && opt.SHOW_CLOSE_BUTTON
? [this._closeButton]
: [];
@ -301,12 +558,12 @@ const WindowPreviewCommon = {
if (!this._overlayShown)
return;
this._overlayShown = false;
if (opt.ALWAYS_ACTIVATE_SELECTED_WINDOW && Main.overview._overview.controls._stateAdjustment.value < 1) {
this.get_parent()?.set_child_above_sibling(this, null);
this._activateSelected = true;
}
if (!opt.ALWAYS_ACTIVATE_SELECTED_WINDOW)
if (opt.ALWAYS_ACTIVATE_SELECTED_WINDOW && Main.overview._overview.controls._stateAdjustment.value < 1)
this._activateSelected = true;
if (opt.WIN_TITLES_POSITION === 2)
this._restack();
// If we're supposed to animate and an animation in our direction
@ -353,14 +610,11 @@ const WindowPreviewCommon = {
this._delegate = null;
if (this._longPressLater) {
if (shellVersion >= 44) {
const laters = global.compositor.get_laters();
laters.remove(this._longPressLater);
delete this._longPressLater;
} else {
Meta.later_remove(this._longPressLater);
delete this._longPressLater;
}
if (Meta.later_add)
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, this._longPressLater);
else
global.compositor.get_laters().add(Meta.LaterType.BEFORE_REDRAW, this._longPressLater);
delete this._longPressLater;
}
if (this._idleHideOverlayId > 0) {

View file

@ -9,30 +9,23 @@
'use strict';
const { GLib, Gio, Meta, St, Shell } = imports.gi;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Main = imports.ui.main;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Settings = Me.imports.lib.settings;
const _Util = Me.imports.lib.util;
let Me;
let opt;
// gettext
const _ = Settings._;
const shellVersion = Settings.shellVersion;
const ModifierType = imports.gi.Clutter.ModifierType;
let windowSearchProvider;
let _enableTimeoutId = 0;
let _;
// prefix helps to eliminate results from other search providers
// so it needs to be something less common
// needs to be accessible from vw module
var prefix = 'wq//';
let opt;
const PREFIX = 'wq//';
const Action = {
NONE: 0,
@ -42,66 +35,77 @@ const Action = {
MOVE_ALL_TO_WS: 4,
};
function getOverviewSearchResult() {
return Main.overview._overview.controls._searchController._searchResults;
}
var WindowSearchProviderModule = class {
// export for other modules
static _PREFIX = PREFIX;
constructor(me) {
Me = me;
opt = Me.opt;
_ = Me.gettext;
function update(reset = false) {
opt = Me.imports.lib.settings.opt;
if (!reset && opt.WINDOW_SEARCH_PROVIDER_ENABLED && !windowSearchProvider) {
enable();
} else if (reset || !opt.WINDOW_SEARCH_PROVIDER_ENABLED) {
disable();
this._firstActivation = true;
this.moduleEnabled = false;
// export for other modules
this._windowSearchProvider = null;
this._enableTimeoutId = 0;
}
cleanGlobals() {
Me = null;
opt = null;
_ = null;
}
}
function enable() {
// delay because Fedora had problem to register a new provider soon after Shell restarts
_enableTimeoutId = GLib.timeout_add(
GLib.PRIORITY_DEFAULT,
2000,
() => {
if (!windowSearchProvider) {
windowSearchProvider = new WindowSearchProvider(opt);
getOverviewSearchResult()._registerProvider(
windowSearchProvider
);
}
_enableTimeoutId = 0;
return GLib.SOURCE_REMOVE;
update(reset) {
this.moduleEnabled = opt.get('windowSearchProviderModule');
reset = reset || !this.moduleEnabled;
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
);
}
if (reset && this._firstActivation)
console.debug(' WindowSearchProviderModule - Keeping untouched');
}
function disable() {
if (windowSearchProvider) {
getOverviewSearchResult()._unregisterProvider(
windowSearchProvider
_activateModule() {
// delay because Fedora had problem to register a new provider soon after Shell restarts
this._enableTimeoutId = GLib.timeout_add(
GLib.PRIORITY_DEFAULT,
2000,
() => {
if (!this._windowSearchProvider) {
this._windowSearchProvider = new WindowSearchProvider(opt);
this._getOverviewSearchResult()._registerProvider(this._windowSearchProvider);
}
this._enableTimeoutId = 0;
return GLib.SOURCE_REMOVE;
}
);
windowSearchProvider = null;
console.debug(' WindowSearchProviderModule - Activated');
}
if (_enableTimeoutId) {
GLib.source_remove(_enableTimeoutId);
_enableTimeoutId = 0;
_disableModule() {
if (this._windowSearchProvider) {
this._getOverviewSearchResult()._unregisterProvider(this._windowSearchProvider);
this._windowSearchProvider = null;
}
if (this._enableTimeoutId) {
GLib.source_remove(this._enableTimeoutId);
this._enableTimeoutId = 0;
}
console.debug(' WindowSearchProviderModule - Disabled');
}
}
function makeResult(window, i) {
const app = Shell.WindowTracker.get_default().get_window_app(window);
const appName = app ? app.get_name() : 'Unknown';
const windowTitle = window.get_title();
const wsIndex = window.get_workspace().index();
return {
'id': i,
// convert all accented chars to their basic form and lower case for search
'name': `${wsIndex + 1}: ${windowTitle} ${appName}`.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase(),
appName,
windowTitle,
window,
};
}
_getOverviewSearchResult() {
return Main.overview._overview.controls._searchController._searchResults;
}
};
const closeSelectedRegex = /^\/x!$/;
const closeAllResultsRegex = /^\/xa!$/;
@ -110,15 +114,22 @@ const moveAllToWsRegex = /^\/ma[0-9]+$/;
const WindowSearchProvider = class WindowSearchProvider {
constructor() {
this.id = `open-windows@${Me.metadata.uuid}`;
this.appInfo = Gio.AppInfo.create_from_commandline('true', _('Open Windows'), null);
this.appInfo.get_description = () => _('List of open windows');
this.appInfo.get_name = () => _('Open Windows');
this.appInfo.get_id = () => this.id;
this.appInfo.get_icon = () => Gio.icon_new_for_string('focus-windows-symbolic');
this.appInfo.should_show = () => true;
this.id = 'open-windows';
const appSystem = Shell.AppSystem.get_default();
// use arbitrary app to get complete appInfo object
let appInfo = appSystem.lookup_app('com.matjakeman.ExtensionManager.desktop')?.get_app_info();
if (!appInfo)
appInfo = appSystem.lookup_app('org.gnome.Extensions.desktop')?.get_app_info();
if (!appInfo)
appInfo = Gio.AppInfo.create_from_commandline('true', _('Open Windows'), null);
appInfo.get_description = () => _('Search open windows');
appInfo.get_name = () => _('Open Windows');
appInfo.get_id = () => this.id;
appInfo.get_icon = () => Gio.icon_new_for_string('focus-windows-symbolic');
appInfo.should_show = () => true;
this.canLaunchSearch = true;
this.appInfo = appInfo;
this.canLaunchSearch = false;
this.isRemoteProvider = false;
this.action = 0;
@ -128,7 +139,7 @@ const WindowSearchProvider = class WindowSearchProvider {
// do not modify original terms
let termsCopy = [...terms];
// search for terms without prefix
termsCopy[0] = termsCopy[0].replace(prefix, '');
termsCopy[0] = termsCopy[0].replace(PREFIX, '');
/* if (gOptions.get('searchWindowsCommands')) {
this.action = 0;
@ -167,9 +178,9 @@ const WindowSearchProvider = class WindowSearchProvider {
let m;
for (let key in candidates) {
if (opt.SEARCH_FUZZY)
m = _Util.fuzzyMatch(term, candidates[key].name);
m = Me.Util.fuzzyMatch(term, candidates[key].name);
else
m = _Util.strictMatch(term, candidates[key].name);
m = Me.Util.strictMatch(term, candidates[key].name);
if (m !== -1)
results.push({ weight: m, id: key });
@ -178,7 +189,19 @@ const WindowSearchProvider = class WindowSearchProvider {
results.sort((a, b) => a.weight > b.weight);
const currentWs = global.workspace_manager.get_active_workspace_index();
// prefer current workspace
results.sort((a, b) => (this.windows[a.id].window.get_workspace().index() !== currentWs) && (this.windows[b.id].window.get_workspace().index() === currentWs));
switch (opt.WINDOW_SEARCH_ORDER) {
case 1: // MRU - current ws first
results.sort((a, b) => (this.windows[a.id].window.get_workspace().index() !== currentWs) && (this.windows[b.id].window.get_workspace().index() === currentWs));
break;
case 2: // MRU - by workspace
results.sort((a, b) => this.windows[a.id].window.get_workspace().index() > this.windows[b.id].window.get_workspace().index());
break;
case 3: // Stable sequence - by workspace
results.sort((a, b) => this.windows[a.id].window.get_stable_sequence() > this.windows[b.id].window.get_stable_sequence());
results.sort((a, b) => this.windows[a.id].window.get_workspace().index() > this.windows[b.id].window.get_workspace().index());
break;
}
results.sort((a, b) => (_terms !== ' ') && (a.weight > 0 && b.weight === 0));
this.resultIds = results.map(item => item.id);
@ -187,7 +210,7 @@ const WindowSearchProvider = class WindowSearchProvider {
getResultMetas(resultIds, callback = null) {
const metas = resultIds.map(id => this.getResultMeta(id));
if (shellVersion >= 43)
if (Me.shellVersion >= 43)
return new Promise(resolve => resolve(metas));
else
callback(metas);
@ -210,12 +233,29 @@ const WindowSearchProvider = class WindowSearchProvider {
};
}
makeResult(window, i) {
const app = Shell.WindowTracker.get_default().get_window_app(window);
const appName = app ? app.get_name() : 'Unknown';
const windowTitle = window.get_title();
const wsIndex = window.get_workspace().index();
return {
'id': i,
// convert all accented chars to their basic form and lower case for search
'name': `${wsIndex + 1}: ${windowTitle} ${appName}`.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase(),
appName,
windowTitle,
window,
};
}
launchSearch(/* terms, timeStamp*/) {
}
activateResult(resultId/* , terms, timeStamp*/) {
const isCtrlPressed = _Util.isCtrlPressed();
const isShiftPressed = _Util.isShiftPressed();
const isCtrlPressed = Me.Util.isCtrlPressed();
const isShiftPressed = Me.Util.isShiftPressed();
this.action = 0;
this.targetWs = 0;
@ -276,15 +316,16 @@ const WindowSearchProvider = class WindowSearchProvider {
this.windows = windows = {};
global.display.get_tab_list(Meta.TabList.NORMAL, null).filter(w => w.get_workspace() !== null).map(
(v, i) => {
windows[`${i}-${v.get_id()}`] = makeResult(v, `${i}-${v.get_id()}`);
windows[`${i}-${v.get_id()}`] = this.makeResult(v, `${i}-${v.get_id()}`);
return windows[`${i}-${v.get_id()}`];
}
);
if (shellVersion >= 43)
if (Me.shellVersion >= 43)
return new Promise(resolve => resolve(this._getResultSet(terms)));
else
callback(this._getResultSet(terms));
return null;
}
@ -293,13 +334,15 @@ const WindowSearchProvider = class WindowSearchProvider {
return results;
}
getSubsearchResultSet(previousResults, terms, callback/* , cancellable*/) {
// if we return previous results, quick typers get non-actual results
callback(this._getResultSet(terms));
getSubsearchResultSet(previousResults, terms, callback) {
if (Me.shellVersion < 43) {
this.getSubsearchResultSet42(terms, callback);
return null;
}
return this.getInitialResultSet(terms);
}
/* createResultObject(resultMeta) {
const app = Shell.WindowTracker.get_default().get_window_app(resultMeta.id);
return new AppIcon(app);
}*/
getSubsearchResultSet42(terms, callback) {
callback(this._getResultSet(terms));
}
};

View file

@ -10,51 +10,68 @@
'use strict';
const { St, Graphene } = imports.gi;
const Graphene = imports.gi.Graphene;
const St = imports.gi.St;
const Main = imports.ui.main;
const Util = imports.misc.util;
const Workspace = imports.ui.workspace;
const Util = imports.misc.util;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const _Util = Me.imports.lib.util;
let _overrides;
let Me;
let opt;
let _firstRun = true;
function update(reset = false) {
opt = Me.imports.lib.settings.opt;
const moduleEnabled = opt.get('workspaceModule', true);
reset = reset || !moduleEnabled;
var WorkspaceModule = class {
constructor(me) {
Me = me;
opt = Me.opt;
// don't even touch this module if disabled
if (_firstRun && reset)
return;
_firstRun = false;
if (_overrides)
_overrides.removeAll();
if (reset) {
Workspace.WINDOW_PREVIEW_MAXIMUM_SCALE = 0.95;
_overrides = null;
opt = null;
return;
this._firstActivation = true;
this.moduleEnabled = false;
this._overrides = null;
}
_overrides = new _Util.Overrides();
cleanGlobals() {
Me = null;
opt = null;
}
_overrides.addOverride('WorkspaceBackground', Workspace.WorkspaceBackground.prototype, WorkspaceBackground);
update(reset) {
this.moduleEnabled = opt.get('workspaceModule');
const conflict = false;
// fix overlay base for Vertical Workspaces
_overrides.addOverride('WorkspaceLayout', Workspace.WorkspaceLayout.prototype, WorkspaceLayout);
}
reset = reset || !this.moduleEnabled || conflict;
// don't touch the original code if module disabled
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation)
console.debug(' WorkspaceModule - Keeping untouched');
}
_activateModule() {
if (!this._overrides)
this._overrides = new Me.Util.Overrides();
this._overrides.addOverride('WorkspaceBackground', Workspace.WorkspaceBackground.prototype, WorkspaceBackground);
// fix overlay base for Vertical Workspaces
this._overrides.addOverride('WorkspaceLayout', Workspace.WorkspaceLayout.prototype, WorkspaceLayout);
console.debug(' WorkspaceModule - Activated');
}
_disableModule() {
if (this._overrides)
this._overrides.removeAll();
this._overrides = null;
Workspace.WINDOW_PREVIEW_MAXIMUM_SCALE = 0.95;
console.debug(' WorkspaceModule - Disabled');
}
};
// workaround for upstream bug (that is not that invisible in default shell)
// smaller window cannot be scaled below 0.95 (WINDOW_PREVIEW_MAXIMUM_SCALE)

View file

@ -9,81 +9,147 @@
*/
'use strict';
const Main = imports.ui.main;
const WorkspaceSwitcherPopup = imports.ui.workspaceSwitcherPopup;
const WorkspaceAnimation = imports.ui.workspaceAnimation;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const _Util = Me.imports.lib.util;
const WorkspaceSwitcherPopup = imports.ui.workspaceSwitcherPopup;
// first reference to constant defined using const in other module returns undefined, the MonitorGroup const will remain empty and unused
let MonitorGroupDummy = WorkspaceAnimation.MonitorGroup;
MonitorGroupDummy = null;
let _origBaseDistance;
let _wsAnimationSwipeBeginId;
let _wsAnimationSwipeUpdateId;
let _wsAnimationSwipeEndId;
let _overrides;
let Me;
let opt;
let _firstRun = true;
function update(reset = false) {
opt = Me.imports.lib.settings.opt;
const moduleEnabled = opt.get('workspaceAnimationModule', true);
reset = reset || !moduleEnabled;
var WorkspaceAnimationModule = class {
constructor(me) {
Me = me;
opt = Me.opt;
// don't even touch this module if disabled
if (_firstRun && reset)
return;
// first reference to constant defined using const in other module returns undefined, the MonitorGroup const will remain empty and unused
this.dummy = WorkspaceAnimation.MonitorGroup;
_firstRun = false;
this._firstActivation = true;
this.moduleEnabled = false;
this._overrides = null;
this._origBaseDistance = null;
this._wsAnimationSwipeBeginId = 0;
this._wsAnimationSwipeUpdateId = 0;
this._wsAnimationSwipeEndId = 0;
}
if (_overrides)
_overrides.removeAll();
if (reset || !moduleEnabled) {
_connectWsAnimationSwipeTracker(true);
_overrideMonitorGroupProperty(true);
_overrides = null;
cleanGlobals() {
Me = null;
opt = null;
return;
}
if (opt.STATIC_WS_SWITCHER_BG) {
_overrides = new _Util.Overrides();
_overrideMonitorGroupProperty();
_overrides.addOverride('WorkspaceAnimationMonitorGroup', WorkspaceAnimation.MonitorGroup.prototype, MonitorGroup);
update(reset) {
this.moduleEnabled = opt.get('workspaceAnimationModule');
const conflict = false;
reset = reset || !this.moduleEnabled || conflict;
// don't touch the original code if module disabled
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation)
console.debug(' WorkspaceAnimationModule - Keeping untouched');
}
_connectWsAnimationSwipeTracker();
}
_activateModule() {
if (!this._overrides)
this._overrides = new Me.Util.Overrides();
// remove spacing between workspaces during transition to remove flashing wallpaper between workspaces with maximized windows
function _overrideMonitorGroupProperty(reset = false) {
if (!_origBaseDistance)
_origBaseDistance = Object.getOwnPropertyDescriptor(WorkspaceAnimation.MonitorGroup.prototype, 'baseDistance').get;
if (opt.STATIC_WS_SWITCHER_BG) {
this._overrideMonitorGroupProperty();
this._overrides.addOverride('WorkspaceAnimationMonitorGroup', WorkspaceAnimation.MonitorGroup.prototype, MonitorGroup);
}
let getter;
if (reset) {
if (_origBaseDistance)
getter = { get: _origBaseDistance };
} else {
getter = {
get() {
// const spacing = 100 * imports.gi.St.ThemeContext.get_for_stage(global.stage).scale_factor;
const spacing = 0;
if (global.workspace_manager.layout_rows === -1)
return this._monitor.height + spacing + (opt.PANEL_MODE ? Main.panel.height : 0); // compensation for hidden panel
else
return this._monitor.width + spacing;
},
};
this._connectWsAnimationSwipeTracker();
console.debug(' WorkspaceAnimationModule - Activated');
}
if (getter)
Object.defineProperty(WorkspaceAnimation.MonitorGroup.prototype, 'baseDistance', getter);
}
_disableModule() {
if (this._overrides)
this._overrides.removeAll();
this._overrides = null;
const reset = true;
this._connectWsAnimationSwipeTracker(reset);
this._overrideMonitorGroupProperty(reset);
console.debug(' WorkspaceAnimationModule - Disabled');
}
_overrideMonitorGroupProperty(reset = false) {
if (!this._origBaseDistance)
this._origBaseDistance = Object.getOwnPropertyDescriptor(WorkspaceAnimation.MonitorGroup.prototype, 'baseDistance').get;
let getter;
if (reset) {
if (this._origBaseDistance)
getter = { get: this._origBaseDistance };
} else {
getter = {
get() {
// const spacing = 100 * imports.gi.St.ThemeContext.get_for_stage(global.stage).scale_factor;
const spacing = 0;
if (global.workspace_manager.layout_rows === -1)
return this._monitor.height + spacing + (opt.PANEL_MODE ? Main.panel.height : 0); // compensation for hidden panel
else
return this._monitor.width + spacing;
},
};
}
if (getter)
Object.defineProperty(WorkspaceAnimation.MonitorGroup.prototype, 'baseDistance', getter);
}
_connectWsAnimationSwipeTracker(reset = false) {
if (reset) {
if (this._wsAnimationSwipeBeginId) {
Main.wm._workspaceAnimation._swipeTracker.disconnect(this._wsAnimationSwipeBeginId);
this._wsAnimationSwipeBeginId = 0;
}
if (this._wsAnimationSwipeEndId) {
Main.wm._workspaceAnimation._swipeTracker.disconnect(this._wsAnimationSwipeEndId);
this._wsAnimationSwipeEndId = 0;
}
} else if (!this._wsAnimationSwipeBeginId) {
// display ws switcher popup when gesture begins and connect progress
this._wsAnimationSwipeBeginId = Main.wm._workspaceAnimation._swipeTracker.connect('begin', () => this._connectWsAnimationProgress(true));
// we want to be sure that popup with the final ws index show up when gesture ends
this._wsAnimationSwipeEndId = Main.wm._workspaceAnimation._swipeTracker.connect('end', (tracker, duration, endProgress) => this._connectWsAnimationProgress(false, endProgress));
}
}
_connectWsAnimationProgress(connect, endProgress = null) {
if (Main.overview.visible)
return;
if (connect && !this._wsAnimationSwipeUpdateId) {
this._wsAnimationSwipeUpdateId = Main.wm._workspaceAnimation._swipeTracker.connect('update', (tracker, progress) => this._showWsSwitcherPopup(progress));
} else if (!connect && this._wsAnimationSwipeUpdateId) {
Main.wm._workspaceAnimation._swipeTracker.disconnect(this._wsAnimationSwipeUpdateId);
this._wsAnimationSwipeUpdateId = 0;
this._showWsSwitcherPopup(Math.round(endProgress));
}
}
_showWsSwitcherPopup(progress) {
if (Main.overview.visible)
return;
const wsIndex = Math.round(progress);
if (Main.wm._workspaceSwitcherPopup === null) {
Main.wm._workspaceSwitcherPopup = new WorkspaceSwitcherPopup.WorkspaceSwitcherPopup();
Main.wm._workspaceSwitcherPopup.connect('destroy', () => {
Main.wm._workspaceSwitcherPopup = null;
});
}
Main.wm._workspaceSwitcherPopup.display(wsIndex);
}
};
const MonitorGroup = {
// injection to _init()
@ -119,7 +185,9 @@ const MonitorGroup = {
// hide (scale to 0) all non-sticky windows, their clones will be animated
global.get_window_actors().forEach(actor => {
const metaWin = actor.metaWindow;
if (metaWin?.get_monitor() === this._monitor.index && !(metaWin?.wm_class === 'conky' && metaWin?.is_on_all_workspaces())) { //* && !w.is_on_all_workspaces()*/) {
if (metaWin?.get_monitor() === this._monitor.index &&
!(metaWin?.wm_class === 'conky' && metaWin?.is_on_all_workspaces()) &&
!(metaWin?.wm_class === 'Gjs' && metaWin?.is_on_all_workspaces())) { // DING extension uses window with Gjs class
// hide original window. we cannot use opacity since it also affects clones.
// scaling them to 0 works well
actor.scale_x = 0;
@ -136,49 +204,3 @@ const MonitorGroup = {
});
},
};
function _connectWsAnimationSwipeTracker(reset = false) {
if (reset) {
if (_wsAnimationSwipeBeginId) {
Main.wm._workspaceAnimation._swipeTracker.disconnect(_wsAnimationSwipeBeginId);
_wsAnimationSwipeBeginId = 0;
}
if (_wsAnimationSwipeEndId) {
Main.wm._workspaceAnimation._swipeTracker.disconnect(_wsAnimationSwipeEndId);
_wsAnimationSwipeEndId = 0;
}
} else if (!_wsAnimationSwipeBeginId) {
// display ws switcher popup when gesture begins and connect progress
_wsAnimationSwipeBeginId = Main.wm._workspaceAnimation._swipeTracker.connect('begin', () => _connectWsAnimationProgress(true));
// we want to be sure that popup with the final ws index show up when gesture ends
_wsAnimationSwipeEndId = Main.wm._workspaceAnimation._swipeTracker.connect('end', (tracker, duration, endProgress) => _connectWsAnimationProgress(false, endProgress));
}
}
function _connectWsAnimationProgress(connect, endProgress = null) {
if (Main.overview.visible)
return;
if (connect && !_wsAnimationSwipeUpdateId) {
_wsAnimationSwipeUpdateId = Main.wm._workspaceAnimation._swipeTracker.connect('update', (tracker, progress) => _showWsSwitcherPopup(progress));
} else if (!connect && _wsAnimationSwipeUpdateId) {
Main.wm._workspaceAnimation._swipeTracker.disconnect(_wsAnimationSwipeUpdateId);
_wsAnimationSwipeUpdateId = 0;
_showWsSwitcherPopup(Math.round(endProgress));
}
}
function _showWsSwitcherPopup(progress) {
if (Main.overview.visible)
return;
const wsIndex = Math.round(progress);
if (Main.wm._workspaceSwitcherPopup === null) {
Main.wm._workspaceSwitcherPopup = new WorkspaceSwitcherPopup.WorkspaceSwitcherPopup();
Main.wm._workspaceSwitcherPopup.connect('destroy', () => {
Main.wm._workspaceSwitcherPopup = null;
});
}
Main.wm._workspaceSwitcherPopup.display(wsIndex);
}

View file

@ -13,52 +13,71 @@
const Main = imports.ui.main;
const WorkspaceSwitcherPopup = imports.ui.workspaceSwitcherPopup;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const _Util = Me.imports.lib.util;
let _overrides;
let Me;
let opt;
let _firstRun = true;
function update(reset = false) {
opt = Me.imports.lib.settings.opt;
const moduleEnabled = opt.get('workspaceSwitcherPopupModule', true);
reset = reset || !moduleEnabled;
var WorkspaceSwitcherPopupModule = class {
constructor(me) {
Me = me;
opt = Me.opt;
// don't even touch this module if disabled
if (_firstRun && reset)
return;
this._firstActivation = true;
this.moduleEnabled = false;
this._overrides = null;
}
_firstRun = false;
if (_overrides)
_overrides.removeAll();
if (reset) {
_overrides = null;
cleanGlobals() {
Me = null;
opt = null;
return;
}
_overrides = new _Util.Overrides();
update(reset) {
this.moduleEnabled = opt.get('workspaceSwitcherPopupModule');
const conflict = Me.Util.getEnabledExtensions('workspace-switcher-manager').length ||
Me.Util.getEnabledExtensions('WsSwitcherPopupManager').length;
const enabled = global.settings.get_strv('enabled-extensions');
const allowWsPopupInjection = !(enabled.includes('workspace-switcher-manager@G-dH.github.com') || enabled.includes('WsSwitcherPopupManager@G-dH.github.com-dev'));
if (allowWsPopupInjection) { // 1-VERTICAL, 0-HORIZONTAL
_overrides.addOverride('WorkspaceSwitcherPopup', WorkspaceSwitcherPopup.WorkspaceSwitcherPopup.prototype, WorkspaceSwitcherPopupOverride);
if (conflict && !reset)
console.warn(`[${Me.metadata.name}] Warning: "WorkspaceSwitcherPopup" module disabled due to potential conflict with another extension`);
reset = reset || !this.moduleEnabled || conflict;
// don't touch original code if module disabled
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation)
console.debug(' WorkspaceSwitcherPopupModule - Keeping untouched');
}
}
const WorkspaceSwitcherPopupOverride = {
_activateModule() {
if (!this._overrides)
this._overrides = new Me.Util.Overrides();
this._overrides.addOverride('WorkspaceSwitcherPopup', WorkspaceSwitcherPopup.WorkspaceSwitcherPopup.prototype, WorkspaceSwitcherPopupCommon);
console.debug(' WorkspaceSwitcherPopupModule - Activated');
}
_disableModule() {
if (this._overrides)
this._overrides.removeAll();
this._overrides = null;
console.debug(' WorkspaceSwitcherPopupModule - Disabled');
}
};
const WorkspaceSwitcherPopupCommon = {
// injection to _init()
after__init() {
if (opt.ORIENTATION) { // 1-VERTICAL, 0-HORIZONTAL
this._list.vertical = true;
}
this._list.set_style('margin: 0;');
this.remove_constraint(this.get_constraints()[0]);
if (this.get_constraints()[0])
this.remove_constraint(this.get_constraints()[0]);
},
// injection to display()

View file

@ -10,56 +10,90 @@
'use strict';
const { GLib, Clutter, Graphene, Meta, Shell, St } = imports.gi;
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const AppDisplay = imports.ui.appDisplay;
const Background = imports.ui.background;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
const Background = imports.ui.background;
const OverviewControls = imports.ui.overviewControls;
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
let Me;
let opt;
const ThumbnailState = WorkspaceThumbnail.ThumbnailState;
const ControlsState = imports.ui.overviewControls.ControlsState;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
// gettext
const _ = Me.imports.lib.settings._;
const _Util = Me.imports.lib.util;
const shellVersion = _Util.shellVersion;
let _overrides;
const ControlsState = OverviewControls.ControlsState;
const WORKSPACE_CUT_SIZE = 10;
const _originalMaxThumbnailScale = WorkspaceThumbnail.MAX_THUMBNAIL_SCALE;
let opt = null;
var WorkspaceThumbnailModule = class {
constructor(me) {
Me = me;
opt = Me.opt;
function update(reset = false) {
if (_overrides)
_overrides.removeAll();
if (reset) {
if (_originalMaxThumbnailScale)
WorkspaceThumbnail.MAX_THUMBNAIL_SCALE = _originalMaxThumbnailScale;
_overrides = null;
opt = null;
return;
this._firstActivation = true;
this.moduleEnabled = false;
this._overrides = null;
}
opt = Me.imports.lib.settings.opt;
_overrides = new _Util.Overrides();
cleanGlobals() {
Me = null;
opt = null;
}
// don't limit max thumbnail scale for other clients than overview, for example AATWS.
WorkspaceThumbnail.MAX_THUMBNAIL_SCALE = 1;
update(reset) {
this.moduleEnabled = true;
const conflict = false;
_overrides.addOverride('WorkspaceThumbnail', WorkspaceThumbnail.WorkspaceThumbnail.prototype, WorkspaceThumbnailCommon);
_overrides.addOverride('ThumbnailsBoxCommon', WorkspaceThumbnail.ThumbnailsBox.prototype, ThumbnailsBoxCommon);
reset = reset || !this.moduleEnabled || conflict;
// replacing opt.ORIENTATION local constant with boxOrientation internal variable allows external customers such as the AATWS extension to control the box orientation.
Main.overview._overview.controls._thumbnailsBox._boxOrientation = opt.ORIENTATION;
}
// don't touch the original code if module disabled
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation)
console.debug(' WorkspaceThumbnailModule - Keeping untouched');
}
_activateModule() {
if (!this._overrides)
this._overrides = new Me.Util.Overrides();
if (!this._originalMaxThumbnailScale)
this._originalMaxThumbnailScale = WorkspaceThumbnail.MAX_THUMBNAIL_SCALE;
// don't limit max thumbnail scale for other clients than overview, specifically AATWS.
WorkspaceThumbnail.MAX_THUMBNAIL_SCALE = 1;
// WorkspaceThumbnail.ThumbnailsBox._MAX_THUMBNAIL_SCALE = 1;
this._overrides.addOverride('WorkspaceThumbnail', WorkspaceThumbnail.WorkspaceThumbnail.prototype, WorkspaceThumbnailCommon);
this._overrides.addOverride('ThumbnailsBoxCommon', WorkspaceThumbnail.ThumbnailsBox.prototype, ThumbnailsBoxCommon);
// replacing opt.ORIENTATION local constant with boxOrientation internal variable allows external customers such as the AATWS extension to control the box orientation.
Main.overview._overview.controls._thumbnailsBox._boxOrientation = opt.ORIENTATION;
console.debug(' WorkspaceThumbnailModule - Activated');
}
_disableModule() {
if (this._overrides)
this._overrides.removeAll();
this._overrides = null;
WorkspaceThumbnail.MAX_THUMBNAIL_SCALE = this._originalMaxThumbnailScale;
console.debug(' WorkspaceThumbnailModule - Disabled');
}
};
const WorkspaceThumbnailCommon = {
// injection to _init()
@ -70,6 +104,8 @@ const WorkspaceThumbnailCommon = {
// unless border is removed
if (opt.SHOW_WS_TMB_BG)
this.add_style_class_name('ws-tmb-labeled');
else
this.add_style_class_name('ws-tmb-transparent');
// add workspace thumbnails labels if enabled
if (opt.SHOW_WST_LABELS) { // 0 - disable
@ -77,7 +113,7 @@ const WorkspaceThumbnailCommon = {
const wsIndex = this.metaWorkspace.index();
let label = `${wsIndex + 1}`;
if (opt.SHOW_WST_LABELS === 2) { // 2 - index + workspace name
const settings = ExtensionUtils.getSettings('org.gnome.desktop.wm.preferences');
const settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.wm.preferences' });
const wsLabels = settings.get_strv('workspace-names');
if (wsLabels.length > wsIndex && wsLabels[wsIndex])
label += `: ${wsLabels[wsIndex]}`;
@ -129,7 +165,9 @@ const WorkspaceThumbnailCommon = {
}
});
this._nWindowsConId = this.metaWorkspace.connect('notify::n-windows', () => {
// wait for new information
if (this._updateLabelTimeout)
return;
// wait for new data
this._updateLabelTimeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 250, () => {
const newLabel = getLabel();
this._wsLabel.text = newLabel;
@ -168,7 +206,7 @@ const WorkspaceThumbnailCommon = {
closeButton.opacity = 255;
if (!Meta.prefs_get_dynamic_workspaces() || (Meta.prefs_get_dynamic_workspaces() && global.workspace_manager.get_n_workspaces() - 1 !== this.metaWorkspace.index())) {
// color the button red if ready to react on clicks
if (opt.CLOSE_WS_BUTTON_MODE < 3 || (opt.CLOSE_WS_BUTTON_MODE === 3 && _Util.isCtrlPressed()))
if (opt.CLOSE_WS_BUTTON_MODE < 3 || (opt.CLOSE_WS_BUTTON_MODE === 3 && Me.Util.isCtrlPressed()))
closeButton.add_style_class_name('workspace-close-button-hover');
}
});
@ -220,12 +258,6 @@ const WorkspaceThumbnailCommon = {
this._viewport.set_child_below_sibling(this._bgManager.backgroundActor, null);
this.connect('destroy', () => {
if (this._bgManager)
this._bgManager.destroy();
this._bgManager = null;
});
// full brightness of the thumbnail bg draws unnecessary attention
// there is a grey bg under the wallpaper
this._bgManager.backgroundActor.opacity = 220;
@ -256,7 +288,7 @@ const WorkspaceThumbnailCommon = {
this._lastCloseClickTime = Date.now();
return;
}
} else if (opt.CLOSE_WS_BUTTON_MODE === 3 && !_Util.isCtrlPressed()) {
} else if (opt.CLOSE_WS_BUTTON_MODE === 3 && !Me.Util.isCtrlPressed()) {
return;
}
@ -335,7 +367,7 @@ const WorkspaceThumbnailCommon = {
if (!source.app && source.shellWorkspaceLaunch)
return DND.DragMotionResult.COPY_DROP;
if (source instanceof imports.ui.appDisplay.FolderIcon)
if (source instanceof AppDisplay.FolderIcon)
return DND.DragMotionResult.COPY_DROP;
@ -369,8 +401,8 @@ const WorkspaceThumbnailCommon = {
timestamp: time,
});
return true;
} else if (source instanceof imports.ui.appDisplay.FolderIcon) {
if (shellVersion >= 44) {
} else if (source instanceof AppDisplay.FolderIcon) {
if (Me.shellVersion >= 44) {
for (let app of source.view._apps) {
// const app = Shell.AppSystem.get_default().lookup_app(id);
app.open_new_window(this.metaWorkspace.index());
@ -419,7 +451,7 @@ const ThumbnailsBoxCommon = {
if (!source.metaWindow &&
(!source.app || !source.app.can_open_new_window()) &&
(source.app || !source.shellWorkspaceLaunch) &&
!(source instanceof imports.ui.appDisplay.FolderIcon))
!(source instanceof AppDisplay.FolderIcon))
return false;
@ -448,8 +480,8 @@ const ThumbnailsBoxCommon = {
workspace: newWorkspaceIndex,
timestamp: time,
});
} else if (source instanceof imports.ui.appDisplay.FolderIcon) {
if (shellVersion >= 44) {
} else if (source instanceof AppDisplay.FolderIcon) {
if (Me.shellVersion >= 44) {
for (let app of source.view._apps) {
// const app = Shell.AppSystem.get_default().lookup_app(id);
app.open_new_window(newWorkspaceIndex);
@ -495,7 +527,7 @@ const ThumbnailsBoxCommon = {
if (!source.metaWindow &&
(!source.app || !source.app.can_open_new_window()) &&
(source.app || !source.shellWorkspaceLaunch) &&
source !== Main.xdndHandler && !(source instanceof imports.ui.appDisplay.FolderIcon))
source !== Main.xdndHandler && !(source instanceof AppDisplay.FolderIcon))
return DND.DragMotionResult.CONTINUE;
const rtl = Clutter.get_default_text_direction() === Clutter.TextDirection.RTL;
@ -551,18 +583,18 @@ const ThumbnailsBoxCommon = {
return ThumbnailsBoxHorizontal._withinWorkspace.bind(this)(...args);
},
get_preferred_custom_width(...args) {
vfunc_get_preferred_width(...args) {
if (this._boxOrientation)
return ThumbnailsBoxVertical.get_preferred_custom_width.bind(this)(...args);
return ThumbnailsBoxVertical.vfunc_get_preferred_width.bind(this)(...args);
else
return ThumbnailsBoxHorizontal.get_preferred_custom_width.bind(this)(...args);
return ThumbnailsBoxHorizontal.vfunc_get_preferred_width.bind(this)(...args);
},
get_preferred_custom_height(...args) {
vfunc_get_preferred_height(...args) {
if (this._boxOrientation)
return ThumbnailsBoxVertical.get_preferred_custom_height.bind(this)(...args);
return ThumbnailsBoxVertical.vfunc_get_preferred_height.bind(this)(...args);
else
return ThumbnailsBoxHorizontal.get_preferred_custom_height.bind(this)(...args);
return ThumbnailsBoxHorizontal.vfunc_get_preferred_height.bind(this)(...args);
},
vfunc_allocate(...args) {
@ -632,14 +664,9 @@ const ThumbnailsBoxVertical = {
return y > workspaceY1 && y <= workspaceY2;
},
// vfunc_get_preferred_width: function(forHeight) {
// override of this vfunc doesn't work for some reason (tested on Ubuntu and Fedora), it's not reachable
get_preferred_custom_width(forHeight) {
if (!this.visible)
return [0, 0];
if (forHeight === -1)
return this.get_preferred_custom_height(forHeight);
vfunc_get_preferred_width(forHeight) {
if (forHeight < 10)
return [this._porthole.width, this._porthole.width];
let themeNode = this.get_theme_node();
@ -652,19 +679,14 @@ const ThumbnailsBoxVertical = {
const avail = forHeight - totalSpacing;
let scale = (avail / nWorkspaces) / this._porthole.height;
// scale = Math.min(scale, opt.MAX_THUMBNAIL_SCALE);
const width = Math.round(this._porthole.width * scale);
return themeNode.adjust_preferred_height(width, width);
},
get_preferred_custom_height(_forWidth) {
if (!this.visible)
return [0, 0];
// Note that for getPreferredHeight/Width we cheat a bit and skip propagating
// the size request to our children because we know how big they are and know
// that the actors aren't depending on the virtual functions being called.
vfunc_get_preferred_height(forWidth) {
if (forWidth < 10)
return [0, this._porthole.height];
let themeNode = this.get_theme_node();
let spacing = themeNode.get_length('spacing');
@ -674,15 +696,14 @@ const ThumbnailsBoxVertical = {
let totalSpacing = (nWorkspaces - 3) * spacing;
const ratio = this._porthole.width / this._porthole.height;
const tmbHeight = themeNode.adjust_for_width(_forWidth) / ratio;
const tmbHeight = themeNode.adjust_for_width(forWidth) / ratio;
const naturalheight = this._thumbnails.reduce((accumulator, thumbnail/* , index*/) => {
const progress = 1 - thumbnail.collapse_fraction;
const height = tmbHeight * progress;
return accumulator + height;
}, 0);
return themeNode.adjust_preferred_width(totalSpacing, naturalheight);
return themeNode.adjust_preferred_width(totalSpacing, Math.round(naturalheight));
},
// removes extra space (extraWidth in the original function), we need the box as accurate as possible
@ -759,16 +780,11 @@ const ThumbnailsBoxVertical = {
this._dropPlaceholder.allocate_preferred_size(
...this._dropPlaceholder.get_position());
if (shellVersion >= 44) {
const laters = global.compositor.get_laters();
laters.add(Meta.LaterType.BEFORE_REDRAW, () => {
this._dropPlaceholder.hide();
});
} else {
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
this._dropPlaceholder.hide();
});
}
const laterFunc = () => this._dropPlaceholder.hide();
if (Meta.later_add)
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, laterFunc);
else
global.compositor.get_laters().add(Meta.LaterType.BEFORE_REDRAW, laterFunc);
}
let childBox = new Clutter.ActorBox();
@ -796,16 +812,11 @@ const ThumbnailsBoxVertical = {
this._dropPlaceholder.allocate(childBox);
if (shellVersion >= 44) {
const laters = global.compositor.get_laters();
laters.add(Meta.LaterType.BEFORE_REDRAW, () => {
this._dropPlaceholder.show();
});
} else {
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
this._dropPlaceholder.show();
});
}
const laterFunc = () => this._dropPlaceholder.show();
if (Meta.later_add)
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, laterFunc);
else
global.compositor.get_laters().add(Meta.LaterType.BEFORE_REDRAW, laterFunc);
y += placeholderHeight + spacing;
}
@ -925,7 +936,10 @@ const ThumbnailsBoxHorizontal = {
return x > workspaceX1 && x <= workspaceX2;
},
get_preferred_custom_height(forWidth) {
vfunc_get_preferred_height(forWidth) {
if (forWidth < 10)
return [this._porthole.height, this._porthole.height];
let themeNode = this.get_theme_node();
forWidth = themeNode.adjust_for_width(forWidth);
@ -937,18 +951,15 @@ const ThumbnailsBoxHorizontal = {
const avail = forWidth - totalSpacing;
let scale = (avail / nWorkspaces) / this._porthole.width;
// scale = Math.min(scale, opt.MAX_THUMBNAIL_SCALE);
const height = Math.round(this._porthole.height * scale);
return themeNode.adjust_preferred_height(height, height);
},
get_preferred_custom_width(_forHeight) {
// Note that for getPreferredHeight/Width we cheat a bit and skip propagating
// the size request to our children because we know how big they are and know
// that the actors aren't depending on the virtual functions being called.
if (!this.visible)
return [0, 0];
vfunc_get_preferred_width(forHeight) {
if (forHeight < 10)
return [0, this._porthole.width];
let themeNode = this.get_theme_node();
@ -959,13 +970,14 @@ const ThumbnailsBoxHorizontal = {
const ratio = this._porthole.height / this._porthole.width;
const tmbWidth = themeNode.adjust_for_height(_forHeight) / ratio;
const tmbWidth = themeNode.adjust_for_height(forHeight) / ratio;
const naturalWidth = this._thumbnails.reduce((accumulator, thumbnail) => {
const progress = 1 - thumbnail.collapse_fraction;
const width = tmbWidth * progress;
return accumulator + width;
}, 0);
return themeNode.adjust_preferred_width(totalSpacing, naturalWidth);
},
@ -1041,16 +1053,11 @@ const ThumbnailsBoxHorizontal = {
this._dropPlaceholder.allocate_preferred_size(
...this._dropPlaceholder.get_position());
if (shellVersion >= 44) {
const laters = global.compositor.get_laters();
laters.add(Meta.LaterType.BEFORE_REDRAW, () => {
this._dropPlaceholder.hide();
});
} else {
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
this._dropPlaceholder.hide();
});
}
const laterFunc = () => this._dropPlaceholder.hide();
if (Meta.later_add)
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, laterFunc);
else
global.compositor.get_laters().add(Meta.LaterType.BEFORE_REDRAW, laterFunc);
}
let childBox = new Clutter.ActorBox();
@ -1078,16 +1085,11 @@ const ThumbnailsBoxHorizontal = {
this._dropPlaceholder.allocate(childBox);
if (shellVersion >= 44) {
const laters = global.compositor.get_laters();
laters.add(Meta.LaterType.BEFORE_REDRAW, () => {
this._dropPlaceholder.show();
});
} else {
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
this._dropPlaceholder.show();
});
}
const laterFunc = () => this._dropPlaceholder.show();
if (Meta.later_add)
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, laterFunc);
else
global.compositor.get_laters().add(Meta.LaterType.BEFORE_REDRAW, laterFunc);
x += placeholderWidth + spacing;
}

View file

@ -10,62 +10,92 @@
'use strict';
const { GObject, Clutter, Meta, St } = imports.gi;
const Clutter = imports.gi.Clutter;
const GObject = imports.gi.GObject;
const Meta = imports.gi.Meta;
const St = imports.gi.St;
const Main = imports.ui.main;
const Util = imports.misc.util;
const OverviewControls = imports.ui.overviewControls;
const WorkspacesView = imports.ui.workspacesView;
// first reference to constant defined using const in other module returns undefined, the SecondaryMonitorDisplay const will remain empty and unused
const SecondaryMonitorDisplay = WorkspacesView.SecondaryMonitorDisplay;
const ControlsState = imports.ui.overviewControls.ControlsState;
const FitMode = imports.ui.workspacesView.FitMode;
const SIDE_CONTROLS_ANIMATION_TIME = imports.ui.overview.ANIMATION_TIME;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const SEARCH_WINDOWS_PREFIX = Me.imports.lib.windowSearchProvider.prefix;
const SEARCH_RECENT_FILES_PREFIX = Me.imports.lib.recentFilesSearchProvider.prefix;
const _Util = Me.imports.lib.util;
let _overrides;
const Util = imports.misc.util;
let Me;
let opt;
const ControlsState = OverviewControls.ControlsState;
const FitMode = WorkspacesView.FitMode;
function update(reset = false) {
opt = Me.imports.lib.settings.opt;
opt.DESKTOP_CUBE_ENABLED = Main.extensionManager._enabledExtensions.includes('desktop-cube@schneegans.github.com');
const cubeSupported = opt.DESKTOP_CUBE_ENABLED && !opt.ORIENTATION && !opt.OVERVIEW_MODE;
var WorkspacesViewModule = class {
constructor(me) {
// first reference to constant defined using const in other module returns undefined, the SecondaryMonitorDisplay const will remain empty and unused
this.dummy = WorkspacesView.SecondaryMonitorDisplay;
// if desktop cube extension is enabled while V-Shell is loaded, removeAll() would override its code
if (_overrides && !cubeSupported) {
_overrides.removeAll();
global.workspace_manager.override_workspace_layout(Meta.DisplayCorner.TOPLEFT, false, 1, -1);
Me = me;
opt = Me.opt;
this._firstActivation = true;
this.moduleEnabled = false;
this._overrides = null;
}
if (reset) {
_overrides = null;
cleanGlobals() {
Me = null;
opt = null;
return;
}
update(reset) {
this.moduleEnabled = true;
const conflict = false;
_overrides = new _Util.Overrides();
reset = reset || !this.moduleEnabled || conflict;
if (!cubeSupported)
_overrides.addOverride('WorkspacesView', WorkspacesView.WorkspacesView.prototype, WorkspacesViewCommon);
_overrides.addOverride('WorkspacesDisplay', WorkspacesView.WorkspacesDisplay.prototype, WorkspacesDisplay);
_overrides.addOverride('ExtraWorkspaceView', WorkspacesView.ExtraWorkspaceView.prototype, ExtraWorkspaceView);
if (opt.ORIENTATION) {
// switch internal workspace orientation in GS
global.workspace_manager.override_workspace_layout(Meta.DisplayCorner.TOPLEFT, false, -1, 1);
_overrides.addOverride('SecondaryMonitorDisplay', WorkspacesView.SecondaryMonitorDisplay.prototype, SecondaryMonitorDisplayVertical);
} else {
_overrides.addOverride('SecondaryMonitorDisplay', WorkspacesView.SecondaryMonitorDisplay.prototype, SecondaryMonitorDisplayHorizontal);
// don't touch the original code if module disabled
if (reset && !this._firstActivation) {
this._disableModule();
} else if (!reset) {
this._firstActivation = false;
this._activateModule();
}
if (reset && this._firstActivation)
console.debug(' WorkspacesViewModule - Keeping untouched');
}
}
_activateModule() {
if (!this._overrides)
this._overrides = new Me.Util.Overrides();
const desktopCubeEnabled = Me.Util.getEnabledExtensions('desktop-cube@schneegans.github.com').length;
const desktopCubeConflict = desktopCubeEnabled && !opt.ORIENTATION && !opt.OVERVIEW_MODE;
if (!desktopCubeConflict)
this._overrides.addOverride('WorkspacesView', WorkspacesView.WorkspacesView.prototype, WorkspacesViewCommon);
this._overrides.addOverride('WorkspacesDisplay', WorkspacesView.WorkspacesDisplay.prototype, WorkspacesDisplayCommon);
this._overrides.addOverride('ExtraWorkspaceView', WorkspacesView.ExtraWorkspaceView.prototype, ExtraWorkspaceViewCommon);
this._overrides.addOverride('SecondaryMonitorDisplayCommon', WorkspacesView.SecondaryMonitorDisplay.prototype, SecondaryMonitorDisplayCommon);
if (opt.ORIENTATION) {
// switch internal workspace orientation in GS
global.workspace_manager.override_workspace_layout(Meta.DisplayCorner.TOPLEFT, false, -1, 1);
this._overrides.addOverride('SecondaryMonitorDisplay', WorkspacesView.SecondaryMonitorDisplay.prototype, SecondaryMonitorDisplayVertical);
} else {
global.workspace_manager.override_workspace_layout(Meta.DisplayCorner.TOPLEFT, false, 1, -1);
this._overrides.addOverride('SecondaryMonitorDisplay', WorkspacesView.SecondaryMonitorDisplay.prototype, SecondaryMonitorDisplayHorizontal);
}
console.debug(' WorkspacesViewModule - Activated');
}
_disableModule() {
global.workspace_manager.override_workspace_layout(Meta.DisplayCorner.TOPLEFT, false, 1, -1);
if (this._overrides)
this._overrides.removeAll();
this._overrides = null;
console.debug(' WorkspacesViewModule - Disabled');
}
};
const WorkspacesViewCommon = {
_getFirstFitSingleWorkspaceBox(box, spacing, vertical) {
@ -91,7 +121,6 @@ const WorkspacesViewCommon = {
}
const fitSingleBox = new Clutter.ActorBox({ x1, y1 });
fitSingleBox.set_size(workspaceWidth, workspaceHeight);
return fitSingleBox;
@ -143,21 +172,7 @@ const WorkspacesViewCommon = {
},
_updateVisibility() {
// replaced in _updateWorkspacesState
/* let workspaceManager = global.workspace_manager;
let active = workspaceManager.get_active_workspace_index();
const fitMode = this._fitModeAdjustment.value;
const singleFitMode = fitMode === FitMode.SINGLE;
for (let w = 0; w < this._workspaces.length; w++) {
let workspace = this._workspaces[w];
if (this._animating || this._gestureActive || !singleFitMode)
workspace.show();
else
workspace.visible = Math.abs(w - active) <= opt.NUMBER_OF_VISIBLE_NEIGHBORS;
}*/
// visibility handles _updateWorkspacesState()
},
// disable scaling and hide inactive workspaces
@ -175,27 +190,21 @@ const WorkspacesViewCommon = {
const primaryMonitor = Main.layoutManager.primaryMonitor.index;
// define the transition values here to save time in each ws
let scaleX, scaleY;
if (opt.ORIENTATION) { // vertical 1 / horizontal 0
scaleX = 1;
scaleY = 0.1;
} else {
scaleX = 0.1;
scaleY = 1;
}
const wsScrollProgress = adj.value % 1;
const secondaryMonitor = this._monitorIndex !== global.display.get_primary_monitor();
const blockSecondaryAppGrid = opt.OVERVIEW_MODE && currentState > 1;
// Hide inactive workspaces
this._workspaces.forEach((w, index) => {
if (!(blockSecondaryAppGrid && secondaryMonitor))
w.stateAdjustment.value = workspaceMode;
const distanceToCurrentWorkspace = Math.abs(adj.value - index);
let distance = adj.value - index;
const distanceToCurrentWorkspace = Math.abs(distance);
const scaleProgress = 1 - Math.clamp(distanceToCurrentWorkspace, 0, 1);
// const scale = Util.lerp(0.94, 1, scaleProgress);
// w.set_scale(scale, scale);
// if we disable workspaces that we can't or don't need to see, transition animations will be noticeably smoother
// only the current ws needs to be visible during overview transition animations
@ -210,22 +219,28 @@ const WorkspacesViewCommon = {
// after transition from APP_GRID to WINDOW_PICKER state,
// adjacent workspaces are hidden and we need them to show up
// make them visible during animation can impact smoothness of the animation
// so we show them after the animation finished, scaling animation will make impression that they move in from outside the monitor
// so we show them after the animation finished, move them to their position from outside of the monitor
if (!w.visible && distanceToCurrentWorkspace === 1 && initialState === ControlsState.APP_GRID && currentState === ControlsState.WINDOW_PICKER) {
w.scale_x = scaleX;
w.scale_y = scaleY;
w.visible = true;
const directionNext = distance > 0;
if (!opt.ORIENTATION) {
const width = w.width * 0.6 * opt.WS_PREVIEW_SCALE;
w.translation_x = directionNext ? -width : width;
}
if (opt.ORIENTATION) {
const height = w.height * 0.6 * opt.WS_PREVIEW_SCALE;
w.translation_y = directionNext ? -height : height;
}
w.opacity = 10;
w.get_parent().set_child_below_sibling(w, null);
w.ease({
duration: 100,
scale_x: 1,
scale_y: 1,
duration: 300,
translation_x: 0,
translation_y: 0,
opacity: 255,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
});
} else if (!w.visible && distanceToCurrentWorkspace <= opt.NUMBER_OF_VISIBLE_NEIGHBORS && currentState === ControlsState.WINDOW_PICKER) {
w.set({
scale_x: 1,
scale_y: 1,
});
}
// force ws preview bg corner radiuses where GS doesn't do it
@ -238,9 +253,40 @@ const WorkspacesViewCommon = {
w._background.opacity = 0;
});
},
exposeWindows(workspaceIndex = null, callback) {
let adjustments = [];
if (workspaceIndex === null) {
this._workspaces.forEach(ws => {
adjustments.push(ws._background._stateAdjustment);
});
} else {
adjustments.push(this._workspaces[workspaceIndex]._background._stateAdjustment);
}
adjustments.forEach(adj => {
if (adj.value === 0) {
adj.value = 0;
adj.ease(1, {
duration: 200,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
opt.WORKSPACE_MODE = 1;
if (callback)
callback();
},
});
}
});
},
};
const SecondaryMonitorDisplayCommon = {
exposeWindows(...args) {
this._workspacesView.exposeWindows(...args);
},
};
// SecondaryMonitorDisplay Vertical
const SecondaryMonitorDisplayVertical = {
_getThumbnailParamsForState(state) {
@ -270,24 +316,6 @@ const SecondaryMonitorDisplayVertical = {
return { opacity, scale, translationX };
},
_getThumbnailsWidth(box, spacing) {
if (opt.SEC_WS_TMB_HIDDEN)
return 0;
const [width, height] = box.get_size();
const { expandFraction } = this._thumbnails;
const [, thumbnailsWidth] = this._thumbnails.get_preferred_custom_width(height - 2 * spacing);
let scaledWidth;
if (opt.SEC_WS_PREVIEW_SHIFT && !opt.PANEL_DISABLED)
scaledWidth = ((height - Main.panel.height) * opt.SEC_MAX_THUMBNAIL_SCALE) * (width / height);
else
scaledWidth = width * opt.SEC_MAX_THUMBNAIL_SCALE;
return Math.min(
thumbnailsWidth * expandFraction,
Math.round(scaledWidth));
},
_getWorkspacesBoxForState(state, box, padding, thumbnailsWidth, spacing) {
// const { ControlsState } = OverviewControls;
const workspaceBox = box.copy();
@ -303,7 +331,7 @@ const SecondaryMonitorDisplayVertical = {
break;
yShift = 0;
if (opt.SEC_WS_PREVIEW_SHIFT && !opt.PANEL_DISABLED) {
if (opt.SEC_WS_PREVIEW_SHIFT && Main.panel.visible) {
if (opt.PANEL_POSITION_TOP)
yShift = Main.panel.height;
else
@ -341,26 +369,40 @@ const SecondaryMonitorDisplayVertical = {
const spacing = themeNode.get_length('spacing') * expandFraction;
const padding = Math.round(0.1 * height);
let thumbnailsWidth = this._getThumbnailsWidth(contentBox, spacing);
let [, thumbnailsHeight] = this._thumbnails.get_preferred_custom_height(thumbnailsWidth);
thumbnailsHeight = Math.min(thumbnailsHeight, height - 2 * spacing);
let thumbnailsWidth = 0;
let thumbnailsHeight = 0;
this._thumbnails.visible = !opt.SEC_WS_TMB_HIDDEN;
if (this._thumbnails.visible) {
const reduceBoxHeight = opt.SEC_WS_PREVIEW_SHIFT && Main.panel.visible ? Main.panel.height : 0;
thumbnailsWidth = width * opt.SEC_MAX_THUMBNAIL_SCALE;
let totalTmbSpacing;
[totalTmbSpacing, thumbnailsHeight] = this._thumbnails.get_preferred_height(thumbnailsWidth);
thumbnailsHeight = Math.round(thumbnailsHeight + totalTmbSpacing);
const thumbnailsHeightMax = height - spacing - reduceBoxHeight;
if (thumbnailsHeight > thumbnailsHeightMax) {
thumbnailsHeight = thumbnailsHeightMax;
thumbnailsWidth = Math.round(this._thumbnails.get_preferred_width(thumbnailsHeight)[1]);
}
let wsTmbX;
if (opt.SEC_WS_TMB_LEFT) { // left
wsTmbX = Math.round(spacing / 4);
wsTmbX = spacing / 2;
this._thumbnails._positionLeft = true;
} else {
wsTmbX = Math.round(width - spacing / 4 - thumbnailsWidth);
wsTmbX = width - spacing / 2 - thumbnailsWidth;
this._thumbnails._positionLeft = false;
}
const childBox = new Clutter.ActorBox();
const availSpace = height - thumbnailsHeight - 2 * spacing;
const availSpace = height - thumbnailsHeight;
let wsTmbY = availSpace / 2;
wsTmbY -= opt.SEC_WS_TMB_POSITION_ADJUSTMENT * wsTmbY - spacing;
wsTmbY -= opt.SEC_WS_TMB_POSITION_ADJUSTMENT * wsTmbY;
wsTmbY += opt.SEC_WS_PREVIEW_SHIFT && Main.panel.visible ? Main.panel.height : 0;
childBox.set_origin(Math.round(wsTmbX), Math.round(wsTmbY));
childBox.set_size(thumbnailsWidth, thumbnailsHeight);
@ -390,22 +432,14 @@ const SecondaryMonitorDisplayVertical = {
if (opt.OVERVIEW_MODE2)
this.set_child_above_sibling(this._thumbnails, null);
const visible = !opt.SEC_WS_TMB_HIDDEN;
if (this._thumbnails.visible === visible)
return;
this._thumbnails.show();
this._thumbnails.visible = visible;
this._updateThumbnailParams();
this._thumbnails.ease_property('expand-fraction', visible ? 1 : 0, {
duration: SIDE_CONTROLS_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
this._thumbnails.visible = visible;
this._thumbnails._indicator.visible = visible;
},
});
},
_updateThumbnailParams() {
@ -417,7 +451,6 @@ const SecondaryMonitorDisplayVertical = {
if (!this._thumbnails._thumbnails.length)
this._thumbnails._createThumbnails();
const { initialState, finalState, progress } =
this._overviewAdjustment.getStateTransitionParams();
@ -474,7 +507,6 @@ const SecondaryMonitorDisplayVertical = {
},
};
// SecondaryMonitorDisplay Horizontal
const SecondaryMonitorDisplayHorizontal = {
_getThumbnailParamsForState(state) {
// const { ControlsState } = OverviewControls;
@ -520,7 +552,7 @@ const SecondaryMonitorDisplayHorizontal = {
break;
yShift = 0;
if (opt.SEC_WS_PREVIEW_SHIFT && !opt.PANEL_DISABLED) {
if (opt.SEC_WS_PREVIEW_SHIFT && Main.panel.visible) {
if (opt.PANEL_POSITION_TOP)
yShift = Main.panel.height;
else
@ -571,24 +603,36 @@ const SecondaryMonitorDisplayHorizontal = {
const spacing = themeNode.get_length('spacing') * expandFraction;
const padding = Math.round(0.1 * height);
let thumbnailsHeight = this._getThumbnailsHeight(contentBox);
let [, thumbnailsWidth] = this._thumbnails.get_preferred_custom_width(thumbnailsHeight);
thumbnailsWidth = Math.min(thumbnailsWidth, width - 2 * spacing);
let thumbnailsWidth = 0;
let thumbnailsHeight = 0;
this._thumbnails.visible = !opt.SEC_WS_TMB_HIDDEN;
if (this._thumbnails.visible) {
const reservedHeight = opt.SEC_WS_PREVIEW_SHIFT && Main.panel.visible ? Main.panel.height : 0;
thumbnailsHeight = height * opt.SEC_MAX_THUMBNAIL_SCALE;
let totalTmbSpacing;
[totalTmbSpacing, thumbnailsWidth] = this._thumbnails.get_preferred_width(thumbnailsHeight);
thumbnailsWidth = Math.round(thumbnailsWidth + totalTmbSpacing);
const thumbnailsWidthMax = width - spacing;
if (thumbnailsWidth > thumbnailsWidthMax) {
thumbnailsWidth = thumbnailsWidthMax;
thumbnailsHeight = Math.round(this._thumbnails.get_preferred_height(thumbnailsWidth)[1]);
}
let wsTmbY;
if (opt.SEC_WS_TMB_TOP)
wsTmbY = Math.round(spacing / 4);
wsTmbY = spacing / 2 + reservedHeight;
else
wsTmbY = Math.round(height - spacing / 4 - thumbnailsHeight);
wsTmbY = height - spacing / 2 - thumbnailsHeight;
const childBox = new Clutter.ActorBox();
const availSpace = width - thumbnailsWidth - 2 * spacing;
const availSpace = width - thumbnailsWidth;
let wsTmbX = availSpace / 2;
wsTmbX -= opt.SEC_WS_TMB_POSITION_ADJUSTMENT * wsTmbX - spacing;
wsTmbX -= opt.SEC_WS_TMB_POSITION_ADJUSTMENT * wsTmbX;
childBox.set_origin(Math.round(wsTmbX), Math.round(wsTmbY));
childBox.set_size(thumbnailsWidth, thumbnailsHeight);
@ -625,7 +669,6 @@ const SecondaryMonitorDisplayHorizontal = {
if (!this._thumbnails._thumbnails.length)
this._thumbnails._createThumbnails();
const { initialState, finalState, progress } =
this._overviewAdjustment.getStateTransitionParams();
@ -682,7 +725,7 @@ const SecondaryMonitorDisplayHorizontal = {
},
};
const ExtraWorkspaceView = {
const ExtraWorkspaceViewCommon = {
_updateWorkspaceMode() {
const overviewState = this._overviewAdjustment.value;
@ -701,9 +744,23 @@ const ExtraWorkspaceView = {
if (!opt.SHOW_WS_PREVIEW_BG && this._workspace._background.opacity)
this._workspace._background.opacity = 0;
},
exposeWindows() {
const adjustment = this._workspace._background._stateAdjustment;
if (adjustment.value === 0) {
adjustment.value = 0;
adjustment.ease(1, {
duration: 200,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
opt.WORKSPACE_MODE = 1;
},
});
}
},
};
const WorkspacesDisplay = {
const WorkspacesDisplayCommon = {
_updateWorkspacesViews() {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].destroy();
@ -761,8 +818,8 @@ const WorkspacesDisplay = {
return Clutter.EVENT_STOP;
}
if (_Util.isShiftPressed()) {
let direction = _Util.getScrollDirection(event);
if (Me.Util.isShiftPressed()) {
let direction = Me.Util.getScrollDirection(event);
if (direction === null || (Date.now() - this._lastScrollTime) < 150)
return Clutter.EVENT_STOP;
this._lastScrollTime = Date.now();
@ -775,11 +832,11 @@ const WorkspacesDisplay = {
else
direction = 0;
if (direction) {
_Util.reorderWorkspace(direction);
Me.Util.reorderWorkspace(direction);
// make all workspaces on primary monitor visible for case the new position is hidden
Main.overview._overview._controls._workspacesDisplay._workspacesViews[0]._workspaces.forEach(w => {
const primaryMonitorIndex = global.display.get_primary_monitor();
Main.overview._overview._controls._workspacesDisplay._workspacesViews[primaryMonitorIndex]._workspaces.forEach(w => {
w.visible = true;
});
return Clutter.EVENT_STOP;
@ -806,7 +863,7 @@ const WorkspacesDisplay = {
switch (symbol) {
case Clutter.KEY_Return:
case Clutter.KEY_KP_Enter:
if (_Util.isCtrlPressed()) {
if (Me.Util.isCtrlPressed()) {
Main.ctrlAltTabManager._items.forEach(i => {
if (i.sortGroup === 1 && i.name === 'Dash')
Main.ctrlAltTabManager.focusGroup(i);
@ -836,17 +893,17 @@ const WorkspacesDisplay = {
which = workspaceManager.n_workspaces - 1;
break;
case Clutter.KEY_space:
if (_Util.isCtrlPressed() && _Util.isShiftPressed()) {
_Util.openPreferences();
} else if (_Util.isAltPressed()) {
if (Me.Util.isCtrlPressed() && Me.Util.isShiftPressed()) {
Me.Util.activateSearchProvider(Me.ESP_PREFIX);
} else if (Me.Util.isAltPressed()) {
Main.ctrlAltTabManager._items.forEach(i => {
if (i.sortGroup === 1 && i.name === 'Dash')
Main.ctrlAltTabManager.focusGroup(i);
});
} else if (opt.RECENT_FILES_SEARCH_PROVIDER_ENABLED && _Util.isCtrlPressed()) {
_Util.activateSearchProvider(SEARCH_RECENT_FILES_PREFIX);
} else if (opt.WINDOW_SEARCH_PROVIDER_ENABLED) {
_Util.activateSearchProvider(SEARCH_WINDOWS_PREFIX);
} else if (opt.get('recentFilesSearchProviderModule') && Me.Util.isCtrlPressed()) {
Me.Util.activateSearchProvider(Me.RFSP_PREFIX);
} else if (opt.get('windowSearchProviderModule')) {
Me.Util.activateSearchProvider(Me.WSP_PREFIX);
}
return Clutter.EVENT_STOP;
@ -867,16 +924,18 @@ const WorkspacesDisplay = {
});
} else if (opt.OVERVIEW_MODE && !opt.WORKSPACE_MODE && state === 1) {
// expose windows for OVERVIEW_MODE 1
const adjustment = this._workspacesViews[0]._workspaces[global.workspace_manager.get_active_workspace().index()]._background._stateAdjustment;
opt.WORKSPACE_MODE = 1;
_Util.exposeWindows(adjustment, true);
const wsIndex = global.workspace_manager.get_active_workspace().index();
// after expose animation activate keyboard for window selection
const callback = Me.Util.activateKeyboardForWorkspaceView;
this._workspacesViews.forEach(
view => {
view.exposeWindows(wsIndex, callback);
}
);
} else {
if (state === 2)
return Clutter.EVENT_PROPAGATE;
Main.ctrlAltTabManager._items.forEach(i => {
if (i.sortGroup === 1 && i.name === 'Windows')
Main.ctrlAltTabManager.focusGroup(i);
});
Me.Util.activateKeyboardForWorkspaceView();
}
return Clutter.EVENT_STOP;
@ -895,14 +954,14 @@ const WorkspacesDisplay = {
// Otherwise it is a workspace index
ws = workspaceManager.get_workspace_by_index(which);
if (_Util.isShiftPressed()) {
if (Me.Util.isShiftPressed()) {
let direction;
if (which === Meta.MotionDirection.UP || which === Meta.MotionDirection.LEFT)
direction = -1;
else if (which === Meta.MotionDirection.DOWN || which === Meta.MotionDirection.RIGHT)
direction = 1;
if (direction)
_Util.reorderWorkspace(direction);
Me.Util.reorderWorkspace(direction);
// make all workspaces on primary monitor visible for case the new position is hidden
Main.overview._overview._controls._workspacesDisplay._workspacesViews[0]._workspaces.forEach(w => {
w.visible = true;

View file

@ -7,8 +7,16 @@
"43",
"44"
],
"session-modes": [
"user",
"unlock-dialog"
],
"url": "https://github.com/G-dH/vertical-workspaces",
"donations": {
"buymeacoffee": "georgdh"
},
"gettext-domain": "vertical-workspaces",
"settings-schema": "org.gnome.shell.extensions.vertical-workspaces",
"version": 28
"version-name": "44.10"
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -14,7 +14,7 @@
<default>350</default>
</key>
<key type="i" name="ws-preview-scale">
<default>100</default>
<default>95</default>
</key>
<key type="i" name="secondary-ws-preview-scale">
<default>100</default>
@ -23,7 +23,7 @@
<default>false</default>
</key>
<key type="i" name="dash-position">
<default>0</default>
<default>2</default>
</key>
<key type="i" name="dash-position-adjust">
<default>0</default>
@ -37,6 +37,9 @@
<key type="i" name="dash-show-recent-files-icon">
<default>1</default>
</key>
<key type="i" name="dash-show-extensions-icon">
<default>1</default>
</key>
<key type="i" name="wst-position-adjust">
<default>0</default>
</key>
@ -77,10 +80,19 @@
<default>48</default>
</key>
<key type="i" name="dash-bg-opacity">
<default>80</default>
<default>85</default>
</key>
<key type="i" name="dash-bg-color">
<default>0</default>
</key>
<key type="i" name="dash-bg-radius">
<default>17</default>
<default>18</default>
</key>
<key type="b" name="dash-bg-gs3-style">
<default>true</default>
</key>
<key type="i" name="running-dot-style">
<default>1</default>
</key>
<key type="b" name="enable-page-shortcuts">
<default>false</default>
@ -104,7 +116,10 @@
<default>40</default>
</key>
<key type="i" name="overview-bg-brightness">
<default>95</default>
<default>60</default>
</key>
<key type="i" name="search-bg-brightness">
<default>30</default>
</key>
<key type="b" name="smooth-blur-transitions">
<default>false</default>
@ -113,7 +128,7 @@
<default>4</default>
</key>
<key type="i" name="search-view-animation">
<default>4</default>
<default>0</default>
</key>
<key type="i" name="workspace-animation">
<default>1</default>
@ -124,14 +139,11 @@
<key type="i" name="animation-speed-factor">
<default>100</default>
</key>
<key type="b" name="fix-ubuntu-dock">
<default>true</default>
</key>
<key type="i" name="win-preview-icon-size">
<default>1</default>
</key>
<key type="b" name="always-show-win-titles">
<default>true</default>
<key type="i" name="win-title-position">
<default>0</default>
</key>
<key type="i" name="startup-state">
<default>2</default>
@ -157,6 +169,9 @@
<key type="i" name="app-grid-order">
<default>0</default>
</key>
<key type="i" name="app-folder-order">
<default>0</default>
</key>
<key type="i" name="app-grid-content">
<default>2</default>
</key>
@ -176,7 +191,7 @@
<default>true</default>
</key>
<key type="i" name="app-grid-names">
<default>0</default>
<default>1</default>
</key>
<key type="i" name="app-grid-folder-icon-grid">
<default>3</default>
@ -196,14 +211,17 @@
<key type="i" name="dash-icon-scroll">
<default>1</default>
</key>
<key type="b" name="dash-isolate-workspaces">
<default>false</default>
</key>
<key type="i" name="search-windows-icon-scroll">
<default>1</default>
</key>
<key type="b" name="search-windows-enable">
<default>true</default>
</key>
<key type="b" name="search-recent-files-enable">
<default>true</default>
<key type="i" name="search-windows-order">
<default>1</default>
</key>
<key type="b" name="search-fuzzy">
<default>false</default>
@ -229,6 +247,12 @@
<key type="i" name="ws-sw-popup-mode">
<default>1</default>
</key>
<key type="b" name="ws-switcher-wraparound">
<default>false</default>
</key>
<key type="b" name="ws-switcher-ignore-last">
<default>false</default>
</key>
<key type="i" name="favorites-notify">
<default>1</default>
</key>
@ -242,10 +266,10 @@
<default>1</default>
</key>
<key type="i" name="hot-corner-position">
<default>0</default>
<default>6</default>
</key>
<key type="b" name="hot-corner-fullscreen">
<default>false</default>
<default>true</default>
</key>
<key type="b" name="hot-corner-ripples">
<default>true</default>
@ -253,19 +277,37 @@
<key type="b" name="always-activate-selected-window">
<default>false</default>
</key>
<key type="b" name="window-icon-click-search">
<key type="i" name="win-preview-sec-mouse-btn-action">
<default>2</default>
</key>
<key type="i" name="win-preview-mid-mouse-btn-action">
<default>0</default>
</key>
<key type="b" name="win-preview-show-close-button">
<default>true</default>
</key>
<key type="i" name="window-icon-click-action">
<default>1</default>
</key>
<key type="i" name="overlay-key-primary">
<default>1</default>
</key>
<key type="i" name="overlay-key-secondary">
<default>1</default>
</key>
<key type="b" name="workspace-thumbnails-module">
<key type="i" name="overview-esc-behavior">
<default>0</default>
</key>
<key type="b" name="new-window-focus-fix">
<default>false</default>
</key>
<key type="b" name="app-grid-performance">
<default>true</default>
</key>
<key type="i" name="window-thumbnail-scale">
<default>15</default>
</key>
<key type="b" name="workspace-switcher-popup-module">
<default>true</default>
</key>
@ -284,9 +326,15 @@
<key type="b" name="win-attention-handler-module">
<default>true</default>
</key>
<key type="b" name="window-thumbnail-module">
<default>true</default>
</key>
<key type="b" name="swipe-tracker-module">
<default>true</default>
</key>
<key type="b" name="search-controller-module">
<default>true</default>
</key>
<key type="b" name="search-module">
<default>true</default>
</key>
@ -314,6 +362,15 @@
<key type="b" name="app-favorites-module">
<default>true</default>
</key>
<key type="b" name="window-search-provider-module">
<default>true</default>
</key>
<key type="b" name="recent-files-search-provider-module">
<default>true</default>
</key>
<key type="b" name="extensions-search-provider-module">
<default>true</default>
</key>
<key type="b" name="aaa-loading-profile">
<default>false</default>
@ -323,28 +380,28 @@
<default>""</default>
</key>
<key type="a{ss}" name="profile-data-1">
<default>{'workspaceThumbnailsPosition': '1', 'wsMaxSpacing': '350', 'wsPreviewScale': '95', 'secWsPreviewScale': '100', 'secWsPreviewShift': 'false', 'wsThumbnailsFull': 'false', 'secWsThumbnailsPosition': '2', 'dashPosition': '3', 'dashPositionAdjust': '0', 'wsTmbPositionAdjust': '-80', 'showWsTmbLabels': '3', 'showWsTmbLabelsOnHover': 'false', 'closeWsButtonMode': '2', 'secWsTmbPositionAdjust': '-80', 'dashMaxIconSize': '64', 'dashShowWindowsIcon': '2', 'dashShowRecentFilesIcon': '2', 'centerDashToWs': 'false', 'showAppsIconPosition': '1', 'wsThumbnailScale': '13', 'wsThumbnailScaleAppGrid': '0', 'secWsThumbnailScale': '13', 'showSearchEntry': 'true', 'centerSearch': 'true', 'centerAppGrid': 'true', 'appGridPageWidthScale': '100', 'dashBgOpacity': '80', 'dashBgRadius': '17', 'enablePageShortcuts': 'true', 'showWsSwitcherBg': 'true', 'showWsPreviewBg': 'false', 'showBgInOverview': 'true', 'overviewBgBrightness': '30', 'overviewBgBlurSigma': '0', 'appGridBgBlurSigma': '0', 'smoothBlurTransitions': 'false', 'appGridAnimation': '4', 'searchViewAnimation': '4', 'workspaceAnimation': '1', 'animationSpeedFactor': '100', 'fixUbuntuDock': 'true', 'winPreviewIconSize': '1', 'alwaysShowWinTitles': 'false', 'startupState': '0', 'overviewMode': '0', 'workspaceSwitcherAnimation': '1', 'searchIconSize': '96', 'searchViewScale': '104', 'appGridIconSize': '-1', 'appGridColumns': '0', 'appGridRows': '0', 'appGridFolderIconSize': '-1', 'appGridFolderColumns': '4', 'appGridFolderRows': '3', 'appGridSpacing': '12', 'appGridFolderIconGrid': '2', 'appGridContent': '2', 'appGridIncompletePages': 'false', 'appGridOrder': '0', 'appGridNamesMode': '0', 'appGridActivePreview': 'false', 'appGridFolderCenter': 'false', 'searchWindowsEnable': 'true', 'searchRecentFilesEnable': 'true', 'searchFuzzy': 'false', 'searchMaxResultsRows': '5', 'dashShowWindowsBeforeActivation': '1', 'panelVisibility': '0', 'panelPosition': '0', 'windowAttentionMode': '0', 'wsSwPopupHPosition': '50', 'wsSwPopupVPosition': '50', 'wsSwPopupMode': '1', 'favoritesNotify': '1', 'notificationPosition': '1', 'hotCornerAction': '1', 'hotCornerPosition': '0', 'hotCornerFullscreen': 'true', 'hotCornerRipples': 'true', 'alwaysActivateSelectedWindow': 'false', 'workspaceThumbnailsModule': 'true', 'workspaceSwitcherPopupModule': 'true', 'workspaceAnimationModule': 'true', 'workspaceModule': 'true', 'windowManagerModule': 'true', 'windowPreviewModule': 'true', 'winAttentionHandlerModule': 'true', 'swipeTrackerModule': 'true', 'searchModule': 'true', 'panelModule': 'true', 'messageTrayModule': 'true', 'layoutModule': 'true', 'dashModule': 'true', 'appFavoritesModule': 'true', 'appDisplayModule': 'true'}</default>
<default>{'workspaceThumbnailsPosition': '1', 'wsMaxSpacing': '350', 'wsPreviewScale': '95', 'secWsPreviewScale': '100', 'secWsPreviewShift': 'false', 'wsThumbnailsFull': 'false', 'secWsThumbnailsPosition': '2', 'dashPosition': '3', 'dashPositionAdjust': '0', 'wsTmbPositionAdjust': '-80', 'showWsTmbLabels': '3', 'showWsTmbLabelsOnHover': 'false', 'closeWsButtonMode': '2', 'secWsTmbPositionAdjust': '-80', 'dashMaxIconSize': '64', 'dashShowWindowsIcon': '2', 'dashShowRecentFilesIcon': '2', 'dashShowExtensionsIcon': '2', 'centerDashToWs': 'false', 'showAppsIconPosition': '1', 'wsThumbnailScale': '13', 'wsThumbnailScaleAppGrid': '13', 'secWsThumbnailScale': '13', 'showSearchEntry': 'true', 'centerSearch': 'true', 'centerAppGrid': 'true', 'dashBgOpacity': '80', 'dashBgColor': '0', 'dashBgRadius': '0', 'dashBgGS3Style': 'true', 'runningDotStyle': '1', 'enablePageShortcuts': 'false', 'showWsSwitcherBg': 'true', 'showWsPreviewBg': 'false', 'wsPreviewBgRadius': '30', 'showBgInOverview': 'true', 'overviewBgBrightness': '30', 'searchBgBrightness': '30', 'overviewBgBlurSigma': '0', 'appGridBgBlurSigma': '40', 'smoothBlurTransitions': 'false', 'appGridAnimation': '4', 'searchViewAnimation': '0', 'workspaceAnimation': '1', 'animationSpeedFactor': '100', 'winPreviewIconSize': '1', 'winTitlePosition': '0', 'startupState': '0', 'overviewMode': '0', 'workspaceSwitcherAnimation': '1', 'searchIconSize': '96', 'searchViewScale': '104', 'appGridIconSize': '-1', 'appGridColumns': '0', 'appGridRows': '0', 'appGridFolderIconSize': '-1', 'appGridFolderColumns': '0', 'appGridFolderRows': '0', 'appGridFolderIconGrid': '2', 'appGridContent': '2', 'appGridIncompletePages': 'false', 'appGridOrder': '0', 'appFolderOrder': '0', 'appGridNamesMode': '1', 'appGridActivePreview': 'false', 'appGridFolderCenter': 'false', 'appGridPageWidthScale': '100', 'appGridSpacing': '12', 'searchWindowsOrder': '1', 'searchFuzzy': 'false', 'searchMaxResultsRows': '5', 'dashShowWindowsBeforeActivation': '1', 'dashIconScroll': '1', 'dashIsolateWorkspaces': 'false', 'searchWindowsIconScroll': '1', 'panelVisibility': '0', 'panelPosition': '0', 'windowAttentionMode': '0', 'wsSwPopupHPosition': '50', 'wsSwPopupVPosition': '95', 'wsSwPopupMode': '1', 'wsSwitcherWraparound': 'false', 'wsSwitcherIgnoreLast': 'false', 'favoritesNotify': '1', 'notificationPosition': '1', 'osdPosition': '6', 'hotCornerAction': '1', 'hotCornerPosition': '0', 'hotCornerFullscreen': 'true', 'hotCornerRipples': 'true', 'alwaysActivateSelectedWindow': 'false', 'winPreviewSecBtnAction': '3', 'winPreviewMidBtnAction': '1', 'winPreviewShowCloseButton': 'true', 'windowIconClickAction': '1', 'overlayKeyPrimary': '1', 'overlayKeySecondary': '1', 'overviewEscBehavior': '0', 'newWindowFocusFix': 'false', 'appGridPerformance': 'true', 'windowThumbnailScale': '20', 'workspaceSwitcherPopupModule': 'true', 'workspaceAnimationModule': 'true', 'workspaceModule': 'true', 'windowManagerModule': 'true', 'windowPreviewModule': 'true', 'windowAttentionHandlerModule': 'true', 'windowThumbnailModule': 'true', 'swipeTrackerModule': 'true', 'searchControllerModule': 'true', 'searchModule': 'true', 'panelModule': 'true', 'overlayKeyModule': 'true', 'osdWindowModule': 'true', 'messageTrayModule': 'true', 'layoutModule': 'true', 'dashModule': 'true', 'appFavoritesModule': 'true', 'appDisplayModule': 'true', 'windowSearchProviderModule': 'true', 'extensionsSearchProviderModule': 'true'}</default>
</key>
<key type="s" name="profile-name-2">
<default>""</default>
</key>
<key type="a{ss}" name="profile-data-2">
<default>{'workspaceThumbnailsPosition': '5', 'wsMaxSpacing': '80', 'wsPreviewScale': '100', 'secWsPreviewScale': '100', 'secWsPreviewShift': 'false', 'wsThumbnailsFull': 'false', 'secWsThumbnailsPosition': '2', 'dashPosition': '2', 'dashPositionAdjust': '0', 'wsTmbPositionAdjust': '0', 'showWsTmbLabels': '0', 'showWsTmbLabelsOnHover': 'false', 'closeWsButtonMode': '2', 'secWsTmbPositionAdjust': '0', 'dashMaxIconSize': '64', 'dashShowWindowsIcon': '2', 'dashShowRecentFilesIcon': '2', 'centerDashToWs': 'false', 'showAppsIconPosition': '1', 'wsThumbnailScale': '5', 'wsThumbnailScaleAppGrid': '15', 'secWsThumbnailScale': '13', 'showSearchEntry': 'true', 'centerSearch': 'true', 'centerAppGrid': 'true', 'appGridPageWidthScale': '80', 'dashBgOpacity': '100', 'dashBgRadius': '17', 'enablePageShortcuts': 'true', 'showWsSwitcherBg': 'true', 'showWsPreviewBg': 'true', 'showBgInOverview': 'false', 'overviewBgBrightness': '30', 'overviewBgBlurSigma': '0', 'appGridBgBlurSigma': '0', 'smoothBlurTransitions': 'false', 'appGridAnimation': '4', 'searchViewAnimation': '4', 'workspaceAnimation': '1', 'animationSpeedFactor': '100', 'fixUbuntuDock': 'true', 'winPreviewIconSize': '0', 'alwaysShowWinTitles': 'false', 'startupState': '0', 'overviewMode': '0', 'workspaceSwitcherAnimation': '0', 'searchIconSize': '96', 'searchViewScale': '104', 'appGridIconSize': '-1', 'appGridColumns': '0', 'appGridRows': '0', 'appGridFolderIconSize': '-1', 'appGridFolderColumns': '3', 'appGridFolderRows': '3', 'appGridSpacing': '12', 'appGridFolderIconGrid': '2', 'appGridContent': '2', 'appGridIncompletePages': 'false', 'appGridOrder': '0', 'appGridNamesMode': '0', 'appGridActivePreview': 'false', 'appGridFolderCenter': 'false', 'searchWindowsEnable': 'true', 'searchRecentFilesEnable': 'true', 'searchFuzzy': 'false', 'searchMaxResultsRows': '5', 'dashShowWindowsBeforeActivation': '1', 'panelVisibility': '0', 'panelPosition': '0', 'windowAttentionMode': '0', 'wsSwPopupHPosition': '50', 'wsSwPopupVPosition': '95', 'wsSwPopupMode': '1', 'favoritesNotify': '1', 'notificationPosition': '1', 'hotCornerAction': '1', 'hotCornerPosition': '6', 'hotCornerFullscreen': 'true', 'hotCornerRipples': 'false', 'alwaysActivateSelectedWindow': 'false', 'workspaceThumbnailsModule': 'true', 'workspaceSwitcherPopupModule': 'true', 'workspaceAnimationModule': 'true', 'workspaceModule': 'true', 'windowManagerModule': 'true', 'windowPreviewModule': 'true', 'winAttentionHandlerModule': 'true', 'swipeTrackerModule': 'true', 'searchModule': 'true', 'panelModule': 'true', 'messageTrayModule': 'true', 'layoutModule': 'true', 'dashModule': 'true', 'appFavoritesModule': 'true', 'appDisplayModule': 'true'}</default>
<default>{'workspaceThumbnailsPosition': '5', 'wsMaxSpacing': '80', 'wsPreviewScale': '100', 'secWsPreviewScale': '100', 'secWsPreviewShift': 'false', 'wsThumbnailsFull': 'false', 'secWsThumbnailsPosition': '2', 'dashPosition': '2', 'dashPositionAdjust': '0', 'wsTmbPositionAdjust': '0', 'showWsTmbLabels': '0', 'showWsTmbLabelsOnHover': 'false', 'closeWsButtonMode': '2', 'secWsTmbPositionAdjust': '0', 'dashMaxIconSize': '64', 'dashShowWindowsIcon': '2', 'dashShowRecentFilesIcon': '2', 'dashShowExtensionsIcon': '2', 'centerDashToWs': 'false', 'showAppsIconPosition': '1', 'wsThumbnailScale': '5', 'wsThumbnailScaleAppGrid': '15', 'secWsThumbnailScale': '5', 'showSearchEntry': 'true', 'centerSearch': 'true', 'centerAppGrid': 'true', 'dashBgOpacity': '20', 'dashBgColor': '1', 'dashBgRadius': '0', 'dashBgGS3Style': 'false', 'runningDotStyle': '1', 'enablePageShortcuts': 'true', 'showWsSwitcherBg': 'false', 'showWsPreviewBg': 'true', 'wsPreviewBgRadius': '30', 'showBgInOverview': 'true', 'overviewBgBrightness': '50', 'searchBgBrightness': '30', 'overviewBgBlurSigma': '50', 'appGridBgBlurSigma': '40', 'smoothBlurTransitions': 'false', 'appGridAnimation': '4', 'searchViewAnimation': '4', 'workspaceAnimation': '1', 'animationSpeedFactor': '100', 'winPreviewIconSize': '1', 'winTitlePosition': '0', 'startupState': '0', 'overviewMode': '0', 'workspaceSwitcherAnimation': '0', 'searchIconSize': '96', 'searchViewScale': '104', 'appGridIconSize': '-1', 'appGridColumns': '0', 'appGridRows': '0', 'appGridFolderIconSize': '-1', 'appGridFolderColumns': '0', 'appGridFolderRows': '0', 'appGridFolderIconGrid': '2', 'appGridContent': '2', 'appGridIncompletePages': 'false', 'appGridOrder': '0', 'appFolderOrder': '0', 'appGridNamesMode': '1', 'appGridActivePreview': 'false', 'appGridFolderCenter': 'true', 'appGridPageWidthScale': '90', 'appGridSpacing': '12', 'searchWindowsOrder': '1', 'searchFuzzy': 'false', 'searchMaxResultsRows': '5', 'dashShowWindowsBeforeActivation': '1', 'dashIconScroll': '1', 'dashIsolateWorkspaces': 'false', 'searchWindowsIconScroll': '1', 'panelVisibility': '0', 'panelPosition': '0', 'windowAttentionMode': '0', 'wsSwPopupHPosition': '50', 'wsSwPopupVPosition': '95', 'wsSwPopupMode': '1', 'wsSwitcherWraparound': 'false', 'wsSwitcherIgnoreLast': 'false', 'favoritesNotify': '1', 'notificationPosition': '1', 'osdPosition': '6', 'hotCornerAction': '1', 'hotCornerPosition': '6', 'hotCornerFullscreen': 'true', 'hotCornerRipples': 'false', 'alwaysActivateSelectedWindow': 'false', 'winPreviewSecBtnAction': '2', 'winPreviewMidBtnAction': '1', 'winPreviewShowCloseButton': 'true', 'windowIconClickAction': '1', 'overlayKeyPrimary': '1', 'overlayKeySecondary': '1', 'overviewEscBehavior': '0', 'newWindowFocusFix': 'false', 'appGridPerformance': 'true', 'windowThumbnailScale': '20', 'workspaceSwitcherPopupModule': 'true', 'workspaceAnimationModule': 'true', 'workspaceModule': 'true', 'windowManagerModule': 'true', 'windowPreviewModule': 'true', 'windowAttentionHandlerModule': 'true', 'windowThumbnailModule': 'true', 'swipeTrackerModule': 'true', 'searchControllerModule': 'true', 'searchModule': 'true', 'panelModule': 'true', 'overlayKeyModule': 'true', 'osdWindowModule': 'true', 'messageTrayModule': 'true', 'layoutModule': 'true', 'dashModule': 'true', 'appFavoritesModule': 'true', 'appDisplayModule': 'true', 'windowSearchProviderModule': 'true', 'extensionsSearchProviderModule': 'true'}</default>
</key>
<key type="s" name="profile-name-3">
<default>""</default>
</key>
<key type="a{ss}" name="profile-data-3">
<default>{'workspaceThumbnailsPosition': '0', 'wsMaxSpacing': '350', 'wsPreviewScale': '95', 'secWsPreviewScale': '100', 'secWsPreviewShift': 'false', 'wsThumbnailsFull': 'false', 'secWsThumbnailsPosition': '2', 'dashPosition': '0', 'dashPositionAdjust': '-100', 'wsTmbPositionAdjust': '-100', 'showWsTmbLabels': '3', 'showWsTmbLabelsOnHover': 'false', 'closeWsButtonMode': '2', 'secWsTmbPositionAdjust': '0', 'dashMaxIconSize': '48', 'dashShowWindowsIcon': '1', 'dashShowRecentFilesIcon': '1', 'centerDashToWs': 'false', 'showAppsIconPosition': '0', 'wsThumbnailScale': '13', 'wsThumbnailScaleAppGrid': '0', 'secWsThumbnailScale': '13', 'showSearchEntry': 'false', 'centerSearch': 'true', 'centerAppGrid': 'false', 'appGridPageWidthScale': '90', 'dashBgOpacity': '85', 'dashBgRadius': '17', 'enablePageShortcuts': 'true', 'showWsSwitcherBg': 'true', 'showWsPreviewBg': 'false', 'showBgInOverview': 'true', 'overviewBgBrightness': '95', 'overviewBgBlurSigma': '0', 'appGridBgBlurSigma': '80', 'smoothBlurTransitions': 'false', 'appGridAnimation': '4', 'searchViewAnimation': '4', 'workspaceAnimation': '1', 'animationSpeedFactor': '100', 'fixUbuntuDock': 'true', 'winPreviewIconSize': '1', 'alwaysShowWinTitles': 'true', 'startupState': '2', 'overviewMode': '1', 'workspaceSwitcherAnimation': '1', 'searchIconSize': '96', 'searchViewScale': '104', 'appGridIconSize': '-1', 'appGridColumns': '0', 'appGridRows': '0', 'appGridFolderIconSize': '-1', 'appGridFolderColumns': '0', 'appGridFolderRows': '0', 'appGridSpacing': '12', 'appGridFolderIconGrid': '3', 'appGridContent': '0', 'appGridIncompletePages': 'false', 'appGridOrder': '0', 'appGridNamesMode': '0', 'appGridActivePreview': 'true', 'appGridFolderCenter': 'false', 'searchWindowsEnable': 'true', 'searchRecentFilesEnable': 'true', 'searchFuzzy': 'false', 'searchMaxResultsRows': '5', 'dashShowWindowsBeforeActivation': '1', 'panelVisibility': '0', 'panelPosition': '0', 'windowAttentionMode': '2', 'wsSwPopupHPosition': '50', 'wsSwPopupVPosition': '95', 'wsSwPopupMode': '1', 'favoritesNotify': '0', 'notificationPosition': '2', 'hotCornerAction': '1', 'hotCornerPosition': '1', 'hotCornerFullscreen': 'true', 'hotCornerRipples': 'true', 'alwaysActivateSelectedWindow': 'false', 'workspaceThumbnailsModule': 'true', 'workspaceSwitcherPopupModule': 'true', 'workspaceAnimationModule': 'true', 'workspaceModule': 'true', 'windowManagerModule': 'true', 'windowPreviewModule': 'true', 'winAttentionHandlerModule': 'true', 'swipeTrackerModule': 'true', 'searchModule': 'true', 'panelModule': 'true', 'messageTrayModule': 'true', 'layoutModule': 'true', 'dashModule': 'true', 'appFavoritesModule': 'true', 'appDisplayModule': 'true'}</default>
<default>{'workspaceThumbnailsPosition': '0', 'wsMaxSpacing': '350', 'wsPreviewScale': '95', 'secWsPreviewScale': '100', 'secWsPreviewShift': 'false', 'wsThumbnailsFull': 'false', 'secWsThumbnailsPosition': '2', 'dashPosition': '0', 'dashPositionAdjust': '-100', 'wsTmbPositionAdjust': '-100', 'showWsTmbLabels': '3', 'showWsTmbLabelsOnHover': 'false', 'closeWsButtonMode': '2', 'secWsTmbPositionAdjust': '0', 'dashMaxIconSize': '48', 'dashShowWindowsIcon': '1', 'dashShowRecentFilesIcon': '1', 'dashShowExtensionsIcon': '1', 'centerDashToWs': 'false', 'showAppsIconPosition': '0', 'wsThumbnailScale': '13', 'wsThumbnailScaleAppGrid': '13', 'secWsThumbnailScale': '13', 'showSearchEntry': 'false', 'centerSearch': 'true', 'centerAppGrid': 'false', 'dashBgOpacity': '20', 'dashBgColor': '1', 'dashBgRadius': '0', 'dashBgGS3Style': 'false', 'runningDotStyle': '1', 'enablePageShortcuts': 'true', 'showWsSwitcherBg': 'false', 'showWsPreviewBg': 'true', 'wsPreviewBgRadius': '30', 'showBgInOverview': 'true', 'overviewBgBrightness': '60', 'searchBgBrightness': '30', 'overviewBgBlurSigma': '30', 'appGridBgBlurSigma': '80', 'smoothBlurTransitions': 'false', 'appGridAnimation': '4', 'searchViewAnimation': '4', 'workspaceAnimation': '1', 'animationSpeedFactor': '100', 'winPreviewIconSize': '1', 'winTitlePosition': '0', 'startupState': '2', 'overviewMode': '1', 'workspaceSwitcherAnimation': '1', 'searchIconSize': '96', 'searchViewScale': '104', 'appGridIconSize': '-1', 'appGridColumns': '0', 'appGridRows': '0', 'appGridFolderIconSize': '-1', 'appGridFolderColumns': '0', 'appGridFolderRows': '0', 'appGridFolderIconGrid': '3', 'appGridContent': '0', 'appGridIncompletePages': 'false', 'appGridOrder': '0', 'appFolderOrder': '0', 'appGridNamesMode': '1', 'appGridActivePreview': 'true', 'appGridFolderCenter': 'false', 'appGridPageWidthScale': '90', 'appGridSpacing': '12', 'searchWindowsOrder': '1', 'searchFuzzy': 'false', 'searchMaxResultsRows': '5', 'dashShowWindowsBeforeActivation': '1', 'dashIconScroll': '1', 'dashIsolateWorkspaces': 'false', 'searchWindowsIconScroll': '1', 'panelVisibility': '0', 'panelPosition': '0', 'windowAttentionMode': '0', 'wsSwPopupHPosition': '50', 'wsSwPopupVPosition': '95', 'wsSwPopupMode': '1', 'wsSwitcherWraparound': 'false', 'wsSwitcherIgnoreLast': 'false', 'favoritesNotify': '0', 'notificationPosition': '2', 'osdPosition': '6', 'hotCornerAction': '1', 'hotCornerPosition': '1', 'hotCornerFullscreen': 'true', 'hotCornerRipples': 'true', 'alwaysActivateSelectedWindow': 'false', 'winPreviewSecBtnAction': '2', 'winPreviewMidBtnAction': '1', 'winPreviewShowCloseButton': 'true', 'windowIconClickAction': '1', 'overlayKeyPrimary': '1', 'overlayKeySecondary': '1', 'overviewEscBehavior': '0', 'newWindowFocusFix': 'false', 'appGridPerformance': 'true', 'windowThumbnailScale': '20', 'workspaceSwitcherPopupModule': 'true', 'workspaceAnimationModule': 'true', 'workspaceModule': 'true', 'windowManagerModule': 'true', 'windowPreviewModule': 'true', 'windowAttentionHandlerModule': 'true', 'windowThumbnailModule': 'true', 'swipeTrackerModule': 'true', 'searchControllerModule': 'true', 'searchModule': 'true', 'panelModule': 'true', 'overlayKeyModule': 'true', 'osdWindowModule': 'true', 'messageTrayModule': 'true', 'layoutModule': 'true', 'dashModule': 'true', 'appFavoritesModule': 'true', 'appDisplayModule': 'true', 'windowSearchProviderModule': 'true', 'extensionsSearchProviderModule': 'true'}</default>
</key>
<key type="s" name="profile-name-4">
<default>""</default>
</key>
<key type="a{ss}" name="profile-data-4">
<default>{'workspaceThumbnailsPosition': '6', 'wsMaxSpacing': '65', 'wsPreviewScale': '95', 'secWsPreviewScale': '100', 'secWsPreviewShift': 'false', 'wsThumbnailsFull': 'false', 'secWsThumbnailsPosition': '2', 'dashPosition': '2', 'dashPositionAdjust': '0', 'wsTmbPositionAdjust': '0', 'showWsTmbLabels': '3', 'showWsTmbLabelsOnHover': 'false', 'closeWsButtonMode': '2', 'secWsTmbPositionAdjust': '0', 'dashMaxIconSize': '48', 'dashShowWindowsIcon': '1', 'dashShowRecentFilesIcon': '1', 'centerDashToWs': 'false', 'showAppsIconPosition': '1', 'wsThumbnailScale': '10', 'wsThumbnailScaleAppGrid': '0', 'secWsThumbnailScale': '10', 'showSearchEntry': 'false', 'centerSearch': 'true', 'centerAppGrid': 'false', 'appGridPageWidthScale': '90', 'dashBgOpacity': '85', 'dashBgRadius': '17', 'enablePageShortcuts': 'true', 'showWsSwitcherBg': 'true', 'showWsPreviewBg': 'true', 'showBgInOverview': 'true', 'overviewBgBrightness': '100', 'overviewBgBlurSigma': '80', 'appGridBgBlurSigma': '80', 'smoothBlurTransitions': 'false', 'appGridAnimation': '4', 'searchViewAnimation': '4', 'workspaceAnimation': '1', 'animationSpeedFactor': '100', 'fixUbuntuDock': 'true', 'winPreviewIconSize': '2', 'alwaysShowWinTitles': 'true', 'startupState': '2', 'overviewMode': '2', 'workspaceSwitcherAnimation': '1', 'searchIconSize': '96', 'searchViewScale': '104', 'appGridIconSize': '-1', 'appGridColumns': '0', 'appGridRows': '0', 'appGridFolderIconSize': '-1', 'appGridFolderColumns': '0', 'appGridFolderRows': '0', 'appGridSpacing': '12', 'appGridFolderIconGrid': '3', 'appGridContent': '0', 'appGridIncompletePages': 'false', 'appGridOrder': '0', 'appGridNamesMode': '0', 'appGridActivePreview': 'true', 'appGridFolderCenter': 'false', 'searchWindowsEnable': 'true', 'searchRecentFilesEnable': 'true', 'searchFuzzy': 'false', 'searchMaxResultsRows': '5', 'dashShowWindowsBeforeActivation': '1', 'panelVisibility': '0', 'panelPosition': '0', 'windowAttentionMode': '2', 'wsSwPopupHPosition': '50', 'wsSwPopupVPosition': '95', 'wsSwPopupMode': '1', 'favoritesNotify': '0', 'notificationPosition': '1', 'hotCornerAction': '1', 'hotCornerPosition': '6', 'hotCornerFullscreen': 'true', 'hotCornerRipples': 'false', 'alwaysActivateSelectedWindow': 'false', 'workspaceThumbnailsModule': 'true', 'workspaceSwitcherPopupModule': 'true', 'workspaceAnimationModule': 'true', 'workspaceModule': 'true', 'windowManagerModule': 'true', 'windowPreviewModule': 'true', 'winAttentionHandlerModule': 'true', 'swipeTrackerModule': 'true', 'searchModule': 'true', 'panelModule': 'true', 'messageTrayModule': 'true', 'layoutModule': 'true', 'dashModule': 'true', 'appFavoritesModule': 'true', 'appDisplayModule': 'true'}</default>
<default>{'workspaceThumbnailsPosition': '6', 'wsMaxSpacing': '65', 'wsPreviewScale': '95', 'secWsPreviewScale': '100', 'secWsPreviewShift': 'false', 'wsThumbnailsFull': 'false', 'secWsThumbnailsPosition': '2', 'dashPosition': '2', 'dashPositionAdjust': '0', 'wsTmbPositionAdjust': '0', 'showWsTmbLabels': '3', 'showWsTmbLabelsOnHover': 'false', 'closeWsButtonMode': '2', 'secWsTmbPositionAdjust': '0', 'dashMaxIconSize': '48', 'dashShowWindowsIcon': '1', 'dashShowRecentFilesIcon': '1', 'dashShowExtensionsIcon': '1', 'centerDashToWs': 'false', 'showAppsIconPosition': '1', 'wsThumbnailScale': '10', 'wsThumbnailScaleAppGrid': '10', 'secWsThumbnailScale': '10', 'showSearchEntry': 'false', 'centerSearch': 'true', 'centerAppGrid': 'false', 'dashBgOpacity': '100', 'dashBgColor': '0', 'dashBgRadius': '0', 'dashBgGS3Style': 'false', 'runningDotStyle': '1', 'enablePageShortcuts': 'true', 'showWsSwitcherBg': 'true', 'showWsPreviewBg': 'true', 'wsPreviewBgRadius': '30', 'showBgInOverview': 'true', 'overviewBgBrightness': '60', 'searchBgBrightness': '30', 'overviewBgBlurSigma': '80', 'appGridBgBlurSigma': '80', 'smoothBlurTransitions': 'false', 'appGridAnimation': '4', 'searchViewAnimation': '4', 'workspaceAnimation': '1', 'animationSpeedFactor': '100', 'winPreviewIconSize': '1', 'winTitlePosition': '0', 'startupState': '2', 'overviewMode': '2', 'workspaceSwitcherAnimation': '1', 'searchIconSize': '96', 'searchViewScale': '104', 'appGridIconSize': '-1', 'appGridColumns': '0', 'appGridRows': '0', 'appGridFolderIconSize': '-1', 'appGridFolderColumns': '0', 'appGridFolderRows': '0', 'appGridFolderIconGrid': '3', 'appGridContent': '0', 'appGridIncompletePages': 'false', 'appGridOrder': '0', 'appFolderOrder': '0', 'appGridNamesMode': '1', 'appGridActivePreview': 'true', 'appGridFolderCenter': 'false', 'appGridPageWidthScale': '90', 'appGridSpacing': '5', 'searchWindowsOrder': '1', 'searchFuzzy': 'false', 'searchMaxResultsRows': '5', 'dashShowWindowsBeforeActivation': '1', 'dashIconScroll': '1', 'dashIsolateWorkspaces': 'false', 'searchWindowsIconScroll': '1', 'panelVisibility': '0', 'panelPosition': '0', 'windowAttentionMode': '0', 'wsSwPopupHPosition': '50', 'wsSwPopupVPosition': '95', 'wsSwPopupMode': '1', 'wsSwitcherWraparound': 'false', 'wsSwitcherIgnoreLast': 'false', 'favoritesNotify': '0', 'notificationPosition': '1', 'osdPosition': '6', 'hotCornerAction': '1', 'hotCornerPosition': '6', 'hotCornerFullscreen': 'true', 'hotCornerRipples': 'false', 'alwaysActivateSelectedWindow': 'false', 'winPreviewSecBtnAction': '2', 'winPreviewMidBtnAction': '1', 'winPreviewShowCloseButton': 'true', 'windowIconClickAction': '1', 'overlayKeyPrimary': '1', 'overlayKeySecondary': '1', 'overviewEscBehavior': '0', 'newWindowFocusFix': 'false', 'appGridPerformance': 'true', 'windowThumbnailScale': '20', 'workspaceSwitcherPopupModule': 'true', 'workspaceAnimationModule': 'true', 'workspaceModule': 'true', 'windowManagerModule': 'true', 'windowPreviewModule': 'true', 'windowAttentionHandlerModule': 'true', 'windowThumbnailModule': 'true', 'swipeTrackerModule': 'true', 'searchControllerModule': 'true', 'searchModule': 'true', 'panelModule': 'true', 'overlayKeyModule': 'true', 'osdWindowModule': 'true', 'messageTrayModule': 'true', 'layoutModule': 'true', 'dashModule': 'true', 'appFavoritesModule': 'true', 'appDisplayModule': 'true', 'windowSearchProviderModule': 'true', 'extensionsSearchProviderModule': 'true'}</default>
</key>
</schema>

View file

@ -5,15 +5,18 @@
/* General dash */
#dash.vertical {
margin-right: 0px;
margin-left: 0px;
padding: 0px 0;
margin: 0px;
padding: 0px;
}
#dash.vertical .app-well-app,
#dash.vertical .show-apps {
padding-right: 8px;
padding-left: 8px;
/* left/right padding exceeds dash bg by 6px to
cover spacing between dash and the edge of the screen
so the icons will be selectable even at the edge
this spacing must be accounted for in overview allocate() */
padding-right: 16px;
padding-left: 16px;
/*spacing between icons*/
padding-top: 1px;
padding-bottom: 1px;
@ -35,48 +38,81 @@
#dash.vertical .app-well-app-running-dot {
margin: 4px 0px;
}
#dash.vertical .app-well-app-running-dot-custom {
margin: 4px 0px;
width: 2px;
height: 16px;
}
#dash.vertical .dash-background {
margin: 0;
margin: 0px;
}
#dash.vertical-left .dash-background {
#dash.vertical-gs3-left .dash-background {
border-radius: 0 18px 18px 0;
border-left: 0px;
padding: 8px 12px 8px 4px;
margin-left: 0;
}
#dash.vertical-right .dash-background {
#dash.vertical-gs3-right .dash-background {
border-radius: 18px 0 0 18px;
border-right: 0px;
padding: 8px 4px 8px 12px;
margin-right: 0;
}
/* default horizontal dash */
.v-shell-dash-background {
padding: 6px;
#dash.vertical-gs3-left {
margin-right: 6px;
margin-left: 0px;
padding: 0px;
}
.app-well-app {
margin-left: 1px;
margin-right: 1px;
#dash.vertical-gs3-right {
margin-right: 0px;
margin-left: 6px;
padding: 0px;
}
#dash.vertical-gs3-left .app-well-app,
#dash.vertical-gs3-left .show-apps,
#dash.vertical-gs3-right .app-well-app,
#dash.vertical-gs3-right .show-apps {
/* left/right padding exceeds dash bg by 6px to
cover spacing between dash and the edge of the screen
so the icons will be selectable even at the edge
this spacing must be accounted for in overview allocate() */
padding-right: 9px;
padding-left: 9px;
}
.dash-background-light {
background-color: rgb(200, 200, 200);
border-color: rgba(150, 150, 150, 0.4);
}
.dash-background-reduced {
padding: 10px;
}
.app-well-app-running-dot {
margin-bottom: 6px;
margin-bottom: 12px;
}
.app-well-app-running-dot-custom {
margin-bottom: 12px;
width: 16px;
height: 2px;
}
/* add shadow to the app grid app label to be readable if it overlaps light icon below */
.overview-icon-with-label {
text-shadow: 1px 1px 3px rgba(33, 33, 33, 1);
.overview-icon-with-label, .folder-name-label {
text-shadow: 1px 1px 3px rgba(33, 33, 33, 0.5);
}
/*adjustment for the vertical ws switcher indicator popup*/
/* adjustment for the vertical ws switcher indicator popup*/
.ws-switcher-indicator {
padding: 3px;
margin: 5px;
@ -87,11 +123,11 @@
margin: 3px;
}
/*ws thumbnails captions*/
/* ws thumbnails captions */
.ws-tmb-label {
padding: 2px;
color: rgb(255, 255, 255);
background-color: rgba(10,10,10,0.8);
background-color: rgba(40,40,40,0.8);
text-align: center;
}
@ -103,7 +139,12 @@
border: 0px;
}
/*app grid page indicatos*/
.ws-tmb-transparent {
border: 0px;
background-color: rgba(200, 200, 200, 0.2);
}
/* app grid page indicatos */
.page-indicator-icon {
margin: 10px 10px 10px 10px;
}
@ -128,32 +169,47 @@
border-radius: 0px 0px 100px 100px;
}
.search-entry, .search-entry-om2 {
padding: 5px;
/*
.search-entry{
background-color: rgba(200, 200, 200, 0.1);
color: white;
border-color: rgba(160, 160, 160, 0.4);
}
.search-entry:hover,
.search-entry:focus {
background-color: rgba(200, 200, 200, 0.2);
}*/
.search-entry-om2 {
border: 5px;
color: white;
background-color: rgba(40, 40, 40, 1);
}
.search-section-content {
background-color: rgba(20, 20, 20, 0.8);
color: white;
.search-entry-om2:hover,
.search-entry-om2:focus {
background-color: rgba(50, 50, 50, 1);
}
/* for static ws mode */
.search-section-content-om2 {
background-color: rgba(20, 20, 20, 0.95);
color: white;
border-radius: 20px;
border: 1px, rgb(40, 40, 40);
padding-top: 12px;
/*.search-section-content-bg,*/
.search-section-content-bg-om2 {
border-radius: 26px;
border: 1px, rgb(60, 60, 60);
padding-top: 15px;
}
.search-section-content-bg-om2 {
background-color: rgb(40, 40, 40);
}
.search-section-content {
background-color: rgba(200, 200, 200, 0.1);
}
/* "no results" / "searching..." text*/
.search-statustext {
background-color: rgba(23,23,23, 0.95);
.search-statustext, .search-statustext-om2 {
background-color: rgba(200, 200, 200, 0.1);
color: white;
margin-top: 50px;
padding: 30px;
@ -161,17 +217,18 @@
text-shadow: 0px 0px 5px rgb(23, 23, 23);
}
.transparent-panel {
.search-statustext-om2 {
background-color: rgb(40, 40, 40);
border: 1px rgba(200, 200, 200, 0.1);
}
#panel:overview, .transparent-panel {
background-color: transparent;
}
/*reduce spacing between app icons in search results*/
/* reduce spacing between app icons in search results */
.grid-search-results {
spacing: 2px;
}
.panel {
text-shadow: 1px 1px 3px rgba(33, 33, 33, 1);
spacing: 4px;
}
/* hide vertical scroll bar, it's distracting in the search results */
@ -222,3 +279,29 @@ StButton#vhandle {
.osd-window {
margin: 4em;
}
.app-folder .overview-icon,
.edit-folder-button,
.folder-name-entry {
background-color: rgba(200, 200, 200, 0.08);
}
.app-folder-dialog-vshell {
background-color: rgba(200, 200, 200, 0.08);
}
.app-folder-dialog {
border-color: rgba(160, 160, 160, 0.3);
}
.edit-folder-button:hover,
.app-folder:hover .overview-icon,
.app-folder:focus .overview-icon {
background-color: rgba(200, 200, 200, 0.15);
}
/* reduce quick menu buttons height in GS44 */
/*.quick-toggle,
.quick-menu-toggle {
min-height: 42px;
}*/