Branch data Line data Source code
1 : 50 : /* -*- mode: js; indent-tabs-mode: nil; -*- */
2 : : /* exported Class, Interface, defineGObjectLegacyObjects,
3 : : defineGtkLegacyObjects */
4 : : // SPDX-License-Identifier: MIT
5 : : // SPDX-FileCopyrightText: 2008 litl, LLC
6 : : // SPDX-FileCopyrightText: 2011 Jasper St. Pierre
7 : :
8 : : // Class magic
9 : : // Adapted from MooTools
10 : : // https://github.com/mootools/mootools-core
11 : :
12 : 0 : function _Base() {
13 : 0 : throw new TypeError('Cannot instantiate abstract class _Base');
14 : : }
15 : :
16 : 50 : _Base.__super__ = null;
17 : 50 : _Base.prototype._init = function () { };
18 : 116 : _Base.prototype._construct = function (...args) {
19 [ + - ][ # # ]: 66 : this._init(...args);
20 : 66 : return this;
21 : : };
22 : 50 : _Base.prototype.__name__ = '_Base';
23 : 50 : _Base.prototype.toString = function () {
24 : 2 : return `[object ${this.__name__}]`;
25 : : };
26 : :
27 : 111 : function _parent(...args) {
28 [ + - ]: 111 : if (!this.__caller__)
29 : 0 : throw new TypeError("The method 'parent' cannot be called");
30 : :
31 : 111 : let caller = this.__caller__;
32 : 111 : let name = caller._name;
33 : 111 : let parent = caller._owner.__super__;
34 : :
35 [ - + ]: 111 : let previous = parent ? parent.prototype[name] : undefined;
36 : :
37 [ + - ]: 111 : if (!previous)
38 : 0 : throw new TypeError(`The method '${name}' is not on the superclass`);
39 : :
40 : 111 : return previous.apply(this, args);
41 : 111 : }
42 : :
43 : 71 : function _interfacePresent(required, proto) {
44 [ + + ]: 71 : if (!proto.__interfaces__)
45 : 17 : return false;
46 [ + + ]: 54 : if (proto.__interfaces__.indexOf(required) !== -1)
47 : 29 : return true; // implemented here
48 : : // Might be implemented on a parent class
49 : 25 : return _interfacePresent(required, proto.constructor.__super__.prototype);
50 : : }
51 : :
52 : 123 : function getMetaClass(params) {
53 [ + - ]: 123 : if (params.MetaClass)
54 : 0 : return params.MetaClass;
55 : :
56 [ + + ][ + + ]: 123 : if (params.Extends && params.Extends.prototype.__metaclass__)
57 : 45 : return params.Extends.prototype.__metaclass__;
58 : :
59 : 78 : return null;
60 : : }
61 : :
62 : 122 : function Class(params, ...otherArgs) {
63 : 122 : let metaClass = getMetaClass(params);
64 : :
65 [ + + ][ + + ]: 122 : if (metaClass && metaClass !== this.constructor)
66 [ + - ]: 26 : return new metaClass(params, ...otherArgs);
67 : : else
68 [ + - ]: 96 : return this._construct(params, ...otherArgs);
69 : 114 : }
70 : :
71 : 50 : Class.__super__ = _Base;
72 : 50 : Class.prototype = Object.create(_Base.prototype);
73 : 50 : Class.prototype.constructor = Class;
74 : 50 : Class.prototype.__name__ = 'Class';
75 : :
76 : 367 : Class.prototype.wrapFunction = function (name, meth) {
77 [ + - ]: 317 : if (meth._origin)
78 : 0 : meth = meth._origin;
79 : :
80 : 255 : function wrapper(...args) {
81 : 255 : let prevCaller = this.__caller__;
82 : 255 : this.__caller__ = wrapper;
83 : 255 : let result = meth.apply(this, args);
84 : 254 : this.__caller__ = prevCaller;
85 : 254 : return result;
86 : 254 : }
87 : :
88 : 317 : wrapper._origin = meth;
89 : 317 : wrapper._name = name;
90 : 317 : wrapper._owner = this;
91 : :
92 : 317 : return wrapper;
93 : : };
94 : :
95 : 50 : Class.prototype.toString = function () {
96 : 0 : return `[object ${this.__name__} for ${this.prototype.__name__}]`;
97 : : };
98 : :
99 : 149 : Class.prototype._construct = function (params, ...otherArgs) {
100 [ + - ]: 99 : if (!params.Name)
101 : 0 : throw new TypeError("Classes require an explicit 'Name' parameter.");
102 : :
103 : 99 : let name = params.Name;
104 : :
105 : 99 : let parent = params.Extends;
106 [ + + ]: 99 : if (!parent)
107 : 27 : parent = _Base;
108 : :
109 : 98 : function newClass(...args) {
110 [ + + ][ + + ]: 98 : if (params.Abstract && new.target.name === name)
111 : 1 : throw new TypeError(`Cannot instantiate abstract class ${name}`);
112 : :
113 : 97 : this.__caller__ = null;
114 : :
115 [ + - ][ # # ]: 97 : return this._construct(...args);
116 : : }
117 : :
118 : : // Since it's not possible to create a constructor with
119 : : // a custom [[Prototype]], we have to do this to make
120 : : // "newClass instanceof Class" work, and so we can inherit
121 : : // methods/properties of Class.prototype, like wrapFunction.
122 : 99 : Object.setPrototypeOf(newClass, this.constructor.prototype);
123 : :
124 : 99 : newClass.__super__ = parent;
125 : 99 : newClass.prototype = Object.create(parent.prototype);
126 : 99 : newClass.prototype.constructor = newClass;
127 : :
128 [ + - ]: 99 : newClass._init(params, ...otherArgs);
129 : :
130 [ + + ]: 99 : let interfaces = params.Implements || [];
131 : : // If the parent already implements an interface, then we do too
132 [ + + ]: 99 : if (parent instanceof Class)
133 : 25 : interfaces = interfaces.filter(iface => !parent.implements(iface));
134 : :
135 : 198 : Object.defineProperties(newClass.prototype, {
136 : 99 : '__metaclass__': {
137 : 99 : writable: false,
138 : 99 : configurable: false,
139 : 99 : enumerable: false,
140 : 99 : value: this.constructor,
141 : : },
142 : 99 : '__interfaces__': {
143 : 99 : writable: false,
144 : 99 : configurable: false,
145 : 99 : enumerable: false,
146 : 99 : value: interfaces,
147 : : },
148 : : });
149 : 198 : Object.defineProperty(newClass, 'name', {
150 : 99 : writable: false,
151 : 99 : configurable: true,
152 : 99 : enumerable: false,
153 : 99 : value: name,
154 : : });
155 : :
156 : 99 : interfaces.forEach(iface => {
157 : 21 : iface._check(newClass.prototype);
158 : : });
159 : :
160 : 92 : return newClass;
161 : 92 : };
162 : :
163 : : /**
164 : : * Check whether this class conforms to the interface "iface".
165 : : *
166 : : * @param {object} iface a Lang.Interface
167 : : * @returns {boolean} whether this class implements iface
168 : : */
169 : 50 : Class.prototype.implements = function (iface) {
170 [ + + ]: 21 : if (_interfacePresent(iface, this.prototype))
171 : 18 : return true;
172 [ + - ]: 3 : if (this.__super__ instanceof Class)
173 : 0 : return this.__super__.implements(iface);
174 : 3 : return false;
175 : : };
176 : :
177 : : // key can be either a string or a symbol
178 : 407 : Class.prototype._copyPropertyDescriptor = function (params, propertyObj, key) {
179 : 357 : let descriptor = Object.getOwnPropertyDescriptor(params, key);
180 : :
181 [ + + ]: 357 : if (typeof descriptor.value === 'function')
182 : 315 : descriptor.value = this.wrapFunction(key, descriptor.value);
183 : :
184 : : // we inherit writable and enumerable from the property
185 : : // descriptor of params (they're both true if created from an
186 : : // object literal)
187 : 357 : descriptor.configurable = false;
188 : :
189 : 357 : propertyObj[key] = descriptor;
190 : : };
191 : :
192 : 176 : Class.prototype._init = function (params) {
193 : 126 : let className = params.Name;
194 : :
195 : 126 : let propertyObj = { };
196 : :
197 [ + + ]: 126 : let interfaces = params.Implements || [];
198 : 126 : interfaces.forEach(iface => {
199 : 42 : Object.entries(Object.getOwnPropertyDescriptors(iface.prototype))
200 [ - + ][ - + ]: 331 : .forEach(([name, descriptor]) => {
[ - + ][ # # ]
[ # # ][ # # ]
[ # # ]
201 [ + + ][ + + ]: 289 : if (name.startsWith('__') || name === 'constructor')
202 : 156 : return;
203 [ + + ]: 133 : if (name in this.prototype)
204 : 34 : return; // don't overwrite something that's already there
205 : : // writable and enumerable are inherited, see note above
206 : 99 : descriptor.configurable = false;
207 : 99 : propertyObj[name] = descriptor;
208 : : });
209 : : });
210 : :
211 : 126 : Object.getOwnPropertyNames(params)
212 : 126 : .filter(name =>
213 : 613 : ['Name', 'Extends', 'Abstract', 'Implements'].indexOf(name) === -1)
214 : 126 : .concat(Object.getOwnPropertySymbols(params))
215 : 126 : .forEach(this._copyPropertyDescriptor.bind(this, params, propertyObj));
216 : :
217 : 126 : Object.defineProperties(this.prototype, propertyObj);
218 : 252 : Object.defineProperties(this.prototype, {
219 : 126 : '__name__': {
220 : 126 : writable: false,
221 : 126 : configurable: false,
222 : 126 : enumerable: false,
223 : 126 : value: className,
224 : : },
225 : 126 : 'parent': {
226 : 126 : writable: false,
227 : 126 : configurable: false,
228 : 126 : enumerable: false,
229 : 126 : value: _parent,
230 : : },
231 : : });
232 : : };
233 : :
234 : : // This introduces the concept of a "meta-interface" which is given by the
235 : : // MetaInterface property on an object's metaclass. For objects whose metaclass
236 : : // is Lang.Class, the meta-interface is Lang.Interface. Subclasses of Lang.Class
237 : : // such as GObject.Class supply their own meta-interface.
238 : : // This is in order to enable creating GObject interfaces with Lang.Interface,
239 : : // much as you can create GObject classes with Lang.Class.
240 : 15 : function _getMetaInterface(params) {
241 [ + + ][ + + ]: 15 : if (!params.Requires || params.Requires.length === 0)
242 : 6 : return null;
243 : :
244 : 9 : let metaInterface = params.Requires.map(req => {
245 [ + + ]: 11 : if (req instanceof Interface)
246 : 3 : return req.__super__;
247 [ + + ]: 8 : for (let metaclass = req.prototype.__metaclass__; metaclass;
248 : 1 : metaclass = metaclass.__super__) {
249 [ + + ]: 7 : if (Object.hasOwn(metaclass, 'MetaInterface'))
250 : 6 : return metaclass.MetaInterface;
251 : : }
252 : 2 : return null;
253 : 6 : })
254 : 18 : .reduce((best, candidate) => {
255 : : // This function reduces to the "most derived" meta interface in the list.
256 [ + + ]: 11 : if (best === null)
257 : 9 : return candidate;
258 [ + + ]: 2 : if (candidate === null)
259 : 1 : return best;
260 [ - + ]: 1 : for (let sup = candidate; sup; sup = sup.__super__) {
261 [ - + ]: 1 : if (sup === best)
262 : 1 : return candidate;
263 : : }
264 : 0 : return best;
265 : 10 : }, null);
266 : :
267 : : // If we reach this point and we don't know the meta-interface, then it's
268 : : // most likely because there were only pure-C interfaces listed in Requires
269 : : // (and those don't have our magic properties.) However, all pure-C
270 : : // interfaces should require GObject.Object anyway.
271 [ + + ]: 9 : if (metaInterface === null)
272 : 1 : throw new Error('Did you forget to include GObject.Object in Requires?');
273 : :
274 : 8 : return metaInterface;
275 : 14 : }
276 : :
277 : 15 : function Interface(params, ...otherArgs) {
278 : 15 : let metaInterface = _getMetaInterface(params);
279 [ + + ][ + + ]: 14 : if (metaInterface && metaInterface !== this.constructor)
280 [ + - ]: 6 : return new metaInterface(params, ...otherArgs);
281 [ + - ]: 8 : return this._construct(params, ...otherArgs);
282 : 13 : }
283 : :
284 : 50 : Class.MetaInterface = Interface;
285 : :
286 : : /**
287 : : * Use this to signify a function that must be overridden in an implementation
288 : : * of the interface. Creating a class that doesn't override the function will
289 : : * throw an error.
290 : : */
291 : 50 : Interface.UNIMPLEMENTED = function UNIMPLEMENTED() {
292 : 0 : throw new Error('Not implemented');
293 : : };
294 : :
295 : 50 : Interface.__super__ = _Base;
296 : 50 : Interface.prototype = Object.create(_Base.prototype);
297 : 50 : Interface.prototype.constructor = Interface;
298 : 50 : Interface.prototype.__name__ = 'Interface';
299 : :
300 : 58 : Interface.prototype._construct = function (params, ...otherArgs) {
301 [ + + ]: 8 : if (!params.Name)
302 : 1 : throw new TypeError("Interfaces require an explicit 'Name' parameter.");
303 : :
304 : 7 : let newInterface = Object.create(this.constructor.prototype);
305 : :
306 : 7 : newInterface.__super__ = Interface;
307 : 7 : newInterface.prototype = Object.create(Interface.prototype);
308 : 7 : newInterface.prototype.constructor = newInterface;
309 : 7 : newInterface.prototype.__name__ = params.Name;
310 : :
311 [ + - ]: 7 : newInterface._init(params, ...otherArgs);
312 : :
313 : 14 : Object.defineProperty(newInterface.prototype, '__metaclass__', {
314 : 7 : writable: false,
315 : 7 : configurable: false,
316 : 7 : enumerable: false,
317 : 7 : value: this.constructor,
318 : : });
319 : 14 : Object.defineProperty(newInterface, 'name', {
320 : 7 : writable: false,
321 : 7 : configurable: true,
322 : 7 : enumerable: false,
323 : 7 : value: params.Name,
324 : : });
325 : :
326 : 7 : return newInterface;
327 : 7 : };
328 : :
329 : 84 : Interface.prototype._check = function (proto) {
330 : : // Check that proto implements all of this interface's required interfaces.
331 : : // "proto" refers to the object's prototype (which implements the interface)
332 : : // whereas "this.prototype" is the interface's prototype (which may still
333 : : // contain unimplemented methods.)
334 : :
335 : 59 : let unfulfilledReqs = this.prototype.__requires__.filter(required => {
336 : : // Either the interface is not present or it is not listed before the
337 : : // interface that requires it or the class does not inherit it. This is
338 : : // so that required interfaces don't copy over properties from other
339 : : // interfaces that require them.
340 : 25 : let interfaces = proto.__interfaces__;
341 [ + + ]: 25 : return (!_interfacePresent(required, proto) ||
342 [ + + ]: 11 : interfaces.indexOf(required) > interfaces.indexOf(this)) &&
343 : 16 : !(proto instanceof required);
344 : 55 : }).map(required =>
345 : : // __name__ is only present on GJS-created classes and will be the most
346 : : // accurate name. required.name will be present on introspected GObjects
347 : : // but is not preferred because it will be the C name. The last option
348 : : // is just so that we print something if there is garbage in Requires.
349 [ + + ][ + - ]: 5 : required.prototype.__name__ || required.name || required);
350 [ + + ]: 32 : if (unfulfilledReqs.length > 0) {
351 : 8 : throw new Error(`The following interfaces must be implemented before ${
352 : 4 : this.prototype.__name__}: ${unfulfilledReqs.join(', ')}`);
353 : : }
354 : :
355 : : // Check that this interface's required methods are implemented
356 : 28 : let unimplementedFns = Object.getOwnPropertyNames(this.prototype)
357 : 238 : .filter(p => this.prototype[p] === Interface.UNIMPLEMENTED)
358 [ - + ]: 43 : .filter(p => !(p in proto) || proto[p] === Interface.UNIMPLEMENTED);
359 [ + + ]: 28 : if (unimplementedFns.length > 0) {
360 : 4 : throw new Error(`The following members of ${
361 : 2 : this.prototype.__name__} are not implemented yet: ${
362 : 2 : unimplementedFns.join(', ')}`);
363 : : }
364 : : };
365 : :
366 : 50 : Interface.prototype.toString = function () {
367 : 1 : return `[interface ${this.__name__} for ${this.prototype.__name__}]`;
368 : : };
369 : :
370 : 63 : Interface.prototype._init = function (params) {
371 : 13 : let ifaceName = params.Name;
372 : :
373 : 13 : let propertyObj = {};
374 : 13 : Object.entries(Object.getOwnPropertyDescriptors(params))
375 [ - + ][ - + ]: 59 : .forEach(([name, descriptor]) => {
[ - + ][ # # ]
[ # # ][ # # ]
[ # # ]
376 [ + + ][ + + ]: 46 : if (name === 'Name' || name === 'Requires')
377 : 22 : return;
378 : :
379 : : // Create wrappers on the interface object so that generics work (e.g.
380 : : // SomeInterface.some_function(this, blah) instead of
381 : : // SomeInterface.prototype.some_function.call(this, blah)
382 [ + + ]: 24 : if (typeof descriptor.value === 'function') {
383 : 23 : let interfaceProto = this.prototype; // capture in closure
384 : 32 : this[name] = function (thisObj, ...args) {
385 [ + + ]: 9 : return interfaceProto[name].call(thisObj, ...args);
386 : : };
387 : : }
388 : :
389 : : // writable and enumerable are inherited, see note in Class._init()
390 : 24 : descriptor.configurable = false;
391 : :
392 : 24 : propertyObj[name] = descriptor;
393 : : });
394 : :
395 : 13 : Object.defineProperties(this.prototype, propertyObj);
396 : 26 : Object.defineProperties(this.prototype, {
397 : 13 : '__name__': {
398 : 13 : writable: false,
399 : 13 : configurable: false,
400 : 13 : enumerable: false,
401 : 13 : value: ifaceName,
402 : : },
403 : 13 : '__requires__': {
404 : 13 : writable: false,
405 : 13 : configurable: false,
406 : 13 : enumerable: false,
407 [ + + ]: 13 : value: params.Requires || [],
408 : : },
409 : : });
410 : : };
411 : :
412 : : // GObject Lang.Class magic
413 : :
414 : 50 : function defineGObjectLegacyObjects(GObject) {
415 : 50 : const Gi = imports._gi;
416 : 50 : const {_checkAccessors} = imports._common;
417 : :
418 : : // Some common functions between GObject.Class and GObject.Interface
419 : :
420 : 10 : function _createSignals(gtype, signals) {
421 [ + + ]: 21 : for (let signalName in signals) {
422 : 11 : let obj = signals[signalName];
423 [ + + ]: 11 : let flags = obj.flags !== undefined ? obj.flags : GObject.SignalFlags.RUN_FIRST;
424 [ + + ]: 11 : let accumulator = obj.accumulator !== undefined ? obj.accumulator : GObject.AccumulatorType.NONE;
425 [ + + ]: 11 : let rtype = obj.return_type !== undefined ? obj.return_type : GObject.TYPE_NONE;
426 [ + + ]: 11 : let paramtypes = obj.param_types !== undefined ? obj.param_types : [];
427 : :
428 : 11 : try {
429 : 11 : obj.signal_id = Gi.signal_new(gtype, signalName, flags, accumulator, rtype, paramtypes);
430 : 0 : } catch (e) {
431 : 0 : throw new TypeError(`Invalid signal ${signalName}: ${e.message}`);
432 : : }
433 : : }
434 : : }
435 : :
436 : 33 : function _createGTypeName(params) {
437 [ + + ]: 33 : if (params.GTypeName)
438 : 1 : return params.GTypeName;
439 : : else
440 : 32 : return `Gjs_${params.Name.replace(/[^a-z0-9_+-]/gi, '_')}`;
441 : : }
442 : :
443 : 33 : function _getGObjectInterfaces(interfaces) {
444 : 57 : return interfaces.filter(iface => Object.hasOwn(iface, '$gtype'));
445 : : }
446 : :
447 : 33 : function _propertiesAsArray(params) {
448 : 33 : let propertiesArray = [];
449 [ + + ]: 33 : if (params.Properties) {
450 [ + + ]: 28 : for (let prop in params.Properties)
451 : 16 : propertiesArray.push(params.Properties[prop]);
452 : : }
453 : 33 : return propertiesArray;
454 : 33 : }
455 : :
456 : 100 : const GObjectMeta = new Class({
457 : 50 : Name: 'GObjectClass',
458 : 50 : Extends: Class,
459 : :
460 : 77 : _init(params) {
461 : : // retrieve signals and remove them from params before chaining
462 : 27 : let signals = params.Signals;
463 : 27 : delete params.Signals;
464 : :
465 : 27 : this.parent(params);
466 : :
467 [ + + ]: 27 : if (signals)
468 : 4 : _createSignals(this.$gtype, signals);
469 : :
470 : 27 : Object.entries(Object.getOwnPropertyDescriptors(params))
471 [ - + ][ - + ]: 163 : .forEach(([name, descriptor]) => {
[ - + ][ # # ]
[ # # ][ # # ]
[ # # ]
472 [ + + ]: 136 : if (typeof descriptor.value !== 'function' ||
473 [ + + ]: 65 : ['Name', 'Extends', 'Abstract'].includes(name))
474 : 98 : return;
475 : :
476 : 38 : let wrapped = this.prototype[name];
477 : :
478 [ + + ]: 38 : if (name.startsWith('vfunc_')) {
479 : 1 : this.prototype[Gi.hook_up_vfunc_symbol](name.slice(6), wrapped);
480 [ + + ]: 37 : } else if (name.startsWith('on_')) {
481 : 3 : let id = GObject.signal_lookup(name.slice(3).replace('_', '-'), this.$gtype);
482 [ - + ]: 3 : if (id !== 0) {
483 : 6 : GObject.signal_override_class_closure(id, this.$gtype, function (...argArray) {
484 : 3 : let emitter = argArray.shift();
485 : :
486 : 3 : return wrapped.apply(emitter, argArray);
487 : 3 : });
488 : : }
489 : : }
490 : 98 : });
491 : : },
492 : :
493 : 74 : _isValidClass(klass) {
494 : 24 : let proto = klass.prototype;
495 : :
496 [ + - ]: 24 : if (!proto)
497 : 0 : return false;
498 : :
499 : : // If proto === GObject.Object.prototype, then
500 : : // proto.__proto__ is Object, so "proto instanceof GObject.Object"
501 : : // will return false.
502 [ + + ]: 24 : return proto === GObject.Object.prototype ||
503 : 9 : proto instanceof GObject.Object;
504 : 24 : },
505 : :
506 : : // If we want an object with a custom JSClass, we can't just
507 : : // use a function. We have to use a custom constructor here.
508 : 77 : _construct(params, ...otherArgs) {
509 [ + - ]: 27 : if (!params.Name)
510 : 0 : throw new TypeError("Classes require an explicit 'Name' parameter.");
511 : 27 : let name = params.Name;
512 : :
513 : 27 : let gtypename = _createGTypeName(params);
514 [ + - ]: 27 : let gflags = params.Abstract ? GObject.TypeFlags.ABSTRACT : 0;
515 : :
516 [ + + ]: 27 : if (!params.Extends)
517 : 2 : params.Extends = GObject.Object;
518 : 27 : let parent = params.Extends;
519 : :
520 [ + - ]: 27 : if (!this._isValidClass(parent))
521 : 0 : throw new TypeError(`GObject.Class used with invalid base class (is ${parent})`);
522 : :
523 [ + + ]: 27 : let interfaces = params.Implements || [];
524 [ + + ]: 27 : if (parent instanceof Class)
525 : 7 : interfaces = interfaces.filter(iface => !parent.implements(iface));
526 : 27 : let gobjectInterfaces = _getGObjectInterfaces(interfaces);
527 : :
528 : 27 : let propertiesArray = _propertiesAsArray(params);
529 : 27 : delete params.Properties;
530 : :
531 : 42 : propertiesArray.forEach(pspec => _checkAccessors(params, pspec, GObject));
532 : :
533 : 54 : let newClass = Gi.register_type(parent.prototype, gtypename,
534 : 27 : gflags, gobjectInterfaces, propertiesArray);
535 : :
536 : : // See Class.prototype._construct for the reasoning
537 : : // behind this direct prototype set.
538 : 27 : Object.setPrototypeOf(newClass, this.constructor.prototype);
539 : 27 : newClass.__super__ = parent;
540 : :
541 [ + - ]: 27 : newClass._init(params, ...otherArgs);
542 : :
543 : 54 : Object.defineProperties(newClass.prototype, {
544 : 27 : '__metaclass__': {
545 : 27 : writable: false,
546 : 27 : configurable: false,
547 : 27 : enumerable: false,
548 : 27 : value: this.constructor,
549 : : },
550 : 27 : '__interfaces__': {
551 : 27 : writable: false,
552 : 27 : configurable: false,
553 : 27 : enumerable: false,
554 : 27 : value: interfaces,
555 : : },
556 : : });
557 : : // Overwrite the C++-set class name, as if it were an ES6 class
558 : 54 : Object.defineProperty(newClass, 'name', {
559 : 27 : writable: false,
560 : 27 : configurable: true,
561 : 27 : enumerable: false,
562 : 27 : value: name,
563 : : });
564 : :
565 : 27 : interfaces.forEach(iface => {
566 [ + + ]: 17 : if (iface instanceof Interface)
567 : 13 : iface._check(newClass.prototype);
568 : : });
569 : :
570 : 26 : return newClass;
571 : 26 : },
572 : :
573 : : // Overrides Lang.Class.implements()
574 : 50 : implements(iface) {
575 [ + + ]: 13 : if (iface instanceof GObject.Interface)
576 : 8 : return GObject.type_is_a(this.$gtype, iface.$gtype);
577 : : else
578 : 5 : return this.parent(iface);
579 : : },
580 : : });
581 : :
582 : 7 : function GObjectInterface(...args) {
583 [ + - ][ # # ]: 7 : return this._construct(...args);
584 : : }
585 : :
586 : 50 : GObjectMeta.MetaInterface = GObjectInterface;
587 : :
588 : 50 : GObjectInterface.__super__ = Interface;
589 : 50 : GObjectInterface.prototype = Object.create(Interface.prototype);
590 : 50 : GObjectInterface.prototype.constructor = GObjectInterface;
591 : 50 : GObjectInterface.prototype.__name__ = 'GObjectInterface';
592 : :
593 : 57 : GObjectInterface.prototype._construct = function (params, ...otherArgs) {
594 [ + - ]: 7 : if (!params.Name)
595 : 0 : throw new TypeError("Interfaces require an explicit 'Name' parameter.");
596 : :
597 : 6 : let gtypename = _createGTypeName(params);
598 : 6 : delete params.GTypeName;
599 : :
600 [ + - ]: 6 : let interfaces = params.Requires || [];
601 : 6 : let gobjectInterfaces = _getGObjectInterfaces(interfaces);
602 : :
603 : 6 : let properties = _propertiesAsArray(params);
604 : 6 : delete params.Properties;
605 : :
606 : 12 : let newInterface = Gi.register_interface(gtypename, gobjectInterfaces,
607 : 6 : properties);
608 : :
609 : : // See Class.prototype._construct for the reasoning
610 : : // behind this direct prototype set.
611 : 6 : Object.setPrototypeOf(newInterface, this.constructor.prototype);
612 : 6 : newInterface.__super__ = GObjectInterface;
613 : 6 : newInterface.prototype.constructor = newInterface;
614 : :
615 [ + - ]: 6 : newInterface._init(params, ...otherArgs);
616 : :
617 : 12 : Object.defineProperty(newInterface.prototype, '__metaclass__', {
618 : 6 : writable: false,
619 : 6 : configurable: false,
620 : 6 : enumerable: false,
621 : 6 : value: this.constructor,
622 : : });
623 : : // Overwrite the C++-set class name, as if it were an ES6 class
624 : 12 : Object.defineProperty(newInterface, 'name', {
625 : 6 : writable: false,
626 : 6 : configurable: true,
627 : 6 : enumerable: false,
628 : 6 : value: params.Name,
629 : : });
630 : :
631 : 6 : return newInterface;
632 : 6 : };
633 : :
634 : 56 : GObjectInterface.prototype._init = function (params) {
635 : 6 : let signals = params.Signals;
636 : 6 : delete params.Signals;
637 : :
638 : 6 : Interface.prototype._init.call(this, params);
639 : :
640 : 6 : _createSignals(this.$gtype, signals);
641 : : };
642 : :
643 : 50 : return {GObjectMeta, GObjectInterface};
644 : 50 : }
645 : :
646 : 9 : function defineGtkLegacyObjects(GObject, Gtk) {
647 : 9 : const {_createBuilderConnectFunc} = imports._common;
648 : :
649 : 18 : const GtkWidgetClass = new Class({
650 : 9 : Name: 'GtkWidgetClass',
651 : 9 : Extends: GObject.Class,
652 : :
653 : 12 : _init(params) {
654 : 3 : let template = params.Template;
655 : 3 : delete params.Template;
656 : :
657 : 3 : let children = params.Children;
658 : 3 : delete params.Children;
659 : :
660 : 3 : let internalChildren = params.InternalChildren;
661 : 3 : delete params.InternalChildren;
662 : :
663 : 3 : let cssName = params.CssName;
664 : 3 : delete params.CssName;
665 : :
666 [ - + ]: 3 : if (template) {
667 : 3 : params._instance_init = function () {
668 : 7 : this.init_template();
669 : : };
670 : : }
671 : :
672 : 3 : this.parent(params);
673 : :
674 [ + + ]: 3 : if (cssName)
675 : 1 : Gtk.Widget.set_css_name.call(this, cssName);
676 : :
677 [ - + ]: 3 : if (template) {
678 [ + + ]: 3 : if (typeof template === 'string' &&
679 [ + + ]: 1 : template.startsWith('resource:///'))
680 : 1 : Gtk.Widget.set_template_from_resource.call(this, template.slice(11));
681 : : else
682 : 2 : Gtk.Widget.set_template.call(this, template);
683 : : }
684 : :
685 : 3 : Gtk.Widget.set_connect_func.call(this, _createBuilderConnectFunc(this));
686 : :
687 : 3 : this[Gtk.template] = template;
688 : 3 : this[Gtk.children] = children;
689 : 3 : this[Gtk.internalChildren] = internalChildren;
690 : :
691 [ + + ]: 3 : if (children) {
692 [ + + ]: 6 : for (let i = 0; i < children.length; i++)
693 : 4 : Gtk.Widget.bind_template_child_full.call(this, children[i], false, 0);
694 : : }
695 : :
696 [ + + ]: 3 : if (internalChildren) {
697 [ + + ]: 4 : for (let i = 0; i < internalChildren.length; i++)
698 : 2 : Gtk.Widget.bind_template_child_full.call(this, internalChildren[i], true, 0);
699 : : }
700 : : },
701 : :
702 : 12 : _isValidClass(klass) {
703 : 3 : let proto = klass.prototype;
704 : :
705 [ + - ]: 3 : if (!proto)
706 : 0 : return false;
707 : :
708 : : // If proto === Gtk.Widget.prototype, then
709 : : // proto.__proto__ is GObject.InitiallyUnowned, so
710 : : // "proto instanceof Gtk.Widget"
711 : : // will return false.
712 [ - + ]: 3 : return proto === Gtk.Widget.prototype ||
713 : 3 : proto instanceof Gtk.Widget;
714 : 3 : },
715 : : });
716 : :
717 : 9 : return {GtkWidgetClass};
718 : 9 : }
|