GJS, communication with a C++ program

I was having a hard time interfacing my Gnome JS application with a little C++ class I made to communicate with the Linux kernel. This class can receive “enable” and “disable” and takes a callback function for signaling an event from kernel.

I tried for so long to make it a GObject so I can do a .typelib with GObject Introspection. It has never worked and anyway may force me to use C (still not sure if it is possible to embed C++ in there) and the inner Glib types so either downgrade the features and/or not being confident of their safety, without mentioning the ugliest code readability ever.

I found I could use D-Bus, but I thought it a bit overkill and exposing to make it a session/system-wide service as I only need to communicate with my GJS application.

So I resigned to just use stdin/stdout and am very happy about the code readability on the C++ side. But it is obviously not very ideal as I use strings as commands/signals in order to keep them explicit and that would be so clean to have my C++ class as a JS object just like GObject Introspection enables it.

So any idea in this topic ?

Can you show the code you used to launch the subprocess?

Sorry I mixed my general question with a specific issue I was having at the time. Since then I’ve edited my message to be more focused on the title, but some times before yours, which is a bit weird.

GObject-introspection only works for a C ABI; if you have C++ code you will need to wrap it into a GObject-based API, and then use that API to generate the introspection data.

An example is Xapian-GLib, a library I wrote a while ago; it takes the Xapian C++ API, writes GObject wrappers around it, and then provides introspection data.

1 Like

Note if you are willing to use the (unstable) mozjs API, you can also invoke the GJS context from C++ after defining some functions, which for certain uses may be simpler than using GObject.

#include <gjs/gjs.h>
#include <jsapi.h>
#include <iostream>

#define JS_MAIN "main.js"

static bool myfunc(JSContext* cx, unsigned argc, JS::Value* vp) {
  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  std::cout << "called myfunc with " << argc << " arguments" << std::endl;
  args.rval().setDouble(argc);
  return true;
}

static void init(GjsContext *gcx, void *data) {
  auto cx = static_cast<JSContext*>(gjs_context_get_native_context(gcx));
  auto obj = JS::RootedObject(cx, JS::CurrentGlobalOrNull(cx));
  JS_DefineFunction(cx, obj, "myfunc", myfunc, 0, 0);
  // ...define more functions here...
}

int main() {
  GjsContext *gcx = gjs_context_new();
  int status = 0;
  GError *error = nullptr;

  gjs_context_run_in_realm(gcx, init, nullptr);

  if (!gjs_context_eval_file(gcx, JS_MAIN, &status, &error)) {
    std::cerr << error->message << std::endl;
    g_error_free(error);
    return 1;
  }
  return status;
}

May I ask you to elaborate on how it works and what should be done on the GJS side ?

All that does is declare a function “myfunc” and the executes a file main.js. Then from the GJS side you can invoke it as myfunc(). I can’t give a full tutorial how to use mozjs, it may be difficult if you are not familiar with manually writing bindings to a GC language.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.