Compare commits
	
		
			15 Commits
		
	
	
		
			wip/ptomat
			...
			wip/deskto
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					45797a977b | ||
| 
						 | 
					884b94233e | ||
| 
						 | 
					74d3e3139f | ||
| 
						 | 
					77b5385cc3 | ||
| 
						 | 
					d749d646be | ||
| 
						 | 
					fa8224d7b5 | ||
| 
						 | 
					f687197ccc | ||
| 
						 | 
					28a6aefb6c | ||
| 
						 | 
					96c2a90e11 | ||
| 
						 | 
					63cf46e49b | ||
| 
						 | 
					200a9ef1af | ||
| 
						 | 
					6050ca6e0c | ||
| 
						 | 
					8bd7db9227 | ||
| 
						 | 
					982feb85c1 | ||
| 
						 | 
					f165cc23c0 | 
@@ -70,7 +70,6 @@ POLKIT_MIN_VERSION=0.100
 | 
			
		||||
STARTUP_NOTIFICATION_MIN_VERSION=0.11
 | 
			
		||||
GCR_MIN_VERSION=3.7.5
 | 
			
		||||
GNOME_DESKTOP_REQUIRED_VERSION=3.7.90
 | 
			
		||||
GNOME_MENUS_REQUIRED_VERSION=3.5.3
 | 
			
		||||
NETWORKMANAGER_MIN_VERSION=0.9.8
 | 
			
		||||
PULSE_MIN_VERS=2.0
 | 
			
		||||
 | 
			
		||||
@@ -80,7 +79,6 @@ SHARED_PCS="gio-unix-2.0 >= $GIO_MIN_VERSION
 | 
			
		||||
            gtk+-3.0 >= $GTK_MIN_VERSION
 | 
			
		||||
            atk-bridge-2.0
 | 
			
		||||
            gjs-internals-1.0 >= $GJS_MIN_VERSION
 | 
			
		||||
            libgnome-menu-3.0 >= $GNOME_MENUS_REQUIRED_VERSION
 | 
			
		||||
            $recorder_modules
 | 
			
		||||
            gdk-x11-3.0 libsoup-2.4
 | 
			
		||||
            xtst
 | 
			
		||||
 
 | 
			
		||||
@@ -55,13 +55,13 @@ function _loadCategory(dir, view) {
 | 
			
		||||
    while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) {
 | 
			
		||||
        if (nextType == GMenu.TreeItemType.ENTRY) {
 | 
			
		||||
            let entry = iter.get_entry();
 | 
			
		||||
            let app = appSystem.lookup_app_by_tree_entry(entry);
 | 
			
		||||
            if (!entry.get_app_info().get_nodisplay())
 | 
			
		||||
            let appInfo = entry.get_app_info();
 | 
			
		||||
            let app = appSystem.lookup_app(entry.get_desktop_file_id());
 | 
			
		||||
            if (appInfo.should_show())
 | 
			
		||||
                view.addApp(app);
 | 
			
		||||
        } else if (nextType == GMenu.TreeItemType.DIRECTORY) {
 | 
			
		||||
            let itemDir = iter.get_directory();
 | 
			
		||||
            if (!itemDir.get_is_nodisplay())
 | 
			
		||||
                _loadCategory(itemDir, view);
 | 
			
		||||
            _loadCategory(itemDir, view);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
@@ -691,8 +691,7 @@ const AppDisplay = new Lang.Class({
 | 
			
		||||
    Name: 'AppDisplay',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._appSystem = Shell.AppSystem.get_default();
 | 
			
		||||
        this._appSystem.connect('installed-changed', Lang.bind(this, function() {
 | 
			
		||||
        Shell.AppSystem.get_default().connect('installed-changed', Lang.bind(this, function() {
 | 
			
		||||
            Main.queueDeferredWork(this._allAppsWorkId);
 | 
			
		||||
        }));
 | 
			
		||||
        Main.overview.connect('showing', Lang.bind(this, function() {
 | 
			
		||||
@@ -808,7 +807,8 @@ const AppDisplay = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        view.removeAll();
 | 
			
		||||
 | 
			
		||||
        let tree = this._appSystem.get_tree();
 | 
			
		||||
        let tree = new GMenu.Tree({ menu_basename: "applications.menu" });
 | 
			
		||||
        tree.load_sync();
 | 
			
		||||
        let root = tree.get_root_directory();
 | 
			
		||||
 | 
			
		||||
        let iter = root.iter();
 | 
			
		||||
@@ -817,8 +817,6 @@ const AppDisplay = new Lang.Class({
 | 
			
		||||
        while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) {
 | 
			
		||||
            if (nextType == GMenu.TreeItemType.DIRECTORY) {
 | 
			
		||||
                let dir = iter.get_directory();
 | 
			
		||||
                if (dir.get_is_nodisplay())
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                if (folderCategories.indexOf(dir.get_menu_id()) != -1)
 | 
			
		||||
                    view.addFolder(dir);
 | 
			
		||||
@@ -866,8 +864,8 @@ const AppSearchProvider = new Lang.Class({
 | 
			
		||||
    getResultMetas: function(apps, callback) {
 | 
			
		||||
        let metas = [];
 | 
			
		||||
        for (let i = 0; i < apps.length; i++) {
 | 
			
		||||
            let app = apps[i];
 | 
			
		||||
            metas.push({ 'id': app,
 | 
			
		||||
            let app = this._appSys.lookup_app(apps[i]);
 | 
			
		||||
            metas.push({ 'id': app.get_id(),
 | 
			
		||||
                         'name': app.get_name(),
 | 
			
		||||
                         'createIcon': function(size) {
 | 
			
		||||
                             return app.create_icon_texture(size);
 | 
			
		||||
@@ -877,15 +875,23 @@ const AppSearchProvider = new Lang.Class({
 | 
			
		||||
        callback(metas);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _compareResults: function(a, b) {
 | 
			
		||||
        let usage = Shell.AppUsage.get_default();
 | 
			
		||||
        return usage.compare('', a, b);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getInitialResultSet: function(terms) {
 | 
			
		||||
        this.searchSystem.setResults(this, this._appSys.initial_search(terms));
 | 
			
		||||
        let query = terms.join(' ');
 | 
			
		||||
        let results = Gio.DesktopAppInfo.search(query, Lang.bind(this, this._compareResults), MAX_COLUMNS);
 | 
			
		||||
        this.searchSystem.setResults(this, results);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getSubsearchResultSet: function(previousResults, terms) {
 | 
			
		||||
        this.searchSystem.setResults(this, this._appSys.subsearch(previousResults, terms));
 | 
			
		||||
        this.getInitialResultSet(terms);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    activateResult: function(app) {
 | 
			
		||||
    activateResult: function(result) {
 | 
			
		||||
        let app = this._appSys.lookup_app(result);
 | 
			
		||||
        let event = Clutter.get_current_event();
 | 
			
		||||
        let modifiers = event ? event.get_state() : 0;
 | 
			
		||||
        let openNewWindow = modifiers & Clutter.ModifierType.CONTROL_MASK;
 | 
			
		||||
@@ -905,7 +911,7 @@ const AppSearchProvider = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createResultObject: function (resultMeta, terms) {
 | 
			
		||||
        let app = resultMeta['id'];
 | 
			
		||||
        let app = this._appSys.lookup_app(resultMeta['id']);
 | 
			
		||||
        return new AppIcon(app);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -12,9 +12,9 @@ G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
ShellApp* _shell_app_new_for_window (MetaWindow *window);
 | 
			
		||||
 | 
			
		||||
ShellApp* _shell_app_new (GMenuTreeEntry *entry);
 | 
			
		||||
ShellApp* _shell_app_new (GDesktopAppInfo *info);
 | 
			
		||||
 | 
			
		||||
void _shell_app_set_entry (ShellApp *app, GMenuTreeEntry *entry);
 | 
			
		||||
void _shell_app_set_app_info (ShellApp *app, GDesktopAppInfo *info);
 | 
			
		||||
 | 
			
		||||
void _shell_app_handle_startup_sequence (ShellApp *app, SnStartupSequence *sequence);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -38,18 +38,12 @@ enum {
 | 
			
		||||
static guint signals[LAST_SIGNAL] = { 0 };
 | 
			
		||||
 | 
			
		||||
struct _ShellAppSystemPrivate {
 | 
			
		||||
  GMenuTree *apps_tree;
 | 
			
		||||
 | 
			
		||||
  GHashTable *running_apps;
 | 
			
		||||
  GHashTable *visible_id_to_app;
 | 
			
		||||
  GHashTable *id_to_app;
 | 
			
		||||
  GHashTable *startup_wm_class_to_app;
 | 
			
		||||
 | 
			
		||||
  GSList *known_vendor_prefixes;
 | 
			
		||||
  GHashTable *startup_wm_class_to_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void shell_app_system_finalize (GObject *object);
 | 
			
		||||
static void on_apps_tree_changed_cb (GMenuTree *tree, gpointer user_data);
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE(ShellAppSystem, shell_app_system, G_TYPE_OBJECT);
 | 
			
		||||
 | 
			
		||||
@@ -77,10 +71,45 @@ static void shell_app_system_class_init(ShellAppSystemClass *klass)
 | 
			
		||||
  g_type_class_add_private (gobject_class, sizeof (ShellAppSystemPrivate));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
scan_startup_wm_class_to_id (ShellAppSystem *self)
 | 
			
		||||
{
 | 
			
		||||
  ShellAppSystemPrivate *priv = self->priv;
 | 
			
		||||
  GList *apps, *l;
 | 
			
		||||
 | 
			
		||||
  g_hash_table_remove_all (priv->startup_wm_class_to_id);
 | 
			
		||||
 | 
			
		||||
  apps = g_app_info_get_all ();
 | 
			
		||||
  for (l = apps; l != NULL; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      GAppInfo *info = l->data;
 | 
			
		||||
      const char *startup_wm_class, *id;
 | 
			
		||||
 | 
			
		||||
      id = g_app_info_get_id (info);
 | 
			
		||||
      startup_wm_class = g_desktop_app_info_get_startup_wm_class (G_DESKTOP_APP_INFO (info));
 | 
			
		||||
      if (startup_wm_class != NULL)
 | 
			
		||||
        g_hash_table_insert (priv->startup_wm_class_to_id, (char *) startup_wm_class, (char *) id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_list_free_full (apps, g_object_unref);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
installed_changed (GAppInfoMonitor *monitor,
 | 
			
		||||
                   gpointer         user_data)
 | 
			
		||||
{
 | 
			
		||||
  ShellAppSystem *self = user_data;
 | 
			
		||||
 | 
			
		||||
  scan_startup_wm_class_to_id (self);
 | 
			
		||||
 | 
			
		||||
  g_signal_emit (self, signals[INSTALLED_CHANGED], 0, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
shell_app_system_init (ShellAppSystem *self)
 | 
			
		||||
{
 | 
			
		||||
  ShellAppSystemPrivate *priv;
 | 
			
		||||
  GAppInfoMonitor *monitor;
 | 
			
		||||
 | 
			
		||||
  self->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
 | 
			
		||||
                                                   SHELL_TYPE_APP_SYSTEM,
 | 
			
		||||
@@ -91,19 +120,11 @@ shell_app_system_init (ShellAppSystem *self)
 | 
			
		||||
                                           NULL,
 | 
			
		||||
                                           (GDestroyNotify)g_object_unref);
 | 
			
		||||
 | 
			
		||||
  /* All the objects in this hash table are owned by id_to_app */
 | 
			
		||||
  priv->visible_id_to_app = g_hash_table_new (g_str_hash, g_str_equal);
 | 
			
		||||
  priv->startup_wm_class_to_id = g_hash_table_new (g_str_hash, g_str_equal);
 | 
			
		||||
 | 
			
		||||
  priv->startup_wm_class_to_app = g_hash_table_new_full (g_str_hash, g_str_equal,
 | 
			
		||||
                                                         NULL,
 | 
			
		||||
                                                         (GDestroyNotify)g_object_unref);
 | 
			
		||||
 | 
			
		||||
  /* We want to track NoDisplay apps, so we add INCLUDE_NODISPLAY. We'll
 | 
			
		||||
   * filter NoDisplay apps out when showing them to the user. */
 | 
			
		||||
  priv->apps_tree = gmenu_tree_new ("applications.menu", GMENU_TREE_FLAGS_INCLUDE_NODISPLAY);
 | 
			
		||||
  g_signal_connect (priv->apps_tree, "changed", G_CALLBACK (on_apps_tree_changed_cb), self);
 | 
			
		||||
 | 
			
		||||
  on_apps_tree_changed_cb (priv->apps_tree, self);
 | 
			
		||||
  monitor = g_app_info_monitor_get ();
 | 
			
		||||
  g_signal_connect (monitor, "changed", G_CALLBACK (installed_changed), self);
 | 
			
		||||
  installed_changed (monitor, self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -112,313 +133,13 @@ shell_app_system_finalize (GObject *object)
 | 
			
		||||
  ShellAppSystem *self = SHELL_APP_SYSTEM (object);
 | 
			
		||||
  ShellAppSystemPrivate *priv = self->priv;
 | 
			
		||||
 | 
			
		||||
  g_object_unref (priv->apps_tree);
 | 
			
		||||
 | 
			
		||||
  g_hash_table_destroy (priv->running_apps);
 | 
			
		||||
  g_hash_table_destroy (priv->id_to_app);
 | 
			
		||||
  g_hash_table_destroy (priv->visible_id_to_app);
 | 
			
		||||
  g_hash_table_destroy (priv->startup_wm_class_to_app);
 | 
			
		||||
 | 
			
		||||
  g_slist_free_full (priv->known_vendor_prefixes, g_free);
 | 
			
		||||
  priv->known_vendor_prefixes = NULL;
 | 
			
		||||
  g_hash_table_destroy (priv->startup_wm_class_to_id);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (shell_app_system_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *
 | 
			
		||||
get_prefix_for_entry (GMenuTreeEntry *entry)
 | 
			
		||||
{
 | 
			
		||||
  char *prefix = NULL, *file_prefix = NULL;
 | 
			
		||||
  const char *id;
 | 
			
		||||
  GFile *file;
 | 
			
		||||
  char *name;
 | 
			
		||||
  int i = 0;
 | 
			
		||||
 | 
			
		||||
  id = gmenu_tree_entry_get_desktop_file_id (entry);
 | 
			
		||||
  file = g_file_new_for_path (gmenu_tree_entry_get_desktop_file_path (entry));
 | 
			
		||||
  name = g_file_get_basename (file);
 | 
			
		||||
 | 
			
		||||
  if (!name)
 | 
			
		||||
    {
 | 
			
		||||
      g_object_unref (file);
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
  for (i = 0; vendor_prefixes[i]; i++)
 | 
			
		||||
    {
 | 
			
		||||
      if (g_str_has_prefix (name, vendor_prefixes[i]))
 | 
			
		||||
        {
 | 
			
		||||
          file_prefix = g_strdup (vendor_prefixes[i]);
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  while (strcmp (name, id) != 0)
 | 
			
		||||
    {
 | 
			
		||||
      char *t;
 | 
			
		||||
      char *pname;
 | 
			
		||||
      GFile *parent = g_file_get_parent (file);
 | 
			
		||||
 | 
			
		||||
      if (!parent)
 | 
			
		||||
        {
 | 
			
		||||
          g_warn_if_reached ();
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      pname = g_file_get_basename (parent);
 | 
			
		||||
      if (!pname)
 | 
			
		||||
        {
 | 
			
		||||
          g_object_unref (parent);
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
      if (!g_strstr_len (id, -1, pname))
 | 
			
		||||
        {
 | 
			
		||||
          /* handle <LegacyDir prefix="..."> */
 | 
			
		||||
          char *t;
 | 
			
		||||
          size_t name_len = strlen (name);
 | 
			
		||||
          size_t id_len = strlen (id);
 | 
			
		||||
          char *t_id = g_strdup (id);
 | 
			
		||||
 | 
			
		||||
          t_id[id_len - name_len] = '\0';
 | 
			
		||||
          t = g_strdup(t_id);
 | 
			
		||||
          g_free (prefix);
 | 
			
		||||
          g_free (t_id);
 | 
			
		||||
          g_free (name);
 | 
			
		||||
          name = g_strdup (id);
 | 
			
		||||
          prefix = t;
 | 
			
		||||
 | 
			
		||||
          g_object_unref (file);
 | 
			
		||||
          file = parent;
 | 
			
		||||
          g_free (pname);
 | 
			
		||||
          g_free (file_prefix);
 | 
			
		||||
          file_prefix = NULL;
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      t = g_strconcat (pname, "-", name, NULL);
 | 
			
		||||
      g_free (name);
 | 
			
		||||
      name = t;
 | 
			
		||||
 | 
			
		||||
      t = g_strconcat (pname, "-", prefix, NULL);
 | 
			
		||||
      g_free (prefix);
 | 
			
		||||
      prefix = t;
 | 
			
		||||
 | 
			
		||||
      g_object_unref (file);
 | 
			
		||||
      file = parent;
 | 
			
		||||
      g_free (pname);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (file)
 | 
			
		||||
    g_object_unref (file);
 | 
			
		||||
 | 
			
		||||
  if (strcmp (name, id) == 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_free (name);
 | 
			
		||||
      if (file_prefix && !prefix)
 | 
			
		||||
        return file_prefix;
 | 
			
		||||
      if (file_prefix)
 | 
			
		||||
        {
 | 
			
		||||
          char *t = g_strconcat (prefix, "-", file_prefix, NULL);
 | 
			
		||||
          g_free (prefix);
 | 
			
		||||
          g_free (file_prefix);
 | 
			
		||||
          prefix = t;
 | 
			
		||||
        }
 | 
			
		||||
      return prefix;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_free (name);
 | 
			
		||||
  g_free (prefix);
 | 
			
		||||
  g_free (file_prefix);
 | 
			
		||||
  g_return_val_if_reached (NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
get_flattened_entries_recurse (GMenuTreeDirectory *dir,
 | 
			
		||||
                               GHashTable         *entry_set)
 | 
			
		||||
{
 | 
			
		||||
  GMenuTreeIter *iter = gmenu_tree_directory_iter (dir);
 | 
			
		||||
  GMenuTreeItemType next_type;
 | 
			
		||||
 | 
			
		||||
  while ((next_type = gmenu_tree_iter_next (iter)) != GMENU_TREE_ITEM_INVALID)
 | 
			
		||||
    {
 | 
			
		||||
      gpointer item = NULL;
 | 
			
		||||
 | 
			
		||||
      switch (next_type)
 | 
			
		||||
        {
 | 
			
		||||
        case GMENU_TREE_ITEM_ENTRY:
 | 
			
		||||
          {
 | 
			
		||||
            GMenuTreeEntry *entry;
 | 
			
		||||
            item = entry = gmenu_tree_iter_get_entry (iter);
 | 
			
		||||
            /* Key is owned by entry */
 | 
			
		||||
            g_hash_table_replace (entry_set,
 | 
			
		||||
                                  (char*)gmenu_tree_entry_get_desktop_file_id (entry),
 | 
			
		||||
                                  gmenu_tree_item_ref (entry));
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
        case GMENU_TREE_ITEM_DIRECTORY:
 | 
			
		||||
          {
 | 
			
		||||
            item = gmenu_tree_iter_get_directory (iter);
 | 
			
		||||
            get_flattened_entries_recurse ((GMenuTreeDirectory*)item, entry_set);
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
        default:
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
      if (item != NULL)
 | 
			
		||||
        gmenu_tree_item_unref (item);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  gmenu_tree_iter_unref (iter);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GHashTable *
 | 
			
		||||
get_flattened_entries_from_tree (GMenuTree *tree)
 | 
			
		||||
{
 | 
			
		||||
  GHashTable *table;
 | 
			
		||||
  GMenuTreeDirectory *root;
 | 
			
		||||
 | 
			
		||||
  table = g_hash_table_new_full (g_str_hash, g_str_equal,
 | 
			
		||||
                                 (GDestroyNotify) NULL,
 | 
			
		||||
                                 (GDestroyNotify) gmenu_tree_item_unref);
 | 
			
		||||
 | 
			
		||||
  root = gmenu_tree_get_root_directory (tree);
 | 
			
		||||
  
 | 
			
		||||
  if (root != NULL)
 | 
			
		||||
    get_flattened_entries_recurse (root, table);
 | 
			
		||||
 | 
			
		||||
  gmenu_tree_item_unref (root);
 | 
			
		||||
  
 | 
			
		||||
  return table;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_apps_tree_changed_cb (GMenuTree *tree,
 | 
			
		||||
                         gpointer   user_data)
 | 
			
		||||
{
 | 
			
		||||
  ShellAppSystem *self = SHELL_APP_SYSTEM (user_data);
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
  GHashTable *new_apps;
 | 
			
		||||
  GHashTableIter iter;
 | 
			
		||||
  gpointer key, value;
 | 
			
		||||
 | 
			
		||||
  g_assert (tree == self->priv->apps_tree);
 | 
			
		||||
 | 
			
		||||
  g_hash_table_remove_all (self->priv->visible_id_to_app);
 | 
			
		||||
  g_slist_free_full (self->priv->known_vendor_prefixes, g_free);
 | 
			
		||||
  self->priv->known_vendor_prefixes = NULL;
 | 
			
		||||
 | 
			
		||||
  if (!gmenu_tree_load_sync (self->priv->apps_tree, &error))
 | 
			
		||||
    {
 | 
			
		||||
      if (error)
 | 
			
		||||
        {
 | 
			
		||||
          g_warning ("Failed to load apps: %s", error->message);
 | 
			
		||||
          g_error_free (error);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          g_warning ("Failed to load apps");
 | 
			
		||||
        }
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  new_apps = get_flattened_entries_from_tree (self->priv->apps_tree);
 | 
			
		||||
  g_hash_table_iter_init (&iter, new_apps);
 | 
			
		||||
  while (g_hash_table_iter_next (&iter, &key, &value))
 | 
			
		||||
    {
 | 
			
		||||
      const char *id = key;
 | 
			
		||||
      GMenuTreeEntry *entry = value;
 | 
			
		||||
      GMenuTreeEntry *old_entry;
 | 
			
		||||
      char *prefix;
 | 
			
		||||
      ShellApp *app;
 | 
			
		||||
      GDesktopAppInfo *info;
 | 
			
		||||
      const char *startup_wm_class;
 | 
			
		||||
 | 
			
		||||
      prefix = get_prefix_for_entry (entry);
 | 
			
		||||
 | 
			
		||||
      if (prefix != NULL
 | 
			
		||||
          && !g_slist_find_custom (self->priv->known_vendor_prefixes, prefix,
 | 
			
		||||
                                   (GCompareFunc)g_strcmp0))
 | 
			
		||||
        self->priv->known_vendor_prefixes = g_slist_append (self->priv->known_vendor_prefixes,
 | 
			
		||||
                                                            prefix);
 | 
			
		||||
      else
 | 
			
		||||
        g_free (prefix);
 | 
			
		||||
 | 
			
		||||
      app = g_hash_table_lookup (self->priv->id_to_app, id);
 | 
			
		||||
      if (app != NULL)
 | 
			
		||||
        {
 | 
			
		||||
          /* We hold a reference to the original entry temporarily,
 | 
			
		||||
           * because otherwise the hash table would be referencing
 | 
			
		||||
           * potentially free'd memory until we replace it below with
 | 
			
		||||
           * the new data.
 | 
			
		||||
           */
 | 
			
		||||
          old_entry = shell_app_get_tree_entry (app);
 | 
			
		||||
          gmenu_tree_item_ref (old_entry);
 | 
			
		||||
          _shell_app_set_entry (app, entry);
 | 
			
		||||
          g_object_ref (app);  /* Extra ref, removed in _replace below */
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          old_entry = NULL;
 | 
			
		||||
          app = _shell_app_new (entry);
 | 
			
		||||
        }
 | 
			
		||||
      /* Note that "id" is owned by app->entry.  Since we're always
 | 
			
		||||
       * setting a new entry, even if the app already exists in the
 | 
			
		||||
       * hash table we need to replace the key so that the new id
 | 
			
		||||
       * string is pointed to.
 | 
			
		||||
       */
 | 
			
		||||
      g_hash_table_replace (self->priv->id_to_app, (char*)id, app);
 | 
			
		||||
      if (!gmenu_tree_entry_get_is_nodisplay_recurse (entry))
 | 
			
		||||
        g_hash_table_replace (self->priv->visible_id_to_app, (char*)id, app);
 | 
			
		||||
 | 
			
		||||
      if (old_entry)
 | 
			
		||||
        {
 | 
			
		||||
          GDesktopAppInfo *old_info;
 | 
			
		||||
          const gchar *old_startup_wm_class;
 | 
			
		||||
 | 
			
		||||
          old_info = gmenu_tree_entry_get_app_info (old_entry);
 | 
			
		||||
          old_startup_wm_class = g_desktop_app_info_get_startup_wm_class (old_info);
 | 
			
		||||
 | 
			
		||||
          if (old_startup_wm_class)
 | 
			
		||||
            g_hash_table_remove (self->priv->startup_wm_class_to_app, old_startup_wm_class);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      info = gmenu_tree_entry_get_app_info (entry);
 | 
			
		||||
      startup_wm_class = g_desktop_app_info_get_startup_wm_class (info);
 | 
			
		||||
      if (startup_wm_class)
 | 
			
		||||
        g_hash_table_replace (self->priv->startup_wm_class_to_app,
 | 
			
		||||
                              (char*)startup_wm_class, g_object_ref (app));
 | 
			
		||||
 | 
			
		||||
      if (old_entry)
 | 
			
		||||
        gmenu_tree_item_unref (old_entry);
 | 
			
		||||
    }
 | 
			
		||||
  /* Now iterate over the apps again; we need to unreference any apps
 | 
			
		||||
   * which have been removed.  The JS code may still be holding a
 | 
			
		||||
   * reference; that's fine.
 | 
			
		||||
   */
 | 
			
		||||
  g_hash_table_iter_init (&iter, self->priv->id_to_app);
 | 
			
		||||
  while (g_hash_table_iter_next (&iter, &key, &value))
 | 
			
		||||
    {
 | 
			
		||||
      const char *id = key;
 | 
			
		||||
      
 | 
			
		||||
      if (!g_hash_table_lookup (new_apps, id))
 | 
			
		||||
        g_hash_table_iter_remove (&iter);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_hash_table_destroy (new_apps);
 | 
			
		||||
 | 
			
		||||
  g_signal_emit (self, signals[INSTALLED_CHANGED], 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * shell_app_system_get_tree:
 | 
			
		||||
 *
 | 
			
		||||
 * Return Value: (transfer none): The #GMenuTree for apps
 | 
			
		||||
 */
 | 
			
		||||
GMenuTree *
 | 
			
		||||
shell_app_system_get_tree (ShellAppSystem *self)
 | 
			
		||||
{
 | 
			
		||||
  return self->priv->apps_tree;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * shell_app_system_get_default:
 | 
			
		||||
 *
 | 
			
		||||
@@ -446,61 +167,20 @@ ShellApp *
 | 
			
		||||
shell_app_system_lookup_app (ShellAppSystem   *self,
 | 
			
		||||
                             const char       *id)
 | 
			
		||||
{
 | 
			
		||||
  return g_hash_table_lookup (self->priv->id_to_app, id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * shell_app_system_lookup_app_by_tree_entry:
 | 
			
		||||
 * @system: a #ShellAppSystem
 | 
			
		||||
 * @entry: a #GMenuTreeEntry
 | 
			
		||||
 *
 | 
			
		||||
 * Find a #ShellApp corresponding to a #GMenuTreeEntry.
 | 
			
		||||
 *
 | 
			
		||||
 * Return value: (transfer none): The #ShellApp for @entry, or %NULL if none
 | 
			
		||||
 */
 | 
			
		||||
ShellApp *
 | 
			
		||||
shell_app_system_lookup_app_by_tree_entry (ShellAppSystem  *self,
 | 
			
		||||
                                           GMenuTreeEntry  *entry)
 | 
			
		||||
{
 | 
			
		||||
  /* If we looked up directly in ->entry_to_app, we'd lose the
 | 
			
		||||
   * override of running apps.  Thus, indirect through the id.
 | 
			
		||||
   */
 | 
			
		||||
  return shell_app_system_lookup_app (self, gmenu_tree_entry_get_desktop_file_id (entry));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * shell_app_system_lookup_app_for_path:
 | 
			
		||||
 * @system: a #ShellAppSystem
 | 
			
		||||
 * @desktop_path: (type utf8): UTF-8 encoded absolute file name
 | 
			
		||||
 *
 | 
			
		||||
 * Find or create a #ShellApp corresponding to a given absolute file
 | 
			
		||||
 * name which must be in the standard paths (XDG_DATA_DIRS).  For
 | 
			
		||||
 * files outside the datadirs, this function returns %NULL.
 | 
			
		||||
 *
 | 
			
		||||
 * Return value: (transfer none): The #ShellApp for id, or %NULL if none
 | 
			
		||||
 */
 | 
			
		||||
ShellApp *
 | 
			
		||||
shell_app_system_lookup_app_for_path (ShellAppSystem   *system,
 | 
			
		||||
                                      const char       *desktop_path)
 | 
			
		||||
{
 | 
			
		||||
  const char *basename;
 | 
			
		||||
  const char *app_path;
 | 
			
		||||
  ShellAppSystemPrivate *priv = self->priv;
 | 
			
		||||
  ShellApp *app;
 | 
			
		||||
  GDesktopAppInfo *info;
 | 
			
		||||
 | 
			
		||||
  basename = g_strrstr (desktop_path, "/");
 | 
			
		||||
  if (basename)
 | 
			
		||||
    basename += 1;
 | 
			
		||||
  else
 | 
			
		||||
    basename = desktop_path;
 | 
			
		||||
  app = g_hash_table_lookup (priv->id_to_app, id);
 | 
			
		||||
  if (app)
 | 
			
		||||
    return app;
 | 
			
		||||
 | 
			
		||||
  app = shell_app_system_lookup_app (system, basename);
 | 
			
		||||
  if (!app)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  app_path = g_desktop_app_info_get_filename (shell_app_get_app_info (app));
 | 
			
		||||
  if (strcmp (desktop_path, app_path) != 0)
 | 
			
		||||
  info = g_desktop_app_info_new (id);
 | 
			
		||||
  if (!info)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  app = _shell_app_new (info);
 | 
			
		||||
  g_hash_table_insert (priv->id_to_app, (char *) id, app);
 | 
			
		||||
  return app;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -520,15 +200,15 @@ shell_app_system_lookup_heuristic_basename (ShellAppSystem *system,
 | 
			
		||||
                                            const char     *name)
 | 
			
		||||
{
 | 
			
		||||
  ShellApp *result;
 | 
			
		||||
  GSList *prefix;
 | 
			
		||||
  const char *const *prefix;
 | 
			
		||||
 | 
			
		||||
  result = shell_app_system_lookup_app (system, name);
 | 
			
		||||
  if (result != NULL)
 | 
			
		||||
    return result;
 | 
			
		||||
 | 
			
		||||
  for (prefix = system->priv->known_vendor_prefixes; prefix; prefix = g_slist_next (prefix))
 | 
			
		||||
  for (prefix = vendor_prefixes; *prefix != NULL; prefix++)
 | 
			
		||||
    {
 | 
			
		||||
      char *tmpid = g_strconcat ((char*)prefix->data, name, NULL);
 | 
			
		||||
      char *tmpid = g_strconcat (*prefix, name, NULL);
 | 
			
		||||
      result = shell_app_system_lookup_app (system, tmpid);
 | 
			
		||||
      g_free (tmpid);
 | 
			
		||||
      if (result != NULL)
 | 
			
		||||
@@ -603,10 +283,16 @@ ShellApp *
 | 
			
		||||
shell_app_system_lookup_startup_wmclass (ShellAppSystem *system,
 | 
			
		||||
                                         const char     *wmclass)
 | 
			
		||||
{
 | 
			
		||||
  const char *id;
 | 
			
		||||
 | 
			
		||||
  if (wmclass == NULL)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  return g_hash_table_lookup (system->priv->startup_wm_class_to_app, wmclass);
 | 
			
		||||
  id = g_hash_table_lookup (system->priv->startup_wm_class_to_id, wmclass);
 | 
			
		||||
  if (id == NULL)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  return shell_app_system_lookup_app (system, id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -661,136 +347,3 @@ shell_app_system_get_running (ShellAppSystem *self)
 | 
			
		||||
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static gint
 | 
			
		||||
compare_apps_by_usage (gconstpointer a,
 | 
			
		||||
                       gconstpointer b,
 | 
			
		||||
                       gpointer      data)
 | 
			
		||||
{
 | 
			
		||||
  ShellAppUsage *usage = shell_app_usage_get_default ();
 | 
			
		||||
 | 
			
		||||
  ShellApp *app_a = (ShellApp*)a;
 | 
			
		||||
  ShellApp *app_b = (ShellApp*)b;
 | 
			
		||||
 | 
			
		||||
  return shell_app_usage_compare (usage, "", app_a, app_b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GSList *
 | 
			
		||||
sort_and_concat_results (ShellAppSystem *system,
 | 
			
		||||
                         GSList         *prefix_matches,
 | 
			
		||||
                         GSList         *substring_matches)
 | 
			
		||||
{
 | 
			
		||||
  prefix_matches = g_slist_sort_with_data (prefix_matches,
 | 
			
		||||
                                           compare_apps_by_usage,
 | 
			
		||||
                                           system);
 | 
			
		||||
  substring_matches = g_slist_sort_with_data (substring_matches,
 | 
			
		||||
                                              compare_apps_by_usage,
 | 
			
		||||
                                              system);
 | 
			
		||||
  return g_slist_concat (prefix_matches, substring_matches);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * normalize_terms:
 | 
			
		||||
 * @terms: (element-type utf8): Input search terms
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: (element-type utf8) (transfer full): Unicode-normalized and lowercased terms
 | 
			
		||||
 */
 | 
			
		||||
static GSList *
 | 
			
		||||
normalize_terms (GSList *terms)
 | 
			
		||||
{
 | 
			
		||||
  GSList *normalized_terms = NULL;
 | 
			
		||||
  GSList *iter;
 | 
			
		||||
  for (iter = terms; iter; iter = iter->next)
 | 
			
		||||
    {
 | 
			
		||||
      const char *term = iter->data;
 | 
			
		||||
      normalized_terms = g_slist_prepend (normalized_terms,
 | 
			
		||||
                                          shell_util_normalize_casefold_and_unaccent (term));
 | 
			
		||||
    }
 | 
			
		||||
  return normalized_terms;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GSList *
 | 
			
		||||
search_tree (ShellAppSystem *self,
 | 
			
		||||
             GSList         *terms,
 | 
			
		||||
             GHashTable     *apps)
 | 
			
		||||
{
 | 
			
		||||
  GSList *prefix_results = NULL;
 | 
			
		||||
  GSList *substring_results = NULL;
 | 
			
		||||
  GSList *normalized_terms;
 | 
			
		||||
  GHashTableIter iter;
 | 
			
		||||
  gpointer key, value;
 | 
			
		||||
 | 
			
		||||
  normalized_terms = normalize_terms (terms);
 | 
			
		||||
 | 
			
		||||
  g_hash_table_iter_init (&iter, apps);
 | 
			
		||||
  while (g_hash_table_iter_next (&iter, &key, &value))
 | 
			
		||||
    {
 | 
			
		||||
      ShellApp *app = value;
 | 
			
		||||
      _shell_app_do_match (app, normalized_terms,
 | 
			
		||||
                           &prefix_results,
 | 
			
		||||
                           &substring_results);
 | 
			
		||||
    }
 | 
			
		||||
  g_slist_free_full (normalized_terms, g_free);
 | 
			
		||||
 | 
			
		||||
  return sort_and_concat_results (self, prefix_results, substring_results);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * shell_app_system_initial_search:
 | 
			
		||||
 * @system: A #ShellAppSystem
 | 
			
		||||
 * @terms: (element-type utf8): List of terms, logical AND
 | 
			
		||||
 *
 | 
			
		||||
 * Search through applications for the given search terms.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: (transfer container) (element-type ShellApp): List of applications
 | 
			
		||||
 */
 | 
			
		||||
GSList *
 | 
			
		||||
shell_app_system_initial_search (ShellAppSystem  *self,
 | 
			
		||||
                                 GSList          *terms)
 | 
			
		||||
{
 | 
			
		||||
  return search_tree (self, terms, self->priv->visible_id_to_app);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * shell_app_system_subsearch:
 | 
			
		||||
 * @system: A #ShellAppSystem
 | 
			
		||||
 * @previous_results: (element-type ShellApp): List of previous results
 | 
			
		||||
 * @terms: (element-type utf8): List of terms, logical AND
 | 
			
		||||
 *
 | 
			
		||||
 * Search through a previous result set; for more information, see
 | 
			
		||||
 * js/ui/search.js.  Note the value of @prefs must be
 | 
			
		||||
 * the same as passed to shell_app_system_initial_search().  Note that returned
 | 
			
		||||
 * strings are only valid until a return to the main loop.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: (transfer container) (element-type ShellApp): List of application identifiers
 | 
			
		||||
 */
 | 
			
		||||
GSList *
 | 
			
		||||
shell_app_system_subsearch (ShellAppSystem   *system,
 | 
			
		||||
                            GSList           *previous_results,
 | 
			
		||||
                            GSList           *terms)
 | 
			
		||||
{
 | 
			
		||||
  GSList *iter;
 | 
			
		||||
  GSList *prefix_results = NULL;
 | 
			
		||||
  GSList *substring_results = NULL;
 | 
			
		||||
  GSList *normalized_terms = normalize_terms (terms);
 | 
			
		||||
 | 
			
		||||
  previous_results = g_slist_reverse (previous_results);
 | 
			
		||||
 | 
			
		||||
  for (iter = previous_results; iter; iter = iter->next)
 | 
			
		||||
    {
 | 
			
		||||
      ShellApp *app = iter->data;
 | 
			
		||||
      
 | 
			
		||||
      _shell_app_do_match (app, normalized_terms,
 | 
			
		||||
                           &prefix_results,
 | 
			
		||||
                           &substring_results);
 | 
			
		||||
    }
 | 
			
		||||
  g_slist_free_full (normalized_terms, g_free);
 | 
			
		||||
 | 
			
		||||
  /* Note that a shorter term might have matched as a prefix, but
 | 
			
		||||
     when extended only as a substring, so we have to redo the
 | 
			
		||||
     sort rather than reusing the existing ordering */
 | 
			
		||||
  return sort_and_concat_results (system, prefix_results, substring_results);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,6 @@
 | 
			
		||||
#include <gio/gio.h>
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
#include <meta/window.h>
 | 
			
		||||
#define GMENU_I_KNOW_THIS_IS_UNSTABLE
 | 
			
		||||
#include <gmenu-tree.h>
 | 
			
		||||
 | 
			
		||||
#include "shell-app.h"
 | 
			
		||||
 | 
			
		||||
@@ -39,14 +37,8 @@ struct _ShellAppSystemClass
 | 
			
		||||
GType           shell_app_system_get_type    (void) G_GNUC_CONST;
 | 
			
		||||
ShellAppSystem *shell_app_system_get_default (void);
 | 
			
		||||
 | 
			
		||||
GMenuTree      *shell_app_system_get_tree                     (ShellAppSystem *system);
 | 
			
		||||
 | 
			
		||||
ShellApp       *shell_app_system_lookup_app                   (ShellAppSystem  *system,
 | 
			
		||||
                                                               const char      *id);
 | 
			
		||||
ShellApp       *shell_app_system_lookup_app_by_tree_entry     (ShellAppSystem  *system,
 | 
			
		||||
                                                               GMenuTreeEntry  *entry);
 | 
			
		||||
ShellApp       *shell_app_system_lookup_app_for_path          (ShellAppSystem  *system,
 | 
			
		||||
                                                               const char      *desktop_path);
 | 
			
		||||
ShellApp       *shell_app_system_lookup_heuristic_basename    (ShellAppSystem  *system,
 | 
			
		||||
                                                               const char      *id);
 | 
			
		||||
 | 
			
		||||
@@ -57,10 +49,4 @@ ShellApp       *shell_app_system_lookup_desktop_wmclass       (ShellAppSystem *s
 | 
			
		||||
 | 
			
		||||
GSList         *shell_app_system_get_running               (ShellAppSystem  *self);
 | 
			
		||||
 | 
			
		||||
GSList         *shell_app_system_initial_search            (ShellAppSystem  *system,
 | 
			
		||||
                                                            GSList          *terms);
 | 
			
		||||
GSList         *shell_app_system_subsearch                 (ShellAppSystem  *system,
 | 
			
		||||
                                                            GSList          *previous_results,
 | 
			
		||||
                                                            GSList          *terms);
 | 
			
		||||
 | 
			
		||||
#endif /* __SHELL_APP_SYSTEM_H__ */
 | 
			
		||||
 
 | 
			
		||||
@@ -527,19 +527,19 @@ shell_app_usage_get_most_used (ShellAppUsage   *self,
 | 
			
		||||
 * shell_app_usage_compare:
 | 
			
		||||
 * @self: the usage instance to request
 | 
			
		||||
 * @context: Activity identifier
 | 
			
		||||
 * @app_a: First app
 | 
			
		||||
 * @app_b: Second app
 | 
			
		||||
 * @id_a: ID of first app
 | 
			
		||||
 * @id_b: ID of second app
 | 
			
		||||
 *
 | 
			
		||||
 * Compare @app_a and @app_b based on frequency of use.
 | 
			
		||||
 * Compare @id_a and @id_b based on frequency of use.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: -1 if @app_a ranks higher than @app_b, 1 if @app_b ranks higher
 | 
			
		||||
 *          than @app_a, and 0 if both rank equally.
 | 
			
		||||
 * Returns: -1 if @id_a ranks higher than @id_b, 1 if @id_b ranks higher
 | 
			
		||||
 *          than @id_a, and 0 if both rank equally.
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
shell_app_usage_compare (ShellAppUsage *self,
 | 
			
		||||
                         const char    *context,
 | 
			
		||||
                         ShellApp      *app_a,
 | 
			
		||||
                         ShellApp      *app_b)
 | 
			
		||||
                         const char    *id_a,
 | 
			
		||||
                         const char    *id_b)
 | 
			
		||||
{
 | 
			
		||||
  GHashTable *usages;
 | 
			
		||||
  UsageData *usage_a, *usage_b;
 | 
			
		||||
@@ -548,8 +548,8 @@ shell_app_usage_compare (ShellAppUsage *self,
 | 
			
		||||
  if (usages == NULL)
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
  usage_a = g_hash_table_lookup (usages, shell_app_get_id (app_a));
 | 
			
		||||
  usage_b = g_hash_table_lookup (usages, shell_app_get_id (app_b));
 | 
			
		||||
  usage_a = g_hash_table_lookup (usages, id_a);
 | 
			
		||||
  usage_b = g_hash_table_lookup (usages, id_b);
 | 
			
		||||
 | 
			
		||||
  if (usage_a == NULL && usage_b == NULL)
 | 
			
		||||
    return 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -31,8 +31,8 @@ GSList *shell_app_usage_get_most_used (ShellAppUsage *usage,
 | 
			
		||||
                                       const char    *context);
 | 
			
		||||
int shell_app_usage_compare (ShellAppUsage *self,
 | 
			
		||||
                             const char    *context,
 | 
			
		||||
                             ShellApp      *app_a,
 | 
			
		||||
                             ShellApp      *app_b);
 | 
			
		||||
                             const char    *id_a,
 | 
			
		||||
                             const char    *id_b);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -53,7 +53,7 @@ typedef struct {
 | 
			
		||||
 * SECTION:shell-app
 | 
			
		||||
 * @short_description: Object representing an application
 | 
			
		||||
 *
 | 
			
		||||
 * This object wraps a #GMenuTreeEntry, providing methods and signals
 | 
			
		||||
 * This object wraps a #GDesktopAppInfo, providing methods and signals
 | 
			
		||||
 * primarily useful for running applications.
 | 
			
		||||
 */
 | 
			
		||||
struct _ShellApp
 | 
			
		||||
@@ -64,7 +64,7 @@ struct _ShellApp
 | 
			
		||||
 | 
			
		||||
  ShellAppState state;
 | 
			
		||||
 | 
			
		||||
  GMenuTreeEntry *entry; /* If NULL, this app is backed by one or more
 | 
			
		||||
  GDesktopAppInfo *info; /* If NULL, this app is backed by one or more
 | 
			
		||||
                          * MetaWindow.  For purposes of app title
 | 
			
		||||
                          * etc., we use the first window added,
 | 
			
		||||
                          * because it's most likely to be what we
 | 
			
		||||
@@ -137,15 +137,15 @@ shell_app_get_property (GObject    *gobject,
 | 
			
		||||
const char *
 | 
			
		||||
shell_app_get_id (ShellApp *app)
 | 
			
		||||
{
 | 
			
		||||
  if (app->entry)
 | 
			
		||||
    return gmenu_tree_entry_get_desktop_file_id (app->entry);
 | 
			
		||||
  if (app->info)
 | 
			
		||||
    return g_app_info_get_id (G_APP_INFO (app->info));
 | 
			
		||||
  return app->window_id_string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaWindow *
 | 
			
		||||
window_backed_app_get_window (ShellApp     *app)
 | 
			
		||||
{
 | 
			
		||||
  g_assert (app->entry == NULL);
 | 
			
		||||
  g_assert (app->info == NULL);
 | 
			
		||||
  g_assert (app->running_state);
 | 
			
		||||
  g_assert (app->running_state->windows);
 | 
			
		||||
  return app->running_state->windows->data;
 | 
			
		||||
@@ -194,10 +194,10 @@ shell_app_create_icon_texture (ShellApp   *app,
 | 
			
		||||
 | 
			
		||||
  ret = NULL;
 | 
			
		||||
 | 
			
		||||
  if (app->entry == NULL)
 | 
			
		||||
  if (app->info == NULL)
 | 
			
		||||
    return window_backed_app_get_icon (app, size);
 | 
			
		||||
 | 
			
		||||
  icon = g_app_info_get_icon (G_APP_INFO (gmenu_tree_entry_get_app_info (app->entry)));
 | 
			
		||||
  icon = g_app_info_get_icon (G_APP_INFO (app->info));
 | 
			
		||||
  if (icon != NULL)
 | 
			
		||||
    ret = st_texture_cache_load_gicon (st_texture_cache_get_default (), NULL, icon, size);
 | 
			
		||||
 | 
			
		||||
@@ -245,7 +245,7 @@ shell_app_create_faded_icon_cpu (StTextureCache *cache,
 | 
			
		||||
 | 
			
		||||
  info = NULL;
 | 
			
		||||
 | 
			
		||||
  icon = g_app_info_get_icon (G_APP_INFO (gmenu_tree_entry_get_app_info (app->entry)));
 | 
			
		||||
  icon = g_app_info_get_icon (G_APP_INFO (app->info));
 | 
			
		||||
  if (icon != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      info = gtk_icon_theme_lookup_by_gicon (gtk_icon_theme_get_default (),
 | 
			
		||||
@@ -347,7 +347,7 @@ shell_app_get_faded_icon (ShellApp *app, int size, ClutterTextDirection directio
 | 
			
		||||
   * property tracking bits, and this helps us visually distinguish
 | 
			
		||||
   * app-tracked from not.
 | 
			
		||||
   */
 | 
			
		||||
  if (!app->entry)
 | 
			
		||||
  if (!app->info)
 | 
			
		||||
    return window_backed_app_get_icon (app, size);
 | 
			
		||||
 | 
			
		||||
  /* Use icon: prefix so that we get evicted from the cache on
 | 
			
		||||
@@ -384,8 +384,8 @@ shell_app_get_faded_icon (ShellApp *app, int size, ClutterTextDirection directio
 | 
			
		||||
const char *
 | 
			
		||||
shell_app_get_name (ShellApp *app)
 | 
			
		||||
{
 | 
			
		||||
  if (app->entry)
 | 
			
		||||
    return g_app_info_get_name (G_APP_INFO (gmenu_tree_entry_get_app_info (app->entry)));
 | 
			
		||||
  if (app->info)
 | 
			
		||||
    return g_app_info_get_name (G_APP_INFO (app->info));
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      MetaWindow *window = window_backed_app_get_window (app);
 | 
			
		||||
@@ -401,8 +401,8 @@ shell_app_get_name (ShellApp *app)
 | 
			
		||||
const char *
 | 
			
		||||
shell_app_get_description (ShellApp *app)
 | 
			
		||||
{
 | 
			
		||||
  if (app->entry)
 | 
			
		||||
    return g_app_info_get_description (G_APP_INFO (gmenu_tree_entry_get_app_info (app->entry)));
 | 
			
		||||
  if (app->info)
 | 
			
		||||
    return g_app_info_get_description (G_APP_INFO (app->info));
 | 
			
		||||
  else
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
@@ -417,7 +417,7 @@ shell_app_get_description (ShellApp *app)
 | 
			
		||||
gboolean
 | 
			
		||||
shell_app_is_window_backed (ShellApp *app)
 | 
			
		||||
{
 | 
			
		||||
  return app->entry == NULL;
 | 
			
		||||
  return app->info == NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
@@ -670,7 +670,7 @@ void
 | 
			
		||||
shell_app_open_new_window (ShellApp      *app,
 | 
			
		||||
                           int            workspace)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (app->entry != NULL);
 | 
			
		||||
  g_return_if_fail (app->info != NULL);
 | 
			
		||||
 | 
			
		||||
  /* Here we just always launch the application again, even if we know
 | 
			
		||||
   * it was already running.  For most applications this
 | 
			
		||||
@@ -865,25 +865,24 @@ _shell_app_new_for_window (MetaWindow      *window)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ShellApp *
 | 
			
		||||
_shell_app_new (GMenuTreeEntry *info)
 | 
			
		||||
_shell_app_new (GDesktopAppInfo *info)
 | 
			
		||||
{
 | 
			
		||||
  ShellApp *app;
 | 
			
		||||
 | 
			
		||||
  app = g_object_new (SHELL_TYPE_APP, NULL);
 | 
			
		||||
 | 
			
		||||
  _shell_app_set_entry (app, info);
 | 
			
		||||
  _shell_app_set_app_info (app, info);
 | 
			
		||||
 | 
			
		||||
  return app;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
_shell_app_set_entry (ShellApp       *app,
 | 
			
		||||
                      GMenuTreeEntry *entry)
 | 
			
		||||
_shell_app_set_app_info (ShellApp        *app,
 | 
			
		||||
                         GDesktopAppInfo *info)
 | 
			
		||||
{
 | 
			
		||||
  if (app->entry != NULL)
 | 
			
		||||
    gmenu_tree_item_unref (app->entry);
 | 
			
		||||
  app->entry = gmenu_tree_item_ref (entry);
 | 
			
		||||
  
 | 
			
		||||
  g_clear_object (&app->info);
 | 
			
		||||
  app->info = g_object_ref (info);
 | 
			
		||||
 | 
			
		||||
  if (app->name_collation_key != NULL)
 | 
			
		||||
    g_free (app->name_collation_key);
 | 
			
		||||
  app->name_collation_key = g_utf8_collate_key (shell_app_get_name (app), -1);
 | 
			
		||||
@@ -1188,7 +1187,6 @@ shell_app_launch (ShellApp     *app,
 | 
			
		||||
                  char        **startup_id,
 | 
			
		||||
                  GError      **error)
 | 
			
		||||
{
 | 
			
		||||
  GDesktopAppInfo *gapp;
 | 
			
		||||
  GdkAppLaunchContext *context;
 | 
			
		||||
  gboolean ret;
 | 
			
		||||
  ShellGlobal *global;
 | 
			
		||||
@@ -1198,7 +1196,7 @@ shell_app_launch (ShellApp     *app,
 | 
			
		||||
  if (startup_id)
 | 
			
		||||
    *startup_id = NULL;
 | 
			
		||||
 | 
			
		||||
  if (app->entry == NULL)
 | 
			
		||||
  if (app->info == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      MetaWindow *window = window_backed_app_get_window (app);
 | 
			
		||||
      /* We can't pass URIs into a window; shouldn't hit this
 | 
			
		||||
@@ -1224,8 +1222,7 @@ shell_app_launch (ShellApp     *app,
 | 
			
		||||
  gdk_app_launch_context_set_timestamp (context, timestamp);
 | 
			
		||||
  gdk_app_launch_context_set_desktop (context, workspace);
 | 
			
		||||
 | 
			
		||||
  gapp = gmenu_tree_entry_get_app_info (app->entry);
 | 
			
		||||
  ret = g_desktop_app_info_launch_uris_as_manager (gapp, uris,
 | 
			
		||||
  ret = g_desktop_app_info_launch_uris_as_manager (app->info, uris,
 | 
			
		||||
                                                   G_APP_LAUNCH_CONTEXT (context),
 | 
			
		||||
                                                   G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
 | 
			
		||||
                                                   NULL, NULL,
 | 
			
		||||
@@ -1245,21 +1242,7 @@ shell_app_launch (ShellApp     *app,
 | 
			
		||||
GDesktopAppInfo *
 | 
			
		||||
shell_app_get_app_info (ShellApp *app)
 | 
			
		||||
{
 | 
			
		||||
  if (app->entry)
 | 
			
		||||
    return gmenu_tree_entry_get_app_info (app->entry);
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * shell_app_get_tree_entry:
 | 
			
		||||
 * @app: a #ShellApp
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: (transfer none): The #GMenuTreeEntry for this app, or %NULL if backed by a window
 | 
			
		||||
 */
 | 
			
		||||
GMenuTreeEntry *
 | 
			
		||||
shell_app_get_tree_entry (ShellApp *app)
 | 
			
		||||
{
 | 
			
		||||
  return app->entry;
 | 
			
		||||
  return app->info;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -1374,24 +1357,22 @@ shell_app_init_search_data (ShellApp *app)
 | 
			
		||||
  const char *exec;
 | 
			
		||||
  const char * const *keywords;
 | 
			
		||||
  char *normalized_exec;
 | 
			
		||||
  GDesktopAppInfo *appinfo;
 | 
			
		||||
 | 
			
		||||
  appinfo = gmenu_tree_entry_get_app_info (app->entry);
 | 
			
		||||
  name = g_app_info_get_name (G_APP_INFO (appinfo));
 | 
			
		||||
  name = g_app_info_get_name (G_APP_INFO (app->info));
 | 
			
		||||
  app->casefolded_name = shell_util_normalize_casefold_and_unaccent (name);
 | 
			
		||||
 | 
			
		||||
  generic_name = g_desktop_app_info_get_generic_name (appinfo);
 | 
			
		||||
  generic_name = g_desktop_app_info_get_generic_name (app->info);
 | 
			
		||||
  if (generic_name)
 | 
			
		||||
    app->casefolded_generic_name = shell_util_normalize_casefold_and_unaccent (generic_name);
 | 
			
		||||
  else
 | 
			
		||||
    app->casefolded_generic_name = NULL;
 | 
			
		||||
 | 
			
		||||
  exec = g_app_info_get_executable (G_APP_INFO (appinfo));
 | 
			
		||||
  exec = g_app_info_get_executable (G_APP_INFO (app->info));
 | 
			
		||||
  normalized_exec = shell_util_normalize_casefold_and_unaccent (exec);
 | 
			
		||||
  app->casefolded_exec = trim_exec_line (normalized_exec);
 | 
			
		||||
  g_free (normalized_exec);
 | 
			
		||||
 | 
			
		||||
  keywords = g_desktop_app_info_get_keywords (appinfo);
 | 
			
		||||
  keywords = g_desktop_app_info_get_keywords (app->info);
 | 
			
		||||
 | 
			
		||||
  if (keywords)
 | 
			
		||||
    {
 | 
			
		||||
@@ -1512,16 +1493,14 @@ _shell_app_do_match (ShellApp         *app,
 | 
			
		||||
                     GSList          **substring_results)
 | 
			
		||||
{
 | 
			
		||||
  ShellAppSearchMatch match;
 | 
			
		||||
  GAppInfo *appinfo;
 | 
			
		||||
 | 
			
		||||
  g_assert (app != NULL);
 | 
			
		||||
 | 
			
		||||
  /* Skip window-backed apps */ 
 | 
			
		||||
  appinfo = (GAppInfo*)shell_app_get_app_info (app);
 | 
			
		||||
  if (appinfo == NULL)
 | 
			
		||||
  if (app->info == NULL)
 | 
			
		||||
    return;
 | 
			
		||||
  /* Skip not-visible apps */ 
 | 
			
		||||
  if (!g_app_info_should_show (appinfo))
 | 
			
		||||
  if (!g_app_info_should_show (G_APP_INFO (app->info)))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  match = _shell_app_match_search_terms (app, terms);
 | 
			
		||||
@@ -1550,11 +1529,7 @@ shell_app_dispose (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  ShellApp *app = SHELL_APP (object);
 | 
			
		||||
 | 
			
		||||
  if (app->entry)
 | 
			
		||||
    {
 | 
			
		||||
      gmenu_tree_item_unref (app->entry);
 | 
			
		||||
      app->entry = NULL;
 | 
			
		||||
    }
 | 
			
		||||
  g_clear_object (&app->info);
 | 
			
		||||
 | 
			
		||||
  if (app->running_state)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,9 +4,8 @@
 | 
			
		||||
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
#include <gio/gio.h>
 | 
			
		||||
#include <gio/gdesktopappinfo.h>
 | 
			
		||||
#include <meta/window.h>
 | 
			
		||||
#define GMENU_I_KNOW_THIS_IS_UNSTABLE
 | 
			
		||||
#include <gmenu-tree.h>
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
@@ -39,7 +38,6 @@ GType shell_app_get_type (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
const char *shell_app_get_id (ShellApp *app);
 | 
			
		||||
 | 
			
		||||
GMenuTreeEntry *shell_app_get_tree_entry (ShellApp *app);
 | 
			
		||||
GDesktopAppInfo *shell_app_get_app_info (ShellApp *app);
 | 
			
		||||
 | 
			
		||||
ClutterActor *shell_app_create_icon_texture (ShellApp *app, int size);
 | 
			
		||||
 
 | 
			
		||||
@@ -844,6 +844,7 @@ ShellApp *
 | 
			
		||||
shell_startup_sequence_get_app (ShellStartupSequence *sequence)
 | 
			
		||||
{
 | 
			
		||||
  const char *appid;
 | 
			
		||||
  char *basename;
 | 
			
		||||
  ShellAppSystem *appsys;
 | 
			
		||||
  ShellApp *app;
 | 
			
		||||
 | 
			
		||||
@@ -851,8 +852,10 @@ shell_startup_sequence_get_app (ShellStartupSequence *sequence)
 | 
			
		||||
  if (!appid)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  basename = g_path_get_basename (appid);
 | 
			
		||||
  appsys = shell_app_system_get_default ();
 | 
			
		||||
  app = shell_app_system_lookup_app_for_path (appsys, appid);
 | 
			
		||||
  app = shell_app_system_lookup_app (appsys, basename);
 | 
			
		||||
  g_free (basename);
 | 
			
		||||
  return app;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user