Branch data Line data Source code
1 : 48 : /* -*- 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 : 48 : _Base.__super__ = null;
17 : 48 : _Base.prototype._init = function () { };
18 : 114 : _Base.prototype._construct = function (...args) {
19 [ + - ][ # # ]: 66 : this._init(...args);
20 : 66 : return this;
21 : : };
22 : 48 : _Base.prototype.__name__ = '_Base';
23 : 48 : _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 : 121 : function getMetaClass(params) {
53 [ + - ]: 121 : if (params.MetaClass)
54 : 0 : return params.MetaClass;
55 : :
56 [ + + ][ + + ]: 121 : if (params.Extends && params.Extends.prototype.__metaclass__)
57 : 45 : return params.Extends.prototype.__metaclass__;
58 : :
59 : 76 : return null;
60 : : }
61 : :
62 : 120 : function Class(params, ...otherArgs) {
63 : 120 : let metaClass = getMetaClass(params);
64 : :
65 [ + + ][ + + ]: 120 : if (metaClass && metaClass !== this.constructor)
66 [ + - ]: 26 : return new metaClass(params, ...otherArgs);
67 : : else
68 [ + - ]: 94 : return this._construct(params, ...otherArgs);
69 : 112 : }
70 : :
71 : 48 : Class.__super__ = _Base;
72 : 48 : Class.prototype = Object.create(_Base.prototype);
73 : 48 : Class.prototype.constructor = Class;
74 : 48 : Class.prototype.__name__ = 'Class';
75 : :
76 : 357 : Class.prototype.wrapFunction = function (name, meth) {
77 [ + - ]: 309 : 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 : 309 : wrapper._origin = meth;
89 : 309 : wrapper._name = name;
90 : 309 : wrapper._owner = this;
91 : :
92 : 309 : return wrapper;
93 : : };
94 : :
95 : 48 : Class.prototype.toString = function () {
96 : 0 : return `[object ${this.__name__} for ${this.prototype.__name__}]`;
97 : : };
98 : :
99 : 145 : Class.prototype._construct = function (params, ...otherArgs) {
100 [ + - ]: 97 : if (!params.Name)
101 : 0 : throw new TypeError("Classes require an explicit 'Name' parameter.");
102 : :
103 : 97 : let name = params.Name;
104 : :
105 : 97 : let parent = params.Extends;
106 [ + + ]: 97 : 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 : 97 : Object.setPrototypeOf(newClass, this.constructor.prototype);
123 : :
124 : 97 : newClass.__super__ = parent;
125 : 97 : newClass.prototype = Object.create(parent.prototype);
126 : 97 : newClass.prototype.constructor = newClass;
127 : :
128 [ + - ]: 97 : newClass._init(params, ...otherArgs);
129 : :
130 [ + + ]: 97 : let interfaces = params.Implements || [];
131 : : // If the parent already implements an interface, then we do too
132 [ + + ]: 97 : if (parent instanceof Class)
133 : 25 : interfaces = interfaces.filter(iface => !parent.implements(iface));
134 : :
135 : 194 : Object.defineProperties(newClass.prototype, {
136 : 97 : '__metaclass__': {
137 : 97 : writable: false,
138 : 97 : configurable: false,
139 : 97 : enumerable: false,
140 : 97 : value: this.constructor,
141 : : },
142 : 97 : '__interfaces__': {
143 : 97 : writable: false,
144 : 97 : configurable: false,
145 : 97 : enumerable: false,
146 : 97 : value: interfaces,
147 : : },
148 : : });
149 : 194 : Object.defineProperty(newClass, 'name', {
150 : 97 : writable: false,
151 : 97 : configurable: true,
152 : 97 : enumerable: false,
153 : 97 : value: name,
154 : : });
155 : :
156 : 97 : interfaces.forEach(iface => {
157 : 21 : iface._check(newClass.prototype);
158 : : });
159 : :
160 : 90 : return newClass;
161 : 90 : };
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 : 48 : 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 : 397 : Class.prototype._copyPropertyDescriptor = function (params, propertyObj, key) {
179 : 349 : let descriptor = Object.getOwnPropertyDescriptor(params, key);
180 : :
181 [ + + ]: 349 : if (typeof descriptor.value === 'function')
182 : 307 : 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 : 349 : descriptor.configurable = false;
188 : :
189 : 349 : propertyObj[key] = descriptor;
190 : : };
191 : :
192 : 172 : Class.prototype._init = function (params) {
193 : 124 : let className = params.Name;
194 : :
195 : 124 : let propertyObj = { };
196 : :
197 [ + + ]: 124 : let interfaces = params.Implements || [];
198 : 124 : interfaces.forEach(iface => {
199 : 42 : Object.getOwnPropertyNames(iface.prototype)
200 [ + + ]: 331 : .filter(name => !name.startsWith('__') && name !== 'constructor')
201 : 175 : .filter(name => !(name in this.prototype))
202 : 141 : .forEach(name => {
203 : 198 : let descriptor = Object.getOwnPropertyDescriptor(iface.prototype,
204 : 99 : name);
205 : : // writable and enumerable are inherited, see note above
206 : 99 : descriptor.configurable = false;
207 : 99 : propertyObj[name] = descriptor;
208 : : });
209 : : });
210 : :
211 : 124 : Object.getOwnPropertyNames(params)
212 : 124 : .filter(name =>
213 : 601 : ['Name', 'Extends', 'Abstract', 'Implements'].indexOf(name) === -1)
214 : 124 : .concat(Object.getOwnPropertySymbols(params))
215 : 124 : .forEach(this._copyPropertyDescriptor.bind(this, params, propertyObj));
216 : :
217 : 124 : Object.defineProperties(this.prototype, propertyObj);
218 : 248 : Object.defineProperties(this.prototype, {
219 : 124 : '__name__': {
220 : 124 : writable: false,
221 : 124 : configurable: false,
222 : 124 : enumerable: false,
223 : 124 : value: className,
224 : : },
225 : 124 : 'parent': {
226 : 124 : writable: false,
227 : 124 : configurable: false,
228 : 124 : enumerable: false,
229 : 124 : 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 : 36 : function _getMetaInterface(params) {
241 [ + + ][ + + ]: 36 : if (!params.Requires || params.Requires.length === 0)
242 : 27 : 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 : 35 : }
276 : :
277 : 36 : function Interface(params, ...otherArgs) {
278 : 36 : let metaInterface = _getMetaInterface(params);
279 [ + + ][ + + ]: 35 : if (metaInterface && metaInterface !== this.constructor)
280 [ + - ]: 6 : return new metaInterface(params, ...otherArgs);
281 [ + - ]: 29 : return this._construct(params, ...otherArgs);
282 : 34 : }
283 : :
284 : 48 : 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 : 48 : Interface.UNIMPLEMENTED = function UNIMPLEMENTED() {
292 : 0 : throw new Error('Not implemented');
293 : : };
294 : :
295 : 48 : Interface.__super__ = _Base;
296 : 48 : Interface.prototype = Object.create(_Base.prototype);
297 : 48 : Interface.prototype.constructor = Interface;
298 : 48 : Interface.prototype.__name__ = 'Interface';
299 : :
300 : 77 : Interface.prototype._construct = function (params, ...otherArgs) {
301 [ + + ]: 29 : if (!params.Name)
302 : 1 : throw new TypeError("Interfaces require an explicit 'Name' parameter.");
303 : :
304 : 28 : let newInterface = Object.create(this.constructor.prototype);
305 : :
306 : 28 : newInterface.__super__ = Interface;
307 : 28 : newInterface.prototype = Object.create(Interface.prototype);
308 : 28 : newInterface.prototype.constructor = newInterface;
309 : 28 : newInterface.prototype.__name__ = params.Name;
310 : :
311 [ + - ]: 28 : newInterface._init(params, ...otherArgs);
312 : :
313 : 56 : Object.defineProperty(newInterface.prototype, '__metaclass__', {
314 : 28 : writable: false,
315 : 28 : configurable: false,
316 : 28 : enumerable: false,
317 : 28 : value: this.constructor,
318 : : });
319 : 56 : Object.defineProperty(newInterface, 'name', {
320 : 28 : writable: false,
321 : 28 : configurable: true,
322 : 28 : enumerable: false,
323 : 28 : value: params.Name,
324 : : });
325 : :
326 : 28 : return newInterface;
327 : 28 : };
328 : :
329 : 82 : 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 : 48 : Interface.prototype.toString = function () {
367 : 1 : return `[interface ${this.__name__} for ${this.prototype.__name__}]`;
368 : : };
369 : :
370 : 82 : Interface.prototype._init = function (params) {
371 : 34 : let ifaceName = params.Name;
372 : :
373 : 34 : let propertyObj = {};
374 : 34 : Object.getOwnPropertyNames(params)
375 : 227 : .filter(name => ['Name', 'Requires'].indexOf(name) === -1)
376 : 184 : .forEach(name => {
377 : 150 : let descriptor = Object.getOwnPropertyDescriptor(params, name);
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 [ + + ]: 150 : if (typeof descriptor.value === 'function') {
383 : 149 : let interfaceProto = this.prototype; // capture in closure
384 : 158 : 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 : 150 : descriptor.configurable = false;
391 : :
392 : 150 : propertyObj[name] = descriptor;
393 : : });
394 : :
395 : 34 : Object.defineProperties(this.prototype, propertyObj);
396 : 68 : Object.defineProperties(this.prototype, {
397 : 34 : '__name__': {
398 : 34 : writable: false,
399 : 34 : configurable: false,
400 : 34 : enumerable: false,
401 : 34 : value: ifaceName,
402 : : },
403 : 34 : '__requires__': {
404 : 34 : writable: false,
405 : 34 : configurable: false,
406 : 34 : enumerable: false,
407 [ + + ]: 34 : value: params.Requires || [],
408 : : },
409 : : });
410 : : };
411 : :
412 : : // GObject Lang.Class magic
413 : :
414 : 48 : function defineGObjectLegacyObjects(GObject) {
415 : 48 : const Gi = imports._gi;
416 : 48 : 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 : 96 : const GObjectMeta = new Class({
457 : 48 : Name: 'GObjectClass',
458 : 48 : Extends: Class,
459 : :
460 : 75 : _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 : 163 : Object.getOwnPropertyNames(params).forEach(name => {
471 [ + + ]: 136 : if (['Name', 'Extends', 'Abstract'].includes(name))
472 : 54 : return;
473 : :
474 : 82 : let descriptor = Object.getOwnPropertyDescriptor(params, name);
475 : :
476 [ + + ]: 82 : if (typeof descriptor.value === 'function') {
477 : 38 : let wrapped = this.prototype[name];
478 : :
479 [ + + ]: 38 : if (name.startsWith('vfunc_')) {
480 : 2 : this.prototype[Gi.hook_up_vfunc_symbol](name.slice(6),
481 : 1 : wrapped);
482 [ + + ]: 37 : } else if (name.startsWith('on_')) {
483 : 3 : let id = GObject.signal_lookup(name.slice(3).replace('_', '-'), this.$gtype);
484 [ - + ]: 3 : if (id !== 0) {
485 : 6 : GObject.signal_override_class_closure(id, this.$gtype, function (...argArray) {
486 : 3 : let emitter = argArray.shift();
487 : :
488 : 3 : return wrapped.apply(emitter, argArray);
489 : 3 : });
490 : : }
491 : : }
492 : : }
493 : 54 : });
494 : : },
495 : :
496 : 72 : _isValidClass(klass) {
497 : 24 : let proto = klass.prototype;
498 : :
499 [ + - ]: 24 : if (!proto)
500 : 0 : return false;
501 : :
502 : : // If proto === GObject.Object.prototype, then
503 : : // proto.__proto__ is Object, so "proto instanceof GObject.Object"
504 : : // will return false.
505 [ + + ]: 24 : return proto === GObject.Object.prototype ||
506 : 9 : proto instanceof GObject.Object;
507 : 24 : },
508 : :
509 : : // If we want an object with a custom JSClass, we can't just
510 : : // use a function. We have to use a custom constructor here.
511 : 75 : _construct(params, ...otherArgs) {
512 [ + - ]: 27 : if (!params.Name)
513 : 0 : throw new TypeError("Classes require an explicit 'Name' parameter.");
514 : 27 : let name = params.Name;
515 : :
516 : 27 : let gtypename = _createGTypeName(params);
517 [ + - ]: 27 : let gflags = params.Abstract ? GObject.TypeFlags.ABSTRACT : 0;
518 : :
519 [ + + ]: 27 : if (!params.Extends)
520 : 2 : params.Extends = GObject.Object;
521 : 27 : let parent = params.Extends;
522 : :
523 [ + - ]: 27 : if (!this._isValidClass(parent))
524 : 0 : throw new TypeError(`GObject.Class used with invalid base class (is ${parent})`);
525 : :
526 [ + + ]: 27 : let interfaces = params.Implements || [];
527 [ + + ]: 27 : if (parent instanceof Class)
528 : 7 : interfaces = interfaces.filter(iface => !parent.implements(iface));
529 : 27 : let gobjectInterfaces = _getGObjectInterfaces(interfaces);
530 : :
531 : 27 : let propertiesArray = _propertiesAsArray(params);
532 : 27 : delete params.Properties;
533 : :
534 : 42 : propertiesArray.forEach(pspec => _checkAccessors(params, pspec, GObject));
535 : :
536 : 54 : let newClass = Gi.register_type(parent.prototype, gtypename,
537 : 27 : gflags, gobjectInterfaces, propertiesArray);
538 : :
539 : : // See Class.prototype._construct for the reasoning
540 : : // behind this direct prototype set.
541 : 27 : Object.setPrototypeOf(newClass, this.constructor.prototype);
542 : 27 : newClass.__super__ = parent;
543 : :
544 [ + - ]: 27 : newClass._init(params, ...otherArgs);
545 : :
546 : 54 : Object.defineProperties(newClass.prototype, {
547 : 27 : '__metaclass__': {
548 : 27 : writable: false,
549 : 27 : configurable: false,
550 : 27 : enumerable: false,
551 : 27 : value: this.constructor,
552 : : },
553 : 27 : '__interfaces__': {
554 : 27 : writable: false,
555 : 27 : configurable: false,
556 : 27 : enumerable: false,
557 : 27 : value: interfaces,
558 : : },
559 : : });
560 : : // Overwrite the C++-set class name, as if it were an ES6 class
561 : 54 : Object.defineProperty(newClass, 'name', {
562 : 27 : writable: false,
563 : 27 : configurable: true,
564 : 27 : enumerable: false,
565 : 27 : value: name,
566 : : });
567 : :
568 : 27 : interfaces.forEach(iface => {
569 [ + + ]: 17 : if (iface instanceof Interface)
570 : 13 : iface._check(newClass.prototype);
571 : : });
572 : :
573 : 26 : return newClass;
574 : 26 : },
575 : :
576 : : // Overrides Lang.Class.implements()
577 : 48 : implements(iface) {
578 [ + + ]: 13 : if (iface instanceof GObject.Interface)
579 : 8 : return GObject.type_is_a(this.$gtype, iface.$gtype);
580 : : else
581 : 5 : return this.parent(iface);
582 : : },
583 : : });
584 : :
585 : 7 : function GObjectInterface(...args) {
586 [ + - ][ # # ]: 7 : return this._construct(...args);
587 : : }
588 : :
589 : 48 : GObjectMeta.MetaInterface = GObjectInterface;
590 : :
591 : 48 : GObjectInterface.__super__ = Interface;
592 : 48 : GObjectInterface.prototype = Object.create(Interface.prototype);
593 : 48 : GObjectInterface.prototype.constructor = GObjectInterface;
594 : 48 : GObjectInterface.prototype.__name__ = 'GObjectInterface';
595 : :
596 : 55 : GObjectInterface.prototype._construct = function (params, ...otherArgs) {
597 [ + - ]: 7 : if (!params.Name)
598 : 0 : throw new TypeError("Interfaces require an explicit 'Name' parameter.");
599 : :
600 : 6 : let gtypename = _createGTypeName(params);
601 : 6 : delete params.GTypeName;
602 : :
603 [ + - ]: 6 : let interfaces = params.Requires || [];
604 : 6 : let gobjectInterfaces = _getGObjectInterfaces(interfaces);
605 : :
606 : 6 : let properties = _propertiesAsArray(params);
607 : 6 : delete params.Properties;
608 : :
609 : 12 : let newInterface = Gi.register_interface(gtypename, gobjectInterfaces,
610 : 6 : properties);
611 : :
612 : : // See Class.prototype._construct for the reasoning
613 : : // behind this direct prototype set.
614 : 6 : Object.setPrototypeOf(newInterface, this.constructor.prototype);
615 : 6 : newInterface.__super__ = GObjectInterface;
616 : 6 : newInterface.prototype.constructor = newInterface;
617 : :
618 [ + - ]: 6 : newInterface._init(params, ...otherArgs);
619 : :
620 : 12 : Object.defineProperty(newInterface.prototype, '__metaclass__', {
621 : 6 : writable: false,
622 : 6 : configurable: false,
623 : 6 : enumerable: false,
624 : 6 : value: this.constructor,
625 : : });
626 : : // Overwrite the C++-set class name, as if it were an ES6 class
627 : 12 : Object.defineProperty(newInterface, 'name', {
628 : 6 : writable: false,
629 : 6 : configurable: true,
630 : 6 : enumerable: false,
631 : 6 : value: params.Name,
632 : : });
633 : :
634 : 6 : return newInterface;
635 : 6 : };
636 : :
637 : 54 : GObjectInterface.prototype._init = function (params) {
638 : 6 : let signals = params.Signals;
639 : 6 : delete params.Signals;
640 : :
641 : 6 : Interface.prototype._init.call(this, params);
642 : :
643 : 6 : _createSignals(this.$gtype, signals);
644 : : };
645 : :
646 : 48 : return {GObjectMeta, GObjectInterface};
647 : 48 : }
648 : :
649 : 9 : function defineGtkLegacyObjects(GObject, Gtk) {
650 : 9 : const {_createBuilderConnectFunc} = imports._common;
651 : :
652 : 18 : const GtkWidgetClass = new Class({
653 : 9 : Name: 'GtkWidgetClass',
654 : 9 : Extends: GObject.Class,
655 : :
656 : 12 : _init(params) {
657 : 3 : let template = params.Template;
658 : 3 : delete params.Template;
659 : :
660 : 3 : let children = params.Children;
661 : 3 : delete params.Children;
662 : :
663 : 3 : let internalChildren = params.InternalChildren;
664 : 3 : delete params.InternalChildren;
665 : :
666 : 3 : let cssName = params.CssName;
667 : 3 : delete params.CssName;
668 : :
669 [ - + ]: 3 : if (template) {
670 : 3 : params._instance_init = function () {
671 : 7 : this.init_template();
672 : : };
673 : : }
674 : :
675 : 3 : this.parent(params);
676 : :
677 [ + + ]: 3 : if (cssName)
678 : 1 : Gtk.Widget.set_css_name.call(this, cssName);
679 : :
680 [ - + ]: 3 : if (template) {
681 [ + + ]: 3 : if (typeof template === 'string' &&
682 [ + + ]: 1 : template.startsWith('resource:///'))
683 : 1 : Gtk.Widget.set_template_from_resource.call(this, template.slice(11));
684 : : else
685 : 2 : Gtk.Widget.set_template.call(this, template);
686 : : }
687 : :
688 : 3 : Gtk.Widget.set_connect_func.call(this, _createBuilderConnectFunc(this));
689 : :
690 : 3 : this[Gtk.template] = template;
691 : 3 : this[Gtk.children] = children;
692 : 3 : this[Gtk.internalChildren] = internalChildren;
693 : :
694 [ + + ]: 3 : if (children) {
695 [ + + ]: 6 : for (let i = 0; i < children.length; i++)
696 : 4 : Gtk.Widget.bind_template_child_full.call(this, children[i], false, 0);
697 : : }
698 : :
699 [ + + ]: 3 : if (internalChildren) {
700 [ + + ]: 4 : for (let i = 0; i < internalChildren.length; i++)
701 : 2 : Gtk.Widget.bind_template_child_full.call(this, internalChildren[i], true, 0);
702 : : }
703 : : },
704 : :
705 : 12 : _isValidClass(klass) {
706 : 3 : let proto = klass.prototype;
707 : :
708 [ + - ]: 3 : if (!proto)
709 : 0 : return false;
710 : :
711 : : // If proto === Gtk.Widget.prototype, then
712 : : // proto.__proto__ is GObject.InitiallyUnowned, so
713 : : // "proto instanceof Gtk.Widget"
714 : : // will return false.
715 [ - + ]: 3 : return proto === Gtk.Widget.prototype ||
716 : 3 : proto instanceof Gtk.Widget;
717 : 3 : },
718 : : });
719 : :
720 : 9 : return {GtkWidgetClass};
721 : 9 : }
|