Skip to content

Instantly share code, notes, and snippets.

@Noitidart
Last active August 29, 2015 14:16
Show Gist options
  • Save Noitidart/dbe54fcd7794c8ddff6f to your computer and use it in GitHub Desktop.
Save Noitidart/dbe54fcd7794c8ddff6f to your computer and use it in GitHub Desktop.
_ff-addon-snippet-GDK_GioLaunch - Uses Gio to launch a .desktop file. [jsctypes] [gdk]
Cu.import('resource://gre/modules/ctypes.jsm');
var gio = ctypes.open('libgio-2.0.so.0');
// BASIC TYPES
var TYPES = {
gchar: ctypes.char,
gint: ctypes.int,
GAppInfo: ctypes.StructType('GAppInfo'),
GAppLaunchContext: ctypes.StructType('GAppLaunchContext'),
GDesktopAppInfo: ctypes.StructType('GDesktopAppInfo'),
GList: new ctypes.StructType('GList', [
{'data': ctypes.voidptr_t},
{'next': ctypes.voidptr_t},
{'prev': ctypes.voidptr_t}
]),
GQuark: ctypes.uint32_t
};
// ADVANCED TYPES
TYPES.gboolean = TYPES.gint;
TYPES.GError = new ctypes.StructType('GError', [
{'domain': TYPES.GQuark},
{'code': ctypes.int},
{'message': ctypes.char.ptr}
]);
// FUNCTIONS
/* https://developer.gnome.org/gio/unstable/gio-Desktop-file-based-GAppInfo.html#g-desktop-app-info-new-from-filename
* GDesktopAppInfo * g_desktop_app_info_new_from_filename(
* const char *filename
* );
*/
var new_from_filename = gio.declare('g_desktop_app_info_new_from_filename', ctypes.default_abi,
TYPES.GDesktopAppInfo.ptr, // return
TYPES.gchar.ptr // *filename
);
/* https://developer.gnome.org/gio/unstable/GAppInfo.html#g-app-info-launch-uris
* gboolean g_app_info_launch_uris (
* GAppInfo *appinfo,
* GList *uris,
* GAppLaunchContext *launch_context,
* GError **error
* );
*/
var launch_uris = gio.declare('g_app_info_launch_uris', ctypes.default_abi,
TYPES.gboolean, // return
TYPES.GAppInfo.ptr, // *appinfo
TYPES.GList.ptr, // *uris
TYPES.GAppLaunchContext.ptr, // *launch_context
TYPES.GError.ptr.ptr // **error
);
// start - helper functions
// end - helper functions
var shutdown = function() {
gio.close();
console.log('succesfully shutdown');
}
function main() {
var jsStr_pathToDesktopFile = OS.Path.join(OS.Constants.Path.desktopDir, 'Firefox - Profile Manager.desktop');
var launcher = new_from_filename(OS.Path.join(OS.Constants.Path.desktopDir, jsStr_pathToDesktopFile));
console.info('launcher:', launcher, launcher.toString(), uneval(launcher));
if (launcher.isNull()) {
throw new Error('No file exists at path: "' + jsStr_pathToDesktopFile + '"');
}
launcher = ctypes.cast(launcher, TYPES.GAppInfo.ptr);
var uris = new TYPES.GList(); // can use `null`
var launch_context = null; // have to use null due o this explanation here: // cannot use `var launch_context = new TYPES.GAppLaunchContext();` //throws `Error: cannot construct an opaque StructType` so i have to get launch_context from something like `gdk_display_get_app_launch_context` because i dont know he structure to it, and i obviously cannto create opaque structures
var error = new TYPES.GError.ptr(); // can use `null`
var rez_launch_uris = launch_uris(launcher, uris.address(), launch_context/*launch_context.address()*/, error.address());
console.info('rez_launch_uris:', rez_launch_uris, rez_launch_uris.toString(), uneval(rez_launch_uris));
console.info('error:', error, error.toString(), uneval(error));
}
try {
main();
} catch (ex) {
console.error('Error Occured:', ex);
} finally {
shutdown();
}
@Noitidart
Copy link
Author

Before I finished the code above I was worried that it wouldn't launch with the icon applied to the .desktop so I started work on this, it's not working code, but the same fixes made above if applied to here it should work. It features gdk_app_launch_context_set_icon_name which allows to launch with a custom icon it seems from the documentation:

Cu.import('resource://gre/modules/ctypes.jsm');

var gio = ctypes.open('libgio-2.0.so.0');
var gdk = ctypes.open('libgdk-x11-2.0.so.0');

// BASIC TYPES
var TYPES = {
    gchar: ctypes.char,
    gint: ctypes.int,
    GAppInfo: ctypes.voidptr_t, //ctypes.StructType('GAppInfo'),
    GAppLaunchContext: ctypes.voidptr_t, //ctypes.StructType('GAppLaunchContext'),
    GDesktopAppInfo: ctypes.voidptr_t, //ctypes.StructType('GDesktopAppInfo'),
    //GError: ctypes.voidptr_t, //ctypes.StructType('GError'),

    GError: new ctypes.StructType('GError', [
        {'domain': ctypes.int32_t},
        {'code': ctypes.int32_t},
        {'message': ctypes.char.ptr}
    ]),

    //GList: ctypes.voidptr_t, //ctypes.StructType('GList')

    GList: new ctypes.StructType('GList', [
        {'data': ctypes.voidptr_t},
        {'next': ctypes.voidptr_t},
        {'prev': ctypes.voidptr_t}
    ]),

  GdkDisplay: ctypes.StructType('GdkDisplay'),
    GdkAppLaunchContext: ctypes.voidptr_t

};

// ADVANCED TYPES
TYPES.gboolean = TYPES.gint;

// CONSTANTS
var CONSTS = {
    None: 0
};

// FUNCTIONS
/* https://developer.gnome.org/gio/unstable/gio-Desktop-file-based-GAppInfo.html#g-desktop-app-info-new-from-filename
 * GDesktopAppInfo * g_desktop_app_info_new_from_filename(
 *   const char *filename
 * );
 */
var g_desktop_app_info_new_from_filename = gio.declare('g_desktop_app_info_new_from_filename', ctypes.default_abi,
    TYPES.GDesktopAppInfo,  // return
    TYPES.gchar.ptr         // *filename
);

/* https://developer.gnome.org/gio/unstable/GAppInfo.html#g-app-info-launch-uris
 * gboolean g_app_info_launch_uris (
 *   GAppInfo *appinfo,
 *   GList *uris,
 *   GAppLaunchContext *launch_context,
 *   GError **error
 * );
 */
var g_app_info_launch_uris = gio.declare('g_app_info_launch_uris', ctypes.default_abi,
    TYPES.gboolean,                 // return
    TYPES.GAppInfo.ptr,             // *appinfo
    TYPES.GList.ptr,                // *uris
    TYPES.GAppLaunchContext.ptr,    // *launch_context
    TYPES.GError.ptr.ptr            // **error
);

/* https://developer.gnome.org/gdk3/stable/GdkDisplay.html#gdk-display-get-default
 * GdkDisplay * gdk_display_get_default (
 *   void
 * );
 */
var gdk_display_get_default = gdk.declare('gdk_display_get_default', ctypes.default_abi,
    TYPES.GdkDisplay.ptr                // return
);

/* https://developer.gnome.org/gdk3/stable/gdk3-Application-launching.html#gdk-app-launch-context-set-icon-name
 * void gdk_app_launch_context_set_icon_name (
 *   GdkAppLaunchContext *context
 *   const char *icon_name
 * );
 */
var gdk_app_launch_context_set_icon_name = gdk.declare('gdk_app_launch_context_set_icon_name', ctypes.default_abi,
    TYPES.voi,                                          // return
    TYPES.GdkAppLaunchContext.ptr,  // *context
    TYPES.char.ptr                                  // *icon_name
);

/* https://developer.gnome.org/gdk3/stable/GdkDisplay.html#gdk-display-get-app-launch-context
 * GdkAppLaunchContext * gdk_display_get_app_launch_context (
 *   GdkDisplay *display
 * );
 */
var gdk_display_get_app_launch_context = gdk.declare('gdk_display_get_app_launch_context', ctypes.default_abi,
    TYPES.GdkAppLaunchContext.ptr,  // return
    TYPES.GdkDisplay.ptr                        // *display
);

// start - helper functions

// end - helper functions

var shutdown = function() {

    gio.close();
    gdk.close();
    console.log('succesfully shutdown');
}

function main() {

    var display = ;
    var launch_context = 

    var jsStr_pathToDesktopFile = OS.Path.join(OS.Constants.Path.desktopDir, 'Firefox - Profile Manager.desktop');
    var launcher = g_desktop_app_info_new_from_filename(OS.Path.join(OS.Constants.Path.desktopDir, jsStr_pathToDesktopFile));
    console.info('launcher:', launcher, launcher.toString(), uneval(launcher));

    if (launcher.isNull()) {
        throw new Error('No file exists at path: "' + jsStr_pathToDesktopFile + '"');
    }

    var uris = new TYPES.GList(ctypes.voidptr_t(0), ctypes.voidptr_t(0), ctypes.voidptr_t(0));
    //var launch_context = ctypes.cast(ctypes.uint64_t(0x0), TYPES.GAppLaunchContext);
    var error = new TYPES.GError.ptr();
    var rez_launch_uris = g_app_info_launch_uris(launcher.address(), uris.address(), launch_context.address(), error.address());
    console.info('rez_launch_uris:', rez_launch_uris, rez_launch_uris.toString(), uneval(rez_launch_uris));
    console.info('error:', error, error.toString(), uneval(error));
}

try {
    main();
} catch (ex) {
    console.error('Error Occured:', ex);
} finally {
    shutdown();
}

@Noitidart
Copy link
Author

Basis for this code was Nautlius, excerpt below and direct link here: https://github.com/mathitme/nautilus/blob/2944be953ef54717bb24968b0eebe468c9705db4/libnautilus-private/nautilus-program-choosing.c#L153

    if (parent_window != NULL) {
        display = gtk_widget_get_display (GTK_WIDGET (parent_window));
    } else {
        display = gdk_display_get_default ();
    }

    launch_context = gdk_display_get_app_launch_context (display);

    if (parent_window != NULL) {
        gdk_app_launch_context_set_screen (launch_context,
                           gtk_window_get_screen (parent_window));
    }

    file = nautilus_file_get_by_uri (uris->data);
    icon = nautilus_file_get_icon (file, 48, 0);
    nautilus_file_unref (file);
    if (icon) {
        gdk_app_launch_context_set_icon_name (launch_context,
                            nautilus_icon_info_get_used_name (icon));
        g_object_unref (icon);
    }

    error = NULL;

    if (count == total) {
        /* All files are local, so we can use g_app_info_launch () with
         * the file list we constructed before.
         */
        result = g_app_info_launch (application,
                        locations,
                        G_APP_LAUNCH_CONTEXT (launch_context),
                        &error);
    } else {
        /* Some files are non local, better use g_app_info_launch_uris ().
         */
        result = g_app_info_launch_uris (application,
                         uris,
                         G_APP_LAUNCH_CONTEXT (launch_context),
                         &error);
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment