diff options
author | Evan Welsh <contact@evanwelsh.com> | 2022-05-22 13:43:23 -0700 |
---|---|---|
committer | Evan Welsh <contact@evanwelsh.com> | 2022-05-22 13:43:23 -0700 |
commit | 6671f83d8614ed355f03389ad692b0a6ab3fea7b (patch) | |
tree | 7e839e4ec54ad3268d738f2e2649ed3d3ee1b4c0 | |
parent | 6ab6db38fe5a45979167d2b6f0cadd06a772798f (diff) | |
download | gjs-ewlsh/fix-reentrancy-issues-private-lib.tar.gz |
overrides: Allow re-entrancy in GLib importsewlsh/fix-reentrancy-issues-private-lib
-rw-r--r-- | gi/repo.cpp | 7 | ||||
-rw-r--r-- | gjs/engine.cpp | 23 | ||||
-rw-r--r-- | modules/core/overrides/GLib.js | 420 | ||||
-rw-r--r-- | modules/core/overrides/GObject.js | 978 | ||||
-rw-r--r-- | modules/core/overrides/Gio.js | 347 | ||||
-rw-r--r-- | modules/core/overrides/Gtk.js | 268 | ||||
-rw-r--r-- | modules/core/overrides/cairo.js | 6 |
7 files changed, 1031 insertions, 1018 deletions
diff --git a/gi/repo.cpp b/gi/repo.cpp index 9f5d4e1f..f09b4f80 100644 --- a/gi/repo.cpp +++ b/gi/repo.cpp @@ -551,9 +551,10 @@ lookup_override_function(JSContext *cx, goto fail; } - if (!gjs_object_require_property(cx, module, "override module", - atoms.init(), function) || - !function.isObjectOrNull()) { + if (!JS_GetPropertyById(cx, module, atoms.init(), function)) + return false; + + if (!function.isUndefined() && !function.isObjectOrNull()) { gjs_throw(cx, "Unexpected value for _init in overrides module"); goto fail; } diff --git a/gjs/engine.cpp b/gjs/engine.cpp index 16d84cc1..bd66a79b 100644 --- a/gjs/engine.cpp +++ b/gjs/engine.cpp @@ -79,7 +79,9 @@ class GjsSourceHook : public js::SourceHook { #ifdef G_OS_WIN32 HMODULE gjs_dll; -static bool gjs_is_inited = false; +static bool _gjs_is_inited = false; + +static bool gjs_is_inited() { return _gjs_is_inited; } BOOL WINAPI DllMain (HINSTANCE hinstDLL, @@ -90,7 +92,11 @@ LPVOID lpvReserved) { case DLL_PROCESS_ATTACH: gjs_dll = hinstDLL; - gjs_is_inited = JS_Init(); + + if (!JS_Init()) + g_error("Could not initialize Javascript"); + + _gjs_is_inited = true; break; case DLL_THREAD_DETACH: @@ -104,7 +110,6 @@ LPVOID lpvReserved) return TRUE; } - #else class GjsInit { public: @@ -116,15 +121,19 @@ public: ~GjsInit() { JS_ShutDown(); } - - explicit operator bool() const { return true; } }; -static GjsInit gjs_is_inited; +static bool gjs_is_inited() { + // In C++11 static function variables are guaranteed to only be + // initialized once. + static GjsInit gjs_is_inited; + + return true; +} #endif JSContext* gjs_create_js_context(GjsContextPrivate* uninitialized_gjs) { - g_assert(gjs_is_inited); + g_assert(gjs_is_inited()); JSContext *cx = JS_NewContext(32 * 1024 * 1024 /* max bytes */); if (!cx) return nullptr; diff --git a/modules/core/overrides/GLib.js b/modules/core/overrides/GLib.js index cb8f177e..ed6005ba 100644 --- a/modules/core/overrides/GLib.js +++ b/modules/core/overrides/GLib.js @@ -2,8 +2,8 @@ // SPDX-FileCopyrightText: 2011 Giovanni Campagna const ByteArray = imports.byteArray; - -let GLib; +const {GLib, GjsPrivate} = imports.gi; +const {log_set_writer_func, log_set_writer_default} = GjsPrivate; const SIMPLE_TYPES = ['b', 'y', 'n', 'q', 'i', 'u', 'x', 't', 'h', 'd', 's', 'o', 'g']; @@ -256,71 +256,66 @@ function _escapeCharacterSetChars(char) { return char; } -function _init() { - // this is imports.gi.GLib - - GLib = this; - - // For convenience in property min or max values, since GLib.MAXINT64 and - // friends will log a warning when used - this.MAXINT64_BIGINT = 0x7fff_ffff_ffff_ffffn; - this.MININT64_BIGINT = -this.MAXINT64_BIGINT - 1n; - this.MAXUINT64_BIGINT = 0xffff_ffff_ffff_ffffn; - - // small HACK: we add a matches() method to standard Errors so that - // you can do "if (e.matches(Ns.FooError, Ns.FooError.SOME_CODE))" - // without checking instanceof - Error.prototype.matches = function () { - return false; - }; - - // Guard against domains that aren't valid quarks and would lead - // to a crash - const quarkToString = this.quark_to_string; - const realNewLiteral = this.Error.new_literal; - this.Error.new_literal = function (domain, code, message) { - if (quarkToString(domain) === null) - throw new TypeError(`Error.new_literal: ${domain} is not a valid domain`); - return realNewLiteral(domain, code, message); - }; - - this.Variant._new_internal = function (sig, value) { - let signature = Array.prototype.slice.call(sig); - - let variant = _packVariant(signature, value); - if (signature.length !== 0) - throw new TypeError('Invalid GVariant signature (more than one single complete type)'); - - return variant; - }; - - // Deprecate version of new GLib.Variant() - this.Variant.new = function (sig, value) { - return new GLib.Variant(sig, value); - }; - this.Variant.prototype.unpack = function () { - return _unpackVariant(this, false); - }; - this.Variant.prototype.deepUnpack = function () { - return _unpackVariant(this, true); - }; - // backwards compatibility alias - this.Variant.prototype.deep_unpack = this.Variant.prototype.deepUnpack; - - // Note: discards type information, if the variant contains any 'v' types - this.Variant.prototype.recursiveUnpack = function () { - return _unpackVariant(this, true, true); - }; - - this.Variant.prototype.toString = function () { - return `[object variant of type "${this.get_type_string()}"]`; - }; - - this.Bytes.prototype.toArray = function () { - return imports._byteArrayNative.fromGBytes(this); - }; - - this.log_structured = +// For convenience in property min or max values, since GLib.MAXINT64 and +// friends will log a warning when used +GLib.MAXINT64_BIGINT = 0x7fff_ffff_ffff_ffffn; +GLib.MININT64_BIGINT = -GLib.MAXINT64_BIGINT - 1n; +GLib.MAXUINT64_BIGINT = 0xffff_ffff_ffff_ffffn; + +// small HACK: we add a matches() method to standard Errors so that +// you can do "if (e.matches(Ns.FooError, Ns.FooError.SOME_CODE))" +// without checking instanceof +Error.prototype.matches = function () { + return false; +}; + +// Guard against domains that aren't valid quarks and would lead +// to a crash +const quarkToString = GLib.quark_to_string; +const realNewLiteral = GLib.Error.new_literal; +GLib.Error.new_literal = function (domain, code, message) { + if (quarkToString(domain) === null) + throw new TypeError(`Error.new_literal: ${domain} is not a valid domain`); + return realNewLiteral(domain, code, message); +}; + +GLib.Variant._new_internal = function (sig, value) { + let signature = Array.prototype.slice.call(sig); + + let variant = _packVariant(signature, value); + if (signature.length !== 0) + throw new TypeError('Invalid GVariant signature (more than one single complete type)'); + + return variant; +}; + +// Deprecate version of new GLib.Variant() +GLib.Variant.new = function (sig, value) { + return new GLib.Variant(sig, value); +}; +GLib.Variant.prototype.unpack = function () { + return _unpackVariant(this, false); +}; +GLib.Variant.prototype.deepUnpack = function () { + return _unpackVariant(this, true); +}; +// backwards compatibility alias +GLib.Variant.prototype.deep_unpack = GLib.Variant.prototype.deepUnpack; + +// Note: discards type information, if the variant contains any 'v' types +GLib.Variant.prototype.recursiveUnpack = function () { + return _unpackVariant(this, true, true); +}; + +GLib.Variant.prototype.toString = function () { + return `[object variant of type "${GLib.get_type_string()}"]`; +}; + +GLib.Bytes.prototype.toArray = function () { + return imports._byteArrayNative.fromGBytes(this); +}; + +GLib.log_structured = /** * @param {string} logDomain * @param {GLib.LogLevelFlags} logLevel @@ -353,156 +348,147 @@ function _init() { GLib.log_variant(logDomain, logLevel, new GLib.Variant('a{sv}', fields)); }; - // GjsPrivate depends on GLib so we cannot import it - // before GLib is fully resolved. - - this.log_set_writer_func_variant = function (...args) { - const {log_set_writer_func} = imports.gi.GjsPrivate; - - log_set_writer_func(...args); - }; - - this.log_set_writer_default = function (...args) { - const {log_set_writer_default} = imports.gi.GjsPrivate; - - log_set_writer_default(...args); - }; - - this.log_set_writer_func = function (writer_func) { - const {log_set_writer_func} = imports.gi.GjsPrivate; - - if (typeof writer_func !== 'function') { - log_set_writer_func(writer_func); - } else { - log_set_writer_func(function (logLevel, stringFields) { - const stringFieldsObj = {...stringFields.recursiveUnpack()}; - return writer_func(logLevel, stringFieldsObj); - }); - } - }; - - this.VariantDict.prototype.lookup = function (key, variantType = null, deep = false) { - if (typeof variantType === 'string') - variantType = new GLib.VariantType(variantType); +GLib.log_set_writer_func_variant = function (...args) { + log_set_writer_func(...args); +}; - const variant = this.lookup_value(key, variantType); - if (variant === null) - return null; - return _unpackVariant(variant, deep); - }; - - // Prevent user code from calling GLib string manipulation functions that - // return the same string that was passed in. These can't be annotated - // properly, and will mostly crash. - // Here we provide approximate implementations of the functions so that if - // they had happened to work in the past, they will continue working, but - // log a stack trace and a suggestion of what to use instead. - // Exceptions are thrown instead for GLib.stpcpy() of which the return value - // is useless anyway and GLib.ascii_formatd() which is too complicated to - // implement here. - - this.stpcpy = function () { - throw _notIntrospectableError('GLib.stpcpy()', 'the + operator'); - }; - - this.strstr_len = function (haystack, len, needle) { - _warnNotIntrospectable('GLib.strstr_len()', 'String.indexOf()'); - let searchString = haystack; - if (len !== -1) - searchString = searchString.slice(0, len); - const index = searchString.indexOf(needle); - if (index === -1) - return null; - return haystack.slice(index); - }; - - this.strrstr = function (haystack, needle) { - _warnNotIntrospectable('GLib.strrstr()', 'String.lastIndexOf()'); - const index = haystack.lastIndexOf(needle); - if (index === -1) - return null; - return haystack.slice(index); - }; - - this.strrstr_len = function (haystack, len, needle) { - _warnNotIntrospectable('GLib.strrstr_len()', 'String.lastIndexOf()'); - let searchString = haystack; - if (len !== -1) - searchString = searchString.slice(0, len); - const index = searchString.lastIndexOf(needle); - if (index === -1) - return null; - return haystack.slice(index); - }; - - this.strup = function (string) { - _warnNotIntrospectable('GLib.strup()', - 'String.toUpperCase() or GLib.ascii_strup()'); - return string.toUpperCase(); - }; - - this.strdown = function (string) { - _warnNotIntrospectable('GLib.strdown()', - 'String.toLowerCase() or GLib.ascii_strdown()'); - return string.toLowerCase(); - }; - - this.strreverse = function (string) { - _warnNotIntrospectable('GLib.strreverse()', - 'Array.reverse() and String.join()'); - return [...string].reverse().join(''); - }; - - this.ascii_dtostr = function (unused, len, number) { - _warnNotIntrospectable('GLib.ascii_dtostr()', 'JS string conversion'); - return `${number}`.slice(0, len); - }; +GLib.log_set_writer_default = function (...args) { + log_set_writer_default(...args); +}; - this.ascii_formatd = function () { - throw _notIntrospectableError('GLib.ascii_formatd()', - 'Number.toExponential() and string interpolation'); - }; - - this.strchug = function (string) { - _warnNotIntrospectable('GLib.strchug()', 'String.trimStart()'); - return string.trimStart(); - }; - - this.strchomp = function (string) { - _warnNotIntrospectable('GLib.strchomp()', 'String.trimEnd()'); - return string.trimEnd(); - }; - - // g_strstrip() is a macro and therefore doesn't even appear in the GIR - // file, but we may as well include it here since it's trivial - this.strstrip = function (string) { - _warnNotIntrospectable('GLib.strstrip()', 'String.trim()'); - return string.trim(); - }; - - this.strdelimit = function (string, delimiters, newDelimiter) { - _warnNotIntrospectable('GLib.strdelimit()', 'String.replace()'); - - if (delimiters === null) - delimiters = GLib.STR_DELIMITERS; - if (typeof newDelimiter === 'number') - newDelimiter = String.fromCharCode(newDelimiter); - - const delimiterChars = delimiters.split(''); - const escapedDelimiterChars = delimiterChars.map(_escapeCharacterSetChars); - const delimiterRegex = new RegExp(`[${escapedDelimiterChars.join('')}]`, 'g'); - return string.replace(delimiterRegex, newDelimiter); - }; - - this.strcanon = function (string, validChars, substitutor) { - _warnNotIntrospectable('GLib.strcanon()', 'String.replace()'); - - if (typeof substitutor === 'number') - substitutor = String.fromCharCode(substitutor); +GLib.log_set_writer_func = function (writer_func) { + if (typeof writer_func !== 'function') { + log_set_writer_func(writer_func); + } else { + log_set_writer_func(function (logLevel, stringFields) { + const stringFieldsObj = {...stringFields.recursiveUnpack()}; + return writer_func(logLevel, stringFieldsObj); + }); + } +}; + +GLib.VariantDict.prototype.lookup = function (key, variantType = null, deep = false) { + if (typeof variantType === 'string') + variantType = new GLib.VariantType(variantType); + + const variant = this.lookup_value(key, variantType); + if (variant === null) + return null; + return _unpackVariant(variant, deep); +}; + +// Prevent user code from calling GLib string manipulation functions that +// return the same string that was passed in. These can't be annotated +// properly, and will mostly crash. +// Here we provide approximate implementations of the functions so that if +// they had happened to work in the past, they will continue working, but +// log a stack trace and a suggestion of what to use instead. +// Exceptions are thrown instead for GLib.stpcpy() of which the return value +// is useless anyway and GLib.ascii_formatd() which is too complicated to +// implement here. + +GLib.stpcpy = function () { + throw _notIntrospectableError('GLib.stpcpy()', 'the + operator'); +}; + +GLib.strstr_len = function (haystack, len, needle) { + _warnNotIntrospectable('GLib.strstr_len()', 'String.indexOf()'); + let searchString = haystack; + if (len !== -1) + searchString = searchString.slice(0, len); + const index = searchString.indexOf(needle); + if (index === -1) + return null; + return haystack.slice(index); +}; + +GLib.strrstr = function (haystack, needle) { + _warnNotIntrospectable('GLib.strrstr()', 'String.lastIndexOf()'); + const index = haystack.lastIndexOf(needle); + if (index === -1) + return null; + return haystack.slice(index); +}; + +GLib.strrstr_len = function (haystack, len, needle) { + _warnNotIntrospectable('GLib.strrstr_len()', 'String.lastIndexOf()'); + let searchString = haystack; + if (len !== -1) + searchString = searchString.slice(0, len); + const index = searchString.lastIndexOf(needle); + if (index === -1) + return null; + return haystack.slice(index); +}; + +GLib.strup = function (string) { + _warnNotIntrospectable('GLib.strup()', + 'String.toUpperCase() or GLib.ascii_strup()'); + return string.toUpperCase(); +}; + +GLib.strdown = function (string) { + _warnNotIntrospectable('GLib.strdown()', + 'String.toLowerCase() or GLib.ascii_strdown()'); + return string.toLowerCase(); +}; + +GLib.strreverse = function (string) { + _warnNotIntrospectable('GLib.strreverse()', + 'Array.reverse() and String.join()'); + return [...string].reverse().join(''); +}; + +GLib.ascii_dtostr = function (unused, len, number) { + _warnNotIntrospectable('GLib.ascii_dtostr()', 'JS string conversion'); + return `${number}`.slice(0, len); +}; + +GLib.ascii_formatd = function () { + throw _notIntrospectableError('GLib.ascii_formatd()', + 'Number.toExponential() and string interpolation'); +}; + +GLib.strchug = function (string) { + _warnNotIntrospectable('GLib.strchug()', 'String.trimStart()'); + return string.trimStart(); +}; + +GLib.strchomp = function (string) { + _warnNotIntrospectable('GLib.strchomp()', 'String.trimEnd()'); + return string.trimEnd(); +}; + +// g_strstrip() is a macro and therefore doesn't even appear in the GIR +// file, but we may as well include it here since it's trivial +GLib.strstrip = function (string) { + _warnNotIntrospectable('GLib.strstrip()', 'String.trim()'); + return string.trim(); +}; + +GLib.strdelimit = function (string, delimiters, newDelimiter) { + _warnNotIntrospectable('GLib.strdelimit()', 'String.replace()'); + + if (delimiters === null) + delimiters = GLib.STR_DELIMITERS; + if (typeof newDelimiter === 'number') + newDelimiter = String.fromCharCode(newDelimiter); + + const delimiterChars = delimiters.split(''); + const escapedDelimiterChars = delimiterChars.map(_escapeCharacterSetChars); + const delimiterRegex = new RegExp(`[${escapedDelimiterChars.join('')}]`, 'g'); + return string.replace(delimiterRegex, newDelimiter); +}; + +GLib.strcanon = function (string, validChars, substitutor) { + _warnNotIntrospectable('GLib.strcanon()', 'String.replace()'); + + if (typeof substitutor === 'number') + substitutor = String.fromCharCode(substitutor); + + const validArray = validChars.split(''); + const escapedValidArray = validArray.map(_escapeCharacterSetChars); + const invalidRegex = new RegExp(`[^${escapedValidArray.join('')}]`, 'g'); + return string.replace(invalidRegex, substitutor); +}; - const validArray = validChars.split(''); - const escapedValidArray = validArray.map(_escapeCharacterSetChars); - const invalidRegex = new RegExp(`[^${escapedValidArray.join('')}]`, 'g'); - return string.replace(invalidRegex, substitutor); - }; -} diff --git a/modules/core/overrides/GObject.js b/modules/core/overrides/GObject.js index df6f9dc2..76168bf7 100644 --- a/modules/core/overrides/GObject.js +++ b/modules/core/overrides/GObject.js @@ -4,12 +4,10 @@ // SPDX-FileCopyrightText: 2017 Philip Chimento <philip.chimento@gmail.com>, <philip@endlessm.com> const Gi = imports._gi; -const {GjsPrivate, GLib} = imports.gi; +const {GjsPrivate, GLib, GObject} = imports.gi; const {_checkAccessors, _registerType} = imports._common; const Legacy = imports._legacy; -let GObject; - var GTypeName = Symbol('GType name'); var GTypeFlags = Symbol('GType flags'); var interfaces = Symbol('GObject interfaces'); @@ -281,277 +279,276 @@ function _checkProperties(klass) { _checkAccessors(klass.prototype, pspec, GObject); } -function _init() { - GObject = this; - function _makeDummyClass(obj, name, upperName, gtypeName, actual) { - let gtype = GObject.type_from_name(gtypeName); - obj[`TYPE_${upperName}`] = gtype; - obj[name] = function (v) { - return actual(v); - }; - obj[name].$gtype = gtype; - } - GObject.gtypeNameBasedOnJSPath = false; +function _makeDummyClass(obj, name, upperName, gtypeName, actual) { + let gtype = GObject.type_from_name(gtypeName); + obj[`TYPE_${upperName}`] = gtype; + obj[name] = function (v) { + return actual(v); + }; + obj[name].$gtype = gtype; +} - _makeDummyClass(GObject, 'VoidType', 'NONE', 'void', function () {}); - _makeDummyClass(GObject, 'Char', 'CHAR', 'gchar', Number); - _makeDummyClass(GObject, 'UChar', 'UCHAR', 'guchar', Number); - _makeDummyClass(GObject, 'Unichar', 'UNICHAR', 'gint', String); +GObject.gtypeNameBasedOnJSPath = false; - GObject.TYPE_BOOLEAN = GObject.type_from_name('gboolean'); - GObject.Boolean = Boolean; - Boolean.$gtype = GObject.TYPE_BOOLEAN; +_makeDummyClass(GObject, 'VoidType', 'NONE', 'void', function () {}); +_makeDummyClass(GObject, 'Char', 'CHAR', 'gchar', Number); +_makeDummyClass(GObject, 'UChar', 'UCHAR', 'guchar', Number); +_makeDummyClass(GObject, 'Unichar', 'UNICHAR', 'gint', String); - _makeDummyClass(GObject, 'Int', 'INT', 'gint', Number); - _makeDummyClass(GObject, 'UInt', 'UINT', 'guint', Number); - _makeDummyClass(GObject, 'Long', 'LONG', 'glong', Number); - _makeDummyClass(GObject, 'ULong', 'ULONG', 'gulong', Number); - _makeDummyClass(GObject, 'Int64', 'INT64', 'gint64', Number); - _makeDummyClass(GObject, 'UInt64', 'UINT64', 'guint64', Number); +GObject.TYPE_BOOLEAN = GObject.type_from_name('gboolean'); +GObject.Boolean = Boolean; +Boolean.$gtype = GObject.TYPE_BOOLEAN; - GObject.TYPE_ENUM = GObject.type_from_name('GEnum'); - GObject.TYPE_FLAGS = GObject.type_from_name('GFlags'); +_makeDummyClass(GObject, 'Int', 'INT', 'gint', Number); +_makeDummyClass(GObject, 'UInt', 'UINT', 'guint', Number); +_makeDummyClass(GObject, 'Long', 'LONG', 'glong', Number); +_makeDummyClass(GObject, 'ULong', 'ULONG', 'gulong', Number); +_makeDummyClass(GObject, 'Int64', 'INT64', 'gint64', Number); +_makeDummyClass(GObject, 'UInt64', 'UINT64', 'guint64', Number); - _makeDummyClass(GObject, 'Float', 'FLOAT', 'gfloat', Number); - GObject.TYPE_DOUBLE = GObject.type_from_name('gdouble'); - GObject.Double = Number; - Number.$gtype = GObject.TYPE_DOUBLE; +GObject.TYPE_ENUM = GObject.type_from_name('GEnum'); +GObject.TYPE_FLAGS = GObject.type_from_name('GFlags'); - GObject.TYPE_STRING = GObject.type_from_name('gchararray'); - GObject.String = String; - String.$gtype = GObject.TYPE_STRING; +_makeDummyClass(GObject, 'Float', 'FLOAT', 'gfloat', Number); +GObject.TYPE_DOUBLE = GObject.type_from_name('gdouble'); +GObject.Double = Number; +Number.$gtype = GObject.TYPE_DOUBLE; - GObject.TYPE_JSOBJECT = GObject.type_from_name('JSObject'); - GObject.JSObject = Object; - Object.$gtype = GObject.TYPE_JSOBJECT; +GObject.TYPE_STRING = GObject.type_from_name('gchararray'); +GObject.String = String; +String.$gtype = GObject.TYPE_STRING; - GObject.TYPE_POINTER = GObject.type_from_name('gpointer'); - GObject.TYPE_BOXED = GObject.type_from_name('GBoxed'); - GObject.TYPE_PARAM = GObject.type_from_name('GParam'); - GObject.TYPE_INTERFACE = GObject.type_from_name('GInterface'); - GObject.TYPE_OBJECT = GObject.type_from_name('GObject'); - GObject.TYPE_VARIANT = GObject.type_from_name('GVariant'); +GObject.TYPE_JSOBJECT = GObject.type_from_name('JSObject'); +GObject.JSObject = Object; +Object.$gtype = GObject.TYPE_JSOBJECT; - _makeDummyClass(GObject, 'Type', 'GTYPE', 'GType', GObject.type_from_name); +GObject.TYPE_POINTER = GObject.type_from_name('gpointer'); +GObject.TYPE_BOXED = GObject.type_from_name('GBoxed'); +GObject.TYPE_PARAM = GObject.type_from_name('GParam'); +GObject.TYPE_INTERFACE = GObject.type_from_name('GInterface'); +GObject.TYPE_OBJECT = GObject.type_from_name('GObject'); +GObject.TYPE_VARIANT = GObject.type_from_name('GVariant'); - GObject.ParamSpec.char = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { - return GObject.param_spec_char(name, nick, blurb, minimum, maximum, defaultValue, flags); - }; +_makeDummyClass(GObject, 'Type', 'GTYPE', 'GType', GObject.type_from_name); - GObject.ParamSpec.uchar = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { - return GObject.param_spec_uchar(name, nick, blurb, minimum, maximum, defaultValue, flags); - }; +GObject.ParamSpec.char = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { + return GObject.param_spec_char(name, nick, blurb, minimum, maximum, defaultValue, flags); +}; - GObject.ParamSpec.int = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { - return GObject.param_spec_int(name, nick, blurb, minimum, maximum, defaultValue, flags); - }; +GObject.ParamSpec.uchar = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { + return GObject.param_spec_uchar(name, nick, blurb, minimum, maximum, defaultValue, flags); +}; - GObject.ParamSpec.uint = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { - return GObject.param_spec_uint(name, nick, blurb, minimum, maximum, defaultValue, flags); - }; +GObject.ParamSpec.int = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { + return GObject.param_spec_int(name, nick, blurb, minimum, maximum, defaultValue, flags); +}; - GObject.ParamSpec.long = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { - return GObject.param_spec_long(name, nick, blurb, minimum, maximum, defaultValue, flags); - }; +GObject.ParamSpec.uint = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { + return GObject.param_spec_uint(name, nick, blurb, minimum, maximum, defaultValue, flags); +}; - GObject.ParamSpec.ulong = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { - return GObject.param_spec_ulong(name, nick, blurb, minimum, maximum, defaultValue, flags); - }; +GObject.ParamSpec.long = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { + return GObject.param_spec_long(name, nick, blurb, minimum, maximum, defaultValue, flags); +}; - GObject.ParamSpec.int64 = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { - return GObject.param_spec_int64(name, nick, blurb, minimum, maximum, defaultValue, flags); - }; +GObject.ParamSpec.ulong = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { + return GObject.param_spec_ulong(name, nick, blurb, minimum, maximum, defaultValue, flags); +}; - GObject.ParamSpec.uint64 = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { - return GObject.param_spec_uint64(name, nick, blurb, minimum, maximum, defaultValue, flags); - }; +GObject.ParamSpec.int64 = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { + return GObject.param_spec_int64(name, nick, blurb, minimum, maximum, defaultValue, flags); +}; - GObject.ParamSpec.float = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { - return GObject.param_spec_float(name, nick, blurb, minimum, maximum, defaultValue, flags); - }; +GObject.ParamSpec.uint64 = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { + return GObject.param_spec_uint64(name, nick, blurb, minimum, maximum, defaultValue, flags); +}; - GObject.ParamSpec.boolean = function (name, nick, blurb, flags, defaultValue) { - return GObject.param_spec_boolean(name, nick, blurb, defaultValue, flags); - }; +GObject.ParamSpec.float = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { + return GObject.param_spec_float(name, nick, blurb, minimum, maximum, defaultValue, flags); +}; - GObject.ParamSpec.flags = function (name, nick, blurb, flags, flagsType, defaultValue) { - return GObject.param_spec_flags(name, nick, blurb, flagsType, defaultValue, flags); - }; +GObject.ParamSpec.boolean = function (name, nick, blurb, flags, defaultValue) { + return GObject.param_spec_boolean(name, nick, blurb, defaultValue, flags); +}; - GObject.ParamSpec.enum = function (name, nick, blurb, flags, enumType, defaultValue) { - return GObject.param_spec_enum(name, nick, blurb, enumType, defaultValue, flags); - }; +GObject.ParamSpec.flags = function (name, nick, blurb, flags, flagsType, defaultValue) { + return GObject.param_spec_flags(name, nick, blurb, flagsType, defaultValue, flags); +}; - GObject.ParamSpec.double = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { - return GObject.param_spec_double(name, nick, blurb, minimum, maximum, defaultValue, flags); - }; +GObject.ParamSpec.enum = function (name, nick, blurb, flags, enumType, defaultValue) { + return GObject.param_spec_enum(name, nick, blurb, enumType, defaultValue, flags); +}; - GObject.ParamSpec.string = function (name, nick, blurb, flags, defaultValue) { - return GObject.param_spec_string(name, nick, blurb, defaultValue, flags); - }; +GObject.ParamSpec.double = function (name, nick, blurb, flags, minimum, maximum, defaultValue) { + return GObject.param_spec_double(name, nick, blurb, minimum, maximum, defaultValue, flags); +}; - GObject.ParamSpec.boxed = function (name, nick, blurb, flags, boxedType) { - return GObject.param_spec_boxed(name, nick, blurb, boxedType, flags); - }; +GObject.ParamSpec.string = function (name, nick, blurb, flags, defaultValue) { + return GObject.param_spec_string(name, nick, blurb, defaultValue, flags); +}; - GObject.ParamSpec.object = function (name, nick, blurb, flags, objectType) { - return GObject.param_spec_object(name, nick, blurb, objectType, flags); - }; +GObject.ParamSpec.boxed = function (name, nick, blurb, flags, boxedType) { + return GObject.param_spec_boxed(name, nick, blurb, boxedType, flags); +}; + +GObject.ParamSpec.object = function (name, nick, blurb, flags, objectType) { + return GObject.param_spec_object(name, nick, blurb, objectType, flags); +}; - GObject.ParamSpec.jsobject = function (name, nick, blurb, flags) { - return GObject.param_spec_boxed(name, nick, blurb, Object.$gtype, flags); - }; +GObject.ParamSpec.jsobject = function (name, nick, blurb, flags) { + return GObject.param_spec_boxed(name, nick, blurb, Object.$gtype, flags); +}; - GObject.ParamSpec.param = function (name, nick, blurb, flags, paramType) { - return GObject.param_spec_param(name, nick, blurb, paramType, flags); - }; +GObject.ParamSpec.param = function (name, nick, blurb, flags, paramType) { + return GObject.param_spec_param(name, nick, blurb, paramType, flags); +}; - GObject.ParamSpec.override = Gi.override_property; +GObject.ParamSpec.override = Gi.override_property; - Object.defineProperties(GObject.ParamSpec.prototype, { - 'name': { - configurable: false, - enumerable: false, - get() { - return this.get_name(); - }, +Object.defineProperties(GObject.ParamSpec.prototype, { + 'name': { + configurable: false, + enumerable: false, + get() { + return this.get_name(); }, - '_nick': { - configurable: false, - enumerable: false, - get() { - return this.get_nick(); - }, + }, + '_nick': { + configurable: false, + enumerable: false, + get() { + return this.get_nick(); }, - 'nick': { - configurable: false, - enumerable: false, - get() { - return this.get_nick(); - }, + }, + 'nick': { + configurable: false, + enumerable: false, + get() { + return this.get_nick(); }, - '_blurb': { - configurable: false, - enumerable: false, - get() { - return this.get_blurb(); - }, + }, + '_blurb': { + configurable: false, + enumerable: false, + get() { + return this.get_blurb(); }, - 'blurb': { - configurable: false, - enumerable: false, - get() { - return this.get_blurb(); - }, + }, + 'blurb': { + configurable: false, + enumerable: false, + get() { + return this.get_blurb(); }, - 'default_value': { - configurable: false, - enumerable: false, - get() { - return this.get_default_value(); - }, + }, + 'default_value': { + configurable: false, + enumerable: false, + get() { + return this.get_default_value(); }, - 'flags': { - configurable: false, - enumerable: false, - get() { - return GjsPrivate.param_spec_get_flags(this); - }, + }, + 'flags': { + configurable: false, + enumerable: false, + get() { + return GjsPrivate.param_spec_get_flags(this); }, - 'value_type': { - configurable: false, - enumerable: false, - get() { - return GjsPrivate.param_spec_get_value_type(this); - }, + }, + 'value_type': { + configurable: false, + enumerable: false, + get() { + return GjsPrivate.param_spec_get_value_type(this); }, - 'owner_type': { - configurable: false, - enumerable: false, - get() { - return GjsPrivate.param_spec_get_owner_type(this); - }, + }, + 'owner_type': { + configurable: false, + enumerable: false, + get() { + return GjsPrivate.param_spec_get_owner_type(this); }, - }); + }, +}); - let {GObjectMeta, GObjectInterface} = Legacy.defineGObjectLegacyObjects(GObject); - GObject.Class = GObjectMeta; - GObject.Interface = GObjectInterface; - GObject.Object.prototype.__metaclass__ = GObject.Class; +let {GObjectMeta, GObjectInterface} = Legacy.defineGObjectLegacyObjects(GObject); +GObject.Class = GObjectMeta; +GObject.Interface = GObjectInterface; +GObject.Object.prototype.__metaclass__ = GObject.Class; - // For compatibility with Lang.Class... we need a _construct - // or the Lang.Class constructor will fail. - GObject.Object.prototype._construct = function (...args) { - this._init(...args); - return this; - }; +// For compatibility with Lang.Class... we need a _construct +// or the Lang.Class constructor will fail. +GObject.Object.prototype._construct = function (...args) { + this._init(...args); + return this; +}; - GObject.registerClass = registerClass; +GObject.registerClass = registerClass; - GObject.Object.new = function (gtype, props = {}) { - const constructor = Gi.lookupConstructor(gtype); +GObject.Object.new = function (gtype, props = {}) { + const constructor = Gi.lookupConstructor(gtype); - if (!constructor) - throw new Error(`Constructor for gtype ${gtype} not found`); - return new constructor(props); - }; + if (!constructor) + throw new Error(`Constructor for gtype ${gtype} not found`); + return new constructor(props); +}; - GObject.Object.new_with_properties = function (gtype, names, values) { - if (!Array.isArray(names) || !Array.isArray(values)) - throw new Error('new_with_properties takes two arrays (names, values)'); - if (names.length !== values.length) - throw new Error('Arrays passed to new_with_properties must be the same length'); +GObject.Object.new_with_properties = function (gtype, names, values) { + if (!Array.isArray(names) || !Array.isArray(values)) + throw new Error('new_with_properties takes two arrays (names, values)'); + if (names.length !== values.length) + throw new Error('Arrays passed to new_with_properties must be the same length'); - const props = Object.fromEntries(names.map((name, ix) => [name, values[ix]])); - return GObject.Object.new(gtype, props); - }; + const props = Object.fromEntries(names.map((name, ix) => [name, values[ix]])); + return GObject.Object.new(gtype, props); +}; - GObject.Object._classInit = function (klass) { - _checkProperties(klass); +GObject.Object._classInit = function (klass) { + _checkProperties(klass); - if (_registerType in klass) - klass[_registerType](); - else - _resolveLegacyClassFunction(klass, _registerType).call(klass); + if (_registerType in klass) + klass[_registerType](); + else + _resolveLegacyClassFunction(klass, _registerType).call(klass); - return klass; - }; + return klass; +}; - // For backwards compatibility only. Use instanceof instead. - GObject.Object.implements = function (iface) { - if (iface.$gtype) - return GObject.type_is_a(this, iface.$gtype); - return false; - }; +// For backwards compatibility only. Use instanceof instead. +GObject.Object.implements = function (iface) { + if (iface.$gtype) + return GObject.type_is_a(this, iface.$gtype); + return false; +}; - function registerGObjectType() { - let klass = this; +function registerGObjectType() { + let klass = this; - let gtypename = _createGTypeName(klass); - let gflags = klass.hasOwnProperty(GTypeFlags) ? klass[GTypeFlags] : 0; - let gobjectInterfaces = klass.hasOwnProperty(interfaces) ? klass[interfaces] : []; - let propertiesArray = _propertiesAsArray(klass); - let parent = Object.getPrototypeOf(klass); - let gobjectSignals = klass.hasOwnProperty(signals) ? klass[signals] : []; + let gtypename = _createGTypeName(klass); + let gflags = klass.hasOwnProperty(GTypeFlags) ? klass[GTypeFlags] : 0; + let gobjectInterfaces = klass.hasOwnProperty(interfaces) ? klass[interfaces] : []; + let propertiesArray = _propertiesAsArray(klass); + let parent = Object.getPrototypeOf(klass); + let gobjectSignals = klass.hasOwnProperty(signals) ? klass[signals] : []; - // Default to the GObject-specific prototype, fallback on the JS prototype for GI native classes. - const parentPrototype = parent.prototype[Gi.gobject_prototype_symbol] ?? parent.prototype; + // Default to the GObject-specific prototype, fallback on the JS prototype for GI native classes. + const parentPrototype = parent.prototype[Gi.gobject_prototype_symbol] ?? parent.prototype; - const [giPrototype, registeredType] = Gi.register_type_with_class( - klass, parentPrototype, gtypename, gflags, - gobjectInterfaces, propertiesArray); + const [giPrototype, registeredType] = Gi.register_type_with_class( + klass, parentPrototype, gtypename, gflags, + gobjectInterfaces, propertiesArray); - _defineGType(klass, giPrototype, registeredType); - _createSignals(klass.$gtype, gobjectSignals); + _defineGType(klass, giPrototype, registeredType); + _createSignals(klass.$gtype, gobjectSignals); - // Reverse the interface array to give the last required interface precedence over the first. - const requiredInterfaces = [...gobjectInterfaces].reverse(); - requiredInterfaces.forEach(iface => - _copyInterfacePrototypeDescriptors(klass.prototype, iface.prototype)); + // Reverse the interface array to give the last required interface precedence over the first. + const requiredInterfaces = [...gobjectInterfaces].reverse(); + requiredInterfaces.forEach(iface => + _copyInterfacePrototypeDescriptors(klass.prototype, iface.prototype)); - Object.getOwnPropertyNames(klass.prototype) + Object.getOwnPropertyNames(klass.prototype) .filter(name => name.startsWith('vfunc_') || name.startsWith('on_')) .forEach(name => { let descr = Object.getOwnPropertyDescriptor(klass.prototype, name); @@ -575,64 +572,64 @@ function _init() { } }); - gobjectInterfaces.forEach(iface => - _checkInterface(iface, klass.prototype)); + gobjectInterfaces.forEach(iface => + _checkInterface(iface, klass.prototype)); - // Lang.Class parent classes don't support static inheritance - if (!('implements' in klass)) - klass.implements = GObject.Object.implements; - } + // Lang.Class parent classes don't support static inheritance + if (!('implements' in klass)) + klass.implements = GObject.Object.implements; +} - Object.defineProperty(GObject.Object, _registerType, { - value: registerGObjectType, - writable: false, - configurable: false, - enumerable: false, - }); +Object.defineProperty(GObject.Object, _registerType, { + value: registerGObjectType, + writable: false, + configurable: false, + enumerable: false, +}); - function interfaceInstanceOf(instance) { - if (instance && typeof instance === 'object' && +function interfaceInstanceOf(instance) { + if (instance && typeof instance === 'object' && GObject.Interface.prototype.isPrototypeOf(this.prototype)) - return GObject.type_is_a(instance, this); + return GObject.type_is_a(instance, this); - return false; - } + return false; +} - function registerInterfaceType() { - let klass = this; +function registerInterfaceType() { + let klass = this; - let gtypename = _createGTypeName(klass); - let gobjectInterfaces = klass.hasOwnProperty(requires) ? klass[requires] : []; - let props = _propertiesAsArray(klass); - let gobjectSignals = klass.hasOwnProperty(signals) ? klass[signals] : []; + let gtypename = _createGTypeName(klass); + let gobjectInterfaces = klass.hasOwnProperty(requires) ? klass[requires] : []; + let props = _propertiesAsArray(klass); + let gobjectSignals = klass.hasOwnProperty(signals) ? klass[signals] : []; - const [giPrototype, registeredType] = Gi.register_interface_with_class(klass, gtypename, gobjectInterfaces, - props); + const [giPrototype, registeredType] = Gi.register_interface_with_class(klass, gtypename, gobjectInterfaces, + props); - _defineGType(klass, giPrototype, registeredType); - _createSignals(klass.$gtype, gobjectSignals); + _defineGType(klass, giPrototype, registeredType); + _createSignals(klass.$gtype, gobjectSignals); - Object.defineProperty(klass, Symbol.hasInstance, { - value: interfaceInstanceOf, - }); + Object.defineProperty(klass, Symbol.hasInstance, { + value: interfaceInstanceOf, + }); - return klass; - } + return klass; +} - Object.defineProperty(GObject.Interface, _registerType, { - value: registerInterfaceType, - writable: false, - configurable: false, - enumerable: false, - }); +Object.defineProperty(GObject.Interface, _registerType, { + value: registerInterfaceType, + writable: false, + configurable: false, + enumerable: false, +}); - GObject.Interface._classInit = function (klass) { - if (_registerType in klass) - klass[_registerType](); - else - _resolveLegacyClassFunction(klass, _registerType).call(klass); +GObject.Interface._classInit = function (klass) { + if (_registerType in klass) + klass[_registerType](); + else + _resolveLegacyClassFunction(klass, _registerType).call(klass); - Object.getOwnPropertyNames(klass.prototype) + Object.getOwnPropertyNames(klass.prototype) .filter(key => key !== 'constructor') .concat(Object.getOwnPropertySymbols(klass.prototype)) .forEach(key => { @@ -651,235 +648,234 @@ function _init() { Object.defineProperty(klass.prototype, key, descr); }); - return klass; - }; - - /** - * Use this to signify a function that must be overridden in an - * implementation of the interface. - */ - GObject.NotImplementedError = class NotImplementedError extends Error { - get name() { - return 'NotImplementedError'; - } - }; - - // These will be copied in the Gtk overrides - // Use __X__ syntax to indicate these variables should not be used publicly. - - GObject.__gtkCssName__ = _gtkCssName; - GObject.__gtkTemplate__ = _gtkTemplate; - GObject.__gtkChildren__ = _gtkChildren; - GObject.__gtkInternalChildren__ = _gtkInternalChildren; - - // Expose GObject static properties for ES6 classes - - GObject.GTypeName = GTypeName; - GObject.requires = requires; - GObject.interfaces = interfaces; - GObject.properties = properties; - GObject.signals = signals; - - // Replacement for non-introspectable g_object_set() - GObject.Object.prototype.set = function (params) { - Object.assign(this, params); - }; - - GObject.Object.prototype.bind_property_full = function (...args) { - return GjsPrivate.g_object_bind_property_full(this, ...args); - }; - - // fake enum for signal accumulators, keep in sync with gi/object.c - GObject.AccumulatorType = { - NONE: 0, - FIRST_WINS: 1, - TRUE_HANDLED: 2, - }; - - GObject.Object.prototype.disconnect = function (id) { - return GObject.signal_handler_disconnect(this, id); - }; - GObject.Object.prototype.block_signal_handler = function (id) { - return GObject.signal_handler_block(this, id); - }; - GObject.Object.prototype.unblock_signal_handler = function (id) { - return GObject.signal_handler_unblock(this, id); - }; - GObject.Object.prototype.stop_emission_by_name = function (detailedName) { - return GObject.signal_stop_emission_by_name(this, detailedName); - }; - - // A simple workaround if you have a class with .connect, .disconnect or .emit - // methods (such as Gio.Socket.connect or NMClient.Device.disconnect) - // The original g_signal_* functions are not introspectable anyway, because - // we need our own handling of signal argument marshalling - GObject.signal_connect = function (object, name, handler) { - return GObject.Object.prototype.connect.call(object, name, handler); - }; - GObject.signal_connect_after = function (object, name, handler) { - return GObject.Object.prototype.connect_after.call(object, name, handler); - }; - GObject.signal_emit_by_name = function (object, ...nameAndArgs) { - return GObject.Object.prototype.emit.apply(object, nameAndArgs); - }; - - // Replacements for signal_handler_find() and similar functions, which can't - // work normally since we connect private closures - GObject._real_signal_handler_find = GObject.signal_handler_find; - GObject._real_signal_handlers_block_matched = GObject.signal_handlers_block_matched; - GObject._real_signal_handlers_unblock_matched = GObject.signal_handlers_unblock_matched; - GObject._real_signal_handlers_disconnect_matched = GObject.signal_handlers_disconnect_matched; - - /** - * Finds the first signal handler that matches certain selection criteria. - * The criteria are passed as properties of a match object. - * The match object has to be non-empty for successful matches. - * If no handler was found, a falsy value is returned. - * - * @function - * @param {GObject.Object} instance - the instance owning the signal handler - * to be found. - * @param {object} match - a properties object indicating whether to match - * by signal ID, detail, or callback function. - * @param {string} [match.signalId] - signal the handler has to be connected - * to. - * @param {string} [match.detail] - signal detail the handler has to be - * connected to. - * @param {Function} [match.func] - the callback function the handler will - * invoke. - * @returns {number | bigint | object | null} A valid non-0 signal handler ID for - * a successful match. - */ - GObject.signal_handler_find = function (instance, match) { - // For backwards compatibility - if (arguments.length === 7) - // eslint-disable-next-line prefer-rest-params - return GObject._real_signal_handler_find(...arguments); - return instance[Gi.signal_find_symbol](match); - }; - /** - * Blocks all handlers on an instance that match certain selection criteria. - * The criteria are passed as properties of a match object. - * The match object has to have at least `func` for successful matches. - * If no handlers were found, 0 is returned, the number of blocked handlers - * otherwise. - * - * @function - * @param {GObject.Object} instance - the instance owning the signal handler - * to be found. - * @param {object} match - a properties object indicating whether to match - * by signal ID, detail, or callback function. - * @param {string} [match.signalId] - signal the handler has to be connected - * to. - * @param {string} [match.detail] - signal detail the handler has to be - * connected to. - * @param {Function} match.func - the callback function the handler will - * invoke. - * @returns {number} The number of handlers that matched. - */ - GObject.signal_handlers_block_matched = function (instance, match) { - // For backwards compatibility - if (arguments.length === 7) - // eslint-disable-next-line prefer-rest-params - return GObject._real_signal_handlers_block_matched(...arguments); - return instance[Gi.signals_block_symbol](match); - }; - /** - * Unblocks all handlers on an instance that match certain selection - * criteria. - * The criteria are passed as properties of a match object. - * The match object has to have at least `func` for successful matches. - * If no handlers were found, 0 is returned, the number of unblocked - * handlers otherwise. - * The match criteria should not apply to any handlers that are not - * currently blocked. - * - * @function - * @param {GObject.Object} instance - the instance owning the signal handler - * to be found. - * @param {object} match - a properties object indicating whether to match - * by signal ID, detail, or callback function. - * @param {string} [match.signalId] - signal the handler has to be connected - * to. - * @param {string} [match.detail] - signal detail the handler has to be - * connected to. - * @param {Function} match.func - the callback function the handler will - * invoke. - * @returns {number} The number of handlers that matched. - */ - GObject.signal_handlers_unblock_matched = function (instance, match) { - // For backwards compatibility - if (arguments.length === 7) - // eslint-disable-next-line prefer-rest-params - return GObject._real_signal_handlers_unblock_matched(...arguments); - return instance[Gi.signals_unblock_symbol](match); - }; - /** - * Disconnects all handlers on an instance that match certain selection - * criteria. - * The criteria are passed as properties of a match object. - * The match object has to have at least `func` for successful matches. - * If no handlers were found, 0 is returned, the number of disconnected - * handlers otherwise. - * - * @function - * @param {GObject.Object} instance - the instance owning the signal handler - * to be found. - * @param {object} match - a properties object indicating whether to match - * by signal ID, detail, or callback function. - * @param {string} [match.signalId] - signal the handler has to be connected - * to. - * @param {string} [match.detail] - signal detail the handler has to be - * connected to. - * @param {Function} match.func - the callback function the handler will - * invoke. - * @returns {number} The number of handlers that matched. - */ - GObject.signal_handlers_disconnect_matched = function (instance, match) { - // For backwards compatibility - if (arguments.length === 7) - // eslint-disable-next-line prefer-rest-params - return GObject._real_signal_handlers_disconnect_matched(...arguments); - return instance[Gi.signals_disconnect_symbol](match); - }; - - // Also match the macros used in C APIs, even though they're not introspected - - /** - * Blocks all handlers on an instance that match `func`. - * - * @function - * @param {GObject.Object} instance - the instance to block handlers from. - * @param {Function} func - the callback function the handler will invoke. - * @returns {number} The number of handlers that matched. - */ - GObject.signal_handlers_block_by_func = function (instance, func) { - return instance[Gi.signals_block_symbol]({func}); - }; - /** - * Unblocks all handlers on an instance that match `func`. - * - * @function - * @param {GObject.Object} instance - the instance to unblock handlers from. - * @param {Function} func - the callback function the handler will invoke. - * @returns {number} The number of handlers that matched. - */ - GObject.signal_handlers_unblock_by_func = function (instance, func) { - return instance[Gi.signals_unblock_symbol]({func}); - }; - /** - * Disconnects all handlers on an instance that match `func`. - * - * @function - * @param {GObject.Object} instance - the instance to remove handlers from. - * @param {Function} func - the callback function the handler will invoke. - * @returns {number} The number of handlers that matched. - */ - GObject.signal_handlers_disconnect_by_func = function (instance, func) { - return instance[Gi.signals_disconnect_symbol]({func}); - }; - GObject.signal_handlers_disconnect_by_data = function () { - throw new Error('GObject.signal_handlers_disconnect_by_data() is not \ + return klass; +}; + +/** + * Use this to signify a function that must be overridden in an + * implementation of the interface. + */ +GObject.NotImplementedError = class NotImplementedError extends Error { + get name() { + return 'NotImplementedError'; + } +}; + +// These will be copied in the Gtk overrides +// Use __X__ syntax to indicate these variables should not be used publicly. + +GObject.__gtkCssName__ = _gtkCssName; +GObject.__gtkTemplate__ = _gtkTemplate; +GObject.__gtkChildren__ = _gtkChildren; +GObject.__gtkInternalChildren__ = _gtkInternalChildren; + +// Expose GObject static properties for ES6 classes + +GObject.GTypeName = GTypeName; +GObject.requires = requires; +GObject.interfaces = interfaces; +GObject.properties = properties; +GObject.signals = signals; + +// Replacement for non-introspectable g_object_set() +GObject.Object.prototype.set = function (params) { + Object.assign(this, params); +}; + +GObject.Object.prototype.bind_property_full = function (...args) { + return GjsPrivate.g_object_bind_property_full(this, ...args); +}; + +// fake enum for signal accumulators, keep in sync with gi/object.c +GObject.AccumulatorType = { + NONE: 0, + FIRST_WINS: 1, + TRUE_HANDLED: 2, +}; + +GObject.Object.prototype.disconnect = function (id) { + return GObject.signal_handler_disconnect(this, id); +}; +GObject.Object.prototype.block_signal_handler = function (id) { + return GObject.signal_handler_block(this, id); +}; +GObject.Object.prototype.unblock_signal_handler = function (id) { + return GObject.signal_handler_unblock(this, id); +}; +GObject.Object.prototype.stop_emission_by_name = function (detailedName) { + return GObject.signal_stop_emission_by_name(this, detailedName); +}; + +// A simple workaround if you have a class with .connect, .disconnect or .emit +// methods (such as Gio.Socket.connect or NMClient.Device.disconnect) +// The original g_signal_* functions are not introspectable anyway, because +// we need our own handling of signal argument marshalling +GObject.signal_connect = function (object, name, handler) { + return GObject.Object.prototype.connect.call(object, name, handler); +}; +GObject.signal_connect_after = function (object, name, handler) { + return GObject.Object.prototype.connect_after.call(object, name, handler); +}; +GObject.signal_emit_by_name = function (object, ...nameAndArgs) { + return GObject.Object.prototype.emit.apply(object, nameAndArgs); +}; + +// Replacements for signal_handler_find() and similar functions, which can't +// work normally since we connect private closures +GObject._real_signal_handler_find = GObject.signal_handler_find; +GObject._real_signal_handlers_block_matched = GObject.signal_handlers_block_matched; +GObject._real_signal_handlers_unblock_matched = GObject.signal_handlers_unblock_matched; +GObject._real_signal_handlers_disconnect_matched = GObject.signal_handlers_disconnect_matched; + +/** + * Finds the first signal handler that matches certain selection criteria. + * The criteria are passed as properties of a match object. + * The match object has to be non-empty for successful matches. + * If no handler was found, a falsy value is returned. + * + * @function + * @param {GObject.Object} instance - the instance owning the signal handler + * to be found. + * @param {object} match - a properties object indicating whether to match + * by signal ID, detail, or callback function. + * @param {string} [match.signalId] - signal the handler has to be connected + * to. + * @param {string} [match.detail] - signal detail the handler has to be + * connected to. + * @param {Function} [match.func] - the callback function the handler will + * invoke. + * @returns {number | bigint | object | null} A valid non-0 signal handler ID for + * a successful match. + */ +GObject.signal_handler_find = function (instance, match) { + // For backwards compatibility + if (arguments.length === 7) + // eslint-disable-next-line prefer-rest-params + return GObject._real_signal_handler_find(...arguments); + return instance[Gi.signal_find_symbol](match); +}; +/** + * Blocks all handlers on an instance that match certain selection criteria. + * The criteria are passed as properties of a match object. + * The match object has to have at least `func` for successful matches. + * If no handlers were found, 0 is returned, the number of blocked handlers + * otherwise. + * + * @function + * @param {GObject.Object} instance - the instance owning the signal handler + * to be found. + * @param {object} match - a properties object indicating whether to match + * by signal ID, detail, or callback function. + * @param {string} [match.signalId] - signal the handler has to be connected + * to. + * @param {string} [match.detail] - signal detail the handler has to be + * connected to. + * @param {Function} match.func - the callback function the handler will + * invoke. + * @returns {number} The number of handlers that matched. + */ +GObject.signal_handlers_block_matched = function (instance, match) { + // For backwards compatibility + if (arguments.length === 7) + // eslint-disable-next-line prefer-rest-params + return GObject._real_signal_handlers_block_matched(...arguments); + return instance[Gi.signals_block_symbol](match); +}; +/** + * Unblocks all handlers on an instance that match certain selection + * criteria. + * The criteria are passed as properties of a match object. + * The match object has to have at least `func` for successful matches. + * If no handlers were found, 0 is returned, the number of unblocked + * handlers otherwise. + * The match criteria should not apply to any handlers that are not + * currently blocked. + * + * @function + * @param {GObject.Object} instance - the instance owning the signal handler + * to be found. + * @param {object} match - a properties object indicating whether to match + * by signal ID, detail, or callback function. + * @param {string} [match.signalId] - signal the handler has to be connected + * to. + * @param {string} [match.detail] - signal detail the handler has to be + * connected to. + * @param {Function} match.func - the callback function the handler will + * invoke. + * @returns {number} The number of handlers that matched. + */ +GObject.signal_handlers_unblock_matched = function (instance, match) { + // For backwards compatibility + if (arguments.length === 7) + // eslint-disable-next-line prefer-rest-params + return GObject._real_signal_handlers_unblock_matched(...arguments); + return instance[Gi.signals_unblock_symbol](match); +}; +/** + * Disconnects all handlers on an instance that match certain selection + * criteria. + * The criteria are passed as properties of a match object. + * The match object has to have at least `func` for successful matches. + * If no handlers were found, 0 is returned, the number of disconnected + * handlers otherwise. + * + * @function + * @param {GObject.Object} instance - the instance owning the signal handler + * to be found. + * @param {object} match - a properties object indicating whether to match + * by signal ID, detail, or callback function. + * @param {string} [match.signalId] - signal the handler has to be connected + * to. + * @param {string} [match.detail] - signal detail the handler has to be + * connected to. + * @param {Function} match.func - the callback function the handler will + * invoke. + * @returns {number} The number of handlers that matched. + */ +GObject.signal_handlers_disconnect_matched = function (instance, match) { + // For backwards compatibility + if (arguments.length === 7) + // eslint-disable-next-line prefer-rest-params + return GObject._real_signal_handlers_disconnect_matched(...arguments); + return instance[Gi.signals_disconnect_symbol](match); +}; + +// Also match the macros used in C APIs, even though they're not introspected + +/** + * Blocks all handlers on an instance that match `func`. + * + * @function + * @param {GObject.Object} instance - the instance to block handlers from. + * @param {Function} func - the callback function the handler will invoke. + * @returns {number} The number of handlers that matched. + */ +GObject.signal_handlers_block_by_func = function (instance, func) { + return instance[Gi.signals_block_symbol]({func}); +}; +/** + * Unblocks all handlers on an instance that match `func`. + * + * @function + * @param {GObject.Object} instance - the instance to unblock handlers from. + * @param {Function} func - the callback function the handler will invoke. + * @returns {number} The number of handlers that matched. + */ +GObject.signal_handlers_unblock_by_func = function (instance, func) { + return instance[Gi.signals_unblock_symbol]({func}); +}; +/** + * Disconnects all handlers on an instance that match `func`. + * + * @function + * @param {GObject.Object} instance - the instance to remove handlers from. + * @param {Function} func - the callback function the handler will invoke. + * @returns {number} The number of handlers that matched. + */ +GObject.signal_handlers_disconnect_by_func = function (instance, func) { + return instance[Gi.signals_disconnect_symbol]({func}); +}; +GObject.signal_handlers_disconnect_by_data = function () { + throw new Error('GObject.signal_handlers_disconnect_by_data() is not \ introspectable. Use GObject.signal_handlers_disconnect_by_func() instead.'); - }; -} +}; diff --git a/modules/core/overrides/Gio.js b/modules/core/overrides/Gio.js index 6cc29b17..16c5c4d9 100644 --- a/modules/core/overrides/Gio.js +++ b/modules/core/overrides/Gio.js @@ -1,10 +1,8 @@ // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later // SPDX-FileCopyrightText: 2011 Giovanni Campagna -var GLib = imports.gi.GLib; -var GjsPrivate = imports.gi.GjsPrivate; -var Signals = imports.signals; -var Gio; +const {GLib, Gio, GjsPrivate} = imports.gi; +const Signals = imports.signals; // Ensures that a Gio.UnixFDList being passed into or out of a DBus method with // a parameter type that includes 'h' somewhere, actually has entries in it for @@ -453,186 +451,183 @@ function _promisify(proto, asyncFunc, }; } -function _init() { - Gio = this; - - Gio.DBus = { - get session() { - return Gio.bus_get_sync(Gio.BusType.SESSION, null); - }, - get system() { - return Gio.bus_get_sync(Gio.BusType.SYSTEM, null); - }, - - // Namespace some functions - get: Gio.bus_get, - get_finish: Gio.bus_get_finish, - get_sync: Gio.bus_get_sync, - - own_name: Gio.bus_own_name, - own_name_on_connection: Gio.bus_own_name_on_connection, - unown_name: Gio.bus_unown_name, - - watch_name: Gio.bus_watch_name, - watch_name_on_connection: Gio.bus_watch_name_on_connection, - unwatch_name: Gio.bus_unwatch_name, +Gio.DBus = { + get session() { + return Gio.bus_get_sync(Gio.BusType.SESSION, null); + }, + get system() { + return Gio.bus_get_sync(Gio.BusType.SYSTEM, null); + }, + + // Namespace some functions + get: Gio.bus_get, + get_finish: Gio.bus_get_finish, + get_sync: Gio.bus_get_sync, + + own_name: Gio.bus_own_name, + own_name_on_connection: Gio.bus_own_name_on_connection, + unown_name: Gio.bus_unown_name, + + watch_name: Gio.bus_watch_name, + watch_name_on_connection: Gio.bus_watch_name_on_connection, + unwatch_name: Gio.bus_unwatch_name, +}; + +Gio.DBusConnection.prototype.watch_name = function (name, flags, appeared, vanished) { + return Gio.bus_watch_name_on_connection(this, name, flags, appeared, vanished); +}; +Gio.DBusConnection.prototype.unwatch_name = function (id) { + return Gio.bus_unwatch_name(id); +}; +Gio.DBusConnection.prototype.own_name = function (name, flags, acquired, lost) { + return Gio.bus_own_name_on_connection(this, name, flags, acquired, lost); +}; +Gio.DBusConnection.prototype.unown_name = function (id) { + return Gio.bus_unown_name(id); +}; + +_injectToMethod(Gio.DBusProxy.prototype, 'init', _addDBusConvenience); +_injectToMethod(Gio.DBusProxy.prototype, 'init_async', _addDBusConvenience); +_injectToStaticMethod(Gio.DBusProxy, 'new_sync', _addDBusConvenience); +_injectToStaticMethod(Gio.DBusProxy, 'new_finish', _addDBusConvenience); +_injectToStaticMethod(Gio.DBusProxy, 'new_for_bus_sync', _addDBusConvenience); +_injectToStaticMethod(Gio.DBusProxy, 'new_for_bus_finish', _addDBusConvenience); +Gio.DBusProxy.prototype.connectSignal = Signals._connect; +Gio.DBusProxy.prototype.disconnectSignal = Signals._disconnect; + +Gio.DBusProxy.makeProxyWrapper = _makeProxyWrapper; + +// Some helpers +_wrapFunction(Gio.DBusNodeInfo, 'new_for_xml', _newNodeInfo); +Gio.DBusInterfaceInfo.new_for_xml = _newInterfaceInfo; + +Gio.DBusExportedObject = GjsPrivate.DBusImplementation; +Gio.DBusExportedObject.wrapJSObject = _wrapJSObject; + +// ListStore +Gio.ListStore.prototype[Symbol.iterator] = _listModelIterator; +Gio.ListStore.prototype.insert_sorted = function (item, compareFunc) { + return GjsPrivate.list_store_insert_sorted(this, item, compareFunc); +}; +Gio.ListStore.prototype.sort = function (compareFunc) { + return GjsPrivate.list_store_sort(this, compareFunc); +}; + +// Promisify +Gio._promisify = _promisify; + +// Temporary Gio.File.prototype fix +Gio._LocalFilePrototype = Gio.File.new_for_path('/').constructor.prototype; + +Gio.File.prototype.replace_contents_async = function replace_contents_async(contents, etag, make_backup, flags, cancellable, callback) { + return this.replace_contents_bytes_async(contents, etag, make_backup, flags, cancellable, callback); +}; + +// Override Gio.Settings and Gio.SettingsSchema - the C API asserts if +// trying to access a nonexistent schema or key, which is not handy for +// shell-extension writers + +Gio.SettingsSchema.prototype._realGetKey = Gio.SettingsSchema.prototype.get_key; +Gio.SettingsSchema.prototype.get_key = function (key) { + if (!this.has_key(key)) + throw new Error(`GSettings key ${key} not found in schema ${this.get_id()}`); + return this._realGetKey(key); +}; + +Gio.Settings.prototype._realMethods = Object.assign({}, Gio.Settings.prototype); + +function createCheckedMethod(method, checkMethod = '_checkKey') { + return function (id, ...args) { + this[checkMethod](id); + return this._realMethods[method].call(this, id, ...args); }; +} - Gio.DBusConnection.prototype.watch_name = function (name, flags, appeared, vanished) { - return Gio.bus_watch_name_on_connection(this, name, flags, appeared, vanished); - }; - Gio.DBusConnection.prototype.unwatch_name = function (id) { - return Gio.bus_unwatch_name(id); - }; - Gio.DBusConnection.prototype.own_name = function (name, flags, acquired, lost) { - return Gio.bus_own_name_on_connection(this, name, flags, acquired, lost); - }; - Gio.DBusConnection.prototype.unown_name = function (id) { - return Gio.bus_unown_name(id); - }; - - _injectToMethod(Gio.DBusProxy.prototype, 'init', _addDBusConvenience); - _injectToMethod(Gio.DBusProxy.prototype, 'init_async', _addDBusConvenience); - _injectToStaticMethod(Gio.DBusProxy, 'new_sync', _addDBusConvenience); - _injectToStaticMethod(Gio.DBusProxy, 'new_finish', _addDBusConvenience); - _injectToStaticMethod(Gio.DBusProxy, 'new_for_bus_sync', _addDBusConvenience); - _injectToStaticMethod(Gio.DBusProxy, 'new_for_bus_finish', _addDBusConvenience); - Gio.DBusProxy.prototype.connectSignal = Signals._connect; - Gio.DBusProxy.prototype.disconnectSignal = Signals._disconnect; - - Gio.DBusProxy.makeProxyWrapper = _makeProxyWrapper; - - // Some helpers - _wrapFunction(Gio.DBusNodeInfo, 'new_for_xml', _newNodeInfo); - Gio.DBusInterfaceInfo.new_for_xml = _newInterfaceInfo; - - Gio.DBusExportedObject = GjsPrivate.DBusImplementation; - Gio.DBusExportedObject.wrapJSObject = _wrapJSObject; - - // ListStore - Gio.ListStore.prototype[Symbol.iterator] = _listModelIterator; - Gio.ListStore.prototype.insert_sorted = function (item, compareFunc) { - return GjsPrivate.list_store_insert_sorted(this, item, compareFunc); - }; - Gio.ListStore.prototype.sort = function (compareFunc) { - return GjsPrivate.list_store_sort(this, compareFunc); - }; - - // Promisify - Gio._promisify = _promisify; - - // Temporary Gio.File.prototype fix - Gio._LocalFilePrototype = Gio.File.new_for_path('/').constructor.prototype; - - Gio.File.prototype.replace_contents_async = function replace_contents_async(contents, etag, make_backup, flags, cancellable, callback) { - return this.replace_contents_bytes_async(contents, etag, make_backup, flags, cancellable, callback); - }; - - // Override Gio.Settings and Gio.SettingsSchema - the C API asserts if - // trying to access a nonexistent schema or key, which is not handy for - // shell-extension writers - - Gio.SettingsSchema.prototype._realGetKey = Gio.SettingsSchema.prototype.get_key; - Gio.SettingsSchema.prototype.get_key = function (key) { - if (!this.has_key(key)) - throw new Error(`GSettings key ${key} not found in schema ${this.get_id()}`); - return this._realGetKey(key); - }; - - Gio.Settings.prototype._realMethods = Object.assign({}, Gio.Settings.prototype); - - function createCheckedMethod(method, checkMethod = '_checkKey') { - return function (id, ...args) { - this[checkMethod](id); - return this._realMethods[method].call(this, id, ...args); - }; - } - - Object.assign(Gio.Settings.prototype, { - _realInit: Gio.Settings.prototype._init, // add manually, not enumerable - _init(props = {}) { - // 'schema' is a deprecated alias for schema_id - const schemaIdProp = ['schema', 'schema-id', 'schema_id', - 'schemaId'].find(prop => prop in props); - const settingsSchemaProp = ['settings-schema', 'settings_schema', - 'settingsSchema'].find(prop => prop in props); - if (!schemaIdProp && !settingsSchemaProp) { - throw new Error('One of property \'schema-id\' or ' + +Object.assign(Gio.Settings.prototype, { + _realInit: Gio.Settings.prototype._init, // add manually, not enumerable + _init(props = {}) { + // 'schema' is a deprecated alias for schema_id + const schemaIdProp = ['schema', 'schema-id', 'schema_id', + 'schemaId'].find(prop => prop in props); + const settingsSchemaProp = ['settings-schema', 'settings_schema', + 'settingsSchema'].find(prop => prop in props); + if (!schemaIdProp && !settingsSchemaProp) { + throw new Error('One of property \'schema-id\' or ' + '\'settings-schema\' are required for Gio.Settings'); - } + } - const source = Gio.SettingsSchemaSource.get_default(); - const settingsSchema = settingsSchemaProp - ? props[settingsSchemaProp] - : source.lookup(props[schemaIdProp], true); + const source = Gio.SettingsSchemaSource.get_default(); + const settingsSchema = settingsSchemaProp + ? props[settingsSchemaProp] + : source.lookup(props[schemaIdProp], true); - if (!settingsSchema) - throw new Error(`GSettings schema ${props[schemaIdProp]} not found`); + if (!settingsSchema) + throw new Error(`GSettings schema ${props[schemaIdProp]} not found`); - const settingsSchemaPath = settingsSchema.get_path(); - if (props['path'] === undefined && !settingsSchemaPath) { - throw new Error('Attempting to create schema ' + + const settingsSchemaPath = settingsSchema.get_path(); + if (props['path'] === undefined && !settingsSchemaPath) { + throw new Error('Attempting to create schema ' + `'${settingsSchema.get_id()}' without a path`); - } + } - if (props['path'] !== undefined && settingsSchemaPath && + if (props['path'] !== undefined && settingsSchemaPath && props['path'] !== settingsSchemaPath) { - throw new Error(`GSettings created for path '${props['path']}'` + + throw new Error(`GSettings created for path '${props['path']}'` + `, but schema specifies '${settingsSchemaPath}'`); - } + } + + return this._realInit(props); + }, + + _checkKey(key) { + // Avoid using has_key(); checking a JS array is faster than calling + // through G-I. + if (!this._keys) + this._keys = this.settings_schema.list_keys(); + + if (!this._keys.includes(key)) + throw new Error(`GSettings key ${key} not found in schema ${this.schema_id}`); + }, + + _checkChild(name) { + if (!this._children) + this._children = this.list_children(); + + if (!this._children.includes(name)) + throw new Error(`Child ${name} not found in GSettings schema ${this.schema_id}`); + }, + + get_boolean: createCheckedMethod('get_boolean'), + set_boolean: createCheckedMethod('set_boolean'), + get_double: createCheckedMethod('get_double'), + set_double: createCheckedMethod('set_double'), + get_enum: createCheckedMethod('get_enum'), + set_enum: createCheckedMethod('set_enum'), + get_flags: createCheckedMethod('get_flags'), + set_flags: createCheckedMethod('set_flags'), + get_int: createCheckedMethod('get_int'), + set_int: createCheckedMethod('set_int'), + get_int64: createCheckedMethod('get_int64'), + set_int64: createCheckedMethod('set_int64'), + get_string: createCheckedMethod('get_string'), + set_string: createCheckedMethod('set_string'), + get_strv: createCheckedMethod('get_strv'), + set_strv: createCheckedMethod('set_strv'), + get_uint: createCheckedMethod('get_uint'), + set_uint: createCheckedMethod('set_uint'), + get_uint64: createCheckedMethod('get_uint64'), + set_uint64: createCheckedMethod('set_uint64'), + get_value: createCheckedMethod('get_value'), + set_value: createCheckedMethod('set_value'), + + bind: createCheckedMethod('bind'), + bind_writable: createCheckedMethod('bind_writable'), + create_action: createCheckedMethod('create_action'), + get_default_value: createCheckedMethod('get_default_value'), + get_user_value: createCheckedMethod('get_user_value'), + is_writable: createCheckedMethod('is_writable'), + reset: createCheckedMethod('reset'), + + get_child: createCheckedMethod('get_child', '_checkChild'), +}); - return this._realInit(props); - }, - - _checkKey(key) { - // Avoid using has_key(); checking a JS array is faster than calling - // through G-I. - if (!this._keys) - this._keys = this.settings_schema.list_keys(); - - if (!this._keys.includes(key)) - throw new Error(`GSettings key ${key} not found in schema ${this.schema_id}`); - }, - - _checkChild(name) { - if (!this._children) - this._children = this.list_children(); - - if (!this._children.includes(name)) - throw new Error(`Child ${name} not found in GSettings schema ${this.schema_id}`); - }, - - get_boolean: createCheckedMethod('get_boolean'), - set_boolean: createCheckedMethod('set_boolean'), - get_double: createCheckedMethod('get_double'), - set_double: createCheckedMethod('set_double'), - get_enum: createCheckedMethod('get_enum'), - set_enum: createCheckedMethod('set_enum'), - get_flags: createCheckedMethod('get_flags'), - set_flags: createCheckedMethod('set_flags'), - get_int: createCheckedMethod('get_int'), - set_int: createCheckedMethod('set_int'), - get_int64: createCheckedMethod('get_int64'), - set_int64: createCheckedMethod('set_int64'), - get_string: createCheckedMethod('get_string'), - set_string: createCheckedMethod('set_string'), - get_strv: createCheckedMethod('get_strv'), - set_strv: createCheckedMethod('set_strv'), - get_uint: createCheckedMethod('get_uint'), - set_uint: createCheckedMethod('set_uint'), - get_uint64: createCheckedMethod('get_uint64'), - set_uint64: createCheckedMethod('set_uint64'), - get_value: createCheckedMethod('get_value'), - set_value: createCheckedMethod('set_value'), - - bind: createCheckedMethod('bind'), - bind_writable: createCheckedMethod('bind_writable'), - create_action: createCheckedMethod('create_action'), - get_default_value: createCheckedMethod('get_default_value'), - get_user_value: createCheckedMethod('get_user_value'), - is_writable: createCheckedMethod('is_writable'), - reset: createCheckedMethod('reset'), - - get_child: createCheckedMethod('get_child', '_checkChild'), - }); -} diff --git a/modules/core/overrides/Gtk.js b/modules/core/overrides/Gtk.js index ce63ba4e..43a3d69e 100644 --- a/modules/core/overrides/Gtk.js +++ b/modules/core/overrides/Gtk.js @@ -3,162 +3,188 @@ // SPDX-FileCopyrightText: 2013 Giovanni Campagna const Legacy = imports._legacy; -const {Gio, GjsPrivate, GObject} = imports.gi; +const {Gio, GjsPrivate, GObject, Gtk} = imports.gi; const {_registerType} = imports._common; -let Gtk; let BuilderScope; -function _init() { - Gtk = this; - - Gtk.children = GObject.__gtkChildren__; - Gtk.cssName = GObject.__gtkCssName__; - Gtk.internalChildren = GObject.__gtkInternalChildren__; - Gtk.template = GObject.__gtkTemplate__; - - let {GtkWidgetClass} = Legacy.defineGtkLegacyObjects(GObject, Gtk); - Gtk.Widget.prototype.__metaclass__ = GtkWidgetClass; - - if (Gtk.Container && Gtk.Container.prototype.child_set_property) { - Gtk.Container.prototype.child_set_property = function (child, property, value) { - GjsPrivate.gtk_container_child_set_property(this, child, property, value); - }; - } - - if (Gtk.CustomSorter) { - Gtk.CustomSorter.new = GjsPrivate.gtk_custom_sorter_new; - Gtk.CustomSorter.prototype.set_sort_func = function (sortFunc) { - GjsPrivate.gtk_custom_sorter_set_sort_func(this, sortFunc); - }; - } - - Gtk.Widget.prototype._init = function (params) { - let wrapper = this; - - if (wrapper.constructor[Gtk.template]) { - if (!BuilderScope) { - Gtk.Widget.set_connect_func.call(wrapper.constructor, - (builder, obj, signalName, handlerName, connectObj, flags) => { - const swapped = flags & GObject.ConnectFlags.SWAPPED; - const closure = _createClosure( - builder, wrapper, handlerName, swapped, connectObj); - - if (flags & GObject.ConnectFlags.AFTER) - obj.connect_after(signalName, closure); - else - obj.connect(signalName, closure); - }); +if (Gtk.BuilderScope) { + BuilderScope = GObject.registerClass( + { + Implements: [Gtk.BuilderScope], + }, + class extends GObject.Object { + vfunc_create_closure(builder, handlerName, flags, connectObject) { + const swapped = flags & Gtk.BuilderClosureFlags.SWAPPED; + return _createClosure( + builder, + builder.get_current_object(), + handlerName, + swapped, + connectObject + ); } } + ); +} - wrapper = GObject.Object.prototype._init.call(wrapper, params) ?? wrapper; - - if (wrapper.constructor[Gtk.template]) { - let children = wrapper.constructor[Gtk.children] || []; - for (let child of children) { - wrapper[child.replace(/-/g, '_')] = - wrapper.get_template_child(wrapper.constructor, child); - } - let internalChildren = wrapper.constructor[Gtk.internalChildren] || []; - for (let child of internalChildren) { - wrapper[`_${child.replace(/-/g, '_')}`] = - wrapper.get_template_child(wrapper.constructor, child); - } - } - - return wrapper; +Gtk.children = GObject.__gtkChildren__; +Gtk.cssName = GObject.__gtkCssName__; +Gtk.internalChildren = GObject.__gtkInternalChildren__; +Gtk.template = GObject.__gtkTemplate__; + +let {GtkWidgetClass} = Legacy.defineGtkLegacyObjects(GObject, Gtk); +Gtk.Widget.prototype.__metaclass__ = GtkWidgetClass; + +if (Gtk.Container && Gtk.Container.prototype.child_set_property) { + Gtk.Container.prototype.child_set_property = function ( + child, + property, + value + ) { + GjsPrivate.gtk_container_child_set_property( + this, + child, + property, + value + ); }; +} - Gtk.Widget._classInit = function (klass) { - return GObject.Object._classInit(klass); +if (Gtk.CustomSorter) { + Gtk.CustomSorter.new = GjsPrivate.gtk_custom_sorter_new; + Gtk.CustomSorter.prototype.set_sort_func = function (sortFunc) { + GjsPrivate.gtk_custom_sorter_set_sort_func(this, sortFunc); }; +} + +Gtk.Widget.prototype._init = function (params) { + let wrapper = this; + + if (wrapper.constructor[Gtk.template]) { + if (!BuilderScope) { + Gtk.Widget.set_connect_func.call( + wrapper.constructor, + (builder, obj, signalName, handlerName, connectObj, flags) => { + const swapped = flags & GObject.ConnectFlags.SWAPPED; + const closure = _createClosure( + builder, + wrapper, + handlerName, + swapped, + connectObj + ); + + if (flags & GObject.ConnectFlags.AFTER) + obj.connect_after(signalName, closure); + else + obj.connect(signalName, closure); + } + ); + } + } - function registerWidgetType() { - let klass = this; + wrapper = GObject.Object.prototype._init.call(wrapper, params) ?? wrapper; - let template = klass[Gtk.template]; - let cssName = klass[Gtk.cssName]; - let children = klass[Gtk.children]; - let internalChildren = klass[Gtk.internalChildren]; + if (wrapper.constructor[Gtk.template]) { + let children = wrapper.constructor[Gtk.children] || []; + for (let child of children) { + wrapper[child.replace(/-/g, '_')] = wrapper.get_template_child( + wrapper.constructor, + child + ); + } - if (template) { - klass.prototype._instance_init = function () { - this.init_template(); - }; + let internalChildren = wrapper.constructor[Gtk.internalChildren] || []; + for (let child of internalChildren) { + wrapper[`_${child.replace(/-/g, '_')}`] = + wrapper.get_template_child(wrapper.constructor, child); } + } - GObject.Object[_registerType].call(klass); + return wrapper; +}; - if (cssName) - Gtk.Widget.set_css_name.call(klass, cssName); +Gtk.Widget._classInit = function (klass) { + return GObject.Object._classInit(klass); +}; - if (template) { - if (typeof template === 'string') { - if (template.startsWith('resource:///')) { - Gtk.Widget.set_template_from_resource.call(klass, - template.slice(11)); - } else if (template.startsWith('file:///')) { - let file = Gio.File.new_for_uri(template); - let [, contents] = file.load_contents(null); - Gtk.Widget.set_template.call(klass, contents); - } - } else { - Gtk.Widget.set_template.call(klass, template); - } +function registerWidgetType() { + let klass = this; - if (BuilderScope) - Gtk.Widget.set_template_scope.call(klass, new BuilderScope()); - } + let template = klass[Gtk.template]; + let cssName = klass[Gtk.cssName]; + let children = klass[Gtk.children]; + let internalChildren = klass[Gtk.internalChildren]; - if (children) { - children.forEach(child => - Gtk.Widget.bind_template_child_full.call(klass, child, false, 0)); - } + if (template) { + klass.prototype._instance_init = function () { + this.init_template(); + }; + } - if (internalChildren) { - internalChildren.forEach(child => - Gtk.Widget.bind_template_child_full.call(klass, child, true, 0)); + GObject.Object[_registerType].call(klass); + + if (cssName) + Gtk.Widget.set_css_name.call(klass, cssName); + + if (template) { + if (typeof template === 'string') { + if (template.startsWith('resource:///')) { + Gtk.Widget.set_template_from_resource.call( + klass, + template.slice(11) + ); + } else if (template.startsWith('file:///')) { + let file = Gio.File.new_for_uri(template); + let [, contents] = file.load_contents(null); + Gtk.Widget.set_template.call(klass, contents); + } + } else { + Gtk.Widget.set_template.call(klass, template); } + + if (BuilderScope) + Gtk.Widget.set_template_scope.call(klass, new BuilderScope()); } - Object.defineProperty(Gtk.Widget, _registerType, { - value: registerWidgetType, - writable: false, - configurable: false, - enumerable: false, - }); - - if (Gtk.Widget.prototype.get_first_child) { - Gtk.Widget.prototype[Symbol.iterator] = function* () { - for (let c = this.get_first_child(); c; c = c.get_next_sibling()) - yield c; - }; + if (children) { + children.forEach(child => + Gtk.Widget.bind_template_child_full.call(klass, child, false, 0) + ); } - if (Gtk.BuilderScope) { - BuilderScope = GObject.registerClass({ - Implements: [Gtk.BuilderScope], - }, class extends GObject.Object { - vfunc_create_closure(builder, handlerName, flags, connectObject) { - const swapped = flags & Gtk.BuilderClosureFlags.SWAPPED; - return _createClosure( - builder, builder.get_current_object(), - handlerName, swapped, connectObject); - } - }); + if (internalChildren) { + internalChildren.forEach(child => + Gtk.Widget.bind_template_child_full.call(klass, child, true, 0) + ); } } +Object.defineProperty(Gtk.Widget, _registerType, { + value: registerWidgetType, + writable: false, + configurable: false, + enumerable: false, +}); + +if (Gtk.Widget.prototype.get_first_child) { + Gtk.Widget.prototype[Symbol.iterator] = function* () { + for (let c = this.get_first_child(); c; c = c.get_next_sibling()) + yield c; + }; +} + function _createClosure(builder, thisArg, handlerName, swapped, connectObject) { connectObject = connectObject || thisArg; if (swapped) { throw new Error('Unsupported template signal flag "swapped"'); } else if (typeof thisArg[handlerName] === 'undefined') { - throw new Error(`A handler called ${handlerName} was not ` + - `defined on ${thisArg}`); + throw new Error( + `A handler called ${handlerName} was not defined on ${thisArg}` + ); } return thisArg[handlerName].bind(connectObject); diff --git a/modules/core/overrides/cairo.js b/modules/core/overrides/cairo.js index 1d3ba0f9..0718dce0 100644 --- a/modules/core/overrides/cairo.js +++ b/modules/core/overrides/cairo.js @@ -4,6 +4,6 @@ // This override adds the builtin Cairo bindings to imports.gi.cairo. // (It's confusing to have two incompatible ways to import Cairo.) -function _init() { - Object.assign(this, imports.cairo); -} +const {cairo} = imports.gi; +Object.assign(cairo, imports.cairo); + |