Merge branch 'master' into overlay-design02
This commit is contained in:
commit
2fd2293e4a
17
configure.ac
17
configure.ac
@ -40,7 +40,7 @@ fi
|
|||||||
|
|
||||||
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
||||||
|
|
||||||
PKG_CHECK_MODULES(MUTTER_PLUGIN, gtk+-2.0 dbus-glib-1 metacity-plugins gjs-gi-1.0 xscrnsaver libgnome-menu $recorder_modules gconf-2.0 gdk-x11-2.0 clutter-x11-0.9 clutter-glx-0.9)
|
PKG_CHECK_MODULES(MUTTER_PLUGIN, gtk+-2.0 dbus-glib-1 mutter-plugins gjs-gi-1.0 xscrnsaver libgnome-menu $recorder_modules gconf-2.0 gdk-x11-2.0 clutter-x11-0.9 clutter-glx-0.9)
|
||||||
PKG_CHECK_MODULES(TIDY, clutter-0.9)
|
PKG_CHECK_MODULES(TIDY, clutter-0.9)
|
||||||
PKG_CHECK_MODULES(BIG, clutter-0.9 gtk+-2.0 librsvg-2.0)
|
PKG_CHECK_MODULES(BIG, clutter-0.9 gtk+-2.0 librsvg-2.0)
|
||||||
PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-2.0)
|
PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-2.0)
|
||||||
@ -51,11 +51,13 @@ PKG_CHECK_MODULES(TASKPANEL, libwnck-1.0 dbus-glib-1)
|
|||||||
# it becomes stable.
|
# it becomes stable.
|
||||||
PKG_CHECK_MODULES(LIBGNOMEUI, libgnomeui-2.0)
|
PKG_CHECK_MODULES(LIBGNOMEUI, libgnomeui-2.0)
|
||||||
|
|
||||||
META_BIN_DIR=`$PKG_CONFIG --variable=exec_prefix metacity-plugins`/bin
|
MUTTER_BIN_DIR=`$PKG_CONFIG --variable=exec_prefix mutter-plugins`/bin
|
||||||
# FIXME: metacity-plugins.pc should point directly to its .gir file
|
# FIXME: metacity-plugins.pc should point directly to its .gir file
|
||||||
META_LIB_DIR=`$PKG_CONFIG --variable=libdir metacity-plugins`
|
MUTTER_LIB_DIR=`$PKG_CONFIG --variable=libdir mutter-plugins`
|
||||||
AC_SUBST(META_BIN_DIR)
|
MUTTER_PLUGIN_DIR=`$PKG_CONFIG --variable=plugindir mutter-plugins`
|
||||||
AC_SUBST(META_LIB_DIR)
|
AC_SUBST(MUTTER_BIN_DIR)
|
||||||
|
AC_SUBST(MUTTER_LIB_DIR)
|
||||||
|
AC_SUBST(MUTTER_PLUGIN_DIR)
|
||||||
|
|
||||||
GJS_JS_DIR=`$PKG_CONFIG --variable=jsdir gjs-1.0`
|
GJS_JS_DIR=`$PKG_CONFIG --variable=jsdir gjs-1.0`
|
||||||
GJS_JS_NATIVE_DIR=`$PKG_CONFIG --variable=jsnativedir gjs-1.0`
|
GJS_JS_NATIVE_DIR=`$PKG_CONFIG --variable=jsnativedir gjs-1.0`
|
||||||
@ -92,13 +94,14 @@ if test "x$GCC" = "xyes"; then
|
|||||||
fi
|
fi
|
||||||
changequote([,])dnl
|
changequote([,])dnl
|
||||||
|
|
||||||
AC_PATH_PROG(metacity, [metacity])
|
AC_PATH_PROG(mutter, [mutter])
|
||||||
AC_SUBST(metacity)
|
AC_SUBST(mutter)
|
||||||
|
|
||||||
AC_OUTPUT([
|
AC_OUTPUT([
|
||||||
Makefile
|
Makefile
|
||||||
data/Makefile
|
data/Makefile
|
||||||
js/Makefile
|
js/Makefile
|
||||||
|
js/misc/Makefile
|
||||||
js/ui/Makefile
|
js/ui/Makefile
|
||||||
src/Makefile
|
src/Makefile
|
||||||
])
|
])
|
||||||
|
@ -1 +1 @@
|
|||||||
SUBDIRS = ui
|
SUBDIRS = misc ui
|
||||||
|
5
js/misc/Makefile.am
Normal file
5
js/misc/Makefile.am
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
jsmiscdir = $(pkgdatadir)/js/misc
|
||||||
|
|
||||||
|
dist_jsmisc_DATA = \
|
||||||
|
appInfo.js \
|
||||||
|
docInfo.js
|
133
js/misc/appInfo.js
Normal file
133
js/misc/appInfo.js
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/* -*- 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 Main = imports.ui.main;
|
||||||
|
|
||||||
|
// TODO - move this into GConf once we're not a plugin anymore
|
||||||
|
// but have taken over metacity
|
||||||
|
// This list is taken from GNOME Online popular applications
|
||||||
|
// http://online.gnome.org/applications
|
||||||
|
// but with nautilus removed (since it should already be running)
|
||||||
|
// and evince, totem, and gnome-file-roller removed (since they're
|
||||||
|
// usually started by opening documents, not by opening the app
|
||||||
|
// directly)
|
||||||
|
const DEFAULT_APPLICATIONS = [
|
||||||
|
'mozilla-firefox.desktop',
|
||||||
|
'gnome-terminal.desktop',
|
||||||
|
'evolution.desktop',
|
||||||
|
'gedit.desktop',
|
||||||
|
'mozilla-thunderbird.desktop',
|
||||||
|
'rhythmbox.desktop',
|
||||||
|
'epiphany.desktop',
|
||||||
|
'xchat.desktop',
|
||||||
|
'openoffice.org-1.9-writer.desktop',
|
||||||
|
'emacs.desktop',
|
||||||
|
'gnome-system-monitor.desktop',
|
||||||
|
'openoffice.org-1.9-calc.desktop',
|
||||||
|
'eclipse.desktop',
|
||||||
|
'openoffice.org-1.9-impress.desktop',
|
||||||
|
'vncviewer.desktop'
|
||||||
|
];
|
||||||
|
|
||||||
|
function AppInfo(appId) {
|
||||||
|
this._init(appId);
|
||||||
|
}
|
||||||
|
|
||||||
|
AppInfo.prototype = {
|
||||||
|
_init : function(appId) {
|
||||||
|
this.appId = appId;
|
||||||
|
this._gAppInfo = Gio.DesktopAppInfo.new(appId);
|
||||||
|
if (!this._gAppInfo)
|
||||||
|
throw new Error('Unknown appId ' + appId);
|
||||||
|
|
||||||
|
this.name = this._gAppInfo.get_name();
|
||||||
|
this.description = this._gAppInfo.get_description();
|
||||||
|
|
||||||
|
this._gicon = this._gAppInfo.get_icon();
|
||||||
|
},
|
||||||
|
|
||||||
|
getIcon : function(size) {
|
||||||
|
if (this._gicon)
|
||||||
|
return Shell.TextureCache.get_default().load_gicon(this._gicon, size);
|
||||||
|
else
|
||||||
|
return new Clutter.Texture({ width: size, height: size });
|
||||||
|
},
|
||||||
|
|
||||||
|
getIconPath : function(size) {
|
||||||
|
if (this._gicon) {
|
||||||
|
let iconTheme = Gtk.IconTheme.get_default();
|
||||||
|
let previewIconInfo = iconTheme.lookup_by_gicon(this._gicon, size, 0);
|
||||||
|
if (previewIconInfo)
|
||||||
|
return previewIconInfo.get_filename();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
launch : function() {
|
||||||
|
this._gAppInfo.launch([], Main.createAppLaunchContext());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var _infos = {};
|
||||||
|
|
||||||
|
// getAppInfo:
|
||||||
|
// @appId: an appId
|
||||||
|
//
|
||||||
|
// Gets an #AppInfo for @appId. This is preferable to calling
|
||||||
|
// new AppInfo() directly, because it caches #AppInfos.
|
||||||
|
//
|
||||||
|
// Return value: the new or cached #AppInfo, or %null if @appId
|
||||||
|
// doesn't point to a valid .desktop file
|
||||||
|
function getAppInfo(appId) {
|
||||||
|
let info = _infos[appId];
|
||||||
|
if (info === undefined) {
|
||||||
|
try {
|
||||||
|
info = _infos[appId] = new AppInfo(appId);
|
||||||
|
} catch (e) {
|
||||||
|
info = _infos[appId] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
// getMostUsedApps:
|
||||||
|
// @count: maximum number of apps to retrieve
|
||||||
|
//
|
||||||
|
// Gets a list of #AppInfos for the @count most-frequently-used
|
||||||
|
// applications
|
||||||
|
//
|
||||||
|
// Return value: the list of #AppInfo
|
||||||
|
function getMostUsedApps(count) {
|
||||||
|
let appMonitor = new Shell.AppMonitor();
|
||||||
|
|
||||||
|
// Ask for more apps than we need, since the list of recently used
|
||||||
|
// apps might contain an app we don't have a desktop file for
|
||||||
|
let apps = appMonitor.get_most_used_apps (0, Math.round(count * 1.5));
|
||||||
|
let matches = [], alreadyAdded = {};
|
||||||
|
|
||||||
|
for (let i = 0; i < apps.length && matches.length <= count; i++) {
|
||||||
|
let appId = apps[i] + ".desktop";
|
||||||
|
let appInfo = getAppInfo(appId);
|
||||||
|
if (appInfo) {
|
||||||
|
matches.push(appInfo);
|
||||||
|
alreadyAdded[appId] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the list with default applications it's not full yet
|
||||||
|
for (let i = 0; i < DEFAULT_APPLICATIONS.length && matches.length <= count; i++) {
|
||||||
|
let appId = DEFAULT_APPLICATIONS[i];
|
||||||
|
if (alreadyAdded[appId])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
let appInfo = getAppInfo(appId);
|
||||||
|
if (appInfo)
|
||||||
|
matches.push(appInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches;
|
||||||
|
}
|
112
js/misc/docInfo.js
Normal file
112
js/misc/docInfo.js
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/* -*- 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 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();
|
||||||
|
|
||||||
|
this._iconPixbuf = Shell.get_thumbnail(this.uri, this.mimeType);
|
||||||
|
},
|
||||||
|
|
||||||
|
getIcon : function(size) {
|
||||||
|
let icon = new Clutter.Texture();
|
||||||
|
|
||||||
|
if (this._iconPixbuf) {
|
||||||
|
// We calculate the width and height of the texture so as
|
||||||
|
// to preserve the aspect ratio of the thumbnail. Because
|
||||||
|
// the images generated based on thumbnails don't have an
|
||||||
|
// internal padding like system icons do, we create a
|
||||||
|
// slightly smaller texture and then create a group around
|
||||||
|
// it for padding purposes
|
||||||
|
|
||||||
|
let scalingFactor = (size - THUMBNAIL_ICON_MARGIN * 2) / Math.max(this._iconPixbuf.get_width(), this._iconPixbuf.get_height());
|
||||||
|
icon.set_width(Math.ceil(this._iconPixbuf.get_width() * scalingFactor));
|
||||||
|
icon.set_height(Math.ceil(this._iconPixbuf.get_height() * scalingFactor));
|
||||||
|
Shell.clutter_texture_set_from_pixbuf(icon, this._iconPixbuf);
|
||||||
|
|
||||||
|
let group = new Clutter.Group({ width: size,
|
||||||
|
height: size });
|
||||||
|
group.add_actor(icon);
|
||||||
|
icon.set_position(THUMBNAIL_ICON_MARGIN, THUMBNAIL_ICON_MARGIN);
|
||||||
|
return group;
|
||||||
|
} else {
|
||||||
|
Shell.clutter_texture_set_from_pixbuf(icon, this._recentInfo.get_icon(size));
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
};
|
@ -9,8 +9,8 @@ const Shell = imports.gi.Shell;
|
|||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
|
|
||||||
|
const AppInfo = imports.misc.appInfo;
|
||||||
const GenericDisplay = imports.ui.genericDisplay;
|
const GenericDisplay = imports.ui.genericDisplay;
|
||||||
const Main = imports.ui.main;
|
|
||||||
|
|
||||||
const ENTERED_MENU_COLOR = new Clutter.Color();
|
const ENTERED_MENU_COLOR = new Clutter.Color();
|
||||||
ENTERED_MENU_COLOR.from_pixel(0x00ff0022);
|
ENTERED_MENU_COLOR.from_pixel(0x00ff0022);
|
||||||
@ -48,7 +48,7 @@ const MAX_ITEMS = 30;
|
|||||||
|
|
||||||
/* This class represents a single display item containing information about an application.
|
/* This class represents a single display item containing information about an application.
|
||||||
*
|
*
|
||||||
* appInfo - GAppInfo object containing information about the application
|
* appInfo - AppInfo object containing information about the application
|
||||||
* availableWidth - total width available for the item
|
* availableWidth - total width available for the item
|
||||||
*/
|
*/
|
||||||
function AppDisplayItem(appInfo, availableWidth) {
|
function AppDisplayItem(appInfo, availableWidth) {
|
||||||
@ -62,36 +62,15 @@ AppDisplayItem.prototype = {
|
|||||||
GenericDisplay.GenericDisplayItem.prototype._init.call(this, availableWidth);
|
GenericDisplay.GenericDisplayItem.prototype._init.call(this, availableWidth);
|
||||||
this._appInfo = appInfo;
|
this._appInfo = appInfo;
|
||||||
|
|
||||||
let name = appInfo.get_name();
|
this._setItemInfo(appInfo.name, appInfo.description,
|
||||||
|
appInfo.getIcon(GenericDisplay.ITEM_DISPLAY_ICON_SIZE));
|
||||||
let description = appInfo.get_description();
|
|
||||||
|
|
||||||
let iconTheme = Gtk.IconTheme.get_default();
|
|
||||||
|
|
||||||
let gicon = appInfo.get_icon();
|
|
||||||
let texCache = Shell.TextureCache.get_default();
|
|
||||||
let icon;
|
|
||||||
if (gicon == null)
|
|
||||||
icon = new Clutter.Texture({ width: GenericDisplay.ITEM_DISPLAY_ICON_SIZE,
|
|
||||||
height: GenericDisplay.ITEM_DISPLAY_ICON_SIZE
|
|
||||||
});
|
|
||||||
else
|
|
||||||
icon = texCache.load_gicon(gicon, GenericDisplay.ITEM_DISPLAY_ICON_SIZE);
|
|
||||||
this._setItemInfo(name, description, icon);
|
|
||||||
},
|
|
||||||
|
|
||||||
//// Public methods ////
|
|
||||||
|
|
||||||
// Returns the application info associated with this display item.
|
|
||||||
getAppInfo : function () {
|
|
||||||
return this._appInfo;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
//// Public method overrides ////
|
//// Public method overrides ////
|
||||||
|
|
||||||
// Opens an application represented by this display item.
|
// Opens an application represented by this display item.
|
||||||
launch : function() {
|
launch : function() {
|
||||||
this._appInfo.launch([], Main.createAppLaunchContext());
|
this._appInfo.launch();
|
||||||
},
|
},
|
||||||
|
|
||||||
//// Protected method overrides ////
|
//// Protected method overrides ////
|
||||||
@ -101,15 +80,7 @@ AppDisplayItem.prototype = {
|
|||||||
if (!this._showPreview || this._previewIcon)
|
if (!this._showPreview || this._previewIcon)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let previewIconPath = null;
|
let previewIconPath = this._appInfo.getIconPath(GenericDisplay.PREVIEW_ICON_SIZE);
|
||||||
|
|
||||||
if (this._gicon != null) {
|
|
||||||
let iconTheme = Gtk.IconTheme.get_default();
|
|
||||||
let previewIconInfo = iconTheme.lookup_by_gicon(this._gicon, GenericDisplay.PREVIEW_ICON_SIZE, Gtk.IconLookupFlags.NO_SVG);
|
|
||||||
if (previewIconInfo)
|
|
||||||
previewIconPath = previewIconInfo.get_filename();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (previewIconPath) {
|
if (previewIconPath) {
|
||||||
try {
|
try {
|
||||||
this._previewIcon = new Clutter.Texture({ width: GenericDisplay.PREVIEW_ICON_SIZE, height: GenericDisplay.PREVIEW_ICON_SIZE});
|
this._previewIcon = new Clutter.Texture({ width: GenericDisplay.PREVIEW_ICON_SIZE, height: GenericDisplay.PREVIEW_ICON_SIZE});
|
||||||
@ -346,7 +317,7 @@ AppDisplay.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
_addApp: function(appId) {
|
_addApp: function(appId) {
|
||||||
let appInfo = Gio.DesktopAppInfo.new(appId);
|
let appInfo = AppInfo.getAppInfo(appId);
|
||||||
if (appInfo != null) {
|
if (appInfo != null) {
|
||||||
this._allItems[appId] = appInfo;
|
this._allItems[appId] = appInfo;
|
||||||
// [] is returned if we could not get the categories or the list of categories was empty
|
// [] is returned if we could not get the categories or the list of categories was empty
|
||||||
@ -393,31 +364,8 @@ AppDisplay.prototype = {
|
|||||||
|
|
||||||
// Sets the list of the displayed items based on the most used apps.
|
// Sets the list of the displayed items based on the most used apps.
|
||||||
_setDefaultList : function() {
|
_setDefaultList : function() {
|
||||||
// Ask or more app than we need, since the list of recently used apps
|
let matchedInfos = AppInfo.getMostUsedApps(MAX_ITEMS);
|
||||||
// might contain an app we don't have a desktop file for
|
this._matchedItems = matchedInfos.map(function(info) { return info.appId; });
|
||||||
var apps = this._appMonitor.get_most_used_apps (0, Math.round(MAX_ITEMS * 1.5));
|
|
||||||
this._matchedItems = [];
|
|
||||||
for (let i = 0; i < apps.length; i++) {
|
|
||||||
if (this._matchedItems.length > MAX_ITEMS)
|
|
||||||
break;
|
|
||||||
let appId = apps[i] + ".desktop";
|
|
||||||
let appInfo = this._allItems[appId];
|
|
||||||
if (appInfo) {
|
|
||||||
this._matchedItems.push(appId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill the list with default applications it's not full yet
|
|
||||||
for (let i = 0; i < DEFAULT_APPLICATIONS.length; i++) {
|
|
||||||
if (this._matchedItems.length > MAX_ITEMS)
|
|
||||||
break;
|
|
||||||
let appId = DEFAULT_APPLICATIONS[i];
|
|
||||||
let appInfo = this._allItems[appId];
|
|
||||||
// Don't add if not available or already present in the list
|
|
||||||
if (appInfo && (this._matchedItems.indexOf(appId) == -1)) {
|
|
||||||
this._matchedItems.push(appId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Compares items associated with the item ids based on the alphabetical order
|
// Compares items associated with the item ids based on the alphabetical order
|
||||||
@ -486,7 +434,7 @@ AppDisplay.prototype = {
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Creates an AppDisplayItem based on itemInfo, which is expected be a GAppInfo object.
|
// Creates an AppDisplayItem based on itemInfo, which is expected be an AppInfo object.
|
||||||
_createDisplayItem: function(itemInfo) {
|
_createDisplayItem: function(itemInfo) {
|
||||||
return new AppDisplayItem(itemInfo, this._columnWidth);
|
return new AppDisplayItem(itemInfo, this._columnWidth);
|
||||||
}
|
}
|
||||||
|
@ -7,14 +7,13 @@ const Lang = imports.lang;
|
|||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
|
|
||||||
|
const DocInfo = imports.misc.docInfo;
|
||||||
const GenericDisplay = imports.ui.genericDisplay;
|
const GenericDisplay = imports.ui.genericDisplay;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
|
||||||
const ITEM_DISPLAY_ICON_MARGIN = 2;
|
|
||||||
|
|
||||||
/* This class represents a single display item containing information about a document.
|
/* This class represents a single display item containing information about a document.
|
||||||
*
|
*
|
||||||
* docInfo - GtkRecentInfo object containing information about the document
|
* docInfo - DocInfo object containing information about the document
|
||||||
* availableWidth - total width available for the item
|
* availableWidth - total width available for the item
|
||||||
*/
|
*/
|
||||||
function DocDisplayItem(docInfo, availableWidth) {
|
function DocDisplayItem(docInfo, availableWidth) {
|
||||||
@ -28,107 +27,34 @@ DocDisplayItem.prototype = {
|
|||||||
GenericDisplay.GenericDisplayItem.prototype._init.call(this, availableWidth);
|
GenericDisplay.GenericDisplayItem.prototype._init.call(this, availableWidth);
|
||||||
this._docInfo = docInfo;
|
this._docInfo = docInfo;
|
||||||
|
|
||||||
let name = docInfo.get_display_name();
|
this._setItemInfo(docInfo.name, "",
|
||||||
|
docInfo.getIcon(GenericDisplay.ITEM_DISPLAY_ICON_SIZE));
|
||||||
// we can possibly display tags in the space for description in the future
|
|
||||||
let description = "";
|
|
||||||
|
|
||||||
let icon = new Clutter.Texture();
|
|
||||||
this._iconPixbuf = Shell.get_thumbnail(docInfo.get_uri(), docInfo.get_mime_type());
|
|
||||||
if (this._iconPixbuf) {
|
|
||||||
// We calculate the width and height of the texture so as to preserve the aspect ratio of the thumbnail.
|
|
||||||
// Because the images generated based on thumbnails don't have an internal padding like system icons do,
|
|
||||||
// we create a slightly smaller texture and then use extra margin when positioning it.
|
|
||||||
let scalingFactor = (GenericDisplay.ITEM_DISPLAY_ICON_SIZE - ITEM_DISPLAY_ICON_MARGIN * 2) / Math.max(this._iconPixbuf.get_width(), this._iconPixbuf.get_height());
|
|
||||||
icon.set_width(Math.ceil(this._iconPixbuf.get_width() * scalingFactor));
|
|
||||||
icon.set_height(Math.ceil(this._iconPixbuf.get_height() * scalingFactor));
|
|
||||||
Shell.clutter_texture_set_from_pixbuf(icon, this._iconPixbuf);
|
|
||||||
icon.x = GenericDisplay.ITEM_DISPLAY_PADDING + ITEM_DISPLAY_ICON_MARGIN;
|
|
||||||
icon.y = GenericDisplay.ITEM_DISPLAY_PADDING + ITEM_DISPLAY_ICON_MARGIN;
|
|
||||||
} else {
|
|
||||||
Shell.clutter_texture_set_from_pixbuf(icon, docInfo.get_icon(GenericDisplay.ITEM_DISPLAY_ICON_SIZE));
|
|
||||||
icon.x = GenericDisplay.ITEM_DISPLAY_PADDING;
|
|
||||||
icon.y = GenericDisplay.ITEM_DISPLAY_PADDING;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._setItemInfo(name, description, icon);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
//// Public methods ////
|
//// Public methods ////
|
||||||
|
|
||||||
// Returns the document info associated with this display item.
|
|
||||||
getDocInfo : function() {
|
|
||||||
return this._docInfo;
|
|
||||||
},
|
|
||||||
|
|
||||||
//// Public method overrides ////
|
//// Public method overrides ////
|
||||||
|
|
||||||
// Opens a document represented by this display item.
|
// Opens a document represented by this display item.
|
||||||
launch : function() {
|
launch : function() {
|
||||||
// While using Gio.app_info_launch_default_for_uri() would be shorter
|
this._docInfo.launch();
|
||||||
// in terms of lines of code, we are not doing so because that would
|
|
||||||
// duplicate the work of retrieving the mime type.
|
|
||||||
let mimeType = this._docInfo.get_mime_type();
|
|
||||||
let appInfo = Gio.app_info_get_default_for_type(mimeType, true);
|
|
||||||
|
|
||||||
if (appInfo != null) {
|
|
||||||
appInfo.launch_uris([this._docInfo.get_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._docInfo.last_application();
|
|
||||||
let [success, appExec, count, time] = this._docInfo.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._docInfo.get_uri());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
//// Protected method overrides ////
|
//// Protected method overrides ////
|
||||||
|
|
||||||
// Ensures the preview icon is created.
|
// Ensures the preview icon is created.
|
||||||
_ensurePreviewIconCreated : function() {
|
_ensurePreviewIconCreated : function() {
|
||||||
if (this._previewIcon)
|
if (!this._previewIcon)
|
||||||
return;
|
this._previewIcon = this._docInfo.getIcon(GenericDisplay.PREVIEW_ICON_SIZE);
|
||||||
|
|
||||||
this._previewIcon = new Clutter.Texture();
|
|
||||||
if (this._iconPixbuf) {
|
|
||||||
let scalingFactor = (GenericDisplay.PREVIEW_ICON_SIZE / Math.max(this._iconPixbuf.get_width(), this._iconPixbuf.get_height()));
|
|
||||||
this._previewIcon.set_width(Math.ceil(this._iconPixbuf.get_width() * scalingFactor));
|
|
||||||
this._previewIcon.set_height(Math.ceil(this._iconPixbuf.get_height() * scalingFactor));
|
|
||||||
Shell.clutter_texture_set_from_pixbuf(this._previewIcon, this._iconPixbuf);
|
|
||||||
} else {
|
|
||||||
Shell.clutter_texture_set_from_pixbuf(this._previewIcon, this._docInfo.get_icon(GenericDisplay.PREVIEW_ICON_SIZE));
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Creates and returns a large preview icon, but only if this._docInfo is an image file
|
// Creates and returns a large preview icon, but only if this._docInfo is an image file
|
||||||
// and we were able to generate a pixbuf from it successfully.
|
// and we were able to generate a pixbuf from it successfully.
|
||||||
_createLargePreviewIcon : function(availableWidth, availableHeight) {
|
_createLargePreviewIcon : function(availableWidth, availableHeight) {
|
||||||
if (this._docInfo.get_mime_type() == null || this._docInfo.get_mime_type().indexOf("image/") != 0)
|
if (this._docInfo.mimeType == null || this._docInfo.mimeType.indexOf("image/") != 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return Shell.TextureCache.get_default().load_uri_sync(this._docInfo.get_uri(), availableWidth, availableHeight);
|
return Shell.TextureCache.get_default().load_uri_sync(this._docInfo.uri, availableWidth, availableHeight);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -170,10 +96,11 @@ DocDisplay.prototype = {
|
|||||||
this._allItems = {};
|
this._allItems = {};
|
||||||
let docs = this._recentManager.get_items();
|
let docs = this._recentManager.get_items();
|
||||||
for (let i = 0; i < docs.length; i++) {
|
for (let i = 0; i < docs.length; i++) {
|
||||||
let docInfo = docs[i];
|
let recentInfo = docs[i];
|
||||||
let docId = docInfo.get_uri();
|
let docInfo = new DocInfo.DocInfo(recentInfo);
|
||||||
|
|
||||||
// we use GtkRecentInfo URI as an item Id
|
// we use GtkRecentInfo URI as an item Id
|
||||||
this._allItems[docId] = docInfo;
|
this._allItems[docInfo.uri] = docInfo;
|
||||||
}
|
}
|
||||||
this._docsStale = false;
|
this._docsStale = false;
|
||||||
},
|
},
|
||||||
@ -217,15 +144,8 @@ DocDisplay.prototype = {
|
|||||||
_compareItems : function(itemIdA, itemIdB) {
|
_compareItems : function(itemIdA, itemIdB) {
|
||||||
let docA = this._allItems[itemIdA];
|
let docA = this._allItems[itemIdA];
|
||||||
let docB = this._allItems[itemIdB];
|
let docB = this._allItems[itemIdB];
|
||||||
// We actually used get_modified() instead of get_visited() here, as GtkRecentInfo
|
|
||||||
// doesn't updated get_visited() correctly.
|
return docB.lastVisited() - docA.lastVisited();
|
||||||
// See http://bugzilla.gnome.org/show_bug.cgi?id=567094
|
|
||||||
if (docA.get_modified() > docB.get_modified())
|
|
||||||
return -1;
|
|
||||||
else if (docA.get_modified() < docB.get_modified())
|
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Checks if the item info can be a match for the search string by checking
|
// Checks if the item info can be a match for the search string by checking
|
||||||
@ -238,7 +158,7 @@ DocDisplay.prototype = {
|
|||||||
if (search == null || search == '')
|
if (search == null || search == '')
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
let name = itemInfo.get_display_name().toLowerCase();
|
let name = itemInfo.name.toLowerCase();
|
||||||
if (name.indexOf(search) >= 0)
|
if (name.indexOf(search) >= 0)
|
||||||
return true;
|
return true;
|
||||||
// TODO: we can also check doc URIs, so that
|
// TODO: we can also check doc URIs, so that
|
||||||
@ -246,7 +166,7 @@ DocDisplay.prototype = {
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Creates a DocDisplayItem based on itemInfo, which is expected be a GtkRecentInfo object.
|
// Creates a DocDisplayItem based on itemInfo, which is expected to be a DocInfo object.
|
||||||
_createDisplayItem: function(itemInfo) {
|
_createDisplayItem: function(itemInfo) {
|
||||||
return new DocDisplayItem(itemInfo, this._columnWidth);
|
return new DocDisplayItem(itemInfo, this._columnWidth);
|
||||||
}
|
}
|
||||||
|
218
js/ui/widget.js
218
js/ui/widget.js
@ -6,11 +6,13 @@ const Gio = imports.gi.Gio;
|
|||||||
const Gtk = imports.gi.Gtk;
|
const Gtk = imports.gi.Gtk;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
|
const Pango = imports.gi.Pango;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
|
|
||||||
const AppDisplay = imports.ui.appDisplay;
|
const AppInfo = imports.misc.appInfo;
|
||||||
const DocDisplay = imports.ui.docDisplay;
|
const DocDisplay = imports.ui.docDisplay;
|
||||||
|
const DocInfo = imports.misc.docInfo;
|
||||||
|
|
||||||
const COLLAPSED_WIDTH = 24;
|
const COLLAPSED_WIDTH = 24;
|
||||||
const EXPANDED_WIDTH = 200;
|
const EXPANDED_WIDTH = 200;
|
||||||
@ -156,17 +158,118 @@ ClockWidget.prototype = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const ITEM_ICON_SIZE = 48;
|
||||||
|
const ITEM_PADDING = 1;
|
||||||
|
const ITEM_SPACING = 4;
|
||||||
|
|
||||||
const ITEM_BG_COLOR = new Clutter.Color();
|
const ITEM_BG_COLOR = new Clutter.Color();
|
||||||
ITEM_BG_COLOR.from_pixel(0x00000000);
|
ITEM_BG_COLOR.from_pixel(0x00000000);
|
||||||
const ITEM_NAME_COLOR = new Clutter.Color();
|
const ITEM_NAME_COLOR = new Clutter.Color();
|
||||||
ITEM_NAME_COLOR.from_pixel(0x000000ff);
|
ITEM_NAME_COLOR.from_pixel(0x000000ff);
|
||||||
const ITEM_DESCRIPTION_COLOR = new Clutter.Color();
|
|
||||||
ITEM_DESCRIPTION_COLOR.from_pixel(0x404040ff);
|
|
||||||
|
|
||||||
function hackUpDisplayItemColors(item) {
|
function LauncherWidget() {
|
||||||
item._bg.background_color = ITEM_BG_COLOR;
|
this._init();
|
||||||
item._name.color = ITEM_NAME_COLOR;
|
}
|
||||||
item._description.color = ITEM_DESCRIPTION_COLOR;
|
|
||||||
|
LauncherWidget.prototype = {
|
||||||
|
__proto__ : Widget.prototype,
|
||||||
|
|
||||||
|
addItem : function(info) {
|
||||||
|
let item = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||||
|
width: EXPANDED_WIDTH,
|
||||||
|
height: ITEM_ICON_SIZE,
|
||||||
|
padding: ITEM_PADDING,
|
||||||
|
spacing: ITEM_SPACING,
|
||||||
|
reactive: true });
|
||||||
|
item._info = info;
|
||||||
|
item.append(info.getIcon(ITEM_ICON_SIZE), Big.BoxPackFlags.NONE);
|
||||||
|
item.append(new Clutter.Text({ color: ITEM_NAME_COLOR,
|
||||||
|
font_name: "Sans 14px",
|
||||||
|
ellipsize: Pango.EllipsizeMode.END,
|
||||||
|
text: info.name }),
|
||||||
|
Big.BoxPackFlags.NONE);
|
||||||
|
|
||||||
|
this.actor.append(item, Big.BoxPackFlags.NONE);
|
||||||
|
item.connect('button-press-event', Lang.bind(this, this._buttonPress));
|
||||||
|
item.connect('button-release-event', Lang.bind(this, this._buttonRelease));
|
||||||
|
item.connect('leave-event', Lang.bind(this, this._leave));
|
||||||
|
item.connect('enter-event', Lang.bind(this, this._enter));
|
||||||
|
|
||||||
|
if (!this.collapsedActor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
item = new Big.Box({ width: COLLAPSED_WIDTH,
|
||||||
|
height: COLLAPSED_WIDTH,
|
||||||
|
padding: ITEM_PADDING,
|
||||||
|
reactive: true });
|
||||||
|
item._info = info;
|
||||||
|
item.append(info.getIcon(COLLAPSED_WIDTH - 2 * ITEM_PADDING),
|
||||||
|
Big.BoxPackFlags.NONE);
|
||||||
|
|
||||||
|
this.collapsedActor.append(item, Big.BoxPackFlags.NONE);
|
||||||
|
item.connect('button-press-event', Lang.bind(this, this._buttonPress));
|
||||||
|
item.connect('button-release-event', Lang.bind(this, this._buttonRelease));
|
||||||
|
item.connect('leave-event', Lang.bind(this, this._leave));
|
||||||
|
item.connect('enter-event', Lang.bind(this, this._enter));
|
||||||
|
},
|
||||||
|
|
||||||
|
clear : function() {
|
||||||
|
let children, i;
|
||||||
|
|
||||||
|
children = this.actor.get_children();
|
||||||
|
for (i = 0; i < children.length; i++)
|
||||||
|
children[i].destroy();
|
||||||
|
|
||||||
|
if (this.collapsedActor) {
|
||||||
|
children = this.collapsedActor.get_children();
|
||||||
|
for (i = 0; i < children.length; i++)
|
||||||
|
children[i].destroy();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_buttonPress : function(item) {
|
||||||
|
Clutter.grab_pointer(item);
|
||||||
|
item._buttonDown = true;
|
||||||
|
item._inItem = true;
|
||||||
|
this._updateItemState(item);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
_leave : function(item, evt) {
|
||||||
|
if (evt.get_source() == item && item._buttonDown) {
|
||||||
|
item._inItem = false;
|
||||||
|
this._updateItemState(item);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
_enter : function(item, evt) {
|
||||||
|
if (evt.get_source() == item && item._buttonDown) {
|
||||||
|
item._inItem = true;
|
||||||
|
this._updateItemState(item);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
_buttonRelease : function(item) {
|
||||||
|
Clutter.ungrab_pointer(item);
|
||||||
|
item._buttonDown = false;
|
||||||
|
this._updateItemState(item);
|
||||||
|
|
||||||
|
if (item._inItem) {
|
||||||
|
item._info.launch();
|
||||||
|
this.activated();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateItemState : function(item) {
|
||||||
|
if (item._buttonDown && item._inItem) {
|
||||||
|
item.padding_top = item.padding_left = 2 * ITEM_PADDING;
|
||||||
|
item.padding_bottom = item.padding_right = 0;
|
||||||
|
} else
|
||||||
|
item.padding = ITEM_PADDING;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function AppsWidget() {
|
function AppsWidget() {
|
||||||
@ -174,44 +277,16 @@ function AppsWidget() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AppsWidget.prototype = {
|
AppsWidget.prototype = {
|
||||||
__proto__ : Widget.prototype,
|
__proto__ : LauncherWidget.prototype,
|
||||||
|
|
||||||
_init : function() {
|
_init : function() {
|
||||||
this.title = "Applications";
|
this.title = "Applications";
|
||||||
this.actor = new Big.Box({ spacing: 2 });
|
this.actor = new Big.Box({ spacing: 2 });
|
||||||
this.collapsedActor = new Big.Box({ spacing: 2});
|
this.collapsedActor = new Big.Box({ spacing: 2});
|
||||||
|
|
||||||
let added = 0;
|
let apps = AppInfo.getMostUsedApps(5);
|
||||||
for (let i = 0; i < AppDisplay.DEFAULT_APPLICATIONS.length && added < 5; i++) {
|
for (let i = 0; i < apps.length; i++)
|
||||||
let id = AppDisplay.DEFAULT_APPLICATIONS[i];
|
this.addItem(apps[i]);
|
||||||
let appInfo = Gio.DesktopAppInfo.new(id);
|
|
||||||
if (!appInfo)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
let box = new Big.Box({ padding: 2,
|
|
||||||
corner_radius: 2 });
|
|
||||||
let appDisplayItem = new AppDisplay.AppDisplayItem(
|
|
||||||
appInfo, EXPANDED_WIDTH);
|
|
||||||
hackUpDisplayItemColors(appDisplayItem);
|
|
||||||
box.append(appDisplayItem.actor, Big.BoxPackFlags.NONE);
|
|
||||||
this.actor.append(box, Big.BoxPackFlags.NONE);
|
|
||||||
appDisplayItem.connect('select', Lang.bind(this, this._itemActivated));
|
|
||||||
|
|
||||||
// Cheaty cheat cheat
|
|
||||||
let icon = new Clutter.Clone({ source: appDisplayItem._icon,
|
|
||||||
width: COLLAPSED_WIDTH,
|
|
||||||
height: COLLAPSED_WIDTH,
|
|
||||||
reactive: true });
|
|
||||||
this.collapsedActor.append(icon, Big.BoxPackFlags.NONE);
|
|
||||||
icon.connect('button-release-event', Lang.bind(this, function() { this._itemActivated(appDisplayItem); }));
|
|
||||||
|
|
||||||
added++;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_itemActivated: function(item) {
|
|
||||||
item.launch();
|
|
||||||
this.activated();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -220,7 +295,7 @@ function DocsWidget() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DocsWidget.prototype = {
|
DocsWidget.prototype = {
|
||||||
__proto__ : Widget.prototype,
|
__proto__ : LauncherWidget.prototype,
|
||||||
|
|
||||||
_init : function() {
|
_init : function() {
|
||||||
this.title = "Recent Docs";
|
this.title = "Recent Docs";
|
||||||
@ -232,62 +307,21 @@ DocsWidget.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
_recentChanged: function() {
|
_recentChanged: function() {
|
||||||
let i, docId;
|
let i;
|
||||||
|
|
||||||
this._allItems = {};
|
this.clear();
|
||||||
|
|
||||||
|
let items = [];
|
||||||
let docs = this._recentManager.get_items();
|
let docs = this._recentManager.get_items();
|
||||||
for (i = 0; i < docs.length; i++) {
|
for (i = 0; i < docs.length; i++) {
|
||||||
let docInfo = docs[i];
|
let docInfo = new DocInfo.DocInfo (docs[i]);
|
||||||
let docId = docInfo.get_uri();
|
|
||||||
// we use GtkRecentInfo URI as an item Id
|
if (docInfo.exists())
|
||||||
this._allItems[docId] = docInfo;
|
items.push(docInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._matchedItems = [];
|
items.sort(function (a,b) { return b.lastVisited() - a.lastVisited(); });
|
||||||
let docIdsToRemove = [];
|
for (i = 0; i < Math.min(items.length, 5); i++)
|
||||||
for (docId in this._allItems) {
|
this.addItem(items[i]);
|
||||||
// this._allItems[docId].exists() checks if the resource still exists
|
|
||||||
if (this._allItems[docId].exists())
|
|
||||||
this._matchedItems.push(docId);
|
|
||||||
else
|
|
||||||
docIdsToRemove.push(docId);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (docId in docIdsToRemove) {
|
|
||||||
delete this._allItems[docId];
|
|
||||||
}
|
|
||||||
|
|
||||||
this._matchedItems.sort(Lang.bind(this, function (a,b) { return this._compareItems(a,b); }));
|
|
||||||
|
|
||||||
let children = this.actor.get_children();
|
|
||||||
for (let c = 0; c < children.length; c++)
|
|
||||||
this.actor.remove_actor(children[c]);
|
|
||||||
|
|
||||||
for (i = 0; i < Math.min(this._matchedItems.length, 5); i++) {
|
|
||||||
let box = new Big.Box({ padding: 2,
|
|
||||||
corner_radius: 2 });
|
|
||||||
let docDisplayItem = new DocDisplay.DocDisplayItem(
|
|
||||||
this._allItems[this._matchedItems[i]], EXPANDED_WIDTH);
|
|
||||||
hackUpDisplayItemColors(docDisplayItem);
|
|
||||||
box.append(docDisplayItem.actor, Big.BoxPackFlags.NONE);
|
|
||||||
this.actor.append(box, Big.BoxPackFlags.NONE);
|
|
||||||
docDisplayItem.connect('select', Lang.bind(this, this._itemActivated));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_compareItems : function(itemIdA, itemIdB) {
|
|
||||||
let docA = this._allItems[itemIdA];
|
|
||||||
let docB = this._allItems[itemIdB];
|
|
||||||
if (docA.get_modified() > docB.get_modified())
|
|
||||||
return -1;
|
|
||||||
else if (docA.get_modified() < docB.get_modified())
|
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
_itemActivated: function(item) {
|
|
||||||
item.launch();
|
|
||||||
this.activated();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -8,7 +8,7 @@ noinst_LTLIBRARIES =
|
|||||||
bin_SCRIPTS = gnome-shell
|
bin_SCRIPTS = gnome-shell
|
||||||
|
|
||||||
gnome-shell: gnome-shell.in
|
gnome-shell: gnome-shell.in
|
||||||
sed -e "s|@META_BIN_DIR[@]|$(META_BIN_DIR)|" \
|
sed -e "s|@MUTTER_BIN_DIR[@]|$(MUTTER_BIN_DIR)|" \
|
||||||
-e "s|@GJS_JS_DIR[@]|$(GJS_JS_DIR)|" \
|
-e "s|@GJS_JS_DIR[@]|$(GJS_JS_DIR)|" \
|
||||||
-e "s|@GJS_JS_NATIVE_DIR[@]|$(GJS_JS_NATIVE_DIR)|" \
|
-e "s|@GJS_JS_NATIVE_DIR[@]|$(GJS_JS_NATIVE_DIR)|" \
|
||||||
-e "s|@libexecdir[@]|$(libexecdir)|" \
|
-e "s|@libexecdir[@]|$(libexecdir)|" \
|
||||||
@ -33,7 +33,7 @@ gnome_shell_cflags = \
|
|||||||
-DGNOME_SHELL_PKGLIBDIR=\"$(pkglibdir)\" \
|
-DGNOME_SHELL_PKGLIBDIR=\"$(pkglibdir)\" \
|
||||||
-DJSDIR=\"$(pkgdatadir)/js\"
|
-DJSDIR=\"$(pkgdatadir)/js\"
|
||||||
|
|
||||||
plugindir = $(libdir)/metacity/plugins/clutter
|
plugindir = $(MUTTER_PLUGIN_DIR)
|
||||||
plugin_LTLIBRARIES = libgnome-shell.la
|
plugin_LTLIBRARIES = libgnome-shell.la
|
||||||
|
|
||||||
shell_built_sources = \
|
shell_built_sources = \
|
||||||
@ -139,16 +139,16 @@ libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)
|
|||||||
typelibdir = $(pkglibdir)
|
typelibdir = $(pkglibdir)
|
||||||
typelib_DATA = Shell-0.1.typelib Tidy-1.0.typelib Big-1.0.typelib
|
typelib_DATA = Shell-0.1.typelib Tidy-1.0.typelib Big-1.0.typelib
|
||||||
|
|
||||||
Shell-0.1.gir: $(metacity) $(G_IR_SCANNER) Big-1.0.gir libgnome-shell.la Makefile
|
Shell-0.1.gir: $(mutter) $(G_IR_SCANNER) Big-1.0.gir libgnome-shell.la Makefile
|
||||||
$(G_IR_SCANNER) \
|
$(G_IR_SCANNER) \
|
||||||
--namespace=Shell \
|
--namespace=Shell \
|
||||||
--nsversion=0.1 \
|
--nsversion=0.1 \
|
||||||
--add-include-path=$(META_LIB_DIR)/metacity/ \
|
--add-include-path=$(MUTTER_LIB_DIR)/mutter/ \
|
||||||
--include=Clutter-0.9 \
|
--include=Clutter-0.9 \
|
||||||
--include=Meta-2.27 \
|
--include=Meta-2.27 \
|
||||||
--add-include-path=$(builddir) \
|
--add-include-path=$(builddir) \
|
||||||
--include=Big-1.0 \
|
--include=Big-1.0 \
|
||||||
--program=metacity \
|
--program=mutter \
|
||||||
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
|
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
|
||||||
$(addprefix $(srcdir)/,$(libgnome_shell_la_gir_sources)) \
|
$(addprefix $(srcdir)/,$(libgnome_shell_la_gir_sources)) \
|
||||||
$(libgnome_shell_la_CPPFLAGS) \
|
$(libgnome_shell_la_CPPFLAGS) \
|
||||||
@ -158,15 +158,15 @@ CLEANFILES += Shell-0.1.gir
|
|||||||
# The dependency on libgnome-shell.la here is because g-ir-compiler opens it
|
# The dependency on libgnome-shell.la here is because g-ir-compiler opens it
|
||||||
# (not the fake library, since we've already done the rewriting)
|
# (not the fake library, since we've already done the rewriting)
|
||||||
Shell-0.1.typelib: libgnome-shell.la Shell-0.1.gir Big-1.0.gir
|
Shell-0.1.typelib: libgnome-shell.la Shell-0.1.gir Big-1.0.gir
|
||||||
LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. g-ir-compiler --includedir=$(builddir) --includedir=$(META_LIB_DIR)/metacity/ Shell-0.1.gir -o $@
|
LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. g-ir-compiler --includedir=$(builddir) --includedir=$(MUTTER_LIB_DIR)/mutter/ Shell-0.1.gir -o $@
|
||||||
CLEANFILES += Shell-0.1.typelib
|
CLEANFILES += Shell-0.1.typelib
|
||||||
|
|
||||||
Tidy-1.0.gir: $(metacity) $(G_IR_SCANNER) libgnome-shell.la libtidy-1.0.la Makefile
|
Tidy-1.0.gir: $(mutter) $(G_IR_SCANNER) libgnome-shell.la libtidy-1.0.la Makefile
|
||||||
$(G_IR_SCANNER) \
|
$(G_IR_SCANNER) \
|
||||||
--namespace=Tidy \
|
--namespace=Tidy \
|
||||||
--nsversion=1.0 \
|
--nsversion=1.0 \
|
||||||
--include=Clutter-0.9 \
|
--include=Clutter-0.9 \
|
||||||
--program=metacity \
|
--program=mutter \
|
||||||
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
|
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
|
||||||
$(addprefix $(srcdir)/,$(tidy_source_h)) \
|
$(addprefix $(srcdir)/,$(tidy_source_h)) \
|
||||||
$(addprefix $(srcdir)/,$(tidy_source_c)) \
|
$(addprefix $(srcdir)/,$(tidy_source_c)) \
|
||||||
@ -179,13 +179,13 @@ Tidy-1.0.typelib: libtidy-1.0.la Tidy-1.0.gir
|
|||||||
LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. g-ir-compiler Tidy-1.0.gir -o $@
|
LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. g-ir-compiler Tidy-1.0.gir -o $@
|
||||||
CLEANFILES += Tidy-1.0.typelib
|
CLEANFILES += Tidy-1.0.typelib
|
||||||
|
|
||||||
Big-1.0.gir: $(metacity) $(G_IR_SCANNER) libgnome-shell.la libbig-1.0.la Makefile
|
Big-1.0.gir: $(mutter) $(G_IR_SCANNER) libgnome-shell.la libbig-1.0.la Makefile
|
||||||
$(G_IR_SCANNER) \
|
$(G_IR_SCANNER) \
|
||||||
--namespace=Big \
|
--namespace=Big \
|
||||||
--nsversion=1.0 \
|
--nsversion=1.0 \
|
||||||
--include=Clutter-0.9 \
|
--include=Clutter-0.9 \
|
||||||
--include=GdkPixbuf-2.0 \
|
--include=GdkPixbuf-2.0 \
|
||||||
--program=metacity \
|
--program=mutter \
|
||||||
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
|
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
|
||||||
$(addprefix $(srcdir)/,$(big_source_h)) \
|
$(addprefix $(srcdir)/,$(big_source_h)) \
|
||||||
$(addprefix $(srcdir)/,$(big_source_c)) \
|
$(addprefix $(srcdir)/,$(big_source_c)) \
|
||||||
|
@ -134,7 +134,7 @@ def start_shell():
|
|||||||
# Set up environment
|
# Set up environment
|
||||||
env = dict(os.environ)
|
env = dict(os.environ)
|
||||||
env.update({'GNOME_SHELL_JS' : '@GJS_JS_DIR@:@GJS_JS_NATIVE_DIR@:' + js_dir,
|
env.update({'GNOME_SHELL_JS' : '@GJS_JS_DIR@:@GJS_JS_NATIVE_DIR@:' + js_dir,
|
||||||
'PATH' : '@META_BIN_DIR@:' + os.environ.get('PATH', '') + ':' + taskpanel_dir,
|
'PATH' : '@MUTTER_BIN_DIR@:' + os.environ.get('PATH', '') + ':' + taskpanel_dir,
|
||||||
'GNOME_DISABLE_CRASH_DIALOG' : '1'})
|
'GNOME_DISABLE_CRASH_DIALOG' : '1'})
|
||||||
|
|
||||||
if running_from_source_tree:
|
if running_from_source_tree:
|
||||||
@ -187,7 +187,7 @@ def start_shell():
|
|||||||
else:
|
else:
|
||||||
args = []
|
args = []
|
||||||
|
|
||||||
args.extend(['metacity', '--mutter-plugins=' + plugin, '--replace'])
|
args.extend(['mutter', '--mutter-plugins=' + plugin, '--replace'])
|
||||||
if options.sync:
|
if options.sync:
|
||||||
args.append('--sync')
|
args.append('--sync')
|
||||||
return subprocess.Popen(args, env=env)
|
return subprocess.Popen(args, env=env)
|
||||||
|
@ -812,13 +812,11 @@ restore_from_file (ShellAppMonitor *monitor)
|
|||||||
/* FIXME: do something if conversion fails! */
|
/* FIXME: do something if conversion fails! */
|
||||||
/* like: errno = NULL; ... if (errno) { g_free (line); goto out; } */
|
/* like: errno = NULL; ... if (errno) { g_free (line); goto out; } */
|
||||||
}
|
}
|
||||||
else if (error)
|
else
|
||||||
{
|
{
|
||||||
g_free (line);
|
g_free (line);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
else /* End of file */
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
/* Line is about an app.
|
/* Line is about an app.
|
||||||
* If no activity was provided yet, just skip */
|
* If no activity was provided yet, just skip */
|
||||||
|
@ -145,13 +145,13 @@ reread_directories (ShellAppSystem *self, GSList **cache, GMenuTree *tree)
|
|||||||
shell_entry->icon = g_strdup (gmenu_tree_directory_get_icon (dir));
|
shell_entry->icon = g_strdup (gmenu_tree_directory_get_icon (dir));
|
||||||
|
|
||||||
*cache = g_slist_prepend (*cache, shell_entry);
|
*cache = g_slist_prepend (*cache, shell_entry);
|
||||||
|
|
||||||
gmenu_tree_item_unref (dir);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gmenu_tree_item_unref (item);
|
||||||
}
|
}
|
||||||
*cache = g_slist_reverse (*cache);
|
*cache = g_slist_reverse (*cache);
|
||||||
|
|
||||||
@ -260,13 +260,18 @@ shell_app_system_get_applications_for_menu (ShellAppSystem *monitor,
|
|||||||
{
|
{
|
||||||
char *path;
|
char *path;
|
||||||
GMenuTreeDirectory *menu_entry;
|
GMenuTreeDirectory *menu_entry;
|
||||||
|
GSList *apps;
|
||||||
|
|
||||||
path = g_strdup_printf ("/%s", menu);
|
path = g_strdup_printf ("/%s", menu);
|
||||||
menu_entry = gmenu_tree_get_directory_from_path (monitor->priv->apps_tree, path);
|
menu_entry = gmenu_tree_get_directory_from_path (monitor->priv->apps_tree, path);
|
||||||
g_free (path);
|
g_free (path);
|
||||||
g_assert (menu_entry != NULL);
|
g_assert (menu_entry != NULL);
|
||||||
|
|
||||||
return gather_entries_recurse (monitor, NULL, menu_entry);
|
apps = gather_entries_recurse (monitor, NULL, menu_entry);
|
||||||
|
|
||||||
|
gmenu_tree_item_unref (menu_entry);
|
||||||
|
|
||||||
|
return apps;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -421,7 +421,6 @@ shell_get_categories_for_desktop_file(const char *desktop_file_name)
|
|||||||
const char * const *search_dirs;
|
const char * const *search_dirs;
|
||||||
char **categories = NULL;
|
char **categories = NULL;
|
||||||
GSList *categories_list = NULL;
|
GSList *categories_list = NULL;
|
||||||
char *full_path = NULL;
|
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
gsize len;
|
gsize len;
|
||||||
int i;
|
int i;
|
||||||
@ -429,7 +428,7 @@ shell_get_categories_for_desktop_file(const char *desktop_file_name)
|
|||||||
key_file = g_key_file_new ();
|
key_file = g_key_file_new ();
|
||||||
search_dirs = get_applications_search_path();
|
search_dirs = get_applications_search_path();
|
||||||
|
|
||||||
g_key_file_load_from_dirs (key_file, desktop_file_name, (const char **)search_dirs, &full_path, 0, &error);
|
g_key_file_load_from_dirs (key_file, desktop_file_name, (const char **)search_dirs, NULL, 0, &error);
|
||||||
|
|
||||||
if (error != NULL)
|
if (error != NULL)
|
||||||
{
|
{
|
||||||
|
@ -188,6 +188,22 @@ typedef struct {
|
|||||||
int height;
|
int height;
|
||||||
} Dimensions;
|
} Dimensions;
|
||||||
|
|
||||||
|
static void
|
||||||
|
icon_lookup_data_destroy (gpointer p)
|
||||||
|
{
|
||||||
|
AsyncIconLookupData *data = p;
|
||||||
|
|
||||||
|
if (data->icon)
|
||||||
|
{
|
||||||
|
g_object_unref (data->icon);
|
||||||
|
gtk_icon_info_free (data->icon_info);
|
||||||
|
}
|
||||||
|
else if (data->uri)
|
||||||
|
g_free (data->uri);
|
||||||
|
|
||||||
|
g_free (data);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* on_image_size_prepared:
|
* on_image_size_prepared:
|
||||||
*
|
*
|
||||||
@ -321,7 +337,7 @@ load_pixbuf_thread (GSimpleAsyncResult *result,
|
|||||||
AsyncIconLookupData *data;
|
AsyncIconLookupData *data;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
data = g_simple_async_result_get_op_res_gpointer (result);
|
data = g_object_get_data (result, "load_icon_pixbuf_async");
|
||||||
|
|
||||||
if (data->uri)
|
if (data->uri)
|
||||||
pixbuf = impl_load_pixbuf_file (data->uri, data->width, data->height, &error);
|
pixbuf = impl_load_pixbuf_file (data->uri, data->width, data->height, &error);
|
||||||
@ -336,27 +352,10 @@ load_pixbuf_thread (GSimpleAsyncResult *result,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
g_simple_async_result_set_op_res_gpointer (result, g_object_ref (pixbuf),
|
g_simple_async_result_set_op_res_gpointer (result, g_object_ref (pixbuf),
|
||||||
g_object_unref);
|
g_object_unref);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
icon_lookup_data_destroy (gpointer p)
|
|
||||||
{
|
|
||||||
AsyncIconLookupData *data = p;
|
|
||||||
|
|
||||||
if (data->icon)
|
|
||||||
{
|
|
||||||
g_object_unref (data->icon);
|
|
||||||
gtk_icon_info_free (data->icon_info);
|
|
||||||
}
|
|
||||||
else if (data->uri)
|
|
||||||
g_free (data->uri);
|
|
||||||
|
|
||||||
g_free (data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* load_icon_pixbuf_async:
|
* load_icon_pixbuf_async:
|
||||||
*
|
*
|
||||||
@ -383,8 +382,10 @@ load_icon_pixbuf_async (ShellTextureCache *cache,
|
|||||||
|
|
||||||
result = g_simple_async_result_new (G_OBJECT (cache), callback, user_data, load_icon_pixbuf_async);
|
result = g_simple_async_result_new (G_OBJECT (cache), callback, user_data, load_icon_pixbuf_async);
|
||||||
|
|
||||||
g_simple_async_result_set_op_res_gpointer (result, data, icon_lookup_data_destroy);
|
g_object_set_data_full (result, "load_icon_pixbuf_async", data, icon_lookup_data_destroy);
|
||||||
g_simple_async_result_run_in_thread (result, load_pixbuf_thread, G_PRIORITY_DEFAULT, cancellable);
|
g_simple_async_result_run_in_thread (result, load_pixbuf_thread, G_PRIORITY_DEFAULT, cancellable);
|
||||||
|
|
||||||
|
g_object_unref (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -407,8 +408,10 @@ load_uri_pixbuf_async (ShellTextureCache *cache,
|
|||||||
|
|
||||||
result = g_simple_async_result_new (G_OBJECT (cache), callback, user_data, load_uri_pixbuf_async);
|
result = g_simple_async_result_new (G_OBJECT (cache), callback, user_data, load_uri_pixbuf_async);
|
||||||
|
|
||||||
g_simple_async_result_set_op_res_gpointer (result, data, icon_lookup_data_destroy);
|
g_object_set_data_full (result, "load_uri_pixbuf_async", data, icon_lookup_data_destroy);
|
||||||
g_simple_async_result_run_in_thread (result, load_pixbuf_thread, G_PRIORITY_DEFAULT, cancellable);
|
g_simple_async_result_run_in_thread (result, load_pixbuf_thread, G_PRIORITY_DEFAULT, cancellable);
|
||||||
|
|
||||||
|
g_object_unref (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GdkPixbuf *
|
static GdkPixbuf *
|
||||||
@ -464,6 +467,8 @@ on_pixbuf_loaded (GObject *source,
|
|||||||
|
|
||||||
texdata = pixbuf_to_cogl_handle (pixbuf);
|
texdata = pixbuf_to_cogl_handle (pixbuf);
|
||||||
|
|
||||||
|
g_object_unref (pixbuf);
|
||||||
|
|
||||||
if (data->icon)
|
if (data->icon)
|
||||||
{
|
{
|
||||||
gpointer orig_key, value;
|
gpointer orig_key, value;
|
||||||
@ -619,6 +624,7 @@ shell_texture_cache_load_uri_sync (ShellTextureCache *cache,
|
|||||||
|
|
||||||
texture = CLUTTER_TEXTURE (clutter_texture_new ());
|
texture = CLUTTER_TEXTURE (clutter_texture_new ());
|
||||||
texdata = pixbuf_to_cogl_handle (pixbuf);
|
texdata = pixbuf_to_cogl_handle (pixbuf);
|
||||||
|
g_object_unref (pixbuf);
|
||||||
clutter_texture_set_cogl_texture (texture, texdata);
|
clutter_texture_set_cogl_texture (texture, texdata);
|
||||||
|
|
||||||
return CLUTTER_ACTOR (texture);
|
return CLUTTER_ACTOR (texture);
|
||||||
|
Loading…
Reference in New Issue
Block a user