LCOV - code coverage report
Current view: top level - modules/core/overrides - Gio.js (source / functions) Coverage Total Hit
Test: gjs-1.89.2 Code Coverage Lines: 88.7 % 604 536
Test Date: 2026-08-01 16:22:07 Functions: 95.1 % 82 78
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 67.8 % 366 248

             Branch data     Line data    Source code
       1                 :         120 : // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
       2                 :             : // SPDX-FileCopyrightText: 2011 Giovanni Campagna
       3                 :             : 
       4                 :          22 : var GLib = imports.gi.GLib;
       5                 :          22 : var GjsPrivate = imports.gi.GjsPrivate;
       6                 :          22 : const Signals = imports._signals;
       7                 :          22 : const {_createWrappersForPlatformSpecificNamespace} = imports._common;
       8                 :          22 : const {setMainLoopHook} = imports._promiseNative;
       9                 :             : var Gio;
      10                 :             : 
      11                 :             : // Ensures that a Gio.UnixFDList being passed into or out of a DBus method with
      12                 :             : // a parameter type that includes 'h' somewhere, actually has entries in it for
      13                 :             : // each of the indices being passed as an 'h' parameter.
      14                 :          12 : function _validateFDVariant(variant, fdList) {
      15 [ -  + ][ -  + ]:          12 :     switch (String.fromCharCode(variant.classify())) {
         [ -  + ][ -  + ]
         [ -  + ][ -  + ]
         [ -  + ][ -  + ]
         [ -  + ][ -  + ]
         [ -  + ][ -  + ]
         [ +  + ][ -  + ]
         [ -  + ][ -  + ]
         [ +  - ][ #  # ]
      16                 :             :     case 'b':
      17                 :             :     case 'y':
      18                 :             :     case 'n':
      19                 :             :     case 'q':
      20                 :             :     case 'i':
      21                 :             :     case 'u':
      22                 :             :     case 'x':
      23                 :             :     case 't':
      24                 :             :     case 'd':
      25                 :             :     case 'o':
      26                 :             :     case 'g':
      27                 :             :     case 's':
      28                 :           0 :         return;
      29                 :           6 :     case 'h': {
      30                 :           6 :         const val = variant.get_handle();
      31                 :           6 :         const numFds = fdList.get_length();
      32         [ +  + ]:           6 :         if (val >= numFds) {
      33                 :           4 :             throw new Error(`handle ${val} is out of range of Gio.UnixFDList ` +
      34                 :           2 :                 `containing ${numFds} FDs`);
      35                 :             :         }
      36                 :           4 :         return;
      37                 :             :     }
      38                 :             :     case 'v':
      39                 :           0 :         _validateFDVariant(variant.get_variant(), fdList);
      40                 :           0 :         return;
      41                 :           0 :     case 'm': {
      42                 :           0 :         let val = variant.get_maybe();
      43         [ #  # ]:           0 :         if (val)
      44                 :           0 :             _validateFDVariant(val, fdList);
      45                 :           0 :         return;
      46                 :             :     }
      47                 :             :     case 'a':
      48                 :             :     case '(':
      49                 :           6 :     case '{': {
      50                 :           6 :         let nElements = variant.n_children();
      51         [ +  + ]:          10 :         for (let ix = 0; ix < nElements; ix++)
      52                 :           6 :             _validateFDVariant(variant.get_child_value(ix), fdList);
      53                 :           4 :         return;
      54                 :             :     }
      55                 :             :     }
      56                 :             : 
      57                 :           0 :     throw new Error('Assertion failure: this code should not be reached');
      58                 :           8 : }
      59                 :             : 
      60                 :          65 : function _proxyInvoker(methodName, sync, inSignature, argArray) {
      61                 :             :     var replyFunc;
      62                 :          65 :     var flags = 0;
      63                 :          65 :     var cancellable = null;
      64                 :          65 :     let fdList = null;
      65                 :             : 
      66                 :             :     // Convert argArray to a *real* array
      67                 :          65 :     argArray = Array.prototype.slice.call(argArray);
      68                 :             : 
      69                 :             :     // The default replyFunc only logs the responses
      70                 :          65 :     replyFunc = _logReply;
      71                 :             : 
      72                 :          65 :     var signatureLength = inSignature.length;
      73                 :          65 :     var minNumberArgs = signatureLength;
      74                 :          65 :     var maxNumberArgs = signatureLength + 4;
      75                 :             : 
      76         [ +  - ]:          65 :     if (argArray.length < minNumberArgs) {
      77                 :           0 :         throw new Error(`Not enough arguments passed for method: ${
      78                 :           0 :             methodName}. Expected ${minNumberArgs}, got ${argArray.length}`);
      79         [ +  - ]:          65 :     } else if (argArray.length > maxNumberArgs) {
      80                 :           0 :         throw new Error(`Too many arguments passed for method ${methodName}. ` +
      81                 :           0 :             `Maximum is ${maxNumberArgs} including one callback, ` +
      82                 :           0 :             'Gio.Cancellable, Gio.UnixFDList, and/or flags');
      83                 :             :     }
      84                 :             : 
      85         [ +  + ]:         137 :     while (argArray.length > signatureLength) {
      86                 :          71 :         var argNum = argArray.length - 1;
      87                 :          71 :         var arg = argArray.pop();
      88 [ +  + ][ +  + ]:          71 :         if (typeof arg === 'function' && !sync) {
      89                 :          65 :             replyFunc = arg;
      90         [ +  - ]:           6 :         } else if (typeof arg === 'number') {
      91                 :           0 :             flags = arg;
      92         [ +  - ]:           6 :         } else if (arg instanceof Gio.Cancellable) {
      93                 :           0 :             cancellable = arg;
      94         [ -  + ]:           6 :         } else if (arg instanceof Gio.UnixFDList) {
      95                 :           6 :             fdList = arg;
      96                 :             :         } else {
      97                 :           0 :             throw new Error(`Argument ${argNum} of method ${methodName} is ` +
      98                 :           0 :                 `${typeof arg}. It should be a callback, flags, ` +
      99                 :           0 :                 'Gio.UnixFDList, or a Gio.Cancellable');
     100                 :             :         }
     101                 :             :     }
     102                 :             : 
     103                 :          65 :     const inTypeString = `(${inSignature.join('')})`;
     104                 :          65 :     const inVariant = new GLib.Variant(inTypeString, argArray);
     105         [ +  + ]:          65 :     if (inTypeString.includes('h')) {
     106         [ +  + ]:           8 :         if (!fdList) {
     107                 :           4 :             throw new Error(`Method ${methodName} with input type containing ` +
     108                 :           2 :                 '\'h\' must have a Gio.UnixFDList as an argument');
     109                 :             :         }
     110                 :           6 :         _validateFDVariant(inVariant, fdList);
     111                 :             :     }
     112                 :             : 
     113                 :          61 :     var asyncCallback = (proxy, result) => {
     114                 :          61 :         try {
     115 [ #  # ][ #  # ]:           0 :             const [outVariant, outFdList] =
         [ #  # ][ #  # ]
     116 [ -  + ][ -  + ]:          61 :                 proxy.call_with_unix_fd_list_finish(result);
                 [ -  + ]
     117                 :          48 :             replyFunc(outVariant.deepUnpack(), null, outFdList);
     118                 :          13 :         } catch (e) {
     119                 :          13 :             replyFunc([], e, null);
     120                 :             :         }
     121                 :             :     };
     122                 :             : 
     123         [ +  - ]:          61 :     if (sync) {
     124 [ #  # ][ #  # ]:           0 :         const [outVariant, outFdList] = this.call_with_unix_fd_list_sync(
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     125                 :           0 :             methodName, inVariant, flags, -1, fdList, cancellable);
     126         [ #  # ]:           0 :         if (fdList)
     127                 :           0 :             return [outVariant.deepUnpack(), outFdList];
     128                 :           0 :         return outVariant.deepUnpack();
     129                 :             :     }
     130                 :             : 
     131                 :         122 :     return this.call_with_unix_fd_list(methodName, inVariant, flags, -1, fdList,
     132                 :          61 :         cancellable, asyncCallback);
     133                 :          61 : }
     134                 :             : 
     135                 :           0 : function _logReply(result, exc) {
     136         [ #  # ]:           0 :     if (exc !== null)
     137                 :           0 :         log(`Ignored exception from dbus method: ${exc}`);
     138                 :             : }
     139                 :             : 
     140                 :         448 : function _makeProxyMethod(method, sync) {
     141                 :             :     var i;
     142                 :         448 :     var name = method.name;
     143                 :         448 :     var inArgs = method.in_args;
     144                 :         448 :     var inSignature = [];
     145         [ +  + ]:         800 :     for (i = 0; i < inArgs.length; i++)
     146                 :         352 :         inSignature.push(inArgs[i].signature);
     147                 :             : 
     148                 :         513 :     return function (...args) {
     149                 :          65 :         return _proxyInvoker.call(this, name, sync, inSignature, args);
     150                 :             :     };
     151                 :             : }
     152                 :             : 
     153                 :           6 : function _convertToNativeSignal(proxy, senderName, signalName, parameters) {
     154                 :           6 :     Signals._emit.call(proxy, signalName, senderName, parameters.deepUnpack());
     155                 :             : }
     156                 :             : 
     157                 :           6 : function _propertyGetter(name) {
     158                 :           6 :     let value = this.get_cached_property(name);
     159         [ -  + ]:           6 :     return value ? value.deepUnpack() : null;
     160                 :           6 : }
     161                 :             : 
     162                 :           2 : function _propertySetter(name, signature, value) {
     163                 :           2 :     let variant = new GLib.Variant(signature, value);
     164                 :           2 :     this.set_cached_property(name, variant);
     165                 :             : 
     166                 :           4 :     this.call('org.freedesktop.DBus.Properties.Set',
     167                 :           2 :         new GLib.Variant('(ssv)', [this.g_interface_name, name, variant]),
     168                 :           2 :         Gio.DBusCallFlags.NONE, -1, null,
     169                 :           2 :         (proxy, result) => {
     170                 :           2 :             try {
     171                 :           2 :                 this.call_finish(result);
     172                 :           0 :             } catch (e) {
     173                 :           0 :                 log(`Could not set property ${name} on remote object ${
     174                 :           0 :                     this.g_object_path}: ${e.message}`);
     175                 :             :             }
     176                 :             :         });
     177                 :             : }
     178                 :             : 
     179                 :           8 : function _addDBusConvenience(proxyInstance) {
     180                 :           8 :     const info = proxyInstance.g_interface_info;
     181         [ +  - ]:           8 :     if (!info)
     182                 :           0 :         return;
     183                 :             : 
     184         [ -  + ]:           8 :     if (info.signals.length > 0)
     185                 :           8 :         proxyInstance.connect('g-signal', _convertToNativeSignal);
     186                 :             : 
     187         [ +  + ]:         232 :     for (const method of info.methods) {
     188                 :         224 :         const remoteMethod = _makeProxyMethod(method, false);
     189                 :         224 :         proxyInstance[`${method.name}Remote`] = remoteMethod;
     190                 :         224 :         proxyInstance[`${method.name}Sync`] = _makeProxyMethod(method, true);
     191                 :         256 :         proxyInstance[`${method.name}Async`] = function (...args) {
     192                 :          32 :             return new Promise((resolve, reject) => {
     193                 :          32 :                 args.push((result, error, fdList) => {
     194         [ +  + ]:          30 :                     if (error)
     195                 :           6 :                         reject(error);
     196         [ +  + ]:          24 :                     else if (fdList)
     197                 :           2 :                         resolve([result, fdList]);
     198                 :             :                     else
     199                 :          22 :                         resolve(result);
     200                 :             :                 });
     201         [ +  + ]:          32 :                 remoteMethod.call(this, ...args);
     202                 :             :             });
     203                 :             :         };
     204                 :             :     }
     205                 :             : 
     206         [ +  + ]:          40 :     for (const {name, signature, flags} of info.properties) {
     207                 :          32 :         let getter = () => {
     208                 :           2 :             throw new Error(`Property ${name} is not readable`);
     209                 :             :         };
     210                 :          32 :         let setter = () => {
     211                 :           1 :             throw new Error(`Property ${name} is not writable`);
     212                 :             :         };
     213                 :             : 
     214         [ +  + ]:          32 :         if (flags & Gio.DBusPropertyInfoFlags.READABLE)
     215                 :          24 :             getter = _propertyGetter.bind(proxyInstance, name);
     216                 :             : 
     217         [ +  + ]:          32 :         if (flags & Gio.DBusPropertyInfoFlags.WRITABLE)
     218                 :          16 :             setter = _propertySetter.bind(proxyInstance, name, signature);
     219                 :             : 
     220                 :          64 :         Object.defineProperty(proxyInstance, name, {
     221                 :          32 :             get: getter,
     222                 :          32 :             set: setter,
     223                 :          32 :             configurable: false,
     224                 :          32 :             enumerable: true,
     225                 :             :         });
     226                 :             :     }
     227                 :           0 : }
     228                 :             : 
     229                 :           1 : function _makeProxyWrapper(interfaceXml) {
     230                 :           1 :     var info = _newInterfaceInfo(interfaceXml);
     231                 :           1 :     var iname = info.name;
     232         [ -  + ]:           1 :     return class extends Gio.DBusProxy {
     233 [ +  + ][ -  + ]:           4 :         constructor(bus, name, object, asyncCallback, cancellable = null,
     234                 :           4 :             flags = Gio.DBusProxyFlags.NONE) {
     235                 :           8 :             const obj = new Gio.DBusProxy({
     236                 :           4 :                 g_connection: bus,
     237                 :           4 :                 g_interface_name: iname,
     238                 :           4 :                 g_interface_info: info,
     239                 :           4 :                 g_name: name,
     240                 :           4 :                 g_flags: flags,
     241                 :           4 :                 g_object_path: object,
     242                 :             :             });
     243                 :             : 
     244         [ +  + ]:           4 :             if (asyncCallback) {
     245                 :           3 :                 obj.init_async(GLib.PRIORITY_DEFAULT, cancellable)
     246                 :           5 :                     .then(() => asyncCallback(obj, null))
     247                 :           4 :                     .catch(e => asyncCallback(null, e));
     248                 :             :             } else {
     249                 :           1 :                 obj.init(cancellable);
     250                 :             :             }
     251                 :             :             // For backwards compatibility, return a new instance of DBusProxy,
     252                 :             :             // overriding `this`
     253                 :           3 :             return obj;
     254                 :           3 :         }
     255                 :             : 
     256 [ +  + ][ -  + ]:           4 :         static newAsync(bus, name, object, cancellable = null,
     257                 :           3 :             flags = Gio.DBusProxyFlags.NONE) {
     258                 :           6 :             const obj = new Gio.DBusProxy({
     259                 :           3 :                 g_connection: bus,
     260                 :           3 :                 g_interface_name: info.name,
     261                 :           3 :                 g_interface_info: info,
     262                 :           3 :                 g_name: name,
     263                 :           3 :                 g_flags: flags,
     264                 :           3 :                 g_object_path: object,
     265                 :             :             });
     266                 :             : 
     267                 :           3 :             return new Promise((resolve, reject) =>
     268                 :           3 :                 obj.init_async(GLib.PRIORITY_DEFAULT, cancellable)
     269                 :           5 :                     .then(() => resolve(obj))
     270                 :           3 :                     .catch(reject));
     271                 :           3 :         }
     272                 :             :     };
     273                 :             : }
     274                 :             : 
     275                 :             : 
     276                 :           3 : function _newNodeInfo(constructor, value) {
     277         [ -  + ]:           3 :     if (typeof value === 'string')
     278                 :           3 :         return constructor(value);
     279                 :           0 :     throw TypeError(`Invalid type ${Object.prototype.toString.call(value)}`);
     280                 :             : }
     281                 :             : 
     282                 :           2 : function _newInterfaceInfo(value) {
     283                 :           2 :     var nodeInfo = Gio.DBusNodeInfo.new_for_xml(value);
     284                 :           2 :     return nodeInfo.interfaces[0];
     285                 :             : }
     286                 :             : 
     287                 :          44 : function _injectToMethod(klass, method) {
     288                 :          44 :     var previous = klass[method];
     289                 :             : 
     290                 :          51 :     klass[method] = function (...args) {
     291                 :           7 :         _addDBusConvenience(this);
     292                 :           7 :         return previous.apply(this, args);
     293                 :             :     };
     294                 :             : }
     295                 :             : 
     296                 :          88 : function _injectToStaticMethod(klass, method) {
     297                 :          88 :     var previous = klass[method];
     298                 :             : 
     299                 :          89 :     klass[method] = function (...parameters) {
     300                 :           1 :         let obj = previous.apply(this, parameters);
     301                 :           1 :         _addDBusConvenience(obj);
     302                 :           1 :         return obj;
     303                 :           1 :     };
     304                 :             : }
     305                 :             : 
     306                 :          22 : function _wrapFunction(klass, method, addition) {
     307                 :          22 :     var previous = klass[method];
     308                 :             : 
     309                 :          25 :     klass[method] = function (...args) {
     310                 :           3 :         args.unshift(previous);
     311                 :           3 :         return addition.apply(this, args);
     312                 :             :     };
     313                 :             : }
     314                 :             : 
     315                 :          36 : function _makeOutSignature(args) {
     316                 :          36 :     var ret = '(';
     317         [ +  + ]:          80 :     for (var i = 0; i < args.length; i++)
     318                 :          44 :         ret += args[i].signature;
     319                 :             : 
     320                 :          36 :     return `${ret})`;
     321                 :             : }
     322                 :             : 
     323                 :          40 : function _handleDBusReply(invocation, ret) {
     324         [ +  + ]:          40 :     if (ret === undefined) {
     325                 :             :         // undefined (no return value) is the empty tuple
     326                 :           4 :         ret = new GLib.Variant('()', []);
     327                 :             :     }
     328                 :             : 
     329                 :          40 :     try {
     330                 :          40 :         let outFdList = null;
     331         [ +  + ]:          40 :         if (!(ret instanceof GLib.Variant)) {
     332                 :             :             // attempt packing according to out signature
     333                 :          36 :             const outArgs = invocation.get_method_info().out_args;
     334                 :          36 :             const outSignature = _makeOutSignature(outArgs);
     335         [ +  + ]:          36 :             if (outSignature.includes('h') &&
     336         [ +  + ]:           2 :                 ret[ret.length - 1] instanceof Gio.UnixFDList) {
     337                 :           2 :                 outFdList = ret.pop();
     338         [ +  + ]:          34 :             } else if (outArgs.length === 1) {
     339                 :             :                 // if one arg, we don't require the handler wrapping it
     340                 :             :                 // into an Array
     341                 :          28 :                 ret = [ret];
     342                 :             :             }
     343                 :          36 :             ret = new GLib.Variant(outSignature, ret);
     344                 :             :         }
     345                 :          38 :         invocation.return_value_with_unix_fd_list(ret, outFdList);
     346                 :           2 :     } catch (e) {
     347                 :           2 :         logError(e, `Exception in method call: ${invocation.get_method_name()}`);
     348                 :             : 
     349                 :             :         // if we don't do this, the other side will never see a reply
     350                 :           4 :         invocation.return_dbus_error('org.gnome.gjs.JSError.ValueError',
     351                 :           2 :             'Service implementation returned an incorrect value type');
     352                 :             :     }
     353                 :             : }
     354                 :             : 
     355                 :           9 : function _handleDBusError(invocation, e) {
     356         [ +  - ]:           9 :     if (e instanceof GLib.Error) {
     357                 :           0 :         invocation.return_gerror(e);
     358                 :           0 :         return;
     359                 :             :     }
     360                 :             : 
     361                 :           9 :     let {name} = e;
     362         [ -  + ]:           9 :     if (!name.includes('.')) {
     363                 :             :         // likely to be a normal JS error
     364                 :           9 :         name = `org.gnome.gjs.JSError.${name}`;
     365                 :             :     }
     366                 :           9 :     logError(e, `Exception in method call: ${invocation.get_method_name()}`);
     367                 :           9 :     invocation.return_dbus_error(name, e.message);
     368                 :           0 : }
     369                 :             : 
     370                 :          61 : function _handleMethodCall(methodName, parameters, invocation) {
     371                 :             :     // prefer a sync version if available
     372                 :          61 :     const method = this[methodName];
     373         [ +  + ]:          61 :     if (method) {
     374                 :          45 :         let retval;
     375                 :          45 :         try {
     376                 :          45 :             const args = parameters.deepUnpack();
     377                 :          45 :             args.push(invocation.get_message().get_unix_fd_list());
     378                 :          45 :             retval = method.apply(this, args);
     379                 :           3 :         } catch (e) {
     380                 :           3 :             _handleDBusError(invocation, e);
     381                 :           3 :             return;
     382                 :             :         }
     383                 :             : 
     384                 :             :         // eslint-disable-next-line no-unused-expressions
     385 [ +  + ][ +  + ]:          48 :         retval?.then?.(r => _handleDBusReply(invocation, r))?.catch?.(
         [ -  + ][ +  - ]
                 [ +  + ]
     386                 :           6 :             e => _handleDBusError(invocation, e)) ??
     387                 :          38 :             _handleDBusReply(invocation, retval);
     388                 :             : 
     389                 :          42 :         return;
     390                 :             :     }
     391                 :             : 
     392                 :          16 :     const asyncMethod = this[`${methodName}Async`];
     393         [ +  + ]:          16 :     if (asyncMethod) {
     394                 :           8 :         function maybeHandleError(e) {
     395         [ +  + ]:           8 :             if (_methodInvocations.has(invocation)) {
     396                 :           4 :                 logError(e, `Exception in method call: ${invocation.get_method_name()}`);
     397                 :           4 :                 return;
     398                 :             :             }
     399                 :             : 
     400                 :           4 :             _handleDBusError(invocation, e);
     401                 :             :         };
     402                 :             : 
     403                 :          14 :         const fdList = invocation.get_message().get_unix_fd_list();
     404                 :          14 :         let ret;
     405                 :          14 :         try {
     406                 :          14 :             ret = asyncMethod.call(this, parameters.deepUnpack(), invocation, fdList);
     407                 :           4 :         } catch (e) {
     408                 :           4 :             maybeHandleError(e);
     409                 :           4 :             return;
     410                 :             :         }
     411                 :             : 
     412 [ +  + ][ +  - ]:          10 :         ret?.catch?.(maybeHandleError);
     413                 :             :     } else {
     414                 :           2 :         logError(new Error(), `Missing handler for DBus method ${methodName}`);
     415                 :           4 :         invocation.return_gerror(new Gio.DBusError({
     416                 :           2 :             code: Gio.DBusError.UNKNOWN_METHOD,
     417                 :           2 :             message: `Method ${methodName} is not implemented`,
     418                 :             :         }));
     419                 :             :     }
     420                 :          49 : }
     421                 :             : 
     422                 :           9 : function _handlePropertyGet(info, impl, propertyName) {
     423                 :           9 :     let propInfo = info.lookup_property(propertyName);
     424                 :           9 :     let jsval = this[propertyName];
     425 [ -  + ][ +  + ]:           9 :     if (jsval?.get_type_string?.() === propInfo.signature)
                 [ +  + ]
     426                 :           3 :         return jsval;
     427         [ -  + ]:           6 :     else if (jsval !== undefined)
     428                 :           6 :         return new GLib.Variant(propInfo.signature, jsval);
     429                 :             :     else
     430                 :           0 :         return null;
     431                 :           9 : }
     432                 :             : 
     433                 :           2 : function _handlePropertySet(info, impl, propertyName, newValue) {
     434                 :           2 :     this[propertyName] = newValue.deepUnpack();
     435                 :             : }
     436                 :             : 
     437                 :           1 : function _wrapJSObject(interfaceInfo, jsObj) {
     438                 :             :     var info;
     439         [ +  - ]:           1 :     if (interfaceInfo instanceof Gio.DBusInterfaceInfo)
     440                 :           0 :         info = interfaceInfo;
     441                 :             :     else
     442                 :           1 :         info = Gio.DBusInterfaceInfo.new_for_xml(interfaceInfo);
     443                 :           1 :     info.cache_build();
     444                 :             : 
     445                 :           1 :     var impl = new GjsPrivate.DBusImplementation({g_interface_info: info});
     446                 :          62 :     impl.connect('handle-method-call', function (_, ...args) {
     447                 :          61 :         return _handleMethodCall.apply(jsObj, args);
     448                 :             :     });
     449                 :           1 :     impl.connect('handle-property-get', function (self, propertyName) {
     450                 :           9 :         return _handlePropertyGet.call(jsObj, info, self, propertyName);
     451                 :             :     });
     452                 :           1 :     impl.connect('handle-property-set', function (self, propertyName, value) {
     453                 :           2 :         return _handlePropertySet.call(jsObj, info, self, propertyName, value);
     454                 :             :     });
     455                 :             : 
     456                 :           1 :     return impl;
     457                 :             : }
     458                 :             : 
     459                 :           3 : function* _listModelIterator() {
     460                 :           3 :     let _index = 0;
     461                 :           3 :     const _len = this.get_n_items();
     462         [ +  + ]:         124 :     while (_index < _len)
     463                 :         120 :         yield this.get_item(_index++);
     464                 :           3 : }
     465                 :             : 
     466         [ +  + ]:          30 : function _promisify(proto, asyncFunc, finishFunc = undefined) {
     467         [ +  + ]:          30 :     if (proto[asyncFunc] === undefined)
     468                 :           1 :         throw new Error(`${proto} has no method named ${asyncFunc}`);
     469                 :             : 
     470         [ +  + ]:          29 :     if (finishFunc === undefined) {
     471 [ -  + ][ +  + ]:          28 :         if (asyncFunc.endsWith('_begin') || asyncFunc.endsWith('_async'))
     472                 :          27 :             finishFunc = `${asyncFunc.slice(0, -5)}finish`;
     473                 :             :         else
     474                 :           1 :             finishFunc = `${asyncFunc}_finish`;
     475                 :             :     }
     476                 :             : 
     477         [ +  + ]:          29 :     if (proto[finishFunc] === undefined)
     478                 :           1 :         throw new Error(`${proto} has no method named ${finishFunc}`);
     479                 :             : 
     480                 :          28 :     const originalFuncName = `_original_${asyncFunc}`;
     481         [ +  + ]:          28 :     if (proto[originalFuncName] !== undefined)
     482                 :           2 :         return;
     483                 :          26 :     proto[originalFuncName] = proto[asyncFunc];
     484                 :          38 :     proto[asyncFunc] = function (...args) {
     485         [ +  + ]:          12 :         if (args.length === this[originalFuncName].length)
     486 [ +  - ][ #  # ]:           3 :             return this[originalFuncName](...args);
     487                 :          18 :         return new Promise((resolve, reject) => {
     488                 :           9 :             let {stack: callStack} = new Error();
     489         [ +  + ]:           9 :             this[originalFuncName](...args, function (source, res) {
     490                 :           9 :                 try {
     491 [ -  + ][ -  + ]:           9 :                     const result = source !== null && source[finishFunc] !== undefined
     492                 :           9 :                         ? source[finishFunc](res)
     493                 :           0 :                         : proto[finishFunc](res);
     494 [ +  + ][ -  + ]:           7 :                     if (Array.isArray(result) && result.length > 1 && result[0] === true)
                 [ +  + ]
     495                 :           2 :                         result.shift();
     496                 :           7 :                     resolve(result);
     497                 :           2 :                 } catch (error) {
     498                 :           2 :                     callStack = callStack.split('\n').filter(line =>
     499                 :          31 :                         line.indexOf('_promisify/') === -1).join('\n');
     500         [ -  + ]:           2 :                     if (error.stack)
     501                 :           2 :                         error.stack += `### Promise created here: ###\n${callStack}`;
     502                 :             :                     else
     503                 :           0 :                         error.stack = callStack;
     504                 :           2 :                     reject(error);
     505                 :             :                 }
     506                 :             :             });
     507                 :             :         });
     508                 :             :     };
     509                 :           2 : }
     510                 :             : 
     511                 :          13 : function _notIntrospectableError(funcName, replacement) {
     512                 :          13 :     return new Error(`${funcName} is not introspectable. Use ${replacement} instead.`);
     513                 :             : }
     514                 :             : 
     515                 :          10 : function _warnNotIntrospectable(funcName, replacement) {
     516                 :          10 :     logError(_notIntrospectableError(funcName, replacement));
     517                 :             : }
     518                 :             : 
     519                 :          22 : const _methodInvocations = new WeakMap();
     520                 :             : 
     521                 :          22 : function _init() {
     522                 :          22 :     Gio = this;
     523                 :             : 
     524                 :          23 :     Gio.Application.prototype.runAsync = function (...args) {
     525                 :           1 :         return new Promise((resolve, reject) => {
     526                 :           1 :             setMainLoopHook(() => {
     527                 :           1 :                 try {
     528 [ +  - ][ #  # ]:           1 :                     resolve(this.run(...args));
     529                 :           0 :                 } catch (error) {
     530                 :           0 :                     reject(error);
     531                 :             :                 }
     532                 :             :             });
     533                 :             :         });
     534                 :             :     };
     535                 :             : 
     536                 :          22 :     _createWrappersForPlatformSpecificNamespace(Gio);
     537                 :             : 
     538                 :          22 :     Gio.DBus = {
     539                 :             :         // Namespace some functions
     540                 :          22 :         get: Gio.bus_get,
     541                 :          22 :         get_finish: Gio.bus_get_finish,
     542                 :          22 :         get_sync: Gio.bus_get_sync,
     543                 :             : 
     544                 :          22 :         own_name: Gio.bus_own_name,
     545                 :          22 :         own_name_on_connection: Gio.bus_own_name_on_connection,
     546                 :          22 :         unown_name: Gio.bus_unown_name,
     547                 :             : 
     548                 :          22 :         watch_name: Gio.bus_watch_name,
     549                 :          22 :         watch_name_on_connection: Gio.bus_watch_name_on_connection,
     550                 :          22 :         unwatch_name: Gio.bus_unwatch_name,
     551                 :             :     };
     552                 :             : 
     553                 :          44 :     Object.defineProperties(Gio.DBus, {
     554                 :          22 :         'session': {
     555                 :          22 :             get() {
     556                 :          10 :                 return Gio.bus_get_sync(Gio.BusType.SESSION, null);
     557                 :             :             },
     558                 :          22 :             enumerable: false,
     559                 :             :         },
     560                 :          22 :         'system': {
     561                 :          22 :             get() {
     562                 :           0 :                 return Gio.bus_get_sync(Gio.BusType.SYSTEM, null);
     563                 :             :             },
     564                 :          22 :             enumerable: false,
     565                 :             :         },
     566                 :             :     });
     567                 :             : 
     568                 :          22 :     Gio.DBusConnection.prototype.watch_name = function (name, flags, appeared, vanished) {
     569                 :           0 :         return Gio.bus_watch_name_on_connection(this, name, flags, appeared, vanished);
     570                 :             :     };
     571                 :          22 :     Gio.DBusConnection.prototype.unwatch_name = function (id) {
     572                 :           0 :         return Gio.bus_unwatch_name(id);
     573                 :             :     };
     574                 :          22 :     Gio.DBusConnection.prototype.own_name = function (name, flags, acquired, lost) {
     575                 :           1 :         return Gio.bus_own_name_on_connection(this, name, flags, acquired, lost);
     576                 :             :     };
     577                 :          22 :     Gio.DBusConnection.prototype.unown_name = function (id) {
     578                 :           1 :         return Gio.bus_unown_name(id);
     579                 :             :     };
     580                 :             : 
     581                 :          22 :     _injectToMethod(Gio.DBusProxy.prototype, 'init');
     582                 :          22 :     _promisify(Gio.DBusProxy.prototype, 'init_async');
     583                 :          22 :     _injectToMethod(Gio.DBusProxy.prototype, 'init_async');
     584                 :          22 :     _injectToStaticMethod(Gio.DBusProxy, 'new_sync');
     585                 :          22 :     _injectToStaticMethod(Gio.DBusProxy, 'new_finish');
     586                 :          22 :     _injectToStaticMethod(Gio.DBusProxy, 'new_for_bus_sync');
     587                 :          22 :     _injectToStaticMethod(Gio.DBusProxy, 'new_for_bus_finish');
     588                 :          22 :     Gio.DBusProxy.prototype.connectSignal = Signals._connect;
     589                 :          22 :     Gio.DBusProxy.prototype.disconnectSignal = Signals._disconnect;
     590                 :             : 
     591                 :          22 :     Gio.DBusProxy.makeProxyWrapper = _makeProxyWrapper;
     592                 :             : 
     593                 :             :     // Wrap the invocation return methods to catch if the method has already
     594                 :             :     // returned, in fact in such case we should not try to return anything
     595                 :             :     // especially because the Gio.DBusMethodInvocation.return_* methods take
     596                 :             :     // the ownership of the invocation itself and, calling it more than once
     597                 :             :     // may lead to memory issues.
     598                 :             :     // The invocated methods are saved in a weak map so that we do not
     599                 :             :     // artificially create a toggle reference that may keep the method
     600                 :             :     // invocation alive forever.
     601 [ -  + ][ -  + ]:         352 :     Object.entries(Object.getOwnPropertyDescriptors(Gio.DBusMethodInvocation.prototype)).forEach(([symbol, desc]) => {
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     602         [ +  + ]:         330 :         if (!symbol.startsWith('return_'))
     603                 :         220 :             return;
     604                 :             : 
     605                 :         110 :         const originalMethod = desc.value;
     606                 :         175 :         desc.value = function (...args) {
     607                 :          65 :             const oldInvocation = _methodInvocations.get(this);
     608         [ +  + ]:          65 :             if (oldInvocation) {
     609                 :             :                 // We do not throw here, not to break compatibility, but
     610                 :             :                 // we make this a no-op, to prevent potential memory issues.
     611                 :           8 :                 logError(new Error(), `${this} (${oldInvocation.methodName}) ` +
     612                 :           8 :                     `already returned @\n${oldInvocation.previousCallStack.split(
     613                 :           8 :                         '\n').slice(1).join('\n')}`);
     614                 :           4 :                 return;
     615                 :             :             }
     616                 :             : 
     617                 :         122 :             _methodInvocations.set(this, {
     618                 :          61 :                 methodName: this.get_method_name(),
     619                 :          61 :                 previousCallStack: new Error().stack,
     620                 :             :             });
     621                 :          61 :             return originalMethod.apply(this, args);
     622                 :          65 :         };
     623                 :             : 
     624                 :         110 :         Object.defineProperty(Gio.DBusMethodInvocation.prototype, symbol, desc);
     625                 :         220 :     });
     626                 :             : 
     627                 :             :     // Some helpers
     628                 :          22 :     _wrapFunction(Gio.DBusNodeInfo, 'new_for_xml', _newNodeInfo);
     629                 :          22 :     Gio.DBusInterfaceInfo.new_for_xml = _newInterfaceInfo;
     630                 :             : 
     631                 :          22 :     Gio.DBusExportedObject = GjsPrivate.DBusImplementation;
     632                 :          22 :     Gio.DBusExportedObject.wrapJSObject = _wrapJSObject;
     633                 :             : 
     634                 :             :     // ListStore
     635                 :          22 :     Gio.ListStore.prototype[Symbol.iterator] = _listModelIterator;
     636                 :          22 :     Gio.ListStore.prototype.insert_sorted = function (item, compareFunc) {
     637                 :          10 :         return GjsPrivate.list_store_insert_sorted(this, item, compareFunc);
     638                 :             :     };
     639                 :          22 :     Gio.ListStore.prototype.sort = function (compareFunc) {
     640                 :           1 :         return GjsPrivate.list_store_sort(this, compareFunc);
     641                 :             :     };
     642                 :             : 
     643                 :             :     // Promisify
     644                 :          22 :     Gio._promisify = _promisify;
     645                 :             : 
     646                 :             :     // Temporary Gio.File.prototype fix
     647                 :          22 :     Gio._LocalFilePrototype = Gio.File.new_for_path('/').constructor.prototype;
     648                 :             : 
     649                 :          22 :     Gio.File.prototype.replace_contents_async = function replace_contents_async(contents, etag, make_backup, flags, cancellable, callback) {
     650         [ +  + ]:           4 :         if (typeof contents === 'string')
     651                 :           2 :             contents = new TextEncoder().encode(contents);
     652                 :           4 :         return this.replace_contents_bytes_async(contents, etag, make_backup, flags, cancellable, callback);
     653                 :             :     };
     654                 :             : 
     655                 :             :     // Best-effort attempt to replace set_attribute(), which is not
     656                 :             :     // introspectable due to the pointer argument
     657                 :          22 :     Gio.File.prototype.set_attribute = function set_attribute(attribute, type, value, flags, cancellable) {
     658                 :           5 :         _warnNotIntrospectable('Gio.File.prototype.set_attribute', 'set_attribute_{type}');
     659                 :             : 
     660                 :           5 :         switch (type) {
     661         [ -  + ]:           5 :         case Gio.FileAttributeType.STRING:
     662                 :           0 :             return this.set_attribute_string(attribute, value, flags, cancellable);
     663         [ -  + ]:           5 :         case Gio.FileAttributeType.BYTE_STRING:
     664                 :           0 :             return this.set_attribute_byte_string(attribute, value, flags, cancellable);
     665         [ +  + ]:           5 :         case Gio.FileAttributeType.UINT32:
     666                 :           1 :             return this.set_attribute_uint32(attribute, value, flags, cancellable);
     667         [ -  + ]:           4 :         case Gio.FileAttributeType.INT32:
     668                 :           0 :             return this.set_attribute_int32(attribute, value, flags, cancellable);
     669         [ +  + ]:           4 :         case Gio.FileAttributeType.UINT64:
     670                 :           1 :             return this.set_attribute_uint64(attribute, value, flags, cancellable);
     671         [ -  + ]:           3 :         case Gio.FileAttributeType.INT64:
     672                 :           0 :             return this.set_attribute_int64(attribute, value, flags, cancellable);
     673         [ +  + ]:           3 :         case Gio.FileAttributeType.INVALID:
     674         [ +  + ]:           2 :         case Gio.FileAttributeType.BOOLEAN:
     675         [ +  - ]:           1 :         case Gio.FileAttributeType.OBJECT:
     676         [ #  # ]:           0 :         case Gio.FileAttributeType.STRINGV:
     677                 :           3 :             throw _notIntrospectableError('This attribute type', 'Gio.FileInfo');
     678                 :             :         }
     679                 :             :     };
     680                 :             : 
     681                 :          22 :     Gio.FileInfo.prototype.set_attribute = function set_attribute(attribute, type, value) {
     682                 :           5 :         _warnNotIntrospectable('Gio.FileInfo.prototype.set_attribute', 'set_attribute_{type}');
     683                 :             : 
     684                 :           5 :         switch (type) {
     685         [ +  + ]:           5 :         case Gio.FileAttributeType.INVALID:
     686                 :           1 :             return this.remove_attribute(attribute);
     687         [ -  + ]:           4 :         case Gio.FileAttributeType.STRING:
     688                 :           0 :             return this.set_attribute_string(attribute, value);
     689         [ -  + ]:           4 :         case Gio.FileAttributeType.BYTE_STRING:
     690                 :           0 :             return this.set_attribute_byte_string(attribute, value);
     691         [ +  + ]:           4 :         case Gio.FileAttributeType.BOOLEAN:
     692                 :           1 :             return this.set_attribute_boolean(attribute, value);
     693         [ +  + ]:           3 :         case Gio.FileAttributeType.UINT32:
     694                 :           1 :             return this.set_attribute_uint32(attribute, value);
     695         [ -  + ]:           2 :         case Gio.FileAttributeType.INT32:
     696                 :           0 :             return this.set_attribute_int32(attribute, value);
     697         [ +  + ]:           2 :         case Gio.FileAttributeType.UINT64:
     698                 :           1 :             return this.set_attribute_uint64(attribute, value);
     699         [ -  + ]:           1 :         case Gio.FileAttributeType.INT64:
     700                 :           0 :             return this.set_attribute_int64(attribute, value);
     701         [ +  - ]:           1 :         case Gio.FileAttributeType.OBJECT:
     702                 :           1 :             return this.set_attribute_object(attribute, value);
     703         [ #  # ]:           0 :         case Gio.FileAttributeType.STRINGV:
     704                 :           0 :             return this.set_attribute_stringv(attribute, value);
     705                 :             :         }
     706                 :             :     };
     707                 :             : 
     708                 :          23 :     Gio.InputStream.prototype.createSyncIterator = function* createSyncIterator(count) {
     709         [ -  + ]:           9 :         while (true) {
     710                 :           9 :             const bytes = this.read_bytes(count, null);
     711         [ +  + ]:           9 :             if (bytes.get_size() === 0)
     712                 :           1 :                 return;
     713                 :           8 :             yield bytes;
     714                 :             :         }
     715                 :           1 :     };
     716                 :             : 
     717         [ -  + ]:          23 :     Gio.InputStream.prototype.createAsyncIterator = async function* createAsyncIterator(
     718                 :           1 :         count, ioPriority = GLib.PRIORITY_DEFAULT) {
     719                 :           1 :         const self = this;
     720                 :             : 
     721                 :           0 :         function next() {
     722                 :           9 :             return new Promise((resolve, reject) => {
     723                 :           9 :                 self.read_bytes_async(count, ioPriority, null, (_self, res) => {
     724                 :           9 :                     try {
     725                 :           9 :                         const bytes = self.read_bytes_finish(res);
     726                 :           9 :                         resolve(bytes);
     727                 :           0 :                     } catch (err) {
     728                 :           0 :                         reject(err);
     729                 :             :                     }
     730                 :             :                 });
     731                 :             :             });
     732                 :             :         }
     733                 :             : 
     734         [ -  + ]:           9 :         while (true) {
     735                 :             :             // eslint-disable-next-line no-await-in-loop
     736         [ -  + ]:           9 :             const bytes = await next();
     737         [ +  + ]:           9 :             if (bytes.get_size() === 0)
     738                 :           1 :                 return;
     739         [ -  + ]:           8 :             yield bytes;
     740                 :             :         }
     741                 :           1 :     };
     742                 :             : 
     743                 :          23 :     Gio.FileEnumerator.prototype[Symbol.iterator] = function* FileEnumeratorIterator() {
     744         [ +  + ]:          39 :         while (true) {
     745                 :          38 :             try {
     746                 :          38 :                 const info = this.next_file(null);
     747         [ +  + ]:          38 :                 if (info === null)
     748                 :           1 :                     break;
     749                 :          37 :                 yield info;
     750                 :           0 :             } catch (err) {
     751                 :           0 :                 this.close(null);
     752                 :           0 :                 throw err;
     753                 :             :             }
     754                 :             :         }
     755                 :           1 :         this.close(null);
     756                 :           1 :     };
     757                 :             : 
     758                 :          23 :     Gio.FileEnumerator.prototype[Symbol.asyncIterator] = async function* AsyncFileEnumeratorIterator() {
     759                 :           1 :         const self = this;
     760                 :             : 
     761                 :          47 :         function next() {
     762                 :          38 :             return new Promise((resolve, reject) => {
     763                 :          38 :                 self.next_files_async(1, GLib.PRIORITY_DEFAULT, null, (_self, res) => {
     764                 :          38 :                     try {
     765                 :          38 :                         const files = self.next_files_finish(res);
     766         [ +  + ]:          38 :                         resolve(files.length === 0 ? null : files[0]);
     767                 :           0 :                     } catch (err) {
     768                 :           0 :                         reject(err);
     769                 :             :                     }
     770                 :             :                 });
     771                 :             :             });
     772                 :             :         }
     773                 :             : 
     774                 :           1 :         function close() {
     775                 :           1 :             return new Promise((resolve, reject) => {
     776                 :           1 :                 self.close_async(GLib.PRIORITY_DEFAULT, null, (_self, res) => {
     777                 :           1 :                     try {
     778                 :           1 :                         resolve(self.close_finish(res));
     779                 :           0 :                     } catch (err) {
     780                 :           0 :                         reject(err);
     781                 :             :                     }
     782                 :             :                 });
     783                 :             :             });
     784                 :             :         }
     785                 :             : 
     786         [ +  + ]:          39 :         while (true) {
     787                 :          38 :             try {
     788                 :             :                 // eslint-disable-next-line no-await-in-loop
     789         [ -  + ]:          38 :                 const info = await next();
     790         [ +  + ]:          38 :                 if (info === null)
     791                 :           1 :                     break;
     792         [ -  + ]:          37 :                 yield info;
     793                 :           0 :             } catch (err) {
     794                 :             :                 // eslint-disable-next-line no-await-in-loop
     795         [ #  # ]:           0 :                 await close();
     796                 :           0 :                 throw err;
     797                 :             :             }
     798                 :             :         }
     799                 :             : 
     800         [ -  + ]:           1 :         return close();
     801                 :           1 :     };
     802                 :             : 
     803                 :             :     // Override Gio.Settings and Gio.SettingsSchema - the C API asserts if
     804                 :             :     // trying to access a nonexistent schema or key, which is not handy for
     805                 :             :     // shell-extension writers
     806                 :             : 
     807                 :          22 :     Gio.SettingsSchema.prototype._realGetKey = Gio.SettingsSchema.prototype.get_key;
     808                 :          22 :     Gio.SettingsSchema.prototype.get_key = function (key) {
     809         [ +  + ]:           2 :         if (!this.has_key(key))
     810                 :           1 :             throw new Error(`GSettings key ${key} not found in schema ${this.get_id()}`);
     811                 :           1 :         return this._realGetKey(key);
     812                 :             :     };
     813                 :             : 
     814                 :          22 :     Gio.Settings.prototype._realMethods = Object.assign({}, Gio.Settings.prototype);
     815                 :             : 
     816         [ +  + ]:         660 :     function createCheckedMethod(method, checkMethod = '_checkKey') {
     817                 :         717 :         return function (id, ...args) {
     818                 :          57 :             this[checkMethod](id);
     819         [ +  + ]:          27 :             return this._realMethods[method].call(this, id, ...args);
     820                 :             :         };
     821                 :             :     }
     822                 :             : 
     823                 :          44 :     Object.assign(Gio.Settings.prototype, {
     824                 :          22 :         _realInit: Gio.Settings.prototype._init,  // add manually, not enumerable
     825         [ +  + ]:          40 :         _init(props = {}) {
     826                 :             :             // 'schema' is a deprecated alias for schema_id
     827                 :          18 :             const schemaIdProp = ['schema', 'schema-id', 'schema_id',
     828                 :          90 :                 'schemaId'].find(prop => prop in props);
     829                 :          18 :             const settingsSchemaProp = ['settings-schema', 'settings_schema',
     830                 :          71 :                 'settingsSchema'].find(prop => prop in props);
     831 [ +  + ][ +  + ]:          18 :             if (!schemaIdProp && !settingsSchemaProp) {
     832                 :           1 :                 throw new Error('One of property \'schema-id\' or ' +
     833                 :             :                     '\'settings-schema\' are required for Gio.Settings');
     834                 :             :             }
     835 [ +  + ][ +  + ]:          17 :             if (settingsSchemaProp && !(props[settingsSchemaProp] instanceof Gio.SettingsSchema))
     836                 :           1 :                 throw new Error(`Value of property '${settingsSchemaProp}' is not of type Gio.SettingsSchema`);
     837                 :             : 
     838                 :          16 :             const source = Gio.SettingsSchemaSource.get_default();
     839         [ +  + ]:          16 :             const settingsSchema = settingsSchemaProp
     840                 :           1 :                 ? props[settingsSchemaProp]
     841                 :          15 :                 : source.lookup(props[schemaIdProp], true);
     842                 :             : 
     843         [ +  + ]:          16 :             if (!settingsSchema)
     844                 :           1 :                 throw new Error(`GSettings schema ${props[schemaIdProp]} not found`);
     845                 :             : 
     846                 :          15 :             const settingsSchemaPath = settingsSchema.get_path();
     847 [ +  + ][ +  + ]:          15 :             if (props['path'] === undefined && !settingsSchemaPath) {
     848                 :           2 :                 throw new Error('Attempting to create schema ' +
     849                 :           1 :                     `'${settingsSchema.get_id()}' without a path`);
     850                 :             :             }
     851                 :             : 
     852 [ +  + ][ -  + ]:          14 :             if (props['path'] !== undefined && settingsSchemaPath &&
     853         [ +  + ]:           1 :                 props['path'] !== settingsSchemaPath) {
     854                 :           2 :                 throw new Error(`GSettings created for path '${props['path']}'` +
     855                 :           1 :                     `, but schema specifies '${settingsSchemaPath}'`);
     856                 :             :             }
     857                 :             : 
     858                 :          13 :             return this._realInit(props);
     859                 :          13 :         },
     860                 :             : 
     861                 :          22 :         _checkKey(key) {
     862                 :             :             // Avoid using has_key(); checking a JS array is faster than calling
     863                 :             :             // through G-I.
     864         [ +  + ]:          55 :             if (!this._keys)
     865                 :          11 :                 this._keys = this.settings_schema.list_keys();
     866                 :             : 
     867         [ +  + ]:          55 :             if (!this._keys.includes(key))
     868                 :          29 :                 throw new Error(`GSettings key ${key} not found in schema ${this.schema_id}`);
     869                 :             :         },
     870                 :             : 
     871                 :          22 :         _checkChild(name) {
     872         [ -  + ]:           2 :             if (!this._children)
     873                 :           2 :                 this._children = this.list_children();
     874                 :             : 
     875         [ +  + ]:           2 :             if (!this._children.includes(name))
     876                 :           1 :                 throw new Error(`Child ${name} not found in GSettings schema ${this.schema_id}`);
     877                 :             :         },
     878                 :             : 
     879                 :          22 :         get_boolean: createCheckedMethod('get_boolean'),
     880                 :          22 :         set_boolean: createCheckedMethod('set_boolean'),
     881                 :          22 :         get_double: createCheckedMethod('get_double'),
     882                 :          22 :         set_double: createCheckedMethod('set_double'),
     883                 :          22 :         get_enum: createCheckedMethod('get_enum'),
     884                 :          22 :         set_enum: createCheckedMethod('set_enum'),
     885                 :          22 :         get_flags: createCheckedMethod('get_flags'),
     886                 :          22 :         set_flags: createCheckedMethod('set_flags'),
     887                 :          22 :         get_int: createCheckedMethod('get_int'),
     888                 :          22 :         set_int: createCheckedMethod('set_int'),
     889                 :          22 :         get_int64: createCheckedMethod('get_int64'),
     890                 :          22 :         set_int64: createCheckedMethod('set_int64'),
     891                 :          22 :         get_string: createCheckedMethod('get_string'),
     892                 :          22 :         set_string: createCheckedMethod('set_string'),
     893                 :          22 :         get_strv: createCheckedMethod('get_strv'),
     894                 :          22 :         set_strv: createCheckedMethod('set_strv'),
     895                 :          22 :         get_uint: createCheckedMethod('get_uint'),
     896                 :          22 :         set_uint: createCheckedMethod('set_uint'),
     897                 :          22 :         get_uint64: createCheckedMethod('get_uint64'),
     898                 :          22 :         set_uint64: createCheckedMethod('set_uint64'),
     899                 :          22 :         get_value: createCheckedMethod('get_value'),
     900                 :          22 :         set_value: createCheckedMethod('set_value'),
     901                 :             : 
     902                 :          22 :         bind: createCheckedMethod('bind'),
     903                 :          22 :         bind_writable: createCheckedMethod('bind_writable'),
     904                 :          22 :         create_action: createCheckedMethod('create_action'),
     905                 :          22 :         get_default_value: createCheckedMethod('get_default_value'),
     906                 :          22 :         get_user_value: createCheckedMethod('get_user_value'),
     907                 :          22 :         is_writable: createCheckedMethod('is_writable'),
     908                 :          22 :         reset: createCheckedMethod('reset'),
     909                 :             : 
     910                 :          22 :         get_child: createCheckedMethod('get_child', '_checkChild'),
     911                 :             :     });
     912                 :             : 
     913                 :             :     // ActionMap
     914                 :             :     // add_action_entries is not introspectable
     915                 :             :     // https://gitlab.gnome.org/GNOME/gjs/-/issues/407
     916                 :          22 :     Gio.ActionMap.prototype.add_action_entries = function add_action_entries(entries) {
     917         [ +  + ]:          12 :         for (let {name, activate, parameter_type, state, change_state} of entries) {
     918         [ +  + ]:           9 :             if (typeof parameter_type === 'string') {
     919         [ +  + ]:           3 :                 if (!GLib.variant_type_string_is_valid(parameter_type))
     920                 :           1 :                     throw new Error(`parameter_type "${parameter_type}" is not a valid VariantType`);
     921                 :             : 
     922                 :           2 :                 parameter_type = new GLib.VariantType(parameter_type);
     923                 :             :             }
     924                 :             : 
     925         [ +  + ]:           8 :             if (typeof state === 'boolean')
     926                 :           1 :                 state = GLib.Variant.new_boolean(state);
     927                 :             : 
     928         [ +  + ]:           8 :             if (typeof state === 'string')
     929                 :           3 :                 state = GLib.Variant.parse(null, state, null, null);
     930                 :             : 
     931                 :          14 :             const action = new Gio.SimpleAction({
     932                 :           7 :                 name,
     933         [ +  + ]:           7 :                 parameter_type: parameter_type instanceof GLib.VariantType ? parameter_type : null,
     934         [ +  + ]:           7 :                 state: state instanceof GLib.Variant ? state : null,
     935                 :             :             });
     936                 :             : 
     937         [ +  + ]:           7 :             if (typeof activate === 'function')
     938                 :           1 :                 action.connect('activate', activate.bind(action));
     939                 :             : 
     940         [ +  + ]:           7 :             if (typeof change_state === 'function')
     941                 :           1 :                 action.connect('change-state', change_state.bind(action));
     942                 :             : 
     943                 :           7 :             this.add_action(action);
     944                 :             :         }
     945                 :             :     };
     946                 :             : }
        

Generated by: LCOV version 2.0-1