[gnome-shell-extensions/wip/apps-menu] apps-menu: Replace it with a new version based on AxeMenu
- From: Debarshi Ray <debarshir src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell-extensions/wip/apps-menu] apps-menu: Replace it with a new version based on AxeMenu
- Date: Mon, 7 Jan 2013 20:32:02 +0000 (UTC)
commit af0299234d723b2626738ac241f69b3ddab14a60
Author: Debarshi Ray <debarshir gnome org>
Date: Fri Jan 4 18:31:57 2013 +0100
apps-menu: Replace it with a new version based on AxeMenu
extensions/apps-menu/Makefile.am | 1 +
extensions/apps-menu/extension.js | 696 ++++++++++++++++++--
extensions/apps-menu/metadata.json.in | 1 +
...gnome.shell.extensions.apps-menu.gschema.xml.in | 8 +
extensions/apps-menu/stylesheet.css | 209 ++++++-
5 files changed, 865 insertions(+), 50 deletions(-)
---
diff --git a/extensions/apps-menu/Makefile.am b/extensions/apps-menu/Makefile.am
index 86431d7..94ebc22 100644
--- a/extensions/apps-menu/Makefile.am
+++ b/extensions/apps-menu/Makefile.am
@@ -1,3 +1,4 @@
EXTENSION_ID = apps-menu
include ../../extension.mk
+include ../../settings.mk
diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js
index faf099f..7160d5e 100644
--- a/extensions/apps-menu/extension.js
+++ b/extensions/apps-menu/extension.js
@@ -1,111 +1,709 @@
-/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
-
+/**TODO:
+ 1. Activites button position
+ */
+const Version = '0.8.3';
+const ShellVersion = imports.misc.config.PACKAGE_VERSION.split(".");
+const Mainloop = imports.mainloop;
+const Atk = imports.gi.Atk;
const GMenu = imports.gi.GMenu;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
-
+const Clutter = imports.gi.Clutter;
const Main = imports.ui.main;
+const Meta = imports.gi.Meta;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
+const AppFavorites = imports.ui.appFavorites;
+const Gtk = imports.gi.Gtk;
+const Gio = imports.gi.Gio;
+const GnomeSession = imports.misc.gnomeSession;
+const Cairo = imports.cairo;
+const GLib = imports.gi.GLib;
+const Signals = imports.signals;
+const Layout = imports.ui.layout;
+const Gettext = imports.gettext;
+const Pango = imports.gi.Pango;
+
+const _ = imports.gettext.domain('axemenu').gettext;
-const ICON_SIZE = 28;
+const ExtensionUtils = imports.misc.extensionUtils;
+const Me = ExtensionUtils.getCurrentExtension();
+const Convenience = Me.imports.convenience;
-const AppMenuItem = new Lang.Class({
- Name: 'AppsMenu.AppMenuItem',
- Extends: PopupMenu.PopupBaseMenuItem,
+let appsys = Shell.AppSystem.get_default();
+let _session = new GnomeSession.SessionManager();
+
+function fixMarkup(text, allowMarkup) {
+ if (allowMarkup) {
+ let _text = text.replace(/&(?!amp;|quot;|apos;|lt;|gt;)/g, '&');
+ _text = _text.replace(/<(?!\/?[biu]>)/g, '<');
+ try {
+ Pango.parse_markup(_text, -1, '');
+ return _text;
+ } catch (e) {}
+ }
+ return GLib.markup_escape_text(text, -1);
+}
- _init: function (app, params) {
- this.parent(params);
+function ApplicationButton(app,iconsize) {
+ this._init(app,iconsize);
+}
+ApplicationButton.prototype = {
+ _init: function(app,iconsize) {
+ this.app = app;
+ let app_name = fixMarkup(this.app.get_name())
+ this.actor = new St.Button({ reactive: true, label: app_name, style_class: 'application-button', x_align: St.Align.START });
+ this.actor._delegate = this;
+ this.buttonbox = new St.BoxLayout();
+ let labelclass = AppFavorites.getAppFavorites().isFavorite(app.get_id())?'application-button-label-favorites':'application-button-label';
+ this.label = new St.Label({ text: this.app.get_name(), style_class: labelclass });
+ this.icon = this.app.create_icon_texture(iconsize);
+ this.buttonbox.add_actor(this.icon);
+ this.buttonbox.add(this.label, { y_align: St.Align.MIDDLE, y_fill: false });
+ this.actor.set_child(this.buttonbox);
+ this._clickEventId = this.actor.connect('clicked', Lang.bind(this, function() {
+ this.app.open_new_window(-1);
+ appsMenuButton._select_category(null, null);
+ appsMenuButton.menu.close();
+ }));
+ this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
+ },
+ _onDestroy : function() {
+ if (this._clickEventId) this.actor.disconnect(this._clickEventId);
+ }
+};
+Signals.addSignalMethods(ApplicationButton.prototype);
- this._app = app;
- this.label = new St.Label({ text: app.get_name() });
- this.addActor(this.label);
- this._icon = app.create_icon_texture(ICON_SIZE);
- this.addActor(this._icon, { expand: false });
+function BaseButton(label,icon,iconsize,onclick) {
+ this._init(label,icon,iconsize,onclick);
+}
+BaseButton.prototype = {
+ _init: function(label,icon,iconsize,onclick) {
+ this.actor = new St.Button({ reactive: true, label: label, style_class: 'application-button am-'+icon+'-button', x_align: St.Align.START });
+ this.actor._delegate = this;
+ this.buttonbox = new St.BoxLayout();
+ if(icon){
+ this.icon = new St.Icon({icon_name: icon, icon_size: iconsize});
+ this.buttonbox.add_actor(this.icon);
+ }
+ if(label){
+ this.label = new St.Label({ text: label, style_class: 'application-button-label' });
+ this.buttonbox.add(this.label, { y_align: St.Align.MIDDLE, y_fill: false });
+ }
+ this.actor.set_child(this.buttonbox);
+ this._clickEventId = this.actor.connect('clicked', Lang.bind(this, onclick));
+ this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
},
+ _onDestroy : function() {
+ if (this._clickEventId)
+ this.actor.disconnect(this._clickEventId);
+ }
+};
+Signals.addSignalMethods(BaseButton.prototype);
- activate: function (event) {
- this._app.activate_full(-1, event.get_time());
+function CategoryButton(parent,category) {
+ this._init(parent,category);
+}
+CategoryButton.prototype = {
+ _init: function(parent,category) {
+ var label;
+ this._parent = parent;
+ this.category = category;
+ if (category){
+ this.menu_id = this.category.get_menu_id();
+ label = category.get_name();
+ }else{
+ label = _("All");
+ this.menu_id = '';
+ }
+ this.actor = new St.Button({ reactive: true, label: label, style_class: 'category-button', x_align: St.Align.START });
+ this.actor._delegate = this;
+ this.buttonbox = new St.BoxLayout();
+ this.label = new St.Label({ text: label, style_class: 'category-button-label' });
+ this.buttonbox.add(this.label, { y_align: St.Align.MIDDLE, y_fill: false });
+ this.actor.set_child(this.buttonbox);
- this.parent(event);
+ this._clickEventId = this.actor.connect('clicked', Lang.bind(this, function() {
+ this._parent._select_category(this.category, this);
+ this._parent.cm.set_val('category_menu_id', this.menu_id);
+ this._parent._scrollToCatButton(this);
+ this._parent.selectedAppTitle.set_text("");
+ this._parent.selectedAppDescription.set_text("");
+ }));
+ this._parent._addEnterEvent(this, Lang.bind(this, function() {
+ this._parent._select_category(this.category, this);
+ this._parent.cm.set_val('category_menu_id', this.menu_id);
+ this._parent.selectedAppTitle.set_text("");
+ this._parent.selectedAppDescription.set_text("");
+ }));
+ this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
+ },
+ _onDestroy : function() {
+ if (this._clickEventId)
+ this.actor.disconnect(this._clickEventId);
}
+};
-});
+Signals.addSignalMethods(CategoryButton.prototype);
-const ApplicationsButton = new Lang.Class({
- Name: 'AppsMenu.ApplicationsButton',
- Extends: PanelMenu.SystemStatusButton,
+function ConfigManager(parent) {
+ this._init(parent);
+}
+ConfigManager.prototype = {
+ _init: function(parent) {
+ this.config_file = this._initConfigFile();
+ this._conf = {};
+ this.parent = parent;
+ },
+ get_val: function(key, defaultValue) {
+ return (this._conf[key]==undefined)?defaultValue:this._conf[key];
+ },
+ get_enum: function(key, defaultValue) {
+ let res;
+ try {
+ res = this._conf[key].split(',');
+ } catch (e) {
+ res = defaultValue;
+ }
+ return res;
+ },
+ set_val: function(key,value) {
+ this._conf[key] = value;
+ },
+ _initConfigFile: function(){
+ let filename;
+ if (!GLib.file_test(GLib.get_home_dir() + '/.config', GLib.FileTest.EXISTS)) {
+ filename = GLib.get_home_dir() + '/.axemenu.conf';
+ }else{
+ filename = GLib.get_home_dir() + '/.config/axemenu.conf';
+ }
+ if (!GLib.file_test(filename, GLib.FileTest.EXISTS)) {
+ this._createDefaultConfig(filename);
+ }
+ return filename;
+ },
+ _createDefaultConfig: function(filename){
+ let default_content = "{}";
+ GLib.file_set_contents(filename, default_content, default_content.length);
+ },
+ implode:function( glue, pieces ) {
+ return ( ( pieces instanceof Array ) ? pieces.join ( glue ) : pieces );
+ },
+ loadConfig: function() {
+ let data = GLib.file_get_contents(this.config_file)[1].toString();
+ this._conf = JSON.parse(data);
+ Main.panel._leftBox.remove_actor(activitiesButton.container);
+ this.button_label = decodeURIComponent(this.get_val('button_label', _("Applications")));
+ this.is_hot_corner = this.get_val('is_hot_corner', true);
+ if(!this.is_hot_corner){
+ this.parent._hotCorner.actor.hide();
+ activitiesButton.hotCorner.actor.show();
+ }else{
+ this.parent._hotCorner.actor.show();
+ activitiesButton.hotCorner.actor.hide();
+ }
+ if(this.button_label!=''){
+ this.parent._label.set_text(this.button_label);
+ this.parent._label.show();
+ }else{
+ this.parent._label.hide();
+ }
+
+ this.main_box_width = this.get_val('main_box_width', 705);
+ this.show_bottom_pane = this.get_val('show_bottom_pane', true);
+ this.category_with_scroll = this.get_val('category_with_scroll', false);
+ this.category_icon_size = this.get_val('category_icon_size',24);
+ this.application_icon_size = this.get_val('application_icon_size',32);
+ this.categories_box_width = this.get_val('categories_box_width',180);
+ this.smart_height = this.get_val('smart_height', true);
+ this.axe_in_hotcorner = this.get_val('axe_in_hotcorner', false);
+ },
+ saveConfig: function() {
+ GLib.file_set_contents(this.config_file, JSON.stringify(this._conf), -1);
+ },
+ resetToDefault: function() {
+ GLib.file_set_contents(this.config_file, '{}', -1);
+ this.parent.reDisplay();
+ },
+ destroy: function() {
+ }
+};
+
+function HotCorner(parent) {
+ this._init(parent);
+}
+HotCorner.prototype = {
+ __proto__: Layout.HotCorner.prototype,
+ _init : function(parent) {
+ this._parent = parent;
+ Layout.HotCorner.prototype._init.call(this);
+ },
+ _onCornerEntered : function() {
+ if (!this._entered) {
+ this._entered = true;
+ if (!Main.overview.animationInProgress) {
+ this._activationTime = Date.now() / 1000;
+ this.rippleAnimation();
+ if(!this._parent.cm.axe_in_hotcorner){
+ Main.overview.toggle();
+ }else{
+ this._parent.toggleMenu();
+ }
+ }
+ }
+ return false;
+ }
+};
+
+function ApplicationsButton() {
+ this._init();
+}
+ApplicationsButton.prototype = {
+ __proto__: PanelMenu.Button.prototype,
_init: function() {
- this.parent('start-here-symbolic');
+ PanelMenu.Button.prototype._init.call(this, 1.0, null, false);
+ Main.panel.menuManager.addMenu(this.menu);
+
+ // At this moment applications menu is not keyboard navigable at
+ // all (so not accessible), so it doesn't make sense to set as
+ // role ATK_ROLE_MENU like other elements of the panel.
+ this.actor.accessible_role = Atk.Role.LABEL;
+
+ let container = new Shell.GenericContainer();
+ container.connect('get-preferred-width', Lang.bind(this, this._containerGetPreferredWidth));
+ container.connect('get-preferred-height', Lang.bind(this, this._containerGetPreferredHeight));
+ container.connect('allocate', Lang.bind(this, this._containerAllocate));
+ this.actor.add_actor(container);
+ this.actor.name = 'panelApplications';
+
+ this._label = new St.Label({ text: _("Applications") });
+ container.add_actor(this._label);
+
+ this.actor.label_actor = this._label;
+
+ this._hotCorner = new HotCorner(this);
+ container.add_actor(this._hotCorner.actor);
- this._appSys = Shell.AppSystem.get_default();
- this._installedChangedId = this._appSys.connect('installed-changed', Lang.bind(this, this._refresh));
+ this.actor.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
+ Main.overview.connect('showing', Lang.bind(this, function() {
+ this.actor.add_accessible_state (Atk.StateType.CHECKED);
+ }));
+ Main.overview.connect('hiding', Lang.bind(this, function() {
+ this.actor.remove_accessible_state (Atk.StateType.CHECKED);
+ }));
+
+ this._selectedItemIndex = null;
+ this._previousSelectedItemIndex = null;
+ this._activeContainer = null;
+ this.cm = new ConfigManager(this);
+ this.reloadFlag = true;
+ this._createLayout();
this._display();
+ _installedChangedId = appsys.connect('installed-changed', Lang.bind(this, this.reDisplay));
+ this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateToggled));
+
+ Main.wm.addKeybinding('menu-toggle',
+ Convenience.getSettings(),
+ Meta.KeyBindingFlags.NONE,
+ Main.KeybindingMode.NORMAL | Main.KeybindingMode.OVERVIEW,
+ function() {
+ appsMenuButton.toggleMenu();
+ });
+
+ // Since the hot corner uses stage coordinates, Clutter won't
+ // queue relayouts for us when the panel moves. Queue a relayout
+ // when that happens.
+ Main.layoutManager.connect('panel-box-changed', Lang.bind(this, function() {
+ container.queue_relayout();
+ }));
},
- destroy: function() {
- this._appSys.disconnect(this._installedChangedId);
+ _containerGetPreferredWidth: function(actor, forHeight, alloc) {
+ [alloc.min_size, alloc.natural_size] = this._label.get_preferred_width(forHeight);
+ },
- this.parent();
+ _containerGetPreferredHeight: function(actor, forWidth, alloc) {
+ [alloc.min_size, alloc.natural_size] = this._label.get_preferred_height(forWidth);
},
- _refresh: function() {
- this._clearAll();
- this._display();
+ _containerAllocate: function(actor, box, flags) {
+ this._label.allocate(box, flags);
+
+ // The hot corner needs to be outside any padding/alignment
+ // that has been imposed on us
+ let primary = Main.layoutManager.primaryMonitor;
+ let hotBox = new Clutter.ActorBox();
+ let ok, x, y;
+ if (actor.get_text_direction() == Clutter.TextDirection.LTR) {
+ [ok, x, y] = actor.transform_stage_point(primary.x, primary.y);
+ } else {
+ [ok, x, y] = actor.transform_stage_point(primary.x + primary.width, primary.y);
+ // hotCorner.actor has northeast gravity, so we don't need
+ // to adjust x for its width
+ }
+
+ hotBox.x1 = Math.round(x);
+ hotBox.x2 = hotBox.x1 + this._hotCorner.actor.width;
+ hotBox.y1 = Math.round(y);
+ hotBox.y2 = hotBox.y1 + this._hotCorner.actor.height;
+ this._hotCorner.actor.allocate(hotBox, flags);
+ },
+ _createActivitiesButton: function()
+ {
+ let buttonContainer = new St.BoxLayout({style: "padding: 10px 0 0 10px;"});
+ let button = new BaseButton(_("Activities Overview"), null, 0, function() {
+ appsMenuButton.toggleMenu();
+ Main.overview.toggle();
+ });
+ buttonContainer.add(button.actor);
+ return buttonContainer;
+ },
+ _createVertSeparator: function()
+ {
+ let separator = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
+ pseudo_class: 'highlighted' });
+ separator.connect('repaint', Lang.bind(this, this._onVertSepRepaint));
+ return separator;
},
- _clearAll: function() {
- this.menu.removeAll();
+ _onCapturedEvent: function(actor, event) {
+ if (event.type() == Clutter.EventType.BUTTON_PRESS) {
+ if (!this._hotCorner.shouldToggleOverviewOnClick())
+ return true;
+ }
+ return false;
},
- // Recursively load a GMenuTreeDirectory; we could put this in ShellAppSystem too
- // (taken from js/ui/appDisplay.js in core shell)
- _loadCategory: function(dir, menu) {
+ _onButtonPress: function(actor, event) {
+ this.toggleMenu();
+ },
+
+ _onVertSepRepaint: function(area) {
+ let cr = area.get_context();
+ let themeNode = area.get_theme_node();
+ let [width, height] = area.get_surface_size();
+ let stippleColor = themeNode.get_color('-stipple-color');
+ let stippleWidth = themeNode.get_length('-stipple-width');
+ let x = Math.floor(width/2) + 0.5;
+ cr.moveTo(x, 0);
+ cr.lineTo(x, height);
+ Clutter.cairo_set_source_color(cr, stippleColor);
+ cr.setDash([1, 3], 1); // Hard-code for now
+ cr.setLineWidth(stippleWidth);
+ cr.stroke();
+ },
+ _addEnterEvent: function(button, callback) {
+ let _callback = Lang.bind(this, function() {
+ let parent = button.actor.get_parent();
+ if (this._activeContainer === this.categoriesBox && parent !== this._activeContainer) {
+ this._previousSelectedItemIndex = this._selectedItemIndex;
+ }
+ this._activeContainer = parent;
+ let children = this._activeContainer.get_children();
+ for (let i=0, l=children.length; i<l; i++) {
+ if (button.actor === children[i]) {
+ this._selectedItemIndex = i;
+ }
+ };
+ callback();
+ });
+ button.connect('enter-event', _callback);
+ button.actor.connect('enter-event', _callback);
+ },
+ _clearSelections: function(container) {
+ container.get_children().forEach(function(actor) {
+ if(actor.style_class != 'popup-separator-menu-item')
+ actor.style_class = "category-button";
+ });
+ },
+ _onOpenStateToggled: function(menu, open) {
+ if (open) {
+ this._selectedItemIndex = null;
+
+ this.categoriesApplicationsBox.show();
+ this._activeContainer = null;
+
+ this.selectedAppTitle.set_text("");
+ this.selectedAppDescription.set_text("");
+ }
+ PanelMenu.Button.prototype._onOpenStateChanged.call(this, menu, open);
+ },
+ reDisplay : function(e,object,p0,p1) {
+ if(this.reloadFlag && (p1==3 || p1===undefined)){
+ this._cleanControls();
+ this._display();
+ }
+ this.reloadFlag = true;
+ },
+ _cleanControls: function(){
+ this.categoriesBox.destroy_all_children();
+ this.applicationsBox.destroy_all_children();
+ },
+ _loadCategory: function(dir) {
var iter = dir.iter();
var nextType;
while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) {
if (nextType == GMenu.TreeItemType.ENTRY) {
var entry = iter.get_entry();
- var app = this._appSys.lookup_app_by_tree_entry(entry);
- if (!entry.get_app_info().get_nodisplay())
- menu.addMenuItem(new AppMenuItem(app));
+ if (!entry.get_app_info().get_nodisplay()) {
+ var app = appsys.lookup_app_by_tree_entry(entry);
+ if (!this.applicationsByCategory[dir.get_menu_id()]) this.applicationsByCategory[dir.get_menu_id()] = new Array();
+ this.applicationsByCategory[dir.get_menu_id()].push(app);
+ }
} else if (nextType == GMenu.TreeItemType.DIRECTORY) {
- this._loadCategory(iter.get_directory(), menu);
+ let subdir = iter.get_directory();
+ if (subdir.get_is_nodisplay()) continue;
+ this.applicationsByCategory[subdir.get_menu_id()] = new Array();
+ this._loadCategory(subdir);
+ if (this.applicationsByCategory[subdir.get_menu_id()].length>0){
+ let categoryButton = new CategoryButton(this,subdir);
+ this.categoriesBox.add_actor(categoryButton.actor);
+ }
}
}
},
-
+ _scrollToButton: function(button) {
+ var current_scroll_value = this.applicationsScrollBox.get_vscroll_bar().get_adjustment().get_value();
+ var box_height = this.applicationsScrollBox.get_allocation_box().y2-this.applicationsScrollBox.get_allocation_box().y1;
+ var new_scroll_value = current_scroll_value;
+ if (current_scroll_value > button.actor.get_allocation_box().y1-10) new_scroll_value = button.actor.get_allocation_box().y1-10;
+ if (box_height+current_scroll_value < button.actor.get_allocation_box().y2+10) new_scroll_value = button.actor.get_allocation_box().y2-box_height+10;
+ if (new_scroll_value!=current_scroll_value) this.applicationsScrollBox.get_vscroll_bar().get_adjustment().set_value(new_scroll_value);
+ },
+ _scrollToCatButton: function(button) {
+ var current_scroll_value = this.categoriesScrollBox.get_vscroll_bar().get_adjustment().get_value();
+ var box_height = this.categoriesScrollBox.get_allocation_box().y2-this.categoriesScrollBox.get_allocation_box().y1;
+ var new_scroll_value = current_scroll_value;
+ if (current_scroll_value > button.actor.get_allocation_box().y1-10) new_scroll_value = button.actor.get_allocation_box().y1-10;
+ if (box_height+current_scroll_value < button.actor.get_allocation_box().y2+10) new_scroll_value = button.actor.get_allocation_box().y2-box_height+10;
+ if (new_scroll_value!=current_scroll_value) this.categoriesScrollBox.get_vscroll_bar().get_adjustment().set_value(new_scroll_value);
+ },
+ _createLayout: function() {
+ let section = new PopupMenu.PopupMenuSection();
+ this.menu.addMenuItem(section);
+ this.categoriesApplicationsBox = new St.BoxLayout({ style_class: 'categories-app-box', vertical: false});
+ this.categoriesBox = new St.BoxLayout({ style_class: 'categories-box', vertical: true });
+ this.applicationsScrollBox = new St.ScrollView({ x_fill: true, y_fill: false, y_align: St.Align.START, style_class: 'vfade applications-scrollbox' });
+ let vscroll = this.applicationsScrollBox.get_vscroll_bar();
+ vscroll.connect('scroll-start', Lang.bind(this, function() {
+ this.menu.passEvents = true;
+ }));
+ vscroll.connect('scroll-stop', Lang.bind(this, function() {
+ this.menu.passEvents = false;
+ }));
+ this.categoriesScrollBox = new St.ScrollView({ x_fill: true, y_fill: false, y_align: St.Align.START, style_class: 'vfade categories-scrollbox' });
+ vscroll = this.categoriesScrollBox.get_vscroll_bar();
+ vscroll.connect('scroll-start', Lang.bind(this, function() {
+ this.menu.passEvents = true;
+ }));
+ vscroll.connect('scroll-stop', Lang.bind(this, function() {
+ this.menu.passEvents = false;
+ }));
+ this.applicationsBox = new St.BoxLayout({ style_class: 'applications-box', vertical:true });
+ this.applicationsScrollBox.add_actor(this.applicationsBox);
+ this.categoriesScrollBox.add_actor(this.categoriesBox, { expand: true,x_fill: false });
+ this.applicationsScrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
+ this.categoriesApplicationsBox.add(this.categoriesScrollBox, { expand: false,x_fill: true,y_fill: false, y_align: St.Align.START });
+ this.categoriesApplicationsBox.add(this._createVertSeparator(),
+ { expand: false, x_fill: false, y_fill: true});
+ this.categoriesApplicationsBox.add(this.applicationsScrollBox, { expand: true,x_fill: true,y_fill: true });
+ this.mainBox = new St.BoxLayout({ style_class: 'main-box', vertical:false });
+ this.mainBox.add(this.categoriesApplicationsBox, { expand: true, x_fill: true, y_fill: true });
+ section.actor.add_actor(this.mainBox);
+ this.selectedAppBox = new St.BoxLayout({ style_class: 'selected-app-box', vertical: true });
+ this.selectedAppTitle = new St.Label({ style_class: 'selected-app-title', text: "" });
+ this.selectedAppBox.add_actor(this.selectedAppTitle);
+ this.selectedAppDescription = new St.Label({ style_class: 'selected-app-description', text: "" });
+ this.selectedAppBox.add_actor(this.selectedAppDescription);
+ this.settingsAndselectedAppBox = new St.BoxLayout();
+ this.settingsAndselectedAppBox.add(this._createActivitiesButton(), { expand: false, x_fill: false, y_fill: false, y_align: St.Align.END });
+ this.settingsAndselectedAppBox.add(this.selectedAppBox, { expand: true, x_fill: true, y_fill: true });
+ section.actor.add_actor(this.settingsAndselectedAppBox);
+ },
_display : function() {
- let tree = this._appSys.get_tree();
- let root = tree.get_root_directory();
+ this.cm.loadConfig();
+ this._activeContainer = null;
+ this._applicationsButtons = new Array();
+ this.categoriesScrollBox.style=('width: '+this.cm.categories_box_width+'px;');
+ this.mainBox.style=('width: '+this.cm.main_box_width+'px;');
+ if(this.cm.show_bottom_pane)
+ this.settingsAndselectedAppBox.show();
+ else
+ this.settingsAndselectedAppBox.hide();
+ this.categoriesApplicationsBox.hide();
+ //Load categories
+ this.applicationsByCategory = {};
+ let tree = appsys.get_tree();
+ let root = tree.get_root_directory();
+ let categoryButton = new CategoryButton(this,null);
+ this.categoriesBox.add_actor(categoryButton.actor);
+ //let separator = new PopupMenu.PopupSeparatorMenuItem();
+ //separator.setColumnWidths(1);
+ //this.categoriesBox.add(separator.actor, {y_align: St.Align.END, expand: true, y_fill: false});
let iter = root.iter();
let nextType;
while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) {
if (nextType == GMenu.TreeItemType.DIRECTORY) {
let dir = iter.get_directory();
- let item = new PopupMenu.PopupSubMenuMenuItem(dir.get_name());
- this._loadCategory(dir, item.menu);
- this.menu.addMenuItem(item);
+ if (dir.get_is_nodisplay()) continue;
+ this.applicationsByCategory[dir.get_menu_id()] = new Array();
+ this._loadCategory(dir);
+ if (this.applicationsByCategory[dir.get_menu_id()].length>0){
+ let categoryButton = new CategoryButton(this,dir);
+ this.categoriesBox.add_actor(categoryButton.actor);
+ }
}
}
+
+ //Load applications
+ this._displayButtons(this._listApplications(null));
+
+ let smartHeight;
+ if(this.cm.smart_height){
+ let catHeight = this.categoriesBox.height+45;
+ if(this.cm.category_with_scroll)
+ catHeight = 0;
+ smartHeight = catHeight+20+'px;';
+ }else{
+ smartHeight = 'auto;';
+ }
+ this.mainBox.style+=('height: '+smartHeight);
+ },
+ _clearApplicationsBox: function(selectedActor){
+ let actors = this.applicationsBox.get_children();
+ for (var i=0; i<actors.length; i++) {
+ let actor = actors[i];
+ this.applicationsBox.remove_actor(actor);
+ }
+ let actors = this.categoriesBox.get_children();
+ for (var i=0; i<actors.length; i++){
+ let actor = actors[i];
+ if(actor.style_class != "popup-separator-menu-item")
+ if (actor==selectedActor)
+ actor.style_class = "category-button-selected";
+ else
+ actor.style_class = "category-button";
+ }
+ },
+ _select_category : function(dir, categoryButton) {
+ if (categoryButton)
+ this._clearApplicationsBox(categoryButton.actor);
+ else
+ this._clearApplicationsBox(null);
+
+ if (dir)
+ this._displayButtons(this._listApplications(dir.get_menu_id()));
+ else
+ this._displayButtons(this._listApplications(null));
+ },
+ _displayButtons: function(apps){
+ if (apps){
+ for (var i=0; i<apps.length; i++) {
+ let app = apps[i];
+ if (!this._applicationsButtons[app]){
+ let applicationButton = new ApplicationButton(app,this.cm.application_icon_size);
+ applicationButton.actor.connect('leave-event', Lang.bind(this, function() {
+ this.selectedAppTitle.set_text("");
+ this.selectedAppDescription.set_text("");
+ }));
+ this._addEnterEvent(applicationButton, Lang.bind(this, function() {
+ this.selectedAppTitle.set_text(applicationButton.app.get_name());
+ if (applicationButton.app.get_description())
+ this.selectedAppDescription.set_text(applicationButton.app.get_description());
+ else
+ this.selectedAppDescription.set_text("");
+ this._clearSelections(this.applicationsBox);
+ applicationButton.actor.style_class = "category-button-selected";
+ this._scrollToButton(applicationButton);
+ }));
+ this._applicationsButtons[app] = applicationButton;
+ }
+ if (!this._applicationsButtons[app].actor.get_parent())
+ this.applicationsBox.add_actor(this._applicationsButtons[app].actor);
+ }
+ }
+ },
+ _listApplications: function(category_menu_id, pattern){
+ var applist;
+ if (category_menu_id) applist = this.applicationsByCategory[category_menu_id];
+ else{
+ applist = new Array();
+ for (directory in this.applicationsByCategory){
+ applist = applist.concat(this.applicationsByCategory[directory]);
+ }
+ }
+ var res;
+ if (pattern){
+ res = new Array();
+ for (var i in applist){
+ let app = applist[i];
+ if (app.get_name().toLowerCase().indexOf(pattern)!=-1 || (app.get_description() && app.get_description().toLowerCase().indexOf(pattern)!=-1)) res.push(app);
+ }
+ }else res = applist;
+ res.sort(function(a,b){
+ return a.get_name().toLowerCase() > b.get_name().toLowerCase();
+ });
+ return res;
+ },
+
+ toggleMenu: function(){
+ if (!this.menu.isOpen) {
+ let monitor = Main.layoutManager.primaryMonitor;
+ this.menu.actor.style = ('max-height: ' +
+ Math.round(monitor.height - Main.panel.actor.height-80) +
+ 'px;');
+ if (Main.overview.visible)
+ Main.overview.hide();
+ } else {
+ //this.reloadFlag = false;
+ //this.cm.saveConfig();
+ this._select_category(null, null);
+ }
+ this.menu.toggle();
+ },
+
+ destroy: function() {
+ this.actor._delegate = null;
+ this.menu.actor.get_children().forEach(function(c) { c.destroy() });
+ this.menu.destroy();
+ Main.wm.removeKeybinding('menu-toggle');
+ this.actor.destroy();
}
-});
+};
let appsMenuButton;
+let activitiesButton;
+let activitiesButtonLabel;
+let _installedChangedId;
+let extensionMeta,egoVersion;
function enable() {
+ activitiesButton = Main.panel.statusArea['activities'];
+ activitiesButtonLabel = activitiesButton._label.get_text();
+ activitiesButton.hotCorner.actor.hide();
+ activitiesButton.container.hide();
appsMenuButton = new ApplicationsButton();
- Main.panel.addToStatusArea('apps-menu', appsMenuButton, 1, 'left');
+ Main.panel._leftBox.insert_child_at_index(appsMenuButton.container, 0);
+ Main.panel._axeMenu = appsMenuButton;
}
function disable() {
+ Main.panel._leftBox.remove_actor(appsMenuButton.container);
+ Main.panel.menuManager.removeMenu(appsMenuButton.menu);
+ appsys.disconnect(_installedChangedId);
appsMenuButton.destroy();
+ activitiesButton.container.show();
+ activitiesButton.hotCorner.actor.show();
+ Main.panel._leftBox.insert_child_at_index(activitiesButton.container, 0);
}
-function init() {
- /* do nothing */
+function init(metadata) {
+ let localePath = metadata.path + '/locale';
+ extensionMeta = metadata;
+ egoVersion = ShellVersion[1]<4?metadata.version:metadata.metadata['version'];
+ Gettext.bindtextdomain('axemenu', localePath);
}
diff --git a/extensions/apps-menu/metadata.json.in b/extensions/apps-menu/metadata.json.in
index 8d5380c..46c5759 100644
--- a/extensions/apps-menu/metadata.json.in
+++ b/extensions/apps-menu/metadata.json.in
@@ -5,6 +5,7 @@
"gettext-domain": "@gettext_domain@",
"name": "Applications Menu",
"description": "Add a gnome 2.x style menu for applications",
+"original-authors": [ "e2002 bk ru", "debarshir gnome org" ],
"shell-version": [ "@shell_current@" ],
"url": "@url@"
}
diff --git a/extensions/apps-menu/org.gnome.shell.extensions.apps-menu.gschema.xml.in b/extensions/apps-menu/org.gnome.shell.extensions.apps-menu.gschema.xml.in
new file mode 100644
index 0000000..56f3013
--- /dev/null
+++ b/extensions/apps-menu/org.gnome.shell.extensions.apps-menu.gschema.xml.in
@@ -0,0 +1,8 @@
+<schemalist gettext-domain="gnome-shell-extensions">
+ <schema id="org.gnome.shell.extensions.apps-menu" path="/org/gnome/shell/extensions/apps-menu/">
+ <key name="menu-toggle" type="as">
+ <default>["<Super>r"]</default>
+ <_summary>Toggle AxeMenu.</_summary>
+ </key>
+ </schema>
+</schemalist>
diff --git a/extensions/apps-menu/stylesheet.css b/extensions/apps-menu/stylesheet.css
index db99e0c..5965c82 100644
--- a/extensions/apps-menu/stylesheet.css
+++ b/extensions/apps-menu/stylesheet.css
@@ -1 +1,208 @@
-/* none used*/
+.applications-menu-favorites-box {
+ padding: 15px;
+}
+.axemenu-icon {
+ padding-right: 0px;
+}
+.applications-menu-favorites-button {
+ padding-top: 10px;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-bottom: 10px;
+}
+.applications-menu-favorites-button:hover {
+ background-gradient-direction: vertical;
+ background-gradient-start: rgba(255,255,255,0.2);
+ background-gradient-end: rgba(255,255,255,0.08);
+ box-shadow: inset 0px 0px 1px 1px rgba(255,255,255,0.06);
+ border-radius: 4px;
+}
+.places-box {
+ padding: 10px;
+}
+.places-button {
+ padding-top: 10px;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-bottom: 10px;
+}
+.categories-box {
+ padding-left: 5px;
+ padding-right: 5px;
+}
+.categories-scrollbox {
+ padding-top: 10px;
+ padding-right: 30px;
+ padding-bottom: 10px;
+}
+.main-box {
+ padding-top: 10px;
+ padding-left: 30px;
+ padding-right: 30px;
+ padding-bottom: 10px;
+}
+.applications-box {
+ padding-right: 10px;
+}
+.applications-scrollbox {
+ padding-left: 30px;
+ padding-top: 10px;
+ padding-bottom: 10px;
+}
+.categories-app-box {
+
+}
+.favorites-button-label {
+ padding-left: 10px;
+}
+.favorites-button-box {
+ padding-left: 0px;
+}
+.application-button {
+ padding-top: 7px;
+ padding-left: 7px;
+ padding-right: 7px;
+ padding-bottom: 7px;
+}
+.application-button:hover,.category-button:hover,
+.application-button-selected {
+ padding-top: 7px;
+ padding-left: 7px;
+ padding-right: 7px;
+ padding-bottom: 7px;
+ background-gradient-direction: vertical;
+ background-gradient-start: rgba(255,255,255,0.2);
+ background-gradient-end: rgba(255,255,255,0.08);
+ box-shadow: inset 0px 0px 1px 1px rgba(255,255,255,0.06);
+ border-radius: 4px;
+}
+.application-button-selected {
+ font-weight: bold;
+}
+.application-button-label {
+ padding-left: 5px;
+}
+.application-button-label-favorites {
+ padding-left: 5px;
+ font-weight: bold;
+ text-decoration: underline;
+}
+.category-button {
+ padding-top: 7px;
+ padding-left: 7px;
+ padding-right: 7px;
+ padding-bottom: 7px;
+ font-weight: normal;
+}
+.category-button-selected,.category-button:hover {
+ padding-top: 7px;
+ padding-left: 7px;
+ padding-right: 7px;
+ padding-bottom: 7px;
+ background-gradient-direction: vertical;
+ background-gradient-start: rgba(255,255,255,0.2);
+ background-gradient-end: rgba(255,255,255,0.08);
+ box-shadow: inset 0px 0px 1px 1px rgba(255,255,255,0.06);
+ border-radius: 4px;
+}
+.favswich-button {
+ width: 150px;
+ font-weight: bold;
+}
+.leftpane-box {
+ padding-right: 10px;
+ font-size: 12px;
+}
+.category-button-label {
+ padding-left: 5px;
+}
+.category-button-button:hover {
+ background-color: #969696;
+ border-radius: 8px;
+}
+.selected-app-box {
+ padding-right: 30px;
+ padding-left: 28px;
+ text-align: right;
+}
+.selected-app-title {
+ font-weight: bold;
+ font-size: small;
+}
+.selected-app-description {
+ max-width: 220px;
+}
+.search_box {
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-bottom: 10px;
+}
+.pane-title {
+ font-weight: bold;
+ padding: 7px 0;
+ font-size: 10pt;
+}
+.config-menu-dialog-box {
+ font-size: 11pt;
+}
+.config-dialog-label {
+ font-size: 10pt;
+}
+.config-dialog-header {
+ font-size: normal;
+ font-weight: bold;
+ padding: 6px;
+}
+.config-dialog-header.nb {
+ text-align: center;
+ background: rgba(255,255,255,0.08);
+ border-radius: 4px;
+}
+.config-dialog-entry {
+ padding: 3px 4px;
+ border-radius: 3px;
+ color: black;
+ selected-color: black;
+ border: 1px solid rgba(245,245,245,0.2);
+ background-gradient-direction: vertical;
+ background-gradient-start: rgb(200,200,200);
+ background-gradient-end: white;
+ transition-duration: 300;
+ box-shadow: inset 0px 2px 4px rgba(0,0,0,0.6);
+ caret-color: #a8a8a8;
+ width: 55px;
+ font-size: small;
+}
+.config-dialog-entry.sysapps {
+ width: 400px;
+}
+.config-button-label-entry {
+ width: 150px;
+ padding: 3px 4px;
+}
+.config-notebook-box {
+ width: 600px;
+ height: 390px;
+ padding-top: 15px;
+}
+.config-notebook-tabs {
+ width: 140px;
+ padding-right: 30px;
+ font-size: small;
+ spacing: 8px;
+}
+.config-notebook-control-box {
+ spacing: 10px;
+}
+.button-reset {
+ border: #a60000 1px solid;
+ color: #a60000;
+ font-size: 10pt;
+ border-radius: 4px;
+ padding: 4px 6px;
+}
+.button-reset:hover {
+ padding: 4px 6px;
+ border: #f00 1px solid;
+ color: #f00;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]