LCOV - code coverage report
Current view: top level - modules/script - _legacy.js (source / functions) Coverage Total Hit
Test: gjs- Code Coverage Lines: 96.1 % 433 416
Test Date: 2024-04-16 04:37:39 Functions: 94.3 % 53 50
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 79.7 % 192 153

             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                 :          35 : function _getMetaInterface(params) {
     241 [ +  + ][ +  + ]:          35 :     if (!params.Requires || params.Requires.length === 0)
     242                 :          26 :         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                 :           9 :     .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                 :          34 : }
     276                 :             : 
     277                 :          35 : function Interface(params, ...otherArgs) {
     278                 :          35 :     let metaInterface = _getMetaInterface(params);
     279 [ +  + ][ +  + ]:          34 :     if (metaInterface && metaInterface !== this.constructor)
     280         [ +  - ]:           6 :         return new metaInterface(params, ...otherArgs);
     281         [ +  - ]:          28 :     return this._construct(params, ...otherArgs);
     282                 :          33 : }
     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                 :          76 : Interface.prototype._construct = function (params, ...otherArgs) {
     301         [ +  + ]:          28 :     if (!params.Name)
     302                 :           1 :         throw new TypeError("Interfaces require an explicit 'Name' parameter.");
     303                 :             : 
     304                 :          27 :     let newInterface = Object.create(this.constructor.prototype);
     305                 :             : 
     306                 :          27 :     newInterface.__super__ = Interface;
     307                 :          27 :     newInterface.prototype = Object.create(Interface.prototype);
     308                 :          27 :     newInterface.prototype.constructor = newInterface;
     309                 :          27 :     newInterface.prototype.__name__ = params.Name;
     310                 :             : 
     311         [ +  - ]:          27 :     newInterface._init(params, ...otherArgs);
     312                 :             : 
     313                 :          54 :     Object.defineProperty(newInterface.prototype, '__metaclass__', {
     314                 :          27 :         writable: false,
     315                 :          27 :         configurable: false,
     316                 :          27 :         enumerable: false,
     317                 :          27 :         value: this.constructor,
     318                 :             :     });
     319                 :          54 :     Object.defineProperty(newInterface, 'name', {
     320                 :          27 :         writable: false,
     321                 :          27 :         configurable: true,
     322                 :          27 :         enumerable: false,
     323                 :          27 :         value: params.Name,
     324                 :             :     });
     325                 :             : 
     326                 :          27 :     return newInterface;
     327                 :          27 : };
     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                 :          81 : Interface.prototype._init = function (params) {
     371                 :          33 :     let ifaceName = params.Name;
     372                 :             : 
     373                 :          33 :     let propertyObj = {};
     374                 :          33 :     Object.getOwnPropertyNames(params)
     375                 :         219 :     .filter(name => ['Name', 'Requires'].indexOf(name) === -1)
     376                 :         177 :     .forEach(name => {
     377                 :         144 :         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         [ +  + ]:         144 :         if (typeof descriptor.value === 'function') {
     383                 :         143 :             let interfaceProto = this.prototype;  // capture in closure
     384                 :         152 :             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                 :         144 :         descriptor.configurable = false;
     391                 :             : 
     392                 :         144 :         propertyObj[name] = descriptor;
     393                 :             :     });
     394                 :             : 
     395                 :          33 :     Object.defineProperties(this.prototype, propertyObj);
     396                 :          66 :     Object.defineProperties(this.prototype, {
     397                 :          33 :         '__name__': {
     398                 :          33 :             writable: false,
     399                 :          33 :             configurable: false,
     400                 :          33 :             enumerable: false,
     401                 :          33 :             value: ifaceName,
     402                 :             :         },
     403                 :          33 :         '__requires__': {
     404                 :          33 :             writable: false,
     405                 :          33 :             configurable: false,
     406                 :          33 :             enumerable: false,
     407         [ +  + ]:          33 :             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 : }
        

Generated by: LCOV version 2.0-1