diff --git a/data/Makefile.am b/data/Makefile.am index 7b9987522..f035f95a5 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -40,6 +40,7 @@ dist_theme_DATA = \ theme/section-back.svg \ theme/section-more.svg \ theme/section-more-open.svg \ + theme/separator-white.png \ theme/single-view-active.svg \ theme/single-view.svg \ theme/ws-switch-arrow-left.svg \ @@ -49,12 +50,18 @@ dist_theme_DATA = \ schemadir = @GCONF_SCHEMA_FILE_DIR@ schema_DATA = gnome-shell.schemas +menudir = $(sysconfdir)/xdg/menus + +menu_DATA = \ + gs-applications.menu + install-data-local: GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(srcdir)/$(schema_DATA) EXTRA_DIST = \ gnome-shell.desktop.in.in \ gnome-shell-clock-preferences.desktop.in.in \ + $(menu_DATA) \ $(schema_DATA) CLEANFILES = \ diff --git a/data/gs-applications.menu b/data/gs-applications.menu new file mode 100644 index 000000000..38ed80514 --- /dev/null +++ b/data/gs-applications.menu @@ -0,0 +1,36 @@ + + Applications + + + Games + + + Game + + + + + Tools + + Development + + System + + Settings + + + Utility + + + + Other + + + + Core + Settings + Screensaver + + + + diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css index c34ae630d..1f3dd03db 100644 --- a/data/theme/gnome-shell.css +++ b/data/theme/gnome-shell.css @@ -520,6 +520,16 @@ StTooltip { color: #ffffff; } +.app-section-divider-container { + padding-top: 10px; + padding-bottom: 10px; +} + +.app-section-divider { + height: 2px; + background-image: url("separator-white.png"); +} + .all-app-controls-panel { height: 30px; } diff --git a/data/theme/separator-white.png b/data/theme/separator-white.png new file mode 100644 index 000000000..c2a8bb91a Binary files /dev/null and b/data/theme/separator-white.png differ diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js index deeeb6ff5..71243c3f9 100644 --- a/js/ui/appDisplay.js +++ b/js/ui/appDisplay.js @@ -24,12 +24,12 @@ const APPICON_SIZE = 48; const WELL_MAX_COLUMNS = 8; const MENU_POPUP_TIMEOUT = 600; -function AllAppView() { +function AlphabeticalView() { this._init(); } -AllAppView.prototype = { - _init: function(apps) { +AlphabeticalView.prototype = { + _init: function() { this.actor = new St.BoxLayout({ vertical: true }); this._grid = new WellGrid(true); this._appSystem = Shell.AppSystem.get_default(); @@ -71,7 +71,67 @@ AllAppView.prototype = { } }; -Signals.addSignalMethods(AllAppView.prototype); +Signals.addSignalMethods(AlphabeticalView.prototype); + +function ViewByCategories() { + this._init(); +} + +ViewByCategories.prototype = { + _init: function() { + this._appSystem = Shell.AppSystem.get_default(); + this.actor = new St.BoxLayout({ vertical: true }); + this.actor._delegate = this; + this._sections = []; + }, + + _updateSections: function(apps) { + this._removeAll(); + + let sections = this._appSystem.get_sections(); + if (!sections) + return; + for (let i = 0; i < sections.length; i++) { + if (i) { + let actor = new St.Bin({ style_class: 'app-section-divider' }); + let divider = new St.Bin({ style_class: 'app-section-divider-container', + child: actor, + x_fill: true }); + + this.actor.add(divider, { y_fill: false, expand: true }); + } + let _apps = apps.filter(function(app) { + return app.get_section() == sections[i]; + }); + this._sections[i] = { view: new AlphabeticalView(), + apps: _apps, + name: sections[i] }; + this._sections[i].view.connect('launching', Lang.bind(this, function() { + this.emit('launching'); + })); + this._sections[i].view.connect('drag-begin', Lang.bind(this, function() { + this.emit('drag-begin'); + })); + this.actor.add(this._sections[i].view.actor, { y_align: St.Align.START, expand: true }); + } + }, + + _removeAll: function() { + this.actor.destroy_children(); + this._sections.forEach(function (section) { section.view.disconnectAll(); }); + + this._sections = []; + }, + + refresh: function(apps) { + this._updateSections(apps); + for (let i = 0; i < this._sections.length; i++) { + this._sections[i].view.refresh(this._sections[i].apps); + } + } +}; + +Signals.addSignalMethods(ViewByCategories.prototype); /* This class represents a display containing a collection of application items. * The applications are sorted based on their name. @@ -100,7 +160,7 @@ AllAppDisplay.prototype = { this.actor.add(bin); this.actor.add(view, { expand: true, y_fill: false, y_align: St.Align.START }); - this._appView = new AllAppView(); + this._appView = new ViewByCategories(); this._appView.connect('launching', Lang.bind(this, this.close)); this._appView.connect('drag-begin', Lang.bind(this, this.close)); this._scrollView.add_actor(this._appView.actor); diff --git a/src/gnome-shell-plugin.c b/src/gnome-shell-plugin.c index 8e689fdb2..2951cb232 100644 --- a/src/gnome-shell-plugin.c +++ b/src/gnome-shell-plugin.c @@ -149,6 +149,7 @@ gnome_shell_plugin_class_init (GnomeShellPluginClass *klass) static void gnome_shell_plugin_init (GnomeShellPlugin *shell_plugin) { + g_setenv ("XDG_MENU_PREFIX", "gs-", TRUE); meta_prefs_override_preference_location ("/apps/metacity/general/button_layout", "/desktop/gnome/shell/windows/button_layout"); } diff --git a/src/gnome-shell.in b/src/gnome-shell.in index 2dfb4f3a0..07dceb44b 100644 --- a/src/gnome-shell.in +++ b/src/gnome-shell.in @@ -156,6 +156,7 @@ def start_shell(perf_output=None): env = dict(os.environ) env.update({'GNOME_SHELL_JS' : '@GJS_JS_DIR@:@GJS_JS_NATIVE_DIR@:' + js_dir, 'PATH' : '@MUTTER_BIN_DIR@:' + os.environ.get('PATH', ''), + 'XDG_CONFIG_DIRS' : '@sysconfdir@/xdg:' + os.environ.get('XDG_CONFIG_DIRS', ''), 'GNOME_DISABLE_CRASH_DIALOG' : '1'}) if running_from_source_tree: diff --git a/src/shell-app-system.c b/src/shell-app-system.c index faa960e55..c0ebc7fce 100644 --- a/src/shell-app-system.c +++ b/src/shell-app-system.c @@ -1109,10 +1109,84 @@ shell_app_info_get_icon (ShellAppInfo *info) return NULL; } -GSList * -shell_app_info_get_categories (ShellAppInfo *info) +/** + * shell_app_system_get_sections: + * + * return names of sections in applications menu. + * + * Returns: (element-type utf8) (transfer full): List of Names + */ +GList * +shell_app_system_get_sections (ShellAppSystem *system) { - return NULL; /* TODO */ + GList *res = NULL; + GSList *i, *contents; + GMenuTreeDirectory *root; + + root = gmenu_tree_get_root_directory (system->priv->apps_tree); + + if (G_UNLIKELY (!root)) + g_error ("applications.menu not found."); + + contents = gmenu_tree_directory_get_contents (root); + + for (i = contents; i; i = i->next) + { + GMenuTreeItem *item = i->data; + if (gmenu_tree_item_get_type (item) == GMENU_TREE_ITEM_DIRECTORY) + { + char *name = g_strdup (gmenu_tree_directory_get_name ((GMenuTreeDirectory*)item)); + + g_assert (name); + + res = g_list_append (res, name); + } + gmenu_tree_item_unref (item); + } + + g_slist_free (contents); + + return res; +} + +/** + * shell_app_info_get_section: + * + * return name of section, that contain this application. + * Returns: (transfer full): section name + */ +char * +shell_app_info_get_section (ShellAppInfo *info) +{ + char *name; + GMenuTreeDirectory *dir, *parent; + + if (info->type != SHELL_APP_INFO_TYPE_ENTRY) + return NULL; + + dir = gmenu_tree_item_get_parent ((GMenuTreeItem*)info->entry); + if (!dir) + return NULL; + + parent = gmenu_tree_item_get_parent ((GMenuTreeItem*)dir); + if (!parent) + return NULL; + + while (TRUE) + { + GMenuTreeDirectory *pparent = gmenu_tree_item_get_parent ((GMenuTreeItem*)parent); + if (!pparent) + break; + gmenu_tree_item_unref ((GMenuTreeItem*)dir); + dir = parent; + parent = pparent; + } + + name = g_strdup (gmenu_tree_directory_get_name (dir)); + + gmenu_tree_item_unref ((GMenuTreeItem*)dir); + gmenu_tree_item_unref ((GMenuTreeItem*)parent); + return name; } gboolean diff --git a/src/shell-app-system.h b/src/shell-app-system.h index 2f3dda74f..696972b11 100644 --- a/src/shell-app-system.h +++ b/src/shell-app-system.h @@ -52,7 +52,7 @@ char *shell_app_info_get_executable (ShellAppInfo *info); char *shell_app_info_get_desktop_file_path (ShellAppInfo *info); GIcon *shell_app_info_get_icon (ShellAppInfo *info); ClutterActor *shell_app_info_create_icon_texture (ShellAppInfo *info, float size); -GSList *shell_app_info_get_categories (ShellAppInfo *info); +char *shell_app_info_get_section (ShellAppInfo *info); gboolean shell_app_info_get_is_nodisplay (ShellAppInfo *info); gboolean shell_app_info_is_transient (ShellAppInfo *info); @@ -69,6 +69,7 @@ gboolean shell_app_info_launch (ShellAppInfo *info, ShellAppInfo *shell_app_system_load_from_desktop_file (ShellAppSystem *system, const char *filename, GError **error); +GList *shell_app_system_get_sections (ShellAppSystem *system); ShellApp *shell_app_system_get_app (ShellAppSystem *system, const char *id); ShellApp *shell_app_system_get_app_for_path (ShellAppSystem *system, const char *desktop_path); ShellApp *shell_app_system_get_app_for_window (ShellAppSystem *self, MetaWindow *window);