Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4345703c2e | ||
|
|
a911447375 | ||
|
|
2d3307c657 | ||
|
|
d59bc0b7f0 | ||
|
|
cb8c2eb27f | ||
|
|
0544729bba | ||
|
|
017c410a6a | ||
|
|
f2c73329be | ||
|
|
ce644be96f | ||
|
|
e75a1a15ac | ||
|
|
1155170c7c | ||
|
|
6d8f54a20b | ||
|
|
93a2e7bdba | ||
|
|
3bfaf6f88a | ||
|
|
37baccd9fc | ||
|
|
9365725246 | ||
|
|
f1257c4523 | ||
|
|
f0865f039e | ||
|
|
4955c20669 | ||
|
|
cf007dd472 | ||
|
|
701b14ecbf | ||
|
|
18674b2e35 |
30
.gitignore
vendored
30
.gitignore
vendored
@@ -1,29 +1,7 @@
|
|||||||
ABOUT-NLS
|
|
||||||
Makefile
|
|
||||||
Makefile.in
|
|
||||||
Makefile.in.in
|
|
||||||
aclocal.m4
|
|
||||||
autom4te.cache/
|
|
||||||
config/
|
|
||||||
configure
|
|
||||||
config.log
|
|
||||||
config.status
|
|
||||||
data/*.json
|
|
||||||
m4/
|
|
||||||
po/*.header
|
|
||||||
po/*.sed
|
|
||||||
po/*.sin
|
|
||||||
po/Makevars.template
|
|
||||||
po/POTFILES
|
|
||||||
po/Rules-quot
|
|
||||||
po/gnome-shell-extensions.pot
|
po/gnome-shell-extensions.pot
|
||||||
po/stamp-it
|
|
||||||
staging/
|
|
||||||
zip-files/
|
zip-files/
|
||||||
|
|
||||||
*~
|
*~
|
||||||
*.gmo
|
*.patch
|
||||||
metadata.json
|
*.sw?
|
||||||
*.desktop
|
.buildconfig
|
||||||
*.gschema.valid
|
.vscode
|
||||||
*.session
|
|
||||||
|
|||||||
@@ -107,7 +107,8 @@ eslint:
|
|||||||
stage: review
|
stage: review
|
||||||
<<: *prereview_req
|
<<: *prereview_req
|
||||||
script:
|
script:
|
||||||
- eslint -o $LINT_LOG -f junit --resolve-plugins-relative-to $(npm root -g) extensions
|
- export NODE_PATH=$(npm root -g)
|
||||||
|
- ./.gitlab-ci/run-eslint --output-file ${LINT_LOG} --format junit --stdout
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- ${LINT_LOG}
|
- ${LINT_LOG}
|
||||||
|
|||||||
54
.gitlab-ci/run-eslint
Executable file
54
.gitlab-ci/run-eslint
Executable file
@@ -0,0 +1,54 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const {ESLint} = require('eslint');
|
||||||
|
|
||||||
|
console.log(`Running ESLint version ${ESLint.version}...`);
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
function hasOption(...names) {
|
||||||
|
return process.argv.some(arg => names.includes(arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOption(...names) {
|
||||||
|
const optIndex =
|
||||||
|
process.argv.findIndex(arg => names.includes(arg)) + 1;
|
||||||
|
|
||||||
|
if (optIndex === 0)
|
||||||
|
return undefined;
|
||||||
|
|
||||||
|
return process.argv[optIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
(async function main() {
|
||||||
|
const outputOption = getOption('--output-file', '-o');
|
||||||
|
const outputPath = outputOption ? path.resolve(outputOption) : null;
|
||||||
|
|
||||||
|
const sourceDir = path.dirname(process.argv[1]);
|
||||||
|
process.chdir(path.resolve(sourceDir, '..'));
|
||||||
|
|
||||||
|
const sources = ['extensions'];
|
||||||
|
const eslint = new ESLint();
|
||||||
|
|
||||||
|
const results = await eslint.lintFiles(sources);
|
||||||
|
const formatter = await eslint.loadFormatter(getOption('--format', '-f'));
|
||||||
|
const resultText = formatter.format(results);
|
||||||
|
|
||||||
|
if (outputPath) {
|
||||||
|
fs.mkdirSync(path.dirname(outputPath), {recursive: true});
|
||||||
|
fs.writeFileSync(outputPath, resultText);
|
||||||
|
|
||||||
|
if (hasOption('--stdout')) {
|
||||||
|
const consoleFormatter = await eslint.loadFormatter();
|
||||||
|
console.log(consoleFormatter.format(results));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log(resultText);
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exitCode = results.some(r => r.errorCount > 0) ? 1 : 0;
|
||||||
|
})().catch((error) => {
|
||||||
|
process.exitCode = 1;
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
11
NEWS
11
NEWS
@@ -1,3 +1,14 @@
|
|||||||
|
45.beta
|
||||||
|
=======
|
||||||
|
* Port extensions to ESM [Florian; !259, !266, !268, !269]
|
||||||
|
* Misc. bug fixes and cleanups [Florian; !260, !261, !262, !263, !264]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Florian Müllner
|
||||||
|
|
||||||
|
Translators:
|
||||||
|
Efstathios Iosifidis [el]
|
||||||
|
|
||||||
45.alpha
|
45.alpha
|
||||||
========
|
========
|
||||||
* window-list: Modernize default styling [Alexander; !253]
|
* window-list: Modernize default styling [Alexander; !253]
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 100 KiB |
@@ -1,18 +1,22 @@
|
|||||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
/* exported init enable disable */
|
import Atk from 'gi://Atk';
|
||||||
|
import Clutter from 'gi://Clutter';
|
||||||
|
import Gio from 'gi://Gio';
|
||||||
|
import GLib from 'gi://GLib';
|
||||||
|
import GMenu from 'gi://GMenu';
|
||||||
|
import GObject from 'gi://GObject';
|
||||||
|
import Gtk from 'gi://Gtk';
|
||||||
|
import Meta from 'gi://Meta';
|
||||||
|
import Shell from 'gi://Shell';
|
||||||
|
import St from 'gi://St';
|
||||||
|
import {EventEmitter} from 'resource:///org/gnome/shell/misc/signals.js';
|
||||||
|
|
||||||
const {
|
import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||||
Atk, Clutter, Gio, GLib, GMenu, GObject, Gtk, Meta, Shell, St,
|
|
||||||
} = imports.gi;
|
|
||||||
const {EventEmitter} = imports.misc.signals;
|
|
||||||
|
|
||||||
const DND = imports.ui.dnd;
|
import * as DND from 'resource:///org/gnome/shell/ui/dnd.js';
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||||
const Main = imports.ui.main;
|
import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
|
||||||
const PanelMenu = imports.ui.panelMenu;
|
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
|
||||||
|
|
||||||
const _ = ExtensionUtils.gettext;
|
|
||||||
|
|
||||||
const appSys = Shell.AppSystem.get_default();
|
const appSys = Shell.AppSystem.get_default();
|
||||||
|
|
||||||
@@ -46,11 +50,8 @@ class ApplicationMenuItem extends PopupMenu.PopupBaseMenuItem {
|
|||||||
this.label_actor = appLabel;
|
this.label_actor = appLabel;
|
||||||
|
|
||||||
let textureCache = St.TextureCache.get_default();
|
let textureCache = St.TextureCache.get_default();
|
||||||
let iconThemeChangedId = textureCache.connect('icon-theme-changed',
|
textureCache.connectObject('icon-theme-changed',
|
||||||
this._updateIcon.bind(this));
|
() => this._updateIcon(), this);
|
||||||
this.connect('destroy', () => {
|
|
||||||
textureCache.disconnect(iconThemeChangedId);
|
|
||||||
});
|
|
||||||
this._updateIcon();
|
this._updateIcon();
|
||||||
|
|
||||||
this._delegate = this;
|
this._delegate = this;
|
||||||
@@ -269,9 +270,7 @@ class DesktopTarget extends EventEmitter {
|
|||||||
|
|
||||||
_setDesktop(desktop) {
|
_setDesktop(desktop) {
|
||||||
if (this._desktop) {
|
if (this._desktop) {
|
||||||
this._desktop.disconnect(this._desktopDestroyedId);
|
this._desktop.disconnectObject(this);
|
||||||
this._desktopDestroyedId = 0;
|
|
||||||
|
|
||||||
delete this._desktop._delegate;
|
delete this._desktop._delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,9 +278,9 @@ class DesktopTarget extends EventEmitter {
|
|||||||
this.emit('desktop-changed');
|
this.emit('desktop-changed');
|
||||||
|
|
||||||
if (this._desktop) {
|
if (this._desktop) {
|
||||||
this._desktopDestroyedId = this._desktop.connect('destroy', () => {
|
this._desktop.connectObject('destroy', () => {
|
||||||
this._setDesktop(null);
|
this._setDesktop(null);
|
||||||
});
|
}, this);
|
||||||
this._desktop._delegate = this;
|
this._desktop._delegate = this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,10 +320,7 @@ class DesktopTarget extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
if (this._windowAddedId)
|
global.window_group.disconnectObject(this);
|
||||||
global.window_group.disconnect(this._windowAddedId);
|
|
||||||
this._windowAddedId = 0;
|
|
||||||
|
|
||||||
this._setDesktop(null);
|
this._setDesktop(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,15 +382,14 @@ class ApplicationsButton extends PanelMenu.Button {
|
|||||||
this.name = 'panelApplications';
|
this.name = 'panelApplications';
|
||||||
this.label_actor = this._label;
|
this.label_actor = this._label;
|
||||||
|
|
||||||
this._showingId = Main.overview.connect('showing', () => {
|
Main.overview.connectObject(
|
||||||
this.add_accessible_state(Atk.StateType.CHECKED);
|
'showing', () => this.add_accessible_state(Atk.StateType.CHECKED),
|
||||||
});
|
'hiding', () => this.remove_accessible_state(Atk.StateType.CHECKED),
|
||||||
this._hidingId = Main.overview.connect('hiding', () => {
|
this);
|
||||||
this.remove_accessible_state(Atk.StateType.CHECKED);
|
|
||||||
});
|
|
||||||
Main.wm.addKeybinding(
|
Main.wm.addKeybinding(
|
||||||
'apps-menu-toggle-menu',
|
'apps-menu-toggle-menu',
|
||||||
ExtensionUtils.getSettings(),
|
Extension.lookupByURL(import.meta.url).getSettings(),
|
||||||
Meta.KeyBindingFlags.IGNORE_AUTOREPEAT,
|
Meta.KeyBindingFlags.IGNORE_AUTOREPEAT,
|
||||||
Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW,
|
Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW,
|
||||||
() => this.menu.toggle());
|
() => this.menu.toggle());
|
||||||
@@ -410,15 +405,15 @@ class ApplicationsButton extends PanelMenu.Button {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this._tree = new GMenu.Tree({menu_basename: 'applications.menu'});
|
this._tree = new GMenu.Tree({menu_basename: 'applications.menu'});
|
||||||
this._treeChangedId = this._tree.connect('changed',
|
this._tree.connectObject('changed',
|
||||||
this._onTreeChanged.bind(this));
|
() => this._onTreeChanged(), this);
|
||||||
|
|
||||||
this._applicationsButtons = new Map();
|
this._applicationsButtons = new Map();
|
||||||
this.reloadFlag = false;
|
this.reloadFlag = false;
|
||||||
this._createLayout();
|
this._createLayout();
|
||||||
this._display();
|
this._display();
|
||||||
this._installedChangedId = appSys.connect('installed-changed',
|
appSys.connectObject('installed-changed',
|
||||||
this._onTreeChanged.bind(this));
|
() => this._onTreeChanged(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onTreeChanged() {
|
_onTreeChanged() {
|
||||||
@@ -442,11 +437,7 @@ class ApplicationsButton extends PanelMenu.Button {
|
|||||||
_onDestroy() {
|
_onDestroy() {
|
||||||
super._onDestroy();
|
super._onDestroy();
|
||||||
|
|
||||||
Main.overview.disconnect(this._showingId);
|
delete this._tree;
|
||||||
Main.overview.disconnect(this._hidingId);
|
|
||||||
appSys.disconnect(this._installedChangedId);
|
|
||||||
this._tree.disconnect(this._treeChangedId);
|
|
||||||
this._tree = null;
|
|
||||||
|
|
||||||
Main.wm.removeKeybinding('apps-menu-toggle-menu');
|
Main.wm.removeKeybinding('apps-menu-toggle-menu');
|
||||||
|
|
||||||
@@ -677,22 +668,17 @@ class ApplicationsButton extends PanelMenu.Button {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let appsMenuButton;
|
export default class AppsMenuExtension extends Extension {
|
||||||
|
enable() {
|
||||||
|
this._appsMenuButton = new ApplicationsButton();
|
||||||
|
const index = Main.sessionMode.panel.left.indexOf('activities') + 1;
|
||||||
|
Main.panel.addToStatusArea(
|
||||||
|
'apps-menu', this._appsMenuButton, index, 'left');
|
||||||
|
}
|
||||||
|
|
||||||
/** */
|
disable() {
|
||||||
function enable() {
|
Main.panel.menuManager.removeMenu(this._appsMenuButton.menu);
|
||||||
appsMenuButton = new ApplicationsButton();
|
this._appsMenuButton.destroy();
|
||||||
let index = Main.sessionMode.panel.left.indexOf('activities') + 1;
|
delete this._appsMenuButton;
|
||||||
Main.panel.addToStatusArea('apps-menu', appsMenuButton, index, 'left');
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/** */
|
|
||||||
function disable() {
|
|
||||||
Main.panel.menuManager.removeMenu(appsMenuButton.menu);
|
|
||||||
appsMenuButton.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** */
|
|
||||||
function init() {
|
|
||||||
ExtensionUtils.initTranslations();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,20 @@
|
|||||||
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
||||||
// Start apps on custom workspaces
|
// Start apps on custom workspaces
|
||||||
/* exported init enable disable */
|
|
||||||
|
|
||||||
const {Shell} = imports.gi;
|
import Shell from 'gi://Shell';
|
||||||
|
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||||
const Main = imports.ui.main;
|
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||||
|
|
||||||
class WindowMover {
|
class WindowMover {
|
||||||
constructor() {
|
constructor(settings) {
|
||||||
this._settings = ExtensionUtils.getSettings();
|
this._settings = settings;
|
||||||
this._appSystem = Shell.AppSystem.get_default();
|
this._appSystem = Shell.AppSystem.get_default();
|
||||||
this._appConfigs = new Map();
|
this._appConfigs = new Map();
|
||||||
this._appData = new Map();
|
this._appData = new Map();
|
||||||
|
|
||||||
this._appsChangedId =
|
this._appSystem.connectObject('installed-changed',
|
||||||
this._appSystem.connect('installed-changed',
|
() => this._updateAppData(), this);
|
||||||
this._updateAppData.bind(this));
|
|
||||||
|
|
||||||
this._settings.connect('changed', this._updateAppConfigs.bind(this));
|
this._settings.connect('changed', this._updateAppConfigs.bind(this));
|
||||||
this._updateAppConfigs();
|
this._updateAppConfigs();
|
||||||
@@ -38,7 +36,7 @@ class WindowMover {
|
|||||||
let removedApps = [...this._appData.keys()]
|
let removedApps = [...this._appData.keys()]
|
||||||
.filter(a => !ids.includes(a.id));
|
.filter(a => !ids.includes(a.id));
|
||||||
removedApps.forEach(app => {
|
removedApps.forEach(app => {
|
||||||
app.disconnect(this._appData.get(app).windowsChangedId);
|
app.disconnectObject(this);
|
||||||
this._appData.delete(app);
|
this._appData.delete(app);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -46,21 +44,14 @@ class WindowMover {
|
|||||||
.map(id => this._appSystem.lookup_app(id))
|
.map(id => this._appSystem.lookup_app(id))
|
||||||
.filter(app => app && !this._appData.has(app));
|
.filter(app => app && !this._appData.has(app));
|
||||||
addedApps.forEach(app => {
|
addedApps.forEach(app => {
|
||||||
let data = {
|
app.connectObject('window-changed',
|
||||||
windowsChangedId: app.connect('windows-changed',
|
this._appWindowsChanged.bind(this), this);
|
||||||
this._appWindowsChanged.bind(this)),
|
this._appData.set(app, {windows: app.get_windows()});
|
||||||
moveWindowsId: 0,
|
|
||||||
windows: app.get_windows(),
|
|
||||||
};
|
|
||||||
this._appData.set(app, data);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
if (this._appsChangedId) {
|
this._appSystem.disconnectObject(this);
|
||||||
this._appSystem.disconnect(this._appsChangedId);
|
|
||||||
this._appsChangedId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._settings) {
|
if (this._settings) {
|
||||||
this._settings.run_dispose();
|
this._settings.run_dispose();
|
||||||
@@ -105,47 +96,41 @@ class WindowMover {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let prevCheckWorkspaces;
|
export default class AutoMoveExtension extends Extension {
|
||||||
let winMover;
|
enable() {
|
||||||
|
this._prevCheckWorkspaces = Main.wm._workspaceTracker._checkWorkspaces;
|
||||||
/** */
|
Main.wm._workspaceTracker._checkWorkspaces =
|
||||||
function init() {
|
this._getCheckWorkspaceOverride(this._prevCheckWorkspaces);
|
||||||
ExtensionUtils.initTranslations();
|
this._windowMover = new WindowMover(this.getSettings());
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {bool} - false (used as MetaLater handler)
|
|
||||||
*/
|
|
||||||
function myCheckWorkspaces() {
|
|
||||||
let keepAliveWorkspaces = [];
|
|
||||||
let foundNonEmpty = false;
|
|
||||||
for (let i = this._workspaces.length - 1; i >= 0; i--) {
|
|
||||||
if (!foundNonEmpty) {
|
|
||||||
foundNonEmpty = this._workspaces[i].list_windows().some(
|
|
||||||
w => !w.is_on_all_workspaces());
|
|
||||||
} else if (!this._workspaces[i]._keepAliveId) {
|
|
||||||
keepAliveWorkspaces.push(this._workspaces[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure the original method only removes empty workspaces at the end
|
disable() {
|
||||||
keepAliveWorkspaces.forEach(ws => (ws._keepAliveId = 1));
|
Main.wm._workspaceTracker._checkWorkspaces = this._prevCheckWorkspaces;
|
||||||
prevCheckWorkspaces.call(this);
|
this._windowMover.destroy();
|
||||||
keepAliveWorkspaces.forEach(ws => delete ws._keepAliveId);
|
delete this._windowMover;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
_getCheckWorkspaceOverride(originalMethod) {
|
||||||
}
|
/* eslint-disable no-invalid-this */
|
||||||
|
return function () {
|
||||||
/** */
|
const keepAliveWorkspaces = [];
|
||||||
function enable() {
|
let foundNonEmpty = false;
|
||||||
prevCheckWorkspaces = Main.wm._workspaceTracker._checkWorkspaces;
|
for (let i = this._workspaces.length - 1; i >= 0; i--) {
|
||||||
Main.wm._workspaceTracker._checkWorkspaces = myCheckWorkspaces;
|
if (!foundNonEmpty) {
|
||||||
|
foundNonEmpty = this._workspaces[i].list_windows().some(
|
||||||
winMover = new WindowMover();
|
w => !w.is_on_all_workspaces());
|
||||||
}
|
} else if (!this._workspaces[i]._keepAliveId) {
|
||||||
|
keepAliveWorkspaces.push(this._workspaces[i]);
|
||||||
/** */
|
}
|
||||||
function disable() {
|
}
|
||||||
Main.wm._workspaceTracker._checkWorkspaces = prevCheckWorkspaces;
|
|
||||||
winMover.destroy();
|
// make sure the original method only removes empty workspaces at the end
|
||||||
|
keepAliveWorkspaces.forEach(ws => (ws._keepAliveId = 1));
|
||||||
|
originalMethod.call(this);
|
||||||
|
keepAliveWorkspaces.forEach(ws => delete ws._keepAliveId);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
/* eslint-enable no-invalid-this */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
||||||
// Start apps on custom workspaces
|
// Start apps on custom workspaces
|
||||||
/* exported init buildPrefsWidget */
|
|
||||||
|
|
||||||
const {Adw, Gio, GLib, GObject, Gtk} = imports.gi;
|
import Adw from 'gi://Adw';
|
||||||
|
import Gio from 'gi://Gio';
|
||||||
|
import GLib from 'gi://GLib';
|
||||||
|
import GObject from 'gi://GObject';
|
||||||
|
import Gtk from 'gi://Gtk';
|
||||||
|
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
import {ExtensionPreferences, gettext as _} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
|
||||||
|
|
||||||
const _ = ExtensionUtils.gettext;
|
|
||||||
|
|
||||||
const SETTINGS_KEY = 'application-list';
|
const SETTINGS_KEY = 'application-list';
|
||||||
|
|
||||||
@@ -59,13 +60,14 @@ class RulesList extends GObject.Object {
|
|||||||
GObject.registerClass(this);
|
GObject.registerClass(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
#settings = ExtensionUtils.getSettings();
|
#settings;
|
||||||
#rules = [];
|
#rules = [];
|
||||||
#changedId;
|
#changedId;
|
||||||
|
|
||||||
constructor() {
|
constructor(settings) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
this.#settings = settings;
|
||||||
this.#changedId =
|
this.#changedId =
|
||||||
this.#settings.connect(`changed::${SETTINGS_KEY}`,
|
this.#settings.connect(`changed::${SETTINGS_KEY}`,
|
||||||
() => this.#sync());
|
() => this.#sync());
|
||||||
@@ -147,12 +149,13 @@ class AutoMoveSettingsWidget extends Adw.PreferencesGroup {
|
|||||||
(self, name, param) => self._rules.changeWorkspace(...param.deepUnpack()));
|
(self, name, param) => self._rules.changeWorkspace(...param.deepUnpack()));
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor(settings) {
|
||||||
super({
|
super({
|
||||||
title: _('Workspace Rules'),
|
title: _('Workspace Rules'),
|
||||||
});
|
});
|
||||||
|
|
||||||
this._rules = new RulesList();
|
this._settings = settings;
|
||||||
|
this._rules = new RulesList(this._settings);
|
||||||
|
|
||||||
const store = new Gio.ListStore({item_type: Gio.ListModel});
|
const store = new Gio.ListStore({item_type: Gio.ListModel});
|
||||||
const listModel = new Gtk.FlattenListModel({model: store});
|
const listModel = new Gtk.FlattenListModel({model: store});
|
||||||
@@ -173,7 +176,7 @@ class AutoMoveSettingsWidget extends Adw.PreferencesGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_addNewRule() {
|
_addNewRule() {
|
||||||
const dialog = new NewRuleDialog(this.get_root());
|
const dialog = new NewRuleDialog(this.get_root(), this._settings);
|
||||||
dialog.connect('response', (dlg, id) => {
|
dialog.connect('response', (dlg, id) => {
|
||||||
const appInfo = id === Gtk.ResponseType.OK
|
const appInfo = id === Gtk.ResponseType.OK
|
||||||
? dialog.get_widget().get_app_info() : null;
|
? dialog.get_widget().get_app_info() : null;
|
||||||
@@ -312,13 +315,13 @@ class NewRuleDialog extends Gtk.AppChooserDialog {
|
|||||||
GObject.registerClass(this);
|
GObject.registerClass(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(parent) {
|
constructor(parent, settings) {
|
||||||
super({
|
super({
|
||||||
transient_for: parent,
|
transient_for: parent,
|
||||||
modal: true,
|
modal: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
this._settings = ExtensionUtils.getSettings();
|
this._settings = settings;
|
||||||
|
|
||||||
this.get_widget().set({
|
this.get_widget().set({
|
||||||
show_all: true,
|
show_all: true,
|
||||||
@@ -338,14 +341,8 @@ class NewRuleDialog extends Gtk.AppChooserDialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
export default class AutoMovePrefs extends ExtensionPreferences {
|
||||||
function init() {
|
getPreferencesWidget() {
|
||||||
ExtensionUtils.initTranslations();
|
return new AutoMoveSettingsWidget(this.getSettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {Gtk.Widget} - the prefs widget
|
|
||||||
*/
|
|
||||||
function buildPrefsWidget() {
|
|
||||||
return new AutoMoveSettingsWidget();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
/* exported init enable disable */
|
|
||||||
// Drive menu extension
|
// Drive menu extension
|
||||||
const {Clutter, Gio, GObject, Shell, St} = imports.gi;
|
import Clutter from 'gi://Clutter';
|
||||||
|
import Gio from 'gi://Gio';
|
||||||
|
import GObject from 'gi://GObject';
|
||||||
|
import Shell from 'gi://Shell';
|
||||||
|
import St from 'gi://St';
|
||||||
|
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||||
const Main = imports.ui.main;
|
|
||||||
const PanelMenu = imports.ui.panelMenu;
|
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
|
||||||
const ShellMountOperation = imports.ui.shellMountOperation;
|
|
||||||
|
|
||||||
const _ = ExtensionUtils.gettext;
|
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||||
|
import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
|
||||||
|
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
|
||||||
|
import * as ShellMountOperation from 'resource:///org/gnome/shell/ui/shellMountOperation.js';
|
||||||
|
|
||||||
Gio._promisify(Gio.File.prototype, 'query_filesystem_info_async');
|
Gio._promisify(Gio.File.prototype, 'query_filesystem_info_async');
|
||||||
|
|
||||||
@@ -47,19 +49,11 @@ class MountMenuItem extends PopupMenu.PopupBaseMenuItem {
|
|||||||
|
|
||||||
this.hide();
|
this.hide();
|
||||||
|
|
||||||
this._changedId = mount.connect('changed', this._syncVisibility.bind(this));
|
mount.connectObject('changed',
|
||||||
|
() => this._syncVisibility(), this);
|
||||||
this._syncVisibility();
|
this._syncVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onDestroy() {
|
|
||||||
if (this._changedId) {
|
|
||||||
this.mount.disconnect(this._changedId);
|
|
||||||
this._changedId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
super.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
async _isInteresting() {
|
async _isInteresting() {
|
||||||
if (!this.mount.can_eject() && !this.mount.can_unmount())
|
if (!this.mount.can_eject() && !this.mount.can_unmount())
|
||||||
return false;
|
return false;
|
||||||
@@ -152,12 +146,12 @@ class DriveMenu extends PanelMenu.Button {
|
|||||||
this.add_child(icon);
|
this.add_child(icon);
|
||||||
|
|
||||||
this._monitor = Gio.VolumeMonitor.get();
|
this._monitor = Gio.VolumeMonitor.get();
|
||||||
this._addedId = this._monitor.connect('mount-added',
|
this._monitor.connectObject(
|
||||||
(monitor, mount) => this._addMount(mount));
|
'mount-added', (monitor, mount) => this._addMount(mount),
|
||||||
this._removedId = this._monitor.connect('mount-removed', (monitor, mount) => {
|
'mount-removed', (monitor, mount) => {
|
||||||
this._removeMount(mount);
|
this._removeMount(mount);
|
||||||
this._updateMenuVisibility();
|
this._updateMenuVisibility();
|
||||||
});
|
}, this);
|
||||||
|
|
||||||
this._mounts = [];
|
this._mounts = [];
|
||||||
|
|
||||||
@@ -199,33 +193,16 @@ class DriveMenu extends PanelMenu.Button {
|
|||||||
}
|
}
|
||||||
log('Removing a mount that was never added to the menu');
|
log('Removing a mount that was never added to the menu');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_onDestroy() {
|
export default class PlaceMenuExtension extends Extension {
|
||||||
if (this._addedId) {
|
enable() {
|
||||||
this._monitor.disconnect(this._addedId);
|
this._indicator = new DriveMenu();
|
||||||
this._monitor.disconnect(this._removedId);
|
Main.panel.addToStatusArea('drive-menu', this._indicator);
|
||||||
this._addedId = 0;
|
}
|
||||||
this._removedId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
super._onDestroy();
|
disable() {
|
||||||
|
this._indicator.destroy();
|
||||||
|
delete this._indicator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
|
||||||
function init() {
|
|
||||||
ExtensionUtils.initTranslations();
|
|
||||||
}
|
|
||||||
|
|
||||||
let _indicator;
|
|
||||||
|
|
||||||
/** */
|
|
||||||
function enable() {
|
|
||||||
_indicator = new DriveMenu();
|
|
||||||
Main.panel.addToStatusArea('drive-menu', _indicator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** */
|
|
||||||
function disable() {
|
|
||||||
_indicator.destroy();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,17 +1,22 @@
|
|||||||
/* exported enable disable */
|
import {AppIcon} from 'resource:///org/gnome/shell/ui/appDisplay.js';
|
||||||
const AppDisplay = imports.ui.appDisplay;
|
import {InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||||
|
|
||||||
let _activateOriginal = null;
|
export default class Extension {
|
||||||
|
constructor() {
|
||||||
|
this._injectionManager = new InjectionManager();
|
||||||
|
}
|
||||||
|
|
||||||
/** */
|
enable() {
|
||||||
function enable() {
|
this._injectionManager.overrideMethod(AppIcon.prototype, 'activate',
|
||||||
_activateOriginal = AppDisplay.AppIcon.prototype.activate;
|
originalMethod => {
|
||||||
AppDisplay.AppIcon.prototype.activate = function () {
|
return function () {
|
||||||
_activateOriginal.call(this, 2);
|
// eslint-disable-next-line no-invalid-this
|
||||||
};
|
originalMethod.call(this, 2);
|
||||||
}
|
};
|
||||||
|
});
|
||||||
/** */
|
}
|
||||||
function disable() {
|
|
||||||
AppDisplay.AppIcon.prototype.activate = _activateOriginal;
|
disable() {
|
||||||
|
this._injectionManager.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
/* exported init */
|
|
||||||
/*
|
/*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -16,11 +15,11 @@
|
|||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const {St} = imports.gi;
|
import St from 'gi://St';
|
||||||
|
|
||||||
const Main = imports.ui.main;
|
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||||
|
|
||||||
class Extension {
|
export default class Extension {
|
||||||
_updateColorScheme(scheme) {
|
_updateColorScheme(scheme) {
|
||||||
Main.sessionMode.colorScheme = scheme;
|
Main.sessionMode.colorScheme = scheme;
|
||||||
St.Settings.get().notify('color-scheme');
|
St.Settings.get().notify('color-scheme');
|
||||||
@@ -35,8 +34,3 @@ class Extension {
|
|||||||
this._updateColorScheme(this._savedColorScheme);
|
this._updateColorScheme(this._savedColorScheme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
|
||||||
function init() {
|
|
||||||
return new Extension();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
||||||
/* exported enable disable */
|
import Clutter from 'gi://Clutter';
|
||||||
const {Clutter} = imports.gi;
|
|
||||||
|
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
import {Extension, InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||||
const Main = imports.ui.main;
|
|
||||||
const {WindowPreview} = imports.ui.windowPreview;
|
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||||
const Workspace = imports.ui.workspace;
|
import {WindowPreview} from 'resource:///org/gnome/shell/ui/windowPreview.js';
|
||||||
|
import * as Workspace from 'resource:///org/gnome/shell/ui/workspace.js';
|
||||||
|
|
||||||
// testing settings for natural window placement strategy:
|
// testing settings for natural window placement strategy:
|
||||||
const WINDOW_PLACEMENT_NATURAL_ACCURACY = 20; // accuracy of window translate moves (KDE-default: 20)
|
const WINDOW_PLACEMENT_NATURAL_ACCURACY = 20; // accuracy of window translate moves (KDE-default: 20)
|
||||||
@@ -236,75 +236,64 @@ class NaturalLayoutStrategy extends Workspace.LayoutStrategy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let winInjections, workspaceInjections;
|
export default class NativeWindowPlacementExtension extends Extension {
|
||||||
|
constructor(metadata) {
|
||||||
|
super(metadata);
|
||||||
|
|
||||||
/** */
|
this._injectionManager = new InjectionManager();
|
||||||
function resetState() {
|
}
|
||||||
winInjections = { };
|
|
||||||
workspaceInjections = { };
|
enable() {
|
||||||
}
|
const settings = this.getSettings();
|
||||||
|
|
||||||
/** */
|
const layoutProto = Workspace.WorkspaceLayout.prototype;
|
||||||
function enable() {
|
const previewProto = WindowPreview.prototype;
|
||||||
resetState();
|
|
||||||
|
this._injectionManager.overrideMethod(layoutProto, '_createBestLayout', () => {
|
||||||
let settings = ExtensionUtils.getSettings();
|
/* eslint-disable no-invalid-this */
|
||||||
|
return function () {
|
||||||
workspaceInjections['_createBestLayout'] = Workspace.WorkspaceLayout.prototype._createBestLayout;
|
this._layoutStrategy = new NaturalLayoutStrategy({
|
||||||
Workspace.WorkspaceLayout.prototype._createBestLayout = function (_area) {
|
monitor: Main.layoutManager.monitors[this._monitorIndex],
|
||||||
this._layoutStrategy = new NaturalLayoutStrategy({
|
}, settings);
|
||||||
monitor: Main.layoutManager.monitors[this._monitorIndex],
|
return this._layoutStrategy.computeLayout(this._sortedWindows);
|
||||||
}, settings);
|
};
|
||||||
return this._layoutStrategy.computeLayout(this._sortedWindows);
|
/* eslint-enable no-invalid-this */
|
||||||
};
|
});
|
||||||
|
|
||||||
// position window titles on top of windows in overlay
|
// position window titles on top of windows in overlay
|
||||||
winInjections['_init'] = WindowPreview.prototype._init;
|
this._injectionManager.overrideMethod(previewProto, '_init', originalMethod => {
|
||||||
WindowPreview.prototype._init = function (...args) {
|
/* eslint-disable no-invalid-this */
|
||||||
winInjections['_init'].call(this, ...args);
|
return function (...args) {
|
||||||
|
originalMethod.call(this, ...args);
|
||||||
if (!settings.get_boolean('window-captions-on-top'))
|
|
||||||
return;
|
if (!settings.get_boolean('window-captions-on-top'))
|
||||||
|
return;
|
||||||
const alignConstraint = this._title.get_constraints().find(
|
|
||||||
c => c.align_axis && c.align_axis === Clutter.AlignAxis.Y_AXIS);
|
const alignConstraint = this._title.get_constraints().find(
|
||||||
alignConstraint.factor = 0;
|
c => c.align_axis && c.align_axis === Clutter.AlignAxis.Y_AXIS);
|
||||||
|
alignConstraint.factor = 0;
|
||||||
const bindConstraint = this._title.get_constraints().find(
|
|
||||||
c => c.coordinate && c.coordinate === Clutter.BindCoordinate.Y);
|
const bindConstraint = this._title.get_constraints().find(
|
||||||
bindConstraint.offset = 0;
|
c => c.coordinate && c.coordinate === Clutter.BindCoordinate.Y);
|
||||||
};
|
bindConstraint.offset = 0;
|
||||||
winInjections['_adjustOverlayOffsets'] =
|
};
|
||||||
WindowPreview.prototype._adjustOverlayOffsets;
|
/* eslint-enable no-invalid-this */
|
||||||
WindowPreview.prototype._adjustOverlayOffsets = function (...args) {
|
});
|
||||||
winInjections['_adjustOverlayOffsets'].call(this, ...args);
|
|
||||||
|
this._injectionManager.overrideMethod(previewProto, '_adjustOverlayOffsets', originalMethod => {
|
||||||
if (settings.get_boolean('window-captions-on-top'))
|
/* eslint-disable no-invalid-this */
|
||||||
this._title.translation_y = -this._title.translation_y;
|
return function (...args) {
|
||||||
};
|
originalMethod.call(this, ...args);
|
||||||
}
|
|
||||||
|
if (settings.get_boolean('window-captions-on-top'))
|
||||||
/**
|
this._title.translation_y = -this._title.translation_y;
|
||||||
* @param {object} object - object that was modified
|
};
|
||||||
* @param {object} injection - the map of previous injections
|
/* eslint-enable no-invalid-this */
|
||||||
* @param {string} name - the @injection key that should be removed
|
});
|
||||||
*/
|
}
|
||||||
function removeInjection(object, injection, name) {
|
|
||||||
if (injection[name] === undefined)
|
disable() {
|
||||||
delete object[name];
|
this._injectionManager.clear();
|
||||||
else
|
global.stage.queue_relayout();
|
||||||
object[name] = injection[name];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/** */
|
|
||||||
function disable() {
|
|
||||||
var i;
|
|
||||||
|
|
||||||
for (i in workspaceInjections)
|
|
||||||
removeInjection(Workspace.WorkspaceLayout.prototype, workspaceInjections, i);
|
|
||||||
for (i in winInjections)
|
|
||||||
removeInjection(WindowPreview.prototype, winInjections, i);
|
|
||||||
|
|
||||||
global.stage.queue_relayout();
|
|
||||||
resetState();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
/* exported init enable disable */
|
import Clutter from 'gi://Clutter';
|
||||||
|
import GObject from 'gi://GObject';
|
||||||
|
import St from 'gi://St';
|
||||||
|
|
||||||
const {Clutter, GObject, St} = imports.gi;
|
import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||||
|
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||||
const Main = imports.ui.main;
|
import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
|
||||||
const PanelMenu = imports.ui.panelMenu;
|
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
|
||||||
|
|
||||||
const Me = ExtensionUtils.getCurrentExtension();
|
import {PlacesManager} from './placeDisplay.js';
|
||||||
const PlaceDisplay = Me.imports.placeDisplay;
|
|
||||||
|
|
||||||
const _ = ExtensionUtils.gettext;
|
|
||||||
const N_ = x => x;
|
const N_ = x => x;
|
||||||
|
|
||||||
const PLACE_ICON_SIZE = 16;
|
const PLACE_ICON_SIZE = 16;
|
||||||
@@ -53,17 +52,8 @@ class PlaceMenuItem extends PopupMenu.PopupBaseMenuItem {
|
|||||||
this.add_child(this._ejectButton);
|
this.add_child(this._ejectButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._changedId = info.connect('changed',
|
info.connectObject('changed',
|
||||||
this._propertiesChanged.bind(this));
|
this._propertiesChanged.bind(this), this);
|
||||||
}
|
|
||||||
|
|
||||||
destroy() {
|
|
||||||
if (this._changedId) {
|
|
||||||
this._info.disconnect(this._changedId);
|
|
||||||
this._changedId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
super.destroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
activate(event) {
|
activate(event) {
|
||||||
@@ -100,7 +90,7 @@ class PlacesMenu extends PanelMenu.Button {
|
|||||||
});
|
});
|
||||||
this.add_actor(label);
|
this.add_actor(label);
|
||||||
|
|
||||||
this.placesManager = new PlaceDisplay.PlacesManager();
|
this.placesManager = new PlacesManager();
|
||||||
|
|
||||||
this._sections = { };
|
this._sections = { };
|
||||||
|
|
||||||
@@ -138,24 +128,18 @@ class PlacesMenu extends PanelMenu.Button {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
export default class PlacesMenuExtension extends Extension {
|
||||||
function init() {
|
enable() {
|
||||||
ExtensionUtils.initTranslations();
|
this._indicator = new PlacesMenu();
|
||||||
}
|
|
||||||
|
let pos = Main.sessionMode.panel.left.length;
|
||||||
let _indicator;
|
if ('apps-menu' in Main.panel.statusArea)
|
||||||
|
pos++;
|
||||||
/** */
|
Main.panel.addToStatusArea('places-menu', this._indicator, pos, 'left');
|
||||||
function enable() {
|
}
|
||||||
_indicator = new PlacesMenu();
|
|
||||||
|
disable() {
|
||||||
let pos = Main.sessionMode.panel.left.length;
|
this._indicator.destroy();
|
||||||
if ('apps-menu' in Main.panel.statusArea)
|
delete this._indicator;
|
||||||
pos++;
|
}
|
||||||
Main.panel.addToStatusArea('places-menu', _indicator, pos, 'left');
|
|
||||||
}
|
|
||||||
|
|
||||||
/** */
|
|
||||||
function disable() {
|
|
||||||
_indicator.destroy();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
/* exported PlacesManager */
|
import Gio from 'gi://Gio';
|
||||||
|
import GLib from 'gi://GLib';
|
||||||
|
import Shell from 'gi://Shell';
|
||||||
|
import {EventEmitter} from 'resource:///org/gnome/shell/misc/signals.js';
|
||||||
|
|
||||||
const {Gio, GLib, Shell} = imports.gi;
|
import {gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||||
const {EventEmitter} = imports.misc.signals;
|
|
||||||
|
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||||
const Main = imports.ui.main;
|
import * as ShellMountOperation from 'resource:///org/gnome/shell/ui/shellMountOperation.js';
|
||||||
const ShellMountOperation = imports.ui.shellMountOperation;
|
|
||||||
|
|
||||||
const _ = ExtensionUtils.gettext;
|
|
||||||
const N_ = x => x;
|
const N_ = x => x;
|
||||||
|
|
||||||
Gio._promisify(Gio.AppInfo, 'launch_default_for_uri_async');
|
Gio._promisify(Gio.AppInfo, 'launch_default_for_uri_async');
|
||||||
@@ -248,7 +248,7 @@ const DEFAULT_DIRECTORIES = [
|
|||||||
GLib.UserDirectory.DIRECTORY_VIDEOS,
|
GLib.UserDirectory.DIRECTORY_VIDEOS,
|
||||||
];
|
];
|
||||||
|
|
||||||
var PlacesManager = class extends EventEmitter {
|
export class PlacesManager extends EventEmitter {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@@ -260,15 +260,25 @@ var PlacesManager = class extends EventEmitter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this._settings = new Gio.Settings({schema_id: BACKGROUND_SCHEMA});
|
this._settings = new Gio.Settings({schema_id: BACKGROUND_SCHEMA});
|
||||||
this._showDesktopIconsChangedId = this._settings.connect(
|
this._settings.connectObject('changed::show-desktop-icons',
|
||||||
'changed::show-desktop-icons', this._updateSpecials.bind(this));
|
() => this._updateSpecials(), this);
|
||||||
this._updateSpecials();
|
this._updateSpecials();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Show devices, code more or less ported from nautilus-places-sidebar.c
|
* Show devices, code more or less ported from nautilus-places-sidebar.c
|
||||||
*/
|
*/
|
||||||
this._volumeMonitor = Gio.VolumeMonitor.get();
|
this._volumeMonitor = Gio.VolumeMonitor.get();
|
||||||
this._connectVolumeMonitorSignals();
|
this._volumeMonitor.connectObject(
|
||||||
|
'volume-added', () => this._updateMounts(),
|
||||||
|
'volume-removed', () => this._updateMounts(),
|
||||||
|
'volume-changed', () => this._updateMounts(),
|
||||||
|
'mount-added', () => this._updateMounts(),
|
||||||
|
'mount-removed', () => this._updateMounts(),
|
||||||
|
'mount-changed', () => this._updateMounts(),
|
||||||
|
'drive-connected', () => this._updateMounts(),
|
||||||
|
'drive-disconnected', () => this._updateMounts(),
|
||||||
|
'drive-changed', () => this._updateMounts(),
|
||||||
|
this);
|
||||||
this._updateMounts();
|
this._updateMounts();
|
||||||
|
|
||||||
this._bookmarksFile = this._findBookmarksFile();
|
this._bookmarksFile = this._findBookmarksFile();
|
||||||
@@ -293,34 +303,11 @@ var PlacesManager = class extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_connectVolumeMonitorSignals() {
|
|
||||||
const signals = [
|
|
||||||
'volume-added',
|
|
||||||
'volume-removed',
|
|
||||||
'volume-changed',
|
|
||||||
'mount-added',
|
|
||||||
'mount-removed',
|
|
||||||
'mount-changed',
|
|
||||||
'drive-connected',
|
|
||||||
'drive-disconnected',
|
|
||||||
'drive-changed',
|
|
||||||
];
|
|
||||||
|
|
||||||
this._volumeMonitorSignals = [];
|
|
||||||
let func = this._updateMounts.bind(this);
|
|
||||||
for (let i = 0; i < signals.length; i++) {
|
|
||||||
let id = this._volumeMonitor.connect(signals[i], func);
|
|
||||||
this._volumeMonitorSignals.push(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
if (this._settings)
|
this._settings?.disconnectObject(this);
|
||||||
this._settings.disconnect(this._showDesktopIconsChangedId);
|
|
||||||
this._settings = null;
|
this._settings = null;
|
||||||
|
|
||||||
for (let i = 0; i < this._volumeMonitorSignals.length; i++)
|
this._volumeMonitor.disconnectObject(this);
|
||||||
this._volumeMonitor.disconnect(this._volumeMonitorSignals[i]);
|
|
||||||
|
|
||||||
if (this._monitor)
|
if (this._monitor)
|
||||||
this._monitor.cancel();
|
this._monitor.cancel();
|
||||||
@@ -546,4 +533,4 @@ var PlacesManager = class extends EventEmitter {
|
|||||||
get(kind) {
|
get(kind) {
|
||||||
return this._places[kind];
|
return this._places[kind];
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
/* exported enable disable */
|
|
||||||
/* Screenshot Window Sizer for Gnome Shell
|
/* Screenshot Window Sizer for Gnome Shell
|
||||||
*
|
*
|
||||||
* Copyright (c) 2013 Owen Taylor <otaylor@redhat.com>
|
* Copyright (c) 2013 Owen Taylor <otaylor@redhat.com>
|
||||||
@@ -19,153 +18,151 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const {Clutter, Meta, Shell, St} = imports.gi;
|
import Clutter from 'gi://Clutter';
|
||||||
|
import Meta from 'gi://Meta';
|
||||||
|
import Shell from 'gi://Shell';
|
||||||
|
import St from 'gi://St';
|
||||||
|
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||||
const Main = imports.ui.main;
|
|
||||||
|
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||||
|
|
||||||
const MESSAGE_FADE_TIME = 2000;
|
const MESSAGE_FADE_TIME = 2000;
|
||||||
|
|
||||||
let text;
|
export default class ScreenshotWindowSizerExtension extends Extension {
|
||||||
|
SIZES = [
|
||||||
|
[624, 351],
|
||||||
|
[800, 450],
|
||||||
|
[1024, 576],
|
||||||
|
[1200, 675],
|
||||||
|
[1600, 900],
|
||||||
|
[360, 654], // Phone portrait maximized
|
||||||
|
[720, 360], // Phone landscape fullscreen
|
||||||
|
];
|
||||||
|
|
||||||
/** */
|
_flashMessage(message) {
|
||||||
function hideMessage() {
|
if (!this._text) {
|
||||||
text.destroy();
|
this._text = new St.Label({style_class: 'screenshot-sizer-message'});
|
||||||
text = null;
|
Main.uiGroup.add_actor(this._text);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} message - the message to flash
|
|
||||||
*/
|
|
||||||
function flashMessage(message) {
|
|
||||||
if (!text) {
|
|
||||||
text = new St.Label({style_class: 'screenshot-sizer-message'});
|
|
||||||
Main.uiGroup.add_actor(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
text.remove_all_transitions();
|
|
||||||
text.text = message;
|
|
||||||
|
|
||||||
text.opacity = 255;
|
|
||||||
|
|
||||||
let monitor = Main.layoutManager.primaryMonitor;
|
|
||||||
text.set_position(
|
|
||||||
monitor.x + Math.floor(monitor.width / 2 - text.width / 2),
|
|
||||||
monitor.y + Math.floor(monitor.height / 2 - text.height / 2));
|
|
||||||
|
|
||||||
text.ease({
|
|
||||||
opacity: 0,
|
|
||||||
duration: MESSAGE_FADE_TIME,
|
|
||||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
|
||||||
onComplete: hideMessage,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let SIZES = [
|
|
||||||
[624, 351],
|
|
||||||
[800, 450],
|
|
||||||
[1024, 576],
|
|
||||||
[1200, 675],
|
|
||||||
[1600, 900],
|
|
||||||
[360, 654], // Phone portrait maximized
|
|
||||||
[720, 360], // Phone landscape fullscreen
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Meta.Display} display - the display
|
|
||||||
* @param {Meta.Window=} window - for per-window bindings, the window
|
|
||||||
* @param {Meta.KeyBinding} binding - the key binding
|
|
||||||
*/
|
|
||||||
function cycleScreenshotSizes(display, window, binding) {
|
|
||||||
// Probably this isn't useful with 5 sizes, but you can decrease instead
|
|
||||||
// of increase by holding down shift.
|
|
||||||
let modifiers = binding.get_modifiers();
|
|
||||||
let backwards = (modifiers & Meta.VirtualModifier.SHIFT_MASK) !== 0;
|
|
||||||
|
|
||||||
// Unmaximize first
|
|
||||||
if (window.get_maximized() !== 0)
|
|
||||||
window.unmaximize(Meta.MaximizeFlags.BOTH);
|
|
||||||
|
|
||||||
let workArea = window.get_work_area_current_monitor();
|
|
||||||
let outerRect = window.get_frame_rect();
|
|
||||||
|
|
||||||
// Double both axes if on a hidpi display
|
|
||||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
|
||||||
let scaledSizes = SIZES.map(size => size.map(wh => wh * scaleFactor))
|
|
||||||
.filter(([w, h]) => w <= workArea.width && h <= workArea.height);
|
|
||||||
|
|
||||||
// Find the nearest 16:9 size for the current window size
|
|
||||||
let nearestIndex;
|
|
||||||
let nearestError;
|
|
||||||
|
|
||||||
for (let i = 0; i < scaledSizes.length; i++) {
|
|
||||||
let [width, height] = scaledSizes[i];
|
|
||||||
|
|
||||||
// get the best initial window size
|
|
||||||
let error = Math.abs(width - outerRect.width) + Math.abs(height - outerRect.height);
|
|
||||||
if (nearestIndex === undefined || error < nearestError) {
|
|
||||||
nearestIndex = i;
|
|
||||||
nearestError = error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._text.remove_all_transitions();
|
||||||
|
this._text.text = message;
|
||||||
|
|
||||||
|
this._text.opacity = 255;
|
||||||
|
|
||||||
|
const monitor = Main.layoutManager.primaryMonitor;
|
||||||
|
this._text.set_position(
|
||||||
|
monitor.x + Math.floor(monitor.width / 2 - this._text.width / 2),
|
||||||
|
monitor.y + Math.floor(monitor.height / 2 - this._text.height / 2));
|
||||||
|
|
||||||
|
this._text.ease({
|
||||||
|
opacity: 0,
|
||||||
|
duration: MESSAGE_FADE_TIME,
|
||||||
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||||
|
onComplete: () => this._hideMessage(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the next size up or down from ideal
|
_hideMessage() {
|
||||||
let newIndex = (nearestIndex + (backwards ? -1 : 1)) % scaledSizes.length;
|
this._text.destroy();
|
||||||
let [newWidth, newHeight] = scaledSizes[newIndex];
|
delete this._text;
|
||||||
|
}
|
||||||
|
|
||||||
// Push the window onscreen if it would be resized offscreen
|
/**
|
||||||
let newX = outerRect.x;
|
* @param {Meta.Display} display - the display
|
||||||
let newY = outerRect.y;
|
* @param {Meta.Window=} window - for per-window bindings, the window
|
||||||
if (newX + newWidth > workArea.x + workArea.width)
|
* @param {Meta.KeyBinding} binding - the key binding
|
||||||
newX = Math.max(workArea.x + workArea.width - newWidth);
|
*/
|
||||||
if (newY + newHeight > workArea.y + workArea.height)
|
_cycleScreenshotSizes(display, window, binding) {
|
||||||
newY = Math.max(workArea.y + workArea.height - newHeight);
|
// Probably this isn't useful with 5 sizes, but you can decrease instead
|
||||||
|
// of increase by holding down shift.
|
||||||
|
let modifiers = binding.get_modifiers();
|
||||||
|
let backwards = (modifiers & Meta.VirtualModifier.SHIFT_MASK) !== 0;
|
||||||
|
|
||||||
const id = window.connect('size-changed', () => {
|
// Unmaximize first
|
||||||
window.disconnect(id);
|
if (window.get_maximized() !== 0)
|
||||||
_notifySizeChange(window);
|
window.unmaximize(Meta.MaximizeFlags.BOTH);
|
||||||
});
|
|
||||||
window.move_resize_frame(true, newX, newY, newWidth, newHeight);
|
let workArea = window.get_work_area_current_monitor();
|
||||||
}
|
let outerRect = window.get_frame_rect();
|
||||||
|
|
||||||
/**
|
// Double both axes if on a hidpi display
|
||||||
* @param {Meta.Window} window - the window whose size changed
|
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||||
*/
|
let scaledSizes = this.SIZES.map(size => size.map(wh => wh * scaleFactor))
|
||||||
function _notifySizeChange(window) {
|
.filter(([w, h]) => w <= workArea.width && h <= workArea.height);
|
||||||
const {scaleFactor} = St.ThemeContext.get_for_stage(global.stage);
|
|
||||||
let newOuterRect = window.get_frame_rect();
|
// Find the nearest 16:9 size for the current window size
|
||||||
let message = '%d×%d'.format(
|
let nearestIndex;
|
||||||
newOuterRect.width / scaleFactor,
|
let nearestError;
|
||||||
newOuterRect.height / scaleFactor);
|
|
||||||
|
for (let i = 0; i < scaledSizes.length; i++) {
|
||||||
// The new size might have been constrained by geometry hints (e.g. for
|
let [width, height] = scaledSizes[i];
|
||||||
// a terminal) - in that case, include the actual ratio to the message
|
|
||||||
// we flash
|
// get the best initial window size
|
||||||
let actualNumerator = 9 * newOuterRect.width / newOuterRect.height;
|
let error = Math.abs(width - outerRect.width) + Math.abs(height - outerRect.height);
|
||||||
if (Math.abs(actualNumerator - 16) > 0.01)
|
if (nearestIndex === undefined || error < nearestError) {
|
||||||
message += ' (%.2f:9)'.format(actualNumerator);
|
nearestIndex = i;
|
||||||
|
nearestError = error;
|
||||||
flashMessage(message);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
// get the next size up or down from ideal
|
||||||
function enable() {
|
let newIndex = (nearestIndex + (backwards ? -1 : 1)) % scaledSizes.length;
|
||||||
Main.wm.addKeybinding(
|
let [newWidth, newHeight] = scaledSizes[newIndex];
|
||||||
'cycle-screenshot-sizes',
|
|
||||||
ExtensionUtils.getSettings(),
|
// Push the window onscreen if it would be resized offscreen
|
||||||
Meta.KeyBindingFlags.PER_WINDOW,
|
let newX = outerRect.x;
|
||||||
Shell.ActionMode.NORMAL,
|
let newY = outerRect.y;
|
||||||
cycleScreenshotSizes);
|
if (newX + newWidth > workArea.x + workArea.width)
|
||||||
Main.wm.addKeybinding(
|
newX = Math.max(workArea.x + workArea.width - newWidth);
|
||||||
'cycle-screenshot-sizes-backward',
|
if (newY + newHeight > workArea.y + workArea.height)
|
||||||
ExtensionUtils.getSettings(),
|
newY = Math.max(workArea.y + workArea.height - newHeight);
|
||||||
Meta.KeyBindingFlags.PER_WINDOW | Meta.KeyBindingFlags.IS_REVERSED,
|
|
||||||
Shell.ActionMode.NORMAL,
|
const id = window.connect('size-changed', () => {
|
||||||
cycleScreenshotSizes);
|
window.disconnect(id);
|
||||||
}
|
this._notifySizeChange(window);
|
||||||
|
});
|
||||||
/** */
|
window.move_resize_frame(true, newX, newY, newWidth, newHeight);
|
||||||
function disable() {
|
}
|
||||||
Main.wm.removeKeybinding('cycle-screenshot-sizes');
|
|
||||||
Main.wm.removeKeybinding('cycle-screenshot-sizes-backward');
|
/**
|
||||||
|
* @param {Meta.Window} window - the window whose size changed
|
||||||
|
*/
|
||||||
|
_notifySizeChange(window) {
|
||||||
|
const {scaleFactor} = St.ThemeContext.get_for_stage(global.stage);
|
||||||
|
let newOuterRect = window.get_frame_rect();
|
||||||
|
let message = '%d×%d'.format(
|
||||||
|
newOuterRect.width / scaleFactor,
|
||||||
|
newOuterRect.height / scaleFactor);
|
||||||
|
|
||||||
|
// The new size might have been constrained by geometry hints (e.g. for
|
||||||
|
// a terminal) - in that case, include the actual ratio to the message
|
||||||
|
// we flash
|
||||||
|
let actualNumerator = 9 * newOuterRect.width / newOuterRect.height;
|
||||||
|
if (Math.abs(actualNumerator - 16) > 0.01)
|
||||||
|
message += ' (%.2f:9)'.format(actualNumerator);
|
||||||
|
|
||||||
|
this._flashMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
enable() {
|
||||||
|
Main.wm.addKeybinding(
|
||||||
|
'cycle-screenshot-sizes',
|
||||||
|
this.getSettings(),
|
||||||
|
Meta.KeyBindingFlags.PER_WINDOW,
|
||||||
|
Shell.ActionMode.NORMAL,
|
||||||
|
this._cycleScreenshotSizes.bind(this));
|
||||||
|
Main.wm.addKeybinding(
|
||||||
|
'cycle-screenshot-sizes-backward',
|
||||||
|
this.getSettings(),
|
||||||
|
Meta.KeyBindingFlags.PER_WINDOW | Meta.KeyBindingFlags.IS_REVERSED,
|
||||||
|
Shell.ActionMode.NORMAL,
|
||||||
|
this._cycleScreenshotSizes.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
disable() {
|
||||||
|
Main.wm.removeKeybinding('cycle-screenshot-sizes');
|
||||||
|
Main.wm.removeKeybinding('cycle-screenshot-sizes-backward');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
||||||
// Load shell theme from ~/.local/share/themes/name/gnome-shell
|
// Load shell theme from ~/.local/share/themes/name/gnome-shell
|
||||||
/* exported init */
|
|
||||||
|
|
||||||
const {Gio} = imports.gi;
|
import Gio from 'gi://Gio';
|
||||||
|
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||||
const Main = imports.ui.main;
|
|
||||||
|
|
||||||
const Me = ExtensionUtils.getCurrentExtension();
|
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||||
const Util = Me.imports.util;
|
|
||||||
|
import {getThemeDirs, getModeThemeDirs} from './util.js';
|
||||||
|
|
||||||
const SETTINGS_KEY = 'name';
|
const SETTINGS_KEY = 'name';
|
||||||
|
|
||||||
class ThemeManager {
|
export default class ThemeManager extends Extension {
|
||||||
enable() {
|
enable() {
|
||||||
this._settings = ExtensionUtils.getSettings();
|
this._settings = this.getSettings();
|
||||||
this._settings.connect(`changed::${SETTINGS_KEY}`, this._changeTheme.bind(this));
|
this._settings.connect(`changed::${SETTINGS_KEY}`, this._changeTheme.bind(this));
|
||||||
this._changeTheme();
|
this._changeTheme();
|
||||||
}
|
}
|
||||||
@@ -32,10 +31,10 @@ class ThemeManager {
|
|||||||
let themeName = this._settings.get_string(SETTINGS_KEY);
|
let themeName = this._settings.get_string(SETTINGS_KEY);
|
||||||
|
|
||||||
if (themeName) {
|
if (themeName) {
|
||||||
const stylesheetPaths = Util.getThemeDirs()
|
const stylesheetPaths = getThemeDirs()
|
||||||
.map(dir => `${dir}/${themeName}/gnome-shell/gnome-shell.css`);
|
.map(dir => `${dir}/${themeName}/gnome-shell/gnome-shell.css`);
|
||||||
|
|
||||||
stylesheetPaths.push(...Util.getModeThemeDirs()
|
stylesheetPaths.push(...getModeThemeDirs()
|
||||||
.map(dir => `${dir}/${themeName}.css`));
|
.map(dir => `${dir}/${themeName}.css`));
|
||||||
|
|
||||||
stylesheet = stylesheetPaths.find(path => {
|
stylesheet = stylesheetPaths.find(path => {
|
||||||
@@ -45,17 +44,10 @@ class ThemeManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (stylesheet)
|
if (stylesheet)
|
||||||
global.log(`loading user theme: ${stylesheet}`);
|
log(`loading user theme: ${stylesheet}`);
|
||||||
else
|
else
|
||||||
global.log('loading default theme (Adwaita)');
|
log('loading default theme (Adwaita)');
|
||||||
Main.setThemeStylesheet(stylesheet);
|
Main.setThemeStylesheet(stylesheet);
|
||||||
Main.loadTheme();
|
Main.loadTheme();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {ThemeManager} - the extension state object
|
|
||||||
*/
|
|
||||||
function init() {
|
|
||||||
return new ThemeManager();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
||||||
/* exported init buildPrefsWidget */
|
|
||||||
|
|
||||||
// we use async/await here to not block the mainloop, not to parallelize
|
// we use async/await here to not block the mainloop, not to parallelize
|
||||||
/* eslint-disable no-await-in-loop */
|
/* eslint-disable no-await-in-loop */
|
||||||
|
|
||||||
const {Adw, Gio, GLib, GObject, Gtk} = imports.gi;
|
import Adw from 'gi://Adw';
|
||||||
|
import Gio from 'gi://Gio';
|
||||||
|
import GLib from 'gi://GLib';
|
||||||
|
import GObject from 'gi://GObject';
|
||||||
|
import Gtk from 'gi://Gtk';
|
||||||
|
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
import {ExtensionPreferences} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
|
||||||
|
|
||||||
const Me = ExtensionUtils.getCurrentExtension();
|
import {getThemeDirs, getModeThemeDirs} from './util.js';
|
||||||
const Util = Me.imports.util;
|
|
||||||
|
|
||||||
Gio._promisify(Gio.File.prototype, 'enumerate_children_async');
|
Gio._promisify(Gio.File.prototype, 'enumerate_children_async');
|
||||||
Gio._promisify(Gio.File.prototype, 'query_info_async');
|
Gio._promisify(Gio.File.prototype, 'query_info_async');
|
||||||
@@ -20,13 +22,13 @@ class UserThemePrefsWidget extends Adw.PreferencesGroup {
|
|||||||
GObject.registerClass(this);
|
GObject.registerClass(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor(settings) {
|
||||||
super({title: 'Themes'});
|
super({title: 'Themes'});
|
||||||
|
|
||||||
this._actionGroup = new Gio.SimpleActionGroup();
|
this._actionGroup = new Gio.SimpleActionGroup();
|
||||||
this.insert_action_group('theme', this._actionGroup);
|
this.insert_action_group('theme', this._actionGroup);
|
||||||
|
|
||||||
this._settings = ExtensionUtils.getSettings();
|
this._settings = settings;
|
||||||
this._actionGroup.add_action(
|
this._actionGroup.add_action(
|
||||||
this._settings.create_action('name'));
|
this._settings.create_action('name'));
|
||||||
|
|
||||||
@@ -39,7 +41,7 @@ class UserThemePrefsWidget extends Adw.PreferencesGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _collectThemes() {
|
async _collectThemes() {
|
||||||
for (const dirName of Util.getThemeDirs()) {
|
for (const dirName of getThemeDirs()) {
|
||||||
const dir = Gio.File.new_for_path(dirName);
|
const dir = Gio.File.new_for_path(dirName);
|
||||||
for (const name of await this._enumerateDir(dir)) {
|
for (const name of await this._enumerateDir(dir)) {
|
||||||
if (this._rows.has(name))
|
if (this._rows.has(name))
|
||||||
@@ -60,7 +62,7 @@ class UserThemePrefsWidget extends Adw.PreferencesGroup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const dirName of Util.getModeThemeDirs()) {
|
for (const dirName of getModeThemeDirs()) {
|
||||||
const dir = Gio.File.new_for_path(dirName);
|
const dir = Gio.File.new_for_path(dirName);
|
||||||
for (const filename of await this._enumerateDir(dir)) {
|
for (const filename of await this._enumerateDir(dir)) {
|
||||||
if (!filename.endsWith('.css'))
|
if (!filename.endsWith('.css'))
|
||||||
@@ -125,13 +127,8 @@ class ThemeRow extends Adw.ActionRow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
export default class UserThemePrefs extends ExtensionPreferences {
|
||||||
function init() {
|
getPreferencesWidget() {
|
||||||
}
|
return new UserThemePrefsWidget(this.getSettings());
|
||||||
|
}
|
||||||
/**
|
|
||||||
* @returns {Gtk.Widget} - the prefs widget
|
|
||||||
*/
|
|
||||||
function buildPrefsWidget() {
|
|
||||||
return new UserThemePrefsWidget();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
/* exported getThemeDirs getModeThemeDirs */
|
import GLib from 'gi://GLib';
|
||||||
const {GLib} = imports.gi;
|
|
||||||
|
|
||||||
const fn = (...args) => GLib.build_filenamev(args);
|
const fn = (...args) => GLib.build_filenamev(args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {string[]} - an ordered list of theme directories
|
* @returns {string[]} - an ordered list of theme directories
|
||||||
*/
|
*/
|
||||||
function getThemeDirs() {
|
export function getThemeDirs() {
|
||||||
return [
|
return [
|
||||||
fn(GLib.get_home_dir(), '.themes'),
|
fn(GLib.get_home_dir(), '.themes'),
|
||||||
fn(GLib.get_user_data_dir(), 'themes'),
|
fn(GLib.get_user_data_dir(), 'themes'),
|
||||||
@@ -17,7 +16,7 @@ function getThemeDirs() {
|
|||||||
/**
|
/**
|
||||||
* @returns {string[]} - an ordered list of mode theme directories
|
* @returns {string[]} - an ordered list of mode theme directories
|
||||||
*/
|
*/
|
||||||
function getModeThemeDirs() {
|
export function getModeThemeDirs() {
|
||||||
return GLib.get_system_data_dirs()
|
return GLib.get_system_data_dirs()
|
||||||
.map(dir => fn(dir, 'gnome-shell', 'theme'));
|
.map(dir => fn(dir, 'gnome-shell', 'theme'));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,21 @@
|
|||||||
/* exported init */
|
import Clutter from 'gi://Clutter';
|
||||||
const {Clutter, Gio, GLib, GObject, Gtk, Meta, Shell, St} = imports.gi;
|
import Gio from 'gi://Gio';
|
||||||
|
import GLib from 'gi://GLib';
|
||||||
|
import GObject from 'gi://GObject';
|
||||||
|
import Gtk from 'gi://Gtk';
|
||||||
|
import Meta from 'gi://Meta';
|
||||||
|
import Shell from 'gi://Shell';
|
||||||
|
import St from 'gi://St';
|
||||||
|
|
||||||
const DND = imports.ui.dnd;
|
import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
|
||||||
const Main = imports.ui.main;
|
|
||||||
const Overview = imports.ui.overview;
|
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
|
||||||
|
|
||||||
const Me = ExtensionUtils.getCurrentExtension();
|
import * as DND from 'resource:///org/gnome/shell/ui/dnd.js';
|
||||||
const {WindowPicker, WindowPickerToggle} = Me.imports.windowPicker;
|
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||||
const {WorkspaceIndicator} = Me.imports.workspaceIndicator;
|
import * as Overview from 'resource:///org/gnome/shell/ui/overview.js';
|
||||||
|
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
|
||||||
|
|
||||||
const _ = ExtensionUtils.gettext;
|
import {WindowPicker, WindowPickerToggle} from './windowPicker.js';
|
||||||
|
import {WorkspaceIndicator} from './workspaceIndicator.js';
|
||||||
|
|
||||||
const ICON_TEXTURE_SIZE = 24;
|
const ICON_TEXTURE_SIZE = 24;
|
||||||
const DND_ACTIVATE_TIMEOUT = 500;
|
const DND_ACTIVATE_TIMEOUT = 500;
|
||||||
@@ -51,10 +55,6 @@ class WindowContextMenu extends PopupMenu.PopupMenu {
|
|||||||
});
|
});
|
||||||
this.addMenuItem(this._minimizeItem);
|
this.addMenuItem(this._minimizeItem);
|
||||||
|
|
||||||
this._notifyMinimizedId = this._metaWindow.connect(
|
|
||||||
'notify::minimized', this._updateMinimizeItem.bind(this));
|
|
||||||
this._updateMinimizeItem();
|
|
||||||
|
|
||||||
this._maximizeItem = new PopupMenu.PopupMenuItem('');
|
this._maximizeItem = new PopupMenu.PopupMenuItem('');
|
||||||
this._maximizeItem.connect('activate', () => {
|
this._maximizeItem.connect('activate', () => {
|
||||||
if (this._metaWindow.get_maximized() === Meta.MaximizeFlags.BOTH)
|
if (this._metaWindow.get_maximized() === Meta.MaximizeFlags.BOTH)
|
||||||
@@ -64,21 +64,20 @@ class WindowContextMenu extends PopupMenu.PopupMenu {
|
|||||||
});
|
});
|
||||||
this.addMenuItem(this._maximizeItem);
|
this.addMenuItem(this._maximizeItem);
|
||||||
|
|
||||||
this._notifyMaximizedHId = this._metaWindow.connect(
|
|
||||||
'notify::maximized-horizontally',
|
|
||||||
this._updateMaximizeItem.bind(this));
|
|
||||||
this._notifyMaximizedVId = this._metaWindow.connect(
|
|
||||||
'notify::maximized-vertically',
|
|
||||||
this._updateMaximizeItem.bind(this));
|
|
||||||
this._updateMaximizeItem();
|
|
||||||
|
|
||||||
this._closeItem = new PopupMenu.PopupMenuItem(_('Close'));
|
this._closeItem = new PopupMenu.PopupMenuItem(_('Close'));
|
||||||
this._closeItem.connect('activate', () => {
|
this._closeItem.connect('activate', () => {
|
||||||
this._metaWindow.delete(global.get_current_time());
|
this._metaWindow.delete(global.get_current_time());
|
||||||
});
|
});
|
||||||
this.addMenuItem(this._closeItem);
|
this.addMenuItem(this._closeItem);
|
||||||
|
|
||||||
this.actor.connect('destroy', this._onDestroy.bind(this));
|
this._metaWindow.connectObject(
|
||||||
|
'notify::minimized', this._updateMinimizeItem.bind(this),
|
||||||
|
'notify::maximized-horizontally', this._updateMaximizeItem.bind(this),
|
||||||
|
'notify::maximized-vertically', this._updateMaximizeItem.bind(this),
|
||||||
|
this);
|
||||||
|
|
||||||
|
this._updateMinimizeItem();
|
||||||
|
this._updateMaximizeItem();
|
||||||
|
|
||||||
this.connect('open-state-changed', () => {
|
this.connect('open-state-changed', () => {
|
||||||
if (!this.isOpen)
|
if (!this.isOpen)
|
||||||
@@ -101,12 +100,6 @@ class WindowContextMenu extends PopupMenu.PopupMenu {
|
|||||||
this._maximizeItem.label.text = maximized
|
this._maximizeItem.label.text = maximized
|
||||||
? _('Unmaximize') : _('Maximize');
|
? _('Unmaximize') : _('Maximize');
|
||||||
}
|
}
|
||||||
|
|
||||||
_onDestroy() {
|
|
||||||
this._metaWindow.disconnect(this._notifyMinimizedId);
|
|
||||||
this._metaWindow.disconnect(this._notifyMaximizedHId);
|
|
||||||
this._metaWindow.disconnect(this._notifyMaximizedVId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class WindowTitle extends St.BoxLayout {
|
class WindowTitle extends St.BoxLayout {
|
||||||
@@ -130,20 +123,19 @@ class WindowTitle extends St.BoxLayout {
|
|||||||
this.add(this.label_actor);
|
this.add(this.label_actor);
|
||||||
|
|
||||||
this._textureCache = St.TextureCache.get_default();
|
this._textureCache = St.TextureCache.get_default();
|
||||||
this._iconThemeChangedId = this._textureCache.connect(
|
this._textureCache.connectObject('icon-theme-changed',
|
||||||
'icon-theme-changed', this._updateIcon.bind(this));
|
() => this._updateIcon(), this);
|
||||||
this._notifyWmClass = this._metaWindow.connect_after(
|
|
||||||
'notify::wm-class', this._updateIcon.bind(this));
|
this._metaWindow.connectObject(
|
||||||
this._notifyAppId = this._metaWindow.connect_after(
|
'notify::wm-class',
|
||||||
'notify::gtk-application-id', this._updateIcon.bind(this));
|
() => this._updateIcon(), GObject.ConnectFlags.AFTER,
|
||||||
|
'notify::gtk-application-id',
|
||||||
|
() => this._updateIcon(), GObject.ConnectFlags.AFTER,
|
||||||
|
'notify::title', () => this._updateTitle(),
|
||||||
|
'notify::minimized', () => this._minimizedChanged(),
|
||||||
|
this);
|
||||||
|
|
||||||
this._updateIcon();
|
this._updateIcon();
|
||||||
|
|
||||||
this.connect('destroy', this._onDestroy.bind(this));
|
|
||||||
|
|
||||||
this._notifyTitleId = this._metaWindow.connect(
|
|
||||||
'notify::title', this._updateTitle.bind(this));
|
|
||||||
this._notifyMinimizedId = this._metaWindow.connect(
|
|
||||||
'notify::minimized', this._minimizedChanged.bind(this));
|
|
||||||
this._minimizedChanged();
|
this._minimizedChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,14 +165,6 @@ class WindowTitle extends St.BoxLayout {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onDestroy() {
|
|
||||||
this._textureCache.disconnect(this._iconThemeChangedId);
|
|
||||||
this._metaWindow.disconnect(this._notifyTitleId);
|
|
||||||
this._metaWindow.disconnect(this._notifyMinimizedId);
|
|
||||||
this._metaWindow.disconnect(this._notifyWmClass);
|
|
||||||
this._metaWindow.disconnect(this._notifyAppId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class BaseButton extends St.Button {
|
class BaseButton extends St.Button {
|
||||||
@@ -216,16 +200,16 @@ class BaseButton extends St.Button {
|
|||||||
|
|
||||||
this._contextMenuManager = new PopupMenu.PopupMenuManager(this);
|
this._contextMenuManager = new PopupMenu.PopupMenuManager(this);
|
||||||
|
|
||||||
this._switchWorkspaceId = global.window_manager.connect(
|
global.window_manager.connectObject('switch-workspace',
|
||||||
'switch-workspace', this._updateVisibility.bind(this));
|
() => this._updateVisibility(), this);
|
||||||
|
|
||||||
if (this._perMonitor) {
|
if (this._perMonitor) {
|
||||||
this._windowEnteredMonitorId = global.display.connect(
|
global.display.connectObject(
|
||||||
'window-entered-monitor',
|
'window-entered-monitor',
|
||||||
this._windowEnteredOrLeftMonitor.bind(this));
|
this._windowEnteredOrLeftMonitor.bind(this),
|
||||||
this._windowLeftMonitorId = global.display.connect(
|
|
||||||
'window-left-monitor',
|
'window-left-monitor',
|
||||||
this._windowEnteredOrLeftMonitor.bind(this));
|
this._windowEnteredOrLeftMonitor.bind(this),
|
||||||
|
this);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._tooltip = new Tooltip(this, {
|
this._tooltip = new Tooltip(this, {
|
||||||
@@ -334,9 +318,11 @@ class BaseButton extends St.Button {
|
|||||||
if (isOpen)
|
if (isOpen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const extension = Extension.lookupByURL(import.meta.url);
|
||||||
|
|
||||||
let [x, y] = global.get_pointer();
|
let [x, y] = global.get_pointer();
|
||||||
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
|
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
|
||||||
if (Me.stateObj.someWindowListContains(actor))
|
if (extension.someWindowListContains(actor))
|
||||||
actor.sync_hover();
|
actor.sync_hover();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,16 +377,6 @@ class BaseButton extends St.Button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_onDestroy() {
|
_onDestroy() {
|
||||||
global.window_manager.disconnect(this._switchWorkspaceId);
|
|
||||||
|
|
||||||
if (this._windowEnteredMonitorId)
|
|
||||||
global.display.disconnect(this._windowEnteredMonitorId);
|
|
||||||
this._windowEnteredMonitorId = 0;
|
|
||||||
|
|
||||||
if (this._windowLeftMonitorId)
|
|
||||||
global.display.disconnect(this._windowLeftMonitorId);
|
|
||||||
this._windowLeftMonitorId = 0;
|
|
||||||
|
|
||||||
this._tooltip.destroy();
|
this._tooltip.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -414,9 +390,11 @@ class WindowButton extends BaseButton {
|
|||||||
super(perMonitor, monitorIndex);
|
super(perMonitor, monitorIndex);
|
||||||
|
|
||||||
this.metaWindow = metaWindow;
|
this.metaWindow = metaWindow;
|
||||||
this._skipTaskbarId = metaWindow.connect('notify::skip-taskbar', () => {
|
metaWindow.connectObject(
|
||||||
this._updateVisibility();
|
'notify::skip-taskbar', () => this._updateVisibility(),
|
||||||
});
|
'workspace-changed', () => this._updateVisibility(),
|
||||||
|
this);
|
||||||
|
|
||||||
this._updateVisibility();
|
this._updateVisibility();
|
||||||
|
|
||||||
this._windowTitle = new WindowTitle(this.metaWindow);
|
this._windowTitle = new WindowTitle(this.metaWindow);
|
||||||
@@ -430,11 +408,8 @@ class WindowButton extends BaseButton {
|
|||||||
this._contextMenuManager.addMenu(this._contextMenu);
|
this._contextMenuManager.addMenu(this._contextMenu);
|
||||||
Main.uiGroup.add_actor(this._contextMenu.actor);
|
Main.uiGroup.add_actor(this._contextMenu.actor);
|
||||||
|
|
||||||
this._workspaceChangedId = this.metaWindow.connect(
|
global.display.connectObject('notify::focus-window',
|
||||||
'workspace-changed', this._updateVisibility.bind(this));
|
() => this._updateStyle(), this);
|
||||||
|
|
||||||
this._notifyFocusId = global.display.connect(
|
|
||||||
'notify::focus-window', this._updateStyle.bind(this));
|
|
||||||
this._updateStyle();
|
this._updateStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,9 +453,6 @@ class WindowButton extends BaseButton {
|
|||||||
|
|
||||||
_onDestroy() {
|
_onDestroy() {
|
||||||
super._onDestroy();
|
super._onDestroy();
|
||||||
this.metaWindow.disconnect(this._skipTaskbarId);
|
|
||||||
this.metaWindow.disconnect(this._workspaceChangedId);
|
|
||||||
global.display.disconnect(this._notifyFocusId);
|
|
||||||
this._contextMenu.destroy();
|
this._contextMenu.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -597,18 +569,17 @@ class AppButton extends BaseButton {
|
|||||||
Main.uiGroup.add_actor(this._appContextMenu.actor);
|
Main.uiGroup.add_actor(this._appContextMenu.actor);
|
||||||
|
|
||||||
this._textureCache = St.TextureCache.get_default();
|
this._textureCache = St.TextureCache.get_default();
|
||||||
this._iconThemeChangedId =
|
this._textureCache.connectObject('icon-theme-changed', () => {
|
||||||
this._textureCache.connect('icon-theme-changed', () => {
|
this._icon.child = app.create_icon_texture(ICON_TEXTURE_SIZE);
|
||||||
this._icon.child = app.create_icon_texture(ICON_TEXTURE_SIZE);
|
}, this);
|
||||||
});
|
|
||||||
|
|
||||||
this._windowsChangedId = this.app.connect(
|
this.app.connectObject('windows-changed',
|
||||||
'windows-changed', this._windowsChanged.bind(this));
|
() => this._windowsChanged(), this);
|
||||||
this._windowsChanged();
|
this._windowsChanged();
|
||||||
|
|
||||||
this._windowTracker = Shell.WindowTracker.get_default();
|
this._windowTracker = Shell.WindowTracker.get_default();
|
||||||
this._notifyFocusId = this._windowTracker.connect(
|
this._windowTracker.connectObject('notify::focus-app',
|
||||||
'notify::focus-app', this._updateStyle.bind(this));
|
() => this._updateStyle(), this);
|
||||||
this._updateStyle();
|
this._updateStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -728,9 +699,6 @@ class AppButton extends BaseButton {
|
|||||||
|
|
||||||
_onDestroy() {
|
_onDestroy() {
|
||||||
super._onDestroy();
|
super._onDestroy();
|
||||||
this._textureCache.disconnect(this._iconThemeChangedId);
|
|
||||||
this._windowTracker.disconnect(this._notifyFocusId);
|
|
||||||
this.app.disconnect(this._windowsChangedId);
|
|
||||||
this._menu.destroy();
|
this._menu.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -740,7 +708,7 @@ class WindowList extends St.Widget {
|
|||||||
GObject.registerClass(this);
|
GObject.registerClass(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(perMonitor, monitor) {
|
constructor(perMonitor, monitor, settings) {
|
||||||
super({
|
super({
|
||||||
name: 'panel',
|
name: 'panel',
|
||||||
style_class: 'bottom-panel solid',
|
style_class: 'bottom-panel solid',
|
||||||
@@ -787,12 +755,12 @@ class WindowList extends St.Widget {
|
|||||||
indicatorsBox.add_child(this._workspaceIndicator.container);
|
indicatorsBox.add_child(this._workspaceIndicator.container);
|
||||||
|
|
||||||
this._mutterSettings = new Gio.Settings({schema_id: 'org.gnome.mutter'});
|
this._mutterSettings = new Gio.Settings({schema_id: 'org.gnome.mutter'});
|
||||||
this._workspacesOnlyOnPrimaryChangedId = this._mutterSettings.connect(
|
this._mutterSettings.connectObject(
|
||||||
'changed::workspaces-only-on-primary',
|
'changed::workspaces-only-on-primary',
|
||||||
this._updateWorkspaceIndicatorVisibility.bind(this));
|
() => this._updateWorkspaceIndicatorVisibility(),
|
||||||
this._dynamicWorkspacesChangedId = this._mutterSettings.connect(
|
|
||||||
'changed::dynamic-workspaces',
|
'changed::dynamic-workspaces',
|
||||||
this._updateWorkspaceIndicatorVisibility.bind(this));
|
() => this._updateWorkspaceIndicatorVisibility(),
|
||||||
|
this);
|
||||||
this._updateWorkspaceIndicatorVisibility();
|
this._updateWorkspaceIndicatorVisibility();
|
||||||
|
|
||||||
this._menuManager = new PopupMenu.PopupMenuManager(this);
|
this._menuManager = new PopupMenu.PopupMenuManager(this);
|
||||||
@@ -810,59 +778,58 @@ class WindowList extends St.Widget {
|
|||||||
this._updatePosition();
|
this._updatePosition();
|
||||||
|
|
||||||
this._appSystem = Shell.AppSystem.get_default();
|
this._appSystem = Shell.AppSystem.get_default();
|
||||||
this._appStateChangedId = this._appSystem.connect(
|
this._appSystem.connectObject('app-state-changed',
|
||||||
'app-state-changed', this._onAppStateChanged.bind(this));
|
this._onAppStateChanged.bind(this), this);
|
||||||
|
|
||||||
// Hack: OSK gesture is tied to visibility, piggy-back on that
|
// Hack: OSK gesture is tied to visibility, piggy-back on that
|
||||||
this._keyboardVisiblechangedId =
|
Main.keyboard._bottomDragAction.connectObject('notify::enabled',
|
||||||
Main.keyboard._bottomDragAction.connect('notify::enabled',
|
action => {
|
||||||
action => {
|
const visible = !action.enabled;
|
||||||
const visible = !action.enabled;
|
if (visible) {
|
||||||
if (visible) {
|
Main.uiGroup.set_child_above_sibling(
|
||||||
Main.uiGroup.set_child_above_sibling(
|
this, Main.layoutManager.keyboardBox);
|
||||||
this, Main.layoutManager.keyboardBox);
|
} else {
|
||||||
} else {
|
Main.uiGroup.set_child_above_sibling(
|
||||||
Main.uiGroup.set_child_above_sibling(
|
this, Main.layoutManager.panelBox);
|
||||||
this, Main.layoutManager.panelBox);
|
}
|
||||||
}
|
this._updateKeyboardAnchor();
|
||||||
this._updateKeyboardAnchor();
|
}, this);
|
||||||
});
|
|
||||||
|
|
||||||
let workspaceManager = global.workspace_manager;
|
let workspaceManager = global.workspace_manager;
|
||||||
|
|
||||||
this._nWorkspacesChangedId = workspaceManager.connect(
|
workspaceManager.connectObject('notify::n-workspaces',
|
||||||
'notify::n-workspaces', this._updateWorkspaceIndicatorVisibility.bind(this));
|
() => this._updateWorkspaceIndicatorVisibility(), this);
|
||||||
this._updateWorkspaceIndicatorVisibility();
|
this._updateWorkspaceIndicatorVisibility();
|
||||||
|
|
||||||
this._switchWorkspaceId = global.window_manager.connect(
|
global.window_manager.connectObject('switch-workspace',
|
||||||
'switch-workspace', this._checkGrouping.bind(this));
|
() => this._checkGrouping(), this);
|
||||||
|
|
||||||
this._overviewShowingId = Main.overview.connect('showing', () => {
|
Main.overview.connectObject(
|
||||||
this.hide();
|
'showing', () => {
|
||||||
this._updateKeyboardAnchor();
|
this.hide();
|
||||||
});
|
|
||||||
|
|
||||||
this._overviewHidingId = Main.overview.connect('hidden', () => {
|
|
||||||
this.visible = !this._monitor.inFullscreen;
|
|
||||||
this._updateKeyboardAnchor();
|
|
||||||
});
|
|
||||||
|
|
||||||
this._fullscreenChangedId =
|
|
||||||
global.display.connect('in-fullscreen-changed', () => {
|
|
||||||
// Work-around for initial change from unknown to !fullscreen
|
|
||||||
if (Main.overview.visible)
|
|
||||||
this.hide();
|
|
||||||
this._updateKeyboardAnchor();
|
this._updateKeyboardAnchor();
|
||||||
});
|
},
|
||||||
|
'hidden', () => {
|
||||||
|
this.visible = !this._monitor.inFullscreen;
|
||||||
|
this._updateKeyboardAnchor();
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
global.display.connectObject('in-fullscreen-changed', () => {
|
||||||
|
// Work-around for initial change from unknown to !fullscreen
|
||||||
|
if (Main.overview.visible)
|
||||||
|
this.hide();
|
||||||
|
this._updateKeyboardAnchor();
|
||||||
|
}, this);
|
||||||
|
|
||||||
this._windowSignals = new Map();
|
this._windowSignals = new Map();
|
||||||
this._windowCreatedId = global.display.connect(
|
this._windowCreatedId = global.display.connect(
|
||||||
'window-created', (dsp, win) => this._addWindow(win));
|
'window-created', (dsp, win) => this._addWindow(win));
|
||||||
|
|
||||||
this._dragBeginId = Main.xdndHandler.connect('drag-begin',
|
Main.xdndHandler.connectObject(
|
||||||
this._monitorDrag.bind(this));
|
'drag-begin', () => this._monitorDrag(),
|
||||||
this._dragEndId = Main.xdndHandler.connect('drag-end',
|
'drag-end', () => this._stopMonitoringDrag(),
|
||||||
this._stopMonitoringDrag.bind(this));
|
this);
|
||||||
|
|
||||||
this._dragMonitor = {
|
this._dragMonitor = {
|
||||||
dragMotion: this._onDragMotion.bind(this),
|
dragMotion: this._onDragMotion.bind(this),
|
||||||
};
|
};
|
||||||
@@ -870,7 +837,7 @@ class WindowList extends St.Widget {
|
|||||||
this._dndTimeoutId = 0;
|
this._dndTimeoutId = 0;
|
||||||
this._dndWindow = null;
|
this._dndWindow = null;
|
||||||
|
|
||||||
this._settings = ExtensionUtils.getSettings();
|
this._settings = settings;
|
||||||
this._settings.connect('changed::grouping-mode',
|
this._settings.connect('changed::grouping-mode',
|
||||||
() => this._groupingModeChanged());
|
() => this._groupingModeChanged());
|
||||||
this._grouped = undefined;
|
this._grouped = undefined;
|
||||||
@@ -911,7 +878,8 @@ class WindowList extends St.Widget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_updateWindowListVisibility() {
|
_updateWindowListVisibility() {
|
||||||
let visible = !Main.windowPicker.visible;
|
const {windowPicker} = Extension.lookupByURL(import.meta.url);
|
||||||
|
const visible = !windowPicker.visible;
|
||||||
|
|
||||||
this._windowList.ease({
|
this._windowList.ease({
|
||||||
opacity: visible ? 255 : 0,
|
opacity: visible ? 255 : 0,
|
||||||
@@ -1109,37 +1077,14 @@ class WindowList extends St.Widget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_onDestroy() {
|
_onDestroy() {
|
||||||
this._mutterSettings.disconnect(this._workspacesOnlyOnPrimaryChangedId);
|
|
||||||
this._mutterSettings.disconnect(this._dynamicWorkspacesChangedId);
|
|
||||||
|
|
||||||
this._workspaceIndicator.destroy();
|
this._workspaceIndicator.destroy();
|
||||||
|
|
||||||
Main.ctrlAltTabManager.removeGroup(this);
|
Main.ctrlAltTabManager.removeGroup(this);
|
||||||
|
|
||||||
this._appSystem.disconnect(this._appStateChangedId);
|
|
||||||
this._appStateChangedId = 0;
|
|
||||||
|
|
||||||
Main.keyboard._bottomDragAction.disconnect(this._keyboardVisiblechangedId);
|
|
||||||
this._keyboardVisiblechangedId = 0;
|
|
||||||
|
|
||||||
global.workspace_manager.disconnect(this._nWorkspacesChangedId);
|
|
||||||
this._nWorkspacesChangedId = 0;
|
|
||||||
|
|
||||||
global.window_manager.disconnect(this._switchWorkspaceId);
|
|
||||||
this._switchWorkspaceId = 0;
|
|
||||||
|
|
||||||
this._windowSignals.forEach((id, win) => win.disconnect(id));
|
this._windowSignals.forEach((id, win) => win.disconnect(id));
|
||||||
this._windowSignals.clear();
|
this._windowSignals.clear();
|
||||||
|
|
||||||
Main.overview.disconnect(this._overviewShowingId);
|
|
||||||
Main.overview.disconnect(this._overviewHidingId);
|
|
||||||
|
|
||||||
global.display.disconnect(this._fullscreenChangedId);
|
|
||||||
global.display.disconnect(this._windowCreatedId);
|
|
||||||
|
|
||||||
this._stopMonitoringDrag();
|
this._stopMonitoringDrag();
|
||||||
Main.xdndHandler.disconnect(this._dragBeginId);
|
|
||||||
Main.xdndHandler.disconnect(this._dragEndId);
|
|
||||||
|
|
||||||
this._settings.run_dispose();
|
this._settings.run_dispose();
|
||||||
|
|
||||||
@@ -1149,9 +1094,9 @@ class WindowList extends St.Widget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Extension {
|
export default class WindowListExtension extends Extension {
|
||||||
constructor() {
|
constructor(metadata) {
|
||||||
ExtensionUtils.initTranslations();
|
super(metadata);
|
||||||
|
|
||||||
this._windowLists = null;
|
this._windowLists = null;
|
||||||
this._hideOverviewOrig = Main.overview.hide;
|
this._hideOverviewOrig = Main.overview.hide;
|
||||||
@@ -1160,17 +1105,17 @@ class Extension {
|
|||||||
enable() {
|
enable() {
|
||||||
this._windowLists = [];
|
this._windowLists = [];
|
||||||
|
|
||||||
this._settings = ExtensionUtils.getSettings();
|
this._settings = this.getSettings();
|
||||||
this._showOnAllMonitorsChangedId = this._settings.connect(
|
this._settings.connectObject('changed::show-on-all-monitors',
|
||||||
'changed::show-on-all-monitors', this._buildWindowLists.bind(this));
|
() => this._buildWindowLists(), this);
|
||||||
|
|
||||||
this._monitorsChangedId = Main.layoutManager.connect(
|
Main.layoutManager.connectObject('monitors-changed',
|
||||||
'monitors-changed', this._buildWindowLists.bind(this));
|
() => this._buildWindowLists(), this);
|
||||||
|
|
||||||
Main.windowPicker = new WindowPicker();
|
this.windowPicker = new WindowPicker();
|
||||||
|
|
||||||
Main.overview.hide = () => {
|
Main.overview.hide = () => {
|
||||||
Main.windowPicker.close();
|
this.windowPicker.close();
|
||||||
this._hideOverviewOrig.call(Main.overview);
|
this._hideOverviewOrig.call(Main.overview);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1185,7 +1130,7 @@ class Extension {
|
|||||||
|
|
||||||
Main.layoutManager.monitors.forEach(monitor => {
|
Main.layoutManager.monitors.forEach(monitor => {
|
||||||
if (showOnAllMonitors || monitor === Main.layoutManager.primaryMonitor)
|
if (showOnAllMonitors || monitor === Main.layoutManager.primaryMonitor)
|
||||||
this._windowLists.push(new WindowList(showOnAllMonitors, monitor));
|
this._windowLists.push(new WindowList(showOnAllMonitors, monitor, this.getSettings()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1193,11 +1138,8 @@ class Extension {
|
|||||||
if (!this._windowLists)
|
if (!this._windowLists)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._settings.disconnect(this._showOnAllMonitorsChangedId);
|
this._settings.disconnectObject(this);
|
||||||
this._showOnAllMonitorsChangedId = 0;
|
Main.layoutManager.disconnectObject(this);
|
||||||
|
|
||||||
Main.layoutManager.disconnect(this._monitorsChangedId);
|
|
||||||
this._monitorsChangedId = 0;
|
|
||||||
|
|
||||||
this._windowLists.forEach(windowList => {
|
this._windowLists.forEach(windowList => {
|
||||||
windowList.hide();
|
windowList.hide();
|
||||||
@@ -1205,8 +1147,8 @@ class Extension {
|
|||||||
});
|
});
|
||||||
this._windowLists = null;
|
this._windowLists = null;
|
||||||
|
|
||||||
Main.windowPicker.destroy();
|
this.windowPicker.destroy();
|
||||||
delete Main.windowPicker;
|
delete this.windowPicker;
|
||||||
|
|
||||||
Main.overview.hide = this._hideOverviewOrig;
|
Main.overview.hide = this._hideOverviewOrig;
|
||||||
}
|
}
|
||||||
@@ -1279,10 +1221,3 @@ class Tooltip extends St.Label {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {Extension} - the extension's state object
|
|
||||||
*/
|
|
||||||
function init() {
|
|
||||||
return new Extension();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,29 +1,24 @@
|
|||||||
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
||||||
/* exported init buildPrefsWidget */
|
import Adw from 'gi://Adw';
|
||||||
|
import Gio from 'gi://Gio';
|
||||||
|
import GLib from 'gi://GLib';
|
||||||
|
import GObject from 'gi://GObject';
|
||||||
|
import Gtk from 'gi://Gtk';
|
||||||
|
|
||||||
const {Adw, Gio, GLib, GObject, Gtk} = imports.gi;
|
import {ExtensionPreferences, gettext as _} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
|
||||||
|
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
|
||||||
|
|
||||||
const _ = ExtensionUtils.gettext;
|
|
||||||
|
|
||||||
/** */
|
|
||||||
function init() {
|
|
||||||
ExtensionUtils.initTranslations();
|
|
||||||
}
|
|
||||||
|
|
||||||
class WindowListPrefsWidget extends Adw.PreferencesPage {
|
class WindowListPrefsWidget extends Adw.PreferencesPage {
|
||||||
static {
|
static {
|
||||||
GObject.registerClass(this);
|
GObject.registerClass(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor(settings) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this._actionGroup = new Gio.SimpleActionGroup();
|
this._actionGroup = new Gio.SimpleActionGroup();
|
||||||
this.insert_action_group('window-list', this._actionGroup);
|
this.insert_action_group('window-list', this._actionGroup);
|
||||||
|
|
||||||
this._settings = ExtensionUtils.getSettings();
|
this._settings = settings;
|
||||||
this._actionGroup.add_action(
|
this._actionGroup.add_action(
|
||||||
this._settings.create_action('grouping-mode'));
|
this._settings.create_action('grouping-mode'));
|
||||||
this._actionGroup.add_action(
|
this._actionGroup.add_action(
|
||||||
@@ -84,9 +79,8 @@ class WindowListPrefsWidget extends Adw.PreferencesPage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export default class WindowListPrefs extends ExtensionPreferences {
|
||||||
* @returns {Gtk.Widget} - the prefs widget
|
getPreferencesWidget() {
|
||||||
*/
|
return new WindowListPrefsWidget(this.getSettings());
|
||||||
function buildPrefsWidget() {
|
}
|
||||||
return new WindowListPrefsWidget();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
/* exported WindowPicker, WindowPickerToggle */
|
import Clutter from 'gi://Clutter';
|
||||||
const {Clutter, GObject, Shell, St} = imports.gi;
|
import GObject from 'gi://GObject';
|
||||||
|
import Shell from 'gi://Shell';
|
||||||
|
import St from 'gi://St';
|
||||||
|
|
||||||
const Layout = imports.ui.layout;
|
import {Extension, InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||||
const Main = imports.ui.main;
|
import * as Layout from 'resource:///org/gnome/shell/ui/layout.js';
|
||||||
const {WorkspacesDisplay} = imports.ui.workspacesView;
|
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||||
const Workspace = imports.ui.workspace;
|
import {WorkspacesDisplay} from 'resource:///org/gnome/shell/ui/workspacesView.js';
|
||||||
|
import * as Workspace from 'resource:///org/gnome/shell/ui/workspace.js';
|
||||||
|
|
||||||
const {VIGNETTE_BRIGHTNESS} = imports.ui.lightbox;
|
import {VIGNETTE_BRIGHTNESS} from 'resource:///org/gnome/shell/ui/lightbox.js';
|
||||||
const {
|
import {
|
||||||
SIDE_CONTROLS_ANIMATION_TIME,
|
SIDE_CONTROLS_ANIMATION_TIME,
|
||||||
OverviewAdjustment,
|
OverviewAdjustment,
|
||||||
ControlsState,
|
ControlsState
|
||||||
} = imports.ui.overviewControls;
|
} from 'resource:///org/gnome/shell/ui/overviewControls.js';
|
||||||
|
|
||||||
class MyWorkspacesDisplay extends WorkspacesDisplay {
|
class MyWorkspacesDisplay extends WorkspacesDisplay {
|
||||||
static {
|
static {
|
||||||
@@ -32,12 +35,13 @@ class MyWorkspacesDisplay extends WorkspacesDisplay {
|
|||||||
|
|
||||||
super(controls, workspaceAdjustment, overviewAdjustment);
|
super(controls, workspaceAdjustment, overviewAdjustment);
|
||||||
|
|
||||||
|
this._windowPicker = controls;
|
||||||
|
|
||||||
this._workspaceAdjustment = workspaceAdjustment;
|
this._workspaceAdjustment = workspaceAdjustment;
|
||||||
this._workspaceAdjustment.actor = this;
|
this._workspaceAdjustment.actor = this;
|
||||||
|
|
||||||
this._nWorkspacesChangedId =
|
workspaceManager.connectObject('notify::n-workspaces',
|
||||||
workspaceManager.connect('notify::n-workspaces',
|
() => this._updateAdjustment(), this);
|
||||||
this._updateAdjustment.bind(this));
|
|
||||||
|
|
||||||
this.add_constraint(
|
this.add_constraint(
|
||||||
new Layout.MonitorConstraint({
|
new Layout.MonitorConstraint({
|
||||||
@@ -48,7 +52,7 @@ class MyWorkspacesDisplay extends WorkspacesDisplay {
|
|||||||
|
|
||||||
prepareToEnterOverview(...args) {
|
prepareToEnterOverview(...args) {
|
||||||
if (!this._scrollEventId) {
|
if (!this._scrollEventId) {
|
||||||
this._scrollEventId = Main.windowPicker.connect('scroll-event',
|
this._scrollEventId = this._windowPicker.connect('scroll-event',
|
||||||
this._onScrollEvent.bind(this));
|
this._onScrollEvent.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +61,7 @@ class MyWorkspacesDisplay extends WorkspacesDisplay {
|
|||||||
|
|
||||||
vfunc_hide(...args) {
|
vfunc_hide(...args) {
|
||||||
if (this._scrollEventId > 0)
|
if (this._scrollEventId > 0)
|
||||||
Main.windowPicker.disconnect(this._scrollEventId);
|
this._windowPicker.disconnect(this._scrollEventId);
|
||||||
this._scrollEventId = 0;
|
this._scrollEventId = 0;
|
||||||
|
|
||||||
super.vfunc_hide(...args);
|
super.vfunc_hide(...args);
|
||||||
@@ -70,86 +74,9 @@ class MyWorkspacesDisplay extends WorkspacesDisplay {
|
|||||||
value: workspaceManager.get_active_workspace_index(),
|
value: workspaceManager.get_active_workspace_index(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_onDestroy() {
|
|
||||||
if (this._nWorkspacesChangedId)
|
|
||||||
global.workspace_manager.disconnect(this._nWorkspacesChangedId);
|
|
||||||
this._nWorkspacesChangedId = 0;
|
|
||||||
|
|
||||||
super._onDestroy();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyWorkspace extends Workspace.Workspace {
|
export class WindowPicker extends Clutter.Actor {
|
||||||
static {
|
|
||||||
GObject.registerClass(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(...args) {
|
|
||||||
super(...args);
|
|
||||||
|
|
||||||
this._adjChangedId =
|
|
||||||
this._overviewAdjustment.connect('notify::value', () => {
|
|
||||||
const {value: progress} = this._overviewAdjustment;
|
|
||||||
const brightness = 1 - (1 - VIGNETTE_BRIGHTNESS) * progress;
|
|
||||||
for (const bg of this._background?._backgroundGroup ?? []) {
|
|
||||||
bg.content.set({
|
|
||||||
vignette: true,
|
|
||||||
brightness,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_onDestroy() {
|
|
||||||
super._onDestroy();
|
|
||||||
|
|
||||||
if (this._adjChangedId)
|
|
||||||
this._overviewAdjustment.disconnect(this._adjChangedId);
|
|
||||||
this._adjChangedId = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyWorkspaceBackground extends Workspace.WorkspaceBackground {
|
|
||||||
static {
|
|
||||||
GObject.registerClass(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
_updateBorderRadius() {
|
|
||||||
}
|
|
||||||
|
|
||||||
vfunc_allocate(box) {
|
|
||||||
this.set_allocation(box);
|
|
||||||
|
|
||||||
const themeNode = this.get_theme_node();
|
|
||||||
const contentBox = themeNode.get_content_box(box);
|
|
||||||
|
|
||||||
this._bin.allocate(contentBox);
|
|
||||||
|
|
||||||
const [contentWidth, contentHeight] = contentBox.get_size();
|
|
||||||
const monitor = Main.layoutManager.monitors[this._monitorIndex];
|
|
||||||
const xRatio = contentWidth / this._workarea.width;
|
|
||||||
const yRatio = contentHeight / this._workarea.height;
|
|
||||||
|
|
||||||
const right = area => area.x + area.width;
|
|
||||||
const bottom = area => area.y + area.height;
|
|
||||||
|
|
||||||
const offsets = {
|
|
||||||
left: xRatio * (this._workarea.x - monitor.x),
|
|
||||||
right: xRatio * (right(monitor) - right(this._workarea)),
|
|
||||||
top: yRatio * (this._workarea.y - monitor.y),
|
|
||||||
bottom: yRatio * (bottom(monitor) - bottom(this._workarea)),
|
|
||||||
};
|
|
||||||
|
|
||||||
contentBox.set_origin(-offsets.left, -offsets.top);
|
|
||||||
contentBox.set_size(
|
|
||||||
offsets.left + contentWidth + offsets.right,
|
|
||||||
offsets.top + contentHeight + offsets.bottom);
|
|
||||||
this._backgroundGroup.allocate(contentBox);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var WindowPicker = class WindowPicker extends Clutter.Actor {
|
|
||||||
static [GObject.signals] = {
|
static [GObject.signals] = {
|
||||||
'open-state-changed': {param_types: [GObject.TYPE_BOOLEAN]},
|
'open-state-changed': {param_types: [GObject.TYPE_BOOLEAN]},
|
||||||
};
|
};
|
||||||
@@ -164,11 +91,11 @@ var WindowPicker = class WindowPicker extends Clutter.Actor {
|
|||||||
this._visible = false;
|
this._visible = false;
|
||||||
this._modal = false;
|
this._modal = false;
|
||||||
|
|
||||||
this._overlayKeyId = 0;
|
|
||||||
this._stageKeyPressId = 0;
|
this._stageKeyPressId = 0;
|
||||||
|
|
||||||
this._adjustment = new OverviewAdjustment(this);
|
this._adjustment = new OverviewAdjustment(this);
|
||||||
|
|
||||||
|
this._injectionManager = new InjectionManager();
|
||||||
this.connect('destroy', this._onDestroy.bind(this));
|
this.connect('destroy', this._onDestroy.bind(this));
|
||||||
|
|
||||||
global.bind_property('screen-width',
|
global.bind_property('screen-width',
|
||||||
@@ -186,21 +113,78 @@ var WindowPicker = class WindowPicker extends Clutter.Actor {
|
|||||||
if (!Main.sessionMode.hasOverview) {
|
if (!Main.sessionMode.hasOverview) {
|
||||||
this._injectBackgroundShade();
|
this._injectBackgroundShade();
|
||||||
|
|
||||||
this._overlayKeyId = global.display.connect('overlay-key', () => {
|
global.display.connectObject('overlay-key', () => {
|
||||||
if (!this._visible)
|
if (!this._visible)
|
||||||
this.open();
|
this.open();
|
||||||
else
|
else
|
||||||
this.close();
|
this.close();
|
||||||
});
|
}, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_injectBackgroundShade() {
|
_injectBackgroundShade() {
|
||||||
this._origWorkspace = Workspace.Workspace;
|
const backgroundProto = Workspace.WorkspaceBackground.prototype;
|
||||||
this._origWorkspaceBackground = Workspace.WorkspaceBackground;
|
this._injectionManager.overrideMethod(backgroundProto, '_updateBorderRadius',
|
||||||
|
() => {
|
||||||
|
return function () {};
|
||||||
|
});
|
||||||
|
this._injectionManager.overrideMethod(backgroundProto, 'vfunc_allocate',
|
||||||
|
() => {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
|
return function (box) {
|
||||||
|
this.set_allocation(box);
|
||||||
|
|
||||||
Workspace.Workspace = MyWorkspace;
|
const themeNode = this.get_theme_node();
|
||||||
Workspace.WorkspaceBackground = MyWorkspaceBackground;
|
const contentBox = themeNode.get_content_box(box);
|
||||||
|
|
||||||
|
this._bin.allocate(contentBox);
|
||||||
|
|
||||||
|
const [contentWidth, contentHeight] = contentBox.get_size();
|
||||||
|
const monitor = Main.layoutManager.monitors[this._monitorIndex];
|
||||||
|
const xRatio = contentWidth / this._workarea.width;
|
||||||
|
const yRatio = contentHeight / this._workarea.height;
|
||||||
|
|
||||||
|
const right = area => area.x + area.width;
|
||||||
|
const bottom = area => area.y + area.height;
|
||||||
|
|
||||||
|
const offsets = {
|
||||||
|
left: xRatio * (this._workarea.x - monitor.x),
|
||||||
|
right: xRatio * (right(monitor) - right(this._workarea)),
|
||||||
|
top: yRatio * (this._workarea.y - monitor.y),
|
||||||
|
bottom: yRatio * (bottom(monitor) - bottom(this._workarea)),
|
||||||
|
};
|
||||||
|
|
||||||
|
contentBox.set_origin(-offsets.left, -offsets.top);
|
||||||
|
contentBox.set_size(
|
||||||
|
offsets.left + contentWidth + offsets.right,
|
||||||
|
offsets.top + contentHeight + offsets.bottom);
|
||||||
|
this._backgroundGroup.allocate(contentBox);
|
||||||
|
};
|
||||||
|
/* eslint-enable */
|
||||||
|
});
|
||||||
|
this._injectionManager.overrideMethod(backgroundProto, 'vfunc_parent_set',
|
||||||
|
() => {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
|
return function () {
|
||||||
|
setTimeout(() => {
|
||||||
|
const parent = this.get_parent();
|
||||||
|
if (!parent)
|
||||||
|
return;
|
||||||
|
|
||||||
|
parent._overviewAdjustment.connectObject('notify::value', () => {
|
||||||
|
const {value: progress} = parent._overviewAdjustment;
|
||||||
|
const brightness = 1 - (1 - VIGNETTE_BRIGHTNESS) * progress;
|
||||||
|
for (const bg of this._backgroundGroup ?? []) {
|
||||||
|
bg.content.set({
|
||||||
|
vignette: true,
|
||||||
|
brightness,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/* eslint-enable */
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get visible() {
|
get visible() {
|
||||||
@@ -306,27 +290,15 @@ var WindowPicker = class WindowPicker extends Clutter.Actor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_onDestroy() {
|
_onDestroy() {
|
||||||
if (this._origWorkspace)
|
this._injectionManager.clear();
|
||||||
Workspace.Workspace = this._origWorkspace;
|
|
||||||
|
|
||||||
if (this._origWorkspaceBackground)
|
|
||||||
Workspace.WorkspaceBackground = this._origWorkspaceBackground;
|
|
||||||
|
|
||||||
if (this._monitorsChangedId)
|
|
||||||
Main.layoutManager.disconnect(this._monitorsChangedId);
|
|
||||||
this._monitorsChangedId = 0;
|
|
||||||
|
|
||||||
if (this._overlayKeyId)
|
|
||||||
global.display.disconnect(this._overlayKeyId);
|
|
||||||
this._overlayKeyId = 0;
|
|
||||||
|
|
||||||
if (this._stageKeyPressId)
|
if (this._stageKeyPressId)
|
||||||
global.stage.disconnect(this._stageKeyPressId);
|
global.stage.disconnect(this._stageKeyPressId);
|
||||||
this._stageKeyPressId = 0;
|
this._stageKeyPressId = 0;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
var WindowPickerToggle = class WindowPickerToggle extends St.Button {
|
export class WindowPickerToggle extends St.Button {
|
||||||
static {
|
static {
|
||||||
GObject.registerClass(this);
|
GObject.registerClass(this);
|
||||||
}
|
}
|
||||||
@@ -350,15 +322,16 @@ var WindowPickerToggle = class WindowPickerToggle extends St.Button {
|
|||||||
toggle_mode: true,
|
toggle_mode: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const {windowPicker} = Extension.lookupByURL(import.meta.url);
|
||||||
this.connect('notify::checked', () => {
|
this.connect('notify::checked', () => {
|
||||||
if (this.checked)
|
if (this.checked)
|
||||||
Main.windowPicker.open();
|
windowPicker.open();
|
||||||
else
|
else
|
||||||
Main.windowPicker.close();
|
windowPicker.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
Main.windowPicker.connect('open-state-changed', () => {
|
windowPicker.connect('open-state-changed', () => {
|
||||||
this.checked = Main.windowPicker.visible;
|
this.checked = windowPicker.visible;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
/* exported WorkspaceIndicator */
|
import Clutter from 'gi://Clutter';
|
||||||
const {Clutter, Gio, GObject, Meta, St} = imports.gi;
|
import Gio from 'gi://Gio';
|
||||||
|
import GObject from 'gi://GObject';
|
||||||
|
import Meta from 'gi://Meta';
|
||||||
|
import St from 'gi://St';
|
||||||
|
|
||||||
const DND = imports.ui.dnd;
|
import {gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
|
||||||
const Main = imports.ui.main;
|
|
||||||
const PanelMenu = imports.ui.panelMenu;
|
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
|
||||||
|
|
||||||
const _ = ExtensionUtils.gettext;
|
import * as DND from 'resource:///org/gnome/shell/ui/dnd.js';
|
||||||
|
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||||
|
import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
|
||||||
|
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
|
||||||
|
|
||||||
const TOOLTIP_OFFSET = 6;
|
const TOOLTIP_OFFSET = 6;
|
||||||
const TOOLTIP_ANIMATION_TIME = 150;
|
const TOOLTIP_ANIMATION_TIME = 150;
|
||||||
@@ -29,20 +31,17 @@ class WindowPreview extends St.Button {
|
|||||||
|
|
||||||
this._window = window;
|
this._window = window;
|
||||||
|
|
||||||
this.connect('destroy', this._onDestroy.bind(this));
|
this._window.connectObject(
|
||||||
|
'size-changed', () => this.queue_relayout(),
|
||||||
this._sizeChangedId = this._window.connect('size-changed',
|
'position-changed', () => {
|
||||||
() => this.queue_relayout());
|
|
||||||
this._positionChangedId = this._window.connect('position-changed',
|
|
||||||
() => {
|
|
||||||
this._updateVisible();
|
this._updateVisible();
|
||||||
this.queue_relayout();
|
this.queue_relayout();
|
||||||
});
|
},
|
||||||
this._minimizedChangedId = this._window.connect('notify::minimized',
|
'notify::minimized', this._updateVisible.bind(this),
|
||||||
this._updateVisible.bind(this));
|
this);
|
||||||
|
|
||||||
this._focusChangedId = global.display.connect('notify::focus-window',
|
global.display.connectObject('notify::focus-window',
|
||||||
this._onFocusChanged.bind(this));
|
this._onFocusChanged.bind(this), this);
|
||||||
this._onFocusChanged();
|
this._onFocusChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,13 +50,6 @@ class WindowPreview extends St.Button {
|
|||||||
return this._window;
|
return this._window;
|
||||||
}
|
}
|
||||||
|
|
||||||
_onDestroy() {
|
|
||||||
this._window.disconnect(this._sizeChangedId);
|
|
||||||
this._window.disconnect(this._positionChangedId);
|
|
||||||
this._window.disconnect(this._minimizedChangedId);
|
|
||||||
global.display.disconnect(this._focusChangedId);
|
|
||||||
}
|
|
||||||
|
|
||||||
_onFocusChanged() {
|
_onFocusChanged() {
|
||||||
if (global.display.focus_window === this._window)
|
if (global.display.focus_window === this._window)
|
||||||
this.add_style_class_name('active');
|
this.add_style_class_name('active');
|
||||||
@@ -138,16 +130,13 @@ class WorkspaceThumbnail extends St.Button {
|
|||||||
let workspaceManager = global.workspace_manager;
|
let workspaceManager = global.workspace_manager;
|
||||||
this._workspace = workspaceManager.get_workspace_by_index(index);
|
this._workspace = workspaceManager.get_workspace_by_index(index);
|
||||||
|
|
||||||
this._windowAddedId = this._workspace.connect('window-added',
|
this._workspace.connectObject(
|
||||||
(ws, window) => {
|
'window-added', (ws, window) => this._addWindow(window),
|
||||||
this._addWindow(window);
|
'window-removed', (ws, window) => this._removeWindow(window),
|
||||||
});
|
this);
|
||||||
this._windowRemovedId = this._workspace.connect('window-removed',
|
|
||||||
(ws, window) => {
|
global.display.connectObject('restacked',
|
||||||
this._removeWindow(window);
|
this._onRestacked.bind(this), this);
|
||||||
});
|
|
||||||
this._restackedId = global.display.connect('restacked',
|
|
||||||
this._onRestacked.bind(this));
|
|
||||||
|
|
||||||
this._workspace.list_windows().forEach(w => this._addWindow(w));
|
this._workspace.list_windows().forEach(w => this._addWindow(w));
|
||||||
this._onRestacked();
|
this._onRestacked();
|
||||||
@@ -245,14 +234,10 @@ class WorkspaceThumbnail extends St.Button {
|
|||||||
|
|
||||||
_onDestroy() {
|
_onDestroy() {
|
||||||
this._tooltip.destroy();
|
this._tooltip.destroy();
|
||||||
|
|
||||||
this._workspace.disconnect(this._windowAddedId);
|
|
||||||
this._workspace.disconnect(this._windowRemovedId);
|
|
||||||
global.display.disconnect(this._restackedId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var WorkspaceIndicator = class WorkspaceIndicator extends PanelMenu.Button {
|
export class WorkspaceIndicator extends PanelMenu.Button {
|
||||||
static {
|
static {
|
||||||
GObject.registerClass(this);
|
GObject.registerClass(this);
|
||||||
}
|
}
|
||||||
@@ -295,14 +280,11 @@ var WorkspaceIndicator = class WorkspaceIndicator extends PanelMenu.Button {
|
|||||||
|
|
||||||
this._workspacesItems = [];
|
this._workspacesItems = [];
|
||||||
|
|
||||||
this._workspaceManagerSignals = [
|
workspaceManager.connectObject(
|
||||||
workspaceManager.connect('notify::n-workspaces',
|
'notify::n-workspaces', this._nWorkspacesChanged.bind(this), GObject.ConnectFlags.AFTER,
|
||||||
this._nWorkspacesChanged.bind(this)),
|
'workspace-switched', this._onWorkspaceSwitched.bind(this), GObject.ConnectFlags.AFTER,
|
||||||
workspaceManager.connect_after('workspace-switched',
|
'notify::layout-rows', this._updateThumbnailVisibility.bind(this),
|
||||||
this._onWorkspaceSwitched.bind(this)),
|
this);
|
||||||
workspaceManager.connect('notify::layout-rows',
|
|
||||||
this._updateThumbnailVisibility.bind(this)),
|
|
||||||
];
|
|
||||||
|
|
||||||
this.connect('scroll-event', this._onScrollEvent.bind(this));
|
this.connect('scroll-event', this._onScrollEvent.bind(this));
|
||||||
this._updateMenu();
|
this._updateMenu();
|
||||||
@@ -310,20 +292,8 @@ var WorkspaceIndicator = class WorkspaceIndicator extends PanelMenu.Button {
|
|||||||
this._updateThumbnailVisibility();
|
this._updateThumbnailVisibility();
|
||||||
|
|
||||||
this._settings = new Gio.Settings({schema_id: 'org.gnome.desktop.wm.preferences'});
|
this._settings = new Gio.Settings({schema_id: 'org.gnome.desktop.wm.preferences'});
|
||||||
this._settingsChangedId = this._settings.connect(
|
this._settings.connectObject('changed::workspace-names',
|
||||||
'changed::workspace-names', this._updateMenuLabels.bind(this));
|
() => this._updateMenuLabels(), this);
|
||||||
}
|
|
||||||
|
|
||||||
_onDestroy() {
|
|
||||||
for (let i = 0; i < this._workspaceManagerSignals.length; i++)
|
|
||||||
global.workspace_manager.disconnect(this._workspaceManagerSignals[i]);
|
|
||||||
|
|
||||||
if (this._settingsChangedId) {
|
|
||||||
this._settings.disconnect(this._settingsChangedId);
|
|
||||||
this._settingsChangedId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
super._onDestroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateThumbnailVisibility() {
|
_updateThumbnailVisibility() {
|
||||||
@@ -447,4 +417,4 @@ var WorkspaceIndicator = class WorkspaceIndicator extends PanelMenu.Button {
|
|||||||
let newIndex = this._currentWorkspace + diff;
|
let newIndex = this._currentWorkspace + diff;
|
||||||
this._activate(newIndex);
|
this._activate(newIndex);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -1,276 +1,290 @@
|
|||||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
/* exported init */
|
import Clutter from 'gi://Clutter';
|
||||||
const {Clutter, Graphene, GObject, St} = imports.gi;
|
import Graphene from 'gi://Graphene';
|
||||||
|
import St from 'gi://St';
|
||||||
|
|
||||||
const Main = imports.ui.main;
|
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||||
const OverviewControls = imports.ui.overviewControls;
|
import * as OverviewControls from 'resource:///org/gnome/shell/ui/overviewControls.js';
|
||||||
const Workspace = imports.ui.workspace;
|
import {InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||||
const WorkspacesView = imports.ui.workspacesView;
|
import {WindowPreview} from 'resource:///org/gnome/shell/ui/windowPreview.js';
|
||||||
|
import {Workspace} from 'resource:///org/gnome/shell/ui/workspace.js';
|
||||||
|
import {WorkspacesView} from 'resource:///org/gnome/shell/ui/workspacesView.js';
|
||||||
|
|
||||||
const WINDOW_SLOT = 4;
|
const WINDOW_SLOT = 4;
|
||||||
|
|
||||||
class MyWorkspace extends Workspace.Workspace {
|
export default class Extension {
|
||||||
static {
|
|
||||||
GObject.registerClass(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(...args) {
|
|
||||||
super(...args);
|
|
||||||
|
|
||||||
if (this.metaWorkspace && this.metaWorkspace.index() < 9) {
|
|
||||||
this._tip = new St.Label({
|
|
||||||
style_class: 'extension-windowsNavigator-window-tooltip',
|
|
||||||
visible: false,
|
|
||||||
});
|
|
||||||
this.add_actor(this._tip);
|
|
||||||
|
|
||||||
this.connect('notify::scale-x', () => {
|
|
||||||
this._tip.set_scale(1 / this.scale_x, 1 / this.scale_x);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this._tip = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vfunc_allocate(box) {
|
|
||||||
super.vfunc_allocate(box);
|
|
||||||
|
|
||||||
if (this._tip)
|
|
||||||
this._tip.allocate_preferred_size(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
showTooltip() {
|
|
||||||
if (!this._tip)
|
|
||||||
return;
|
|
||||||
this._tip.text = (this.metaWorkspace.index() + 1).toString();
|
|
||||||
this._tip.show();
|
|
||||||
this.set_child_below_sibling(this._tip, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
hideTooltip() {
|
|
||||||
if (this._tip)
|
|
||||||
this._tip.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
getWindowWithTooltip(id) {
|
|
||||||
const {layoutManager} = this._container;
|
|
||||||
const slot = layoutManager._windowSlots[id - 1];
|
|
||||||
return slot ? slot[WINDOW_SLOT].metaWindow : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
showWindowsTooltips() {
|
|
||||||
const {layoutManager} = this._container;
|
|
||||||
for (let i = 0; i < layoutManager._windowSlots.length; i++) {
|
|
||||||
if (layoutManager._windowSlots[i])
|
|
||||||
layoutManager._windowSlots[i][WINDOW_SLOT].showTooltip(`${i + 1}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hideWindowsTooltips() {
|
|
||||||
const {layoutManager} = this._container;
|
|
||||||
for (let i in layoutManager._windowSlots) {
|
|
||||||
if (layoutManager._windowSlots[i])
|
|
||||||
layoutManager._windowSlots[i][WINDOW_SLOT].hideTooltip();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// overriding _addWindowClone to apply the tooltip patch on the cloned
|
|
||||||
// windowPreview
|
|
||||||
_addWindowClone(metaWindow) {
|
|
||||||
const clone = super._addWindowClone(metaWindow);
|
|
||||||
|
|
||||||
// appling the tooltip patch
|
|
||||||
(function patchPreview() {
|
|
||||||
this._text = new St.Label({
|
|
||||||
style_class: 'extension-windowsNavigator-window-tooltip',
|
|
||||||
visible: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
this._text.add_constraint(new Clutter.BindConstraint({
|
|
||||||
source: this.windowContainer,
|
|
||||||
coordinate: Clutter.BindCoordinate.POSITION,
|
|
||||||
}));
|
|
||||||
this._text.add_constraint(new Clutter.AlignConstraint({
|
|
||||||
source: this.windowContainer,
|
|
||||||
align_axis: Clutter.AlignAxis.X_AXIS,
|
|
||||||
pivot_point: new Graphene.Point({x: 0.5, y: -1}),
|
|
||||||
factor: this._closeButtonSide === St.Side.LEFT ? 1 : 0,
|
|
||||||
}));
|
|
||||||
this._text.add_constraint(new Clutter.AlignConstraint({
|
|
||||||
source: this.windowContainer,
|
|
||||||
align_axis: Clutter.AlignAxis.Y_AXIS,
|
|
||||||
pivot_point: new Graphene.Point({x: -1, y: 0.5}),
|
|
||||||
factor: 0,
|
|
||||||
}));
|
|
||||||
|
|
||||||
this.add_child(this._text);
|
|
||||||
}).call(clone);
|
|
||||||
|
|
||||||
clone.showTooltip = function (text) {
|
|
||||||
this._text.set({text});
|
|
||||||
this._text.show();
|
|
||||||
};
|
|
||||||
|
|
||||||
clone.hideTooltip = function () {
|
|
||||||
if (this._text && this._text.visible)
|
|
||||||
this._text.hide();
|
|
||||||
};
|
|
||||||
|
|
||||||
return clone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyWorkspacesView extends WorkspacesView.WorkspacesView {
|
|
||||||
static {
|
|
||||||
GObject.registerClass(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(...args) {
|
|
||||||
super(...args);
|
|
||||||
|
|
||||||
this._pickWorkspace = false;
|
|
||||||
this._pickWindow = false;
|
|
||||||
this._keyPressEventId =
|
|
||||||
global.stage.connect('key-press-event', this._onKeyPress.bind(this));
|
|
||||||
this._keyReleaseEventId =
|
|
||||||
global.stage.connect('key-release-event', this._onKeyRelease.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
_onDestroy() {
|
|
||||||
super._onDestroy();
|
|
||||||
|
|
||||||
global.stage.disconnect(this._keyPressEventId);
|
|
||||||
global.stage.disconnect(this._keyReleaseEventId);
|
|
||||||
}
|
|
||||||
|
|
||||||
_hideTooltips() {
|
|
||||||
if (global.stage.get_key_focus() === global.stage)
|
|
||||||
global.stage.set_key_focus(this._prevFocusActor);
|
|
||||||
this._pickWindow = false;
|
|
||||||
for (let i = 0; i < this._workspaces.length; i++)
|
|
||||||
this._workspaces[i].hideWindowsTooltips();
|
|
||||||
}
|
|
||||||
|
|
||||||
_hideWorkspacesTooltips() {
|
|
||||||
global.stage.set_key_focus(this._prevFocusActor);
|
|
||||||
this._pickWorkspace = false;
|
|
||||||
for (let i = 0; i < this._workspaces.length; i++)
|
|
||||||
this._workspaces[i].hideTooltip();
|
|
||||||
}
|
|
||||||
|
|
||||||
_onKeyRelease(s, o) {
|
|
||||||
if (this._pickWindow &&
|
|
||||||
(o.get_key_symbol() === Clutter.KEY_Alt_L ||
|
|
||||||
o.get_key_symbol() === Clutter.KEY_Alt_R))
|
|
||||||
this._hideTooltips();
|
|
||||||
if (this._pickWorkspace &&
|
|
||||||
(o.get_key_symbol() === Clutter.KEY_Control_L ||
|
|
||||||
o.get_key_symbol() === Clutter.KEY_Control_R))
|
|
||||||
this._hideWorkspacesTooltips();
|
|
||||||
}
|
|
||||||
|
|
||||||
_onKeyPress(s, o) {
|
|
||||||
const {ControlsState} = OverviewControls;
|
|
||||||
if (this._overviewAdjustment.value !== ControlsState.WINDOW_PICKER)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
let workspaceManager = global.workspace_manager;
|
|
||||||
|
|
||||||
if ((o.get_key_symbol() === Clutter.KEY_Alt_L ||
|
|
||||||
o.get_key_symbol() === Clutter.KEY_Alt_R) &&
|
|
||||||
!this._pickWorkspace) {
|
|
||||||
this._prevFocusActor = global.stage.get_key_focus();
|
|
||||||
global.stage.set_key_focus(null);
|
|
||||||
this._active = workspaceManager.get_active_workspace_index();
|
|
||||||
this._pickWindow = true;
|
|
||||||
this._workspaces[workspaceManager.get_active_workspace_index()].showWindowsTooltips();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ((o.get_key_symbol() === Clutter.KEY_Control_L ||
|
|
||||||
o.get_key_symbol() === Clutter.KEY_Control_R) &&
|
|
||||||
!this._pickWindow) {
|
|
||||||
this._prevFocusActor = global.stage.get_key_focus();
|
|
||||||
global.stage.set_key_focus(null);
|
|
||||||
this._pickWorkspace = true;
|
|
||||||
for (let i = 0; i < this._workspaces.length; i++)
|
|
||||||
this._workspaces[i].showTooltip();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (global.stage.get_key_focus() !== global.stage)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// ignore shift presses, they're required to get numerals in azerty keyboards
|
|
||||||
if ((this._pickWindow || this._pickWorkspace) &&
|
|
||||||
(o.get_key_symbol() === Clutter.KEY_Shift_L ||
|
|
||||||
o.get_key_symbol() === Clutter.KEY_Shift_R))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (this._pickWindow) {
|
|
||||||
if (this._active !== workspaceManager.get_active_workspace_index()) {
|
|
||||||
this._hideTooltips();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let c = o.get_key_symbol() - Clutter.KEY_KP_0;
|
|
||||||
if (c > 9 || c <= 0) {
|
|
||||||
c = o.get_key_symbol() - Clutter.KEY_0;
|
|
||||||
if (c > 9 || c <= 0) {
|
|
||||||
this._hideTooltips();
|
|
||||||
global.log(c);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let win = this._workspaces[this._active].getWindowWithTooltip(c);
|
|
||||||
this._hideTooltips();
|
|
||||||
|
|
||||||
if (win)
|
|
||||||
Main.activateWindow(win, global.get_current_time());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (this._pickWorkspace) {
|
|
||||||
let c = o.get_key_symbol() - Clutter.KEY_KP_0;
|
|
||||||
if (c > 9 || c <= 0) {
|
|
||||||
c = o.get_key_symbol() - Clutter.KEY_0;
|
|
||||||
if (c > 9 || c <= 0) {
|
|
||||||
this._hideWorkspacesTooltips();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let workspace = this._workspaces[c - 1];
|
|
||||||
if (workspace !== undefined)
|
|
||||||
workspace.metaWorkspace.activate(global.get_current_time());
|
|
||||||
|
|
||||||
this._hideWorkspacesTooltips();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Extension {
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this._origWorkspace = Workspace.Workspace;
|
this._injectionManager = new InjectionManager();
|
||||||
this._origWorkspacesView = WorkspacesView.WorkspacesView;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enable() {
|
enable() {
|
||||||
Workspace.Workspace = MyWorkspace;
|
const previewProto = WindowPreview.prototype;
|
||||||
WorkspacesView.WorkspacesView = MyWorkspacesView;
|
|
||||||
|
this._injectionManager.overrideMethod(previewProto, '_init', originalMethod => {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
|
return function (...args) {
|
||||||
|
originalMethod.call(this, ...args);
|
||||||
|
|
||||||
|
this._text = new St.Label({
|
||||||
|
style_class: 'extension-windowsNavigator-window-tooltip',
|
||||||
|
visible: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
this._text.add_constraint(new Clutter.BindConstraint({
|
||||||
|
source: this.windowContainer,
|
||||||
|
coordinate: Clutter.BindCoordinate.POSITION,
|
||||||
|
}));
|
||||||
|
this._text.add_constraint(new Clutter.AlignConstraint({
|
||||||
|
source: this.windowContainer,
|
||||||
|
align_axis: Clutter.AlignAxis.X_AXIS,
|
||||||
|
pivot_point: new Graphene.Point({x: 0.5, y: -1}),
|
||||||
|
factor: this._closeButtonSide === St.Side.LEFT ? 1 : 0,
|
||||||
|
}));
|
||||||
|
this._text.add_constraint(new Clutter.AlignConstraint({
|
||||||
|
source: this.windowContainer,
|
||||||
|
align_axis: Clutter.AlignAxis.Y_AXIS,
|
||||||
|
pivot_point: new Graphene.Point({x: -1, y: 0.5}),
|
||||||
|
factor: 0,
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.add_child(this._text);
|
||||||
|
};
|
||||||
|
/* eslint-enable */
|
||||||
|
});
|
||||||
|
this._injectionManager.overrideMethod(previewProto, 'showTooltip', () => {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
|
return function (text) {
|
||||||
|
this._text.set({text});
|
||||||
|
this._text.show();
|
||||||
|
};
|
||||||
|
/* eslint-enable */
|
||||||
|
});
|
||||||
|
this._injectionManager.overrideMethod(previewProto, 'hideTooltip', () => {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
|
return function () {
|
||||||
|
this._text?.hide();
|
||||||
|
};
|
||||||
|
/* eslint-enable */
|
||||||
|
});
|
||||||
|
|
||||||
|
const workspaceProto = Workspace.prototype;
|
||||||
|
this._injectionManager.overrideMethod(workspaceProto, '_init', originalMethod => {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
|
return function (...args) {
|
||||||
|
originalMethod.call(this, ...args);
|
||||||
|
|
||||||
|
if (this.metaWorkspace && this.metaWorkspace.index() < 9) {
|
||||||
|
this._tip = new St.Label({
|
||||||
|
style_class: 'extension-windowsNavigator-window-tooltip',
|
||||||
|
visible: false,
|
||||||
|
});
|
||||||
|
this.add_actor(this._tip);
|
||||||
|
|
||||||
|
this.connect('notify::scale-x', () => {
|
||||||
|
this._tip.set_scale(1 / this.scale_x, 1 / this.scale_x);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this._tip = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/* eslint-enable */
|
||||||
|
});
|
||||||
|
this._injectionManager.overrideMethod(workspaceProto, 'vfunc_allocate', originalMethod => {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
|
return function (box) {
|
||||||
|
originalMethod.call(this, box);
|
||||||
|
|
||||||
|
this._tip?.allocate_preferred_size(0, 0);
|
||||||
|
};
|
||||||
|
/* eslint-enable */
|
||||||
|
});
|
||||||
|
this._injectionManager.overrideMethod(workspaceProto, 'showTooltip', () => {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
|
return function () {
|
||||||
|
if (!this._tip)
|
||||||
|
return;
|
||||||
|
this._tip.text = (this.metaWorkspace.index() + 1).toString();
|
||||||
|
this._tip.show();
|
||||||
|
this.set_child_below_sibling(this._tip, null);
|
||||||
|
};
|
||||||
|
/* eslint-enable */
|
||||||
|
});
|
||||||
|
this._injectionManager.overrideMethod(workspaceProto, 'hideTooltip', () => {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
|
return function () {
|
||||||
|
this._tip?.hide();
|
||||||
|
};
|
||||||
|
/* eslint-enable */
|
||||||
|
});
|
||||||
|
this._injectionManager.overrideMethod(workspaceProto, 'getWindowWithTooltip', () => {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
|
return function (id) {
|
||||||
|
const {layoutManager} = this._container;
|
||||||
|
const slot = layoutManager._windowSlots[id - 1];
|
||||||
|
return slot ? slot[WINDOW_SLOT].metaWindow : null;
|
||||||
|
};
|
||||||
|
/* eslint-enable */
|
||||||
|
});
|
||||||
|
this._injectionManager.overrideMethod(workspaceProto, 'showWindowsTooltips', () => {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
|
return function () {
|
||||||
|
const {layoutManager} = this._container;
|
||||||
|
for (let i = 0; i < layoutManager._windowSlots.length; i++) {
|
||||||
|
if (layoutManager._windowSlots[i])
|
||||||
|
layoutManager._windowSlots[i][WINDOW_SLOT].showTooltip(`${i + 1}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/* eslint-enable */
|
||||||
|
});
|
||||||
|
this._injectionManager.overrideMethod(workspaceProto, 'hideWindowsTooltips', () => {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
|
return function () {
|
||||||
|
const {layoutManager} = this._container;
|
||||||
|
for (let i in layoutManager._windowSlots) {
|
||||||
|
if (layoutManager._windowSlots[i])
|
||||||
|
layoutManager._windowSlots[i][WINDOW_SLOT].hideTooltip();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/* eslint-enable */
|
||||||
|
});
|
||||||
|
|
||||||
|
const viewProto = WorkspacesView.prototype;
|
||||||
|
this._injectionManager.overrideMethod(viewProto, '_init', originalMethod => {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
|
return function (...args) {
|
||||||
|
originalMethod.call(this, ...args);
|
||||||
|
|
||||||
|
this._pickWorkspace = false;
|
||||||
|
this._pickWindow = false;
|
||||||
|
global.stage.connectObject(
|
||||||
|
'key-press-event', this._onKeyPress.bind(this),
|
||||||
|
'key-release-event', this._onKeyRelease.bind(this),
|
||||||
|
this);
|
||||||
|
};
|
||||||
|
/* eslint-enable */
|
||||||
|
});
|
||||||
|
this._injectionManager.overrideMethod(viewProto, '_hideTooltips', () => {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
|
return function () {
|
||||||
|
if (global.stage.get_key_focus() === global.stage)
|
||||||
|
global.stage.set_key_focus(this._prevFocusActor);
|
||||||
|
this._pickWindow = false;
|
||||||
|
for (let i = 0; i < this._workspaces.length; i++)
|
||||||
|
this._workspaces[i].hideWindowsTooltips();
|
||||||
|
};
|
||||||
|
/* eslint-enable */
|
||||||
|
});
|
||||||
|
this._injectionManager.overrideMethod(viewProto, '_hideWorkspacesTooltips', () => {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
|
return function () {
|
||||||
|
global.stage.set_key_focus(this._prevFocusActor);
|
||||||
|
this._pickWorkspace = false;
|
||||||
|
for (let i = 0; i < this._workspaces.length; i++)
|
||||||
|
this._workspaces[i].hideTooltip();
|
||||||
|
};
|
||||||
|
/* eslint-enable */
|
||||||
|
});
|
||||||
|
this._injectionManager.overrideMethod(viewProto, '_onKeyRelease', () => {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
|
return function (actor, event) {
|
||||||
|
if (this._pickWindow &&
|
||||||
|
(event.get_key_symbol() === Clutter.KEY_Alt_L ||
|
||||||
|
event.get_key_symbol() === Clutter.KEY_Alt_R))
|
||||||
|
this._hideTooltips();
|
||||||
|
if (this._pickWorkspace &&
|
||||||
|
(event.get_key_symbol() === Clutter.KEY_Control_L ||
|
||||||
|
event.get_key_symbol() === Clutter.KEY_Control_R))
|
||||||
|
this._hideWorkspacesTooltips();
|
||||||
|
};
|
||||||
|
/* eslint-enable */
|
||||||
|
});
|
||||||
|
this._injectionManager.overrideMethod(viewProto, '_onKeyPress', () => {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
|
return function (actor, event) {
|
||||||
|
const {ControlsState} = OverviewControls;
|
||||||
|
if (this._overviewAdjustment.value !== ControlsState.WINDOW_PICKER)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
let workspaceManager = global.workspace_manager;
|
||||||
|
|
||||||
|
if ((event.get_key_symbol() === Clutter.KEY_Alt_L ||
|
||||||
|
event.get_key_symbol() === Clutter.KEY_Alt_R) &&
|
||||||
|
!this._pickWorkspace) {
|
||||||
|
this._prevFocusActor = global.stage.get_key_focus();
|
||||||
|
global.stage.set_key_focus(null);
|
||||||
|
this._active = workspaceManager.get_active_workspace_index();
|
||||||
|
this._pickWindow = true;
|
||||||
|
this._workspaces[workspaceManager.get_active_workspace_index()].showWindowsTooltips();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ((event.get_key_symbol() === Clutter.KEY_Control_L ||
|
||||||
|
event.get_key_symbol() === Clutter.KEY_Control_R) &&
|
||||||
|
!this._pickWindow) {
|
||||||
|
this._prevFocusActor = global.stage.get_key_focus();
|
||||||
|
global.stage.set_key_focus(null);
|
||||||
|
this._pickWorkspace = true;
|
||||||
|
for (let i = 0; i < this._workspaces.length; i++)
|
||||||
|
this._workspaces[i].showTooltip();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (global.stage.get_key_focus() !== global.stage)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// ignore shift presses, they're required to get numerals in azerty keyboards
|
||||||
|
if ((this._pickWindow || this._pickWorkspace) &&
|
||||||
|
(event.get_key_symbol() === Clutter.KEY_Shift_L ||
|
||||||
|
event.get_key_symbol() === Clutter.KEY_Shift_R))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (this._pickWindow) {
|
||||||
|
if (this._active !== workspaceManager.get_active_workspace_index()) {
|
||||||
|
this._hideTooltips();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let c = event.get_key_symbol() - Clutter.KEY_KP_0;
|
||||||
|
if (c > 9 || c <= 0) {
|
||||||
|
c = event.get_key_symbol() - Clutter.KEY_0;
|
||||||
|
if (c > 9 || c <= 0) {
|
||||||
|
this._hideTooltips();
|
||||||
|
log(c);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let win = this._workspaces[this._active].getWindowWithTooltip(c);
|
||||||
|
this._hideTooltips();
|
||||||
|
|
||||||
|
if (win)
|
||||||
|
Main.activateWindow(win, global.get_current_time());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (this._pickWorkspace) {
|
||||||
|
let c = event.get_key_symbol() - Clutter.KEY_KP_0;
|
||||||
|
if (c > 9 || c <= 0) {
|
||||||
|
c = event.get_key_symbol() - Clutter.KEY_0;
|
||||||
|
if (c > 9 || c <= 0) {
|
||||||
|
this._hideWorkspacesTooltips();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let workspace = this._workspaces[c - 1];
|
||||||
|
if (workspace !== undefined)
|
||||||
|
workspace.metaWorkspace.activate(global.get_current_time());
|
||||||
|
|
||||||
|
this._hideWorkspacesTooltips();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
/* eslint-enable */
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
disable() {
|
disable() {
|
||||||
Workspace.Workspace = this._origWorkspace;
|
this._injectionManager.clear();
|
||||||
WorkspacesView.WorkspacesView = this._origWorkspacesView;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {Extension} - the extension's state object
|
|
||||||
*/
|
|
||||||
function init() {
|
|
||||||
return new Extension();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
||||||
/* exported init enable disable */
|
import Clutter from 'gi://Clutter';
|
||||||
|
import Gio from 'gi://Gio';
|
||||||
|
import GObject from 'gi://GObject';
|
||||||
|
import Meta from 'gi://Meta';
|
||||||
|
import St from 'gi://St';
|
||||||
|
|
||||||
const {Clutter, Gio, GObject, Meta, St} = imports.gi;
|
import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||||
|
|
||||||
const DND = imports.ui.dnd;
|
import * as DND from 'resource:///org/gnome/shell/ui/dnd.js';
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||||
const Main = imports.ui.main;
|
import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
|
||||||
const PanelMenu = imports.ui.panelMenu;
|
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
|
||||||
|
|
||||||
const _ = ExtensionUtils.gettext;
|
|
||||||
|
|
||||||
const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
|
const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
|
||||||
const WORKSPACE_KEY = 'workspace-names';
|
const WORKSPACE_KEY = 'workspace-names';
|
||||||
@@ -34,20 +35,17 @@ class WindowPreview extends St.Button {
|
|||||||
|
|
||||||
this._window = window;
|
this._window = window;
|
||||||
|
|
||||||
this.connect('destroy', this._onDestroy.bind(this));
|
this._window.connectObject(
|
||||||
|
'size-changed', () => this.queue_relayout(),
|
||||||
this._sizeChangedId = this._window.connect('size-changed',
|
'position-changed', () => {
|
||||||
() => this.queue_relayout());
|
|
||||||
this._positionChangedId = this._window.connect('position-changed',
|
|
||||||
() => {
|
|
||||||
this._updateVisible();
|
this._updateVisible();
|
||||||
this.queue_relayout();
|
this.queue_relayout();
|
||||||
});
|
},
|
||||||
this._minimizedChangedId = this._window.connect('notify::minimized',
|
'notify::minimized', this._updateVisible.bind(this),
|
||||||
this._updateVisible.bind(this));
|
this);
|
||||||
|
|
||||||
this._focusChangedId = global.display.connect('notify::focus-window',
|
global.display.connectObject('notify::focus-window',
|
||||||
this._onFocusChanged.bind(this));
|
this._onFocusChanged.bind(this), this);
|
||||||
this._onFocusChanged();
|
this._onFocusChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,13 +54,6 @@ class WindowPreview extends St.Button {
|
|||||||
return this._window;
|
return this._window;
|
||||||
}
|
}
|
||||||
|
|
||||||
_onDestroy() {
|
|
||||||
this._window.disconnect(this._sizeChangedId);
|
|
||||||
this._window.disconnect(this._positionChangedId);
|
|
||||||
this._window.disconnect(this._minimizedChangedId);
|
|
||||||
global.display.disconnect(this._focusChangedId);
|
|
||||||
}
|
|
||||||
|
|
||||||
_onFocusChanged() {
|
_onFocusChanged() {
|
||||||
if (global.display.focus_window === this._window)
|
if (global.display.focus_window === this._window)
|
||||||
this.add_style_class_name('active');
|
this.add_style_class_name('active');
|
||||||
@@ -143,16 +134,13 @@ class WorkspaceThumbnail extends St.Button {
|
|||||||
let workspaceManager = global.workspace_manager;
|
let workspaceManager = global.workspace_manager;
|
||||||
this._workspace = workspaceManager.get_workspace_by_index(index);
|
this._workspace = workspaceManager.get_workspace_by_index(index);
|
||||||
|
|
||||||
this._windowAddedId = this._workspace.connect('window-added',
|
this._workspace.connectObject(
|
||||||
(ws, window) => {
|
'window-added', (ws, window) => this._addWindow(window),
|
||||||
this._addWindow(window);
|
'window-removed', (ws, window) => this._removeWindow(window),
|
||||||
});
|
this);
|
||||||
this._windowRemovedId = this._workspace.connect('window-removed',
|
|
||||||
(ws, window) => {
|
global.display.connectObject('restacked',
|
||||||
this._removeWindow(window);
|
this._onRestacked.bind(this), this);
|
||||||
});
|
|
||||||
this._restackedId = global.display.connect('restacked',
|
|
||||||
this._onRestacked.bind(this));
|
|
||||||
|
|
||||||
this._workspace.list_windows().forEach(w => this._addWindow(w));
|
this._workspace.list_windows().forEach(w => this._addWindow(w));
|
||||||
this._onRestacked();
|
this._onRestacked();
|
||||||
@@ -250,10 +238,6 @@ class WorkspaceThumbnail extends St.Button {
|
|||||||
|
|
||||||
_onDestroy() {
|
_onDestroy() {
|
||||||
this._tooltip.destroy();
|
this._tooltip.destroy();
|
||||||
|
|
||||||
this._workspace.disconnect(this._windowAddedId);
|
|
||||||
this._workspace.disconnect(this._windowRemovedId);
|
|
||||||
global.display.disconnect(this._restackedId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,14 +279,11 @@ class WorkspaceIndicator extends PanelMenu.Button {
|
|||||||
this._workspaceSection = new PopupMenu.PopupMenuSection();
|
this._workspaceSection = new PopupMenu.PopupMenuSection();
|
||||||
this.menu.addMenuItem(this._workspaceSection);
|
this.menu.addMenuItem(this._workspaceSection);
|
||||||
|
|
||||||
this._workspaceManagerSignals = [
|
workspaceManager.connectObject(
|
||||||
workspaceManager.connect_after('notify::n-workspaces',
|
'notify::n-workspaces', this._nWorkspacesChanged.bind(this), GObject.ConnectFlags.AFTER,
|
||||||
this._nWorkspacesChanged.bind(this)),
|
'workspace-switched', this._onWorkspaceSwitched.bind(this), GObject.ConnectFlags.AFTER,
|
||||||
workspaceManager.connect_after('workspace-switched',
|
'notify::layout-rows', this._updateThumbnailVisibility.bind(this),
|
||||||
this._onWorkspaceSwitched.bind(this)),
|
this);
|
||||||
workspaceManager.connect('notify::layout-rows',
|
|
||||||
this._updateThumbnailVisibility.bind(this)),
|
|
||||||
];
|
|
||||||
|
|
||||||
this.connect('scroll-event', this._onScrollEvent.bind(this));
|
this.connect('scroll-event', this._onScrollEvent.bind(this));
|
||||||
this._thumbnailsBox.connect('scroll-event', this._onScrollEvent.bind(this));
|
this._thumbnailsBox.connect('scroll-event', this._onScrollEvent.bind(this));
|
||||||
@@ -311,20 +292,11 @@ class WorkspaceIndicator extends PanelMenu.Button {
|
|||||||
this._updateThumbnailVisibility();
|
this._updateThumbnailVisibility();
|
||||||
|
|
||||||
this._settings = new Gio.Settings({schema_id: WORKSPACE_SCHEMA});
|
this._settings = new Gio.Settings({schema_id: WORKSPACE_SCHEMA});
|
||||||
this._settingsChangedId = this._settings.connect(
|
this._settings.connectObject(`changed::${WORKSPACE_KEY}`,
|
||||||
`changed::${WORKSPACE_KEY}`,
|
this._updateMenuLabels.bind(this), this);
|
||||||
this._updateMenuLabels.bind(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_onDestroy() {
|
_onDestroy() {
|
||||||
for (let i = 0; i < this._workspaceManagerSignals.length; i++)
|
|
||||||
global.workspace_manager.disconnect(this._workspaceManagerSignals[i]);
|
|
||||||
|
|
||||||
if (this._settingsChangedId) {
|
|
||||||
this._settings.disconnect(this._settingsChangedId);
|
|
||||||
this._settingsChangedId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Main.panel.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
|
Main.panel.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
|
||||||
|
|
||||||
super._onDestroy();
|
super._onDestroy();
|
||||||
@@ -454,20 +426,14 @@ class WorkspaceIndicator extends PanelMenu.Button {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
export default class WorkspaceIndicatorExtension extends Extension {
|
||||||
function init() {
|
enable() {
|
||||||
ExtensionUtils.initTranslations();
|
this._indicator = new WorkspaceIndicator();
|
||||||
}
|
Main.panel.addToStatusArea('workspace-indicator', this._indicator);
|
||||||
|
}
|
||||||
|
|
||||||
let _indicator;
|
disable() {
|
||||||
|
this._indicator.destroy();
|
||||||
/** */
|
delete this._indicator;
|
||||||
function enable() {
|
}
|
||||||
_indicator = new WorkspaceIndicator();
|
|
||||||
Main.panel.addToStatusArea('workspace-indicator', _indicator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** */
|
|
||||||
function disable() {
|
|
||||||
_indicator.destroy();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
||||||
/* exported init buildPrefsWidget */
|
import Adw from 'gi://Adw';
|
||||||
|
import Gio from 'gi://Gio';
|
||||||
|
import GLib from 'gi://GLib';
|
||||||
|
import GObject from 'gi://GObject';
|
||||||
|
import Gtk from 'gi://Gtk';
|
||||||
|
import Pango from 'gi://Pango';
|
||||||
|
|
||||||
const {Adw, Gio, GLib, GObject, Gtk, Pango} = imports.gi;
|
import {ExtensionPreferences, gettext as _} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
|
||||||
|
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
|
||||||
|
|
||||||
const _ = ExtensionUtils.gettext;
|
|
||||||
const N_ = e => e;
|
const N_ = e => e;
|
||||||
|
|
||||||
const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
|
const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
|
||||||
@@ -256,14 +258,8 @@ class NewWorkspaceRow extends Adw.PreferencesRow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
export default class WorkspaceIndicatorPrefs extends ExtensionPreferences {
|
||||||
function init() {
|
getPreferencesWidget() {
|
||||||
ExtensionUtils.initTranslations();
|
return new WorkspaceSettingsWidget();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {Gtk.Widget} - the prefs widget
|
|
||||||
*/
|
|
||||||
function buildPrefsWidget() {
|
|
||||||
return new WorkspaceSettingsWidget();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,10 @@ rules:
|
|||||||
jsdoc/check-tag-names: error
|
jsdoc/check-tag-names: error
|
||||||
jsdoc/check-types: error
|
jsdoc/check-types: error
|
||||||
jsdoc/implements-on-classes: error
|
jsdoc/implements-on-classes: error
|
||||||
jsdoc/newline-after-description: error
|
jsdoc/tag-lines:
|
||||||
|
- error
|
||||||
|
- any
|
||||||
|
- startLines: 1
|
||||||
jsdoc/require-jsdoc: error
|
jsdoc/require-jsdoc: error
|
||||||
jsdoc/require-param: error
|
jsdoc/require-param: error
|
||||||
jsdoc/require-param-description: error
|
jsdoc/require-param-description: error
|
||||||
|
|||||||
@@ -10,3 +10,5 @@ rules:
|
|||||||
prefer-arrow-callback: error
|
prefer-arrow-callback: error
|
||||||
globals:
|
globals:
|
||||||
global: readonly
|
global: readonly
|
||||||
|
parserOptions:
|
||||||
|
sourceType: module
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
project('gnome-shell-extensions',
|
project('gnome-shell-extensions',
|
||||||
version: '45.alpha',
|
version: '45.beta',
|
||||||
meson_version: '>= 0.58.0',
|
meson_version: '>= 0.58.0',
|
||||||
license: 'GPL2+'
|
license: 'GPL2+'
|
||||||
)
|
)
|
||||||
|
|||||||
101
po/el.po
101
po/el.po
@@ -12,8 +12,8 @@ msgstr ""
|
|||||||
"Project-Id-Version: gnome-shell-extensions master\n"
|
"Project-Id-Version: gnome-shell-extensions master\n"
|
||||||
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/"
|
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/"
|
||||||
"issues\n"
|
"issues\n"
|
||||||
"POT-Creation-Date: 2020-05-28 00:55+0000\n"
|
"POT-Creation-Date: 2023-02-18 15:10+0000\n"
|
||||||
"PO-Revision-Date: 2020-07-14 00:40+0300\n"
|
"PO-Revision-Date: 2023-08-01 23:41+0300\n"
|
||||||
"Last-Translator: Efstathios Iosifidis <eiosifidis@gnome.org>\n"
|
"Last-Translator: Efstathios Iosifidis <eiosifidis@gnome.org>\n"
|
||||||
"Language-Team: Greek, Modern (1453-) <gnome-el-list@gnome.org>\n"
|
"Language-Team: Greek, Modern (1453-) <gnome-el-list@gnome.org>\n"
|
||||||
"Language: el\n"
|
"Language: el\n"
|
||||||
@@ -21,22 +21,31 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Generator: Poedit 1.8.7.1\n"
|
"X-Generator: Poedit 3.3.2\n"
|
||||||
"X-Project-Style: gnome\n"
|
"X-Project-Style: gnome\n"
|
||||||
|
|
||||||
#: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
|
#: data/gnome-classic.desktop.in:3
|
||||||
msgid "GNOME Classic"
|
msgid "GNOME Classic"
|
||||||
msgstr "GNOME Classic"
|
msgstr "GNOME Classic"
|
||||||
|
|
||||||
#: data/gnome-classic.desktop.in:4
|
#: data/gnome-classic.desktop.in:4 data/gnome-classic-wayland.desktop.in:4
|
||||||
|
#: data/gnome-classic-xorg.desktop.in:4
|
||||||
msgid "This session logs you into GNOME Classic"
|
msgid "This session logs you into GNOME Classic"
|
||||||
msgstr "Αυτή η συνεδρία σας συνδέει στο GNOME Classic"
|
msgstr "Αυτή η συνεδρία σας συνδέει στο GNOME Classic"
|
||||||
|
|
||||||
#: extensions/apps-menu/extension.js:113
|
#: data/gnome-classic-wayland.desktop.in:3
|
||||||
|
msgid "GNOME Classic on Wayland"
|
||||||
|
msgstr "GNOME Classic σε Wayland"
|
||||||
|
|
||||||
|
#: data/gnome-classic-xorg.desktop.in:3
|
||||||
|
msgid "GNOME Classic on Xorg"
|
||||||
|
msgstr "GNOME Classic σε Xorg"
|
||||||
|
|
||||||
|
#: extensions/apps-menu/extension.js:118
|
||||||
msgid "Favorites"
|
msgid "Favorites"
|
||||||
msgstr "Αγαπημένα"
|
msgstr "Αγαπημένα"
|
||||||
|
|
||||||
#: extensions/apps-menu/extension.js:369
|
#: extensions/apps-menu/extension.js:380
|
||||||
msgid "Applications"
|
msgid "Applications"
|
||||||
msgstr "Εφαρμογές"
|
msgstr "Εφαρμογές"
|
||||||
|
|
||||||
@@ -53,26 +62,26 @@ msgstr ""
|
|||||||
"(όνομα αρχείου επιφάνειας εργασίας), ακολουθούμενη από άνω-κάτω τελεία και "
|
"(όνομα αρχείου επιφάνειας εργασίας), ακολουθούμενη από άνω-κάτω τελεία και "
|
||||||
"τον αριθμό του χώρου εργασίας"
|
"τον αριθμό του χώρου εργασίας"
|
||||||
|
|
||||||
#: extensions/auto-move-windows/prefs.js:35
|
#: extensions/auto-move-windows/prefs.js:152
|
||||||
msgid "Workspace Rules"
|
msgid "Workspace Rules"
|
||||||
msgstr "Κανόνες χώρων εργασίας"
|
msgstr "Κανόνες χώρων εργασίας"
|
||||||
|
|
||||||
#: extensions/auto-move-windows/prefs.js:243
|
#: extensions/auto-move-windows/prefs.js:306
|
||||||
msgid "Add Rule"
|
msgid "Add Rule"
|
||||||
msgstr "Προσθήκη κανόνα"
|
msgstr "Προσθήκη κανόνα"
|
||||||
|
|
||||||
#. TRANSLATORS: %s is the filesystem name
|
#. TRANSLATORS: %s is the filesystem name
|
||||||
#: extensions/drive-menu/extension.js:112
|
#: extensions/drive-menu/extension.js:126
|
||||||
#: extensions/places-menu/placeDisplay.js:233
|
#: extensions/places-menu/placeDisplay.js:212
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Ejecting drive “%s” failed:"
|
msgid "Ejecting drive “%s” failed:"
|
||||||
msgstr "Αποτυχία εξαγωγής του δίσκου «%s»:"
|
msgstr "Αποτυχία εξαγωγής του δίσκου «%s»:"
|
||||||
|
|
||||||
#: extensions/drive-menu/extension.js:128
|
#: extensions/drive-menu/extension.js:145
|
||||||
msgid "Removable devices"
|
msgid "Removable devices"
|
||||||
msgstr "Αφαιρούμενες συσκευές"
|
msgstr "Αφαιρούμενες συσκευές"
|
||||||
|
|
||||||
#: extensions/drive-menu/extension.js:155
|
#: extensions/drive-menu/extension.js:167
|
||||||
msgid "Open Files"
|
msgid "Open Files"
|
||||||
msgstr "Άνοιγμα αρχείων"
|
msgstr "Άνοιγμα αρχείων"
|
||||||
|
|
||||||
@@ -106,31 +115,31 @@ msgstr ""
|
|||||||
"στο κάτω μέρος. Η αλλαγή αυτής της ρύθμισης απαιτεί επανεκκίνηση του "
|
"στο κάτω μέρος. Η αλλαγή αυτής της ρύθμισης απαιτεί επανεκκίνηση του "
|
||||||
"κελύφους για να υπάρξει κάποιο αποτέλεσμα."
|
"κελύφους για να υπάρξει κάποιο αποτέλεσμα."
|
||||||
|
|
||||||
#: extensions/places-menu/extension.js:89
|
#: extensions/places-menu/extension.js:94
|
||||||
#: extensions/places-menu/extension.js:93
|
#: extensions/places-menu/extension.js:97
|
||||||
msgid "Places"
|
msgid "Places"
|
||||||
msgstr "Τοποθεσίες"
|
msgstr "Τοποθεσίες"
|
||||||
|
|
||||||
#: extensions/places-menu/placeDisplay.js:46
|
#: extensions/places-menu/placeDisplay.js:52
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Failed to launch “%s”"
|
msgid "Failed to launch “%s”"
|
||||||
msgstr "Αποτυχία εκκίνησης «%s»"
|
msgstr "Αποτυχία εκκίνησης «%s»"
|
||||||
|
|
||||||
#: extensions/places-menu/placeDisplay.js:61
|
#: extensions/places-menu/placeDisplay.js:67
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Failed to mount volume for “%s”"
|
msgid "Failed to mount volume for “%s”"
|
||||||
msgstr "Αποτυχία προσάρτησης τόμου για «%s»"
|
msgstr "Αποτυχία προσάρτησης τόμου για «%s»"
|
||||||
|
|
||||||
#: extensions/places-menu/placeDisplay.js:148
|
#: extensions/places-menu/placeDisplay.js:127
|
||||||
#: extensions/places-menu/placeDisplay.js:171
|
#: extensions/places-menu/placeDisplay.js:150
|
||||||
msgid "Computer"
|
msgid "Computer"
|
||||||
msgstr "Υπολογιστής"
|
msgstr "Υπολογιστής"
|
||||||
|
|
||||||
#: extensions/places-menu/placeDisplay.js:359
|
#: extensions/places-menu/placeDisplay.js:340
|
||||||
msgid "Home"
|
msgid "Home"
|
||||||
msgstr "Προσωπικός φάκελος"
|
msgstr "Προσωπικός φάκελος"
|
||||||
|
|
||||||
#: extensions/places-menu/placeDisplay.js:404
|
#: extensions/places-menu/placeDisplay.js:385
|
||||||
msgid "Browse Network"
|
msgid "Browse Network"
|
||||||
msgstr "Περιήγηση δικτύου"
|
msgstr "Περιήγηση δικτύου"
|
||||||
|
|
||||||
@@ -151,47 +160,47 @@ msgid "The name of the theme, to be loaded from ~/.themes/name/gnome-shell"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Το όνομα του θέματος που θα φορτωθεί από το ~ /.themes/name/gnome-shell"
|
"Το όνομα του θέματος που θα φορτωθεί από το ~ /.themes/name/gnome-shell"
|
||||||
|
|
||||||
#: extensions/window-list/extension.js:98
|
#: extensions/window-list/extension.js:72
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Κλείσιμο"
|
msgstr "Κλείσιμο"
|
||||||
|
|
||||||
#: extensions/window-list/extension.js:118
|
#: extensions/window-list/extension.js:92
|
||||||
msgid "Unminimize"
|
msgid "Unminimize"
|
||||||
msgstr "Αποελαχιστοποίηση"
|
msgstr "Αποελαχιστοποίηση"
|
||||||
|
|
||||||
#: extensions/window-list/extension.js:118
|
#: extensions/window-list/extension.js:92
|
||||||
msgid "Minimize"
|
msgid "Minimize"
|
||||||
msgstr "Ελαχιστοποίηση"
|
msgstr "Ελαχιστοποίηση"
|
||||||
|
|
||||||
#: extensions/window-list/extension.js:125
|
#: extensions/window-list/extension.js:99
|
||||||
msgid "Unmaximize"
|
msgid "Unmaximize"
|
||||||
msgstr "Απομεγιστοποίηση"
|
msgstr "Απομεγιστοποίηση"
|
||||||
|
|
||||||
#: extensions/window-list/extension.js:125
|
#: extensions/window-list/extension.js:99
|
||||||
msgid "Maximize"
|
msgid "Maximize"
|
||||||
msgstr "Μεγιστοποίηση"
|
msgstr "Μεγιστοποίηση"
|
||||||
|
|
||||||
#: extensions/window-list/extension.js:428
|
#: extensions/window-list/extension.js:483
|
||||||
msgid "Minimize all"
|
msgid "Minimize all"
|
||||||
msgstr "Ελαχιστοποίηση όλων"
|
msgstr "Ελαχιστοποίηση όλων"
|
||||||
|
|
||||||
#: extensions/window-list/extension.js:434
|
#: extensions/window-list/extension.js:489
|
||||||
msgid "Unminimize all"
|
msgid "Unminimize all"
|
||||||
msgstr "Αποελαχιστοποίηση όλων"
|
msgstr "Αποελαχιστοποίηση όλων"
|
||||||
|
|
||||||
#: extensions/window-list/extension.js:440
|
#: extensions/window-list/extension.js:495
|
||||||
msgid "Maximize all"
|
msgid "Maximize all"
|
||||||
msgstr "Μεγιστοποίηση όλων"
|
msgstr "Μεγιστοποίηση όλων"
|
||||||
|
|
||||||
#: extensions/window-list/extension.js:448
|
#: extensions/window-list/extension.js:503
|
||||||
msgid "Unmaximize all"
|
msgid "Unmaximize all"
|
||||||
msgstr "Απομεγιστοποίηση όλων"
|
msgstr "Απομεγιστοποίηση όλων"
|
||||||
|
|
||||||
#: extensions/window-list/extension.js:456
|
#: extensions/window-list/extension.js:511
|
||||||
msgid "Close all"
|
msgid "Close all"
|
||||||
msgstr "Κλείσιμο όλων"
|
msgstr "Κλείσιμο όλων"
|
||||||
|
|
||||||
#: extensions/window-list/extension.js:734
|
#: extensions/window-list/extension.js:795
|
||||||
msgid "Window List"
|
msgid "Window List"
|
||||||
msgstr "Λίστα παραθύρου"
|
msgstr "Λίστα παραθύρου"
|
||||||
|
|
||||||
@@ -209,7 +218,7 @@ msgstr ""
|
|||||||
"«always» (πάντα)."
|
"«always» (πάντα)."
|
||||||
|
|
||||||
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:20
|
#: extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml:20
|
||||||
#: extensions/window-list/prefs.js:100
|
#: extensions/window-list/prefs.js:79
|
||||||
msgid "Show windows from all workspaces"
|
msgid "Show windows from all workspaces"
|
||||||
msgstr "Εμφάνιση των παραθύρων από όλους τους χώρους εργασίας"
|
msgstr "Εμφάνιση των παραθύρων από όλους τους χώρους εργασίας"
|
||||||
|
|
||||||
@@ -230,41 +239,41 @@ msgstr ""
|
|||||||
"Αν θα εμφανίζεται ο κατάλογος παραθύρων όλων των συνδεμένων οθονών ή μόνο "
|
"Αν θα εμφανίζεται ο κατάλογος παραθύρων όλων των συνδεμένων οθονών ή μόνο "
|
||||||
"της κύριας οθόνης."
|
"της κύριας οθόνης."
|
||||||
|
|
||||||
#: extensions/window-list/prefs.js:29
|
#: extensions/window-list/prefs.js:35
|
||||||
msgid "Window Grouping"
|
msgid "Window Grouping"
|
||||||
msgstr "Ομαδοποίηση παραθύρου"
|
msgstr "Ομαδοποίηση παραθύρου"
|
||||||
|
|
||||||
#: extensions/window-list/prefs.js:58
|
#: extensions/window-list/prefs.js:40
|
||||||
msgid "Never group windows"
|
msgid "Never group windows"
|
||||||
msgstr "Να μη γίνεται ποτέ ομαδοποίηση παραθύρων"
|
msgstr "Να μη γίνεται ποτέ ομαδοποίηση παραθύρων"
|
||||||
|
|
||||||
#: extensions/window-list/prefs.js:59
|
#: extensions/window-list/prefs.js:41
|
||||||
msgid "Group windows when space is limited"
|
msgid "Group windows when space is limited"
|
||||||
msgstr "Ομαδοποίηση παραθύρων όταν ο χώρος είναι περιορισμένος"
|
msgstr "Ομαδοποίηση παραθύρων όταν ο χώρος είναι περιορισμένος"
|
||||||
|
|
||||||
#: extensions/window-list/prefs.js:60
|
#: extensions/window-list/prefs.js:42
|
||||||
msgid "Always group windows"
|
msgid "Always group windows"
|
||||||
msgstr "Να γίνεται πάντα ομαδοποίηση παραθύρων"
|
msgstr "Να γίνεται πάντα ομαδοποίηση παραθύρων"
|
||||||
|
|
||||||
#: extensions/window-list/prefs.js:94
|
#: extensions/window-list/prefs.js:66
|
||||||
msgid "Show on all monitors"
|
msgid "Show on all monitors"
|
||||||
msgstr "Να εμφανίζεται σε όλες τις οθόνες"
|
msgstr "Να εμφανίζεται σε όλες τις οθόνες"
|
||||||
|
|
||||||
#: extensions/window-list/workspaceIndicator.js:207
|
#: extensions/window-list/workspaceIndicator.js:261
|
||||||
#: extensions/workspace-indicator/extension.js:213
|
#: extensions/workspace-indicator/extension.js:266
|
||||||
msgid "Workspace Indicator"
|
msgid "Workspace Indicator"
|
||||||
msgstr "Δείκτης χώρου εργασίας"
|
msgstr "Δείκτης χώρου εργασίας"
|
||||||
|
|
||||||
#: extensions/workspace-indicator/prefs.js:34
|
#: extensions/workspace-indicator/prefs.js:62
|
||||||
msgid "Workspace Names"
|
|
||||||
msgstr "Ονόματα χώρων εργασίας:"
|
|
||||||
|
|
||||||
#: extensions/workspace-indicator/prefs.js:67
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Workspace %d"
|
msgid "Workspace %d"
|
||||||
msgstr "Χώρος εργασίας %d"
|
msgstr "Χώρος εργασίας %d"
|
||||||
|
|
||||||
#: extensions/workspace-indicator/prefs.js:218
|
#: extensions/workspace-indicator/prefs.js:129
|
||||||
|
msgid "Workspace Names"
|
||||||
|
msgstr "Ονόματα χώρων εργασίας"
|
||||||
|
|
||||||
|
#: extensions/workspace-indicator/prefs.js:255
|
||||||
msgid "Add Workspace"
|
msgid "Add Workspace"
|
||||||
msgstr "Προσθήκη χώρου εργασίας"
|
msgstr "Προσθήκη χώρου εργασίας"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user