[gjs/esm/static-imports] Finish adding additional libraries/bindings.



commit 71ff942d68497566cb8cd2da369376ca6f1fa559
Author: Evan Welsh <noreply evanwelsh com>
Date:   Sat Nov 14 14:34:19 2020 -0600

    Finish adding additional libraries/bindings.

 js.gresource.xml                     |  2 +
 lib/modules/gi.js                    |  2 +-
 modules/core/_text.js                | 13 +++++++
 modules/esm/cairo.js                 |  7 ++++
 modules/esm/format.js                |  7 +++-
 modules/esm/gi.js                    | 66 +++++++++++++++++++++++++++++++
 modules/esm/signals.js               | 75 ++++++++++--------------------------
 modules/script/_bootstrap/default.js | 13 +++++++
 8 files changed, 127 insertions(+), 58 deletions(-)
---
diff --git a/js.gresource.xml b/js.gresource.xml
index 410f17ea..bbd0106d 100644
--- a/js.gresource.xml
+++ b/js.gresource.xml
@@ -9,6 +9,7 @@
     <file>lib/entry.js</file>
 
     <!-- ESM-based modules -->
+    <file>modules/esm/cairo.js</file>
     <file>modules/esm/gi.js</file>
     <file>modules/esm/system.js</file>
     <file>modules/esm/format.js</file>
@@ -47,5 +48,6 @@
     <file>modules/core/_format.js</file>
     <file>modules/core/_gettext.js</file>
     <file>modules/core/_signals.js</file>
+    <file>modules/core/_text.js</file>
   </gresource>
 </gresources>
diff --git a/lib/modules/gi.js b/lib/modules/gi.js
index b44d9f65..d38bd347 100644
--- a/lib/modules/gi.js
+++ b/lib/modules/gi.js
@@ -13,7 +13,7 @@ export function generateModule(namespace, version) {
     const source = `
     import $$gi from 'gi';
     
-    const $$ns = $$gi.require${version ? `('${namespace}', '${version}')` : `(${namespace})`};
+    const $$ns = $$gi.require${version ? `('${namespace}', '${version}')` : `('${namespace}')`};
 
     export default $$ns;
     `;
diff --git a/modules/core/_text.js b/modules/core/_text.js
new file mode 100644
index 00000000..60d081d3
--- /dev/null
+++ b/modules/core/_text.js
@@ -0,0 +1,13 @@
+const ByteArray = imports.byteArray;
+
+var TextDecoder = class TextDecoder {
+    decode(bytes) {
+        return ByteArray.toString(bytes);
+    }
+}
+
+var TextEncoder = class TextEncoder {
+    encode(string) {
+        return ByteArray.fromString(string);
+    }
+}
\ No newline at end of file
diff --git a/modules/esm/cairo.js b/modules/esm/cairo.js
new file mode 100644
index 00000000..642f2ccc
--- /dev/null
+++ b/modules/esm/cairo.js
@@ -0,0 +1,7 @@
+const cairo = import.meta.importSync('cairoNative');
+
+export default Object.assign(
+    {},
+    imports._cairo,
+    cairo
+);
\ No newline at end of file
diff --git a/modules/esm/format.js b/modules/esm/format.js
index 8f4c47eb..1d5dc4c9 100644
--- a/modules/esm/format.js
+++ b/modules/esm/format.js
@@ -1,2 +1,5 @@
-export const format = imports._format.format;
-export const vprintf = imports._format.vprintf;
\ No newline at end of file
+export const vprintf = imports._format.vprintf;
+
+export function format(...args) {
+    return vprintf(this, args);
+}
\ No newline at end of file
diff --git a/modules/esm/gi.js b/modules/esm/gi.js
index f9cbc374..8ee1ef14 100644
--- a/modules/esm/gi.js
+++ b/modules/esm/gi.js
@@ -1,5 +1,7 @@
 const gi = import.meta.importSync('gi');
 
+import System from 'system';
+
 const Gi = {
     require(name, version = null) {
         if (version !== null)
@@ -11,6 +13,70 @@ const Gi = {
 
         return gi[name];
     },
+    requireSymbol(lib, ver, symbol) {
+        if (!checkSymbol(lib, ver, symbol)) {
+            if (symbol)
+                printerr(`Unsatisfied dependency: No ${symbol} in ${lib}`);
+            else
+                printerr(`Unsatisfied dependency: ${lib}`);
+            System.exit(1);
+        }
+    },
+
+    /**
+     * Check whether an external GI typelib can be imported
+     * and provides @symbol.
+     *
+     * Symbols may refer to
+     *  - global functions         ('main_quit')
+     *  - classes                  ('Window')
+     *  - class / instance methods ('IconTheme.get_default' / 'IconTheme.has_icon')
+     *  - GObject properties       ('Window.default_height')
+     *
+     * @param {string} lib an external dependency to import
+     * @param {string} [ver] version of the dependency
+     * @param {string} [symbol] symbol to check for
+     * @returns {boolean} true if `lib` can be imported and provides `symbol`, false
+     * otherwise
+     */
+    checkSymbol(lib, ver, symbol) {
+        let Lib = null;
+
+        if (ver)
+            gi.versions[lib] = ver;
+
+        try {
+            Lib = gi[lib];
+        } catch (e) {
+            return false;
+        }
+
+        if (!symbol)
+            return true; // Done
+
+        let [klass, sym] = symbol.split('.');
+        if (klass === symbol) // global symbol
+            return typeof Lib[symbol] !== 'undefined';
+
+        let obj = Lib[klass];
+        if (typeof obj === 'undefined')
+            return false;
+
+        if (typeof obj[sym] !== 'undefined' ||
+            obj.prototype && typeof obj.prototype[sym] !== 'undefined')
+            return true; // class- or object method
+
+        // GObject property
+        let pspec = null;
+        if (GObject.type_is_a(obj.$gtype, GObject.TYPE_INTERFACE)) {
+            let iface = GObject.type_default_interface_ref(obj.$gtype);
+            pspec = GObject.Object.interface_find_property(iface, sym);
+        } else if (GObject.type_is_a(obj.$gtype, GObject.TYPE_OBJECT)) {
+            pspec = GObject.Object.find_property.call(obj.$gtype, sym);
+        }
+
+        return pspec !== null;
+    }
 };
 Object.freeze(Gi);
 
diff --git a/modules/esm/signals.js b/modules/esm/signals.js
index 16946132..d997eda7 100644
--- a/modules/esm/signals.js
+++ b/modules/esm/signals.js
@@ -1,11 +1,3 @@
-const _signals = imports._signals;
-
-function _addSignalMethod(proto, functionName, func) {
-    if (proto[functionName] && proto[functionName] !== func)
-        log(`WARNING: addSignalMethods is replacing existing ${proto} ${functionName} method`);
-
-    proto[functionName] = func;
-}
 
 export class EventEmitter {
     constructor() {
@@ -30,10 +22,6 @@ export class EventEmitter {
 
         // we instantiate the "signal machinery" only on-demand if anything
         // gets connected.
-        if (!('_events' in this)) {
-            this._events = [];
-            this._nextConnectionId = 1n;
-        }
 
         let id = this._nextConnectionId;
         this._nextConnectionId += 1n;
@@ -41,58 +29,52 @@ export class EventEmitter {
         // this makes it O(n) in total connections to emit, but I think
         // it's right to optimize for low memory and reentrancy-safety
         // rather than speed
-        this._events.push({
+
+        this._connectListener(name, {
             id,
             name,
             callback,
             'disconnected': false,
         });
 
-        this._connectListener(name, callback);
-
         return id;
     }
 
     disconnect(id) {
-        if ('_events' in this) {
-            let i;
-            let length = this._events.length;
-            for (i = 0; i < length; ++i) {
-                let connection = this._events[i];
+        this._events.forEach(_events => {
+            for (let i = 0; i < _events.length; ++i) {
+                let connection = _events[i];
                 if (connection.id === id) {
                     if (connection.disconnected)
                         throw new Error(`Signal handler id ${id} already disconnected`);
 
                     // set a flag to deal with removal during emission
                     connection.disconnected = true;
-                    this._events.splice(i, 1);
+                    _events.splice(i, 1);
 
                     return;
                 }
             }
-        }
-        throw new Error(`No signal connection ${id} found`);
+        });
     }
 
     signalHandlerIsConnected(id) {
-        if (!('_events' in this))
-            return false;
-
-        const { length } = this._events;
-        for (let i = 0; i < length; ++i) {
-            const connection = this._events[i];
-            if (connection.id === id)
-                return !connection.disconnected;
-        }
+        this._events.forEach(_events => {
+            for (let i = 0; i < _events.length; ++i) {
+                const connection = this._events[i];
+                if (connection.id === id)
+                    return !connection.disconnected;
+            }
+        });
 
         return false;
     }
 
     disconnectAll() {
-        if ('_events' in this) {
-            while (this._events.length > 0)
-                _disconnect.call(this, this._events[0].id);
-        }
+        this._events.forEach(_events => {
+            while (_events.length > 0)
+                this.disconnect.call(this, _events[0].id);
+        });
     }
 
     emit(name, ...args) {
@@ -104,14 +86,7 @@ export class EventEmitter {
         // emitting), we copy out a list of what was connected
         // at emission start; and just before invoking each
         // handler we check its disconnected flag.
-        let handlers = [];
-        let i;
-        let length = this._events.length;
-        for (i = 0; i < length; ++i) {
-            let connection = this._events[i];
-            if (connection.name === name)
-                handlers.push(connection);
-        }
+        let handlers = [...(this._events.get(name) || [])];
 
         // create arg array which is emitter + everything passed in except
         // signal name. Would be more convenient not to pass emitter to
@@ -121,8 +96,7 @@ export class EventEmitter {
         // which would be a cycle.
         let argArray = [this, ...args];
 
-        length = handlers.length;
-        for (i = 0; i < length; ++i) {
+        for (let i = 0; i < handlers.length; ++i) {
             let connection = handlers[i];
             if (!connection.disconnected) {
                 try {
@@ -142,12 +116,3 @@ export class EventEmitter {
         }
     }
 }
-
-export function addSignalMethods(proto) {
-    _addSignalMethod(proto, 'connect', _connect);
-    _addSignalMethod(proto, 'disconnect', _disconnect);
-    _addSignalMethod(proto, 'emit', _emit);
-    _addSignalMethod(proto, 'signalHandlerIsConnected', _signalHandlerIsConnected);
-    // this one is not in GObject, but useful
-    _addSignalMethod(proto, 'disconnectAll', _disconnectAll);
-}
diff --git a/modules/script/_bootstrap/default.js b/modules/script/_bootstrap/default.js
index eb042d49..e0c1090c 100644
--- a/modules/script/_bootstrap/default.js
+++ b/modules/script/_bootstrap/default.js
@@ -4,8 +4,21 @@
     'use strict';
 
     const {print, printerr, log, logError} = imports._print;
+    const {TextDecoder, TextEncoder} = imports._text;
 
     Object.defineProperties(exports, {
+        TextDecoder: {
+            configurable: false,
+            enumerable: true,
+            writable: false,
+            value: TextDecoder,
+        },
+        TextEncoder: {
+            configurable: false,
+            enumerable: true,
+            writable: false,
+            value: TextEncoder,
+        },
         print: {
             configurable: false,
             enumerable: true,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]