diff --git a/src/modules/commons.js b/src/modules/commons.js index e9b08b8..6f6a890 100644 --- a/src/modules/commons.js +++ b/src/modules/commons.js @@ -174,7 +174,6 @@ firetray.Utils = { tryCloseLibs: function(libs) { try { libs.forEach(function(lib) { - LOG("try closing "+lib.name); if (lib.available()) lib.close(); }); @@ -183,6 +182,8 @@ firetray.Utils = { }; +////////////////////////// more fundamental helpers ////////////////////////// + // http://stackoverflow.com/questions/767486/how-do-you-check-if-a-variable-is-an-array-in-javascript function isArray(o) { return getType(o) === '[object Array]'; diff --git a/src/modules/ctypes/cairo.jsm b/src/modules/ctypes/cairo.jsm index dee2069..7a3bccc 100644 --- a/src/modules/ctypes/cairo.jsm +++ b/src/modules/ctypes/cairo.jsm @@ -23,6 +23,4 @@ function cairo_defines(lib) { } -if (!cairo) { - var cairo = new ctypes_library(CAIRO_LIBNAME, CAIRO_ABIS, cairo_defines); -} +new ctypes_library(CAIRO_LIBNAME, CAIRO_ABIS, cairo_defines, this); diff --git a/src/modules/ctypes/ctypes-utils.jsm b/src/modules/ctypes/ctypes-utils.jsm index 7cf8f7f..b8ab0b8 100644 --- a/src/modules/ctypes/ctypes-utils.jsm +++ b/src/modules/ctypes/ctypes-utils.jsm @@ -44,12 +44,72 @@ Cu.import("resource://firetray/logging.jsm"); var EXPORTED_SYMBOLS = [ "ctypes_library" ]; -function ctypes_library(name, abis, defines) { +/** + * Loads a library using ctypes and exports an object on to the specified + * global object. The name of the exported object will be the first name + * specified in the global objects EXPORTED_SYMBOLS list. + * + * It is an error to call this function more than once in a JS module. This + * implies that you should have one JS module per ctypes library. + * + * In addition to native types and functions, the exported object will contain + * some additional utility functions: + * + * close Close the library and unload the JS module + * available Returns true if the library is available, false otherwise + * ABI A property containing the library ABI loaded (or -1 if unavailable) + * + * @param aName + * The name of the library to load, without the "lib" prefix or any + * file extension. + * + * @param aABIs + * An array of library ABI's to search for. The first one found will + * be loaded and the loaded ABI will be saved on the exported object. + * + * @param aDefines + * A function which will be called to load library symbols and create + * types. The function will be called with one parameter, which contains + * several functions for binding symbols. The "this" object will be + * the exported object, on to which you can should types and symbols. + * + * @param aGlobal + * The global object on to which we export an object. This must be a + * a valid JSM global object. + * + */ +function ctypes_library(aName, aABIs, aDefines, aGlobal) { try { - LOG("Loading library: " + name); + LOG("Trying to load library: " + aName); + + if (typeof(aName) != "string") { + throw Error("Invalid library name"); + } + + if (!aABIs || typeof(aABIs) != "object") { + throw Error("Invalid range of library ABI's"); + } + + if (typeof(aDefines) != "function") { + throw Error("Invalid defines function"); + } + + if (!aGlobal || typeof(aGlobal) != "object" || !aGlobal.EXPORTED_SYMBOLS || + typeof(aGlobal.EXPORTED_SYMBOLS) != "object") { + throw Error("Must specify a valid global object from a loaded JS module"); + } + + if (!("__URI__" in aGlobal) || !aGlobal.__URI__) { + throw Error("This JS module has already been unloaded"); + } + + if (aGlobal[aGlobal.EXPORTED_SYMBOLS[0]]) { + throw Error("Was ctypes_library() called more than once for this module?"); + } + var library; - for each (let abi in abis) { - let soname = "lib" + name + ".so." + abi.toString(); + for each (let abi in aABIs) { + let soname = "lib" + aName + ".so." + abi.toString(); LOG("Trying " + soname); try { library = ctypes.open(soname); @@ -61,11 +121,18 @@ function ctypes_library(name, abis, defines) { } } - this.name = name; - this.close = function() { + LOG("Closing library " + aName); library.close(); this.ABI = -1; + + if (!("__URI__" in aGlobal) || !aGlobal.__URI__) { + // We could have already been unloaded by now + return; + } + + LOG("Unloading JS module " + aGlobal.__URI__); + Cu.unload(aGlobal.__URI__); }; this.available = function() { @@ -73,7 +140,7 @@ function ctypes_library(name, abis, defines) { }; if (!library) { - LOG("Failed to load library: " + name); + LOG("Failed to load library: " + aName); this.ABI = -1; return; } @@ -91,7 +158,8 @@ function ctypes_library(name, abis, defines) { return library.declare.apply(library, args); } catch (ex) { - ERROR("Missing symbol " + arguments[0] + " in library " + name); + Cu.reportError(ex); + ERROR("Missing symbol " + arguments[0] + " in library " + aName); self.ABI = -1; return null; } @@ -109,9 +177,12 @@ function ctypes_library(name, abis, defines) { } }; - defines.call(this, lib); + aDefines.call(this, lib); + + aGlobal[aGlobal.EXPORTED_SYMBOLS[0]] = this; } catch(e) { - ERROR(name+" definition error: "+e); + Cu.reportError(e); + ERROR(aName+" definition error: "+e); this.ABI = -1; } } diff --git a/src/modules/ctypes/gdk.jsm b/src/modules/ctypes/gdk.jsm index ebd8cef..940d9ba 100644 --- a/src/modules/ctypes/gdk.jsm +++ b/src/modules/ctypes/gdk.jsm @@ -235,6 +235,4 @@ function gdk_defines(lib) { } -if (!gdk) { - var gdk = new ctypes_library(GDK_LIBNAME, GDK_ABIS, gdk_defines); -} +new ctypes_library(GDK_LIBNAME, GDK_ABIS, gdk_defines, this); diff --git a/src/modules/ctypes/glib.jsm b/src/modules/ctypes/glib.jsm index 67b2c50..a411d4a 100644 --- a/src/modules/ctypes/glib.jsm +++ b/src/modules/ctypes/glib.jsm @@ -18,6 +18,4 @@ function glib_defines(lib) { this.GError = ctypes.StructType("GError"); }; -if (!glib) { - var glib = new ctypes_library(GLIB_LIBNAME, GLIB_ABIS, glib_defines); -} +new ctypes_library(GLIB_LIBNAME, GLIB_ABIS, glib_defines, this); diff --git a/src/modules/ctypes/gobject.jsm b/src/modules/ctypes/gobject.jsm index ac33fec..8d56d58 100644 --- a/src/modules/ctypes/gobject.jsm +++ b/src/modules/ctypes/gobject.jsm @@ -151,6 +151,4 @@ function gobject_defines(lib) { } -if (!gobject) { - var gobject = new ctypes_library(GOBJECT_LIBNAME, GOBJECT_ABIS, gobject_defines); -} +new ctypes_library(GOBJECT_LIBNAME, GOBJECT_ABIS, gobject_defines, this); diff --git a/src/modules/ctypes/gtk.jsm b/src/modules/ctypes/gtk.jsm index e64cceb..875aac0 100644 --- a/src/modules/ctypes/gtk.jsm +++ b/src/modules/ctypes/gtk.jsm @@ -112,6 +112,4 @@ function gtk_defines(lib) { } -if (!gtk) { - var gtk = new ctypes_library(GTK_LIBNAME, GTK_ABIS, gtk_defines); -} +new ctypes_library(GTK_LIBNAME, GTK_ABIS, gtk_defines, this); diff --git a/src/modules/ctypes/libc.jsm b/src/modules/ctypes/libc.jsm index 1f7315c..d3ae68a 100644 --- a/src/modules/ctypes/libc.jsm +++ b/src/modules/ctypes/libc.jsm @@ -25,6 +25,4 @@ function libc_defines(lib) { lib.lazy_bind("strcmp", ctypes.int, ctypes.char.ptr, ctypes.char.ptr); }; -if (!libc) { - var libc = new ctypes_library(LIBC_LIBNAME, LIBC_ABIS, libc_defines); -} +var libc = new ctypes_library(LIBC_LIBNAME, LIBC_ABIS, libc_defines, this); diff --git a/src/modules/ctypes/pango.jsm b/src/modules/ctypes/pango.jsm index da82217..0ed5622 100644 --- a/src/modules/ctypes/pango.jsm +++ b/src/modules/ctypes/pango.jsm @@ -4,8 +4,6 @@ var EXPORTED_SYMBOLS = [ "pango", "pangocairo" ]; const PANGO_LIBNAME = "pango-1.0"; const PANGO_ABIS = [ 0 ]; -const PANGOCAIRO_LIBNAME = "pangocairo-1.0"; -const PANGOCAIRO_ABIS = [ 0 ]; const Cu = Components.utils; const Cc = Components.classes; @@ -46,15 +44,4 @@ function pango_defines(lib) { } -if (!pango) { - var pango = new ctypes_library(PANGO_LIBNAME, PANGO_ABIS, pango_defines); -} - - -function pangocairo_defines(lib) { - lib.lazy_bind("pango_cairo_show_layout", ctypes.void_t, cairo.cairo_t.ptr, pango.PangoLayout.ptr); -} - -if (!pangocairo) { - var pangocairo = new ctypes_library(PANGOCAIRO_LIBNAME, PANGOCAIRO_ABIS, pangocairo_defines); -} +new ctypes_library(PANGO_LIBNAME, PANGO_ABIS, pango_defines, this); diff --git a/src/modules/ctypes/x11.jsm b/src/modules/ctypes/x11.jsm index 97c8a78..af41410 100644 --- a/src/modules/ctypes/x11.jsm +++ b/src/modules/ctypes/x11.jsm @@ -130,9 +130,7 @@ function x11_defines(lib) { } -if (!x11) { - var x11 = new ctypes_library(X11_LIBNAME, X11_ABIS, x11_defines); -} +new ctypes_library(X11_LIBNAME, X11_ABIS, x11_defines, this); /* Xorg 1.10.4 diff --git a/src/modules/gtk2/FiretrayStatusIcon.jsm b/src/modules/gtk2/FiretrayStatusIcon.jsm index 5dcbb1f..e798254 100644 --- a/src/modules/gtk2/FiretrayStatusIcon.jsm +++ b/src/modules/gtk2/FiretrayStatusIcon.jsm @@ -15,6 +15,7 @@ Cu.import("resource://firetray/ctypes/gdk.jsm"); Cu.import("resource://firetray/ctypes/gtk.jsm"); Cu.import("resource://firetray/ctypes/libc.jsm"); Cu.import("resource://firetray/ctypes/pango.jsm"); +Cu.import("resource://firetray/ctypes/pangocairo.jsm"); Cu.import("resource://firetray/commons.js"); if ("undefined" == typeof(firetray.Handler)) @@ -55,7 +56,7 @@ firetray.StatusIcon = { }, shutdown: function() { - firetray.Utils.tryCloseLibs([cairo, gobject, gdk, gtk, pango]); + firetray.Utils.tryCloseLibs([cairo, gobject, gdk, gtk, pango, pangocairo]); this.initialized = false; },