From 3c77f4152e392532f5542116356d0a03183386f7 Mon Sep 17 00:00:00 2001 From: Yi <32430186+yilozt@users.noreply.github.com> Date: Sun, 15 Oct 2023 03:11:43 +0800 Subject: [PATCH 01/11] Use gettext to compile .po files --- gulp/po.js | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/gulp/po.js b/gulp/po.js index b3eb839..ac541c0 100644 --- a/gulp/po.js +++ b/gulp/po.js @@ -3,13 +3,12 @@ const { GettextExtractor, JsExtractors, HtmlExtractors } = require('gettext-extractor'); const fs = require('fs') const { uuid, version } = require('../resources/metadata.json') -const { series, src, dest } = require('gulp') -const potomo = require('gulp-potomo'); -const rename = require('gulp-rename'); +const { series } = require('gulp') const fg = require('fast-glob'); const { spawnSync } = require('child_process'); const colors = require('ansi-colors'); const { stdout } = require('process'); +const { basename } = require('path') const gen_pot = async () => { let extractor = new GettextExtractor() @@ -43,8 +42,9 @@ const gen_pot = async () => { extractor.printStats() } +const cmd = (command, args) => spawnSync(command, args, { shell: true, stdio: 'inherit' }) + const fill_pot = async () => { - const cmd = (command, args) => spawnSync(command, args, { shell: true, stdio: 'inherit' }) const pot = (await fg('po/*.pot'))[0] const po_files = await fg('po/*.po') @@ -54,15 +54,18 @@ const fill_pot = async () => { } } -const compile_po = () => - src('po/*.po') - .pipe(potomo()) - .pipe(rename(path => { - const locale = path.basename - path.dirname += `/locale/${locale}/LC_MESSAGES` - path.basename = uuid - })) - .pipe(dest('_build')) +const compile_po = async () => { + const po_files = await fg('po/*.po'); + for (const po of po_files) { + const locale = basename(po, ".po"); + const mo_path = `_build/locale/${locale}/LC_MESSAGES`; + const mo = `${mo_path}/${uuid}.mo`; + + fs.mkdirSync(mo_path, { recursive: true }); + cmd('msgfmt', [ '-o', mo, po ]); + stdout.write(colors.green(`Generate ${mo}\n`)) + } +} exports.compile_po = compile_po exports.po = series(gen_pot, fill_pot, compile_po) \ No newline at end of file From c25015859e3867014a8d54fb25577793024009fb Mon Sep 17 00:00:00 2001 From: Yi <32430186+yilozt@users.noreply.github.com> Date: Sun, 15 Oct 2023 03:13:35 +0800 Subject: [PATCH 02/11] Update build script for Gnome 45 * Delete unuseless align formatter when building --- gulp/build.js | 47 ++++++----------------------------------------- gulp/format.js | 43 ------------------------------------------- 2 files changed, 6 insertions(+), 84 deletions(-) delete mode 100644 gulp/format.js diff --git a/gulp/build.js b/gulp/build.js index 676fa0c..205779a 100644 --- a/gulp/build.js +++ b/gulp/build.js @@ -12,7 +12,6 @@ const ts = require('gulp-typescript') const prettier = require('gulp-prettier') const gulpESLintNew = require('gulp-eslint-new') const colors = require('ansi-colors') -const { align_imports } = require('./format') const { po, compile_po } = require('./po') const tsProject = ts.createProject('tsconfig.json') @@ -42,7 +41,6 @@ const compile_ts = () => tsProject.src() // Setup source .pipe(tsProject()).js // Compile ts into js .pipe(restoreWhitespace()) // Restore white space .pipe(prettier()) // Format the output - .pipe(align_imports()) // Align import statements .pipe(eslint_out()) // eslint for output .pipe(gulpESLintNew.fix()) // Auto fix .pipe(gulpESLintNew.format()) @@ -56,7 +54,6 @@ const compile_ts = () => tsProject.src() // Setup source const format = () => tsProject.src() .pipe(prettier()) // Format the source - .pipe(align_imports()) // Align import statements in source .pipe(eslint_src()) // eslint .pipe(gulpESLintNew.fix()) // Auto Fix .pipe(gulpESLintNew.format()) @@ -136,58 +133,26 @@ const replace = () => require('through2').obj(/** @param file {Vinyl} */ functio } const imports_gi = p2.includes('@gi/') || p2.includes('gi://') - const imports_shell = p2.includes('@imports') - const imports_me = p2.includes('@me') let res = null - if (imports_gi || imports_shell || imports_me) { + // Replace import .* as XXX from 'gi://XXX' + // to import XXX from 'gi://XXX' + if (imports_gi) { // We will convert `import * as Abc from 'Xyz'` // to `const Abc = imports.XXXX`, so ' * as ' is unnecessary if (p1.includes('* as')) { p1 = p1.replace('* as ', '') + ' ' } - - if (imports_gi) { - // When we import something from gi - // generate const XXX = imports.gi.XXX - p2 = 'imports.gi.' + p2.replace(/.*@gi\//, '').replace('gi://', '').replace(/-.*/, '') - } else if (imports_shell) { - // When we import something from gnome shell - // generate const XXX = imports.XXX.XXX - p2 = 'imports' + p2.replace(/.*@imports/, '').replace(/\//g, '.') - } else if (imports_me) { - // When we import local modules - // generate const XXX = Me.imports.XXX.XXX - p2 = 'Me.imports' + p2.replace(/.*@me/, '').replace(/\//g, '.') - } - res = `const ${p1} = ${p2}` - } else { - ERR_IMPORTS.push(match) - return '\n// ------------------------------------------------------------------\n' - + '// error: Can replace this import statement.\n' - + `// error: ${match}\n` - + '// ------------------------------------------------------------------\n\n' + + return `import ${p1} from '${p2}'` } - return res + return match } let replaced = file.contents.toString() - const header = 'const ExtensionUtils = imports.misc.extensionUtils;\n' - + 'const Me = ExtensionUtils.getCurrentExtension();\n\n'; - - // Add header to every js file - if (!replaced.includes(header)) { - replaced = header + replaced - } - - // replace export in output js files - replaced = replaced.replace(/^export const/gm, 'var') - .replace(/^export class (.*?) {/gm, 'var $1 = class $1 {') - .replace(/^export /gm, '') - // We will handles all import statements with this simple regex express replaced = replaced.replace(/import (.*?) from\s+?['"](.*?)['"]/gm, replace_func) file.contents = Buffer.from(replaced, encoding) diff --git a/gulp/format.js b/gulp/format.js deleted file mode 100644 index 2cbc178..0000000 --- a/gulp/format.js +++ /dev/null @@ -1,43 +0,0 @@ -const through = require('through2') - -const align_imports = () => through.obj(function (file, enc, cb) { - if (!file.contents) { - cb(null, file) - return - } - /** @type string[] */ - const lines = file.contents.toString().split('\n') - - const imports = [] - const props = [] - let max_pos_of_from = 0 - let max_pos_of_colon = 0 - lines.forEach((line, idx) => { - if (line.trim().startsWith('//') || line.trim().startsWith('* ') || line.trim().startsWith('/* ')) { - return - } - if (line.match(/.* from ['"].*?['"]/)) { - imports.push(idx) - max_pos_of_from = Math.max(max_pos_of_from, line.indexOf('from')) - } else if (line.match(/\s+.*?\!\: .*?/)) { - props.push(idx) - max_pos_of_colon = Math.max(max_pos_of_colon, line.indexOf('!:')) - } - }) - - imports.forEach(idx => { - const line = lines[idx] - const offset = max_pos_of_from - line.lastIndexOf('from') - lines[idx] = line.replace('from', ' '.repeat(offset) + 'from') - }) - props.forEach(idx => { - const line = lines[idx] - const offset = max_pos_of_colon - line.lastIndexOf('!:') - lines[idx] = line.replace('!:', ' '.repeat(offset+1) + '!:') - }) - - file.contents = Buffer.from(lines.join('\n'), enc) - cb(null, file) -}) - -exports.align_imports = align_imports \ No newline at end of file From dca925ca45fbf1bb8be44e6ee4f32ad8f357d90f Mon Sep 17 00:00:00 2001 From: Yi <32430186+yilozt@users.noreply.github.com> Date: Sun, 15 Oct 2023 03:17:30 +0800 Subject: [PATCH 03/11] Update alias of import modules extensionUtils.d.ts have been removed in gnome 45 --- @imports/extensions/extension.d.ts | 50 ++++++++++ @imports/extensions/prefs.d.ts | 35 +++++++ @imports/extensions/sharedInternals.d.ts | 119 +++++++++++++++++++++++ @imports/misc/extensionUtils.d.ts | 91 ----------------- @imports/ui/lookingGlass.d.ts | 5 +- @imports/ui/main.d.ts | 2 +- @imports/ui/windowManager.d.ts | 4 +- @imports/ui/windowPreview.d.ts | 7 +- @imports/ui/workspace.d.ts | 4 +- @imports/ui/workspaceAnimation.d.ts | 4 +- package.json | 2 +- tsconfig.json | 29 +++--- 12 files changed, 234 insertions(+), 118 deletions(-) create mode 100644 @imports/extensions/extension.d.ts create mode 100644 @imports/extensions/prefs.d.ts create mode 100644 @imports/extensions/sharedInternals.d.ts delete mode 100644 @imports/misc/extensionUtils.d.ts diff --git a/@imports/extensions/extension.d.ts b/@imports/extensions/extension.d.ts new file mode 100644 index 0000000..6ce49a9 --- /dev/null +++ b/@imports/extensions/extension.d.ts @@ -0,0 +1,50 @@ +// auto generate by tsc: +// tsc -d --allowJs /path/to/source/of/gnome-shell/js/extensions/* + +export class Extension extends ExtensionBase { + static lookupByUUID(uuid: any): any; + static defineTranslationFunctions(url: any): { + gettext: any; + ngettext: any; + pgettext: any; + }; + enable(): void; + disable(): void; + /** + * Open the extension's preferences window + */ + openPreferences(): void; +} +export const gettext: any; +export const ngettext: any; +export const pgettext: any; +export class InjectionManager { + /** + * @callback CreateOverrideFunc + * @param {Function?} originalMethod - the original method if it exists + * @returns {Function} - a function to be used as override + */ + /** + * Modify, replace or inject a method + * + * @param {object} prototype - the object (or prototype) that is modified + * @param {string} methodName - the name of the overwritten method + * @param {CreateOverrideFunc} createOverrideFunc - function to call to create the override + */ + overrideMethod(prototype: object, methodName: string, createOverrideFunc: (originalMethod: Function | null) => Function): void; + /** + * Restore the original method + * + * @param {object} prototype - the object (or prototype) that is modified + * @param {string} methodName - the name of the method to restore + */ + restoreMethod(prototype: object, methodName: string): void; + /** + * Restore all original methods and clear overrides + */ + clear(): void; + _saveMethod(prototype: any, methodName: any): any; + _installMethod(prototype: any, methodName: any, method: any): void; + #private; +} +import { ExtensionBase } from './sharedInternals.js'; diff --git a/@imports/extensions/prefs.d.ts b/@imports/extensions/prefs.d.ts new file mode 100644 index 0000000..f7e9231 --- /dev/null +++ b/@imports/extensions/prefs.d.ts @@ -0,0 +1,35 @@ +import * as Gtk from '@gi-types/gtk4' +import * as Adw from '@gi-types/adw1' + +// auto generate by tsc: +// tsc -d --allowJs /path/to/source/of/gnome-shell/js/extensions/* + +export class ExtensionPreferences extends ExtensionBase { + static lookupByUUID(uuid: any): any; + static defineTranslationFunctions(url: any): { + gettext: any; + ngettext: any; + pgettext: any; + }; + /** + * Get the single widget that implements + * the extension's preferences. + * + * @returns {Gtk.Widget} + */ + getPreferencesWidget(): Gtk.Widget; + /** + * Fill the preferences window with preferences. + * + * The default implementation adds the widget + * returned by getPreferencesWidget(). + * + * @param {Adw.PreferencesWindow} window - the preferences window + */ + fillPreferencesWindow(window: Adw.PreferencesWindow): void; + _wrapWidget(widget: any): any; +} +export const gettext: any; +export const ngettext: any; +export const pgettext: any; +import { ExtensionBase } from './sharedInternals.js'; diff --git a/@imports/extensions/sharedInternals.d.ts b/@imports/extensions/sharedInternals.d.ts new file mode 100644 index 0000000..77c8772 --- /dev/null +++ b/@imports/extensions/sharedInternals.d.ts @@ -0,0 +1,119 @@ +import * as Gio from '@gi-types/gio2' + +// auto generate by tsc: +// tsc -d --allowJs /path/to/source/of/gnome-shell/js/extensions/* + +export class ExtensionBase { + /** + * Look up an extension by URL (usually 'import.meta.url') + * + * @param {string} url - a file:// URL + */ + static lookupByURL(url: string): ExtensionBase; + /** + * Look up an extension by UUID + * + * @param {string} _uuid + */ + static lookupByUUID(_uuid: string): void; + /** + * @param {object} metadata - metadata passed in when loading the extension + */ + constructor(metadata: object); + metadata: any; + /** + * @type {string} + */ + get uuid(): string; + /** + * @type {Gio.File} + */ + get dir(): Gio.File; + /** + * @type {string} + */ + get path(): string; + /** + * Get a GSettings object for schema, using schema files in + * extensionsdir/schemas. If schema is omitted, it is taken + * from metadata['settings-schema']. + * + * @param {string=} schema - the GSettings schema id + * + * @returns {Gio.Settings} + */ + getSettings(schema?: string | undefined): Gio.Settings; + /** + * Initialize Gettext to load translations from extensionsdir/locale. If + * domain is not provided, it will be taken from metadata['gettext-domain'] + * if provided, or use the UUID + * + * @param {string=} domain - the gettext domain to use + */ + initTranslations(domain?: string | undefined): void; + /** + * Translate `str` using the extension's gettext domain + * + * @param {string} str - the string to translate + * + * @returns {string} the translated string + */ + gettext(str: string): string; + /** + * Translate `str` and choose plural form using the extension's + * gettext domain + * + * @param {string} str - the string to translate + * @param {string} strPlural - the plural form of the string + * @param {number} n - the quantity for which translation is needed + * + * @returns {string} the translated string + */ + ngettext(str: string, strPlural: string, n: number): string; + /** + * Translate `str` in the context of `context` using the extension's + * gettext domain + * + * @param {string} context - context to disambiguate `str` + * @param {string} str - the string to translate + * + * @returns {string} the translated string + */ + pgettext(context: string, str: string): string; + #private; +} +export class GettextWrapper { + constructor(extensionClass: any, url: any); + defineTranslationFunctions(): { + /** + * Translate `str` using the extension's gettext domain + * + * @param {string} str - the string to translate + * + * @returns {string} the translated string + */ + gettext: any; + /** + * Translate `str` and choose plural form using the extension's + * gettext domain + * + * @param {string} str - the string to translate + * @param {string} strPlural - the plural form of the string + * @param {number} n - the quantity for which translation is needed + * + * @returns {string} the translated string + */ + ngettext: any; + /** + * Translate `str` in the context of `context` using the extension's + * gettext domain + * + * @param {string} context - context to disambiguate `str` + * @param {string} str - the string to translate + * + * @returns {string} the translated string + */ + pgettext: any; + }; + #private; +} diff --git a/@imports/misc/extensionUtils.d.ts b/@imports/misc/extensionUtils.d.ts deleted file mode 100644 index 59272a9..0000000 --- a/@imports/misc/extensionUtils.d.ts +++ /dev/null @@ -1,91 +0,0 @@ -import * as Gio from '@gi/Gio' - -/** - * getCurrentExtension: - * - * @returns {?object} - The current extension, or null if not called from - * an extension. - */ -declare function getCurrentExtension(): { uuid: string, path:string }; -/** - * initTranslations: - * @param {string=} domain - the gettext domain to use - * - * Initialize Gettext to load translations from extensionsdir/locale. - * If @domain is not provided, it will be taken from metadata['gettext-domain'] - */ -declare function initTranslations(domain?: string | undefined): void; -/** - * gettext: - * @param {string} str - the string to translate - * - * Translate @str using the extension's gettext domain - * - * @returns {string} - the translated string - * - */ -declare function gettext(str: string): string; -/** - * ngettext: - * @param {string} str - the string to translate - * @param {string} strPlural - the plural form of the string - * @param {number} n - the quantity for which translation is needed - * - * Translate @str and choose plural form using the extension's - * gettext domain - * - * @returns {string} - the translated string - * - */ -declare function ngettext(str: string, strPlural: string, n: number): string; -/** - * pgettext: - * @param {string} context - context to disambiguate @str - * @param {string} str - the string to translate - * - * Translate @str in the context of @context using the extension's - * gettext domain - * - * @returns {string} - the translated string - * - */ -declare function pgettext(context: string, str: string): string; -declare function callExtensionGettextFunc(func: any, ...args: any[]): any; -/** - * getSettings: - * @param {string=} schema - the GSettings schema id - * @returns {Gio.Settings} - a new settings object for @schema - * - * Builds and returns a GSettings schema for @schema, using schema files - * in extensionsdir/schemas. If @schema is omitted, it is taken from - * metadata['settings-schema']. - */ -declare function getSettings(schema?: string | undefined): Gio.Settings; -/** - * openPrefs: - * - * Open the preference dialog of the current extension - */ -declare function openPrefs(): Promise; -declare function isOutOfDate(extension: any): boolean; -declare function serializeExtension(extension: any): {}; -declare function deserializeExtension(variant: any): { - metadata: {}; -}; -declare function installImporter(extension: any): void; -declare const Gettext: any; -declare const Config: any; -declare namespace ExtensionType { - const SYSTEM: number; - const PER_USER: number; -} -declare namespace ExtensionState { - const ENABLED: number; - const DISABLED: number; - const ERROR: number; - const OUT_OF_DATE: number; - const DOWNLOADING: number; - const INITIALIZED: number; - const UNINSTALLED: number; -} -declare const SERIALIZED_PROPERTIES: string[]; diff --git a/@imports/ui/lookingGlass.d.ts b/@imports/ui/lookingGlass.d.ts index 19944d1..e820999 100644 --- a/@imports/ui/lookingGlass.d.ts +++ b/@imports/ui/lookingGlass.d.ts @@ -1,6 +1,7 @@ -import * as St from '@gi/St' -import * as Clutter from '@gi/Clutter' +import * as St from 'gi://St' +import * as Clutter from 'gi://Clutter' export class Inspector extends Clutter.Actor { + constructor(looking_glass: any) connect(signal: 'closed', cb: any); open(); connect(signal: 'target', cb: (me: Inspector, target: Clutter.Actor, stageX: number, stageY: number) => void); diff --git a/@imports/ui/main.d.ts b/@imports/ui/main.d.ts index aa91a3d..b738707 100644 --- a/@imports/ui/main.d.ts +++ b/@imports/ui/main.d.ts @@ -1,5 +1,5 @@ import { LookingGlass } from "./lookingGlass"; -import * as GObject from '@gi/GObject' +import * as GObject from 'gi://GObject' export const createLookingGlass: () => LookingGlass; diff --git a/@imports/ui/windowManager.d.ts b/@imports/ui/windowManager.d.ts index 5fb2400..e82bb95 100644 --- a/@imports/ui/windowManager.d.ts +++ b/@imports/ui/windowManager.d.ts @@ -1,5 +1,5 @@ -import { WindowActor } from '@gi/Meta'; -import { WM } from '@gi/Shell' +import { WindowActor } from 'gi://Meta'; +import { WM } from 'gi://Shell' declare function getWindowDimmer(actor: any): any; diff --git a/@imports/ui/windowPreview.d.ts b/@imports/ui/windowPreview.d.ts index a9fb67f..9d7fe69 100644 --- a/@imports/ui/windowPreview.d.ts +++ b/@imports/ui/windowPreview.d.ts @@ -1,7 +1,8 @@ -import * as Shell from '@gi/Shell' -import * as Meta from '@gi/Meta' +import * as Shell from 'gi://Shell' +import * as Meta from 'gi://Meta' -export class WindowPreview extends Shell.WindowPreview { +export class WindowPreview extends Shell.WindowPreview { + [x: string]: any _addWindow (_: Meta.Window): void; _windowActor: Meta.WindowActor } diff --git a/@imports/ui/workspace.d.ts b/@imports/ui/workspace.d.ts index 0f3ad25..7d5ddc6 100644 --- a/@imports/ui/workspace.d.ts +++ b/@imports/ui/workspace.d.ts @@ -1,6 +1,6 @@ -import { Window } from '@gi/Meta' +import { Window } from 'gi://Meta' import { WindowPreview } from './windowPreview' -import { Actor } from '@gi/Clutter'; +import { Actor } from 'gi://Clutter'; export class Workspace extends Actor { _addWindowClone(metaWindow: Window): WindowPreview; diff --git a/@imports/ui/workspaceAnimation.d.ts b/@imports/ui/workspaceAnimation.d.ts index c3ed334..5d853af 100644 --- a/@imports/ui/workspaceAnimation.d.ts +++ b/@imports/ui/workspaceAnimation.d.ts @@ -1,5 +1,5 @@ -import { Window, WindowActor } from '@gi/Meta' -import { Actor, Clone } from '@gi/Clutter' +import { Window, WindowActor } from 'gi://Meta' +import { Actor, Clone } from 'gi://Clutter' export class WorkspaceAnimationController { _movingWindow: Window; diff --git a/package.json b/package.json index b3906fb..1d981d4 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "license": "GPL-3.0-or-later", "main": "src/extension.ts", "devDependencies": { + "@gi-types/adw1": "^1.1.1", "@gi-types/gtk4": "^4.6.1", "@gi-types/meta10": "^10.0.1", "@gi-types/shell0": "^0.1.1", @@ -18,7 +19,6 @@ "gulp-cli": "^2.3.0", "gulp-eslint-new": "^1.5.1", "gulp-fill-pot-po": "^2.0.2", - "gulp-potomo": "^1.1.0", "gulp-preserve-typescript-whitespace": "^1.0.3", "gulp-prettier": "^4.0.0", "gulp-rename": "^2.0.0", diff --git a/tsconfig.json b/tsconfig.json index 106c7f9..bc46c19 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compileOnSave": true, "compilerOptions": { "target": "ES2020", - "module": "es2020", + "module": "ES2020", "sourceMap": false, "strict": true, "pretty": false, @@ -11,20 +11,21 @@ "baseUrl": ".", "moduleResolution": "node", "paths": { - "@imports/*": ["@imports/*"], + "resource:///org/gnome/shell/*": ["@imports/*"], + "resource:///org/gnome/Shell/Extensions/js/*": ["@imports/*"], "@global": ["src/global.d.ts"], - "@me/*": ["src/*"], - "@gi/Gio": ["node_modules/@gi-types/gio2"], - "@gi/Gtk": ["node_modules/@gi-types/gtk4"], - "@gi/Gdk": ["node_modules/@gi-types/gdk4"], - "@gi/GLib": ["node_modules/@gi-types/glib2"], - "@gi/Meta": ["node_modules/@gi-types/meta10"], - "@gi/Clutter":["node_modules/@gi-types/clutter10"], - "@gi/Cogl": ["node_modules/@gi-types/cogl10"], - "@gi/GObject":["node_modules/@gi-types/gobject2"], - "@gi/Shell": ["node_modules/@gi-types/shell0"], - "@gi/St": ["node_modules/@gi-types/st1"], - "@gi/Graphene": ["node_modules/@gi-types/graphene1"] + "gi://Adw": ["node_modules/@gi-types/adw1"], + "gi://Gio": ["node_modules/@gi-types/gio2"], + "gi://Gtk": ["node_modules/@gi-types/gtk4"], + "gi://Gdk": ["node_modules/@gi-types/gdk4"], + "gi://GLib": ["node_modules/@gi-types/glib2"], + "gi://Meta": ["node_modules/@gi-types/meta10"], + "gi://Clutter":["node_modules/@gi-types/clutter10"], + "gi://Cogl": ["node_modules/@gi-types/cogl10"], + "gi://GObject":["node_modules/@gi-types/gobject2"], + "gi://Shell": ["node_modules/@gi-types/shell0"], + "gi://St": ["node_modules/@gi-types/st1"], + "gi://Graphene": ["node_modules/@gi-types/graphene1"] }, "outDir": "./_build/" }, From 6c8b92dad8d6d044e176d13468c35c4f7d9725b7 Mon Sep 17 00:00:00 2001 From: Yi <32430186+yilozt@users.noreply.github.com> Date: Sun, 15 Oct 2023 03:20:31 +0800 Subject: [PATCH 04/11] Port extension to gnome 45 --- po/rounded-window-corners@yilozt.pot | 19 +- resources/metadata.json | 6 +- src/dbus/client.ts | 2 +- src/dbus/services.ts | 32 ++-- src/effect/clip_shadow_effect.ts | 20 +- src/effect/linear_filter_effect.ts | 23 ++- src/effect/rounded_corners_effect.ts | 28 +-- src/extension.ts | 171 +++++------------- src/global.d.ts | 15 +- src/manager/effect_manager.ts | 103 ++++++----- src/manager/rounded_corners_manager.ts | 78 ++++---- src/preferences/index.ts | 10 +- src/preferences/pages/blacklist.ts | 29 ++- src/preferences/pages/custom.ts | 51 +++--- src/preferences/pages/general.ts | 54 +++--- src/preferences/widgets/app_row.ts | 37 ++-- src/preferences/widgets/edit_shadow_window.ts | 45 ++--- src/preferences/widgets/reset_dialog.ts | 18 +- .../widgets/rounded_corners_item.ts | 40 ++-- src/prefs.ts | 98 ++++------ src/utils/connections.ts | 2 +- src/utils/constants.ts | 6 - src/utils/i18n.ts | 24 --- src/utils/io.ts | 31 +++- src/utils/log.ts | 2 +- src/utils/prefs.ts | 18 +- src/utils/settings.ts | 65 ++++--- src/utils/types.ts | 24 +-- src/utils/ui.ts | 44 +++-- 29 files changed, 482 insertions(+), 613 deletions(-) diff --git a/po/rounded-window-corners@yilozt.pot b/po/rounded-window-corners@yilozt.pot index 577bb50..12a1190 100644 --- a/po/rounded-window-corners@yilozt.pot +++ b/po/rounded-window-corners@yilozt.pot @@ -2,7 +2,7 @@ msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Report-Msgid-Bugs-To: yilozt@outlook.com\n" -"Project-Id-Version: 10\n" +"Project-Id-Version: 11\n" #: src/preferences/pages/general.ui:284 msgid "Add Settings Entry in right-click menu of Background" @@ -56,12 +56,12 @@ msgstr "" msgid "Bottom" msgstr "" -#: src/preferences/pages/blacklist.ts:65 -#: src/preferences/pages/custom.ts:177 +#: src/preferences/pages/blacklist.ts:64 +#: src/preferences/pages/custom.ts:174 msgid "Can't add to list, because it has exists" msgstr "" -#: src/preferences/widgets/app_row.ts:106 +#: src/preferences/widgets/app_row.ts:105 msgid "Can't pick a window window from this position" msgstr "" @@ -86,15 +86,15 @@ msgstr "" msgid "Debug" msgstr "" -#: src/preferences/widgets/edit_shadow_window.ts:58 +#: src/preferences/widgets/edit_shadow_window.ts:59 msgid "Edit Shadow for Rounded Corners Windows" msgstr "" -#: src/preferences/pages/custom.ts:189 +#: src/preferences/pages/custom.ts:186 msgid "Enable" msgstr "" -#: src/preferences/pages/custom.ts:193 +#: src/preferences/pages/custom.ts:190 msgid "Enable custom settings for this window" msgstr "" @@ -103,7 +103,7 @@ msgstr "" msgid "Enable Log" msgstr "" -#: src/utils/constants.ts:17 +#: src/utils/prefs.ts:48 msgid "Expand this row to pick a window." msgstr "" @@ -182,7 +182,8 @@ msgstr "" msgid "Right" msgstr "" -#: src/utils/constants.ts:21 +#: src/utils/ui.ts:103 +#: src/utils/ui.ts:131 msgid "Rounded Corners Settings..." msgstr "" diff --git a/resources/metadata.json b/resources/metadata.json index 0a4b227..1bcc98a 100644 --- a/resources/metadata.json +++ b/resources/metadata.json @@ -2,7 +2,9 @@ "name": "Rounded Window Corners", "description": "Add rounded corners for all windows", "uuid": "rounded-window-corners@yilozt", - "version": "11", + "version": "12", "url": "https://github.com/yilozt/rounded-window-corners", - "shell-version": ["40", "41", "42", "43", "44"] + "gettext-domain": "rounded-window-corners@yilozt", + "settings-schema": "org.gnome.shell.extensions.rounded-window-corners", + "shell-version": ["45"] } diff --git a/src/dbus/client.ts b/src/dbus/client.ts index 733e258..33a8b9b 100644 --- a/src/dbus/client.ts +++ b/src/dbus/client.ts @@ -1,5 +1,5 @@ // imports.gi -import * as Gio from '@gi/Gio' +import * as Gio from 'gi://Gio' // --------------------------------------------------------------- [end imports] diff --git a/src/dbus/services.ts b/src/dbus/services.ts index e89dc3a..3a5de0d 100644 --- a/src/dbus/services.ts +++ b/src/dbus/services.ts @@ -1,22 +1,20 @@ // imports.gi -import * as Gio from '@gi/Gio' -import { Variant } from '@gi/GLib' +import * as Gio from 'gi://Gio' +import * as GLib from 'gi://GLib' +import * as Meta from 'gi://Meta' +import * as Clutter from 'gi://Clutter' // gnome modules -import { Inspector } from '@imports/ui/lookingGlass' -import * as Main from '@imports/ui/main' +import { Inspector } from 'resource:///org/gnome/shell/ui/lookingGlass.js' +import * as Main from 'resource:///org/gnome/shell/ui/main.js' // local modules -import { _log } from '@me/utils/log' -import { load } from '@me/utils/io' +import { _log } from '../utils/log.js' +import { loadFile } from '../utils/io.js' -// types -import { WindowActor } from '@gi/Meta' -import { Me } from '@global' -import { Actor } from '@gi/Clutter' // --------------------------------------------------------------- [end imports] -const iface = load (`${Me.path}/dbus/iface.xml`) +const iface = loadFile (import.meta.url, 'iface.xml') export class Services { DBusImpl = Gio.DBusExportedObject.wrapJSObject (iface, this) @@ -27,7 +25,7 @@ export class Services { const _send_wm_class_instance = (wm_instance_class: string) => { this.DBusImpl.emit_signal ( 'picked', - new Variant ('(s)', [wm_instance_class]) + new GLib.Variant ('(s)', [wm_instance_class]) ) } @@ -51,20 +49,20 @@ export class Services { const effect_name = 'lookingGlass_RedBorderEffect' target .get_effects () - .filter ((e) => e.toString ().includes (effect_name)) - .forEach ((e) => target.remove_effect (e)) + .filter ((e: Clutter.Effect) => e.toString ().includes (effect_name)) + .forEach ((e: Clutter.Effect) => target.remove_effect (e)) - let actor: Actor | null = target + let actor: Clutter.Actor | null = target // User will pick to a Meta.SurfaceActor in most time, let's find the // associate Meta.WindowActor for (let i = 0; i < 2; i++) { - if (actor == null || actor instanceof WindowActor) break + if (actor == null || actor instanceof Meta.WindowActor) break // If picked actor is not a Meta.WindowActor, search it's parent actor = actor.get_parent () } - if (!(actor instanceof WindowActor)) { + if (!(actor instanceof Meta.WindowActor)) { _send_wm_class_instance ('window-not-found') return } diff --git a/src/effect/clip_shadow_effect.ts b/src/effect/clip_shadow_effect.ts index 2b37723..e137695 100644 --- a/src/effect/clip_shadow_effect.ts +++ b/src/effect/clip_shadow_effect.ts @@ -1,29 +1,27 @@ // imports.gi -import * as GObject from '@gi/GObject' -import { SnippetHook, GLSLEffect } from '@gi/Shell' +import * as GObject from 'gi://GObject' +import * as Shell from 'gi://Shell' +import * as Clutter from 'gi://Clutter' // local modules -import { loadShader } from '@me/utils/io' - -// types -import { Me } from '@global' -import { PaintContext, PaintNode } from '@gi/Clutter' +import { loadShader } from '../utils/io.js' // ------------------------------------------------------------------- [imports] const { declarations, code } = loadShader ( - `${Me.path}/effect/shader/clip_shadow.frag` + import.meta.url, + 'shader/clip_shadow.frag' ) export const ClipShadowEffect = GObject.registerClass ( {}, - class extends GLSLEffect { + class extends Shell.GLSLEffect { vfunc_build_pipeline (): void { - const hook = SnippetHook.FRAGMENT + const hook = Shell.SnippetHook.FRAGMENT this.add_glsl_snippet (hook, declarations, code, false) } - vfunc_paint_target (node: PaintNode, ctx: PaintContext) { + vfunc_paint_target (node: Clutter.PaintNode, ctx: Clutter.PaintContext) { // Reset to default blend string. this.get_pipeline ()?.set_blend ( 'RGBA = ADD(SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))' diff --git a/src/effect/linear_filter_effect.ts b/src/effect/linear_filter_effect.ts index 463ade9..94a955e 100644 --- a/src/effect/linear_filter_effect.ts +++ b/src/effect/linear_filter_effect.ts @@ -1,20 +1,23 @@ -import { PaintNode, PaintContext } from '@gi/Clutter' -import { PipelineFilter } from '@gi/Cogl' -import { registerClass } from '@gi/GObject' -import { GLSLEffect, SnippetHook } from '@gi/Shell' +import * as Clutter from 'gi://Clutter' +import * as Cogl from 'gi://Cogl' +import * as GObject from 'gi://GObject' +import * as Shell from 'gi://Shell' -export const LinearFilterEffect = registerClass ( +export const LinearFilterEffect = GObject.registerClass ( {}, - class extends GLSLEffect { + class extends Shell.GLSLEffect { vfunc_build_pipeline (): void { - this.add_glsl_snippet (SnippetHook.FRAGMENT, '', '', false) + this.add_glsl_snippet (Shell.SnippetHook.FRAGMENT, '', '', false) } - vfunc_paint_target (node: PaintNode, ctx: PaintContext): void { + vfunc_paint_target ( + node: Clutter.PaintNode, + ctx: Clutter.PaintContext + ): void { this.get_pipeline ()?.set_layer_filters ( 0, - PipelineFilter.LINEAR_MIPMAP_LINEAR, - PipelineFilter.NEAREST + Cogl.PipelineFilter.LINEAR_MIPMAP_LINEAR, + Cogl.PipelineFilter.NEAREST ) super.vfunc_paint_target (node, ctx) } diff --git a/src/effect/rounded_corners_effect.ts b/src/effect/rounded_corners_effect.ts index 1d0c8ad..ab3a2e9 100644 --- a/src/effect/rounded_corners_effect.ts +++ b/src/effect/rounded_corners_effect.ts @@ -1,22 +1,22 @@ // imports.gi -import { registerClass } from '@gi/GObject' -import { GLSLEffect, SnippetHook } from '@gi/Shell' +import * as GObject from 'gi://GObject' +import * as Meta from 'gi://Meta' +import * as Shell from 'gi://Shell' // local modules -import { loadShader } from '@me/utils/io' -import * as types from '@me/utils/types' +import { loadShader } from '../utils/io.js' +import * as types from '../utils/types.js' // types -import { Me } from '@global' -import { PaintContext, PaintNode } from '@gi/Clutter' -import { shell_version } from '@me/utils/ui' -import { WindowActor } from '@gi/Meta' +import * as Clutter from 'gi://Clutter' +import { shell_version } from '../utils/ui.js' // --------------------------------------------------------------- [end imports] // Load fragment shader of rounded corners effect. const { declarations, code } = loadShader ( - `${Me.path}/effect/shader/rounded_corners.frag` + import.meta.url, + 'shader/rounded_corners.frag' ) /** Location of uniform variants of rounded corners effect */ @@ -31,9 +31,9 @@ class Uniforms { border_color = 0 } -export const RoundedCornersEffect = registerClass ( +export const RoundedCornersEffect = GObject.registerClass ( {}, - class Effect extends GLSLEffect { + class Effect extends Shell.GLSLEffect { /** * Location of uniforms variants in shader, Cache those location * when shader has been setup in `vfunc_build_pipeline()`, sot that @@ -63,12 +63,12 @@ export const RoundedCornersEffect = registerClass ( } vfunc_build_pipeline (): void { - const type = SnippetHook.FRAGMENT + const type = Shell.SnippetHook.FRAGMENT this.add_glsl_snippet (type, declarations, code, false) this._init_uniforms () } - vfunc_paint_target (node: PaintNode, ctx: PaintContext) { + vfunc_paint_target (node: Clutter.PaintNode, ctx: Clutter.PaintContext) { // Reset to default blend string. this.get_pipeline ()?.set_blend ( 'RGBA = ADD(SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))' @@ -125,7 +125,7 @@ export const RoundedCornersEffect = registerClass ( // offers correct one. if ( shell_version () >= 43.1 && - actor instanceof WindowActor && + actor instanceof Meta.WindowActor && actor.first_child?.first_child ) { const { width, height } = actor.first_child.first_child diff --git a/src/extension.ts b/src/extension.ts index 2985056..04b567a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,54 +1,46 @@ // imports.gi -import { Point } from '@gi/Graphene' -import * as Clutter from '@gi/Clutter' -import { Settings } from '@gi/Gio' -import { WindowClientType } from '@gi/Meta' +import * as Graphene from 'gi://Graphene' +import * as Clutter from 'gi://Clutter' +import * as Gio from 'gi://Gio' +import * as Meta from 'gi://Meta' +import * as GObject from 'gi://GObject' // gnome-shell modules -import { WindowPreview } from '@imports/ui/windowPreview' -import { WorkspaceGroup } from '@imports/ui/workspaceAnimation' -import BackgroundMenu from '@imports/ui/backgroundMenu' -import { layoutManager } from '@imports/ui/main' -import { overview } from '@imports/ui/main' +import { WindowPreview } from 'resource:///org/gnome/shell/ui/windowPreview.js' +import { overview, layoutManager } from 'resource:///org/gnome/shell/ui/main.js' +import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js' // local modules -import { constants } from '@me/utils/constants' -import { stackMsg, _log } from '@me/utils/log' -import * as UI from '@me/utils/ui' -import { connections } from '@me/utils/connections' -import { SchemasKeys, settings } from '@me/utils/settings' -import { Services } from '@me/dbus/services' -import { LinearFilterEffect } from '@me/effect/linear_filter_effect' -import { RoundedCornersEffect } from '@me/effect/rounded_corners_effect' -import { init_translations } from '@me/utils/i18n' -import { WindowActorTracker } from '@me/manager/effect_manager' +import { constants } from './utils/constants.js' +import { stackMsg, _log } from './utils/log.js' +import * as UI from './utils/ui.js' +import { connections } from './utils/connections.js' +import { SchemasKeys, init_settings, settings } from './utils/settings.js' +import { Services } from './dbus/services.js' +import { LinearFilterEffect } from './effect/linear_filter_effect.js' +import { RoundedCornersEffect } from './effect/rounded_corners_effect.js' +import { WindowActorTracker } from './manager/effect_manager.js' // types, which will be removed in output -import { RoundedCornersCfg } from '@me/utils/types' -import { ExtensionsWindowActor } from '@me/utils/types' -import { Window, WindowActor } from '@gi/Meta' -import { global } from '@global' -import { registerClass } from '@gi/GObject' +import { RoundedCornersCfg } from './utils/types.js' +import { ExtensionsWindowActor } from './utils/types.js' +import { global } from '@global' // --------------------------------------------------------------- [end imports] -export class Extension { +export default class RoundedWindowCorners extends Extension { // The methods of gnome-shell to monkey patch - private _orig_add_window !: (_: Window) => void - private _orig_create_windows !: () => void - private _orig_sync_stacking !: () => void - private _add_background_menu !: typeof BackgroundMenu.addBackgroundMenu + private _orig_add_window!: (_: Meta.Window) => void private _services: Services | null = null private _window_actor_tracker: WindowActorTracker | null = null enable () { + init_settings (this.getSettings ()) + // Restore original methods, those methods will be restore when // extensions is disabled this._orig_add_window = WindowPreview.prototype._addWindow - this._orig_create_windows = WorkspaceGroup.prototype._createWindows - this._orig_sync_stacking = WorkspaceGroup.prototype._syncStacking - this._add_background_menu = BackgroundMenu.addBackgroundMenu this._services = new Services () this._window_actor_tracker = new WindowActorTracker () @@ -151,7 +143,7 @@ export class Extension { rounded_effect_of_window_actor?.set_enabled (false) // Add rounded corners effect to preview window actor - first_child.add_effect_with_name (name, new RoundedCornersEffect ()) + first_child?.add_effect_with_name (name, new RoundedCornersEffect ()) // Update uniform variables of rounded corners effect when size of // preview windows in overview changed. @@ -176,10 +168,11 @@ export class Extension { let pixel_step: [number, number] | undefined = undefined if ( UI.shell_version () >= 43.1 && - window.get_client_type () == WindowClientType.WAYLAND + window.get_client_type () == Meta.WindowClientType.WAYLAND ) { - const surface = (window.get_compositor_private () as WindowActor) - .first_child + const surface = ( + window.get_compositor_private () as Meta.WindowActor + ).first_child pixel_step = [ 1.0 / (scale_factor * surface.get_width ()), 1.0 / (scale_factor * surface.get_height ()), @@ -211,79 +204,9 @@ export class Extension { }) } - // Just Like the monkey patch when enter overview, need to add shadow - // actor and blur actor into WorkspaceGroup to see them when switching - // workspace - WorkspaceGroup.prototype._createWindows = function () { - self._orig_create_windows.apply (this) - - this._windowRecords.forEach (({ windowActor: actor, clone }) => { - const win = actor.meta_window - const frame_rect = win.get_frame_rect () - const cfg = UI.ChoiceRoundedCornersCfg ( - settings ().global_rounded_corner_settings, - settings ().custom_rounded_corner_settings, - win - ) - const maximized = - win.maximized_horizontally || - win.maximized_vertically || - win.fullscreen - const has_rounded_corners = cfg.keep_rounded_corners || !maximized - - const shadow = (actor as ExtensionsWindowActor) - .__rwc_rounded_window_info?.shadow - if (shadow && has_rounded_corners) { - // Only create shadow actor when window should have rounded - // corners when switching workspace - - // Copy shadow actor to workspace group, so that to see - // shadow when switching workspace - const shadow_clone = new Clutter.Clone ({ source: shadow }) - const paddings = constants.SHADOW_PADDING * UI.WindowScaleFactor (win) - - shadow_clone.width = frame_rect.width + paddings * 2 - shadow_clone.height = frame_rect.height + paddings * 2 - shadow_clone.x = clone.x + frame_rect.x - actor.x - paddings - shadow_clone.y = clone.y + frame_rect.y - actor.y - paddings - - clone.connect ( - 'notify::translation-z', - () => (shadow_clone.translation_z = clone.translation_z + 0.006) - ) - - // Add reference shadow clone for clone actor, so that we - // can restack position of shadow when we need - ;(clone as WsAnimationActor)._shadow_clone = shadow_clone - clone.bind_property ('visible', shadow_clone, 'visible', 0) - this.insert_child_below (shadow_clone, clone) - } - }) - } - - // Let shadow actor always behind the window clone actor when we - // switch workspace by Ctrl+Alt+Left/Right - // - // Fix #55 - WorkspaceGroup.prototype._syncStacking = function () { - self._orig_sync_stacking.apply (this, []) - for (const { clone } of this._windowRecords) { - const shadow_clone = (clone as WsAnimationActor)._shadow_clone - if (shadow_clone && shadow_clone.visible) { - this.set_child_below_sibling (shadow_clone, clone) - } - } - } - if (settings ().enable_preferences_entry) { UI.SetupBackgroundMenu () } - BackgroundMenu.addBackgroundMenu = (actor, layout) => { - this._add_background_menu (actor, layout) - if (settings ().enable_preferences_entry) { - UI.AddBackgroundMenuItem (actor._backgroundMenu) - } - } const c = connections.get () @@ -298,15 +221,19 @@ export class Extension { }) // Watch changes of GSettings - c.connect (settings ().g_settings, 'changed', (_: Settings, k: string) => { - switch (k as SchemasKeys) { - case 'enable-preferences-entry': - settings ().enable_preferences_entry - ? UI.SetupBackgroundMenu () - : UI.RestoreBackgroundMenu () - break + c.connect ( + settings ().g_settings, + 'changed', + (_: Gio.Settings, k: string) => { + switch (k as SchemasKeys) { + case 'enable-preferences-entry': + settings ().enable_preferences_entry + ? UI.SetupBackgroundMenu () + : UI.RestoreBackgroundMenu () + break + } } - }) + ) _log ('Enabled') } @@ -314,9 +241,6 @@ export class Extension { disable () { // Restore patched methods WindowPreview.prototype._addWindow = this._orig_add_window - WorkspaceGroup.prototype._createWindows = this._orig_create_windows - WorkspaceGroup.prototype._syncStacking = this._orig_sync_stacking - BackgroundMenu.addBackgroundMenu = this._add_background_menu // Remove the item to open preferences page in background menu UI.RestoreBackgroundMenu () @@ -336,19 +260,14 @@ export class Extension { } } -export function init () { - init_translations () - return new Extension () -} - /** * Copy shadow of rounded corners window and show it in overview. * This actor will be created when window preview has created for overview */ -const OverviewShadowActor = registerClass ( +const OverviewShadowActor = GObject.registerClass ( {}, class extends Clutter.Clone { - _window_preview !: WindowPreview + _window_preview!: WindowPreview /** * Create shadow actor for WindowPreview in overview @@ -359,7 +278,7 @@ const OverviewShadowActor = registerClass ( super._init ({ source, // the source shadow actor shown in desktop name: constants.OVERVIEW_SHADOW_ACTOR, - pivot_point: new Point ({ x: 0.5, y: 0.5 }), + pivot_point: new Graphene.Point ({ x: 0.5, y: 0.5 }), }) this._window_preview = window_preview @@ -409,5 +328,3 @@ const OverviewShadowActor = registerClass ( } } ) - -type WsAnimationActor = Clutter.Actor & { _shadow_clone?: Clutter.Actor } diff --git a/src/global.d.ts b/src/global.d.ts index ec4e759..ae68e16 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -1,19 +1,10 @@ // @ts-ignore -import { Global, BlurMode } from '@gi/Shell' -import { Effect } from '@gi/Clutter' -import * as Adw from '@gi/Adw' -import * as windowPreview from '@imports/ui/windowPreview' -declare const global: Global, log: any, logError: any +import * as Shell from 'gi://Shell' +import * as Clutter from 'gi://Clutter' +declare const global: Shell.Global, log: any, logError: any declare const imports = { gi: { Adw }, ui: { windowPreview }, } - -declare const Me: { - path: string - uuid: string -} - -type PreferencesWindow = Adw.PreferencesWindow diff --git a/src/manager/effect_manager.ts b/src/manager/effect_manager.ts index 4fc708a..9b8eadd 100644 --- a/src/manager/effect_manager.ts +++ b/src/manager/effect_manager.ts @@ -1,23 +1,22 @@ // imports.gi -import * as Clutter from '@gi/Clutter' -import * as Graphene from '@gi/Graphene' +import * as Clutter from 'gi://Clutter' +import * as Graphene from 'gi://Graphene' +import * as Shell from 'gi://Shell' +import * as Meta from 'gi://Meta' // local modules -import { _log } from '@me/utils/log' -import { settings } from '@me/utils/settings' -import { Connections } from '@me/utils/connections' -import { RoundedCornersManager } from '@me/manager/rounded_corners_manager' +import { _log } from '../utils/log.js' +import { settings } from '../utils/settings.js' +import { Connections } from '../utils/connections.js' +import { RoundedCornersManager } from '../manager/rounded_corners_manager.js' // types, those import statements will be removed in output javascript files. -import { SchemasKeys } from '@me/utils/settings' -import { EffectManager } from '@me/utils/types' -import { ExtensionsWindowActor } from '@me/utils/types' -import { WindowActor, Window } from '@gi/Meta' -import { WM } from '@gi/Shell' -import { global } from '@global' -import * as Gio from '@gi/Gio' -import { Display } from '@gi/Meta' -import { shell_version } from '@me/utils/ui' +import { SchemasKeys } from '../utils/settings.js' +import { EffectManager } from '../utils/types.js' +import { ExtensionsWindowActor } from '../utils/types.js' +import { global } from '@global' +import * as Gio from 'gi://Gio' +import { shell_version } from '../utils/ui.js' // --------------------------------------------------------------- [end imports] @@ -62,8 +61,8 @@ export class WindowActorTracker { this.connections.connect ( global.display, 'window-created', - (_: Display, win: Window) => { - const actor: WindowActor = win.get_compositor_private () + (_: Meta.Display, win: Meta.Window) => { + const actor: Meta.WindowActor = win.get_compositor_private () // If wm_class_instance of Meta.Window is null, try to add rounded // corners when wm_class_instance is set @@ -81,7 +80,7 @@ export class WindowActorTracker { this.connections.connect ( wm, 'switch-workspace', - (_: WM, from: number, to: number) => { + (_: Shell.WM, from: number, to: number) => { this.run ((m) => { const ws = global.workspace_manager.get_workspace_by_index (to) if (!m.on_switch_workspace) return @@ -94,40 +93,50 @@ export class WindowActorTracker { ) // Connect 'minimized' signal - this.connections.connect (wm, 'minimize', (_: WM, actor: WindowActor) => { - this.run ((m) => m.on_minimize (actor)) - }) + this.connections.connect ( + wm, + 'minimize', + (_: Shell.WM, actor: Meta.WindowActor) => { + this.run ((m) => m.on_minimize (actor)) + } + ) // Restore visible of shadow when un-minimized - this.connections.connect (wm, 'unminimize', (_: WM, actor: WindowActor) => { - // Handle visible of shader with Compiz alike magic lamp effect - // After MagicLampUnminimizeEffect completed, then show shadow - // - // https://github.com/hermes83/compiz-alike-magic-lamp-effect - const effect = actor.get_effect ('unminimize-magic-lamp-effect') - if (effect) { - type Effect = Clutter.Effect & { timerId: Clutter.Timeline } - const timer_id = (effect as Effect).timerId - - const id = timer_id.connect ('new-frame', (source) => { - // Effect completed when get_process() touch 1.0 - // Need show shadow here - if (source.get_progress () > 0.98) { - _log ('Handle Unminimize with Magic Lamp Effect') - - this.run ((m) => m.on_unminimize (actor)) - source.disconnect (id) - } - }) - return - } + this.connections.connect ( + wm, + 'unminimize', + (_: Shell.WM, actor: Meta.WindowActor) => { + // Handle visible of shader with Compiz alike magic lamp effect + // After MagicLampUnminimizeEffect completed, then show shadow + // + // https://github.com/hermes83/compiz-alike-magic-lamp-effect + const effect = actor.get_effect ('unminimize-magic-lamp-effect') + if (effect) { + type Effect = Clutter.Effect & { timerId: Clutter.Timeline } + const timer_id = (effect as Effect).timerId + + const id = timer_id.connect ('new-frame', (source) => { + // Effect completed when get_process() touch 1.0 + // Need show shadow here + if (source.get_progress () > 0.98) { + _log ('Handle Unminimize with Magic Lamp Effect') + + this.run ((m) => m.on_unminimize (actor)) + source.disconnect (id) + } + }) + return + } - this.run ((m) => m.on_unminimize (actor)) - }) + this.run ((m) => m.on_unminimize (actor)) + } + ) // Disconnect all signals of window when closed - this.connections.connect (wm, 'destroy', (_: WM, actor: WindowActor) => - this._remove_effect (actor) + this.connections.connect ( + wm, + 'destroy', + (_: Shell.WM, actor: Meta.WindowActor) => this._remove_effect (actor) ) // When windows restacked, change order of shadow actor too diff --git a/src/manager/rounded_corners_manager.ts b/src/manager/rounded_corners_manager.ts index 8cdf7c7..04c00f6 100644 --- a/src/manager/rounded_corners_manager.ts +++ b/src/manager/rounded_corners_manager.ts @@ -1,27 +1,23 @@ // imports.gi -import * as Clutter from '@gi/Clutter' -import * as GLib from '@gi/GLib' -import { ShadowMode, WindowType } from '@gi/Meta' -import { WindowClientType } from '@gi/Meta' -import { Bin } from '@gi/St' -import { BindingFlags } from '@gi/GObject' -import { ThemeContext } from '@gi/St' +import * as Clutter from 'gi://Clutter' +import * as GLib from 'gi://GLib' +import * as Meta from 'gi://Meta' +import * as St from 'gi://St' +import * as GObject from 'gi://GObject' // local modules -import * as UI from '@me/utils/ui' -import { _log } from '@me/utils/log' -import { constants } from '@me/utils/constants' -import { ClipShadowEffect } from '@me/effect/clip_shadow_effect' -import * as types from '@me/utils/types' -import { settings } from '@me/utils/settings' -import { RoundedCornersEffect } from '@me/effect/rounded_corners_effect' +import * as UI from '../utils/ui.js' +import { _log } from '../utils/log.js' +import { constants } from '../utils/constants.js' +import { ClipShadowEffect } from '../effect/clip_shadow_effect.js' +import * as types from '../utils/types.js' +import { settings } from '../utils/settings.js' +import { RoundedCornersEffect } from '../effect/rounded_corners_effect.js' // types, those import statements will be removed in output javascript files. -import { SchemasKeys } from '../utils/settings' -import { Window, WindowActor } from '@gi/Meta' -import { global } from '@global' -import { EffectManager } from '@me/utils/types' -import { ExtensionsWindowActor } from '@me/utils/types' +import { SchemasKeys } from '../utils/settings.js' +import { global } from '@global' +import { EffectManager, ExtensionsWindowActor } from '../utils/types.js' type RoundedCornersEffectType = InstanceType // --------------------------------------------------------------- [end imports] @@ -56,12 +52,12 @@ export class RoundedCornersManager implements EffectManager { // - For csd client, shadow is drew by application itself, it has been cut // out by rounded corners effect if (actor.shadow_mode !== undefined) { - actor.shadow_mode = ShadowMode.FORCED_OFF + actor.shadow_mode = Meta.ShadowMode.FORCED_OFF } // So we have to create an shadow actor for rounded corners shadows const shadow = this._create_shadow (actor) // Bind properties between shadow and window - const flag = BindingFlags.SYNC_CREATE + const flag = GObject.BindingFlags.SYNC_CREATE for (const prop of [ 'pivot-point', 'translation-x', @@ -91,7 +87,7 @@ export class RoundedCornersManager implements EffectManager { // Restore shadow for x11 windows if (actor.shadow_mode) { - actor.shadow_mode = ShadowMode.AUTO + actor.shadow_mode = Meta.ShadowMode.AUTO } // Remove shadow actor @@ -262,7 +258,7 @@ export class RoundedCornersManager implements EffectManager { return } const prop = 'visible' - const flag = BindingFlags.SYNC_CREATE + const flag = GObject.BindingFlags.SYNC_CREATE info.visible_binding = actor.bind_property (prop, info.shadow, prop, flag) } @@ -271,7 +267,7 @@ export class RoundedCornersManager implements EffectManager { * @param win Meta.Window to test */ private _should_enable_effect ( - win: Window & { __app_type?: UI.AppType } + win: Meta.Window & { __app_type?: UI.AppType } ): boolean { // DING (Desktop Icons NG) is a extensions that create a gtk // application to show desktop grid on background, we need to @@ -294,9 +290,9 @@ export class RoundedCornersManager implements EffectManager { // Check type of window, only need to add rounded corners to normal // window and dialog. const normal_type = [ - WindowType.NORMAL, - WindowType.DIALOG, - WindowType.MODAL_DIALOG, + Meta.WindowType.NORMAL, + Meta.WindowType.DIALOG, + Meta.WindowType.MODAL_DIALOG, ].includes (win.window_type) if (!normal_type) { return false @@ -323,24 +319,24 @@ export class RoundedCornersManager implements EffectManager { * In Wayland, we will add rounded corners effect to WindowActor * In XOrg, we will add rounded corners effect to WindowActor.first_child */ - private _actor_to_rounded (actor: WindowActor): Clutter.Actor | null { + private _actor_to_rounded (actor: Meta.WindowActor): Clutter.Actor | null { const type = actor.meta_window.get_client_type () - return type == WindowClientType.X11 ? actor.get_first_child () : actor + return type == Meta.WindowClientType.X11 ? actor.get_first_child () : actor } /** * Create Shadow for rounded corners window * @param actor - window actor which has been setup rounded corners effect */ - private _create_shadow (actor: WindowActor): Bin { - const shadow = new Bin ({ + private _create_shadow (actor: Meta.WindowActor): St.Bin { + const shadow = new St.Bin ({ name: 'Shadow Actor', - child: new Bin ({ + child: new St.Bin ({ x_expand: true, y_expand: true, }), }) - ;(shadow.first_child as Bin).add_style_class_name ('shadow') + ;(shadow.first_child as St.Bin).add_style_class_name ('shadow') this._update_shadow_actor_style ( actor.meta_window, @@ -379,7 +375,7 @@ export class RoundedCornersManager implements EffectManager { /** Compute outer bound of rounded corners for window actor */ private _compute_bounds ( - actor: WindowActor, + actor: Meta.WindowActor, [x, y, width, height]: [number, number, number, number] ): types.Bounds { const bounds = { @@ -392,7 +388,7 @@ export class RoundedCornersManager implements EffectManager { // Kitty draw it's window decoration by itself, we need recompute the // outer bounds for kitty. if (settings ().tweak_kitty_terminal) { - const type = WindowClientType.WAYLAND + const type = Meta.WindowClientType.WAYLAND if ( actor.meta_window.get_client_type () == type && actor.meta_window.get_wm_class_instance () === 'kitty' @@ -409,7 +405,7 @@ export class RoundedCornersManager implements EffectManager { } private _compute_shadow_actor_offset ( - actor: WindowActor, + actor: Meta.WindowActor, [offset_x, offset_y, offset_width, offset_height]: [ number, number, @@ -434,8 +430,8 @@ export class RoundedCornersManager implements EffectManager { /** Update css style of shadow actor */ private _update_shadow_actor_style ( - win: Window, - actor: Bin, + win: Meta.Window, + actor: St.Bin, border_radius = this.global_rounded_corners?.border_radius, shadow = settings ().focused_shadow, padding = this.global_rounded_corners?.padding @@ -457,7 +453,7 @@ export class RoundedCornersManager implements EffectManager { // // So, we have to adjustment this different - const original_scale = ThemeContext.get_for_stage ( + const original_scale = St.ThemeContext.get_for_stage ( global.stage as Clutter.Stage ).scale_factor const win_scale = UI.WindowScaleFactor (win) @@ -470,7 +466,7 @@ export class RoundedCornersManager implements EffectManager { actor.style = `padding: ${constants.SHADOW_PADDING * scale_of_style}px /*background: yellow*/;` - const child = actor.first_child as Bin + const child = actor.first_child as St.Bin if ( win.maximized_horizontally || @@ -537,7 +533,7 @@ export class RoundedCornersManager implements EffectManager { } } - private _get_rounded_corners_cfg (win: Window): types.RoundedCornersCfg { + private _get_rounded_corners_cfg (win: Meta.Window): types.RoundedCornersCfg { return UI.ChoiceRoundedCornersCfg ( this.global_rounded_corners ?? settings ().global_rounded_corner_settings, this.custom_rounded_corners ?? settings ().custom_rounded_corner_settings, diff --git a/src/preferences/index.ts b/src/preferences/index.ts index 8924ff3..ea563a5 100644 --- a/src/preferences/index.ts +++ b/src/preferences/index.ts @@ -1,9 +1,9 @@ -import * as Gtk from '@gi/Gtk' +import * as Gtk from 'gi://Gtk' -import { General } from '@me/preferences/pages/general' -import { BlackList } from '@me/preferences/pages/blacklist' -import { Custom } from '@me/preferences/pages/custom' -import { _ } from '@me/utils/i18n' +import { General } from '../preferences/pages/general.js' +import { BlackList } from '../preferences/pages/blacklist.js' +import { Custom } from '../preferences/pages/custom.js' +import { gettext as _ } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js' type Page = { title: string; icon_name: string; widget: Gtk.Widget } diff --git a/src/preferences/pages/blacklist.ts b/src/preferences/pages/blacklist.ts index feaf4f6..c1acef5 100644 --- a/src/preferences/pages/blacklist.ts +++ b/src/preferences/pages/blacklist.ts @@ -1,35 +1,34 @@ // imports.gi -import * as GObject from '@gi/GObject' +import * as GObject from 'gi://GObject' // Local Modules -import { show_err_msg } from '@me/utils/prefs' -import { settings } from '@me/utils/settings' -import { constants } from '@me/utils/constants' -import { connections } from '@me/utils/connections' -import { AppRow } from '@me/preferences/widgets/app_row' +import { show_err_msg, TIPS_EMPTY } from '../../utils/prefs.js' +import { settings } from '../../utils/settings.js' +import { connections } from '../../utils/connections.js' +import { AppRow } from '../../preferences/widgets/app_row.js' // types -import { AppRowHandler } from '../widgets/app_row' -import { Me } from '@global' +import { AppRowHandler } from '../widgets/app_row.js' -import * as Gtk from '@gi/Gtk' -import { _ } from '@me/utils/i18n' +import * as Gtk from 'gi://Gtk' +import { gettext as _ } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js' +import { uri } from '../../utils/io.js' // --------------------------------------------------------------- [end imports] /** Black list Preferences Page */ export const BlackList = GObject.registerClass ( { - Template: `file://${Me.path}/preferences/pages/blacklist.ui`, + Template: uri (import.meta.url, 'blacklist.ui'), GTypeName: 'RoundedWindowCornersPrefsBlacklist', InternalChildren: ['black_list_group', 'add_row_btn'], }, class extends Gtk.Box { - private _black_list_group !: Gtk.ListBox - private _add_row_btn !: Gtk.Button + private _black_list_group!: Gtk.ListBox + private _add_row_btn!: Gtk.Button /** Store value of settings */ - private black_list !: string[] + private black_list!: string[] _init () { super._init () @@ -86,7 +85,7 @@ export const BlackList = GObject.registerClass ( row.title = title if (!title) { - row.description = constants.TIPS_EMPTY () + row.description = TIPS_EMPTY () } this._black_list_group.append (row) diff --git a/src/preferences/pages/custom.ts b/src/preferences/pages/custom.ts index 189395f..79966de 100644 --- a/src/preferences/pages/custom.ts +++ b/src/preferences/pages/custom.ts @@ -1,38 +1,35 @@ // imports.gi -import * as GObject from '@gi/GObject' -import * as Gtk from '@gi/Gtk' +import * as GObject from 'gi://GObject' +import * as Gtk from 'gi://Gtk' // local modules -import { list_children, show_err_msg } from '@me/utils/prefs' -import { constants } from '@me/utils/constants' -import { settings } from '@me/utils/settings' -import { connections } from '@me/utils/connections' -import { _ } from '@me/utils/i18n' -import { AppRowHandler, AppRow } from '@me/preferences/widgets/app_row' -import { RoundedCornersItem } from '@me/preferences/widgets/rounded_corners_item' - -// types -import { Align, Switch } from '@gi/Gtk' -import { Button, Widget } from '@gi/Gtk' - -// import { AppRowHandler } from '../../../widgets/app-row' -import { CustomRoundedCornersCfg } from '../../utils/types' -import { RoundedCornersCfg } from '../../utils/types' -import { Me } from '@global' +import { list_children, show_err_msg, TIPS_EMPTY } from '../../utils/prefs.js' +import { constants } from '../../utils/constants.js' +import { settings } from '../../utils/settings.js' +import { connections } from '../../utils/connections.js' +import { gettext as _ } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js' +import { AppRowHandler, AppRow } from '../widgets/app_row.js' +import { RoundedCornersItem } from '../widgets/rounded_corners_item.js' + +import { + CustomRoundedCornersCfg, + RoundedCornersCfg, +} from '../../utils/types.js' +import { uri } from '../../utils/io.js' // --------------------------------------------------------------- [end imports] export const Custom = GObject.registerClass ( { - Template: `file://${Me.path}/preferences/pages/custom.ui`, + Template: uri (import.meta.url, 'custom.ui'), GTypeName: 'RoundedWindowCornersPrefsCustomPage', InternalChildren: ['custom_group', 'add_row_btn'], }, class extends Gtk.Box { - private _custom_group !: Gtk.ListBox - private _add_row_btn !: Button + private _custom_group!: Gtk.ListBox + private _add_row_btn!: Gtk.Button - private _settings_cfg !: CustomRoundedCornersCfg + private _settings_cfg!: CustomRoundedCornersCfg _init () { super._init () @@ -64,8 +61,8 @@ export const Custom = GObject.registerClass ( let rounded_corners_item: RoundedCornersItemType | null = new RoundedCornersItem () - const enabled_switch = new Switch ({ - valign: Align.CENTER, + const enabled_switch = new Gtk.Switch ({ + valign: Gtk.Align.CENTER, active: true, visible: true, }) @@ -148,7 +145,7 @@ export const Custom = GObject.registerClass ( expanded_row.activatable = false if (title == '') { - expanded_row.description = constants.TIPS_EMPTY () + expanded_row.description = TIPS_EMPTY () } this._custom_group.append (expanded_row) @@ -183,7 +180,7 @@ export const Custom = GObject.registerClass ( settings ().custom_rounded_corner_settings = this._settings_cfg } - private create_enabled_row (active_widget: Widget): Gtk.ListBoxRow { + private create_enabled_row (active_widget: Gtk.Widget): Gtk.ListBoxRow { const row = new Gtk.ListBoxRow () const title = new Gtk.Label ({ label: _ ('Enable'), @@ -213,7 +210,7 @@ export const Custom = GObject.registerClass ( } ) -function add_row (parent: InstanceType, child: Widget) { +function add_row (parent: InstanceType, child: Gtk.Widget) { parent.add_row (child) } diff --git a/src/preferences/pages/general.ts b/src/preferences/pages/general.ts index 8fc0cd4..a7b8531 100644 --- a/src/preferences/pages/general.ts +++ b/src/preferences/pages/general.ts @@ -1,27 +1,27 @@ // imports.gi -import * as GObject from '@gi/GObject' -import * as Gdk from '@gi/Gdk' -import * as Gio from '@gi/Gio' +import * as GObject from 'gi://GObject' +import * as Gdk from 'gi://Gdk' +import * as Gio from 'gi://Gio' // local modules -import { settings } from '@me/utils/settings' -import { SchemasKeys } from '@me/utils/settings' -import { connections } from '@me/utils/connections' -import { list_children } from '@me/utils/prefs' -import { _log } from '@me/utils/log' -import { RoundedCornersItem } from '@me/preferences/widgets/rounded_corners_item' -import { EditShadowWindow } from '@me/preferences/widgets/edit_shadow_window' -import { ResetDialog } from '@me/preferences/widgets/reset_dialog' +import { settings } from '../../utils/settings.js' +import { SchemasKeys } from '../../utils/settings.js' +import { connections } from '../../utils/connections.js' +import { list_children } from '../../utils/prefs.js' +import { _log } from '../../utils/log.js' +import { RoundedCornersItem } from '../widgets/rounded_corners_item.js' +import { EditShadowWindow } from '../widgets/edit_shadow_window.js' +import { ResetDialog } from '../widgets/reset_dialog.js' // types -import * as Gtk from '@gi/Gtk' -import { Me } from '@global' +import * as Gtk from 'gi://Gtk' +import { uri } from '../../utils/io.js' // --------------------------------------------------------------- [end imports] export const General = GObject.registerClass ( { - Template: `file://${Me.path}/preferences/pages/general.ui`, + Template: uri (import.meta.url, 'general.ui'), GTypeName: 'RoundedWindowCornersPrefsGeneral', // Widgets export from template ui @@ -41,19 +41,19 @@ export const General = GObject.registerClass ( }, class extends Gtk.Box { // Those properties come from 'InternalChildren' - private _global_settings_preferences_group !: Gtk.ListBox - private _enable_log_switch !: Gtk.Switch - private _skip_libhandy_app_switch !: Gtk.Switch - private _skip_libadwaita_app_switch !: Gtk.Switch - private _tweak_kitty_switch !: Gtk.Switch - private _preferences_entry_switch !: Gtk.Switch - private _border_width_ajustment !: Gtk.Adjustment - private _border_color_button !: Gtk.ColorButton - private _edit_shadow_row !: Gtk.ListBoxRow - private _applications_group !: Gtk.ListBox - private _reset_preferences_btn !: Gtk.Button - - private config_items !: _Items + private _global_settings_preferences_group!: Gtk.ListBox + private _enable_log_switch!: Gtk.Switch + private _skip_libhandy_app_switch!: Gtk.Switch + private _skip_libadwaita_app_switch!: Gtk.Switch + private _tweak_kitty_switch!: Gtk.Switch + private _preferences_entry_switch!: Gtk.Switch + private _border_width_ajustment!: Gtk.Adjustment + private _border_color_button!: Gtk.ColorButton + private _edit_shadow_row!: Gtk.ListBoxRow + private _applications_group!: Gtk.ListBox + private _reset_preferences_btn!: Gtk.Button + + private config_items!: _Items _init () { super._init () diff --git a/src/preferences/widgets/app_row.ts b/src/preferences/widgets/app_row.ts index a1959c4..6b240f4 100644 --- a/src/preferences/widgets/app_row.ts +++ b/src/preferences/widgets/app_row.ts @@ -1,22 +1,21 @@ // imports.gi -import * as GObject from '@gi/GObject' -import * as Gtk from '@gi/Gtk' +import * as GObject from 'gi://GObject' +import * as Gtk from 'gi://Gtk' // local Modules -import { show_err_msg } from '@me/utils/prefs' -import { connections } from '@me/utils/connections' -import { constants } from '@me/utils/constants' -import { on_picked, pick } from '@me/dbus/client' -import { _ } from '@me/utils/i18n' +import { show_err_msg, TIPS_EMPTY } from '../../utils/prefs.js' +import { connections } from '../../utils/connections.js' +import { on_picked, pick } from '../../dbus/client.js' +import { gettext as _ } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js' +import { uri } from '../../utils/io.js' // types -import { Me } from '@global' // ----------------------------------------------------------------- end imports export const AppRow = GObject.registerClass ( { - Template: `file://${Me.path}/preferences/widgets/app-row.ui`, + Template: uri (import.meta.url, 'app-row.ui'), GTypeName: 'AppRow', InternalChildren: [ 'wm_class_instance_entry', @@ -31,15 +30,15 @@ export const AppRow = GObject.registerClass ( ], }, class extends Gtk.ListBoxRow { - private _wm_class_instance_entry !: Gtk.Entry - private _remove_button !: Gtk.Button - private _change_title_btn !: Gtk.Button - private _pick_window_btn !: Gtk.Button - private _title !: Gtk.Label - private _description !: Gtk.Label - private _expand_img !: Gtk.Button - private _revealer !: Gtk.Revealer - _expanded_list_box !: Gtk.ListBox + private _wm_class_instance_entry!: Gtk.Entry + private _remove_button!: Gtk.Button + private _change_title_btn!: Gtk.Button + private _pick_window_btn!: Gtk.Button + private _title!: Gtk.Label + private _description!: Gtk.Label + private _expand_img!: Gtk.Button + private _revealer!: Gtk.Revealer + _expanded_list_box!: Gtk.ListBox private bind_property_handler?: GObject.Binding @@ -140,7 +139,7 @@ export const AppRow = GObject.registerClass ( this.description = '' } else { if (this.title == '') { - this.description = constants.TIPS_EMPTY () + this.description = TIPS_EMPTY () } } } diff --git a/src/preferences/widgets/edit_shadow_window.ts b/src/preferences/widgets/edit_shadow_window.ts index e14eecb..d5eecfa 100644 --- a/src/preferences/widgets/edit_shadow_window.ts +++ b/src/preferences/widgets/edit_shadow_window.ts @@ -1,15 +1,16 @@ // imports.gi -import * as Gtk from '@gi/Gtk' -import { registerClass } from '@gi/GObject' +import * as Gtk from 'gi://Gtk' +import * as GObject from 'gi://GObject' // local modules -import { box_shadow_css } from '@me/utils/types' -import { settings } from '@me/utils/settings' -import { _ } from '@me/utils/i18n' +import { box_shadow_css } from '../../utils/types.js' +import { settings } from '../../utils/settings.js' + +import { gettext as _ } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js' // just used to mark type of value, will be remove in output javascript -import { BoxShadow } from '@me/utils/types' -import { Me } from '@global' +import { BoxShadow } from '../../utils/types.js' +import { uri } from '../../utils/io.js' // ----------------------------------------------------------------- end imports /** @@ -18,9 +19,9 @@ import { Me } from '@global' * This widget used to edit shadow of windows which use rounded corners * effects. */ -export const EditShadowWindow = registerClass ( +export const EditShadowWindow = GObject.registerClass ( { - Template: `file://${Me.path}/preferences/widgets/edit-shadow-window.ui`, + Template: uri (import.meta.url, 'edit-shadow-window.ui'), GTypeName: 'EditShadowWindow', InternalChildren: [ 'opacity_scale', @@ -35,23 +36,23 @@ export const EditShadowWindow = registerClass ( ], }, class extends Gtk.Window { - private _opacity_scale !: Gtk.Scale - private _spread_radius_scale !: Gtk.Scale - private _blur_offset_scale !: Gtk.Scale - private _vertical_offset_scale !: Gtk.Scale - private _horizontal_offset_scale !: Gtk.Scale - private _unfocus_shadow_widget !: Gtk.Widget - private _focus_shadow_widget !: Gtk.Widget - private _focus_toggle_button !: Gtk.ToggleButton - private _unfocus_toggle_button !: Gtk.ToggleButton + private _opacity_scale!: Gtk.Scale + private _spread_radius_scale!: Gtk.Scale + private _blur_offset_scale!: Gtk.Scale + private _vertical_offset_scale!: Gtk.Scale + private _horizontal_offset_scale!: Gtk.Scale + private _unfocus_shadow_widget!: Gtk.Widget + private _focus_shadow_widget!: Gtk.Widget + private _focus_toggle_button!: Gtk.ToggleButton + private _unfocus_toggle_button!: Gtk.ToggleButton // CssProvider to change style of preview widgets in edit window - private unfocus_provider !: Gtk.CssProvider - private focus_provider !: Gtk.CssProvider + private unfocus_provider!: Gtk.CssProvider + private focus_provider!: Gtk.CssProvider // Load box-shadow from settings - private focused_shadow !: BoxShadow - private unfocused_shadow !: BoxShadow + private focused_shadow!: BoxShadow + private unfocused_shadow!: BoxShadow _init () { super._init ({ diff --git a/src/preferences/widgets/reset_dialog.ts b/src/preferences/widgets/reset_dialog.ts index 610c5e8..1108e4d 100644 --- a/src/preferences/widgets/reset_dialog.ts +++ b/src/preferences/widgets/reset_dialog.ts @@ -1,9 +1,9 @@ -import * as GObject from '@gi/GObject' -import * as Gtk from '@gi/Gtk' -import { _ } from '@me/utils/i18n' -import { _log } from '@me/utils/log' -import { SchemasKeys, settings } from '@me/utils/settings' -import { RoundedCornersCfg } from '@me/utils/types' +import * as GObject from 'gi://GObject' +import * as Gtk from 'gi://Gtk' +import { _log } from '../../utils/log.js' +import { SchemasKeys, settings } from '../../utils/settings.js' +import { RoundedCornersCfg } from '../../utils/types.js' +import { gettext as _ } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js' class Cfg { description: string @@ -18,15 +18,15 @@ export const ResetDialog = GObject.registerClass ( {}, class extends Gtk.Dialog { /** Keys to reset */ - private _reset_keys !: { + private _reset_keys!: { [name in SchemasKeys]?: Cfg } /** Global rounded corners settings to reset */ - private _reset_corners_cfg !: { + private _reset_corners_cfg!: { [name in keyof RoundedCornersCfg]?: Cfg } /** Used to select all CheckButtons */ - private _all_check_btns !: Gtk.CheckButton[] + private _all_check_btns!: Gtk.CheckButton[] _init (): void { super._init ({ diff --git a/src/preferences/widgets/rounded_corners_item.ts b/src/preferences/widgets/rounded_corners_item.ts index 4fdc07c..0733e73 100644 --- a/src/preferences/widgets/rounded_corners_item.ts +++ b/src/preferences/widgets/rounded_corners_item.ts @@ -1,20 +1,18 @@ // imports.gi -import * as GObject from '@gi/GObject' -import * as Gtk from '@gi/Gtk' +import * as GObject from 'gi://GObject' +import * as Gtk from 'gi://Gtk' // local modules -import { RoundedCornersCfg } from '@me/utils/types' -import { connections } from '@me/utils/connections' +import { RoundedCornersCfg } from '../../utils/types.js' +import { connections } from '../../utils/connections.js' +import { uri } from '../../utils/io.js' // types -import { Me } from '@global' // ------------------------------------------------------------------ end import -const Template = `file://${Me.path}/preferences/widgets/rounded-corners-item.ui` - export const RoundedCornersItem = GObject.registerClass ( { - Template, + Template: uri (import.meta.url, 'rounded-corners-item.ui'), GTypeName: 'RoundedCornersItem', InternalChildren: [ 'rounded_in_maximized_switch', @@ -31,21 +29,21 @@ export const RoundedCornersItem = GObject.registerClass ( ], }, class extends Gtk.ListBox { - private _rounded_in_maximized_switch !: Gtk.Switch - private _rounded_in_fullscreen_switch !: Gtk.Switch - private _border_radius_scale !: Gtk.Scale - private _smoothing_scale !: Gtk.Scale - private _padding_left_scale !: Gtk.Scale - private _padding_right_scale !: Gtk.Scale - private _padding_top_scale !: Gtk.Scale - private _padding_bottom_scale !: Gtk.Scale - private _revealer !: Gtk.Revealer - private _expander_img !: Gtk.Image + private _rounded_in_maximized_switch!: Gtk.Switch + private _rounded_in_fullscreen_switch!: Gtk.Switch + private _border_radius_scale!: Gtk.Scale + private _smoothing_scale!: Gtk.Scale + private _padding_left_scale!: Gtk.Scale + private _padding_right_scale!: Gtk.Scale + private _padding_top_scale!: Gtk.Scale + private _padding_bottom_scale!: Gtk.Scale + private _revealer!: Gtk.Revealer + private _expander_img!: Gtk.Image - _paddings_row !: Gtk.ListBoxRow + _paddings_row!: Gtk.ListBoxRow - private _scales !: Gtk.Scale[] - private _switches !: Gtk.Switch[] + private _scales!: Gtk.Scale[] + private _switches!: Gtk.Switch[] _init () { super._init () diff --git a/src/prefs.ts b/src/prefs.ts index 3b47a77..3bc42a2 100644 --- a/src/prefs.ts +++ b/src/prefs.ts @@ -1,67 +1,39 @@ -import * as Gtk from '@gi/Gtk' -import * as Gdk from '@gi/Gdk' -import { getCurrentExtension } from '@imports/misc/extensionUtils' - -import { pages } from '@me/preferences/index' -import { init_translations_prefs } from '@me/utils/i18n' - -import { PreferencesWindow, imports } from '@global' - -function load_css () { - const display = Gdk.Display.get_default () - if (display) { - const css = new Gtk.CssProvider () - const path = `${getCurrentExtension ().path}/stylesheet-prefs.css` - css.load_from_path (path) - Gtk.StyleContext.add_provider_for_display (display, css, 0) - } -} - -export function init () { - init_translations_prefs () -} - -// Load preferences Pages for Gnome 40 / Gnome 41 -export function buildPrefsWidget () { - const scrolled_win = new Gtk.ScrolledWindow () - const stack = new Gtk.Stack ({ css_classes: ['page'] }) - const switcher = new Gtk.StackSwitcher ({ stack }) - - scrolled_win.set_child (stack) - - // Add StackSwitcher into HeaderBar - scrolled_win.connect ('realize', () => { - const win = scrolled_win.root as Gtk.Window - win.width_request = 550 - const title_bar = win.get_titlebar () as Gtk.HeaderBar | null - title_bar?.set_title_widget (switcher) - }) - - // Load pages - for (const page of pages ()) { - stack.add_titled (page.widget, page.title, page.title) +import * as Gtk from 'gi://Gtk' +import * as Gdk from 'gi://Gdk' +import * as Adw from 'gi://Adw' + +import { init_settings } from './utils/settings.js' +import { pages } from './preferences/index.js' +import * as Utils from './utils/io.js' +import { + ExtensionPreferences +} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js' + +export default class RoundedWindowCornresPrefs extends ExtensionPreferences { + _load_css () { + const display = Gdk.Display.get_default () + if (display) { + const css = new Gtk.CssProvider () + const path = Utils.path (import.meta.url, 'stylesheet-prefs.css') + css.load_from_path (path) + Gtk.StyleContext.add_provider_for_display (display, css, 0) + } } - // Load css - load_css () - - return scrolled_win -} - -// Load ui for Gnome 42+ -export function fillPreferencesWindow (win: PreferencesWindow) { - const Adw = imports.gi.Adw - - for (const page of pages ()) { - const pref_page = new Adw.PreferencesPage ({ - title: page.title, - icon_name: page.icon_name, - }) - const group = new Adw.PreferencesGroup () - pref_page.add (group) - group.add (page.widget) - win.add (pref_page) + fillPreferencesWindow (win: Adw.PreferencesWindow) { + init_settings (this.getSettings ()) + + for (const page of pages ()) { + const pref_page = new Adw.PreferencesPage ({ + title: page.title, + icon_name: page.icon_name, + }) + const group = new Adw.PreferencesGroup () + pref_page.add (group) + group.add (page.widget) + win.add (pref_page) + } + + this._load_css () } - - load_css () } diff --git a/src/utils/connections.ts b/src/utils/connections.ts index f22e36b..1616cca 100644 --- a/src/utils/connections.ts +++ b/src/utils/connections.ts @@ -1,5 +1,5 @@ // Types -import * as GObject from '@gi/GObject' +import * as GObject from 'gi://GObject' // ---------------------------------------------------------------- [end import] diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 5daf8ed..0ed46fb 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -1,7 +1,5 @@ // This files use for store const variants will used by other modules. -import { _ } from '@me/utils/i18n' - export const constants = { /** Name of shadow actors */ SHADOW_ACTOR_NAME: 'Rounded Window Shadow Actor', @@ -13,12 +11,8 @@ export const constants = { BLUR_EFFECT: 'Patched Blur Effect', /** Padding of shadow actors */ SHADOW_PADDING: 80, - /** Tips when add new items in preferences Page */ - TIPS_EMPTY: () => _ ('Expand this row to pick a window.'), /** Used to mark widget in preferences/page/custom.ts */ DON_T_CONFIG: 'Don\'t Configuration in Custom Page', - /** Item label for background menu */ - ITEM_LABEL: () => _ ('Rounded Corners Settings...'), /** Name of shadow actor to be added in overview */ OVERVIEW_SHADOW_ACTOR: 'Shadow Actor (Overview)', } diff --git a/src/utils/i18n.ts b/src/utils/i18n.ts index 1c6f8a7..e69de29 100644 --- a/src/utils/i18n.ts +++ b/src/utils/i18n.ts @@ -1,24 +0,0 @@ -import * as extUtils from '@imports/misc/extensionUtils' - -const { uuid } = extUtils.getCurrentExtension () - -export const init_translations = () => { - extUtils.initTranslations (uuid) -} -export const init_translations_prefs = () => { - imports.gettext.textdomain (uuid) - extUtils.initTranslations (uuid) -} - -export const _ = imports.gettext.domain (uuid).gettext -export const ngettext = imports.gettext.domain (uuid).ngettext - -declare const imports: { - gettext: { - textdomain(str: string): void - domain: (str: string) => { - gettext(str: string): string - ngettext(str: string, strPlural: string, n: number): string - } - } -} diff --git a/src/utils/io.ts b/src/utils/io.ts index 2b32420..b6626ee 100644 --- a/src/utils/io.ts +++ b/src/utils/io.ts @@ -1,28 +1,39 @@ -import * as Gio from '@gi/Gio' -import * as GLib from '@gi/GLib' -import ByteArray from '@imports/byteArray' +import * as Gio from 'gi://Gio' + +import { _log, _logError } from './log.js' // --------------------------------------------------------------- [end imports] export const load = (path: string): string => { - const [, buffer] = GLib.file_get_contents (path) - const contents = ByteArray.toString (buffer) - GLib.free (buffer) - return contents + const file = Gio.File.new_for_path (path) + + const [, contents, ] = file.load_contents (null) + + const decoder = new TextDecoder ('utf-8') + return decoder.decode (contents) } export const path = (mod_url: string, relative_path: string) => { const parent = Gio.File.new_for_uri (mod_url).get_parent () const mod_dir = parent?.get_path () - return Gio.File.new_for_path (`${mod_dir}/${relative_path}`).get_path () + return Gio.File.new_for_path (`${mod_dir}/${relative_path}`).get_path () ?? '' +} + +export const uri = (mod_url: string, relative_path: string) => { + const parent = Gio.File.new_for_uri (mod_url).get_parent () + + const mod_uri = parent?.get_uri () + return `${mod_uri}/${relative_path}` } export const loadFile = (mod_url: string, relative_path: string) => load (path (mod_url, relative_path) ?? '') -export const loadShader = (path: string) => { - let [declarations, main] = load (path).split (/^.*?main\(\s?\)\s?/m) +export const loadShader = (mod_url: string, relative_path: string) => { + let [declarations, main] = load (path (mod_url, relative_path) ?? '').split ( + /^.*?main\(\s?\)\s?/m + ) declarations = declarations.trim () main = main.trim ().replace (/^[{}]/gm, '').trim () diff --git a/src/utils/log.ts b/src/utils/log.ts index 8c4531b..cd79c68 100644 --- a/src/utils/log.ts +++ b/src/utils/log.ts @@ -1,4 +1,4 @@ -import { settings } from '@me/utils/settings' +import { settings } from './settings.js' import { log, logError } from '@global' // --------------------------------------------------------------- [end imports] diff --git a/src/utils/prefs.ts b/src/utils/prefs.ts index 99b7020..6e12b3b 100644 --- a/src/utils/prefs.ts +++ b/src/utils/prefs.ts @@ -1,8 +1,9 @@ -import { DBus, DBusCallFlags } from '@gi/Gio' -import { Variant } from '@gi/GLib' -import { ListBox } from '@gi/Gtk' +import * as Gio from 'gi://Gio' +import * as GLib from 'gi://GLib' +import * as Gtk from 'gi://Gtk' +import { gettext as _ } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js' -export const list_children = (widget: ListBox) => { +export const list_children = (widget: Gtk.ListBox) => { const children = [] for ( let child = widget.get_first_child (); @@ -20,12 +21,12 @@ export const show_err_msg = (info: string) => { // // Ref: https://gjs.guide/guides/gio/dbus.html#direct-calls - DBus.session.call ( + Gio.DBus.session.call ( 'org.freedesktop.Notifications', '/org/freedesktop/Notifications', 'org.freedesktop.Notifications', 'Notify', - new Variant ('(susssasa{sv}i)', [ + new GLib.Variant ('(susssasa{sv}i)', [ '', 0, '', @@ -36,9 +37,12 @@ export const show_err_msg = (info: string) => { 3000, ]), null, - DBusCallFlags.NONE, + Gio.DBusCallFlags.NONE, -1, null, null ) } + +/** Tips when add new items in preferences Page */ +export const TIPS_EMPTY = () => _ ('Expand this row to pick a window.') diff --git a/src/utils/settings.ts b/src/utils/settings.ts index 9fab14c..5ef5902 100644 --- a/src/utils/settings.ts +++ b/src/utils/settings.ts @@ -1,16 +1,15 @@ // imports.gi -import * as GLib from '@gi/GLib' -import * as Gio from '@gi/Gio' - -// gnome modules -import { getSettings } from '@imports/misc/extensionUtils' +import * as GLib from 'gi://GLib' +import * as Gio from 'gi://Gio' // used to mark types, will be remove in output files. -import * as GObject from '@gi/GObject' -import { BoxShadow } from './types' -import { CustomRoundedCornersCfg } from './types' -import { RoundedCornersCfg } from './types' -import { log } from '@global' +import * as GObject from 'gi://GObject' +import { + BoxShadow, + CustomRoundedCornersCfg, + RoundedCornersCfg, +} from './types.js' +import { log } from '@global' // --------------------------------------------------------------- [end imports] @@ -42,28 +41,28 @@ export type SchemasKeys = * Simple wrapper of Gio.Settings, we will use this class to store and * load settings for this gnome-shell extensions. */ -class Settings { +export class Settings { // Keys of settings, define getter and setter in constructor() - black_list !: string[] - skip_libadwaita_app !: boolean - skip_libhandy_app !: boolean - global_rounded_corner_settings !: RoundedCornersCfg - custom_rounded_corner_settings !: CustomRoundedCornersCfg - focused_shadow !: BoxShadow - unfocused_shadow !: BoxShadow - debug_mode !: boolean - tweak_kitty_terminal !: boolean - enable_preferences_entry !: boolean - border_width !: number - settings_version !: number - border_color !: [number, number, number, number] + black_list!: string[] + skip_libadwaita_app!: boolean + skip_libhandy_app!: boolean + global_rounded_corner_settings!: RoundedCornersCfg + custom_rounded_corner_settings!: CustomRoundedCornersCfg + focused_shadow!: BoxShadow + unfocused_shadow!: BoxShadow + debug_mode!: boolean + tweak_kitty_terminal!: boolean + enable_preferences_entry!: boolean + border_width!: number + settings_version!: number + border_color!: [number, number, number, number] /** GSettings, which used to store and load settings */ - g_settings: Gio.Settings = getSettings ( - 'org.gnome.shell.extensions.rounded-window-corners' - ) + g_settings: Gio.Settings + + constructor (g_settings: Gio.Settings) { + this.g_settings = g_settings - constructor () { // Define getter and setter for properties in class for keys in // schemas this.g_settings.list_keys ().forEach ((key) => { @@ -207,13 +206,13 @@ class Settings { } /** A singleton instance of Settings */ -let _settings: Settings | null = null +let _settings!: Settings + +export const init_settings = (g_settings: Gio.Settings) => { + _settings = new Settings (g_settings) +} /** Access _settings by this method */ export const settings = () => { - if (_settings != null) { - return _settings - } - _settings = new Settings () return _settings } diff --git a/src/utils/types.ts b/src/utils/types.ts index 62df1e3..3cabda5 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -1,9 +1,9 @@ -import { Actor } from '@gi/Clutter' -import { Binding } from '@gi/GObject' -import { ShadowMode, WindowActor } from '@gi/Meta' -import { Bin } from '@gi/St' -import * as Graphene from '@gi/Graphene' -import { SchemasKeys } from '@me/utils/settings' +import * as Clutter from 'gi://Clutter' +import * as GObject from 'gi://GObject' +import * as Meta from 'gi://Meta' +import * as St from 'gi://St' +import * as Graphene from 'gi://Graphene' +import { SchemasKeys } from '../utils/settings.js' /** Bounds of rounded corners */ export class Bounds { @@ -65,16 +65,16 @@ export interface EffectManager { on_switch_workspace?: (actor: ExtensionsWindowActor) => void } -export type ExtensionsWindowActor = WindowActor & { +export type ExtensionsWindowActor = Meta.WindowActor & { __rwc_rounded_window_info?: { - shadow: Bin - visible_binding: Binding + shadow: St.Bin + visible_binding: GObject.Binding unminimized_timeout_id: number } __rwc_blurred_window_info?: { - blur_actor: Actor - visible_binding: Binding + blur_actor: Clutter.Actor + visible_binding: GObject.Binding } - shadow_mode?: ShadowMode + shadow_mode?: Meta.ShadowMode __rwc_last_size?: Graphene.Size } diff --git a/src/utils/ui.ts b/src/utils/ui.ts index 0d41630..a4375ee 100644 --- a/src/utils/ui.ts +++ b/src/utils/ui.ts @@ -1,21 +1,23 @@ // imports.gi -import * as Meta from '@gi/Meta' -import { Settings } from '@gi/Gio' +import * as Meta from 'gi://Meta' +import * as Gio from 'gi://Gio' // gnome modules -import { openPrefs } from '@imports/misc/extensionUtils' -import { PACKAGE_VERSION } from '@imports/misc/config' +import { + Extension, + gettext as _, +} from 'resource:///org/gnome/shell/extensions/extension.js' +import { PACKAGE_VERSION } from 'resource:///org/gnome/shell/misc/config.js' // local modules -import { load } from '@me/utils/io' -import { _log, _logError } from '@me/utils/log' -import { constants } from '@me/utils/constants' -import { _ } from '@me/utils/i18n' +import { load } from './io.js' +import { _log, _logError } from './log.js' +import { constants } from './constants.js' // types -import { global } from '@global' -import * as types from '@me/utils/types' -import { Actor, Effect } from '@gi/Clutter' +import { global } from '@global' +import * as types from './types.js' +import * as Clutter from 'gi://Clutter' // --------------------------------------------------------------- [end imports] @@ -65,7 +67,7 @@ export const getAppType = (meta_window: Meta.Window) => { * scale factor of current monitor */ export const WindowScaleFactor = (win?: Meta.Window) => { - const features = Settings.new ('org.gnome.mutter').get_strv ( + const features = Gio.Settings.new ('org.gnome.mutter').get_strv ( 'experimental-features' ) @@ -98,17 +100,19 @@ type BackgroundExtra = { * @param menu - BackgroundMenu to add */ export const AddBackgroundMenuItem = (menu: BackgroundMenu) => { + const openprefs_item = _ ('Rounded Corners Settings...') for (const item of menu._getMenuItems ()) { - if (item.label?.text === _ (constants.ITEM_LABEL ())) { + if (item.label?.text === openprefs_item) { return } } - menu.addAction (_ (constants.ITEM_LABEL ()), () => { + menu.addAction (openprefs_item, () => { + const extension = Extension.lookupByURL (import.meta.url) as Extension try { - openPrefs () + extension.openPreferences () } catch (err) { - openPrefs () + extension.openPreferences () } }) } @@ -124,10 +128,10 @@ export const SetupBackgroundMenu = () => { export const RestoreBackgroundMenu = () => { const remove_menu_item = (menu: BackgroundMenu) => { const items = menu._getMenuItems () - + const openprefs_item = _ ('Rounded Corners Settings...') for (const i of items) { - if (i?.label?.text === _ (constants.ITEM_LABEL ())) { - (i as Actor).destroy () + if (i?.label?.text === openprefs_item) { + (i as Clutter.Actor).destroy () break } } @@ -192,7 +196,7 @@ export function shell_version (): number { */ export function get_rounded_corners_effect ( actor: Meta.WindowActor -): Effect | null { +): Clutter.Effect | null { const win = actor.meta_window const name = constants.ROUNDED_CORNERS_EFFECT return win.get_client_type () === Meta.WindowClientType.X11 From da7e21a28c699f6f74620bf1aacd3367ef3ee1b8 Mon Sep 17 00:00:00 2001 From: Yi <32430186+yilozt@users.noreply.github.com> Date: Sun, 15 Oct 2023 17:14:41 +0800 Subject: [PATCH 05/11] Make translations works for Gtk4 template xml files --- src/prefs.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/prefs.ts b/src/prefs.ts index 3bc42a2..61feb61 100644 --- a/src/prefs.ts +++ b/src/prefs.ts @@ -5,11 +5,18 @@ import * as Adw from 'gi://Adw' import { init_settings } from './utils/settings.js' import { pages } from './preferences/index.js' import * as Utils from './utils/io.js' -import { - ExtensionPreferences -} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js' +import { ExtensionPreferences } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js' +declare const imports: any export default class RoundedWindowCornresPrefs extends ExtensionPreferences { + constructor (metadata: object) { + super (metadata) + + // Classical GTK4 template ui need this to make translatable string works + imports.gettext.textdomain (this.uuid) + this.initTranslations (this.uuid) + } + _load_css () { const display = Gdk.Display.get_default () if (display) { From ca9a5a455bbc8b36c9a19d439e1e6ab962ccf65b Mon Sep 17 00:00:00 2001 From: Yi <32430186+yilozt@users.noreply.github.com> Date: Sun, 15 Oct 2023 17:16:00 +0800 Subject: [PATCH 06/11] Setup entry to open preferences window on background menu properly --- src/extension.ts | 10 ++++++---- src/utils/ui.ts | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 04b567a..a97eb8b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -55,10 +55,16 @@ export default class RoundedWindowCorners extends Extension { if (layoutManager._startingUp) { const id = layoutManager.connect ('startup-complete', () => { this._window_actor_tracker?.enable () + if (settings ().enable_preferences_entry) { + UI.SetupBackgroundMenu () + } layoutManager.disconnect (id) }) } else { this._window_actor_tracker?.enable () + if (settings ().enable_preferences_entry) { + UI.SetupBackgroundMenu () + } } const self = this @@ -204,10 +210,6 @@ export default class RoundedWindowCorners extends Extension { }) } - if (settings ().enable_preferences_entry) { - UI.SetupBackgroundMenu () - } - const c = connections.get () // Gnome-shell will not disable extensions when _logout/shutdown/restart diff --git a/src/utils/ui.ts b/src/utils/ui.ts index a4375ee..88d7e9d 100644 --- a/src/utils/ui.ts +++ b/src/utils/ui.ts @@ -120,6 +120,7 @@ export const AddBackgroundMenuItem = (menu: BackgroundMenu) => { /** Find all Background menu, then add extra item to it */ export const SetupBackgroundMenu = () => { for (const _bg of global.window_group.first_child.get_children ()) { + _log ('Found Desktop Background obj', _bg) const menu = (_bg as typeof _bg & BackgroundExtra)._backgroundMenu AddBackgroundMenuItem (menu) } From bbe2efec49495ef1053987a1ec72fc2cc4146383 Mon Sep 17 00:00:00 2001 From: Yi <32430186+yilozt@users.noreply.github.com> Date: Mon, 16 Oct 2023 19:26:36 +0800 Subject: [PATCH 07/11] Use console.log () instead of Log() https://gjs.guide/extensions/upgrading/gnome-shell-45.html#logging --- src/utils/log.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/utils/log.ts b/src/utils/log.ts index cd79c68..27216b8 100644 --- a/src/utils/log.ts +++ b/src/utils/log.ts @@ -1,5 +1,4 @@ import { settings } from './settings.js' -import { log, logError } from '@global' // --------------------------------------------------------------- [end imports] @@ -8,14 +7,13 @@ import { log, logError } from '@global' */ export const _log = (...args: unknown[]) => { if (settings ().debug_mode) { - log (`[RoundedCornersEffect] ${args}`) + console.log (`[RoundedCornersEffect] ${args}`) } } /** Always log error message */ export const _logError = (err: Error) => { - log (`[Rounded Corners Effect] Error occurs: ${err.message}`) - logError (err) + console.error (err) } /** From 3fbbd8447ee9ec8743a8ee585347b57c88f07414 Mon Sep 17 00:00:00 2001 From: Yi <32430186+yilozt@users.noreply.github.com> Date: Tue, 17 Oct 2023 02:16:02 +0800 Subject: [PATCH 08/11] Add cloned shadow behind the window when swiching workspace on Desktop --- @imports/ui/workspaceAnimation.d.ts | 11 +++- src/extension.ts | 90 +++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 3 deletions(-) diff --git a/@imports/ui/workspaceAnimation.d.ts b/@imports/ui/workspaceAnimation.d.ts index 5d853af..2e80b39 100644 --- a/@imports/ui/workspaceAnimation.d.ts +++ b/@imports/ui/workspaceAnimation.d.ts @@ -1,15 +1,16 @@ import { Window, WindowActor } from 'gi://Meta' import { Actor, Clone } from 'gi://Clutter' +import * as St from 'gi://St' export class WorkspaceAnimationController { _movingWindow: Window; _switchData: { - monitors: any[]; - gestureActivated: boolean; - inProgress: boolean; + monitors: MonitorGroup[]; }; _swipeTracker: any; _prepareWorkspaceSwitch(workspaceIndices: Array): void; + _finishWorkspaceSwitch(switchData: typeof this._switchData): void; + } export class WorkspaceGroup extends Actor { @@ -22,3 +23,7 @@ export class WorkspaceGroup extends Actor { _syncStacking(): void; _shouldShowWindow(win: Window): boolean; } + +export class MonitorGroup extends St.Widget { + _workspaceGroups: WorkspaceGroup [] +} \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index a97eb8b..550ae74 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -9,6 +9,7 @@ import * as GObject from 'gi://GObject' import { WindowPreview } from 'resource:///org/gnome/shell/ui/windowPreview.js' import { overview, layoutManager } from 'resource:///org/gnome/shell/ui/main.js' import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js' +import { WorkspaceAnimationController } from 'resource:///org/gnome/shell/ui/workspaceAnimation.js' // local modules import { constants } from './utils/constants.js' @@ -31,6 +32,8 @@ import { global } from '@global' export default class RoundedWindowCorners extends Extension { // The methods of gnome-shell to monkey patch private _orig_add_window!: (_: Meta.Window) => void + private _orig_prep_worksapce_swt!: (workspaceIndices: number[]) => void + private _orig_finish_workspace_swt!: typeof WorkspaceAnimationController.prototype._finishWorkspaceSwitch private _services: Services | null = null private _window_actor_tracker: WindowActorTracker | null = null @@ -41,6 +44,10 @@ export default class RoundedWindowCorners extends Extension { // Restore original methods, those methods will be restore when // extensions is disabled this._orig_add_window = WindowPreview.prototype._addWindow + this._orig_prep_worksapce_swt = + WorkspaceAnimationController.prototype._prepareWorkspaceSwitch + this._orig_finish_workspace_swt = + WorkspaceAnimationController.prototype._finishWorkspaceSwitch this._services = new Services () this._window_actor_tracker = new WindowActorTracker () @@ -210,6 +217,83 @@ export default class RoundedWindowCorners extends Extension { }) } + // Just Like the monkey patch when enter overview, need to add cloned shadow + // actor when switching workspaces on Desktop + WorkspaceAnimationController.prototype._prepareWorkspaceSwitch = function ( + workspaceIndices + ) { + self._orig_prep_worksapce_swt.apply (this, [workspaceIndices]) + for (const monitor of this._switchData.monitors) { + for (const workspace of monitor._workspaceGroups) { + // Let shadow actor always behind the window clone actor when we + // switch workspace by Ctrl+Alt+Left/Right + // + // Fix #55 + const restacked_id = global.display.connect ('restacked', () => { + workspace._windowRecords.forEach (({ clone }) => { + const shadow = (clone as WsAnimationActor)._shadow_clone + if (shadow) { + workspace.set_child_below_sibling (shadow, clone) + } + }) + }) + const destroy_id = workspace.connect ('destroy', () => { + global.display.disconnect (restacked_id) + workspace.disconnect (destroy_id) + }) + + workspace._windowRecords.forEach (({ windowActor: actor, clone }) => { + const win = actor.meta_window + const frame_rect = win.get_frame_rect () + const shadow = (actor as ExtensionsWindowActor) + .__rwc_rounded_window_info?.shadow + const enabled = UI.get_rounded_corners_effect (actor)?.enabled + if (shadow && enabled) { + // Only create shadow actor when window should have rounded + // corners when switching workspace + + // Copy shadow actor to workspace group, so that to see + // shadow when switching workspace + const shadow_clone = new Clutter.Clone ({ source: shadow }) + const paddings = + constants.SHADOW_PADDING * UI.WindowScaleFactor (win) + + shadow_clone.width = frame_rect.width + paddings * 2 + shadow_clone.height = frame_rect.height + paddings * 2 + shadow_clone.x = clone.x + frame_rect.x - actor.x - paddings + shadow_clone.y = clone.y + frame_rect.y - actor.y - paddings + + // Should works well work Desktop Cube extensions + clone.connect ( + 'notify::translation-z', + () => (shadow_clone.translation_z = clone.translation_z - 0.05) + ) + + // Add reference shadow clone for clone actor, so that we + // can restack position of shadow when we need + ;(clone as WsAnimationActor)._shadow_clone = shadow_clone + clone.bind_property ('visible', shadow_clone, 'visible', 0) + workspace.insert_child_below (shadow_clone, clone) + } + }) + } + } + } + + WorkspaceAnimationController.prototype._finishWorkspaceSwitch = function ( + switchData + ) { + for (const monitor of this._switchData.monitors) { + for (const workspace of monitor._workspaceGroups) { + workspace._windowRecords.forEach (({ clone }) => { + (clone as WsAnimationActor)._shadow_clone?.destroy () + delete (clone as WsAnimationActor)._shadow_clone + }) + } + } + self._orig_finish_workspace_swt.apply (this, [switchData]) + } + const c = connections.get () // Gnome-shell will not disable extensions when _logout/shutdown/restart @@ -243,6 +327,10 @@ export default class RoundedWindowCorners extends Extension { disable () { // Restore patched methods WindowPreview.prototype._addWindow = this._orig_add_window + WorkspaceAnimationController.prototype._prepareWorkspaceSwitch = + this._orig_prep_worksapce_swt + WorkspaceAnimationController.prototype._finishWorkspaceSwitch = + this._orig_finish_workspace_swt // Remove the item to open preferences page in background menu UI.RestoreBackgroundMenu () @@ -330,3 +418,5 @@ const OverviewShadowActor = GObject.registerClass ( } } ) + +type WsAnimationActor = Clutter.Actor & { _shadow_clone?: Clutter.Actor } From c514c33fa9d9bb81bc18524ddfc678fcabe256fc Mon Sep 17 00:00:00 2001 From: Yi <32430186+yilozt@users.noreply.github.com> Date: Tue, 17 Oct 2023 02:32:00 +0800 Subject: [PATCH 09/11] Clear unused imports & styles --- src/.eslintrc.json | 2 +- src/prefs.ts | 5 ++++- src/utils/io.ts | 4 +--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/.eslintrc.json b/src/.eslintrc.json index 3e13cca..81685dd 100644 --- a/src/.eslintrc.json +++ b/src/.eslintrc.json @@ -45,7 +45,7 @@ "func-call-spacing": ["error", "always"], "no-var": ["error"], "max-len": ["warn", { - "code": 80, + "code": 120, "ignorePattern": "^import" }] }, diff --git a/src/prefs.ts b/src/prefs.ts index 61feb61..c5bcb4b 100644 --- a/src/prefs.ts +++ b/src/prefs.ts @@ -7,7 +7,6 @@ import { pages } from './preferences/index.js' import * as Utils from './utils/io.js' import { ExtensionPreferences } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js' -declare const imports: any export default class RoundedWindowCornresPrefs extends ExtensionPreferences { constructor (metadata: object) { super (metadata) @@ -44,3 +43,7 @@ export default class RoundedWindowCornresPrefs extends ExtensionPreferences { this._load_css () } } + +declare const imports: { + gettext: { textdomain: (uuid: string) => void } +} diff --git a/src/utils/io.ts b/src/utils/io.ts index b6626ee..e126ced 100644 --- a/src/utils/io.ts +++ b/src/utils/io.ts @@ -1,13 +1,11 @@ import * as Gio from 'gi://Gio' -import { _log, _logError } from './log.js' - // --------------------------------------------------------------- [end imports] export const load = (path: string): string => { const file = Gio.File.new_for_path (path) - const [, contents, ] = file.load_contents (null) + const [, contents] = file.load_contents (null) const decoder = new TextDecoder ('utf-8') return decoder.decode (contents) From d51fa4e256f70e2c8d69580608ecc94a36fe8fa7 Mon Sep 17 00:00:00 2001 From: Yi <32430186+yilozt@users.noreply.github.com> Date: Sun, 12 Nov 2023 14:05:24 +0800 Subject: [PATCH 10/11] Add utils function to clear inner `GIO.Settings` --- po/rounded-window-corners@yilozt.pot | 4 ++-- src/preferences/pages/general.ts | 13 ------------- src/prefs.ts | 12 +++++++++++- src/utils/settings.ts | 9 +++++++++ 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/po/rounded-window-corners@yilozt.pot b/po/rounded-window-corners@yilozt.pot index 12a1190..b846568 100644 --- a/po/rounded-window-corners@yilozt.pot +++ b/po/rounded-window-corners@yilozt.pot @@ -2,7 +2,7 @@ msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Report-Msgid-Bugs-To: yilozt@outlook.com\n" -"Project-Id-Version: 11\n" +"Project-Id-Version: 12\n" #: src/preferences/pages/general.ui:284 msgid "Add Settings Entry in right-click menu of Background" @@ -183,7 +183,7 @@ msgid "Right" msgstr "" #: src/utils/ui.ts:103 -#: src/utils/ui.ts:131 +#: src/utils/ui.ts:132 msgid "Rounded Corners Settings..." msgstr "" diff --git a/src/preferences/pages/general.ts b/src/preferences/pages/general.ts index a7b8531..c3ae795 100644 --- a/src/preferences/pages/general.ts +++ b/src/preferences/pages/general.ts @@ -8,7 +8,6 @@ import { settings } from '../../utils/settings.js' import { SchemasKeys } from '../../utils/settings.js' import { connections } from '../../utils/connections.js' import { list_children } from '../../utils/prefs.js' -import { _log } from '../../utils/log.js' import { RoundedCornersItem } from '../widgets/rounded_corners_item.js' import { EditShadowWindow } from '../widgets/edit_shadow_window.js' import { ResetDialog } from '../widgets/reset_dialog.js' @@ -157,18 +156,6 @@ export const General = GObject.registerClass ( }) } - vfunc_root (): void { - super.vfunc_root () - const win = this.root as Gtk.Window - - // Disconnect all signal when close prefs - win.connect ('close-request', () => { - _log ('Disconnect Signals') - connections.get ().disconnect_all () - connections.del () - }) - } - private build_ui () { list_children (this.config_items).forEach ((i) => { this.config_items.remove (i) diff --git a/src/prefs.ts b/src/prefs.ts index c5bcb4b..7934482 100644 --- a/src/prefs.ts +++ b/src/prefs.ts @@ -2,8 +2,10 @@ import * as Gtk from 'gi://Gtk' import * as Gdk from 'gi://Gdk' import * as Adw from 'gi://Adw' -import { init_settings } from './utils/settings.js' +import { connections } from './utils/connections.js' +import { init_settings, uninit_settings } from './utils/settings.js' import { pages } from './preferences/index.js' +import { _log } from './utils/log.js' import * as Utils from './utils/io.js' import { ExtensionPreferences } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js' @@ -40,6 +42,14 @@ export default class RoundedWindowCornresPrefs extends ExtensionPreferences { win.add (pref_page) } + // Disconnect all signal when close prefs + win.connect ('close-request', () => { + _log ('Disconnect Signals') + connections.get ().disconnect_all () + connections.del () + uninit_settings () + }) + this._load_css () } } diff --git a/src/utils/settings.ts b/src/utils/settings.ts index 5ef5902..15924b2 100644 --- a/src/utils/settings.ts +++ b/src/utils/settings.ts @@ -203,6 +203,10 @@ export class Settings { log (`[RoundedWindowCorners] Update Settings to v${VERSION}`) } + + _disable () { + (this.g_settings as Gio.Settings | null) = null + } } /** A singleton instance of Settings */ @@ -212,6 +216,11 @@ export const init_settings = (g_settings: Gio.Settings) => { _settings = new Settings (g_settings) } +export const uninit_settings = () => { + _settings?._disable () + ;(_settings as Settings | null) = null +} + /** Access _settings by this method */ export const settings = () => { return _settings From aaa66f0fe35dc1ecd47f6b2d09e7636699fea132 Mon Sep 17 00:00:00 2001 From: Yi <32430186+yilozt@users.noreply.github.com> Date: Sun, 12 Nov 2023 16:08:52 +0800 Subject: [PATCH 11/11] Disconnect notify signal for clone window object when switching workspace --- src/extension.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/extension.ts b/src/extension.ts index 550ae74..bde7985 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -264,10 +264,14 @@ export default class RoundedWindowCorners extends Extension { shadow_clone.y = clone.y + frame_rect.y - actor.y - paddings // Should works well work Desktop Cube extensions - clone.connect ( + const notify_id = clone.connect ( 'notify::translation-z', () => (shadow_clone.translation_z = clone.translation_z - 0.05) ) + const destroy_id = clone.connect ('destroy', () => { + clone.disconnect (notify_id) + clone.disconnect (destroy_id) + }) // Add reference shadow clone for clone actor, so that we // can restack position of shadow when we need