diff options
Diffstat (limited to 'src/actionGroups/menuGroup.vala')
-rw-r--r-- | src/actionGroups/menuGroup.vala | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/src/actionGroups/menuGroup.vala b/src/actionGroups/menuGroup.vala new file mode 100644 index 0000000..07a4bd1 --- /dev/null +++ b/src/actionGroups/menuGroup.vala @@ -0,0 +1,254 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// An ActionGroup which displays the user's main menu. It's a bit ugly, +/// but it supports both, an older version and libgnome-menus-3 at the +/// same time. +///////////////////////////////////////////////////////////////////////// + +public class MenuGroup : ActionGroup { + ///////////////////////////////////////////////////////////////////// + /// Used to register this type of ActionGroup. It sets the display + /// name for this ActionGroup, it's icon name and the string used in + /// the pies.conf file for this kind of ActionGroups. + ///////////////////////////////////////////////////////////////////// + + public static void register(out string name, out string icon, out string settings_name) { + name = _("Main menu"); + icon = "gnome-main-menu"; + settings_name = "menu"; + } + + ///////////////////////////////////////////////////////////////////// + /// True, if this MenuGroup is the top most menu. + ///////////////////////////////////////////////////////////////////// + + public bool is_toplevel {get; construct set; default = true;} + + ///////////////////////////////////////////////////////////////////// + /// The menu tree displayed by the MenuGroup. Only set for the + /// toplevel MenuGroup. + ///////////////////////////////////////////////////////////////////// + + private GMenu.Tree menu = null; + + ///////////////////////////////////////////////////////////////////// + /// A list of all sub menus of this MenuGroup. + ///////////////////////////////////////////////////////////////////// + + private Gee.ArrayList<MenuGroup?> childs; + + ///////////////////////////////////////////////////////////////////// + /// Two members needed to avoid useless, frequent changes of the + /// stored Actions. + ///////////////////////////////////////////////////////////////////// + + private bool changing = false; + private bool changed_again = false; + + ///////////////////////////////////////////////////////////////////// + /// C'tor, initializes all members. Used for the toplevel menu. + ///////////////////////////////////////////////////////////////////// + + public MenuGroup(string parent_id) { + GLib.Object(parent_id : parent_id, is_toplevel : true); + } + + ///////////////////////////////////////////////////////////////////// + /// C'tor, initializes all members. Used for sub menus. + ///////////////////////////////////////////////////////////////////// + + public MenuGroup.sub_menu(string parent_id) { + GLib.Object(parent_id : parent_id, is_toplevel : false); + } + + construct { + this.childs = new Gee.ArrayList<MenuGroup?>(); + + if (this.is_toplevel) { + #if HAVE_GMENU_3 + this.menu = new GMenu.Tree("applications.menu", GMenu.TreeFlags.INCLUDE_EXCLUDED); + this.menu.changed.connect(this.reload); + #endif + + this.load_toplevel(); + } + } + + ///////////////////////////////////////////////////////////////////// + /// Starts to load the menu. + ///////////////////////////////////////////////////////////////////// + + private void load_toplevel() { + #if HAVE_GMENU_3 + try { + if (this.menu.load_sync()) { + this.load_contents(this.menu.get_root_directory(), this.parent_id); + } + } catch (GLib.Error e) { + warning(e.message); + } + #else + this.menu = GMenu.Tree.lookup ("applications.menu", GMenu.TreeFlags.INCLUDE_EXCLUDED); + this.menu.add_monitor(this.reload); + var dir = this.menu.get_root_directory(); + this.load_contents(dir, this.parent_id); + #endif + } + + ///////////////////////////////////////////////////////////////////// + /// Parses the main menu recursively. + ///////////////////////////////////////////////////////////////////// + + private void load_contents(GMenu.TreeDirectory dir, string parent_id) { + #if HAVE_GMENU_3 + var item = dir.iter(); + + while (true) { + var type = item.next(); + if (type == GMenu.TreeItemType.INVALID) + break; + + if (type == GMenu.TreeItemType.DIRECTORY && !item.get_directory().get_is_nodisplay()) { + // create a MenuGroup for sub menus + string[] icons = item.get_directory().get_icon().to_string().split(" "); + string final_icon = "application-default-icon"; + + // search for available icons + foreach (var icon in icons) { + if (Gtk.IconTheme.get_default().has_icon(icon)) { + final_icon = icon; + break; + } + } + + var sub_menu = PieManager.create_dynamic_pie(item.get_directory().get_name(), final_icon); + var group = new MenuGroup.sub_menu(sub_menu.id); + group.add_action(new PieAction(parent_id, true)); + group.load_contents(item.get_directory(), sub_menu.id); + childs.add(group); + + sub_menu.add_group(group); + + this.add_action(new PieAction(sub_menu.id)); + + } else if (type == GMenu.TreeItemType.ENTRY ) { + // create an AppAction for entries + if (!item.get_entry().get_is_excluded()) { + this.add_action(ActionRegistry.new_for_app_info(item.get_entry().get_app_info())); + } + } + } + #else + foreach (var item in dir.get_contents()) { + switch(item.get_type()) { + case GMenu.TreeItemType.DIRECTORY: + // create a MenuGroup for sub menus + if (!((GMenu.TreeDirectory)item).get_is_nodisplay()) { + var sub_menu = PieManager.create_dynamic_pie( + ((GMenu.TreeDirectory)item).get_name(), + ((GMenu.TreeDirectory)item).get_icon()); + var group = new MenuGroup.sub_menu(sub_menu.id); + group.add_action(new PieAction(parent_id, true)); + group.load_contents((GMenu.TreeDirectory)item, sub_menu.id); + childs.add(group); + + sub_menu.add_group(group); + + this.add_action(new PieAction(sub_menu.id)); + } + break; + + case GMenu.TreeItemType.ENTRY: + // create an AppAction for entries + if (!((GMenu.TreeEntry)item).get_is_nodisplay() && !((GMenu.TreeEntry)item).get_is_excluded()) { + this.add_action(new AppAction(((GMenu.TreeEntry)item).get_name(), + ((GMenu.TreeEntry)item).get_icon(), + ((GMenu.TreeEntry)item).get_exec())); + } + break; + } + } + #endif + } + + ///////////////////////////////////////////////////////////////////// + /// Reloads the menu. + ///////////////////////////////////////////////////////////////////// + + private void reload() { + // avoid too frequent changes... + if (!this.changing) { + this.changing = true; + Timeout.add(500, () => { + if (this.changed_again) { + this.changed_again = false; + return true; + } + + // reload + message("Main menu changed..."); + #if !HAVE_GMENU_3 + this.menu.remove_monitor(this.reload); + #endif + + this.clear(); + this.load_toplevel(); + + this.changing = false; + return false; + }); + } else { + this.changed_again = true; + } + } + + ///////////////////////////////////////////////////////////////////// + /// Deletes all generated Pies, when the toplevel menu is deleted. + ///////////////////////////////////////////////////////////////////// + + public override void on_remove() { + if (this.is_toplevel) + this.clear(); + } + + ///////////////////////////////////////////////////////////////////// + /// Clears this ActionGroup recursively. + ///////////////////////////////////////////////////////////////////// + + private void clear() { + foreach (var child in childs) + child.clear(); + + if (!this.is_toplevel) + PieManager.remove_pie(this.parent_id); + + this.delete_all(); + + this.childs.clear(); + + #if !HAVE_GMENU_3 + this.menu = null; + #endif + + } +} + +} |