From 9df09db5fe7c4de8ef004b7a08e6e638b451a6c0 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Sun, 15 Dec 2013 22:24:25 -0500 Subject: [PATCH] appDisplay: Use the new org.gnome.desktop.app-folders schema for grouping Rather than GMenu / app-folder-categories. This removes our last use of gnome-menus in the stock gnome-shell, which is exciting, but also means that app folders in Software start working. Ideally, we'd have a button to launch our Software app as well from the overview. https://bugzilla.gnome.org/show_bug.cgi?id=722117 --- data/org.gnome.shell.gschema.xml.in.in | 8 -- js/ui/appDisplay.js | 131 ++++++++++++------------- 2 files changed, 65 insertions(+), 74 deletions(-) diff --git a/data/org.gnome.shell.gschema.xml.in.in b/data/org.gnome.shell.gschema.xml.in.in index d56feccfc..617bc3868 100644 --- a/data/org.gnome.shell.gschema.xml.in.in +++ b/data/org.gnome.shell.gschema.xml.in.in @@ -29,14 +29,6 @@ will be displayed in the favorites area. - - [ 'Utilities', 'Sundry' ] - <_summary>List of categories that should be displayed as folders - <_description> - Each category name in this list will be represented as folder in the - application view, rather than being displayed inline in the main view. - - 0 App Picker View diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js index 7bc063b99..154ddaa23 100644 --- a/js/ui/appDisplay.js +++ b/js/ui/appDisplay.js @@ -5,7 +5,6 @@ const Gio = imports.gi.Gio; const GLib = imports.gi.GLib; const GObject = imports.gi.GObject; const Gtk = imports.gi.Gtk; -const GMenu = imports.gi.GMenu; const Shell = imports.gi.Shell; const Lang = imports.lang; const Signals = imports.signals; @@ -52,23 +51,22 @@ function _isTerminal(app) { return categories.indexOf('TerminalEmulator') > -1; } -// Recursively load a GMenuTreeDirectory; we could put this in ShellAppSystem too -function _loadCategory(dir, view) { - let iter = dir.iter(); - let appSystem = Shell.AppSystem.get_default(); - let nextType; - while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) { - if (nextType == GMenu.TreeItemType.ENTRY) { - let entry = iter.get_entry(); - 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(); - _loadCategory(itemDir, view); +function _getFolderName(folder) { + let name = folder.get_string('name'); + + if (folder.get_boolean('translate')) { + let keyfile = new GLib.KeyFile(); + let path = 'desktop-directories/' + name; + + try { + keyfile.load_from_data_dirs(path, GLib.KeyFileFlags.NONE); + name = keyfile.get_locale_string('Desktop Entry', 'Name', null); + } catch(e) { + return name; } } + + return name; } const BaseAppView = new Lang.Class({ @@ -102,7 +100,7 @@ const BaseAppView = new Lang.Class({ this._allItems = []; }, - _addItem: function(icon) { + addItem: function(icon) { let id = icon.id; if (this._items[id] !== undefined) return; @@ -268,7 +266,7 @@ const AllView = new Lang.Class({ this._pageIndicators.actor.connect('scroll-event', Lang.bind(this, this._onScroll)); this.actor.add_actor(this._pageIndicators.actor); - this._folderIcons = []; + this.folderIcons = []; this._stack = new St.Widget({ layout_manager: new Clutter.BinLayout() }); let box = new St.BoxLayout({ vertical: true }); @@ -455,27 +453,10 @@ const AllView = new Lang.Class({ }, removeAll: function() { - this._folderIcons = []; + this.folderIcons = []; this.parent(); }, - addApp: function(app) { - let icon = new AppIcon(app); - this._addItem(icon); - if (icon) - icon.actor.connect('key-focus-in', - Lang.bind(this, this._ensureIconVisible)); - }, - - addFolder: function(dir) { - let icon = new FolderIcon(dir, this); - this._addItem(icon); - this._folderIcons.push(icon); - if (icon) - icon.actor.connect('key-focus-in', - Lang.bind(this, this._ensureIconVisible)); - }, - addFolderPopup: function(popup) { this._stack.add_actor(popup.actor); popup.connect('open-state-changed', Lang.bind(this, @@ -540,8 +521,8 @@ const AllView = new Lang.Class({ this._availWidth = availWidth; this._availHeight = availHeight; // Update folder views - for (let i = 0; i < this._folderIcons.length; i++) - this._folderIcons[i].adaptToSize(availWidth, availHeight); + for (let i = 0; i < this.folderIcons.length; i++) + this.folderIcons[i].adaptToSize(availWidth, availHeight); } }); Signals.addSignalMethods(AllView.prototype); @@ -664,7 +645,8 @@ const AppDisplay = new Lang.Class({ Main.overview.connect('showing', Lang.bind(this, function() { Main.queueDeferredWork(this._frequentAppsWorkId); })); - global.settings.connect('changed::app-folder-categories', Lang.bind(this, function() { + this._folderSettings = new Gio.Settings({ schema: 'org.gnome.desktop.app-folders' }); + this._folderSettings.connect('changed::folder-children', Lang.bind(this, function() { Main.queueDeferredWork(this._allAppsWorkId); })); this._privacySettings = new Gio.Settings({ schema: 'org.gnome.desktop.privacy' }); @@ -776,26 +758,42 @@ const AppDisplay = new Lang.Class({ _redisplayAllApps: function() { let view = this._views[Views.ALL].view; - view.removeAll(); - let tree = new GMenu.Tree({ menu_basename: "applications.menu" }); - tree.load_sync(); - let root = tree.get_root_directory(); + let apps = Gio.AppInfo.get_all().filter(function(appInfo) { + return appInfo.should_show(); + }).map(function(app) { + return app.get_id(); + }); - let iter = root.iter(); - let nextType; - let folderCategories = global.settings.get_strv('app-folder-categories'); - while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) { - if (nextType == GMenu.TreeItemType.DIRECTORY) { - let dir = iter.get_directory(); + let appSys = Shell.AppSystem.get_default(); + + let folders = this._folderSettings.get_strv('folder-children'); + folders.forEach(Lang.bind(this, function(id) { + let folder = new Gio.Settings({ schema_id: 'org.gnome.desktop.app-folders.folder', + path: this._folderSettings.path + 'folders/' + id + '/' }); + folder.connect('changed', Lang.bind(this, function() { + Main.queueDeferredWork(this._allAppsWorkId); + })); + + let folderName = _getFolderName(folder); + let folderApps = folder.get_strv('apps'); + folderApps.forEach(function(appId) { + let idx = apps.indexOf(appId); + if (idx >= 0) + apps.splice(idx, 1); + }); + let icon = new FolderIcon(id, folderName, folderApps, view); + view.addItem(icon); + view.folderIcons.push(icon); + })); + + apps.forEach(Lang.bind(this, function(appId) { + let app = appSys.lookup_app(appId); + let icon = new AppIcon(app); + view.addItem(icon); + })); - if (folderCategories.indexOf(dir.get_menu_id()) != -1) - view.addFolder(dir); - else - _loadCategory(dir, view); - } - } view.loadGrid(); if (this._focusDummy) { @@ -919,11 +917,6 @@ const FolderView = new Lang.Class({ this.actor.add_action(action); }, - addApp: function(app) { - let icon = new AppIcon(app); - this._addItem(icon); - }, - createFolderIcon: function(size) { let icon = new St.Widget({ layout_manager: new Clutter.BinLayout(), style_class: 'app-folder-icon', @@ -1009,11 +1002,9 @@ const FolderView = new Lang.Class({ const FolderIcon = new Lang.Class({ Name: 'FolderIcon', - _init: function(dir, parentView) { - this._dir = dir; - this.id = dir.get_menu_id(); - this.name = dir.get_name(); - + _init: function(id, name, apps, parentView) { + this.id = id; + this.name = name; this._parentView = parentView; this.actor = new St.Button({ style_class: 'app-well-app app-folder', @@ -1032,7 +1023,15 @@ const FolderIcon = new Lang.Class({ this.actor.label_actor = this.icon.label; this.view = new FolderView(); - _loadCategory(dir, this.view); + let appSys = Shell.AppSystem.get_default(); + apps.forEach(Lang.bind(this, function(appId) { + let app = appSys.lookup_app(appId); + if (!app) + return; + + let icon = new AppIcon(app); + this.view.addItem(icon); + })); this.view.loadGrid(); this.actor.connect('clicked', Lang.bind(this,