Git Product home page Git Product logo

node-gir's Introduction

Abandoned

I currently don't have enough time to properly develop this library. If you're keen to contribute in this space have a look at: https://github.com/romgrk/node-gtk

node-gir

CircleCI npm npm

Node-gir is Node.js bindings to GObject Introspection making it possible to make automatic and dynamic calls to any library that has GI annotations installed. This includes most libraries from the GNOME project.

This will make it possible to script a GNOME desktop system entirely from node much in the way it's done today with Seed, GJS or pygtk. It also allows using GNOME libraries in Node.js applications. With it you can also write the performance-intensive parts of your applications in Vala and call them from Node.js and other languages.

Installation

You need GObject Introspection library to be installed. On a Debian-like system this would be handled by:

$ sudo apt-get install libgirepository1.0-dev

On an arch based system:

$ sudo pacman -S gobject-introspection

On macOS:

$ brew install gobject-introspection

Then just install node-gir with:

$ npm install node-gir

Running tests

The tests load the gtk3 library to use as a testing target. On a Debian-like system it's likely you already have gtk3 installed, if not, it can be installed using:

$ sudo apt-get install libgtk-3-dev

Or on macOS:

$ brew install gtk+3

You can then run the tests with the following:

$ npm test

Linting code

ClangFormat is used for linting the C/C++ code. On a Debian-like system you can install it by running the following:

$ sudo apt-get install clang-format

You can then run the linter with the following:

$ npm run lint

Things which work

  • Bindings for classes are generated
  • Classes support inheritance
  • Interface methods are inherited
  • C structures are propagated as objects (fields are properties)
    • This is likely to be re-implemented though as it's very buggy currently
  • Both methods and static method can be called
  • functions can be called
    • out arguments are currently buggy.
  • GError is propagated as generic exception
  • Properties can be set/get
  • Support for signals using .connect('signal', callback)
  • Support for glib main loop.
    • the Node eventloop will be nested in the glib loop
    • we need to write documentation to detailing how this works

Things which dont work (correct)

  • Conversion between a v8 value and a GValue/GArgument is veeeery buggy (but everything needs it so most things are buggy)
  • There is no good way to delete an object (memory management sucks at all)
  • GError should be propagated as derived classes depending on GError domain
  • Structs and boxed types are still being implemented

node-gir's People

Contributors

ackalker avatar backwards-rat-race avatar benwaffle avatar bergie avatar cedlemo avatar clayrisser avatar creationix avatar daball avatar ewnd9 avatar jasperla avatar jonnor avatar piotras avatar place1 avatar swick avatar trevorlinton avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-gir's Issues

Why is cmake-js a dev dependency?

In the package.json file cmake-js is a dependency, but grepping the codebase reveals that cmake is not used anywhere and all build related commands use node-gyp.

Why is cmake.js a dependency? Couldn't it be removed?

C linting doesn’t work correctly

So, when I run npm run lint it fails. However when I copy/paste the clang-format command manually, it works. Is anyone else experiencing this same issue. Also, it seems C linting has not been run in ages, because it changes large portions of the code.

Support editorconfig

It would also be nice if we had an editorconfig spec. Most text editors comply with editorconfig. This will help prevent issues like tabs and 4 spaces bleeding into the code.

http://editorconfig.org/

Segmentation fault when tried to load Gio lib

Here is the code that crash:

const { load, Gtk } = require('../');
const Gio = load('Gio');

I have the following error:

3500 segmentation fault (core dumped)  node hello_world.js

Connecting a notify::property-name signal segfaults

Calling connect with a signal that starts with "notify::" causes Node to segfault.

Here is a case that reproduces on my machine (uncomment the commented line to see the segfault):

const Gtk = require('node-gir').Gtk
const Gdk = require('node-gir').load('Gdk', '3.0')

const win = new Gtk.Window({
  type: Gtk.WindowType.TOPLEVEL,
  title: 'Signal Crash',
})

// Not sure if this is necessary on the window or button;
// have added it to both.
win.addEvents(Gdk.EventMask.PROPERTY_CHANGE_MASK)
win.connect('destroy', () => Gtk.mainQuit())

const button = new Gtk.ColorButton()
button.addEvents(Gdk.EventMask.PROPERTY_CHANGE_MASK)
win.add(button)

button.connect('color-set', () => console.log(button.rgba.toString()))
// button.connect('notify::color', () => console.log(button.rgba.toString()))

win.showAll()
Gtk.main()

I tried digging into why this is happening with no luck (though to be frank I know little to nothing about GTK).

Working off 9668a34.

Eslint

As stated in issue #17, eslint should be added. I nominate using the Airbnb style guide. The code already seems to follow it closely. Any thoughts?

Support callback arguments in bindings

Hi, trying to use keybinder

'use strict';

const { load } = require('node-gir');
const gtk = load('Gtk', '3.0');
const keybinder = load('Keybinder', '3.0');

gtk.init(0);
keybinder.init(0);

const res = keybinder.bind('<Super>A', function() {
  console.log('hello');
}, null);
console.log(res);

gtk.main();

throws Error: Unsupported GI Type: argument type "interface" is unsupported.

Corresponding gjs script which works

const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Keybinder = imports.gi.Keybinder;

// https://github.com/rockon999/emoji-keyboard-gjs/blob/master/src/main.js
const Keyboard = new Lang.Class({
  Name: 'ek_EmojiKeyboard',
  Extends: Gtk.ApplicationWindow,
  _init: function (params) {
    this.parent(params);
    Keybinder.init();
    Keybinder.bind('<Super>A', Lang.bind(this, this._keybinding), null);
  },
  _keybinding: function () {
    print('<Super>A click');
  },
});

const Application = new Lang.Class({
  Name: 'EmojiKeyboard',
  Extends: Gtk.Application,
  vfunc_activate: function () {
    this.keyboard = new Keyboard({ application: this });
  }
});

new Application().run(ARGV);

I'm on Ubuntu 16.04 / node@8. Let me know if I missed something that could help.

Unix specific function

Does anyone know why he following Unix specific function was added to the loop initialization in loop.cpp on line 80? I couldn’t figure it out. I’m assuming fd means file descriptor. It seems to me this will make node-gir incompatible with Windows.

https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-source-add-unix-fd

g_source_add_unix_fd(&source->source, uv_backend_fd(loop), (GIOCondition)(G_IO_IN | G_IO_OUT | G_IO_ERR));

It appears it was originally added by Jasper St. Pierre

https://github.com/GNOME/gnode/blob/master/src/loop.cc

refactor use of FunctionCallbackInfo.Callee()

The FunctionCallbackInfo.Callee() that we use for implementing functions is deprecated and we should move await from it for good reason. Here's a link to a small discussion that outlines the reason it's being removed and an alternative.

I'm planning to do a big refactor of function.cc's Func class in addition to moving away from the deprecated APIs. I'll open a MR and reference this issue when I start the refactor.

Options for binary distributions

Developers who wish to use node-gir via npm install node-gir must compile the native code locally with node-gyp. This happens automatically but is a pain if they don't have all the correct libraries/versions installed.

In this issue I'm hoping to find some ideas for creating/distributing binary builds of node-gir's native addon.

node-pre-gyp seems like a good starting point.

This will also have implications for react-native-gtk as users of that library may want to create binary distributions of both node-gir and gtk3.

Plans for custom npm module?

I’m wondering, with the major changes and improvements being made, should we publish this as a separate npm module. It seems to me it might be cumbersome waiting for node-gir to accept the changes.

How should bindings handle function argument type errors

When JS calls native functions but passes incorrect arguments how strict should the bindings be?

example:

const window = new Gtk.Window();
window.setTitle("hello"); // valid
window.setTitle(["hello"]); // invalid

Should the invalid arguments call result in:

  1. Do what GJS does and log a warning to stderr and then do nothing (pretend the function was never called).
  2. Throw a JS error with a message detailing what was expected and what was given.

I'm a fan of the strictness being enforced by option 2 but GJS is lenient in this regard by just logging an error and then not doing the native call.

Personally I think option 1 can lead to harder to solve bugs. While GJS does log a very small stack trace this is not the same as a real uncaught error from the engine itself. It will not trigger tooling around uncaught errors that a nodejs program might have such as process.on('uncaughtException', ...);, and if the program has noisy output if can become very difficult to see the tree from the forest. Clearly i'm biased towards option 2 but this is easy to change so i've created this issue incase someone has some good reasons I may have missed!

update README.md

We should probably do a big update on the README.md as much of it is not correct anymore.

  • we should also add the circleci build status: [![CircleCI](https://circleci.com/gh/Place1/node-gir/tree/master.svg?style=svg)](https://circleci.com/gh/Place1/node-gir/tree/master)

  • add a contributing and roadmap section

  • setup guide for local developers

  • how to run tests

opinions of using a Proxy for importing libs

The GJS GI implementation allows users to access GI libraries like the following:

const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;

Similarly, in Python GI libraries are imported using:

from gi.repository import GObject;
from gi.repository import Gtk;

In NodeJS we could achieve something similar using an ES6 Proxy object.

module.exports = new Proxy({}, {
  get: function(target, property, receiver) {
    return load(property);
});

this would allow users to import GI libraries in NodeJS using the following:

# common JS
const { GObject, Gtk } = require('node-gir');

# es6 import
import { GObject, Gtk } from 'node-gir';

and obviously we'd still allow users to require the load() function that node-gir currently exports so that they can import specific versions of GI libraries.

Using a Proxy would mean the library would have a minimum NodeJS version of 6.4 (when Proxy was introduced to node). I think this is acceptable as the previous LTS, version 4, is very old now and 6 is the following LTS version. It is likely that node-gir won't work on node versions before 6 anyway due to v8 API breakages. CI currently tests against version 6,8,9.

Thoughts

Ignore common editors

Files from common editors should be ignored so they don't accidentally bleed into the project.

What does "typelib not found" mean?

I wanted to try out the examples/browser.js demo in order to find out whether node-gir is a viable alternative for using webkit2gtk (or similar) libraries that are already installed on the system.

But I only get the message Error: Typelib file for namespace 'WebKit', version '3.0' not found.

What does this message mean, and where does node-gir look for files or libraries?
How can I make this work? The GTK demo and others work fine.

OS: Arch Linux / x64, all up-to-date, and all libraries come with headers preinstalled by default.

State of node-gir

Hey! I'm the maintainer of https://github.com/romgrk/node-gtk (I've recently taken over the npm node-gtk package, which was originally owned by WebReflection/node-gtk).
So I stumbled upon this fork of node-gir and I was wondering, what is the state of this? I've been suprised by the number of node<->Gtk bindings package on NPM, and I'm wondering if there isn't a way to focus our efforts into bringing high-quality bindings by combining our efforts. Let me know what you think.

double-precision properties fail to hold value through PropertySetter and PropertyGetter

Related test case:

expect(win.opacity).toEqual(0.33);

output:

expect(received).toEqual(expected)
    Expected value to equal:
      0.33
    Received:
      0.32941176470588235

It would be interesting to get some more eyes on this issue. I've been using GDB to inspect the values in various places.

I found that in the PropertySetter the value was 0.33000000000000002 i.e. calling value->NumberValue() gave that number. This means that V8 is converting the 0.33 from the test-case's source code into 0.33000000000000002 as a c++ double.

After the GIRValue::ToGValue() calling g_value_get_double(&gvalue) returned the same 0.33000000000000002 value; this is good, at least our V8 -> GValue conversion is working as expected!

I believe the problem is in the PropertyGetter. After the call to g_object_get_property() a call to g_value_get_dobule(&gvalue) gives the value of 0.32941176470588235; this is the same number that the test case shows so we know that the GValue -> V8 conversion is working as well!

So, Is there a problem with precision or handling of V8 numbers, or does the window.opacity property do something funny under-the-hood in GTK land? I'm suspecting the latter is the case after my debugging session, but I don't want to change the test-case until we're sure! This is weird behaviour and we need to make sure it's not a bug with our bindings. If it's a bug with GTK, then that also sucks but at least we can push the work up-stream :D

What is the workflow to test node-gir

Hi,

I wanted to test node-gir but I am not really used to npm usage. I forked the repo, cd in it and when I tried to install it I had:

npm install node-gir                                                                                                                                                              JavaScript/node-gir  master
npm ERR! code ENOSELF
npm ERR! Refusing to install package with name "node-gir" under a package
npm ERR! also called "node-gir". Did you name your project the same
npm ERR! as the dependency you're installing?
npm ERR! 
npm ERR! For more information, see:
npm ERR!     <https://docs.npmjs.com/cli/install#limitations-of-npms-install-algorithm>

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/cedlemo/.npm/_logs/2018-02-12T11_37_24_129Z-debug.log

So it looks like I should run the install outside of the local clone but the problem is that I get the node-gir that you published (I guess). How can I, for example, test the local code that I modified/ created ?

Core dump when error is thrown from signal handler

/*
 * gir-throw.js
 */

const gi = require('node-gir')
const Gtk = gi.Gtk

  // main program window
const window = new Gtk.Window({
  type : Gtk.WindowType.TOPLEVEL
})

const urlBar = new Gtk.Entry()
urlBar.connect('key-press-event', (...args) => {
  throw new Error('test')
})

window.setDefaultSize(100, 30)
window.connect('show', () => {
  Gtk.main()
})
window.connect('destroy', () => Gtk.mainQuit())
window.connect('delete-event', () => false)
window.add(urlBar)
window.showAll()

See romgrk/node-gtk#45

Signal callback parameter support

Currently you can connect signals using instance.connect('signal-name', () => console.log('some callback')) but there is no support for converting the original native signal parameters to JS values.

An example test case has been written to outline this:

test('a signal that passes parameters to it\'s callback should work', (done) => {

In types/object.cc there's a Connect method that will be added to the object's prototype (so that JS can call instance.connect()), This function will create a GIRSignalClosure and then connect it to the signal. The signal closure's job is to marshal the native signal callback into the JS callback it wraps. The signal_closure.cpp file outlines this marshalling.

Currently i'm using the GI information about the signal to loop over the expected native parameters to create a list of Local objects (JS values) that will then be passed to the JS callback when it gets invoked.

I'm converting the native values to JS values using GIRValue::FromGValue() but its implementation has a few issues

I could use some help on this issue :D

GIRClosure::find_signal_callable_info question

node-gir/src/closure.cpp

Lines 70 to 75 in 109efbd

GIRInfoUniquePtr GIRClosure::find_signal_callable_info(guint signal_id, char *signal_name) {
// given a signal ID we want to find the GICallableInfo metadata so that
// we can know the param types & return types when marshalling data between
// the native callback and the JS callback.
// Note: this can return nullptr when the signal doesn't have a registered
// GICallableInfo. This happens notably for `notify::<property>` signals.

Here, wouldn't it be better to just use the part before :: to find the signal name?
E.g. if passed notify::label, just look for the signal called notify?

memory safety and failure handling

The codebase currently does an extremely poor job in terms of memory safety and handling failure conditions. Given i'm not a great c++ developer i've been researching some best practices and approaches. Here's what i'm thinking of introducing to help move the codebase towards a better state in this regard.

cpp core guidelines suggests to use exceptions to signal a failure to perform a required task (i.e. function needs to exit exit early and signal a failure). So we want to use c++ exceptions.

How to: Design for Exception Safety also outlines some clear guidelines on how to write code that will be safe when using c++ exceptions.

A key change that will need to be introduced into the codebase (likely over time) will be how glib memory is managed.

example:

GIFunctionInfo *info = g_object_info_get_method(object_info, i);
do_something(info);
g_base_info_unref(info);

In this example do_something(info) might fail and we will leak memory because we never g_base_info_unref(info);. Following the microsoft guidelines linked above we should make use of RAII principles.

auto info = std::unique_ptr<GIFunctionInfo, void(*)(GIBaseInfo*)>(g_object_info_get_method(object_info, i), g_base_info_unref);
do_something(info.get());

The above uses std::unique_ptr to handle cleaning up of the glib memory using a custom deleter function (g_base_info_unref) when the pointer is deallocated. In the case of an exception the stack will unwind and the pointer will be destroyed, cleaning up the glib memory (yay no leaks).

I find the above a bit ugly and hard to read, despite being the best practice (presumably, i'm a newb). It does make a lot of sense though!

We could easily implement a few utilities such as g_base_info_unique_ptr() to hide some of the custom deleter boilerplate which could help readability.

I'd love to hear some alternative thoughts to this though. For reference gjs (also written in c++) uses a mix of error code values (retuning ints), enum return values (returning well known values), boolean return values, out argument values like void do_something(int *error_code); and generally all use goto within the function to handle resource cleanup if a failure flag has been set somewhere.

Cannot run the tests on Ubuntu 17.10

I cloned the latest master, then tried to npm install:

...
> node-gyp rebuild

Package glib-2.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `glib-2.0.pc'
to the PKG_CONFIG_PATH environment variable
No package 'glib-2.0' found
...

I had already installed the system dependencies:

sudo apt-get install build-essential
sudo apt-get install libgtk-3-dev
sudo apt-get install libgirepository1.0-dev

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.