gnome-shell/js/misc/docInfo.js
Colin Walters 5d067ec718 Better caching for document textures and information
Move thumbnail creation into ShellTextureCache.  It's now asynchronous,
and we cache the result.

Create a DocManager class which keeps around the DocInfo objects between
invocations.  This is also where we ensure we remove thumbnails for
recent items not known anymore.
2009-07-09 13:58:45 -04:00

157 lines
5.3 KiB
JavaScript

/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Shell = imports.gi.Shell;
const Lang = imports.lang;
const Signals = imports.signals;
const Main = imports.ui.main;
const THUMBNAIL_ICON_MARGIN = 2;
function DocInfo(recentInfo) {
this._init(recentInfo);
}
DocInfo.prototype = {
_init : function(recentInfo) {
this._recentInfo = recentInfo;
this.name = recentInfo.get_display_name();
this.uri = recentInfo.get_uri();
this.mimeType = recentInfo.get_mime_type();
},
createIcon : function(size) {
let icon = null;
let defaultPixbuf = this._recentInfo.get_icon(size);
if (this.uri.match("^file://")) {
icon = Shell.TextureCache.get_default().load_thumbnail(size, this.uri, this.mimeType,
defaultPixbuf);
}
if (!icon) {
icon = new Clutter.Texture({});
Shell.clutter_texture_set_from_pixbuf(icon, defaultPixbuf);
}
return icon;
},
launch : function() {
// While using Gio.app_info_launch_default_for_uri() would be
// shorter in terms of lines of code, we are not doing so
// because that would duplicate the work of retrieving the
// mime type.
let appInfo = Gio.app_info_get_default_for_type(this.mimeType, true);
if (appInfo != null) {
appInfo.launch_uris([this.uri], Main.createAppLaunchContext());
} else {
log("Failed to get default application info for mime type " + mimeType +
". Will try to use the last application that registered the document.");
let appName = this._recentInfo.last_application();
let [success, appExec, count, time] = this._recentInfo.get_application_info(appName);
if (success) {
log("Will open a document with the following command: " + appExec);
// TODO: Change this once better support for creating
// GAppInfo is added to GtkRecentInfo, as right now
// this relies on the fact that the file uri is
// already a part of appExec, so we don't supply any
// files to appInfo.launch().
// The 'command line' passed to
// create_from_command_line is allowed to contain
// '%<something>' macros that are expanded to file
// name / icon name, etc, so we need to escape % as %%
appExec = appExec.replace(/%/g, "%%");
let appInfo = Gio.app_info_create_from_commandline(appExec, null, 0, null);
// The point of passing an app launch context to
// launch() is mostly to get startup notification and
// associated benefits like the app appearing on the
// right desktop; but it doesn't really work for now
// because with the way we create the appInfo we
// aren't reading the application's desktop file, and
// thus don't find the StartupNotify=true in it. So,
// despite passing the app launch context, no startup
// notification occurs.
appInfo.launch([], Main.createAppLaunchContext());
} else {
log("Failed to get application info for " + this.uri);
}
}
},
exists : function() {
return this._recentInfo.exists();
},
lastVisited : function() {
// We actually used get_modified() instead of get_visited()
// here, as GtkRecentInfo doesn't updated get_visited()
// correctly. See
// http://bugzilla.gnome.org/show_bug.cgi?id=567094
return this._recentInfo.get_modified();
}
};
var docManagerInstance = null;
function getDocManager(size) {
if (docManagerInstance == null)
docManagerInstance = new DocManager(size);
return docManagerInstance;
}
function DocManager(size) {
this._init(size);
}
DocManager.prototype = {
_init: function(iconSize) {
this._iconSize = iconSize;
this._recentManager = Gtk.RecentManager.get_default();
this._items = {};
this._recentManager.connect('changed', Lang.bind(this, function(recentManager) {
this._reload();
this.emit('changed');
}));
this._reload();
},
_reload: function() {
let docs = this._recentManager.get_items();
let newItems = {};
for (let i = 0; i < docs.length; i++) {
let recentInfo = docs[i];
let docInfo = new DocInfo(recentInfo);
// we use GtkRecentInfo URI as an item Id
newItems[docInfo.uri] = docInfo;
}
let deleted = {};
for (var uri in this._items) {
if (!(uri in newItems))
deleted[uri] = 1;
}
/* If we'd cached any thumbnail references that no longer exist,
dump them here */
let texCache = Shell.TextureCache.get_default();
for (var uri in deleted) {
texCache.unref_thumbnail(this._iconSize, uri);
}
this._items = newItems;
},
getItems: function() {
return this._items;
}
}
Signals.addSignalMethods(DocManager.prototype);