Branch data Line data Source code
1 : : // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
2 : : // SPDX-FileCopyrightText: 2011 Giovanni Campagna
3 : :
4 : 47 : const ByteArray = imports._byteArrayNative;
5 : 47 : const {setMainLoopHook} = imports._promiseNative;
6 : :
7 : 47 : let GLib;
8 : :
9 : 47 : const SIMPLE_TYPES = ['b', 'y', 'n', 'q', 'i', 'u', 'x', 't', 'h', 'd', 's', 'o', 'g'];
10 : :
11 : 359 : function _readSingleType(signature, forceSimple) {
12 : 359 : let char = signature.shift();
13 : 359 : let isSimple = false;
14 : :
15 [ + + ]: 359 : if (!SIMPLE_TYPES.includes(char)) {
16 [ + - ]: 218 : if (forceSimple)
17 : 0 : throw new TypeError('Invalid GVariant signature (a simple type was expected)');
18 : : } else {
19 : 141 : isSimple = true;
20 : : }
21 : :
22 [ - + ][ + + ]: 359 : if (char === 'm' || char === 'a')
23 : 2 : return [char].concat(_readSingleType(signature, false));
24 [ + + ]: 357 : if (char === '{') {
25 : 107 : let key = _readSingleType(signature, true);
26 : 107 : let val = _readSingleType(signature, false);
27 : 107 : let close = signature.shift();
28 [ + - ]: 107 : if (close !== '}')
29 : 0 : throw new TypeError('Invalid GVariant signature for type DICT_ENTRY (expected "}"');
30 : 107 : return [char].concat(key, val, close);
31 : : }
32 [ + + ]: 250 : if (char === '(') {
33 : 2 : let res = [char];
34 [ - + ]: 6 : while (true) {
35 [ + - ]: 6 : if (signature.length === 0)
36 : 0 : throw new TypeError('Invalid GVariant signature for type TUPLE (expected ")")');
37 : 6 : let next = signature[0];
38 [ + + ]: 6 : if (next === ')') {
39 : 2 : signature.shift();
40 : 2 : return res.concat(next);
41 : : }
42 : 4 : let el = _readSingleType(signature);
43 : 4 : res = res.concat(el);
44 : : }
45 : : }
46 : :
47 : : // Valid types are simple types, arrays, maybes, tuples, dictionary entries and variants
48 [ + + ][ + - ]: 248 : if (!isSimple && char !== 'v')
49 : 0 : throw new TypeError(`Invalid GVariant signature (${char} is not a valid type)`);
50 : :
51 : 248 : return [char];
52 : 359 : }
53 : :
54 : 1200 : function _packVariant(signature, value) {
55 [ + - ]: 1200 : if (signature.length === 0)
56 : 0 : throw new TypeError('GVariant signature cannot be empty');
57 : :
58 : 1200 : let char = signature.shift();
59 [ + + ][ + + ]: 1200 : switch (char) {
[ - + ][ - + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + - ]
60 : : case 'b':
61 : 3 : return GLib.Variant.new_boolean(value);
62 : : case 'y':
63 : 12 : return GLib.Variant.new_byte(value);
64 : : case 'n':
65 : 0 : return GLib.Variant.new_int16(value);
66 : : case 'q':
67 : 0 : return GLib.Variant.new_uint16(value);
68 : : case 'i':
69 : 35 : return GLib.Variant.new_int32(value);
70 : : case 'u':
71 : 3 : return GLib.Variant.new_uint32(value);
72 : : case 'x':
73 : 5 : return GLib.Variant.new_int64(value);
74 : : case 't':
75 : 4 : return GLib.Variant.new_uint64(value);
76 : : case 'h':
77 : 12 : return GLib.Variant.new_handle(value);
78 : : case 'd':
79 : 7 : return GLib.Variant.new_double(value);
80 : : case 's':
81 : 443 : return GLib.Variant.new_string(value);
82 : : case 'o':
83 : 1 : return GLib.Variant.new_object_path(value);
84 : : case 'g':
85 : 1 : return GLib.Variant.new_signature(value);
86 : : case 'v':
87 : 217 : return GLib.Variant.new_variant(value);
88 : : case 'm':
89 [ + + ]: 2 : if (value !== null) {
90 : 1 : return GLib.Variant.new_maybe(null, _packVariant(signature, value));
91 : : } else {
92 : 3 : return GLib.Variant.new_maybe(new GLib.VariantType(
93 : 2 : _readSingleType(signature, false).join('')), null);
94 : : }
95 : 138 : case 'a': {
96 : 138 : let arrayType = _readSingleType(signature, false);
97 [ + + ]: 138 : if (arrayType[0] === 's') {
98 : : // special case for array of strings
99 : 13 : return GLib.Variant.new_strv(value);
100 : : }
101 [ + + ]: 125 : if (arrayType[0] === 'y') {
102 : : // special case for array of bytes
103 [ + + ]: 13 : if (typeof value === 'string') {
104 : 2 : value = ByteArray.fromString(value);
105 [ - + ]: 2 : if (value[value.length - 1] !== 0)
106 [ + + ]: 2 : value = Uint8Array.of(...value, 0);
107 : : }
108 : 13 : const bytes = new GLib.Bytes(value);
109 : 26 : return GLib.Variant.new_from_bytes(new GLib.VariantType('ay'),
110 : 13 : bytes, true);
111 : : }
112 : :
113 : 112 : let arrayValue = [];
114 [ + + ]: 112 : if (arrayType[0] === '{') {
115 : : // special case for dictionaries
116 [ + + ]: 317 : for (let key in value) {
117 : 210 : let copy = [].concat(arrayType);
118 : 210 : let child = _packVariant(copy, [key, value[key]]);
119 : 210 : arrayValue.push(child);
120 : : }
121 : : } else {
122 [ + + ]: 15 : for (let i = 0; i < value.length; i++) {
123 : 10 : let copy = [].concat(arrayType);
124 : 10 : let child = _packVariant(copy, value[i]);
125 : 10 : arrayValue.push(child);
126 : : }
127 : : }
128 : 112 : return GLib.Variant.new_array(new GLib.VariantType(arrayType.join('')), arrayValue);
129 : : }
130 : :
131 : 107 : case '(': {
132 : 107 : let children = [];
133 [ + + ]: 219 : for (let i = 0; i < value.length; i++) {
134 : 114 : let next = signature[0];
135 [ + - ]: 114 : if (next === ')')
136 : 0 : break;
137 : 114 : children.push(_packVariant(signature, value[i]));
138 : : }
139 : :
140 [ + - ]: 105 : if (signature[0] !== ')')
141 : 0 : throw new TypeError('Invalid GVariant signature for type TUPLE (expected ")")');
142 : 105 : signature.shift();
143 : 105 : return GLib.Variant.new_tuple(children);
144 : : }
145 : 210 : case '{': {
146 : 210 : let key = _packVariant(signature, value[0]);
147 : 210 : let child = _packVariant(signature, value[1]);
148 : :
149 [ + - ]: 210 : if (signature[0] !== '}')
150 : 0 : throw new TypeError('Invalid GVariant signature for type DICT_ENTRY (expected "}")');
151 : 210 : signature.shift();
152 : :
153 : 210 : return GLib.Variant.new_dict_entry(key, child);
154 : : }
155 : : default:
156 : 0 : throw new TypeError(`Invalid GVariant signature (unexpected character ${char})`);
157 : : }
158 : 1196 : }
159 : :
160 [ + + ]: 1348 : function _unpackVariant(variant, deep, recursive = false) {
161 [ + + ][ + + ]: 1348 : switch (String.fromCharCode(variant.classify())) {
[ - + ][ - + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + - ]
162 : : case 'b':
163 : 3 : return variant.get_boolean();
164 : : case 'y':
165 : 12 : return variant.get_byte();
166 : : case 'n':
167 : 0 : return variant.get_int16();
168 : : case 'q':
169 : 0 : return variant.get_uint16();
170 : : case 'i':
171 : 36 : return variant.get_int32();
172 : : case 'u':
173 : 2 : return variant.get_uint32();
174 : : case 'x':
175 : 3 : return variant.get_int64();
176 : : case 't':
177 : 2 : return variant.get_uint64();
178 : : case 'h':
179 : 8 : return variant.get_handle();
180 : : case 'd':
181 : 6 : return variant.get_double();
182 : : case 'o':
183 : : case 'g':
184 : : case 's':
185 : : // g_variant_get_string has length as out argument
186 : 284 : return variant.get_string()[0];
187 : 213 : case 'v': {
188 : 213 : const ret = variant.get_variant();
189 [ + + ][ + + ]: 213 : if (deep && recursive && ret instanceof GLib.Variant)
[ + + ]
190 : 192 : return _unpackVariant(ret, deep, recursive);
191 : 25 : return ret;
192 : : }
193 : 185 : case 'm': {
194 : 185 : let val = variant.get_maybe();
195 [ - + ][ + + ]: 185 : if (deep && val)
196 : 184 : return _unpackVariant(val, deep, recursive);
197 : : else
198 : 1 : return val;
199 : : }
200 : : case 'a':
201 [ + + ]: 285 : if (variant.is_of_type(new GLib.VariantType('a{?*}'))) {
202 : : // special case containers
203 : 75 : let ret = { };
204 : 75 : let nElements = variant.n_children();
205 [ + + ]: 286 : for (let i = 0; i < nElements; i++) {
206 : : // always unpack the dictionary entry, and always unpack
207 : : // the key (or it cannot be added as a key)
208 : 422 : let val = _unpackVariant(variant.get_child_value(i), deep,
209 : 211 : recursive);
210 : 211 : let key;
211 [ + - ]: 211 : if (!deep)
212 : 0 : key = _unpackVariant(val[0], true);
213 : : else
214 : 211 : key = val[0];
215 : 211 : ret[key] = val[1];
216 : : }
217 : 75 : return ret;
218 : : }
219 [ + + ]: 216 : if (variant.is_of_type(new GLib.VariantType('ay'))) {
220 : : // special case byte arrays
221 : 199 : return variant.get_data_as_bytes().toArray();
222 : : }
223 : :
224 : : // fall through
225 : : case '(':
226 : 326 : case '{': {
227 : 326 : let ret = [];
228 : 326 : let nElements = variant.n_children();
229 [ + + ]: 888 : for (let i = 0; i < nElements; i++) {
230 : 561 : let val = variant.get_child_value(i);
231 [ - + ]: 561 : if (deep)
232 : 561 : ret.push(_unpackVariant(val, deep, recursive));
233 : : else
234 : 0 : ret.push(val);
235 : : }
236 : 327 : return ret;
237 : : }
238 : : }
239 : :
240 : 0 : throw new Error('Assertion failure: this code should not be reached');
241 : 804 : }
242 : :
243 : : function _notIntrospectableError(funcName, replacement) {
244 : 30 : return new Error(`${funcName} is not introspectable. Use ${replacement} instead.`);
245 : : }
246 : :
247 : : function _warnNotIntrospectable(funcName, replacement) {
248 : 28 : logError(_notIntrospectableError(funcName, replacement));
249 : : }
250 : :
251 : : function _escapeCharacterSetChars(char) {
252 [ + + ]: 26 : if ('-^]\\'.includes(char))
253 : 2 : return `\\${char}`;
254 : 24 : return char;
255 : : }
256 : :
257 : 47 : function _init() {
258 : : // this is imports.gi.GLib
259 : :
260 : 47 : GLib = this;
261 : :
262 : 96 : GLib.MainLoop.prototype.runAsync = function (...args) {
263 : 49 : return new Promise((resolve, reject) => {
264 : 49 : setMainLoopHook(() => {
265 : 49 : try {
266 [ + - ][ # # ]: 49 : resolve(this.run(...args));
267 : 0 : } catch (error) {
268 : 0 : reject(error);
269 : : }
270 : : });
271 : : });
272 : : };
273 : :
274 : : // For convenience in property min or max values, since GLib.MAXINT64 and
275 : : // friends will log a warning when used
276 : 47 : this.MAXINT64_BIGINT = 0x7fff_ffff_ffff_ffffn;
277 : 47 : this.MININT64_BIGINT = -this.MAXINT64_BIGINT - 1n;
278 : 47 : this.MAXUINT64_BIGINT = 0xffff_ffff_ffff_ffffn;
279 : :
280 : : // small HACK: we add a matches() method to standard Errors so that
281 : : // you can do "if (e.matches(Ns.FooError, Ns.FooError.SOME_CODE))"
282 : : // without checking instanceof
283 : 47 : Error.prototype.matches = function () {
284 : 0 : return false;
285 : : };
286 : :
287 : : // Guard against domains that aren't valid quarks and would lead
288 : : // to a crash
289 : 47 : const quarkToString = this.quark_to_string;
290 : 47 : const realNewLiteral = this.Error.new_literal;
291 : 47 : this.Error.new_literal = function (domain, code, message) {
292 [ + + ]: 5 : if (quarkToString(domain) === null)
293 : 1 : throw new TypeError(`Error.new_literal: ${domain} is not a valid domain`);
294 : 4 : return realNewLiteral(domain, code, message);
295 : : };
296 : :
297 : 492 : this.Variant._new_internal = function (sig, value) {
298 : 445 : let signature = Array.prototype.slice.call(sig);
299 : :
300 : 445 : let variant = _packVariant(signature, value);
301 [ + - ]: 443 : if (signature.length !== 0)
302 : 0 : throw new TypeError('Invalid GVariant signature (more than one single complete type)');
303 : :
304 : 443 : return variant;
305 : 443 : };
306 : :
307 : : // Deprecate version of new GLib.Variant()
308 : 47 : this.Variant.new = function (sig, value) {
309 : 4 : return new GLib.Variant(sig, value);
310 : : };
311 : 47 : this.Variant.prototype.unpack = function () {
312 : 4 : return _unpackVariant(this, false);
313 : : };
314 : 47 : this.Variant.prototype.deepUnpack = function () {
315 : 147 : return _unpackVariant(this, true);
316 : : };
317 : : // backwards compatibility alias
318 : 47 : this.Variant.prototype.deep_unpack = this.Variant.prototype.deepUnpack;
319 : :
320 : : // Note: discards type information, if the variant contains any 'v' types
321 : 47 : this.Variant.prototype.recursiveUnpack = function () {
322 : 76 : return _unpackVariant(this, true, true);
323 : : };
324 : :
325 : 47 : this.Variant.prototype.toString = function () {
326 : 0 : return `[object variant of type "${this.get_type_string()}"]`;
327 : : };
328 : :
329 : 47 : this.Bytes.prototype.toArray = function () {
330 : 307 : return imports._byteArrayNative.fromGBytes(this);
331 : : };
332 : :
333 : 47 : this.log_structured =
334 : : /**
335 : : * @param {string} logDomain Log domain.
336 : : * @param {GLib.LogLevelFlags} logLevel Log level, either from GLib.LogLevelFlags, or a user-defined level.
337 : : * @param {Record<string, unknown>} fields Key-value pairs of structured data to add to the log entry.
338 : : * @returns {void}
339 : : */
340 : 73 : function log_structured(logDomain, logLevel, fields) {
341 : : /** @type {Record<string, GLib.Variant>} */
342 : 73 : let variantFields = {};
343 : :
344 [ + + ]: 220 : for (let key in fields) {
345 : 147 : const field = fields[key];
346 : :
347 [ + + ]: 147 : if (field instanceof Uint8Array) {
348 : 1 : variantFields[key] = new GLib.Variant('ay', field);
349 [ - + ]: 146 : } else if (typeof field === 'string') {
350 : 146 : variantFields[key] = new GLib.Variant('s', field);
351 [ # # ]: 0 : } else if (field instanceof GLib.Variant) {
352 : : // GLib.log_variant converts all Variants that are
353 : : // not 'ay' or 's' type to strings by printing
354 : : // them.
355 : : //
356 : : // https://gitlab.gnome.org/GNOME/glib/-/blob/a380bfdf93cb3bfd3cd4caedc0127c4e5717545b/glib/gmessages.c#L1894
357 : 0 : variantFields[key] = field;
358 : : } else {
359 : 0 : throw new TypeError(`Unsupported value ${field}, log_structured supports GLib.Variant, Uint8Array, and string values.`);
360 : : }
361 : : }
362 : :
363 : 73 : GLib.log_variant(logDomain, logLevel, new GLib.Variant('a{sv}', variantFields));
364 : : };
365 : :
366 : : // GjsPrivate depends on GLib so we cannot import it
367 : : // before GLib is fully resolved.
368 : :
369 : 47 : this.log_set_writer_func_variant = function (...args) {
370 : 0 : const {log_set_writer_func} = imports.gi.GjsPrivate;
371 : :
372 [ # # ][ # # ]: 0 : log_set_writer_func(...args);
373 : : };
374 : :
375 : 47 : this.log_set_writer_default = function (...args) {
376 : 0 : const {log_set_writer_default} = imports.gi.GjsPrivate;
377 : :
378 [ # # ][ # # ]: 0 : log_set_writer_default(...args);
379 : : };
380 : :
381 : 50 : this.log_set_writer_func = function (writer_func) {
382 : 3 : const {log_set_writer_func} = imports.gi.GjsPrivate;
383 : :
384 [ + - ]: 3 : if (typeof writer_func !== 'function') {
385 : 0 : log_set_writer_func(writer_func);
386 : : } else {
387 : 75 : log_set_writer_func(function (logLevel, stringFields) {
388 : 72 : const stringFieldsObj = {...stringFields.recursiveUnpack()};
389 : 72 : return writer_func(logLevel, stringFieldsObj);
390 : 72 : });
391 : : }
392 : : };
393 : :
394 [ + + ][ - + ]: 55 : this.VariantDict.prototype.lookup = function (key, variantType = null, deep = false) {
395 [ + + ]: 8 : if (typeof variantType === 'string')
396 : 2 : variantType = new GLib.VariantType(variantType);
397 : :
398 : 8 : const variant = this.lookup_value(key, variantType);
399 [ + + ]: 8 : if (variant === null)
400 : 4 : return null;
401 : 4 : return _unpackVariant(variant, deep);
402 : 8 : };
403 : :
404 : : // Prevent user code from calling GLib string manipulation functions that
405 : : // return the same string that was passed in. These can't be annotated
406 : : // properly, and will mostly crash.
407 : : // Here we provide approximate implementations of the functions so that if
408 : : // they had happened to work in the past, they will continue working, but
409 : : // log a stack trace and a suggestion of what to use instead.
410 : : // Exceptions are thrown instead for GLib.stpcpy() of which the return value
411 : : // is useless anyway and GLib.ascii_formatd() which is too complicated to
412 : : // implement here.
413 : :
414 : 47 : this.stpcpy = function () {
415 : 1 : throw _notIntrospectableError('GLib.stpcpy()', 'the + operator');
416 : : };
417 : :
418 : 51 : this.strstr_len = function (haystack, len, needle) {
419 : 4 : _warnNotIntrospectable('GLib.strstr_len()', 'String.indexOf()');
420 : 4 : let searchString = haystack;
421 [ + + ]: 4 : if (len !== -1)
422 : 2 : searchString = searchString.slice(0, len);
423 : 4 : const index = searchString.indexOf(needle);
424 [ + + ]: 4 : if (index === -1)
425 : 2 : return null;
426 : 2 : return haystack.slice(index);
427 : 4 : };
428 : :
429 : 49 : this.strrstr = function (haystack, needle) {
430 : 2 : _warnNotIntrospectable('GLib.strrstr()', 'String.lastIndexOf()');
431 : 2 : const index = haystack.lastIndexOf(needle);
432 [ + + ]: 2 : if (index === -1)
433 : 1 : return null;
434 : 1 : return haystack.slice(index);
435 : 2 : };
436 : :
437 : 50 : this.strrstr_len = function (haystack, len, needle) {
438 : 3 : _warnNotIntrospectable('GLib.strrstr_len()', 'String.lastIndexOf()');
439 : 3 : let searchString = haystack;
440 [ + + ]: 3 : if (len !== -1)
441 : 1 : searchString = searchString.slice(0, len);
442 : 3 : const index = searchString.lastIndexOf(needle);
443 [ + + ]: 3 : if (index === -1)
444 : 1 : return null;
445 : 2 : return haystack.slice(index);
446 : 3 : };
447 : :
448 : 47 : this.strup = function (string) {
449 : 2 : _warnNotIntrospectable('GLib.strup()',
450 : 1 : 'String.toUpperCase() or GLib.ascii_strup()');
451 : 1 : return string.toUpperCase();
452 : : };
453 : :
454 : 47 : this.strdown = function (string) {
455 : 2 : _warnNotIntrospectable('GLib.strdown()',
456 : 1 : 'String.toLowerCase() or GLib.ascii_strdown()');
457 : 1 : return string.toLowerCase();
458 : : };
459 : :
460 : 47 : this.strreverse = function (string) {
461 : 2 : _warnNotIntrospectable('GLib.strreverse()',
462 : 1 : 'Array.reverse() and String.join()');
463 [ + + ]: 1 : return [...string].reverse().join('');
464 : : };
465 : :
466 : 47 : this.ascii_dtostr = function (unused, len, number) {
467 : 2 : _warnNotIntrospectable('GLib.ascii_dtostr()', 'JS string conversion');
468 : 2 : return `${number}`.slice(0, len);
469 : : };
470 : :
471 : 47 : this.ascii_formatd = function () {
472 : 2 : throw _notIntrospectableError('GLib.ascii_formatd()',
473 : 1 : 'Number.toExponential() and string interpolation');
474 : : };
475 : :
476 : 47 : this.strchug = function (string) {
477 : 2 : _warnNotIntrospectable('GLib.strchug()', 'String.trimStart()');
478 : 2 : return string.trimStart();
479 : : };
480 : :
481 : 47 : this.strchomp = function (string) {
482 : 2 : _warnNotIntrospectable('GLib.strchomp()', 'String.trimEnd()');
483 : 2 : return string.trimEnd();
484 : : };
485 : :
486 : : // g_strstrip() is a macro and therefore doesn't even appear in the GIR
487 : : // file, but we may as well include it here since it's trivial
488 : 47 : this.strstrip = function (string) {
489 : 4 : _warnNotIntrospectable('GLib.strstrip()', 'String.trim()');
490 : 4 : return string.trim();
491 : : };
492 : :
493 : 51 : this.strdelimit = function (string, delimiters, newDelimiter) {
494 : 4 : _warnNotIntrospectable('GLib.strdelimit()', 'String.replace()');
495 : :
496 [ + + ]: 4 : if (delimiters === null)
497 : 2 : delimiters = GLib.STR_DELIMITERS;
498 [ + + ]: 4 : if (typeof newDelimiter === 'number')
499 : 2 : newDelimiter = String.fromCharCode(newDelimiter);
500 : :
501 : 4 : const delimiterChars = delimiters.split('');
502 : 4 : const escapedDelimiterChars = delimiterChars.map(_escapeCharacterSetChars);
503 : 4 : const delimiterRegex = new RegExp(`[${escapedDelimiterChars.join('')}]`, 'g');
504 : 4 : return string.replace(delimiterRegex, newDelimiter);
505 : 4 : };
506 : :
507 : 49 : this.strcanon = function (string, validChars, substitutor) {
508 : 2 : _warnNotIntrospectable('GLib.strcanon()', 'String.replace()');
509 : :
510 [ + + ]: 2 : if (typeof substitutor === 'number')
511 : 1 : substitutor = String.fromCharCode(substitutor);
512 : :
513 : 2 : const validArray = validChars.split('');
514 : 2 : const escapedValidArray = validArray.map(_escapeCharacterSetChars);
515 : 2 : const invalidRegex = new RegExp(`[^${escapedValidArray.join('')}]`, 'g');
516 : 2 : return string.replace(invalidRegex, substitutor);
517 : 2 : };
518 : :
519 : : // Prevent user code from calling GThread functions which always crash
520 : 47 : this.Thread.new = function () {
521 : 0 : throw _notIntrospectableError('GLib.Thread.new()',
522 : 0 : 'GIO asynchronous methods or Promise()');
523 : : };
524 : :
525 : 47 : this.Thread.try_new = function () {
526 : 0 : throw _notIntrospectableError('GLib.Thread.try_new()',
527 : 0 : 'GIO asynchronous methods or Promise()');
528 : : };
529 : :
530 : 47 : this.Thread.exit = function () {
531 : 0 : throw new Error('\'GLib.Thread.exit()\' may not be called in GJS');
532 : : };
533 : :
534 : 47 : this.Thread.prototype.ref = function () {
535 : 0 : throw new Error('\'GLib.Thread.ref()\' may not be called in GJS');
536 : : };
537 : :
538 : 47 : this.Thread.prototype.unref = function () {
539 : 0 : throw new Error('\'GLib.Thread.unref()\' may not be called in GJS');
540 : : };
541 : : }
|