Branch data Line data Source code
1 : 48 : // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
2 : :
3 : : // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
4 : : // SPDX-FileCopyrightText: 2020 Philip Chimento <philip.chimento@gmail.com>
5 : :
6 : : /* exported _checkAccessors, _createBuilderConnectFunc, _createClosure,
7 : : _registerType */
8 : :
9 : : // This is a helper module in which to put code that is common between the
10 : : // legacy GObject.Class system and the new GObject.registerClass system.
11 : :
12 : 48 : var _registerType = Symbol('GObject register type hook');
13 : :
14 : 33 : function _generateAccessors(pspec, propdesc, GObject) {
15 : 33 : const {name, flags} = pspec;
16 : 33 : const readable = flags & GObject.ParamFlags.READABLE;
17 : 33 : const writable = flags & GObject.ParamFlags.WRITABLE;
18 : :
19 [ + + ]: 33 : if (!propdesc) {
20 : 30 : propdesc = {
21 : 30 : configurable: true,
22 : 30 : enumerable: true,
23 : : };
24 : : }
25 : :
26 [ + + ][ + + ]: 33 : if (readable && writable) {
27 [ + + ][ + + ]: 18 : if (!propdesc.get && !propdesc.set) {
28 : 15 : const privateName = Symbol(`__autogeneratedAccessor__${name}`);
29 : 15 : const defaultValue = pspec.get_default_value();
30 : 15 : propdesc.get = function () {
31 [ + + ]: 58 : if (!(privateName in this))
32 : 10 : this[privateName] = defaultValue;
33 : 58 : return this[privateName];
34 : : };
35 : 15 : propdesc.set = function (value) {
36 [ + + ]: 61 : if (value !== this[privateName]) {
37 : 59 : this[privateName] = value;
38 : 59 : this.notify(name);
39 : : }
40 : : };
41 [ + + ]: 3 : } else if (!propdesc.get) {
42 : 1 : propdesc.get = function () {
43 : 1 : throw new Error(`setter defined without getter for property ${name}`);
44 : : };
45 [ - + ]: 2 : } else if (!propdesc.set) {
46 : 2 : propdesc.set = function () {
47 : 1 : throw new Error(`getter defined without setter for property ${name}`);
48 : : };
49 : : }
50 [ + + ][ + + ]: 15 : } else if (readable && !propdesc.get) {
51 : 14 : propdesc.get = function () {
52 : 1 : throw new Error(`missing getter for read-only property ${name}`);
53 : : };
54 [ - + ][ - + ]: 1 : } else if (writable && !propdesc.set) {
55 : 1 : propdesc.set = function () {
56 : 1 : throw new Error(`missing setter for write-only property ${name}`);
57 : : };
58 : : }
59 : :
60 : 33 : return propdesc;
61 : 33 : }
62 : :
63 : 66 : function _checkAccessors(proto, pspec, GObject) {
64 : 66 : const {name, flags} = pspec;
65 [ + + ]: 66 : if (flags & GObject.ParamFlags.CONSTRUCT_ONLY)
66 : 12 : return;
67 : :
68 : 54 : const underscoreName = name.replace(/-/g, '_');
69 : 79 : const camelName = name.replace(/-([a-z])/g, match => match[1].toUpperCase());
70 : 54 : let propdesc = Object.getOwnPropertyDescriptor(proto, name);
71 : 54 : let dashPropdesc = propdesc, underscorePropdesc, camelPropdesc;
72 : 54 : const nameIsCompound = name.includes('-');
73 [ + + ]: 54 : if (nameIsCompound) {
74 : 24 : underscorePropdesc = Object.getOwnPropertyDescriptor(proto, underscoreName);
75 : 24 : camelPropdesc = Object.getOwnPropertyDescriptor(proto, camelName);
76 [ + + ]: 24 : if (!propdesc)
77 : 23 : propdesc = underscorePropdesc;
78 [ + + ]: 24 : if (!propdesc)
79 : 16 : propdesc = camelPropdesc;
80 : : }
81 : :
82 : 54 : const readable = flags & GObject.ParamFlags.READABLE;
83 : 54 : const writable = flags & GObject.ParamFlags.WRITABLE;
84 [ + + ][ - + ]: 54 : if (!propdesc || (readable && !propdesc.get) || (writable && !propdesc.set))
[ + + ][ + + ]
[ + + ]
85 : 33 : propdesc = _generateAccessors(pspec, propdesc, GObject);
86 : :
87 [ + + ]: 54 : if (!dashPropdesc)
88 : 40 : Object.defineProperty(proto, name, propdesc);
89 [ + + ]: 54 : if (nameIsCompound) {
90 [ + + ]: 24 : if (!underscorePropdesc)
91 : 17 : Object.defineProperty(proto, underscoreName, propdesc);
92 [ + + ]: 24 : if (!camelPropdesc)
93 : 21 : Object.defineProperty(proto, camelName, propdesc);
94 : : }
95 : 12 : }
96 : :
97 : 81 : function _createClosure(builder, thisArg, handlerName, swapped, connectObject) {
98 [ + + ]: 81 : connectObject ??= thisArg;
99 : :
100 [ + - ]: 81 : if (swapped) {
101 : 0 : throw new Error('Unsupported template signal flag "swapped"');
102 [ + - ]: 81 : } else if (typeof thisArg[handlerName] === 'undefined') {
103 : 0 : throw new Error(`A handler called ${handlerName} was not ` +
104 : 0 : `defined on ${thisArg}`);
105 : : }
106 : :
107 : 81 : return thisArg[handlerName].bind(connectObject);
108 : : }
109 : :
110 : 8 : function _createBuilderConnectFunc(klass) {
111 : 8 : const {GObject} = imports.gi;
112 : 46 : return function (builder, obj, signalName, handlerName, connectObj, flags) {
113 : 38 : const objects = builder.get_objects();
114 : 142 : const thisObj = objects.find(o => o instanceof klass);
115 : 38 : const swapped = flags & GObject.ConnectFlags.SWAPPED;
116 : 76 : const closure = _createClosure(builder, thisObj, handlerName, swapped,
117 : 38 : connectObj);
118 : :
119 [ + - ]: 38 : if (flags & GObject.ConnectFlags.AFTER)
120 : 0 : obj.connect_after(signalName, closure);
121 : : else
122 : 38 : obj.connect(signalName, closure);
123 : : };
124 : 8 : }
|