[SOLVED] Re: List of installed applications from prefs.js
- From: Amy C <mathematical coffee gmail com>
- To: gnome-shell-list gnome org
- Subject: [SOLVED] Re: List of installed applications from prefs.js
- Date: Mon, 27 Aug 2012 11:04:50 +1000
(sorry if you get this email twice - the first time I sent I attached
a .js file so the mail got rejected, so I've changed the file
extension to .txt)
On 25 August 2012 01:24, Florian Müllner <fmuellner gnome org> wrote:
> On Fri, Aug 24, 2012 at 2:31 PM, Amy C <mathematical coffee gmail com> wrote:
>> So, how can I get a list of installed applications from a process
>> outside of the gnome-shell one (no access to Shell, etc)?
>
> Use the GnomeMenu-3.0 API - ShellAppSystem is a rather thin wrapper
> around that nowadays.
Hi all,
Thanks for pointing me to GnomeMenu and shell-app-system.c.
Based on these I managed to get a list of installed applications. I
attach a code sample I wrote to do so in case anyone wishes to use it.
(I changed the filename to .txt because the email got rejected the
first time - can't send .js as an attachment).
It is very basic, feel free to tweak as you need - it is basically a
very simple version of shell-app-system.c (with none of the search
features, just the ability to list all the applications). The code
snippet shows how to instantiate an object { app_desktop_id:
GMenuTree.Entry } and keep that in sync with the apps list.
The file can be run via ` ./gjs appsystem.js` and will print a list of
installed apps to your terminal. (if you don't want it to run just
comment out the `main();` at the very buttom of the file). ***USUAL
DISCLAIMER about not running a script file blindly; view the code
before running/don't run at all if you're concerned etc***
I am unsure of the etiquette concerning sending scripts around a
mailing list so I'll outline the main points here in case someone in
the future visits the archive and wants to know:
// import GMenu
const GMenu = imports.gi.GMenu;
// make a GMenu.Tree containing the applications menu tree structure
(Applictions -> {Accessories, Games, Graphics, ...} -> individual
application)
let appsTree = new GMenu.Tree({
menu_basename: 'applications.menu',
flags: GMenu.TreeFlags.INCLUDE_NODISPLAY
});
// you must do this on the tree before anything else, returns a
boolean whether it
// succeeded or not
appsTree.load_sync();
// if you want to connect to changes in this (user installs/removes a program)
appsTree.connect('changed', callback);
Then to get the actual apps as a flat list, you create a TreeIter on
appsTree and iterate through each item in it. If it is an entry, it is
an app - add it to the list. If it is a directory, recurse into it
until you extract the entries. This is the getNodes function in the
attached file.
let dir = appsTree.get_root_directory();
let iter = dir.iter();
// now just call iter.next() until it returns GMenu.TreeItemType.INVALID.
// use iter.get_entry() to get the entry or iter.get_directory() to
get the directory.
// iter.next() returns the type of the current entry (ENTRY, DIRECTORY, ...)
Hope that helps someone in the future, and thanks for the pointers
everyone! (Florian, Yaa101, Milan Bouchet-Valat).
const GMenu = imports.gi.GMenu;
/*******
* Code
* Example use. Getting a list of applications.
* The GMenu.Tree is 'applications.menu', and the top-level children of it
* are the application subclasses (like Accessories, Games, ...)
* The children of these are applications.
*
* This piece of code simply loads the apps menu into a GMenu.Tree object
* `appsTree`, and also populates an object `appsList` where the keys are the
* application's desktop id (e.g. gnome-terminal.desktop) and the entries are
* the GMenu.TreeEntry corresponding to the application.
*
* The code keeps `appsList` in sync with `appsTree` by monitoring changes
* in `appsTree` and mirroring them to `appsList`.
*
* NOTE: shell-app-system.c has much more - for example, it deals with vendor
* prefixes on desktop ids (e.g. gnome-xxx.desktop, fedora-yyy.desktop) and lets
* you search with these prefixes removed.
*******/
let appsTree = null,
appsList = {};
function main() {
// create a GMenu.Tree holding the applications menu.
// (If you want the GNOME controle centre, use 'gnomecc.menu': see
// /etc/xdg/menus)
// This copies off shell-app-system.c shell_app_system_init
appsTree = new GMenu.Tree({
menu_basename: 'applications.menu',
flags: GMenu.TreeFlags.INCLUDE_NODISPLAY
});
// monitor changes in the tree so we can update appsList (i.e. when this
// gets called the installed apps have changed)
appsTree.connect('changed', onTreeChanged);
// update appsList
onTreeChanged(appsTree);
// now, appsList should be always up to date with the current application
// list.
for (let appid in appsList) {
if (appsList.hasOwnProperty(appid)) {
print(appid);
}
}
}
// callback: for example here we update our appsList dictionary to remain in
// sync with the appsTree.
function onTreeChanged(tree) {
// first make sure that tree is appsTree (it should be, that's all we
// connected this function to...)
if (tree !== appsTree) {
throw new Error("`tree` is not the apps tree!");
}
// initialise appsTree
if (!appsTree.load_sync()) {
throw new Error("Failed to load apps...");
}
// new apps tree
let newApps = getTreeNodes(tree);
// look for apps in appsList that are not in newApps and remove them
for (let id in appsList) {
if (!appsList.hasOwnProperty(id)) {
continue;
}
if (!newApps[id]) {
delete appsList[id];
}
}
// add/update appsList from newApps
for (let id in newApps) {
if (!newApps.hasOwnProperty(id)) {
continue;
}
let entry = newApps[id];
// prefix = getPrefixForEntry(entry); // TODO <-- ??
if (appsList[id] !== entry) {
// add the entry to appsList
appsList[id] = entry;
}
}
}
/***************
* Helper functions.
*
* Note:
* GMenu.Tree --> load_sync() to init, get_root_directory().iter() to iterate.
* | Contains:
* |- GMenu.TreeDirectory --> use .iter() to iterate through
* | |- .iter() to iterate through
* | |- .get_menu_id()
* | |- .get_name()
* | |- and so on...
* |- GMenu.TreeEntry
* | |- .get_app_info()
* | |- .get_desktop_file_id()
* | |- and so on...
***************/
/* Get all nodes of a directory
* (shell-app-system.c: get_flattened_entires_recurse)
* @dir: a GMenu.TreeDirectory (example, .get_root_directory() of a GMenu.Tree)
*
* returns: an object with key `id` and value GMenu.TreeEntry, where the id
* is the entry's .get_desktop_file_id().
*/
function getNodes(dir) {
let entry,
nodeType,
entries,
returnDict = {}, // dictionary. id: entry.
iter = dir.iter();
// loop through the directory recursing down directories until we reach
// items.
while ((nodeType = iter.next()) !== GMenu.TreeItemType.INVALID) {
switch (nodeType) {
case GMenu.TreeItemType.ENTRY:
// add it to the return object, overwriting duplicates (if any)
entry = iter.get_entry();
print('adding entry: ' + entry.get_desktop_file_id());
returnDict[entry.get_desktop_file_id()] = entry;
break;
case GMenu.TreeItemType.DIRECTORY:
// recurse into the directory, adding these results to our own
// return object (any duplicates are overwritten):
entries = getNodes(iter.get_directory());
for (entry in entries) {
if (entries.hasOwnProperty(entry)) {
returnDict[entry] = entries[entry];
}
}
break;
default: // SEPARATOR, HEADER, ALIAS. skip for now.
break;
}
}
return returnDict;
}
/* get all nodes from a tree */
function getTreeNodes(tree) {
return getNodes(tree.get_root_directory());
}
/*****************************************************/
// run code sample
main();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]