[gjs/ewlsh/fix-reentrancy-issues-private-lib] overrides: Allow re-entrancy in GLib imports




commit 6671f83d8614ed355f03389ad692b0a6ab3fea7b
Author: Evan Welsh <contact evanwelsh com>
Date:   Sun May 22 13:43:23 2022 -0700

    overrides: Allow re-entrancy in GLib imports

 gi/repo.cpp                       |   7 +-
 gjs/engine.cpp                    |  23 +-
 modules/core/overrides/GLib.js    | 420 ++++++++--------
 modules/core/overrides/GObject.js | 978 +++++++++++++++++++-------------------
 modules/core/overrides/Gio.js     | 347 +++++++-------
 modules/core/overrides/Gtk.js     | 268 ++++++-----
 modules/core/overrides/cairo.js   |   6 +-
 7 files changed, 1031 insertions(+), 1018 deletions(-)
---
diff --git a/gi/repo.cpp b/gi/repo.cpp
index 9f5d4e1f3..f09b4f80c 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 16d84cc19..bd66a79b8 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 cb8f177e7..ed6005ba6 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 df6f9dc27..76168bf74 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 6cc29b17e..16c5c4d94 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 ce63ba4e7..43a3d69ee 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 1d3ba0f94..0718dce00 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);
+


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]