[cinnamon/f17] initial commit

leigh123linux leigh123linux at fedoraproject.org
Fri Jul 20 14:49:03 UTC 2012


commit 8e11cbfd8003278727452e00bd583910b27e22d5
Author: leigh123linux <leigh123linux at googlemail.com>
Date:   Fri Jul 20 15:48:58 2012 +0100

    initial commit

 .gitignore                                      |    1 +
 cinnamon-1.4.1_f17_favourite-apps-firefox.patch |   20 +
 cinnamon-1.4.1_menu.patch                       |  158 ++
 cinnamon-1.4.1_settings.patch                   |  367 +++
 cinnamon-1.4.1_systray.patch                    |   22 +
 cinnamon-menu.patch                             | 3410 +++++++++++++++++++++++
 cinnamon.desktop                                |   10 +
 cinnamon.session                                |    6 +
 cinnamon.spec                                   |  317 +++
 cinnamon2d.desktop                              |    7 +
 cinnamon2d.session                              |    4 +
 menu.png                                        |  Bin 0 -> 1307 bytes
 sources                                         |    1 +
 13 files changed, 4323 insertions(+), 0 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index e69de29..dd557e9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1 @@
+/cinnamon-1.4.1.git7959517.tar.gz
diff --git a/cinnamon-1.4.1_f17_favourite-apps-firefox.patch b/cinnamon-1.4.1_f17_favourite-apps-firefox.patch
new file mode 100644
index 0000000..a5ea847
--- /dev/null
+++ b/cinnamon-1.4.1_f17_favourite-apps-firefox.patch
@@ -0,0 +1,20 @@
+--- cinnamon-1.1.3/data/org.cinnamon.gschema1.xml.in	2012-01-02 12:03:30.000000000 +0000
++++ cinnamon-1.1.3/data/org.cinnamon.gschema.xml.in	2012-01-02 16:41:39.242419968 +0000
+@@ -231,7 +231,7 @@
+     </key>
+     
+     <key name="panel-launchers" type="as">
+-      <default>[ 'firefox.desktop', 'gnome-terminal.desktop', 'nautilus.desktop']</default>
++      <default>[ 'firefox.desktop', 'gnome-terminal.desktop', 'nautilus.desktop']</default>
+       <_summary>Desktop files of the applications to put in the panel launchers applet</_summary>
+       <_description>
+         Cinnamon allows to show applications launchers on the panel.
+@@ -251,7 +251,7 @@
+     </key>
+ 
+     <key name="favorite-apps" type="as">
+-      <default>[ 'firefox.desktop', 'mintInstall.desktop', 'cinnamon-settings.desktop', 'xchat.desktop', 'gnome-terminal.desktop', 'nautilus.desktop' ]</default>
++      <default>[ 'cinnamon-settings.desktop', 'firefox.desktop', 'evolution.desktop', 'empathy.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'libreoffice-writer.desktop', 'nautilus.desktop', 'gnome-documents.desktop' ]</default>
+       <_summary>List of desktop file IDs for favorite applications</_summary>
+       <_description>
+         The applications corresponding to these identifiers
diff --git a/cinnamon-1.4.1_menu.patch b/cinnamon-1.4.1_menu.patch
new file mode 100644
index 0000000..87c46ea
--- /dev/null
+++ b/cinnamon-1.4.1_menu.patch
@@ -0,0 +1,158 @@
+--- a/files/etc/xdg/menus/cinnamon-applications.menu
++++ b/files/etc/xdg/menus/cinnamon-applications.menu
+@@ -4,12 +4,12 @@
+ <Menu>
+ 
+   <Name>Applications</Name>
+-  <Directory>cinnamon-menu-applications.directory</Directory>
++  <Directory>X-GNOME-Menu-Applications.directory</Directory>
+ 
+   <!-- Scan legacy dirs first, as later items take priority -->
+   <KDELegacyDirs/>
+   <LegacyDir>/etc/X11/applnk</LegacyDir>
+-  <LegacyDir>/usr/share/cinnamon/apps</LegacyDir>
++  <LegacyDir>/usr/share/gnome/apps</LegacyDir>
+ 
+   <!-- Read standard .directory and .desktop file locations -->
+   <DefaultAppDirs/>
+@@ -21,7 +21,7 @@
+   <!-- Accessories submenu -->
+   <Menu>
+     <Name>Accessories</Name>
+-    <Directory>cinnamon-utility.directory</Directory>
++    <Directory>Utility.directory</Directory>
+     <Include>
+       <And>
+         <Category>Utility</Category>
+@@ -38,7 +38,7 @@
+   <!-- Accessibility submenu -->
+   <Menu>
+     <Name>Universal Access</Name>
+-    <Directory>cinnamon-utility-accessibility.directory</Directory>
++    <Directory>Utility-Accessibility.directory</Directory>
+     <Include>
+       <And>
+         <Category>Accessibility</Category>
+@@ -50,7 +50,7 @@
+   <!-- Development Tools -->
+   <Menu>
+     <Name>Development</Name>
+-    <Directory>cinnamon-development.directory</Directory>
++    <Directory>Development.directory</Directory>
+     <Include>
+       <And>
+         <Category>Development</Category>
+@@ -62,7 +62,7 @@
+   <!-- Education -->
+   <Menu>
+     <Name>Education</Name>
+-    <Directory>cinnamon-education.directory</Directory>
++    <Directory>Education.directory</Directory>
+     <Include>
+       <And>
+         <Category>Education</Category>
+@@ -73,7 +73,7 @@
+   <!-- Games -->
+   <Menu>
+     <Name>Games</Name>
+-    <Directory>cinnamon-game.directory</Directory>
++    <Directory>Game.directory</Directory>
+     <Include>
+       <And>
+         <Category>Game</Category>
+@@ -84,7 +84,7 @@
+   <!-- Graphics -->
+   <Menu>
+     <Name>Graphics</Name>
+-    <Directory>cinnamon-graphics.directory</Directory>
++    <Directory>Graphics.directory</Directory>
+     <Include>
+       <And>
+         <Category>Graphics</Category>
+@@ -95,7 +95,7 @@
+   <!-- Internet -->
+   <Menu>
+     <Name>Internet</Name>
+-    <Directory>cinnamon-network.directory</Directory>
++    <Directory>Network.directory</Directory>
+     <Include>
+       <And>
+         <Category>Network</Category>
+@@ -106,7 +106,7 @@
+   <!-- Multimedia -->
+   <Menu>
+     <Name>Multimedia</Name>
+-    <Directory>cinnamon-audio-video.directory</Directory>
++    <Directory>AudioVideo.directory</Directory>
+     <Include>
+       <And>
+         <Category>AudioVideo</Category>
+@@ -117,7 +117,7 @@
+   <!-- Office -->
+   <Menu>
+     <Name>Office</Name>
+-    <Directory>cinnamon-office.directory</Directory>
++    <Directory>Office.directory</Directory>
+     <Include>
+       <And>
+         <Category>Office</Category>
+@@ -128,7 +128,7 @@
+   <!-- System Tools-->
+   <Menu>
+     <Name>System</Name>
+-    <Directory>cinnamon-system-tools.directory</Directory>
++    <Directory>System-Tools.directory</Directory>
+     <Include>
+       <And>
+         <Category>System</Category>
+@@ -140,13 +140,15 @@
+   <!-- Other -->
+   <Menu>
+     <Name>Other</Name>
+-    <Directory>cinnamon-other.directory</Directory>
++    <Directory>X-GNOME-Other.directory</Directory>
+     <OnlyUnallocated/>
+     <Include>
+       <And>
+         <Not><Category>Core</Category></Not>
+         <Not><Category>Settings</Category></Not>
+         <Not><Category>Screensaver</Category></Not>
++        <Not><Category>X-GNOME-Settings-Panel</Category></Not>
++        <Not><Category>Documentation</Category></Not>
+       </And>
+     </Include>
+   </Menu> <!-- End Other -->
+@@ -154,10 +156,10 @@
+    <!-- Wine -->
+   <Menu>
+     <Name>Wine</Name>
+-    <Directory>wine-wine.directory</Directory>
++    <Directory>Wine.directory</Directory>
+     <Include>
+       <And>
+-        <Category>Wine</Category>
++        <Category>X-Wine</Category>
+       </And>
+     </Include>
+   </Menu> <!-- End Wine -->
+--- a/files/etc/xdg/menus/cinnamon-settings.menu
++++ b/files/etc/xdg/menus/cinnamon-settings.menu
+@@ -18,9 +18,14 @@
+     <Name>Preferences</Name>
+     <Directory>cinnamon-settings.directory</Directory>
+     <Include>
+-      <And>
+-        <Category>Settings</Category>
+-      </And>
++       <And>
++         <Category>Settings</Category>
++         <Not>
++           <Or>
++             <Category>System</Category>
++           </Or>
++         </Not>
++       </And>
+     </Include>
+   </Menu>
+ 
+
diff --git a/cinnamon-1.4.1_settings.patch b/cinnamon-1.4.1_settings.patch
new file mode 100644
index 0000000..ddf4b3b
--- /dev/null
+++ b/cinnamon-1.4.1_settings.patch
@@ -0,0 +1,367 @@
+--- a/files/usr/lib/cinnamon-settings/cinnamon-settings.py	2012-03-12 14:31:34.000000000 +0000
++++ b/files/usr/lib/cinnamon-settings/cinnamon-settings.py	2012-03-13 10:58:01.866049626 +0000
+@@ -11,9 +11,6 @@ try:
+     import gconf
+     import json
+     import dbus
+-    import tz
+-    import time
+-    from datetime import datetime
+     from user import home
+     import thread
+ except Exception, detail:
+@@ -741,244 +738,7 @@ class GSettingsComboBox(Gtk.HBox):
+             value = self.model[tree_iter][0]            
+             self.settings.set_string(self.key, value)                       
+ 
+-class TimeZoneSelectorWidget(Gtk.HBox):
+-    def __init__(self):
+-        super(TimeZoneSelectorWidget, self).__init__()
+-        
+-        proxy = dbus.SystemBus().get_object("org.gnome.SettingsDaemon.DateTimeMechanism", "/")
+-        self.dbus_iface = dbus.Interface(proxy, dbus_interface="org.gnome.SettingsDaemon.DateTimeMechanism")
+-        
+-        self.timezones = tz.load_db()
+-        
+-        self.selected_region, self.selected_city = self.get_selected_zone()
+-        
+-        region_label = Gtk.Label(_("Region"))
+-        self.pack_start(region_label, False, False, 2)
+-        
+-        regions = self.timezones.keys()
+-        regions.sort()
+-        self.region_model = Gtk.ListStore(str, str)
+-        selected_region_iter = None
+-        for region in regions:
+-            iter = self.region_model.insert_before(None, None)
+-            self.region_model.set_value(iter, 0, region)                
+-            self.region_model.set_value(iter, 1, region.replace("_", " "))                        
+-            if (region == self.selected_region):
+-                selected_region_iter = iter
+-                                
+-        self.region_widget = Gtk.ComboBox.new_with_model(self.region_model)   
+-        renderer_text = Gtk.CellRendererText()
+-        self.region_widget.pack_start(renderer_text, True)
+-        self.region_widget.add_attribute(renderer_text, "text", 1)
+-        if selected_region_iter is not None:
+-            self.region_widget.set_active_iter(selected_region_iter)
+-        self.pack_start(self.region_widget, False, False, 2)
+-        
+-        city_label = Gtk.Label(_("City"))
+-        self.pack_start(city_label, False, False, 2)
+-        
+-        self.city_model = Gtk.ListStore(str, str)
+-        self.city_widget = Gtk.ComboBox.new_with_model(self.city_model)   
+-        renderer_text = Gtk.CellRendererText()
+-        self.city_widget.pack_start(renderer_text, True)
+-        self.city_widget.add_attribute(renderer_text, "text", 1)
+-        self.pack_start(self.city_widget, False, False, 2)
+-        
+-        self.update_cities_list()
+-        
+-        self.region_widget.connect("changed", self.on_region_changed)
+-        self.city_widget.connect("changed", self.on_city_changed)
+-    def on_city_changed(self, widget):
+-        tree_iter = widget.get_active_iter()
+-        if tree_iter != None:
+-            self.selected_city = self.city_model[tree_iter][0]
+-            self.dbus_iface.SetTimezone(self.selected_region+"/"+self.selected_city)
+-    def on_region_changed(self, widget):
+-        tree_iter = widget.get_active_iter()
+-        if tree_iter != None:            
+-            self.selected_region = self.region_model[tree_iter][0]
+-            self.update_cities_list()
+-    def update_cities_list(self):
+-        self.city_model.clear()
+-        if self.selected_region and self.selected_region in self.timezones.keys():
+-            cities = self.timezones[self.selected_region]
+-            cities.sort()
+-            selected_city_iter = None
+-            for city in cities:
+-                iter = self.city_model.insert_before(None, None)
+-                self.city_model.set_value(iter, 0, city)                
+-                self.city_model.set_value(iter, 1, city.replace("_", " "))                        
+-                if (city == self.selected_city):
+-                    selected_city_iter = iter
+-            if selected_city_iter is not None:
+-                self.city_widget.set_active_iter(selected_city_iter)
+-    def get_selected_zone(self):
+-        tz = self.dbus_iface.GetTimezone()
+-        if "/" in tz:
+-            i = tz.index("/")
+-            region = tz[:i]
+-            city = tz[i+1:]
+-            return region, city
+-        else:
+-            return "", ""
+-            
+-class ChangeTimeWidget(Gtk.HBox):
+-    def __init__(self):
+-        super(ChangeTimeWidget, self).__init__()
+-        proxy = dbus.SystemBus().get_object("org.gnome.SettingsDaemon.DateTimeMechanism", "/")
+-        self.dbus_iface = dbus.Interface(proxy, dbus_interface="org.gnome.SettingsDaemon.DateTimeMechanism")
+-        
+-        # Ensures we are setting the system time only when the user changes it
+-        self.changedOnTimeout = False
+-        
+-        # Ensures we do not update the values in the date/time fields during the DBus call to set the time
+-        self._setting_time = False
+-        self._setting_time_lock = thread.allocate()
+-        self._time_to_set = None
+-        
+-        self.thirtyDays = [3, 5, 8, 10]
+-        months = ['January','February','March','April','May','June','July','August','September','October','November','December']
+-        
+-        # Boxes
+-        timeBox = Gtk.HBox()
+-        dateBox = Gtk.HBox()
+-        
+-        # Combo Boxes
+-        self.monthBox = Gtk.ComboBoxText()
+-        
+-        for month in months:
+-            self.monthBox.append_text(month)
+-        
+-        # Adjustments
+-        hourAdj = Gtk.Adjustment(0, 0, 23, 1, 1)
+-        minAdj = Gtk.Adjustment(0, 0, 59, 1, 1)
+-        yearAdj = Gtk.Adjustment(0, 0, 9999, 1, 5)
+-        dayAdj = Gtk.Adjustment(0, 1, 31, 1, 1)
+-        
+-        # Spin buttons
+-        self.hourSpin = Gtk.SpinButton()
+-        self.minSpin = Gtk.SpinButton()
+-        self.yearSpin = Gtk.SpinButton()
+-        self.daySpin = Gtk.SpinButton()
+-        
+-        self.hourSpin.configure(hourAdj, 0.5, 0)
+-        self.minSpin.configure(minAdj, 0.5, 0)
+-        self.yearSpin.configure(yearAdj, 0.5, 0)
+-        self.daySpin.configure(dayAdj, 0.5, 0)
+-        #self.hourSpin.set_editable(False)
+-        #self.minSpin.set_editable(False)
+-        #self.yearSpin.set_editable(False)
+-        #self.daySpin.set_editable(False)
+-        
+-        self.update_time()
+-        GObject.timeout_add(1000, self.update_time)
+-        
+-        # Connect to callback
+-        self.hourSpin.connect('changed', self._change_system_time)
+-        self.minSpin.connect('changed', self._change_system_time)
+-        self.monthBox.connect('changed', self._change_system_time)
+-        self.yearSpin.connect('changed', self._change_system_time)
+-        self.daySpin.connect('changed', self._change_system_time)
+-        
+-        timeBox.pack_start(self.hourSpin, False, False, 2)
+-        timeBox.pack_start(Gtk.Label(_(":")), False, False, 2)
+-        timeBox.pack_start(self.minSpin, False, False, 2)
+-        
+-        dateBox.pack_start(self.monthBox, False, False, 2)
+-        dateBox.pack_start(self.daySpin, False, False, 2)
+-        dateBox.pack_start(self.yearSpin, False, False, 2)
+-        
+-        self.pack_start(Gtk.Label(_("Date : ")), False, False, 2)
+-        self.pack_start(dateBox, True, True, 2)
+-        self.pack_start(Gtk.Label(_("Time : ")), False, False, 2)
+-        self.pack_start(timeBox, True, True, 2)
+-        
+-    def update_time(self):
+-        self._setting_time_lock.acquire()
+-        do_update = not self._setting_time
+-        self._setting_time_lock.release()
+-        
+-        if not do_update:
+-            return True
+-        
+-        dt = datetime.now()
+-        
+-        self.changedOnTimeout = True
+-        
+-        # Time
+-        self.hourSpin.set_value( dt.hour )
+-        self.minSpin.set_value( dt.minute )
+-        
+-        # Date
+-        self.monthBox.set_active( dt.month-1 )
+-        self.daySpin.set_value( dt.day )
+-        self.yearSpin.set_value( dt.year )
+-        
+-        self.changedOnTimeout = False
+-        
+-        # Update the max of the day spin box
+-        maxDay = 31
+-        if dt.month == 2:
+-            if dt.year % 4 == 0:
+-                maxDay = 29
+-            else:
+-                maxDay = 28
+-        elif dt.month-1 in self.thirtyDays:
+-            maxDay = 30
+-            
+-        self.daySpin.get_adjustment().set_upper(maxDay)
+-        
+-        return True
+-        
+-    def change_using_ntp(self, usingNtp):
+-        # Check if we were using Ntp by seeing if the spin button
+-        # is sensitive
+-        self.set_sensitive(not usingNtp)
+-    
+-    def _do_change_system_time(self):
+-        self._setting_time_lock.acquire()
+-        do_set = not self._setting_time
+-        self._setting_time = True
+-        self._setting_time_lock.release()
+-        
+-        # If there is already another thread updating the time, we let it do the job
+-        if not do_set:
+-            return
+-        
+-        done = False
+-        while not done:
+-            self._setting_time_lock.acquire()
+-            time_to_set = self._time_to_set
+-            self._time_to_set = None
+-            self._setting_time_lock.release()
+-            
+-            self.dbus_iface.SetTime(time_to_set)
+-            
+-            # Check whether another request to set the time was done since this thread started
+-            self._setting_time_lock.acquire()
+-            if self._time_to_set==None:
+-                done = True
+-            self._setting_time_lock.release()
+-        
+-        self._setting_time_lock.acquire()
+-        self._setting_time = False
+-        self._setting_time_lock.release()
+-                
+-    def _change_system_time(self, widget):
+-        if not self.changedOnTimeout:
+-            hour = int( self.hourSpin.get_value() )
+-            minute = int( self.minSpin.get_value() )
+-            month = self.monthBox.get_active() + 1
+-            day = int( self.daySpin.get_value() )
+-            year = int( self.yearSpin.get_value() )
+-            
+-            newDt = datetime(year, month, day, hour, minute)
+-            
+-            self._setting_time_lock.acquire()
+-            self._time_to_set = time.mktime(newDt.utctimetuple())
+-            self._setting_time_lock.release()
+-            
+-            thread.start_new_thread(self._do_change_system_time, ())
++
+ 
+ class TitleBarButtonsOrderSelector(Gtk.Table):
+     def __init__(self):        
+@@ -1134,27 +894,12 @@ class MainWindow:
+         sidePage.add_widget(GSettingsCheckButton(_("Panel Launchers draggable"), "org.cinnamon", "panel-launchers-draggable"))       
+         
+         sidePage = SidePage(_("Calendar"), "clock.svg", self.content_box)
+-        self.sidePages.append((sidePage, "calendar"))
+-        self.changeTimeWidget = ChangeTimeWidget()     
++        self.sidePages.append((sidePage, "calendar"))     
+         sidePage.add_widget(GSettingsCheckButton(_("Show week dates in calendar"), "org.cinnamon.calendar", "show-weekdate"))         
+         sidePage.add_widget(GSettingsEntry(_("Date format for the panel"), "org.cinnamon.calendar", "date-format"))                                 
+         sidePage.add_widget(GSettingsEntry(_("Date format inside the date applet"), "org.cinnamon.calendar", "date-format-full"))                                 
+         sidePage.add_widget(Gtk.LinkButton.new_with_label("http://www.foragoodstrftime.com/", _("Generate your own date formats")))
+-        self.ntpCheckButton = None 
+-        try:
+-            self.ntpCheckButton = DBusCheckButton(_("Use network time"), "org.gnome.SettingsDaemon.DateTimeMechanism", "/", "GetUsingNtp", "SetUsingNtp")
+-            sidePage.add_widget(self.ntpCheckButton)
+-        except:
+-            pass
+-        sidePage.add_widget(self.changeTimeWidget)
+-        try:
+-            sidePage.add_widget(TimeZoneSelectorWidget())
+-        except:
+-            pass
+         
+-        if self.ntpCheckButton != None:
+-            self.ntpCheckButton.connect('toggled', self._ntp_toggled)
+-            self.changeTimeWidget.change_using_ntp( self.ntpCheckButton.get_active() )
+         
+         sidePage = SidePage(_("Hot corner"), "overview.svg", self.content_box)
+         self.sidePages.append((sidePage, "hotcorner"))
+@@ -1347,7 +1092,6 @@ class MainWindow:
+         sidePage.add_widget(GSettingsFontButton(_("Default font"), "org.gnome.desktop.interface", "font-name"))
+         sidePage.add_widget(GSettingsFontButton(_("Document font"), "org.gnome.desktop.interface", "document-font-name"))
+         sidePage.add_widget(GSettingsFontButton(_("Monospace font"), "org.gnome.desktop.interface", "monospace-font-name"))
+-        sidePage.add_widget(GConfFontButton(_("Window title font"), "/apps/metacity/general/titlebar_font"))
+         sidePage.add_widget(GSettingsComboBox(_("Hinting"), "org.gnome.settings-daemon.plugins.xsettings", "hinting", [(i, i.title()) for i in ("none", "slight", "medium", "full")]))
+         sidePage.add_widget(GSettingsComboBox(_("Antialiasing"), "org.gnome.settings-daemon.plugins.xsettings", "antialiasing", [(i, i.title()) for i in ("none", "grayscale", "rgba")]))
+         
+@@ -1394,8 +1138,6 @@ class MainWindow:
+         self.top_button_box.hide()
+         self.side_view_sw.show_all()
+         
+-    def _ntp_toggled(self, widget):
+-        self.changeTimeWidget.change_using_ntp( self.ntpCheckButton.get_active() )
+                 
+                 
+ if __name__ == "__main__":
+--- a/files/usr/lib/cinnamon-settings/tz.py	2012-03-12 14:31:34.000000000 +0000
++++ /dev/null	2012-03-13 10:08:58.957000026 +0000
+@@ -1,35 +0,0 @@
+-import os
+-
+-def load_db():
+-    tz_db = {}
+-    
+-    filename = '/usr/share/zoneinfo/zone.tab'
+-    if not os.path.exists(filename):
+-        filename = '/usr/share/lib/zoneinfo/tab/zone_sun.tab'
+-    if not os.path.exists(filename):
+-        return {}
+-        
+-    tz_file = open(filename)
+-    
+-    for line in tz_file:
+-        line = line.rstrip().lstrip()
+-        if line=="" or line[0] == '#':
+-            continue
+-        
+-        tz_info = line.split('\t')
+-        if len(tz_info)<3:
+-            continue
+-        tz = tz_info[2]
+-        if "/" in tz:
+-            i = tz.index("/")
+-            region = tz[:i]
+-            zone = tz[i+1:]
+-        
+-            if region not in tz_db:
+-                tz_db[region] = []
+-            
+-            tz_db[region].append(zone)
+-        
+-    tz_file.close()
+-    
+-    return tz_db
+--- a/files/usr/share/cinnamon/applets/calendar at cinnamon.org/applet.js	2012-03-12 14:31:34.000000000 +0000
++++ b/files/usr/share/cinnamon/applets/calendar at cinnamon.org/applet.js	2012-03-13 10:56:47.918048379 +0000
+@@ -62,9 +62,7 @@ MyApplet.prototype = {
+             this._calendar = new Calendar.Calendar(this._eventSource);       
+             vbox.add(this._calendar.actor);
+ 
+-            let item = new PopupMenu.PopupMenuItem(_("Date and Time Settings"))
+-            item.connect("activate", Lang.bind(this, this._onLaunchSettings));
+-            //this.menu.addMenuItem(item);
++            item = this.menu.addSettingsAction(_("Date and Time Settings"), 'gnome-datetime-panel.desktop');
+             if (item) {
+                 let separator = new PopupMenu.PopupSeparatorMenuItem();
+                 separator.setColumnWidths(1);
+@@ -96,11 +94,6 @@ MyApplet.prototype = {
+     on_applet_clicked: function(event) {
+         this.menu.toggle();
+     },
+-    
+-    _onLaunchSettings: function() {
+-        this.menu.close();
+-        Util.spawnCommandLine("cinnamon-settings calendar");
+-    },
+ 
+     _updateClockAndDate: function() {
+         let dateFormat = this._calendarSettings.get_string('date-format');       
diff --git a/cinnamon-1.4.1_systray.patch b/cinnamon-1.4.1_systray.patch
new file mode 100644
index 0000000..40a7908
--- /dev/null
+++ b/cinnamon-1.4.1_systray.patch
@@ -0,0 +1,22 @@
+--- a/files/usr/share/cinnamon/applets/systray at cinnamon.org/applet.js
++++ b/files/usr/share/cinnamon/applets/systray at cinnamon.org/applet.js
+@@ -50,12 +50,14 @@ MyApplet.prototype = {
+             box.add_actor(icon);
+ 
+             this._insertStatusItem(box, -1);
+-
++            let width = 22;
++            let height = 22;
+             let themeNode = buttonBox.actor.get_theme_node();
+-            if (!themeNode.get_length('width')) icon.width = 22;
+-            else icon.width = themeNode.get_length('width');
+-            if (!themeNode.get_length('height')) icon.height = 22;
+-            else icon.height = themeNode.get_length('height');
++            if (themeNode.get_length('width'))
++                width = themeNode.get_length('width');
++            if (themeNode.get_length('height'));
++                height = themeNode.get_length('height');
++            icon.set_height(height); // change this to .set_size(width, height) if we figure out why pidgin is messed up
+         }
+         catch (e) {
+             global.logError(e);
diff --git a/cinnamon-menu.patch b/cinnamon-menu.patch
new file mode 100644
index 0000000..4eda3e9
--- /dev/null
+++ b/cinnamon-menu.patch
@@ -0,0 +1,3410 @@
+--- a/files/usr/bin/cinnamon-menu-editor
++++ b/files/usr/bin/cinnamon-menu-editor
+@@ -12,7 +12,7 @@ def main():
+ 	except:
+ 		datadir = '.'
+ 		version = '0.9'
+-	app = MainWindow.MainWindow(datadir, version, sys.argv)
++	app = MainWindow.MainWindow(datadir, version)
+ 	app.run()
+ 
+ if __name__ == '__main__':
+--- a/files/usr/lib/cinnamon-menu-editor/Alacarte/config.py
++++ b/files/usr/lib/cinnamon-menu-editor/Alacarte/config.py
+@@ -5,5 +5,5 @@ pkgdatadir="/usr/share/alacarte"
+ libdir="/usr/lib"
+ libexecdir="/usr/lib/alacarte"
+ PACKAGE="alacarte"
+-VERSION="0.13.2"
++VERSION="3.5.4"
+ GETTEXT_PACKAGE="alacarte"
+--- a/files/usr/lib/cinnamon-menu-editor/Alacarte/MainWindow.py
++++ b/files/usr/lib/cinnamon-menu-editor/Alacarte/MainWindow.py
+@@ -1,4 +1,5 @@
+ # -*- coding: utf-8 -*-
++# vim: set noexpandtab:
+ #   Alacarte Menu Editor - Simple fd.o Compliant Menu Editor
+ #   Copyright (C) 2006  Travis Watkins
+ #
+@@ -16,614 +17,437 @@
+ #   License along with this library; if not, write to the Free Software
+ #   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ 
+-import gtk, gmenu, gobject, gio
+-import cgi, os
+-import gettext, locale
++from gi.repository import Gtk, GObject, Gio, GdkPixbuf, Gdk, GMenu, GLib
++import cgi
++import os
++import gettext
+ import subprocess
+-import urllib
+-try:
+-	from Alacarte import config
+-	gettext.bindtextdomain(config.GETTEXT_PACKAGE,config.localedir)
+-	gettext.textdomain(config.GETTEXT_PACKAGE)
+-	locale.bind_textdomain_codeset(config.GETTEXT_PACKAGE,'UTF-8')
+-except:
+-	pass
++
++from Alacarte import config
++gettext.bindtextdomain(config.GETTEXT_PACKAGE, config.localedir)
++gettext.textdomain(config.GETTEXT_PACKAGE)
++
+ _ = gettext.gettext
+ from Alacarte.MenuEditor import MenuEditor
+ from Alacarte import util
+ 
+-class MainWindow:
+-	timer = None
+-	#hack to make editing menu properties work
+-	allow_update = True
+-	#drag-and-drop stuff
+-	dnd_items = [('ALACARTE_ITEM_ROW', gtk.TARGET_SAME_APP, 0), ('text/plain', 0, 1)]
+-	dnd_menus = [('ALACARTE_MENU_ROW', gtk.TARGET_SAME_APP, 0)]
+-	dnd_both = [dnd_items[0],] + dnd_menus
+-	drag_data = None
+-	edit_pool = []
+-
+-	def __init__(self, datadir, version, argv):
+-		self.file_path = datadir
+-		self.version = version
+-		self.editor = MenuEditor()
+-		gtk.window_set_default_icon_name('alacarte')
+-		self.tree = gtk.Builder()
+-		self.tree.set_translation_domain(config.GETTEXT_PACKAGE)
+-		self.tree.add_from_file('/usr/lib/cinnamon-menu-editor/cinnamon-menu-editor.ui')
+-		self.tree.connect_signals(self)
+-		self.setupMenuTree()
+-		self.setupItemTree()
+-		self.tree.get_object('edit_delete').set_sensitive(False)
+-		self.tree.get_object('edit_revert_to_original').set_sensitive(False)
+-		self.tree.get_object('edit_properties').set_sensitive(False)
+-		self.tree.get_object('move_up_button').set_sensitive(False)
+-		self.tree.get_object('move_down_button').set_sensitive(False)
+-		self.tree.get_object('new_separator_button').set_sensitive(False)
+-		accelgroup = gtk.AccelGroup()
+-		keyval, modifier = gtk.accelerator_parse('<Ctrl>Z')
+-		accelgroup.connect_group(keyval, modifier, gtk.ACCEL_VISIBLE, self.on_mainwindow_undo)
+-		keyval, modifier = gtk.accelerator_parse('<Ctrl><Shift>Z')
+-		accelgroup.connect_group(keyval, modifier, gtk.ACCEL_VISIBLE, self.on_mainwindow_redo)		
+-		self.tree.get_object('mainwindow').add_accel_group(accelgroup)
+-
+-	def run(self):
+-		self.loadMenus()
+-		self.editor.applications.tree.add_monitor(self.menuChanged, None)
+-		self.tree.get_object('mainwindow').show_all()
+-		gtk.main()
+-
+-	def menuChanged(self, *a):
+-		if self.timer:
+-			gobject.source_remove(self.timer)
+-			self.timer = None
+-		self.timer = gobject.timeout_add(3, self.loadUpdates)
+-
+-	def loadUpdates(self):
+-		if not self.allow_update:
+-			return False
+-		menu_tree = self.tree.get_object('menu_tree')
+-		item_tree = self.tree.get_object('item_tree')
+-		items, iter = item_tree.get_selection().get_selected()
+-		update_items = False
+-		item_id, separator_path = None, None
+-		if iter:
+-			update_items = True
+-			if items[iter][3].get_type() == gmenu.TYPE_DIRECTORY:
+-				item_id = os.path.split(items[iter][3].get_desktop_file_path())[1]
+-				update_items = True
+-			elif items[iter][3].get_type() == gmenu.TYPE_ENTRY:
+-				item_id = items[iter][3].get_desktop_file_id()
+-				update_items = True
+-			elif items[iter][3].get_type() == gmenu.TYPE_SEPARATOR:
+-				item_id = items.get_path(iter)
+-				update_items = True
+-		menus, iter = menu_tree.get_selection().get_selected()
+-		update_menus = False
+-		menu_id = None
+-		if iter:
+-			if menus[iter][2].get_desktop_file_path():
+-				menu_id = os.path.split(menus[iter][2].get_desktop_file_path())[1]
+-			else:
+-				menu_id = menus[iter][2].get_menu_id()
+-			update_menus = True
+-		self.loadMenus()
+-		#find current menu in new tree
+-		if update_menus:
+-			menu_tree.get_model().foreach(self.findMenu, menu_id)
+-			menus, iter = menu_tree.get_selection().get_selected()
+-			if iter:
+-				self.on_menu_tree_cursor_changed(menu_tree)
+-		#find current item in new list
+-		if update_items:
+-			i = 0
+-			for item in item_tree.get_model():
+-				found = False
+-				if item[3].get_type() == gmenu.TYPE_ENTRY and item[3].get_desktop_file_id() == item_id:
+-					found = True
+-				if item[3].get_type() == gmenu.TYPE_DIRECTORY and item[3].get_desktop_file_path():
+-					if os.path.split(item[3].get_desktop_file_path())[1] == item_id:
+-						found = True
+-				if item[3].get_type() == gmenu.TYPE_SEPARATOR:
+-					if not isinstance(item_id, tuple):
+-						continue
+-					#separators have no id, have to find them manually
+-					#probably won't work with two separators together
+-					if (item_id[0] - 1,) == (i,):
+-						found = True
+-					elif (item_id[0] + 1,) == (i,):
+-						found = True
+-					elif (item_id[0],) == (i,):
+-						found = True
+-				if found:
+-					item_tree.get_selection().select_path((i,))
+-					self.on_item_tree_cursor_changed(item_tree)
+-					break
+-				i += 1
+-		return False
+-
+-	def findMenu(self, menus, path, iter, menu_id):
+-		if not menus[path][2].get_desktop_file_path():
+-			if menu_id == menus[path][2].get_menu_id():
+-				menu_tree = self.tree.get_object('menu_tree')
+-				menu_tree.expand_to_path(path)
+-				menu_tree.get_selection().select_path(path)
+-				return True
+-			return False
+-		if os.path.split(menus[path][2].get_desktop_file_path())[1] == menu_id:
+-			menu_tree = self.tree.get_object('menu_tree')
+-			menu_tree.expand_to_path(path)
+-			menu_tree.get_selection().select_path(path)
+-			return True
+-
+-	def setupMenuTree(self):
+-		self.menu_store = gtk.TreeStore(gtk.gdk.Pixbuf, str, object)
+-		menus = self.tree.get_object('menu_tree')
+-		column = gtk.TreeViewColumn(_("Name"))
+-		column.set_spacing(4)
+-		cell = gtk.CellRendererPixbuf()
+-		column.pack_start(cell, False)
+-		column.set_attributes(cell, pixbuf=0)
+-		cell = gtk.CellRendererText()
+-		cell.set_fixed_size(-1, 25)
+-		column.pack_start(cell, True)
+-		column.set_attributes(cell, markup=1)
+-		column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
+-		menus.append_column(column)
+-		menus.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, self.dnd_menus, gtk.gdk.ACTION_COPY)
+-		menus.enable_model_drag_dest(self.dnd_both, gtk.gdk.ACTION_PRIVATE)
+-
+-	def setupItemTree(self):
+-		items = self.tree.get_object('item_tree')
+-		column = gtk.TreeViewColumn(_("Show"))
+-		cell = gtk.CellRendererToggle()
+-		cell.connect('toggled', self.on_item_tree_show_toggled)
+-		column.pack_start(cell, True)
+-		column.set_attributes(cell, active=0)
+-		#hide toggle for separators
+-		column.set_cell_data_func(cell, self._cell_data_toggle_func)
+-		items.append_column(column)
+-		column = gtk.TreeViewColumn(_("Item"))
+-		column.set_spacing(4)
+-		cell = gtk.CellRendererPixbuf()
+-		column.pack_start(cell, False)
+-		column.set_attributes(cell, pixbuf=1)
+-		cell = gtk.CellRendererText()
+-		cell.set_fixed_size(-1, 25)
+-		column.pack_start(cell, True)
+-		column.set_attributes(cell, markup=2)
+-		items.append_column(column)
+-		self.item_store = gtk.ListStore(bool, gtk.gdk.Pixbuf, str, object)
+-		items.set_model(self.item_store)
+-		items.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, self.dnd_items, gtk.gdk.ACTION_COPY)
+-		items.enable_model_drag_dest(self.dnd_items, gtk.gdk.ACTION_PRIVATE)
+-
+-	def _cell_data_toggle_func(self, tree_column, renderer, model, treeiter):
+-		if model[treeiter][3].get_type() == gmenu.TYPE_SEPARATOR:
+-			renderer.set_property('visible', False)
+-		else:
+-			renderer.set_property('visible', True)
+-
+-	def loadMenus(self):
+-		self.menu_store.clear()
+-		for menu in self.editor.getMenus():
+-			iters = [None]*20
+-			self.loadMenu(iters, menu)
+-		menu_tree = self.tree.get_object('menu_tree')
+-		menu_tree.set_model(self.menu_store)
+-		for menu in self.menu_store:
+-			#this might not work for some reason
+-			try:
+-				menu_tree.expand_to_path(menu.path)
+-			except:
+-				pass
+-		menu_tree.get_selection().select_path((0,))
+-		self.on_menu_tree_cursor_changed(menu_tree)
+-
+-	def loadMenu(self, iters, parent, depth=0):
+-		if depth == 0:
+-			icon = util.getIcon(parent)
+-			iters[depth] = self.menu_store.append(None, (icon, cgi.escape(parent.get_name()), parent))
+-		depth += 1
+-		for menu, show in self.editor.getMenus(parent):
+-			if show:
+-				name = cgi.escape(menu.get_name())
+-			else:
+-				name = '<small><i>' + cgi.escape(menu.get_name()) + '</i></small>'
+-			icon = util.getIcon(menu)
+-			iters[depth] = self.menu_store.append(iters[depth-1], (icon, name, menu))
+-			self.loadMenu(iters, menu, depth)
+-		depth -= 1
+-
+-	def loadItems(self, menu, menu_path):
+-		self.item_store.clear()
+-		for item, show in self.editor.getItems(menu):
+-			menu_icon = None
+-			if item.get_type() == gmenu.TYPE_SEPARATOR:
+-				name = '---'
+-				icon = None
+-			elif item.get_type() == gmenu.TYPE_ENTRY:
+-				if show:
+-					name = cgi.escape(item.get_display_name())
+-				else:
+-					name = '<small><i>' + cgi.escape(item.get_display_name()) + '</i></small>'
+-				icon = util.getIcon(item)
+-			else:
+-				if show:
+-					name = cgi.escape(item.get_name())
+-				else:
+-					name = '<small><i>' + cgi.escape(item.get_name()) + '</i></small>'
+-				icon = util.getIcon(item)
+-			self.item_store.append((show, icon, name, item))
+-
+-	#this is a little timeout callback to insert new items after
+-	#gnome-desktop-item-edit has finished running
+-	def waitForNewItemProcess(self, process, parent, file_path):
+-		if process.poll() != None:
+-			if os.path.isfile(file_path):
+-				self.editor.insertExternalItem(os.path.split(file_path)[1], parent)
+-			return False
+-		return True
+-
+-	def waitForNewMenuProcess(self, process, parent_id, file_path):
+-		if process.poll() != None:
+-			#hack for broken gnome-desktop-item-edit
+-			broken_path = os.path.join(os.path.split(file_path)[0], '.directory')
+-			if os.path.isfile(broken_path):
+-				os.rename(broken_path, file_path)
+-			if os.path.isfile(file_path):
+-				self.editor.insertExternalMenu(os.path.split(file_path)[1], parent_id)
+-			return False
+-		return True
+-
+-	#this callback keeps you from editing the same item twice
+-	def waitForEditProcess(self, process, file_path):
+-		if process.poll() != None:
+-			self.edit_pool.remove(file_path)
+-			return False
+-		return True
+-
+-	def on_new_menu_button_clicked(self, button):
+-		menu_tree = self.tree.get_object('menu_tree')
+-		menus, iter = menu_tree.get_selection().get_selected()
+-		if not iter:
+-			parent = menus[(0,)][2]
+-			menu_tree.expand_to_path((0,))
+-			menu_tree.get_selection().select_path((0,))
+-		else:
+-			parent = menus[iter][2]
+-		file_path = os.path.join(util.getUserDirectoryPath(), util.getUniqueFileId('alacarte-made', '.directory'))
+-		process = subprocess.Popen(['gnome-desktop-item-edit', file_path], env=os.environ)
+-		gobject.timeout_add(100, self.waitForNewMenuProcess, process, parent.menu_id, file_path)
+-
+-	def on_new_item_button_clicked(self, button):
+-		menu_tree = self.tree.get_object('menu_tree')
+-		menus, iter = menu_tree.get_selection().get_selected()
+-		if not iter:
+-			parent = menus[(0,)][2]
+-			menu_tree.expand_to_path((0,))
+-			menu_tree.get_selection().select_path((0,))
+-		else:
+-			parent = menus[iter][2]
+-		file_path = os.path.join(util.getUserItemPath(), util.getUniqueFileId('alacarte-made', '.desktop'))
+-		process = subprocess.Popen(['gnome-desktop-item-edit', file_path], env=os.environ)
+-		gobject.timeout_add(100, self.waitForNewItemProcess, process, parent, file_path)
+-
+-	def on_new_separator_button_clicked(self, button):
+-		item_tree = self.tree.get_object('item_tree')
+-		items, iter = item_tree.get_selection().get_selected()
+-		if not iter:
+-			return
+-		else:
+-			after = items[iter][3]
+-			menu_tree = self.tree.get_object('menu_tree')
+-			menus, iter = menu_tree.get_selection().get_selected()
+-			parent = menus[iter][2]
+-			self.editor.createSeparator(parent, after=after)
+-
+-	def on_edit_delete_activate(self, menu):
+-		item_tree = self.tree.get_object('item_tree')
+-		items, iter = item_tree.get_selection().get_selected()
+-		if not iter:
+-			return
+-		item = items[iter][3]
+-		if item.get_type() == gmenu.TYPE_ENTRY:
+-			self.editor.deleteItem(item)
+-		elif item.get_type() == gmenu.TYPE_DIRECTORY:
+-			self.editor.deleteMenu(item)
+-		elif item.get_type() == gmenu.TYPE_SEPARATOR:
+-			self.editor.deleteSeparator(item)
+-
+-	def on_edit_revert_to_original_activate(self, menu):
+-		item_tree = self.tree.get_object('item_tree')
+-		items, iter = item_tree.get_selection().get_selected()
+-		if not iter:
+-			return
+-		item = items[iter][3]
+-		if item.get_type() == gmenu.TYPE_ENTRY:
+-			self.editor.revertItem(item)
+-		elif item.get_type() == gmenu.TYPE_DIRECTORY:
+-			self.editor.revertMenu(item)
+-
+-	def on_edit_properties_activate(self, menu):
+-		item_tree = self.tree.get_object('item_tree')
+-		items, iter = item_tree.get_selection().get_selected()
+-		if not iter:
+-			return
+-		item = items[iter][3]
+-		if item.get_type() not in (gmenu.TYPE_ENTRY, gmenu.TYPE_DIRECTORY):
+-			return
+-
+-		if item.get_type() == gmenu.TYPE_ENTRY:
+-			file_path = os.path.join(util.getUserItemPath(), item.get_desktop_file_id())
+-			file_type = 'Item'
+-		elif item.get_type() == gmenu.TYPE_DIRECTORY:
+-			if item.get_desktop_file_path() == None:
+-				file_path = util.getUniqueFileId('alacarte-made', '.directory')
+-				parser = util.DesktopParser(file_path, 'Directory')
+-				parser.set('Name', item.get_name())
+-				parser.set('Comment', item.get_comment())
+-				parser.set('Icon', item.get_icon())
+-				parser.write(open(file_path))
+-			else:
+-				file_path = os.path.join(util.getUserDirectoryPath(), os.path.split(item.get_desktop_file_path())[1])
+-			file_type = 'Menu'
+-
+-		if not os.path.isfile(file_path):
+-			data = open(item.get_desktop_file_path()).read()
+-			open(file_path, 'w').write(data)
+-			self.editor._MenuEditor__addUndo([(file_type, os.path.split(file_path)[1]),])
+-		else:
+-			self.editor._MenuEditor__addUndo([item,])
+-		if file_path not in self.edit_pool:
+-			self.edit_pool.append(file_path)
+-			process = subprocess.Popen(['gnome-desktop-item-edit', file_path], env=os.environ)
+-			gobject.timeout_add(100, self.waitForEditProcess, process, file_path)
+-
+-	def on_menu_tree_cursor_changed(self, treeview):
+-		menus, iter = treeview.get_selection().get_selected()
+-		menu_path = menus.get_path(iter)
+-		item_tree = self.tree.get_object('item_tree')
+-		item_tree.get_selection().unselect_all()
+-		self.loadItems(self.menu_store[menu_path][2], menu_path)
+-		self.tree.get_object('edit_delete').set_sensitive(False)
+-		self.tree.get_object('edit_revert_to_original').set_sensitive(False)
+-		self.tree.get_object('edit_properties').set_sensitive(False)
+-		self.tree.get_object('move_up_button').set_sensitive(False)
+-		self.tree.get_object('move_down_button').set_sensitive(False)
+-		self.tree.get_object('new_separator_button').set_sensitive(False)
+-		self.tree.get_object('properties_button').set_sensitive(False)
+-		self.tree.get_object('delete_button').set_sensitive(False)
+-
+-	def on_menu_tree_drag_data_get(self, treeview, context, selection, target_id, etime):
+-		menus, iter = treeview.get_selection().get_selected()
+-		self.drag_data = menus[iter][2]
+-
+-	def on_menu_tree_drag_data_received(self, treeview, context, x, y, selection, info, etime):
+-		menus = treeview.get_model()
+-		drop_info = treeview.get_dest_row_at_pos(x, y)
+-		if drop_info:
+-			path, position = drop_info
+-			types = (gtk.TREE_VIEW_DROP_INTO_OR_BEFORE, gtk.TREE_VIEW_DROP_INTO_OR_AFTER)
+-			if position not in types:
+-				context.finish(False, False, etime)
+-				return False
+-			if selection.target in ('ALACARTE_ITEM_ROW', 'ALACARTE_MENU_ROW'):
+-				if self.drag_data == None:
+-					return False
+-				item = self.drag_data
+-				new_parent = menus[path][2]
+-				treeview.get_selection().select_path(path)
+-				if item.get_type() == gmenu.TYPE_ENTRY:
+-					self.editor.copyItem(item, new_parent)
+-				elif item.get_type() == gmenu.TYPE_DIRECTORY:
+-					if self.editor.moveMenu(item, new_parent) == False:
+-						self.loadUpdates()
+-				else:
+-					context.finish(False, False, etime) 
+-				context.finish(True, True, etime)
+-		self.drag_data = None
+-
+-	def on_item_tree_show_toggled(self, cell, path):
+-		item = self.item_store[path][3]
+-		if item.get_type() == gmenu.TYPE_SEPARATOR:
+-			return
+-		if self.item_store[path][0]:
+-			self.editor.setVisible(item, False)
+-		else:
+-			self.editor.setVisible(item, True)
+-		self.item_store[path][0] = not self.item_store[path][0]
+-
+-	def on_item_tree_cursor_changed(self, treeview):
+-		items, iter = treeview.get_selection().get_selected()
+-		if iter is None:
+-			return
+-		item = items[iter][3]
+-		self.tree.get_object('edit_delete').set_sensitive(True)
+-		self.tree.get_object('new_separator_button').set_sensitive(True)
+-		self.tree.get_object('delete_button').set_sensitive(True)
+-		if self.editor.canRevert(item):
+-			self.tree.get_object('edit_revert_to_original').set_sensitive(True)
+-		else:
+-			self.tree.get_object('edit_revert_to_original').set_sensitive(False)
+-		if not item.get_type() == gmenu.TYPE_SEPARATOR:
+-			self.tree.get_object('edit_properties').set_sensitive(True)
+-			self.tree.get_object('properties_button').set_sensitive(True)
+-		else:
+-			self.tree.get_object('edit_properties').set_sensitive(False)
+-			self.tree.get_object('properties_button').set_sensitive(False)
+-
+-		# If first item...
+-		if items.get_path(iter)[0] == 0:
+-			self.tree.get_object('move_up_button').set_sensitive(False)
+-		else:
+-			self.tree.get_object('move_up_button').set_sensitive(True)
+-
+-		# If last item...
+-		if items.get_path(iter)[0] == (len(items)-1):
+-			self.tree.get_object('move_down_button').set_sensitive(False)
+-		else:
+-			self.tree.get_object('move_down_button').set_sensitive(True)
+-
+-	def on_item_tree_row_activated(self, treeview, path, column):
+-		self.on_edit_properties_activate(None)
+-
+-	def on_item_tree_popup_menu(self, item_tree, event=None):
+-		model, iter = item_tree.get_selection().get_selected()
+-		if event:
+-			#don't show if it's not the right mouse button
+-			if event.button != 3:
+-				return
+-			button = event.button
+-			event_time = event.time
+-			info = item_tree.get_path_at_pos(int(event.x), int(event.y))
+-			if info != None:
+-				path, col, cellx, celly = info
+-				item_tree.grab_focus()
+-				item_tree.set_cursor(path, col, 0)
+-		else:
+-			path = model.get_path(iter)
+-			button = 0
+-			event_time = 0
+-			item_tree.grab_focus()
+-			item_tree.set_cursor(path, item_tree.get_columns()[0], 0)
+-		popup = self.tree.get_object('edit_menu')
+-		popup.popup(None, None, None, button, event_time)
+-		#without this shift-f10 won't work
+-		return True
+-
+-	def on_item_tree_drag_data_get(self, treeview, context, selection, target_id, etime):
+-		items, iter = treeview.get_selection().get_selected()
+-		self.drag_data = items[iter][3]
+-
+-	def on_item_tree_drag_data_received(self, treeview, context, x, y, selection, info, etime):
+-		items = treeview.get_model()
+-		types = (gtk.TREE_VIEW_DROP_BEFORE,	gtk.TREE_VIEW_DROP_INTO_OR_BEFORE)
+-		if selection.target == 'ALACARTE_ITEM_ROW':
+-			drop_info = treeview.get_dest_row_at_pos(x, y)
+-			before = None
+-			after = None
+-			if self.drag_data == None:
+-				return False
+-			item = self.drag_data
+-			if drop_info:
+-				path, position = drop_info
+-				if position in types:
+-					before = items[path][3]
+-				else:
+-					after = items[path][3]
+-			else:
+-				path = (len(items) - 1,)
+-				after = items[path][3]
+-			if item.get_type() == gmenu.TYPE_ENTRY:
+-				self.editor.moveItem(item, item.get_parent(), before, after)
+-			elif item.get_type() == gmenu.TYPE_DIRECTORY:
+-				if self.editor.moveMenu(item, item.get_parent(), before, after) == False:
+-					self.loadUpdates()
+-			elif item.get_type() == gmenu.TYPE_SEPARATOR:
+-				self.editor.moveSeparator(item, item.get_parent(), before, after)
+-			context.finish(True, True, etime)
+-		elif selection.target == 'text/plain':
+-			if selection.data == None:
+-				return False
+-			menus, iter = self.tree.get_object('menu_tree').get_selection().get_selected()
+-			parent = menus[iter][2]
+-			drop_info = treeview.get_dest_row_at_pos(x, y)
+-			before = None
+-			after = None
+-			if drop_info:
+-				path, position = drop_info
+-				if position in types:
+-					before = items[path][3]
+-				else:
+-					after = items[path][3]
+-			else:
+-				path = (len(items) - 1,)
+-				after = items[path][3]
+-			file_path = urllib.unquote(selection.data).strip()
+-			if not file_path.startswith('file:'):
+-				return
+-			myfile = gio.File(uri=file_path)
+-			file_info = myfile.query_info(gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE)
+-			content_type = file_info.get_content_type()
+-			if content_type == 'application/x-desktop':
+-				input_stream = myfile.read()
+-				open('/tmp/alacarte-dnd.desktop', 'w').write(input_stream.read())
+-				parser = util.DesktopParser('/tmp/alacarte-dnd.desktop')
+-				self.editor.createItem(parent, parser.get('Icon'), parser.get('Name', self.editor.locale), parser.get('Comment', self.editor.locale), parser.get('Exec'), parser.get('Terminal'), before, after)
+-			elif content_type in ('application/x-shellscript', 'application/x-executable'):
+-				self.editor.createItem(parent, None, os.path.split(file_path)[1].strip(), None, file_path.replace('file://', '').strip(), False, before, after)
+-		self.drag_data = None
+-
+-	def on_item_tree_key_press_event(self, item_tree, event):
+-		if event.keyval == gtk.keysyms.Delete:
+-			self.on_edit_delete_activate(item_tree)
+-
+-	def on_move_up_button_clicked(self, button):
+-		item_tree = self.tree.get_object('item_tree')
+-		items, iter = item_tree.get_selection().get_selected()
+-		if not iter:
+-			return
+-		path = items.get_path(iter)
+-		#at top, can't move up
+-		if path[0] == 0:
+-			return
+-		item = items[path][3]
+-		before = items[(path[0] - 1,)][3]
+-		if item.get_type() == gmenu.TYPE_ENTRY:
+-			self.editor.moveItem(item, item.get_parent(), before=before)
+-		elif item.get_type() == gmenu.TYPE_DIRECTORY:
+-			self.editor.moveMenu(item, item.get_parent(), before=before)
+-		elif item.get_type() == gmenu.TYPE_SEPARATOR:
+-			self.editor.moveSeparator(item, item.get_parent(), before=before)
+-
+-	def on_move_down_button_clicked(self, button):
+-		item_tree = self.tree.get_object('item_tree')
+-		items, iter = item_tree.get_selection().get_selected()
+-		if not iter:
+-			return
+-		path = items.get_path(iter)
+-		#at bottom, can't move down
+-		if path[0] == (len(items) - 1):
+-			return
+-		item = items[path][3]
+-		after = items[path][3]
+-		if item.get_type() == gmenu.TYPE_ENTRY:
+-			self.editor.moveItem(item, item.get_parent(), after=after)
+-		elif item.get_type() == gmenu.TYPE_DIRECTORY:
+-			self.editor.moveMenu(item, item.get_parent(), after=after)
+-		elif item.get_type() == gmenu.TYPE_SEPARATOR:
+-			self.editor.moveSeparator(item, item.get_parent(), after=after)
+-
+-	def on_mainwindow_undo(self, accelgroup, window, keyval, modifier):
+-		self.editor.undo()
+-
+-	def on_mainwindow_redo(self, accelgroup, window, keyval, modifier):
+-		self.editor.redo()	
+-
+-	def on_revert_button_clicked(self, button):
+-		dialog = self.tree.get_object('revertdialog')
+-		dialog.set_transient_for(self.tree.get_object('mainwindow'))
+-		dialog.show_all()
+-		if dialog.run() == gtk.RESPONSE_YES:
+-			self.editor.revert()
+-		dialog.hide()
+-
+-	def on_close_button_clicked(self, button):
+-		try:
+-			self.tree.get_object('mainwindow').hide()
+-		except:
+-			pass
+-		gobject.timeout_add(10, self.quit)
+-
+-	def on_properties_button_clicked(self, button):
+-		self.on_edit_properties_activate(None)
+-	def on_delete_button_clicked(self, button):
+-		self.on_edit_delete_activate(None)
+-
+-	def on_style_set(self, *args):
+-		self.loadUpdates()
+-
+-	def quit(self):
+-		self.editor.quit()
+-		gtk.main_quit()		
++class MainWindow(object):
++    timer = None
++    #hack to make editing menu properties work
++    edit_pool = []
++
++    def __init__(self, datadir, version):
++        self.file_path = datadir
++        self.version = version
++        self.editor = MenuEditor()
++        self.editor.tree.connect("changed", self.menuChanged)
++        Gtk.Window.set_default_icon_name('alacarte')
++        self.tree = Gtk.Builder()
++        self.tree.set_translation_domain(config.GETTEXT_PACKAGE)
++        self.tree.add_from_file('/usr/lib/cinnamon-menu-editor/cinnamon-menu-editor.ui')
++        self.tree.connect_signals(self)
++        self.setupMenuTree()
++        self.setupItemTree()
++        self.tree.get_object('edit_delete').set_sensitive(False)
++        self.tree.get_object('edit_properties').set_sensitive(False)
++        self.tree.get_object('move_up_button').set_sensitive(False)
++        self.tree.get_object('move_down_button').set_sensitive(False)
++        self.tree.get_object('new_separator_button').set_sensitive(False)
++        accelgroup = Gtk.AccelGroup()
++        keyval, modifier = Gtk.accelerator_parse('F1')
++        accelgroup.connect(keyval, modifier, Gtk.AccelFlags.VISIBLE, self.on_help_button_clicked)
++        self.tree.get_object('mainwindow').add_accel_group(accelgroup)
++
++    def run(self):
++        self.loadMenus()
++        self.tree.get_object('mainwindow').show_all()
++        Gtk.main()
++
++    def menuChanged(self, *a):
++        self.loadUpdates()
++
++    def loadUpdates(self):
++        menu_tree = self.tree.get_object('menu_tree')
++        item_tree = self.tree.get_object('item_tree')
++        items, iter = item_tree.get_selection().get_selected()
++        update_items = False
++        update_type = None
++        item_id = None
++        if iter:
++            update_items = True
++            if isinstance(items[iter][3], GMenu.TreeEntry):
++                item_id = items[iter][3].get_desktop_file_id()
++                update_type = GMenu.TreeItemType.ENTRY
++            elif isinstance(items[iter][3], GMenu.TreeDirectory):
++                item_id = os.path.split(items[iter][3].get_desktop_file_path())[1]
++                update_type = GMenu.TreeItemType.DIRECTORY
++            elif isinstance(items[iter][3], GMenu.TreeSeparator):
++                item_id = items.get_path(iter)
++                update_type = GMenu.TreeItemType.SEPARATOR
++        menus, iter = menu_tree.get_selection().get_selected()
++        update_menus = False
++        menu_id = None
++        if iter:
++            if menus[iter][2].get_desktop_file_path():
++                menu_id = os.path.split(menus[iter][2].get_desktop_file_path())[1]
++            else:
++                menu_id = menus[iter][2].get_menu_id()
++            update_menus = True
++        self.loadMenus()
++        #find current menu in new tree
++        if update_menus:
++            menu_tree.get_model().foreach(self.findMenu, menu_id)
++            menus, iter = menu_tree.get_selection().get_selected()
++            if iter:
++                self.on_menu_tree_cursor_changed(menu_tree)
++        #find current item in new list
++        if update_items:
++            i = 0
++            for item in item_tree.get_model():
++                found = False
++                if update_type != GMenu.TreeItemType.SEPARATOR:
++                    if isinstance (item[3], GMenu.TreeEntry) and item[3].get_desktop_file_id() == item_id:
++                        found = True
++                    if isinstance (item[3], GMenu.TreeDirectory) and item[3].get_desktop_file_path() and update_type == GMenu.TreeItemType.DIRECTORY:
++                        if os.path.split(item[3].get_desktop_file_path())[1] == item_id:
++                            found = True
++                if isinstance(item[3], GMenu.TreeSeparator):
++                    if not isinstance(item_id, tuple):
++                        #we may not skip the increment via "continue"
++                        i += 1
++                        continue
++                    #separators have no id, have to find them manually
++                    #probably won't work with two separators together
++                    if (item_id[0] - 1,) == (i,):
++                        found = True
++                    elif (item_id[0] + 1,) == (i,):
++                        found = True
++                    elif (item_id[0],) == (i,):
++                        found = True
++                if found:
++                    item_tree.get_selection().select_path((i,))
++                    self.on_item_tree_cursor_changed(item_tree)
++                    break
++                i += 1
++        return False
++
++    def findMenu(self, menus, path, iter, menu_id):
++        if not menus[path][2].get_desktop_file_path():
++            if menu_id == menus[path][2].get_menu_id():
++                menu_tree = self.tree.get_object('menu_tree')
++                menu_tree.expand_to_path(path)
++                menu_tree.get_selection().select_path(path)
++                return True
++            return False
++        if os.path.split(menus[path][2].get_desktop_file_path())[1] == menu_id:
++            menu_tree = self.tree.get_object('menu_tree')
++            menu_tree.expand_to_path(path)
++            menu_tree.get_selection().select_path(path)
++            return True
++
++    def setupMenuTree(self):
++        self.menu_store = Gtk.TreeStore(GdkPixbuf.Pixbuf, str, object)
++        menus = self.tree.get_object('menu_tree')
++        column = Gtk.TreeViewColumn(_('Name'))
++        column.set_spacing(4)
++        cell = Gtk.CellRendererPixbuf()
++        column.pack_start(cell, False)
++        column.add_attribute(cell, 'pixbuf', 0)
++        cell = Gtk.CellRendererText()
++        column.pack_start(cell, True)
++        column.add_attribute(cell, 'markup', 1)
++        menus.append_column(column)
++        menus.get_selection().set_mode(Gtk.SelectionMode.BROWSE)
++
++    def setupItemTree(self):
++        items = self.tree.get_object('item_tree')
++        column = Gtk.TreeViewColumn(_('Show'))
++        cell = Gtk.CellRendererToggle()
++        cell.connect('toggled', self.on_item_tree_show_toggled)
++        column.pack_start(cell, True)
++        column.add_attribute(cell, 'active', 0)
++        #hide toggle for separators
++        column.set_cell_data_func(cell, self._cell_data_toggle_func)
++        items.append_column(column)
++        column = Gtk.TreeViewColumn(_('Item'))
++        column.set_spacing(4)
++        cell = Gtk.CellRendererPixbuf()
++        column.pack_start(cell, False)
++        column.add_attribute(cell, 'pixbuf', 1)
++        cell = Gtk.CellRendererText()
++        column.pack_start(cell, True)
++        column.add_attribute(cell, 'markup', 2)
++        items.append_column(column)
++        self.item_store = Gtk.ListStore(bool, GdkPixbuf.Pixbuf, str, object)
++        items.set_model(self.item_store)
++
++    def _cell_data_toggle_func(self, tree_column, renderer, model, treeiter, data=None):
++        if isinstance(model[treeiter][3], GMenu.TreeSeparator):
++            renderer.set_property('visible', False)
++        else:
++            renderer.set_property('visible', True)
++
++    def loadMenus(self):
++        self.menu_store.clear()
++        self.loadMenu({ None: None })
++
++        menu_tree = self.tree.get_object('menu_tree')
++        menu_tree.set_model(self.menu_store)
++        for menu in self.menu_store:
++            menu_tree.expand_to_path(menu.path)
++        menu_tree.get_selection().select_path((0,))
++        self.on_menu_tree_cursor_changed(menu_tree)
++
++    def loadMenu(self, iters, parent=None):
++        for menu, show in self.editor.getMenus(parent):
++            name = cgi.escape(menu.get_name())
++            if not show:
++                name = "<small><i>%s</i></small>" % (name,)
++
++            icon = util.getIcon(menu)
++            iters[menu] = self.menu_store.append(iters[parent], (icon, name, menu))
++            self.loadMenu(iters, menu)
++
++    def loadItems(self, menu):
++        self.item_store.clear()
++        for item, show in self.editor.getItems(menu):
++            icon = util.getIcon(item)
++            if isinstance(item, GMenu.TreeDirectory):
++                name = item.get_name()
++            elif isinstance(item, GMenu.TreeEntry):
++                name = item.get_app_info().get_display_name()
++            elif isinstance(item, GMenu.TreeSeparator):
++                name = '---'
++            else:
++                assert False, 'should not be reached'
++
++            name = cgi.escape(name)
++            if not show:
++                name = "<small><i>%s</i></small>" % (name,)
++
++            self.item_store.append((show, icon, name, item))
++
++    #this is a little timeout callback to insert new items after
++    #gnome-desktop-item-edit has finished running
++    def waitForNewItemProcess(self, process, parent_id, file_path):
++        if process.poll() is not None:
++            if os.path.isfile(file_path):
++                self.editor.insertExternalItem(os.path.split(file_path)[1], parent_id)
++            return False
++        return True
++
++    def waitForNewMenuProcess(self, process, parent_id, file_path):
++        if process.poll() is not None:
++            if os.path.isfile(file_path):
++                self.editor.insertExternalMenu(os.path.split(file_path)[1], parent_id)
++            return False
++        return True
++
++    #this callback keeps you from editing the same item twice
++    def waitForEditProcess(self, process, file_path):
++        if process.poll() is not None:
++            self.edit_pool.remove(file_path)
++            return False
++        return True
++
++    def on_new_menu_button_clicked(self, button):
++        menu_tree = self.tree.get_object('menu_tree')
++        menus, iter = menu_tree.get_selection().get_selected()
++        if not iter:
++            parent = menus[(0,)][2]
++            menu_tree.expand_to_path((0,))
++            menu_tree.get_selection().select_path((0,))
++        else:
++            parent = menus[iter][2]
++        file_path = os.path.join(util.getUserDirectoryPath(), util.getUniqueFileId('alacarte-made', '.directory'))
++        process = subprocess.Popen(['gnome-desktop-item-edit', file_path], env=os.environ)
++        GObject.timeout_add(100, self.waitForNewMenuProcess, process, parent.get_menu_id(), file_path)
++
++    def on_new_item_button_clicked(self, button):
++        menu_tree = self.tree.get_object('menu_tree')
++        menus, iter = menu_tree.get_selection().get_selected()
++        if not iter:
++            parent = menus[(0,)][2]
++            menu_tree.expand_to_path((0,))
++            menu_tree.get_selection().select_path((0,))
++        else:
++            parent = menus[iter][2]
++        file_path = os.path.join(util.getUserItemPath(), util.getUniqueFileId('alacarte-made', '.desktop'))
++        process = subprocess.Popen(['gnome-desktop-item-edit', file_path], env=os.environ)
++        GObject.timeout_add(100, self.waitForNewItemProcess, process, parent.get_menu_id(), file_path)
++
++    def on_new_separator_button_clicked(self, button):
++        item_tree = self.tree.get_object('item_tree')
++        items, iter = item_tree.get_selection().get_selected()
++        if not iter:
++            return
++        else:
++            after = items[iter][3]
++            menu_tree = self.tree.get_object('menu_tree')
++            menus, iter = menu_tree.get_selection().get_selected()
++            parent = menus[iter][2]
++            self.editor.createSeparator(parent, after=after)
++
++    def on_edit_delete_activate(self, menu):
++        item_tree = self.tree.get_object('item_tree')
++        items, iter = item_tree.get_selection().get_selected()
++        if not iter:
++            return
++        item = items[iter][3]
++        if isinstance(item, GMenu.TreeEntry):
++            self.editor.deleteItem(item)
++        elif isinstance(item, GMenu.TreeDirectory):
++            self.editor.deleteMenu(item)
++        elif isinstance(item, GMenu.TreeSeparator):
++            self.editor.deleteSeparator(item)
++
++    def on_edit_properties_activate(self, menu):
++        item_tree = self.tree.get_object('item_tree')
++        items, iter = item_tree.get_selection().get_selected()
++        if not iter:
++            return
++        item = items[iter][3]
++        if not isinstance(item, GMenu.TreeEntry) and not isinstance(item, GMenu.TreeDirectory):
++            return
++
++        if isinstance(item, GMenu.TreeEntry):
++            file_path = os.path.join(util.getUserItemPath(), item.get_desktop_file_id())
++            file_type = 'Item'
++        elif isinstance(item, GMenu.TreeDirectory):
++            file_path = os.path.join(util.getUserDirectoryPath(), os.path.split(item.get_desktop_file_path())[1])
++            file_type = 'Menu'
++
++        if not os.path.isfile(file_path):
++            data = open(item.get_desktop_file_path()).read()
++            open(file_path, 'w').write(data)
++
++        if file_path not in self.edit_pool:
++            self.edit_pool.append(file_path)
++            process = subprocess.Popen(['gnome-desktop-item-edit', file_path], env=os.environ)
++            GObject.timeout_add(100, self.waitForEditProcess, process, file_path)
++
++    def on_menu_tree_cursor_changed(self, treeview):
++        selection = treeview.get_selection()
++        if selection is None:
++            return
++        menus, iter = selection.get_selected()
++        if iter is None:
++            return
++        menu_path = menus.get_path(iter)
++        item_tree = self.tree.get_object('item_tree')
++        item_tree.get_selection().unselect_all()
++        self.loadItems(self.menu_store[menu_path][2])
++        self.tree.get_object('edit_delete').set_sensitive(False)
++        self.tree.get_object('edit_properties').set_sensitive(False)
++        self.tree.get_object('move_up_button').set_sensitive(False)
++        self.tree.get_object('move_down_button').set_sensitive(False)
++        self.tree.get_object('new_separator_button').set_sensitive(False)
++        self.tree.get_object('properties_button').set_sensitive(False)
++        self.tree.get_object('delete_button').set_sensitive(False)
++
++    def on_item_tree_show_toggled(self, cell, path):
++        item = self.item_store[path][3]
++        if isinstance(item, GMenu.TreeSeparator):
++            return
++        if self.item_store[path][0]:
++            self.editor.setVisible(item, False)
++        else:
++            self.editor.setVisible(item, True)
++        self.item_store[path][0] = not self.item_store[path][0]
++
++    def on_item_tree_cursor_changed(self, treeview):
++        selection = treeview.get_selection()
++        if selection is None:
++            return
++        items, iter = selection.get_selected()
++        if iter is None:
++            return
++
++        item = items[iter][3]
++        self.tree.get_object('edit_delete').set_sensitive(True)
++        self.tree.get_object('new_separator_button').set_sensitive(True)
++        self.tree.get_object('delete_button').set_sensitive(True)
++
++        can_edit = not isinstance(item, GMenu.TreeSeparator)
++        self.tree.get_object('edit_properties').set_sensitive(can_edit)
++        self.tree.get_object('properties_button').set_sensitive(can_edit)
++
++        index = items.get_path(iter).get_indices()[0]
++        can_go_up = index > 0
++        can_go_down = index < len(items) - 1
++        self.tree.get_object('move_up_button').set_sensitive(can_go_up)
++        self.tree.get_object('move_down_button').set_sensitive(can_go_down)
++
++    def on_item_tree_row_activated(self, treeview, path, column):
++        self.on_edit_properties_activate(None)
++
++    def on_item_tree_popup_menu(self, item_tree, event=None):
++        model, iter = item_tree.get_selection().get_selected()
++        if event:
++            #don't show if it's not the right mouse button
++            if event.button != 3:
++                return
++            button = event.button
++            event_time = event.time
++            info = item_tree.get_path_at_pos(int(event.x), int(event.y))
++            if info is not None:
++                path, col, cellx, celly = info
++                item_tree.grab_focus()
++                item_tree.set_cursor(path, col, 0)
++        else:
++            path = model.get_path(iter)
++            button = 0
++            event_time = 0
++            item_tree.grab_focus()
++            item_tree.set_cursor(path, item_tree.get_columns()[0], 0)
++        popup = self.tree.get_object('edit_menu')
++        popup.popup(None, None, None, None, button, event_time)
++        #without this shift-f10 won't work
++        return True
++
++    def on_item_tree_key_press_event(self, item_tree, event):
++        if event.keyval == Gdk.KEY_Delete:
++            self.on_edit_delete_activate(item_tree)
++
++    def on_move_up_button_clicked(self, button):
++        item_tree = self.tree.get_object('item_tree')
++        items, iter = item_tree.get_selection().get_selected()
++        if not iter:
++            return
++        path = items.get_path(iter)
++        #at top, can't move up
++        if path.get_indices()[0] == 0:
++            return
++        item = items[path][3]
++        before = items[(path.get_indices()[0] - 1,)][3]
++        self.editor.moveItem(item.get_parent(), item, before=before)
++
++    def on_move_down_button_clicked(self, button):
++        item_tree = self.tree.get_object('item_tree')
++        items, iter = item_tree.get_selection().get_selected()
++        if not iter:
++            return
++        path = items.get_path(iter)
++        #at bottom, can't move down
++        if path.get_indices()[0] == (len(items) - 1):
++            return
++        item = items[path][3]
++        after = items[path][3]
++        self.editor.moveItem(item.get_parent(), item, after=after)
++
++    def on_help_button_clicked(self, *args):
++        Gtk.show_uri(Gdk.Screen.get_default(), "ghelp:user-guide#menu-editor", Gtk.get_current_event_time())
++
++    def on_restore_button_clicked(self, button):
++        self.editor.restoreToSystem()
++
++    def on_close_button_clicked(self, button):
++        self.quit()
++
++    def on_properties_button_clicked(self, button):
++        self.on_edit_properties_activate(None)
++    def on_delete_button_clicked(self, button):
++        self.on_edit_delete_activate(None)
++
++    def quit(self):
++        Gtk.main_quit()
+--- a/files/usr/lib/cinnamon-menu-editor/Alacarte/MenuEditor.py
++++ b/files/usr/lib/cinnamon-menu-editor/Alacarte/MenuEditor.py
+@@ -16,731 +16,555 @@
+ #   License along with this library; if not, write to the Free Software
+ #   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ 
+-import os, re, xml.dom.minidom, locale
+-import gmenu
++import os
++import xml.dom.minidom
++import xml.parsers.expat
++from gi.repository import GMenu, GLib
+ from Alacarte import util
+ 
+-class Menu:
+-	tree = None
+-	visible_tree = None
+-	path = None
+-	dom = None
+-
+-class MenuEditor:
+-	#lists for undo/redo functionality
+-	__undo = []
+-	__redo = []
+-
+-	def __init__(self):
+-		self.locale = locale.getdefaultlocale()[0]
+-		self.__loadMenus()
+-
+-	def __loadMenus(self):
+-		self.applications = Menu()
+-		self.applications.tree = gmenu.lookup_tree('cinnamon-applications.menu', gmenu.FLAGS_SHOW_EMPTY|gmenu.FLAGS_INCLUDE_EXCLUDED|gmenu.FLAGS_INCLUDE_NODISPLAY|gmenu.FLAGS_SHOW_ALL_SEPARATORS)
+-		self.applications.visible_tree = gmenu.lookup_tree('cinnamon-applications.menu')
+-		self.applications.tree.sort_key = gmenu.SORT_DISPLAY_NAME
+-		self.applications.visible_tree.sort_key = gmenu.SORT_DISPLAY_NAME
+-		self.applications.path = os.path.join(util.getUserMenuPath(), self.applications.tree.get_menu_file())
+-		if not os.path.isfile(self.applications.path):
+-			self.applications.dom = xml.dom.minidom.parseString(util.getUserMenuXml(self.applications.tree))
+-		else:
+-			self.applications.dom = xml.dom.minidom.parse(self.applications.path)
+-		self.__remove_whilespace_nodes(self.applications.dom)
+-
+-		self.save(True)
+-
+-	def save(self, from_loading=False):
+-		for menu in ('applications',):
+-			fd = open(getattr(self, menu).path, 'w')
+-			fd.write(re.sub("\n[\s]*([^\n<]*)\n[\s]*</", "\\1</", getattr(self, menu).dom.toprettyxml().replace('<?xml version="1.0" ?>\n', '')))
+-			fd.close()
+-		if not from_loading:
+-			self.__loadMenus()
+-
+-	def quit(self):
+-		for file_name in os.listdir(util.getUserItemPath()):
+-			if file_name[-6:-2] in ('redo', 'undo'):
+-				file_path = os.path.join(util.getUserItemPath(), file_name)
+-				os.unlink(file_path)
+-		for file_name in os.listdir(util.getUserDirectoryPath()):
+-			if file_name[-6:-2] in ('redo', 'undo'):
+-				file_path = os.path.join(util.getUserDirectoryPath(), file_name)
+-				os.unlink(file_path)
+-		for file_name in os.listdir(util.getUserMenuPath()):
+-			if file_name[-6:-2] in ('redo', 'undo'):
+-				file_path = os.path.join(util.getUserMenuPath(), file_name)
+-				os.unlink(file_path)
+-
+-	def revert(self):
+-		for name in ('applications',):
+-			menu = getattr(self, name)
+-			self.revertTree(menu.tree.root)
+-			path = os.path.join(util.getUserMenuPath(), menu.tree.get_menu_file())
+-			try:
+-				os.unlink(path)
+-			except OSError:
+-				pass
+-			#reload DOM for each menu
+-			if not os.path.isfile(menu.path):
+-				menu.dom = xml.dom.minidom.parseString(util.getUserMenuXml(menu.tree))
+-			else:
+-				menu.dom = xml.dom.minidom.parse(menu.path)
+-			self.__remove_whilespace_nodes(menu.dom)
+-		#reset undo/redo, no way to recover from this
+-		self.__undo, self.__redo = [], []
+-		self.save()
+-
+-	def revertTree(self, menu):
+-		for child in menu.get_contents():
+-			if child.get_type() == gmenu.TYPE_DIRECTORY:
+-				self.revertTree(child)
+-			elif child.get_type() == gmenu.TYPE_ENTRY:
+-				self.revertItem(child)
+-		self.revertMenu(menu)
+-
+-	def undo(self):
+-		if len(self.__undo) == 0:
+-			return
+-		files = self.__undo.pop()
+-		redo = []
+-		for file_path in files:
+-			new_path = file_path.rsplit('.', 1)[0]
+-			redo_path = util.getUniqueRedoFile(new_path)
+-			data = open(new_path).read()
+-			open(redo_path, 'w').write(data)
+-			data = open(file_path).read()
+-			open(new_path, 'w').write(data)
+-			os.unlink(file_path)
+-			redo.append(redo_path)
+-		#reload DOM to make changes stick
+-		for name in ('applications',):
+-			menu = getattr(self, name)
+-			if not os.path.isfile(menu.path):
+-				menu.dom = xml.dom.minidom.parseString(util.getUserMenuXml(menu.tree))
+-			else:
+-				menu.dom = xml.dom.minidom.parse(menu.path)
+-			self.__remove_whilespace_nodes(menu.dom)
+-		self.__redo.append(redo)
+-
+-	def redo(self):
+-		if len(self.__redo) == 0:
+-			return
+-		files = self.__redo.pop()
+-		undo = []
+-		for file_path in files:
+-			new_path = file_path.rsplit('.', 1)[0]
+-			undo_path = util.getUniqueUndoFile(new_path)
+-			data = open(new_path).read()
+-			open(undo_path, 'w').write(data)
+-			data = open(file_path).read()
+-			open(new_path, 'w').write(data)
+-			os.unlink(file_path)
+-			undo.append(undo_path)
+-		#reload DOM to make changes stick
+-		for name in ('applications',):
+-			menu = getattr(self, name)
+-			if not os.path.isfile(menu.path):
+-				menu.dom = xml.dom.minidom.parseString(util.getUserMenuXml(menu.tree))
+-			else:
+-				menu.dom = xml.dom.minidom.parse(menu.path)
+-			self.__remove_whilespace_nodes(menu.dom)
+-		self.__undo.append(undo)
+-
+-	def getMenus(self, parent=None):
+-		if parent == None:
+-			yield self.applications.tree.root
+-		else:
+-			for menu in parent.get_contents():
+-				if menu.get_type() == gmenu.TYPE_DIRECTORY:
+-					yield (menu, self.__isVisible(menu))
+-
+-	def getItems(self, menu):
+-		for item in menu.get_contents():
+-			if item.get_type() == gmenu.TYPE_SEPARATOR:
+-				yield (item, True)
+-			else:
+-				if item.get_type() == gmenu.TYPE_ENTRY and item.get_desktop_file_id()[-19:] == '-usercustom.desktop':
+-					continue
+-				yield (item, self.__isVisible(item))
+-
+-	def canRevert(self, item):
+-		if item.get_type() == gmenu.TYPE_ENTRY:
+-			if util.getItemPath(item.get_desktop_file_id()):
+-				path = util.getUserItemPath()
+-				if os.path.isfile(os.path.join(path, item.get_desktop_file_id())):
+-					return True
+-		elif item.get_type() == gmenu.TYPE_DIRECTORY:
+-			if item.get_desktop_file_path():
+-				file_id = os.path.split(item.get_desktop_file_path())[1]
+-			else:
+-				file_id = item.get_menu_id() + '.directory'
+-			if util.getDirectoryPath(file_id):
+-				path = util.getUserDirectoryPath()
+-				if os.path.isfile(os.path.join(path, file_id)):
+-					return True
+-		return False
+-
+-	def setVisible(self, item, visible):
+-		dom = self.__getMenu(item).dom
+-		if item.get_type() == gmenu.TYPE_ENTRY:
+-			self.__addUndo([self.__getMenu(item), item])
+-			menu_xml = self.__getXmlMenu(self.__getPath(item.get_parent()), dom, dom)
+-			if visible:
+-				self.__addXmlFilename(menu_xml, dom, item.get_desktop_file_id(), 'Include')
+-				self.__writeItem(item, no_display=False)
+-			else:
+-				self.__addXmlFilename(menu_xml, dom, item.get_desktop_file_id(), 'Exclude')
+-			self.__addXmlTextElement(menu_xml, 'AppDir', util.getUserItemPath(), dom)
+-		elif item.get_type() == gmenu.TYPE_DIRECTORY:
+-			self.__addUndo([self.__getMenu(item), item])
+-			#don't mess with it if it's empty
+-			if len(item.get_contents()) == 0:
+-				return
+-			menu_xml = self.__getXmlMenu(self.__getPath(item), dom, dom)
+-			for node in self.__getXmlNodesByName(['Deleted', 'NotDeleted'], menu_xml):
+-				node.parentNode.removeChild(node)
+-			if visible:
+-				self.__writeMenu(item, no_display=False)
+-			else:
+-				self.__writeMenu(item, no_display=True)
+-			self.__addXmlTextElement(menu_xml, 'DirectoryDir', util.getUserDirectoryPath(), dom)
+-		self.save()
+-
+-	def createItem(self, parent, icon, name, comment, command, use_term, before=None, after=None):
+-		file_id = self.__writeItem(None, icon, name, comment, command, use_term)
+-		self.insertExternalItem(file_id, parent, before, after)
+-
+-	def insertExternalItem(self, file_id, parent, before=None, after=None):
+-		dom = self.__getMenu(parent).dom
+-		self.__addItem(parent, file_id, dom)
+-		self.__positionItem(parent, ('Item', file_id), before, after)
+-		self.__addUndo([self.__getMenu(parent), ('Item', file_id)])
+-		self.save()
+-
+-	def createMenu(self, parent, icon, name, comment, before=None, after=None):
+-		file_id = self.__writeMenu(None, icon, name, comment)
+-		self.insertExternalMenu(file_id, parent.menu_id, before, after)
+-
+-	def insertExternalMenu(self, file_id, parent_id, before=None, after=None):
+-		menu_id = file_id.rsplit('.', 1)[0]
+-		parent = self.__findMenu(parent_id)
+-		dom = self.__getMenu(parent).dom
+-		self.__addXmlDefaultLayout(self.__getXmlMenu(self.__getPath(parent), dom, dom) , dom)
+-		menu_xml = self.__getXmlMenu(self.__getPath(parent) + '/' + menu_id, dom, dom)
+-		self.__addXmlTextElement(menu_xml, 'Directory', file_id, dom)
+-		self.__positionItem(parent, ('Menu', menu_id), before, after)
+-		self.__addUndo([self.__getMenu(parent), ('Menu', file_id)])
+-		self.save()
+-
+-	def createSeparator(self, parent, before=None, after=None):
+-		self.__positionItem(parent, ('Separator',), before, after)
+-		self.__addUndo([self.__getMenu(parent), ('Separator',)])
+-		self.save()
+-
+-	def editItem(self, item, icon, name, comment, command, use_term, parent=None, final=True):
+-		#if nothing changed don't make a user copy
+-		if icon == item.get_icon() and name == item.get_display_name() and comment == item.get_comment() and command == item.get_exec() and use_term == item.get_launch_in_terminal():
+-			return
+-		#hack, item.get_parent() seems to fail a lot
+-		if not parent:
+-			parent = item.get_parent()
+-		if final:
+-			self.__addUndo([self.__getMenu(parent), item])
+-		self.__writeItem(item, icon, name, comment, command, use_term)
+-		if final:
+-			dom = self.__getMenu(parent).dom
+-			menu_xml = self.__getXmlMenu(self.__getPath(parent), dom, dom)
+-			self.__addXmlTextElement(menu_xml, 'AppDir', util.getUserItemPath(), dom)
+-		self.save()
+-
+-	def editMenu(self, menu, icon, name, comment, final=True):
+-		#if nothing changed don't make a user copy
+-		if icon == menu.get_icon() and name == menu.get_name() and comment == menu.get_comment():
+-			return
+-		#we don't use this, we just need to make sure the <Menu> exists
+-		#otherwise changes won't show up
+-		dom = self.__getMenu(menu).dom
+-		menu_xml = self.__getXmlMenu(self.__getPath(menu), dom, dom)
+-		file_id = self.__writeMenu(menu, icon, name, comment)
+-		if final:
+-			self.__addXmlTextElement(menu_xml, 'DirectoryDir', util.getUserDirectoryPath(), dom)
+-			self.__addUndo([self.__getMenu(menu), menu])
+-		self.save()
+-
+-	def copyItem(self, item, new_parent, before=None, after=None):
+-		dom = self.__getMenu(new_parent).dom
+-		file_path = item.get_desktop_file_path()
+-		keyfile = util.DesktopParser(file_path)
+-		#erase Categories in new file
+-		keyfile.set('Categories', ('',))
+-		keyfile.set('Hidden', False)
+-		file_id = util.getUniqueFileId(item.get_name(), '.desktop')
+-		out_path = os.path.join(util.getUserItemPath(), file_id)
+-		keyfile.write(open(out_path, 'w'))
+-		self.__addItem(new_parent, file_id, dom)
+-		self.__positionItem(new_parent, ('Item', file_id), before, after)
+-		self.__addUndo([self.__getMenu(new_parent), ('Item', file_id)])
+-		self.save()
+-		return file_id
+-
+-	def moveItem(self, item, new_parent, before=None, after=None):
+-		undo = []
+-		if item.get_parent() != new_parent:
+-			#hide old item
+-			self.deleteItem(item)
+-			undo.append(item)
+-			file_id = self.copyItem(item, new_parent)
+-			item = ('Item', file_id)
+-			undo.append(item)
+-		self.__positionItem(new_parent, item, before, after)
+-		undo.append(self.__getMenu(new_parent))
+-		self.__addUndo(undo)
+-		self.save()
+-
+-	def moveMenu(self, menu, new_parent, before=None, after=None):
+-		parent = new_parent
+-		#don't move a menu into it's child
+-		while parent.get_parent():
+-			parent = parent.get_parent()
+-			if parent == menu:
+-				return False
+-
+-		#don't move a menu into itself
+-		if new_parent == menu:
+-			return False
+-
+-		#can't move between top-level menus
+-		if self.__getMenu(menu) != self.__getMenu(new_parent):
+-			return False
+-		if menu.get_parent() != new_parent:
+-			dom = self.__getMenu(menu).dom
+-			root_path = self.__getPath(menu).split('/', 1)[0]
+-			xml_root = self.__getXmlMenu(root_path, dom, dom)
+-			old_path = self.__getPath(menu).split('/', 1)[1]
+-			#root menu's path has no /
+-			if '/' in self.__getPath(new_parent):
+-				new_path = self.__getPath(new_parent).split('/', 1)[1] + '/' + menu.get_menu_id()
+-			else:
+-				new_path = menu.get_menu_id()
+-			self.__addXmlMove(xml_root, old_path, new_path, dom)
+-		self.__positionItem(new_parent, menu, before, after)
+-		self.__addUndo([self.__getMenu(new_parent),])
+-		self.save()
+-
+-	def moveSeparator(self, separator, new_parent, before=None, after=None):
+-		self.__positionItem(new_parent, separator, before, after)
+-		self.__addUndo([self.__getMenu(new_parent),])
+-		self.save()
+-
+-	def deleteItem(self, item):
+-		self.__addUndo([item,])
+-		self.__writeItem(item, hidden=True)
+-		self.save()
+-
+-	def deleteMenu(self, menu):
+-		dom = self.__getMenu(menu).dom
+-		menu_xml = self.__getXmlMenu(self.__getPath(menu), dom, dom)
+-		self.__addDeleted(menu_xml, dom)
+-		self.__addUndo([self.__getMenu(menu),])
+-		self.save()
+-
+-	def deleteSeparator(self, item):
+-		parent = item.get_parent()
+-		contents = parent.get_contents()
+-		contents.remove(item)
+-		layout = self.__createLayout(contents)
+-		dom = self.__getMenu(parent).dom
+-		menu_xml = self.__getXmlMenu(self.__getPath(parent), dom, dom)
+-		self.__addXmlLayout(menu_xml, layout, dom)
+-		self.__addUndo([self.__getMenu(item.get_parent()),])
+-		self.save()
+-
+-	def revertItem(self, item):
+-		if not self.canRevert(item):
+-			return
+-		self.__addUndo([item,])
+-		try:
+-			os.remove(item.get_desktop_file_path())
+-		except OSError:
+-			pass
+-		self.save()
+-
+-	def revertMenu(self, menu):
+-		if not self.canRevert(menu):
+-			return
+-		#wtf happened here? oh well, just bail
+-		if not menu.get_desktop_file_path():
+-			return
+-		self.__addUndo([menu,])
+-		file_id = os.path.split(menu.get_desktop_file_path())[1]
+-		path = os.path.join(util.getUserDirectoryPath(), file_id)
+-		try:
+-			os.remove(path)
+-		except OSError:
+-			pass
+-		self.save()
+-
+-	#private stuff
+-	def __addUndo(self, items):
+-		self.__undo.append([])
+-		for item in items:
+-			if isinstance(item, Menu):
+-				file_path = item.path
+-			elif isinstance(item, tuple):
+-				if item[0] == 'Item':
+-					file_path = os.path.join(util.getUserItemPath(), item[1])
+-					if not os.path.isfile(file_path):
+-						file_path = util.getItemPath(item[1])
+-				elif item[0] == 'Menu':
+-					file_path = os.path.join(util.getUserDirectoryPath(), item[1])
+-					if not os.path.isfile(file_path):
+-						file_path = util.getDirectoryPath(item[1])
+-				else:
+-					continue
+-			elif item.get_type() == gmenu.TYPE_DIRECTORY:
+-				if item.get_desktop_file_path() == None:
+-					continue
+-				file_path = os.path.join(util.getUserDirectoryPath(), os.path.split(item.get_desktop_file_path())[1])
+-				if not os.path.isfile(file_path):
+-					file_path = item.get_desktop_file_path()
+-			elif item.get_type() == gmenu.TYPE_ENTRY:
+-				file_path = os.path.join(util.getUserItemPath(), item.get_desktop_file_id())
+-				if not os.path.isfile(file_path):
+-					file_path = item.get_desktop_file_path()
+-			else:
+-				continue
+-			data = open(file_path).read()
+-			undo_path = util.getUniqueUndoFile(file_path)
+-			open(undo_path, 'w').write(data)
+-			self.__undo[-1].append(undo_path)
+-
+-	def __getMenu(self, item):
+-		return self.applications
+-
+-	def __findMenu(self, menu_id, parent=None):
+-		if parent == None:
+-			return self.__findMenu(menu_id, self.applications.tree.root)
+-		if menu_id == self.applications.tree.root.menu_id:
+-			return self.applications.tree.root
+-		for item in parent.get_contents():
+-			if item.get_type() == gmenu.TYPE_DIRECTORY:
+-				if item.menu_id == menu_id:
+-					return item
+-				menu = self.__findMenu(menu_id, item)
+-				if menu != None:
+-					return menu
+-
+-	def __isVisible(self, item):
+-		if item.get_type() == gmenu.TYPE_ENTRY:
+-			return not (item.get_is_excluded() or item.get_is_nodisplay())
+-		menu = self.__getMenu(item)
+-		if menu == self.applications:
+-			root = self.applications.visible_tree.root
+-		if item.get_type() == gmenu.TYPE_DIRECTORY:
+-			if self.__findMenu(item.menu_id, root) == None:
+-				return False
+-		return True
+-
+-	def __getPath(self, menu, path=None):
+-		if not path:
+-                        path = menu.tree.root.get_menu_id()
+-		if menu.get_parent():
+-			path = self.__getPath(menu.get_parent(), path)
+-			path += '/'
+-			path += menu.menu_id
+-		return path
+-
+-	def __getXmlMenu(self, path, element, dom):
+-		if '/' in path:
+-			(name, path) = path.split('/', 1)
+-		else:
+-			name = path
+-			path = ''
+-
+-		found = None
+-		for node in self.__getXmlNodesByName('Menu', element):
+-			for child in self.__getXmlNodesByName('Name', node):
+-				if child.childNodes[0].nodeValue == name:
+-					if path:
+-						found = self.__getXmlMenu(path, node, dom)
+-					else:
+-						found = node
+-					break
+-			if found:
+-				break
+-		if not found:
+-			node = self.__addXmlMenuElement(element, name, dom)
+-			if path:
+-				found = self.__getXmlMenu(path, node, dom)
+-			else:
+-				found = node
+-
+-		return found
+-
+-	def __addXmlMenuElement(self, element, name, dom):
+-		node = dom.createElement('Menu')
+-		self.__addXmlTextElement(node, 'Name', name, dom)
+-		return element.appendChild(node)
+-
+-	def __addXmlTextElement(self, element, name, text, dom):
+-		for temp in element.childNodes:
+-			if temp.nodeName == name:
+-				if temp.childNodes[0].nodeValue == text:
+-					return
+-		node = dom.createElement(name)
+-		text = dom.createTextNode(text)
+-		node.appendChild(text)
+-		return element.appendChild(node)
+-
+-	def __addXmlFilename(self, element, dom, filename, type = 'Include'):
+-		# remove old filenames
+-		for node in self.__getXmlNodesByName(['Include', 'Exclude'], element):
+-			if node.childNodes[0].nodeName == 'Filename' and node.childNodes[0].childNodes[0].nodeValue == filename:
+-				element.removeChild(node)
+-
+-		# add new filename
+-		node = dom.createElement(type)
+-		node.appendChild(self.__addXmlTextElement(node, 'Filename', filename, dom))
+-		return element.appendChild(node)
+-
+-	def __addDeleted(self, element, dom):
+-		node = dom.createElement('Deleted')
+-		return element.appendChild(node)
+-
+-	def __writeItem(self, item=None, icon=None, name=None, comment=None, command=None, use_term=None, no_display=None, startup_notify=None, hidden=None):
+-		if item:
+-			file_path = item.get_desktop_file_path()
+-			file_id = item.get_desktop_file_id()
+-			keyfile = util.DesktopParser(file_path)
+-		elif item == None and name == None:
+-			raise Exception('New menu items need a name')
+-		else:
+-			file_id = util.getUniqueFileId(name, '.desktop')
+-			keyfile = util.DesktopParser()
+-		if icon:
+-			keyfile.set('Icon', icon)
+-			keyfile.set('Icon', icon, self.locale)
+-		if name:
+-			keyfile.set('Name', name)
+-			keyfile.set('Name', name, self.locale)
+-		if comment:
+-			keyfile.set('Comment', comment)
+-			keyfile.set('Comment', comment, self.locale)
+-		if command:
+-			keyfile.set('Exec', command)
+-		if use_term != None:
+-			keyfile.set('Terminal', use_term)
+-		if no_display != None:
+-			keyfile.set('NoDisplay', no_display)
+-		if startup_notify != None:
+-			keyfile.set('StartupNotify', startup_notify)
+-		if hidden != None:
+-			keyfile.set('Hidden', hidden)
+-		out_path = os.path.join(util.getUserItemPath(), file_id)
+-		keyfile.write(open(out_path, 'w'))
+-		return file_id
+-
+-	def __writeMenu(self, menu=None, icon=None, name=None, comment=None, no_display=None):
+-		if menu:
+-			file_id = os.path.split(menu.get_desktop_file_path())[1]
+-			file_path = menu.get_desktop_file_path()
+-			keyfile = util.DesktopParser(file_path)
+-		elif menu == None and name == None:
+-			raise Exception('New menus need a name')
+-		else:
+-			file_id = util.getUniqueFileId(name, '.directory')
+-			keyfile = util.DesktopParser(file_type='Directory')
+-		if icon:
+-			keyfile.set('Icon', icon)
+-		if name:
+-			keyfile.set('Name', name)
+-			keyfile.set('Name', name, self.locale)
+-		if comment:
+-			keyfile.set('Comment', comment)
+-			keyfile.set('Comment', comment, self.locale)
+-		if no_display != None:
+-			keyfile.set('NoDisplay', no_display)
+-		out_path = os.path.join(util.getUserDirectoryPath(), file_id)
+-		keyfile.write(open(out_path, 'w'))
+-		return file_id
+-
+-	def __getXmlNodesByName(self, name, element):
+-		for	child in element.childNodes:
+-			if child.nodeType == xml.dom.Node.ELEMENT_NODE:
+-				if isinstance(name, str) and child.nodeName == name:
+-					yield child
+-				elif isinstance(name, list) or isinstance(name, tuple):
+-					if child.nodeName in name:
+-						yield child
+-
+-	def __remove_whilespace_nodes(self, node):
+-		remove_list = []
+-		for child in node.childNodes:
+-			if child.nodeType == xml.dom.minidom.Node.TEXT_NODE:
+-				child.data = child.data.strip()
+-				if not child.data.strip():
+-					remove_list.append(child)
+-			elif child.hasChildNodes():
+-				self.__remove_whilespace_nodes(child)
+-		for node in remove_list:
+-			node.parentNode.removeChild(node)
+-
+-	def __addXmlMove(self, element, old, new, dom):
+-		if not self.__undoMoves(element, old, new, dom):
+-			node = dom.createElement('Move')
+-			node.appendChild(self.__addXmlTextElement(node, 'Old', old, dom))
+-			node.appendChild(self.__addXmlTextElement(node, 'New', new, dom))
+-			#are parsed in reverse order, need to put at the beginning
+-			return element.insertBefore(node, element.firstChild)
+-
+-	def __addXmlLayout(self, element, layout, dom):
+-		# remove old layout
+-		for node in self.__getXmlNodesByName('Layout', element):
+-			element.removeChild(node)
+-
+-		# add new layout
+-		node = dom.createElement('Layout')
+-		for order in layout.order:
+-			if order[0] == 'Separator':
+-				child = dom.createElement('Separator')
+-				node.appendChild(child)
+-			elif order[0] == 'Filename':
+-				child = self.__addXmlTextElement(node, 'Filename', order[1], dom)
+-			elif order[0] == 'Menuname':
+-				child = self.__addXmlTextElement(node, 'Menuname', order[1], dom)
+-			elif order[0] == 'Merge':
+-				child = dom.createElement('Merge')
+-				child.setAttribute('type', order[1])
+-				node.appendChild(child)
+-		return element.appendChild(node)
+-
+-	def __addXmlDefaultLayout(self, element, dom):
+-		# remove old default layout
+-		for node in self.__getXmlNodesByName('DefaultLayout', element):
+-			element.removeChild(node)
+-
+-		# add new layout
+-		node = dom.createElement('DefaultLayout')
+-		node.setAttribute('inline', 'false')
+-		return element.appendChild(node)
+-
+-	def __createLayout(self, items):
+-		layout = Layout()
+-		layout.order = []
+-
+-		layout.order.append(['Merge', 'menus'])
+-		for item in items:
+-			if isinstance(item, tuple):
+-				if item[0] == 'Separator':
+-					layout.parseSeparator()
+-				elif item[0] == 'Menu':
+-					layout.parseMenuname(item[1])
+-				elif item[0] == 'Item':
+-					layout.parseFilename(item[1])
+-			elif item.get_type() == gmenu.TYPE_DIRECTORY:
+-				layout.parseMenuname(item.get_menu_id())
+-			elif item.get_type() == gmenu.TYPE_ENTRY:
+-				layout.parseFilename(item.get_desktop_file_id())
+-			elif item.get_type() == gmenu.TYPE_SEPARATOR:
+-				layout.parseSeparator()
+-		layout.order.append(['Merge', 'files'])
+-		return layout
+-
+-	def __addItem(self, parent, file_id, dom):
+-		xml_parent = self.__getXmlMenu(self.__getPath(parent), dom, dom)
+-		self.__addXmlFilename(xml_parent, dom, file_id, 'Include')
+-
+-	def __deleteItem(self, parent, file_id, dom, before=None, after=None):
+-		xml_parent = self.__getXmlMenu(self.__getPath(parent), dom, dom)
+-		self.__addXmlFilename(xml_parent, dom, file_id, 'Exclude')
+-
+-	def __positionItem(self, parent, item, before=None, after=None):
+-		if not before and not after:
+-			return
+-		current = parent.contents.index(item)
+-		if after:
+-			index = parent.contents.index(after)
+-			if current > index:
+-				index += 1
+-		elif before:
+-			index = parent.contents.index(before)
+-			if current < index:
+-				index -= 1
+-		contents = parent.contents
+-		#if this is a move to a new parent you can't remove the item
+-		try:
+-			contents.remove(item)
+-		except:
+-			pass
+-		contents.insert(index, item)
+-		layout = self.__createLayout(contents)
+-		dom = self.__getMenu(parent).dom
+-		menu_xml = self.__getXmlMenu(self.__getPath(parent), dom, dom)
+-		self.__addXmlLayout(menu_xml, layout, dom)
+-
+-	def __undoMoves(self, element, old, new, dom):
+-		nodes = []
+-		matches = []
+-		original_old = old
+-		final_old = old
+-		#get all <Move> elements
+-		for node in self.__getXmlNodesByName(['Move'], element):
+-			nodes.insert(0, node)
+-		#if the <New> matches our old parent we've found a stage to undo
+-		for node in nodes:
+-			xml_old = node.getElementsByTagName('Old')[0]
+-			xml_new = node.getElementsByTagName('New')[0]
+-			if xml_new.childNodes[0].nodeValue == old:
+-				matches.append(node)
+-				#we should end up with this path when completed
+-				final_old = xml_old.childNodes[0].nodeValue
+-		#undoing <Move>s
+-		for node in matches:
+-			element.removeChild(node)
+-		if len(matches) > 0:
+-			for node in nodes:
+-				xml_old = node.getElementsByTagName('Old')[0]
+-				xml_new = node.getElementsByTagName('New')[0]
+-				path = os.path.split(xml_new.childNodes[0].nodeValue)
+-				if path[0] == original_old:
+-					element.removeChild(node)
+-					for node in dom.getElementsByTagName('Menu'):
+-						name_node = node.getElementsByTagName('Name')[0]
+-						name = name_node.childNodes[0].nodeValue
+-						if name == os.path.split(new)[1]:
+-							#copy app and dir directory info from old <Menu>
+-							root_path = dom.getElementsByTagName('Menu')[0].getElementsByTagName('Name')[0].childNodes[0].nodeValue
+-							xml_menu = self.__getXmlMenu(root_path + '/' + new, dom, dom)
+-							for app_dir in node.getElementsByTagName('AppDir'):
+-								xml_menu.appendChild(app_dir)
+-							for dir_dir in node.getElementsByTagName('DirectoryDir'):
+-								xml_menu.appendChild(dir_dir)
+-							parent = node.parentNode
+-							parent.removeChild(node)
+-					node = dom.createElement('Move')
+-					node.appendChild(self.__addXmlTextElement(node, 'Old', xml_old.childNodes[0].nodeValue, dom))
+-					node.appendChild(self.__addXmlTextElement(node, 'New', os.path.join(new, path[1]), dom))
+-					element.appendChild(node)
+-			if final_old == new:
+-				return True
+-			node = dom.createElement('Move')
+-			node.appendChild(self.__addXmlTextElement(node, 'Old', final_old, dom))
+-			node.appendChild(self.__addXmlTextElement(node, 'New', new, dom))
+-			return element.appendChild(node)
+-
+-class Layout:
+-	def __init__(self, node=None):
+-		self.order = []
+-
+-	def parseMenuname(self, value):
+-		self.order.append(['Menuname', value])
+-
+-	def parseSeparator(self):
+-		self.order.append(['Separator'])
+-
+-	def parseFilename(self, value):
+-		self.order.append(['Filename', value])
+-
+-	def parseMerge(self, merge_type='all'):
+-		self.order.append(['Merge', merge_type])
++class MenuEditor(object):
++    def __init__(self, name='cinnamon-applications.menu'):
++        self.name = name
++
++        self.tree = GMenu.Tree.new(name, GMenu.TreeFlags.SHOW_EMPTY|GMenu.TreeFlags.INCLUDE_EXCLUDED|GMenu.TreeFlags.INCLUDE_NODISPLAY|GMenu.TreeFlags.SHOW_ALL_SEPARATORS|GMenu.TreeFlags.SORT_DISPLAY_NAME)
++        self.tree.connect('changed', self.menuChanged)
++        self.load()
++
++        self.path = os.path.join(util.getUserMenuPath(), self.tree.props.menu_basename)
++        self.loadDOM()
++
++    def loadDOM(self):
++        try:
++            self.dom = xml.dom.minidom.parse(self.path)
++        except (IOError, xml.parsers.expat.ExpatError), e:
++            self.dom = xml.dom.minidom.parseString(util.getUserMenuXml(self.tree))
++        util.removeWhitespaceNodes(self.dom)
++
++    def load(self):
++        if not self.tree.load_sync():
++            raise ValueError("can not load menu tree %r" % (self.name,))
++
++    def menuChanged(self, *a):
++        self.load()
++
++    def save(self):
++        fd = open(self.path, 'w')
++        fd.write(self.dom.toprettyxml())
++        fd.close()
++
++    def restoreToSystem(self):
++        self.restoreTree(self.tree.get_root_directory())
++        path = os.path.join(util.getUserMenuPath(), os.path.basename(self.tree.get_canonical_menu_path()))
++        try:
++            os.unlink(path)
++        except OSError:
++            pass
++
++        self.loadDOM()
++        self.save()
++
++    def restoreTree(self, menu):
++        item_iter = menu.iter()
++        item_type = item_iter.next()
++        while item_type != GMenu.TreeItemType.INVALID:
++            if item_type == GMenu.TreeItemType.DIRECTORY:
++                item = item_iter.get_directory()
++                self.restoreTree(item)
++            elif item_type == GMenu.TreeItemType.ENTRY:
++                item = item_iter.get_entry()
++                self.restoreItem(item)
++            item_type = item_iter.next()
++        self.restoreMenu(menu)
++
++    def restoreItem(self, item):
++        if not self.canRevert(item):
++            return
++        try:
++            os.remove(item.get_desktop_file_path())
++        except OSError:
++            pass
++        self.save()
++
++    def restoreMenu(self, menu):
++        if not self.canRevert(menu):
++            return
++        #wtf happened here? oh well, just bail
++        if not menu.get_desktop_file_path():
++            return
++        file_id = os.path.split(menu.get_desktop_file_path())[1]
++        path = os.path.join(util.getUserDirectoryPath(), file_id)
++        try:
++            os.remove(path)
++        except OSError:
++            pass
++        self.save()
++
++    def getMenus(self, parent):
++        if parent is None:
++            yield (self.tree.get_root_directory(), True)
++            return
++
++        item_iter = parent.iter()
++        item_type = item_iter.next()
++        while item_type != GMenu.TreeItemType.INVALID:
++            if item_type == GMenu.TreeItemType.DIRECTORY:
++                item = item_iter.get_directory()
++                yield (item, self.isVisible(item))
++            item_type = item_iter.next()
++
++    def getContents(self, item):
++        contents = []
++        item_iter = item.iter()
++        item_type = item_iter.next()
++
++        while item_type != GMenu.TreeItemType.INVALID:
++            item = None
++            if item_type == GMenu.TreeItemType.DIRECTORY:
++                item = item_iter.get_directory()
++            elif item_type == GMenu.TreeItemType.ENTRY:
++                item = item_iter.get_entry()
++            elif item_type == GMenu.TreeItemType.HEADER:
++                item = item_iter.get_header()
++            elif item_type == GMenu.TreeItemType.ALIAS:
++                item = item_iter.get_alias()
++            elif item_type == GMenu.TreeItemType.SEPARATOR:
++                item = item_iter.get_separator()
++            if item:
++                contents.append(item)
++            item_type = item_iter.next()
++        return contents
++
++    def getItems(self, menu):
++        item_iter = menu.iter()
++        item_type = item_iter.next()
++        while item_type != GMenu.TreeItemType.INVALID:
++            item = None
++            if item_type == GMenu.TreeItemType.ENTRY:
++                item = item_iter.get_entry()
++            elif item_type == GMenu.TreeItemType.DIRECTORY:
++                item = item_iter.get_directory()
++            elif item_type == GMenu.TreeItemType.HEADER:
++                item = item_iter.get_header()
++            elif item_type == GMenu.TreeItemType.ALIAS:
++                item = item_iter.get_alias()
++            elif item_type == GMenu.TreeItemType.SEPARATOR:
++                item = item_iter.get_separator()
++            yield (item, self.isVisible(item))
++            item_type = item_iter.next()
++
++    def canRevert(self, item):
++        if isinstance(item, GMenu.TreeEntry):
++            if util.getItemPath(item.get_desktop_file_id()) is not None:
++                path = util.getUserItemPath()
++                if os.path.isfile(os.path.join(path, item.get_desktop_file_id())):
++                    return True
++        elif isinstance(item, GMenu.TreeDirectory):
++            if item.get_desktop_file_path():
++                file_id = os.path.split(item.get_desktop_file_path())[1]
++            else:
++                file_id = item.get_menu_id() + '.directory'
++            if util.getDirectoryPath(file_id) is not None:
++                path = util.getUserDirectoryPath()
++                if os.path.isfile(os.path.join(path, file_id)):
++                    return True
++        return False
++
++    def setVisible(self, item, visible):
++        dom = self.dom
++        if isinstance(item, GMenu.TreeEntry):
++            menu_xml = self.getXmlMenu(self.getPath(item.get_parent()), dom.documentElement, dom)
++            if visible:
++                self.addXmlFilename(menu_xml, dom, item.get_desktop_file_id(), 'Include')
++                self.writeItem(item, NoDisplay=False)
++            else:
++                self.addXmlFilename(menu_xml, dom, item.get_desktop_file_id(), 'Exclude')
++            self.addXmlTextElement(menu_xml, 'AppDir', util.getUserItemPath(), dom)
++        elif isinstance(item, GMenu.TreeDirectory):
++            item_iter = item.iter()
++            first_child_type = item_iter.next()
++            #don't mess with it if it's empty
++            if first_child_type == GMenu.TreeItemType.INVALID:
++                return
++            menu_xml = self.getXmlMenu(self.getPath(item), dom.documentElement, dom)
++            for node in self.getXmlNodesByName(['Deleted', 'NotDeleted'], menu_xml):
++                node.parentNode.removeChild(node)
++            self.writeMenu(item, NoDisplay=not visible)
++            self.addXmlTextElement(menu_xml, 'DirectoryDir', util.getUserDirectoryPath(), dom)
++        self.save()
++
++    def createItem(self, parent, before, after, **kwargs):
++        file_id = self.writeItem(None, **kwargs)
++        self.insertExternalItem(file_id, parent.get_menu_id(), before, after)
++
++    def insertExternalItem(self, file_id, parent_id, before=None, after=None):
++        parent = self.findMenu(parent_id)
++        dom = self.dom
++        self.addItem(parent, file_id, dom)
++        self.positionItem(parent, ('Item', file_id), before, after)
++        self.save()
++
++    def insertExternalMenu(self, file_id, parent_id, before=None, after=None):
++        menu_id = file_id.rsplit('.', 1)[0]
++        parent = self.findMenu(parent_id)
++        dom = self.dom
++        self.addXmlDefaultLayout(self.getXmlMenu(self.getPath(parent), dom.documentElement, dom) , dom)
++        menu_xml = self.getXmlMenu(self.getPath(parent) + [menu_id], dom.documentElement, dom)
++        self.addXmlTextElement(menu_xml, 'Directory', file_id, dom)
++        self.positionItem(parent, ('Menu', menu_id), before, after)
++        self.save()
++
++    def createSeparator(self, parent, before=None, after=None):
++        self.positionItem(parent, ('Separator',), before, after)
++        self.save()
++
++    def editItem(self, item, icon, name, comment, command, use_term, parent=None, final=True):
++        #if nothing changed don't make a user copy
++        app_info = item.get_app_info()
++        if icon == app_info.get_icon() and name == app_info.get_display_name() and comment == item.get_comment() and command == item.get_exec() and use_term == item.get_launch_in_terminal():
++            return
++        #hack, item.get_parent() seems to fail a lot
++        if not parent:
++            parent = item.get_parent()
++        self.writeItem(item, Icon=icon, Name=name, Comment=comment, Exec=command, Terminal=use_term)
++        if final:
++            dom = self.dom
++            menu_xml = self.getXmlMenu(self.getPath(parent), dom.documentElement, dom)
++            self.addXmlTextElement(menu_xml, 'AppDir', util.getUserItemPath(), dom)
++        self.save()
++
++    def editMenu(self, menu, icon, name, comment, final=True):
++        #if nothing changed don't make a user copy
++        if icon == menu.get_icon() and name == menu.get_name() and comment == menu.get_comment():
++            return
++        #we don't use this, we just need to make sure the <Menu> exists
++        #otherwise changes won't show up
++        dom = self.dom
++        menu_xml = self.getXmlMenu(self.getPath(menu), dom.documentElement, dom)
++        self.writeMenu(menu, Icon=icon, Name=name, Comment=comment)
++        if final:
++            self.addXmlTextElement(menu_xml, 'DirectoryDir', util.getUserDirectoryPath(), dom)
++        self.save()
++
++    def copyItem(self, item, new_parent, before=None, after=None):
++        dom = self.dom
++        file_path = item.get_desktop_file_path()
++        keyfile = GLib.KeyFile()
++        keyfile.load_from_file(file_path, util.KEY_FILE_FLAGS)
++
++        util.fillKeyFile(keyfile, dict(Categories=[], Hidden=False))
++
++        app_info = item.get_app_info()
++        file_id = util.getUniqueFileId(app_info.get_name().replace(os.sep, '-'), '.desktop')
++        out_path = os.path.join(util.getUserItemPath(), file_id)
++
++        contents, length = keyfile.to_data()
++
++        f = open(out_path, 'w')
++        f.write(contents)
++        f.close()
++
++        self.addItem(new_parent, file_id, dom)
++        self.positionItem(new_parent, ('Item', file_id), before, after)
++        self.save()
++        return file_id
++
++    def deleteItem(self, item):
++        self.writeItem(item, Hidden=True)
++        self.save()
++
++    def deleteMenu(self, menu):
++        dom = self.dom
++        menu_xml = self.getXmlMenu(self.getPath(menu), dom.documentElement, dom)
++        self.addDeleted(menu_xml, dom)
++        self.save()
++
++    def deleteSeparator(self, item):
++        parent = item.get_parent()
++        contents = self.getContents(parent)
++        contents.remove(item)
++        layout = self.createLayout(contents)
++        dom = self.dom
++        menu_xml = self.getXmlMenu(self.getPath(parent), dom.documentElement, dom)
++        self.addXmlLayout(menu_xml, layout, dom)
++        self.save()
++
++    def findMenu(self, menu_id, parent=None):
++        if parent is None:
++            parent = self.tree.get_root_directory()
++
++        if menu_id == parent.get_menu_id():
++            return parent
++
++        item_iter = parent.iter()
++        item_type = item_iter.next()
++        while item_type != GMenu.TreeItemType.INVALID:
++            if item_type == GMenu.TreeItemType.DIRECTORY:
++                item = item_iter.get_directory()
++                if item.get_menu_id() == menu_id:
++                    return item
++                menu = self.findMenu(menu_id, item)
++                if menu is not None:
++                    return menu
++            item_type = item_iter.next()
++
++    def isVisible(self, item):
++        if isinstance(item, GMenu.TreeEntry):
++            app_info = item.get_app_info()
++            return not (item.get_is_excluded() or app_info.get_nodisplay())
++        elif isinstance(item, GMenu.TreeDirectory):
++            return not item.get_is_nodisplay()
++        return True
++
++    def getPath(self, menu):
++        names = []
++        current = menu
++        while current is not None:
++            names.append(current.get_menu_id())
++            current = current.get_parent()
++
++        # XXX - don't append root menu name, alacarte doesn't
++        # expect it. look into this more.
++        names.pop(-1)
++        return names[::-1]
++
++    def getXmlMenuPart(self, element, name):
++        for node in self.getXmlNodesByName('Menu', element):
++            for child in self.getXmlNodesByName('Name', node):
++                if child.childNodes[0].nodeValue == name:
++                    return node
++        return None
++
++    def getXmlMenu(self, path, element, dom):
++        for name in path:
++            found = self.getXmlMenuPart(element, name)
++            if found is not None:
++                element = found
++            else:
++                element = self.addXmlMenuElement(element, name, dom)
++        return element
++
++    def addXmlMenuElement(self, element, name, dom):
++        node = dom.createElement('Menu')
++        self.addXmlTextElement(node, 'Name', name, dom)
++        return element.appendChild(node)
++
++    def addXmlTextElement(self, element, name, text, dom):
++        for temp in element.childNodes:
++            if temp.nodeName == name:
++                if temp.childNodes[0].nodeValue == text:
++                    return
++        node = dom.createElement(name)
++        text = dom.createTextNode(text)
++        node.appendChild(text)
++        return element.appendChild(node)
++
++    def addXmlFilename(self, element, dom, filename, type = 'Include'):
++        # remove old filenames
++        for node in self.getXmlNodesByName(['Include', 'Exclude'], element):
++            if node.childNodes[0].nodeName == 'Filename' and node.childNodes[0].childNodes[0].nodeValue == filename:
++                element.removeChild(node)
++
++        # add new filename
++        node = dom.createElement(type)
++        node.appendChild(self.addXmlTextElement(node, 'Filename', filename, dom))
++        return element.appendChild(node)
++
++    def addDeleted(self, element, dom):
++        node = dom.createElement('Deleted')
++        return element.appendChild(node)
++
++    def makeKeyFile(self, file_path, kwargs):
++        if 'KeyFile' in kwargs:
++            return kwargs['KeyFile']
++
++        keyfile = GLib.KeyFile()
++
++        if file_path is not None:
++            keyfile.load_from_file(file_path, util.KEY_FILE_FLAGS)
++
++        util.fillKeyFile(keyfile, kwargs)
++        return keyfile
++
++    def writeItem(self, item, **kwargs):
++        if item is not None:
++            file_path = item.get_desktop_file_path()
++        else:
++            file_path = None
++
++        keyfile = self.makeKeyFile(file_path, kwargs)
++
++        if item is not None:
++            file_id = item.get_desktop_file_id()
++        else:
++            file_id = util.getUniqueFileId(keyfile.get_string(GLib.KEY_FILE_DESKTOP_GROUP, 'Name'), '.desktop')
++
++        contents, length = keyfile.to_data()
++
++        f = open(os.path.join(util.getUserItemPath(), file_id), 'w')
++        f.write(contents)
++        f.close()
++        return file_id
++
++    def writeMenu(self, menu, **kwargs):
++        if menu is not None:
++            file_id = os.path.split(menu.get_desktop_file_path())[1]
++            file_path = menu.get_desktop_file_path()
++            keyfile = GLib.KeyFile()
++            keyfile.load_from_file(file_path, util.KEY_FILE_FLAGS)
++        elif menu is None and 'Name' not in kwargs:
++            raise Exception('New menus need a name')
++        else:
++            file_id = util.getUniqueFileId(kwargs['Name'], '.directory')
++            keyfile = GLib.KeyFile()
++
++        util.fillKeyFile(keyfile, kwargs)
++
++        contents, length = keyfile.to_data()
++
++        f = open(os.path.join(util.getUserDirectoryPath(), file_id), 'w')
++        f.write(contents)
++        f.close()
++        return file_id
++
++    def getXmlNodesByName(self, name, element):
++        for child in element.childNodes:
++            if child.nodeType == xml.dom.Node.ELEMENT_NODE:
++                if isinstance(name, str) and child.nodeName == name:
++                    yield child
++                elif isinstance(name, list) or isinstance(name, tuple):
++                    if child.nodeName in name:
++                        yield child
++
++    def addXmlMove(self, element, old, new, dom):
++        if not self.undoMoves(element, old, new, dom):
++            node = dom.createElement('Move')
++            node.appendChild(self.addXmlTextElement(node, 'Old', old, dom))
++            node.appendChild(self.addXmlTextElement(node, 'New', new, dom))
++            #are parsed in reverse order, need to put at the beginning
++            return element.insertBefore(node, element.firstChild)
++
++    def addXmlLayout(self, element, layout, dom):
++        # remove old layout
++        for node in self.getXmlNodesByName('Layout', element):
++            element.removeChild(node)
++
++        # add new layout
++        node = dom.createElement('Layout')
++        for order in layout:
++            if order[0] == 'Separator':
++                child = dom.createElement('Separator')
++                node.appendChild(child)
++            elif order[0] == 'Filename':
++                child = self.addXmlTextElement(node, 'Filename', order[1], dom)
++            elif order[0] == 'Menuname':
++                child = self.addXmlTextElement(node, 'Menuname', order[1], dom)
++            elif order[0] == 'Merge':
++                child = dom.createElement('Merge')
++                child.setAttribute('type', order[1])
++                node.appendChild(child)
++        return element.appendChild(node)
++
++    def addXmlDefaultLayout(self, element, dom):
++        # remove old default layout
++        for node in self.getXmlNodesByName('DefaultLayout', element):
++            element.removeChild(node)
++
++        # add new layout
++        node = dom.createElement('DefaultLayout')
++        node.setAttribute('inline', 'false')
++        return element.appendChild(node)
++
++    def createLayout(self, items):
++        layout = []
++        layout.append(('Merge', 'menus'))
++        for item in items:
++            if isinstance(item, GMenu.TreeDirectory):
++                layout.append(('Menuname', item.get_menu_id()))
++            elif isinstance(item, GMenu.TreeEntry):
++                layout.append(('Filename', item.get_desktop_file_id()))
++            elif isinstance(item, GMenu.TreeSeparator):
++                layout.append(('Separator',))
++            else:
++                layout.append(item)
++        layout.append(('Merge', 'files'))
++        return layout
++
++    def addItem(self, parent, file_id, dom):
++        xml_parent = self.getXmlMenu(self.getPath(parent), dom.documentElement, dom)
++        self.addXmlFilename(xml_parent, dom, file_id, 'Include')
++
++    def moveItem(self, parent, item, before=None, after=None):
++        self.positionItem(parent, item, before=before, after=after)
++        self.save()
++
++    def positionItem(self, parent, item, before=None, after=None):
++        contents = self.getContents(parent)
++        if after:
++            index = contents.index(after) + 1
++        elif before:
++            index = contents.index(before)
++        else:
++            # append the item to the list
++            index = len(contents)
++        #if this is a move to a new parent you can't remove the item
++        if item in contents:
++            # decrease the destination index, if we shorten the list
++            if (before and (contents.index(item) < index)) \
++                    or (after and (contents.index(item) < index - 1)):
++                index -= 1
++            contents.remove(item)
++        contents.insert(index, item)
++        layout = self.createLayout(contents)
++        dom = self.dom
++        menu_xml = self.getXmlMenu(self.getPath(parent), dom.documentElement, dom)
++        self.addXmlLayout(menu_xml, layout, dom)
++
++    def undoMoves(self, element, old, new, dom):
++        nodes = []
++        matches = []
++        original_old = old
++        final_old = old
++        #get all <Move> elements
++        for node in self.getXmlNodesByName(['Move'], element):
++            nodes.insert(0, node)
++        #if the <New> matches our old parent we've found a stage to undo
++        for node in nodes:
++            xml_old = node.getElementsByTagName('Old')[0]
++            xml_new = node.getElementsByTagName('New')[0]
++            if xml_new.childNodes[0].nodeValue == old:
++                matches.append(node)
++                #we should end up with this path when completed
++                final_old = xml_old.childNodes[0].nodeValue
++        #undoing <Move>s
++        for node in matches:
++            element.removeChild(node)
++        if len(matches) > 0:
++            for node in nodes:
++                xml_old = node.getElementsByTagName('Old')[0]
++                xml_new = node.getElementsByTagName('New')[0]
++                path = os.path.split(xml_new.childNodes[0].nodeValue)
++                if path[0] == original_old:
++                    element.removeChild(node)
++                    for node in dom.getElementsByTagName('Menu'):
++                        name_node = node.getElementsByTagName('Name')[0]
++                        name = name_node.childNodes[0].nodeValue
++                        if name == os.path.split(new)[1]:
++                            #copy app and dir directory info from old <Menu>
++                            root_path = dom.getElementsByTagName('Menu')[0].getElementsByTagName('Name')[0].childNodes[0].nodeValue
++                            xml_menu = self.getXmlMenu(root_path + '/' + new, dom.documentElement, dom)
++                            for app_dir in node.getElementsByTagName('AppDir'):
++                                xml_menu.appendChild(app_dir)
++                            for dir_dir in node.getElementsByTagName('DirectoryDir'):
++                                xml_menu.appendChild(dir_dir)
++                            parent = node.parentNode
++                            parent.removeChild(node)
++                    node = dom.createElement('Move')
++                    node.appendChild(self.addXmlTextElement(node, 'Old', xml_old.childNodes[0].nodeValue, dom))
++                    node.appendChild(self.addXmlTextElement(node, 'New', os.path.join(new, path[1]), dom))
++                    element.appendChild(node)
++            if final_old == new:
++                return True
++            node = dom.createElement('Move')
++            node.appendChild(self.addXmlTextElement(node, 'Old', final_old, dom))
++            node.appendChild(self.addXmlTextElement(node, 'New', new, dom))
++            return element.appendChild(node)
+--- a/files/usr/lib/cinnamon-menu-editor/Alacarte/util.py
++++ b/files/usr/lib/cinnamon-menu-editor/Alacarte/util.py
+@@ -17,228 +17,158 @@
+ #   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ 
+ import os
+-import gtk, gmenu
+-from ConfigParser import ConfigParser
+-
+-class DesktopParser(ConfigParser):
+-	def __init__(self, filename=None, file_type='Application'):
+-		ConfigParser.__init__(self)
+-		self.filename = filename
+-		self.file_type = file_type
+-		if filename:
+-			if len(self.read(filename)) == 0:
+-				#file doesn't exist
+-				self.add_section('Desktop Entry')
+-		else:
+-			self.add_section('Desktop Entry')
+-		self._list_separator = ';'
+-
+-	def optionxform(self, option):
+-		#makes keys not be lowercase
+-		return option
+-
+-	def get(self, option, locale=None):
+-		locale_option = option + '[%s]' % locale
+-		try:
+-			value = ConfigParser.get(self, 'Desktop Entry', locale_option)
+-		except:
+-			try:
+-				value = ConfigParser.get(self, 'Desktop Entry', option)
+-			except:
+-				return None
+-		if self._list_separator in value:
+-			value = value.split(self._list_separator)
+-		if value == 'true':
+-			value = True
+-		if value == 'false':
+-			value = False
+-		return value
+-
+-	def set(self, option, value, locale=None):
+-		if locale:
+-			option = option + '[%s]' % locale
+-		if value == True:
+-			value = 'true'
+-		if value == False:
+-			value = 'false'
+-		if isinstance(value, tuple) or isinstance(value, list):
+-			value = self._list_separator.join(value) + ';'
+-		ConfigParser.set(self, 'Desktop Entry', option, value)
+-
+-	def write(self, file_object):
+-		file_object.write('[Desktop Entry]\n')
+-		items = []
+-		if not self.filename:
+-			file_object.write('Encoding=UTF-8\n')
+-			file_object.write('Type=' + str(self.file_type) + '\n')
+-		for item in self.items('Desktop Entry'):
+-			items.append(item)
+-		items.sort()
+-		for item in items:
+-			file_object.write(item[0] + '=' + item[1] + '\n')
++import xml.dom.minidom
++from collections import Sequence
++from gi.repository import Gtk, GdkPixbuf, GMenu, GLib
++
++# XXX: look into pygobject error marshalling
++from gi._glib import GError
++
++DESKTOP_GROUP = GLib.KEY_FILE_DESKTOP_GROUP
++KEY_FILE_FLAGS = GLib.KeyFileFlags.KEEP_COMMENTS | GLib.KeyFileFlags.KEEP_TRANSLATIONS
++
++def fillKeyFile(keyfile, items):
++    for key, item in items.iteritems():
++        if item is None:
++            continue
++
++        if isinstance(item, bool):
++            keyfile.set_boolean(DESKTOP_GROUP, key, item)
++        elif isinstance(item, Sequence):
++            keyfile.set_string_list(DESKTOP_GROUP, key, item)
++        elif isinstance(item, basestring):
++            keyfile.set_string(DESKTOP_GROUP, key, item)
+ 
+ def getUniqueFileId(name, extension):
+-	append = 0
+-	while 1:
+-		if append == 0:
+-			filename = name + extension
+-		else:
+-			filename = name + '-' + str(append) + extension
+-		if extension == '.desktop':
+-			path = getUserItemPath()
+-			if not os.path.isfile(os.path.join(path, filename)) and not getItemPath(filename):
+-				break
+-		elif extension == '.directory':
+-			path = getUserDirectoryPath()
+-			if not os.path.isfile(os.path.join(path, filename)) and not getDirectoryPath(filename):
+-				break
+-		append += 1
+-	return filename
++    append = 0
++    while 1:
++        if append == 0:
++            filename = name + extension
++        else:
++            filename = name + '-' + str(append) + extension
++        if extension == '.desktop':
++            path = getUserItemPath()
++            if not os.path.isfile(os.path.join(path, filename)) and not getItemPath(filename):
++                break
++        elif extension == '.directory':
++            path = getUserDirectoryPath()
++            if not os.path.isfile(os.path.join(path, filename)) and not getDirectoryPath(filename):
++                break
++        append += 1
++    return filename
+ 
+ def getUniqueRedoFile(filepath):
+-	append = 0
+-	while 1:
+-		new_filepath = filepath + '.redo-' + str(append)
+-		if not os.path.isfile(new_filepath):
+-			break
+-		else:
+-			append += 1
+-	return new_filepath
++    append = 0
++    while 1:
++        new_filepath = filepath + '.redo-' + str(append)
++        if not os.path.isfile(new_filepath):
++            break
++        else:
++            append += 1
++    return new_filepath
+ 
+ def getUniqueUndoFile(filepath):
+-	filename, extension = os.path.split(filepath)[1].rsplit('.', 1)
+-	append = 0
+-	while 1:
+-		if extension == 'desktop':
+-			path = getUserItemPath()
+-		elif extension == 'directory':
+-			path = getUserDirectoryPath()
+-		elif extension == 'menu':
+-			path = getUserMenuPath()
+-		new_filepath = os.path.join(path, filename + '.' + extension + '.undo-' + str(append))
+-		if not os.path.isfile(new_filepath):
+-			break
+-		else:
+-			append += 1
+-	return new_filepath
+-
+-def getUserMenuPath():
+-	menu_dir = None
+-	if os.environ.has_key('XDG_CONFIG_HOME'):
+-		menu_dir = os.path.join(os.environ['XDG_CONFIG_HOME'], 'menus')
+-	else:
+-		menu_dir = os.path.join(os.environ['HOME'], '.config', 'menus')
+-	#move .config out of the way if it's not a dir, it shouldn't be there
+-	if os.path.isfile(os.path.split(menu_dir)[0]):
+-		os.rename(os.path.split(menu_dir)[0], os.path.split(menu_dir)[0] + '.old')
+-	if not os.path.isdir(menu_dir):
+-		os.makedirs(menu_dir)
+-	return menu_dir
++    filename, extension = os.path.split(filepath)[1].rsplit('.', 1)
++    append = 0
++    while 1:
++        if extension == 'desktop':
++            path = getUserItemPath()
++        elif extension == 'directory':
++            path = getUserDirectoryPath()
++        elif extension == 'menu':
++            path = getUserMenuPath()
++        new_filepath = os.path.join(path, filename + '.' + extension + '.undo-' + str(append))
++        if not os.path.isfile(new_filepath):
++            break
++        else:
++            append += 1
++    return new_filepath
+ 
+ def getItemPath(file_id):
+-	if os.environ.has_key('XDG_DATA_DIRS'):
+-		for system_path in os.environ['XDG_DATA_DIRS'].split(':'):
+-			file_path = os.path.join(system_path, 'applications', file_id)
+-			if os.path.isfile(file_path):
+-				return file_path
+-	file_path = os.path.join('/', 'usr', 'share', 'applications', file_id)
+-	if os.path.isfile(file_path):
+-		return file_path
+-	return False
++    for path in GLib.get_system_data_dirs():
++        file_path = os.path.join(path, 'applications', file_id)
++        if os.path.isfile(file_path):
++            return file_path
++    return None
+ 
+ def getUserItemPath():
+-	item_dir = None
+-	if os.environ.has_key('XDG_DATA_HOME'):
+-		item_dir = os.path.join(os.environ['XDG_DATA_HOME'], 'applications')
+-	else:
+-		item_dir = os.path.join(os.environ['HOME'], '.local', 'share', 'applications')
+-	if not os.path.isdir(item_dir):
+-		os.makedirs(item_dir)
+-	return item_dir
++    item_dir = os.path.join(GLib.get_user_data_dir(), 'applications')
++    if not os.path.isdir(item_dir):
++        os.makedirs(item_dir)
++    return item_dir
+ 
+ def getDirectoryPath(file_id):
+-	home = getUserDirectoryPath()
+-	file_path = os.path.join(home, file_id)
+-	if os.path.isfile(file_path):
+-		return file_path
+-	if os.environ.has_key('XDG_DATA_DIRS'):
+-		for system_path in os.environ['XDG_DATA_DIRS'].split(':'):
+-			file_path = os.path.join(system_path, 'desktop-directories', file_id)
+-			if os.path.isfile(file_path):
+-				return file_path
+-	file_path = os.path.join('/', 'usr', 'share', 'desktop-directories', file_id)
+-	if os.path.isfile(file_path):
+-		return file_path
+-	return False
++    for path in GLib.get_system_data_dirs():
++        file_path = os.path.join(path, 'desktop-directories', file_id)
++        if os.path.isfile(file_path):
++            return file_path
++    return None
+ 
+ def getUserDirectoryPath():
+-	menu_dir = None
+-	if os.environ.has_key('XDG_DATA_HOME'):
+-		menu_dir = os.path.join(os.environ['XDG_DATA_HOME'], 'desktop-directories')
+-	else:
+-		menu_dir = os.path.join(os.environ['HOME'], '.local', 'share', 'desktop-directories')
+-	if not os.path.isdir(menu_dir):
+-		os.makedirs(menu_dir)
+-	return menu_dir
+-
+-def getSystemMenuPath(file_name):
+-	if os.environ.has_key('XDG_CONFIG_DIRS'):
+-		for system_path in os.environ['XDG_CONFIG_DIRS'].split(':'):
+-			file_path = os.path.join(system_path, 'menus', file_name)
+-			if os.path.isfile(file_path):
+-				return file_path
+-	file_path = os.path.join('/', 'etc', 'xdg', 'menus', file_name)
+-	if os.path.isfile(file_path):
+-		return file_path
+-	return False
++    menu_dir = os.path.join(GLib.get_user_data_dir(), 'desktop-directories')
++    if not os.path.isdir(menu_dir):
++        os.makedirs(menu_dir)
++    return menu_dir
++
++def getUserMenuPath():
++    menu_dir = os.path.join(GLib.get_user_config_dir(), 'menus')
++    if not os.path.isdir(menu_dir):
++        os.makedirs(menu_dir)
++    return menu_dir
++
++def getSystemMenuPath(file_id):
++    for path in GLib.get_system_config_dirs():
++        file_path = os.path.join(path, 'menus', file_id)
++        if os.path.isfile(file_path):
++            return file_path
++    return None
+ 
+ def getUserMenuXml(tree):
+-	system_file = getSystemMenuPath(tree.get_menu_file())
+-	name = tree.root.get_menu_id()
+-	menu_xml = "<!DOCTYPE Menu PUBLIC '-//freedesktop//DTD Menu 1.0//EN' 'http://standards.freedesktop.org/menu-spec/menu-1.0.dtd'>\n"
+-	menu_xml += "<Menu>\n  <Name>" + name + "</Name>\n  "
+-	menu_xml += "<MergeFile type=\"parent\">" + system_file +	"</MergeFile>\n</Menu>\n"
+-	return menu_xml
+-
+-def getIcon(item, for_properties=False):
+-	pixbuf, path = None, None
+-	if item == None:
+-		if for_properties:
+-			return None, None
+-		return None
+-	if isinstance(item, str):
+-		iconName = item
+-	else:
+-		iconName = item.get_icon()
+-	if iconName and not '/' in iconName and iconName[-3:] in ('png', 'svg', 'xpm'):
+-		iconName = iconName[:-4]
+-	icon_theme = gtk.icon_theme_get_default()
+-	try:
+-		pixbuf = icon_theme.load_icon(iconName, 24, 0)
+-		path = icon_theme.lookup_icon(iconName, 24, 0).get_filename()
+-	except:
+-		if iconName and '/' in iconName:
+-			try:
+-				pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(iconName, 24, 24)
+-				path = iconName
+-			except:
+-				pass
+-		if pixbuf == None:
+-			if for_properties:
+-				return None, None
+-			if item.get_type() == gmenu.TYPE_DIRECTORY:
+-				iconName = 'gnome-fs-directory'
+-			elif item.get_type() == gmenu.TYPE_ENTRY:
+-				iconName = 'application-default-icon'
+-			try:
+-				pixbuf = icon_theme.load_icon(iconName, 24, 0)
+-				path = icon_theme.lookup_icon(iconName, 24, 0).get_filename()
+-			except:
+-				return None
+-	if pixbuf == None:
+-		return None
+-	if pixbuf.get_width() != 24 or pixbuf.get_height() != 24:
+-		pixbuf = pixbuf.scale_simple(24, 24, gtk.gdk.INTERP_HYPER)
+-	if for_properties:
+-		return pixbuf, path
+-	return pixbuf
++    system_file = getSystemMenuPath(os.path.basename(tree.get_canonical_menu_path()))
++    name = tree.get_root_directory().get_menu_id()
++    menu_xml = "<!DOCTYPE Menu PUBLIC '-//freedesktop//DTD Menu 1.0//EN' 'http://standards.freedesktop.org/menu-spec/menu-1.0.dtd'>\n"
++    menu_xml += "<Menu>\n  <Name>" + name + "</Name>\n  "
++    menu_xml += "<MergeFile type=\"parent\">" + system_file +    "</MergeFile>\n</Menu>\n"
++    return menu_xml
++
++def getIcon(item):
++    pixbuf = None
++    if item is None:
++        return None
++
++    if isinstance(item, GMenu.TreeDirectory):
++        gicon = item.get_icon()
++    elif isinstance(item, GMenu.TreeEntry):
++        app_info = item.get_app_info()
++        gicon = app_info.get_icon()
++    else:
++        return None
++
++    if gicon is None:
++        return None
++
++    icon_theme = Gtk.IconTheme.get_default()
++    info = icon_theme.lookup_by_gicon(gicon, 24, 0)
++    if info is None:
++        return None
++    try:
++        pixbuf = info.load_icon()
++    except GError:
++        return None
++    if pixbuf is None:
++        return None
++    if pixbuf.get_width() != 24 or pixbuf.get_height() != 24:
++        pixbuf = pixbuf.scale_simple(24, 24, GdkPixbuf.InterpType.HYPER)
++    return pixbuf
++
++def removeWhitespaceNodes(node):
++    remove_list = []
++    for child in node.childNodes:
++        if child.nodeType == xml.dom.minidom.Node.TEXT_NODE:
++            child.data = child.data.strip()
++            if not child.data.strip():
++                remove_list.append(child)
++        elif child.hasChildNodes():
++            removeWhitespaceNodes(child)
++    for node in remove_list:
++        node.parentNode.removeChild(node)
+--- a/files/usr/lib/cinnamon-menu-editor/cinnamon-menu-editor.ui
++++ b/files/usr/lib/cinnamon-menu-editor/cinnamon-menu-editor.ui
+@@ -8,22 +8,14 @@
+           <object class="GtkAction" id="edit_properties">
+             <property name="stock_id">gtk-properties</property>
+             <property name="name">edit_properties</property>
+-            <signal handler="on_edit_properties_activate" last_modification_time="Sun, 23 Apr 2006 02:16:34 GMT" name="activate"/>
+-          </object>
+-        </child>
+-        <child>
+-          <object class="GtkAction" id="edit_revert_to_original">
+-            <property name="stock_id">gtk-revert-to-saved</property>
+-            <property name="name">edit_revert_to_original</property>
+-            <property name="label" translatable="yes">_Revert to Original</property>
+-            <signal handler="on_edit_revert_to_original_activate" last_modification_time="Sun, 23 Apr 2006 02:16:34 GMT" name="activate"/>
++            <signal handler="on_edit_properties_activate" name="activate"/>
+           </object>
+         </child>
+         <child>
+           <object class="GtkAction" id="edit_delete">
+             <property name="stock_id">gtk-delete</property>
+             <property name="name">edit_delete</property>
+-            <signal handler="on_edit_delete_activate" last_modification_time="Sun, 23 Apr 2006 02:16:34 GMT" name="activate"/>
++            <signal handler="on_edit_delete_activate" name="activate"/>
+           </object>
+         </child>
+       </object>
+@@ -31,8 +23,6 @@
+     <ui>
+       <popup name="edit_menu">
+         <menuitem action="edit_properties"/>
+-        <menuitem action="edit_revert_to_original"/>
+-        <separator/>
+         <menuitem action="edit_delete"/>
+       </popup>
+     </ui>
+@@ -49,8 +39,8 @@
+ </object>
+   <object class="GtkDialog" id="mainwindow">
+     <property name="border_width">5</property>
+-    <property name="width_request">675</property>
+-    <property name="height_request">530</property>
++    <property name="default_width">675</property>
++    <property name="default_height">530</property>
+     <property name="visible">True</property>
+     <property name="title" translatable="yes">Main Menu</property>
+     <property name="type">GTK_WINDOW_TOPLEVEL</property>
+@@ -65,10 +55,8 @@
+     <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+     <property name="focus_on_map">True</property>
+     <property name="urgency_hint">False</property>
+-    <property name="has_separator">False</property>
+-    <signal handler="on_close_button_clicked" last_modification_time="Wed, 26 Apr 2006 18:46:45 GMT" name="close"/>
+-    <signal handler="on_close_button_clicked" last_modification_time="Fri, 28 Apr 2006 10:49:37 GMT" name="destroy"/>
+-    <signal handler="on_style_set" name="style-set"/>
++    <signal handler="on_close_button_clicked" name="close"/>
++    <signal handler="on_close_button_clicked" name="destroy"/>
+     <accelerator key="Escape" modifiers="0" signal="close"/>
+     <child internal-child="vbox">
+       <object class="GtkVBox" id="dialog-vbox5">
+@@ -78,18 +66,30 @@
+         <child internal-child="action_area">
+           <object class="GtkHButtonBox" id="dialog-action_area5">
+             <property name="visible">True</property>
+-            <property name="layout_style">GTK_BUTTONBOX_END</property>            
++            <property name="layout_style">GTK_BUTTONBOX_END</property>
++            <child>
++              <object class="GtkButton" id="help_button">
++                <property name="visible">True</property>
++                <property name="can_default">True</property>
++                <property name="can_focus">True</property>
++                <property name="label">gtk-help</property>
++                <property name="use_stock">True</property>
++                <property name="relief">GTK_RELIEF_NORMAL</property>
++                <property name="focus_on_click">True</property>
++                <signal handler="on_help_button_clicked" name="clicked"/>
++              </object>
++            </child>
+             <child>
+-              <object class="GtkButton" id="revert_button">
++              <object class="GtkButton" id="restore_button">
+                 <property name="visible">True</property>
+                 <property name="tooltip-text" translatable="yes">Restore the default menu layout</property>
+                 <property name="can_default">True</property>
+                 <property name="can_focus">True</property>
+-                <property name="label">gtk-revert-to-saved</property>
++                <property name="label" translatable="yes">Restore System Configuration</property>
+                 <property name="use_stock">True</property>
+                 <property name="relief">GTK_RELIEF_NORMAL</property>
+                 <property name="focus_on_click">True</property>
+-                <signal handler="on_revert_button_clicked" last_modification_time="Wed, 26 Apr 2006 18:38:17 GMT" name="clicked"/>
++                <signal handler="on_restore_button_clicked" name="clicked"/>
+               </object>
+             </child>
+             <child>
+@@ -102,7 +102,7 @@
+                 <property name="use_stock">True</property>
+                 <property name="relief">GTK_RELIEF_NORMAL</property>
+                 <property name="focus_on_click">True</property>
+-                <signal handler="on_close_button_clicked" last_modification_time="Wed, 26 Apr 2006 18:38:03 GMT" name="clicked"/>
++                <signal handler="on_close_button_clicked" name="clicked"/>
+               </object>
+             </child>
+           </object>
+@@ -140,31 +140,6 @@
+                         <property name="homogeneous">False</property>
+                         <property name="spacing">6</property>
+                         <child>
+-                          <object class="GtkLabel" id="label20">
+-                            <property name="visible">True</property>
+-                            <property name="label" translatable="yes">_Menus:</property>
+-                            <property name="use_underline">True</property>
+-                            <property name="use_markup">False</property>
+-                            <property name="justify">GTK_JUSTIFY_LEFT</property>
+-                            <property name="wrap">False</property>
+-                            <property name="selectable">False</property>
+-                            <property name="xalign">0</property>
+-                            <property name="yalign">0.5</property>
+-                            <property name="xpad">0</property>
+-                            <property name="ypad">0</property>
+-                            <property name="mnemonic_widget">menu_tree</property>
+-                            <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+-                            <property name="width_chars">-1</property>
+-                            <property name="single_line_mode">True</property>
+-                            <property name="angle">0</property>
+-                          </object>
+-                          <packing>
+-                            <property name="padding">0</property>
+-                            <property name="expand">False</property>
+-                            <property name="fill">False</property>
+-                          </packing>
+-                        </child>
+-                        <child>
+                           <object class="GtkScrolledWindow" id="scrolledwindow3">
+                             <property name="visible">True</property>
+                             <property name="can_focus">True</property>
+@@ -185,8 +160,6 @@
+                                 <property name="hover_selection">False</property>
+                                 <property name="hover_expand">False</property>
+                                 <signal handler="on_menu_tree_cursor_changed" name="cursor-changed"/>
+-                                <signal handler="on_menu_tree_drag_data_received" last_modification_time="Tue, 18 Apr 2006 01:13:34 GMT" name="drag_data_received"/>
+-                                <signal handler="on_menu_tree_drag_data_get" last_modification_time="Tue, 18 Apr 2006 23:58:24 GMT" name="drag_data_get"/>
+                               </object>
+                             </child>
+                           </object>
+@@ -208,31 +181,6 @@
+                         <property name="homogeneous">False</property>
+                         <property name="spacing">6</property>
+                         <child>
+-                          <object class="GtkLabel" id="label21">
+-                            <property name="visible">True</property>
+-                            <property name="label" translatable="yes">It_ems:</property>
+-                            <property name="use_underline">True</property>
+-                            <property name="use_markup">False</property>
+-                            <property name="justify">GTK_JUSTIFY_LEFT</property>
+-                            <property name="wrap">False</property>
+-                            <property name="selectable">False</property>
+-                            <property name="xalign">0</property>
+-                            <property name="yalign">0.5</property>
+-                            <property name="xpad">0</property>
+-                            <property name="ypad">0</property>
+-                            <property name="mnemonic_widget">item_tree</property>
+-                            <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+-                            <property name="width_chars">-1</property>
+-                            <property name="single_line_mode">True</property>
+-                            <property name="angle">0</property>
+-                          </object>
+-                          <packing>
+-                            <property name="padding">0</property>
+-                            <property name="expand">False</property>
+-                            <property name="fill">False</property>
+-                          </packing>
+-                        </child>
+-                        <child>
+                           <object class="GtkHBox" id="hbox16">
+                             <property name="visible">True</property>
+                             <property name="homogeneous">False</property>
+@@ -259,11 +207,9 @@
+                                     <signal handler="on_item_tree_row_activated" name="row-activated"/>
+                                     <signal handler="on_item_tree_popup_menu" name="popup-menu"/>
+                                     <signal handler="on_item_tree_cursor_changed" name="cursor-changed"/>
+-                                    <signal handler="on_item_tree_popup_menu" last_modification_time="Thu, 06 Apr 2006 01:25:48 GMT" name="button_press_event"/>
+-                                    <signal handler="on_item_tree_drag_data_get" last_modification_time="Tue, 18 Apr 2006 01:13:21 GMT" name="drag_data_get"/>
+-                                    <signal handler="on_item_tree_cursor_changed" last_modification_time="Tue, 18 Apr 2006 15:32:26 GMT" name="cursor_changed"/>
+-                                    <signal handler="on_item_tree_drag_data_received" last_modification_time="Tue, 18 Apr 2006 23:58:15 GMT" name="drag_data_received"/>
+-                                    <signal handler="on_item_tree_key_press_event" last_modification_time="Sun, 23 Apr 2006 02:21:53 GMT" name="key_press_event"/>
++                                    <signal handler="on_item_tree_popup_menu" name="button_press_event"/>
++                                    <signal handler="on_item_tree_cursor_changed" name="cursor_changed"/>
++                                    <signal handler="on_item_tree_key_press_event" name="key_press_event"/>
+                                   </object>
+                                 </child>
+                               </object>
+@@ -285,142 +231,28 @@
+                                     <property name="spacing">6</property>
+                                     <child>
+                                       <object class="GtkButton" id="new_menu_button">
++                                        <property name="label" translatable="yes">_New Menu</property>
++                                        <property name="use_underline">True</property>
+                                         <property name="visible">True</property>
+                                         <property name="can_default">True</property>
+                                         <property name="can_focus">True</property>
+                                         <property name="relief">GTK_RELIEF_NORMAL</property>
+                                         <property name="focus_on_click">True</property>
+-                                        <signal handler="on_new_menu_button_clicked" last_modification_time="Wed, 26 Apr 2006 18:04:38 GMT" name="clicked"/>
+-                                        <child>
+-                                          <object class="GtkAlignment" id="alignment7">
+-                                            <property name="visible">True</property>
+-                                            <property name="xalign">0.5</property>
+-                                            <property name="yalign">0.5</property>
+-                                            <property name="xscale">0</property>
+-                                            <property name="yscale">0</property>
+-                                            <property name="top_padding">0</property>
+-                                            <property name="bottom_padding">0</property>
+-                                            <property name="left_padding">0</property>
+-                                            <property name="right_padding">0</property>
+-                                            <child>
+-                                              <object class="GtkHBox" id="hbox14">
+-                                                <property name="visible">True</property>
+-                                                <property name="homogeneous">False</property>
+-                                                <property name="spacing">2</property>
+-                                                <child>
+-                                                  <object class="GtkImage" id="image21">
+-                                                    <property name="visible">True</property>
+-                                                    <property name="stock">gtk-new</property>
+-                                                    <property name="icon_size">4</property>
+-                                                    <property name="xalign">0.5</property>
+-                                                    <property name="yalign">0.5</property>
+-                                                    <property name="xpad">0</property>
+-                                                    <property name="ypad">0</property>
+-                                                  </object>
+-                                                  <packing>
+-                                                    <property name="padding">0</property>
+-                                                    <property name="expand">False</property>
+-                                                    <property name="fill">False</property>
+-                                                  </packing>
+-                                                </child>
+-                                                <child>
+-                                                  <object class="GtkLabel" id="label18">
+-                                                    <property name="visible">True</property>
+-                                                    <property name="label" translatable="yes">_New Menu</property>
+-                                                    <property name="use_underline">True</property>
+-                                                    <property name="use_markup">False</property>
+-                                                    <property name="justify">GTK_JUSTIFY_LEFT</property>
+-                                                    <property name="wrap">False</property>
+-                                                    <property name="selectable">False</property>
+-                                                    <property name="xalign">0.5</property>
+-                                                    <property name="yalign">0.5</property>
+-                                                    <property name="xpad">0</property>
+-                                                    <property name="ypad">0</property>
+-                                                    <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+-                                                    <property name="width_chars">-1</property>
+-                                                    <property name="single_line_mode">False</property>
+-                                                    <property name="angle">0</property>
+-                                                  </object>
+-                                                  <packing>
+-                                                    <property name="padding">0</property>
+-                                                    <property name="expand">False</property>
+-                                                    <property name="fill">False</property>
+-                                                  </packing>
+-                                                </child>
+-                                              </object>
+-                                            </child>
+-                                          </object>
+-                                        </child>
++                                        <property name="image">new_menu_image</property>
++                                        <signal handler="on_new_menu_button_clicked" name="clicked"/>
+                                       </object>
+                                     </child>
+                                     <child>
+                                       <object class="GtkButton" id="new_item_button">
++                                        <property name="label" translatable="yes">Ne_w Item</property>
++                                        <property name="use_underline">True</property>
+                                         <property name="visible">True</property>
+                                         <property name="can_default">True</property>
+                                         <property name="can_focus">True</property>
+                                         <property name="relief">GTK_RELIEF_NORMAL</property>
+                                         <property name="focus_on_click">True</property>
+-                                        <signal handler="on_new_item_button_clicked" last_modification_time="Wed, 26 Apr 2006 18:04:43 GMT" name="clicked"/>
+-                                        <child>
+-                                          <object class="GtkAlignment" id="alignment8">
+-                                            <property name="visible">True</property>
+-                                            <property name="xalign">0.5</property>
+-                                            <property name="yalign">0.5</property>
+-                                            <property name="xscale">0</property>
+-                                            <property name="yscale">0</property>
+-                                            <property name="top_padding">0</property>
+-                                            <property name="bottom_padding">0</property>
+-                                            <property name="left_padding">0</property>
+-                                            <property name="right_padding">0</property>
+-                                            <child>
+-                                              <object class="GtkHBox" id="hbox15">
+-                                                <property name="visible">True</property>
+-                                                <property name="homogeneous">False</property>
+-                                                <property name="spacing">2</property>
+-                                                <child>
+-                                                  <object class="GtkImage" id="image22">
+-                                                    <property name="visible">True</property>
+-                                                    <property name="stock">gtk-add</property>
+-                                                    <property name="icon_size">4</property>
+-                                                    <property name="xalign">0.5</property>
+-                                                    <property name="yalign">0.5</property>
+-                                                    <property name="xpad">0</property>
+-                                                    <property name="ypad">0</property>
+-                                                  </object>
+-                                                  <packing>
+-                                                    <property name="padding">0</property>
+-                                                    <property name="expand">False</property>
+-                                                    <property name="fill">False</property>
+-                                                  </packing>
+-                                                </child>
+-                                                <child>
+-                                                  <object class="GtkLabel" id="label19">
+-                                                    <property name="visible">True</property>
+-                                                    <property name="label" translatable="yes">Ne_w Item</property>
+-                                                    <property name="use_underline">True</property>
+-                                                    <property name="use_markup">False</property>
+-                                                    <property name="justify">GTK_JUSTIFY_LEFT</property>
+-                                                    <property name="wrap">False</property>
+-                                                    <property name="selectable">False</property>
+-                                                    <property name="xalign">0.5</property>
+-                                                    <property name="yalign">0.5</property>
+-                                                    <property name="xpad">0</property>
+-                                                    <property name="ypad">0</property>
+-                                                    <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+-                                                    <property name="width_chars">-1</property>
+-                                                    <property name="single_line_mode">False</property>
+-                                                    <property name="angle">0</property>
+-                                                  </object>
+-                                                  <packing>
+-                                                    <property name="padding">0</property>
+-                                                    <property name="expand">False</property>
+-                                                    <property name="fill">False</property>
+-                                                  </packing>
+-                                                </child>
+-                                              </object>
+-                                            </child>
+-                                          </object>
+-                                        </child>
++                                        <property name="image">new_item_image</property>
++                                        <signal handler="on_new_item_button_clicked" name="clicked"/>
+                                       </object>
+                                     </child>
+                                     <child>
+@@ -432,7 +264,7 @@
+                                         <property name="use_underline">True</property>
+                                         <property name="relief">GTK_RELIEF_NORMAL</property>
+                                         <property name="focus_on_click">True</property>
+-                                        <signal handler="on_new_separator_button_clicked" last_modification_time="Wed, 26 Apr 2006 18:04:48 GMT" name="clicked"/>
++                                        <signal handler="on_new_separator_button_clicked" name="clicked"/>
+                                       </object>
+                                     </child>
+                                   </object>
+@@ -460,174 +292,58 @@
+                                         <property name="spacing">6</property>
+                                         <child>
+                                           <object class="GtkButton" id="move_up_button">
++                                            <property name="label" translatable="yes">Move Up</property>
+                                             <property name="visible">True</property>
+                                             <property name="can_default">True</property>
+                                             <property name="can_focus">True</property>
+                                             <property name="relief">GTK_RELIEF_NORMAL</property>
+                                             <property name="focus_on_click">True</property>
+-                                            <signal handler="on_move_up_button_clicked" last_modification_time="Wed, 26 Apr 2006 22:09:11 GMT" name="clicked"/>
+-                                            <child>
+-                                              <object class="GtkAlignment" id="alignment10">
+-                                                <property name="visible">True</property>
+-                                                <property name="xalign">0.5</property>
+-                                                <property name="yalign">0.5</property>
+-                                                <property name="xscale">0</property>
+-                                                <property name="yscale">0</property>
+-                                                <property name="top_padding">0</property>
+-                                                <property name="bottom_padding">0</property>
+-                                                <property name="left_padding">0</property>
+-                                                <property name="right_padding">0</property>
+-                                                <child>
+-                                                  <object class="GtkHBox" id="hbox17">
+-                                                    <property name="visible">True</property>
+-                                                    <property name="homogeneous">False</property>
+-                                                    <property name="spacing">2</property>
+-                                                    <child>
+-                                                      <object class="GtkImage" id="image23">
+-                                                        <property name="visible">True</property>
+-                                                        <property name="stock">gtk-go-up</property>
+-                                                        <property name="icon_size">4</property>
+-                                                        <property name="xalign">0.5</property>
+-                                                        <property name="yalign">0.5</property>
+-                                                        <property name="xpad">0</property>
+-                                                        <property name="ypad">0</property>
+-                                                      </object>
+-                                                      <packing>
+-                                                        <property name="padding">0</property>
+-                                                        <property name="expand">False</property>
+-                                                        <property name="fill">False</property>
+-                                                      </packing>
+-                                                    </child>
+-                                                    <child>
+-                                                      <object class="GtkLabel" id="label22">
+-                                                        <property name="visible">True</property>
+-                                                        <property name="label" translatable="yes">Move Up</property>
+-                                                        <property name="use_underline">True</property>
+-                                                        <property name="use_markup">False</property>
+-                                                        <property name="justify">GTK_JUSTIFY_LEFT</property>
+-                                                        <property name="wrap">False</property>
+-                                                        <property name="selectable">False</property>
+-                                                        <property name="xalign">0.5</property>
+-                                                        <property name="yalign">0.5</property>
+-                                                        <property name="xpad">0</property>
+-                                                        <property name="ypad">0</property>
+-                                                        <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+-                                                        <property name="width_chars">-1</property>
+-                                                        <property name="single_line_mode">False</property>
+-                                                        <property name="angle">0</property>
+-                                                      </object>
+-                                                      <packing>
+-                                                        <property name="padding">0</property>
+-                                                        <property name="expand">False</property>
+-                                                        <property name="fill">False</property>
+-                                                      </packing>
+-                                                    </child>
+-                                                  </object>
+-                                                </child>
+-                                              </object>
+-                                            </child>
++                                            <property name="image">move_up_image</property>
++                                            <signal handler="on_move_up_button_clicked" name="clicked"/>
+                                           </object>
+                                         </child>
+                                         <child>
+                                           <object class="GtkButton" id="move_down_button">
++                                            <property name="label" translatable="yes">Move Down</property>
+                                             <property name="visible">True</property>
+                                             <property name="can_default">True</property>
+                                             <property name="can_focus">True</property>
+                                             <property name="relief">GTK_RELIEF_NORMAL</property>
+                                             <property name="focus_on_click">True</property>
+-                                            <signal handler="on_move_down_button_clicked" last_modification_time="Wed, 26 Apr 2006 22:09:15 GMT" name="clicked"/>
+-                                            <child>
+-                                              <object class="GtkAlignment" id="alignment11">
+-                                                <property name="visible">True</property>
+-                                                <property name="xalign">0.5</property>
+-                                                <property name="yalign">0.5</property>
+-                                                <property name="xscale">0</property>
+-                                                <property name="yscale">0</property>
+-                                                <property name="top_padding">0</property>
+-                                                <property name="bottom_padding">0</property>
+-                                                <property name="left_padding">0</property>
+-                                                <property name="right_padding">0</property>
+-                                                <child>
+-                                                  <object class="GtkHBox" id="hbox18">
+-                                                    <property name="visible">True</property>
+-                                                    <property name="homogeneous">False</property>
+-                                                    <property name="spacing">2</property>
+-                                                    <child>
+-                                                      <object class="GtkImage" id="image24">
+-                                                        <property name="visible">True</property>
+-                                                        <property name="stock">gtk-go-down</property>
+-                                                        <property name="icon_size">4</property>
+-                                                        <property name="xalign">0.5</property>
+-                                                        <property name="yalign">0.5</property>
+-                                                        <property name="xpad">0</property>
+-                                                        <property name="ypad">0</property>
+-                                                      </object>
+-                                                      <packing>
+-                                                        <property name="padding">0</property>
+-                                                        <property name="expand">False</property>
+-                                                        <property name="fill">False</property>
+-                                                      </packing>
+-                                                    </child>
+-                                                    <child>
+-                                                      <object class="GtkLabel" id="label23">
+-                                                        <property name="visible">True</property>
+-                                                        <property name="label" translatable="yes">Move Down</property>
+-                                                        <property name="use_underline">True</property>
+-                                                        <property name="use_markup">False</property>
+-                                                        <property name="justify">GTK_JUSTIFY_LEFT</property>
+-                                                        <property name="wrap">False</property>
+-                                                        <property name="selectable">False</property>
+-                                                        <property name="xalign">0.5</property>
+-                                                        <property name="yalign">0.5</property>
+-                                                        <property name="xpad">0</property>
+-                                                        <property name="ypad">0</property>
+-                                                        <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+-                                                        <property name="width_chars">-1</property>
+-                                                        <property name="single_line_mode">False</property>
+-                                                        <property name="angle">0</property>
+-                                                      </object>
+-                                                      <packing>
+-                                                        <property name="padding">0</property>
+-                                                        <property name="expand">False</property>
+-                                                        <property name="fill">False</property>
+-                                                      </packing>
+-                                                    </child>
+-                                                  </object>
+-                                                </child>
+-                                              </object>
+-                                            </child>
++                                            <property name="image">move_down_image</property>
++                                            <signal handler="on_move_down_button_clicked" name="clicked"/>
+                                           </object>
+                                         </child>
+                                         <child>
+-                                          <object class="GtkButton" id="properties_button">
+-                                            <property name="label" translatable="no">gtk-properties</property>
++                                          <object class="GtkButton" id="delete_button">
++                                            <property name="label" translatable="no">gtk-delete</property>
+                                             <property name="visible">True</property>
+                                             <property name="can_focus">True</property>
+                                             <property name="receives_default">True</property>
+                                             <property name="use_stock">True</property>
+-					    <signal handler="on_properties_button_clicked" name="clicked"/>
++					    <signal handler="on_delete_button_clicked" name="clicked"/>
+                                           </object>
+                                           <packing>
+                                             <property name="expand">False</property>
+                                             <property name="fill">False</property>
+                                             <property name="position">2</property>
+                                           </packing>
+-                                        </child>
++					</child>
+                                         <child>
+-                                          <object class="GtkButton" id="delete_button">
+-                                            <property name="label" translatable="no">gtk-delete</property>
++                                          <object class="GtkButton" id="properties_button">
++                                            <property name="label" translatable="no">gtk-properties</property>
+                                             <property name="visible">True</property>
+                                             <property name="can_focus">True</property>
+                                             <property name="receives_default">True</property>
+                                             <property name="use_stock">True</property>
+-					    <signal handler="on_delete_button_clicked" name="clicked"/>
++					    <signal handler="on_properties_button_clicked" name="clicked"/>
+                                           </object>
+                                           <packing>
+                                             <property name="expand">False</property>
+                                             <property name="fill">False</property>
+                                             <property name="position">3</property>
+                                           </packing>
+-					</child>
++                                        </child>
+                                       </object>
+                                     </child>
+                                   </object>
+@@ -675,124 +391,26 @@
+         </child>
+       </object>
+     </child>
+-    <action-widgets>      
+-      <action-widget response="0">revert_button</action-widget>
++    <action-widgets>
++      <action-widget response="-11">help_button</action-widget>
++      <action-widget response="0">restore_button</action-widget>
+       <action-widget response="-7">close_button</action-widget>
+     </action-widgets>
+   </object>
+-  <object class="GtkDialog" id="revertdialog">
+-    <property name="border_width">5</property>
+-    <property name="title" translatable="yes">Revert Changes?</property>
+-    <property name="type">GTK_WINDOW_TOPLEVEL</property>
+-    <property name="window_position">GTK_WIN_POS_NONE</property>
+-    <property name="modal">False</property>
+-    <property name="resizable">False</property>
+-    <property name="destroy_with_parent">False</property>
+-    <property name="decorated">True</property>
+-    <property name="skip_taskbar_hint">False</property>
+-    <property name="skip_pager_hint">False</property>
+-    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+-    <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+-    <property name="focus_on_map">True</property>
+-    <property name="urgency_hint">False</property>
+-    <property name="has_separator">False</property>
+-    <child internal-child="vbox">
+-      <object class="GtkVBox" id="dialog-vbox6">
+-        <property name="visible">True</property>
+-        <property name="homogeneous">False</property>
+-        <property name="spacing">2</property>
+-        <child internal-child="action_area">
+-          <object class="GtkHButtonBox" id="dialog-action_area6">
+-            <property name="visible">True</property>
+-            <property name="layout_style">GTK_BUTTONBOX_END</property>
+-            <child>
+-              <object class="GtkButton" id="cancel_revert_button">
+-                <property name="visible">True</property>
+-                <property name="can_default">True</property>
+-                <property name="can_focus">True</property>
+-                <property name="label">gtk-cancel</property>
+-                <property name="use_stock">True</property>
+-                <property name="relief">GTK_RELIEF_NORMAL</property>
+-                <property name="focus_on_click">True</property>
+-              </object>
+-            </child>
+-            <child>
+-              <object class="GtkButton" id="button2">
+-                <property name="visible">True</property>
+-                <property name="can_default">True</property>
+-                <property name="can_focus">True</property>
+-                <property name="label">gtk-revert-to-saved</property>
+-                <property name="use_stock">True</property>
+-                <property name="relief">GTK_RELIEF_NORMAL</property>
+-                <property name="focus_on_click">True</property>
+-              </object>
+-            </child>
+-          </object>
+-          <packing>
+-            <property name="padding">0</property>
+-            <property name="expand">False</property>
+-            <property name="fill">True</property>
+-            <property name="pack_type">GTK_PACK_END</property>
+-          </packing>
+-        </child>
+-        <child>
+-          <object class="GtkHBox" id="hbox19">
+-            <property name="border_width">5</property>
+-            <property name="visible">True</property>
+-            <property name="homogeneous">False</property>
+-            <property name="spacing">8</property>
+-            <child>
+-              <object class="GtkImage" id="image25">
+-                <property name="visible">True</property>
+-                <property name="icon_size">6</property>
+-                <property name="icon_name">gtk-dialog-question</property>
+-                <property name="xalign">0</property>
+-                <property name="yalign">0.5</property>
+-                <property name="xpad">0</property>
+-                <property name="ypad">0</property>
+-              </object>
+-              <packing>
+-                <property name="padding">0</property>
+-                <property name="expand">False</property>
+-                <property name="fill">True</property>
+-              </packing>
+-            </child>
+-            <child>
+-              <object class="GtkLabel" id="label24">
+-                <property name="visible">True</property>
+-                <property name="label" translatable="yes">Revert all menus to original settings?</property>
+-                <property name="use_underline">False</property>
+-                <property name="use_markup">False</property>
+-                <property name="justify">GTK_JUSTIFY_LEFT</property>
+-                <property name="wrap">False</property>
+-                <property name="selectable">False</property>
+-                <property name="xalign">0</property>
+-                <property name="yalign">0</property>
+-                <property name="xpad">0</property>
+-                <property name="ypad">0</property>
+-                <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+-                <property name="width_chars">-1</property>
+-                <property name="single_line_mode">False</property>
+-                <property name="angle">0</property>
+-              </object>
+-              <packing>
+-                <property name="padding">0</property>
+-                <property name="expand">True</property>
+-                <property name="fill">True</property>
+-              </packing>
+-            </child>
+-          </object>
+-          <packing>
+-            <property name="padding">0</property>
+-            <property name="expand">True</property>
+-            <property name="fill">True</property>
+-          </packing>
+-        </child>
+-      </object>
+-    </child>
+-    <action-widgets>
+-      <action-widget response="-6">cancel_revert_button</action-widget>
+-      <action-widget response="-8">button2</action-widget>
+-    </action-widgets>
++  <object class="GtkImage" id="new_menu_image">
++    <property name="visible">True</property>
++    <property name="stock">gtk-new</property>
++  </object>
++  <object class="GtkImage" id="new_item_image">
++    <property name="visible">True</property>
++    <property name="stock">gtk-add</property>
++  </object>
++  <object class="GtkImage" id="move_down_image">
++    <property name="visible">True</property>
++    <property name="stock">gtk-go-down</property>
++  </object>
++  <object class="GtkImage" id="move_up_image">
++    <property name="visible">True</property>
++    <property name="stock">gtk-go-up</property>
+   </object>
+ </interface>
diff --git a/cinnamon.desktop b/cinnamon.desktop
new file mode 100644
index 0000000..1b1a95c
--- /dev/null
+++ b/cinnamon.desktop
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Encoding=UTF-8
+Name=Cinnamon
+Name[en_GB]=Cinnamon
+Comment=This session logs you into Cinnamon
+Comment[en_GB]=This session logs you into Cinnamon
+Exec=/usr/bin/gnome-session --session=cinnamon
+# no icon yet, only the top three are currently used
+Icon=
+Type=Application
diff --git a/cinnamon.session b/cinnamon.session
new file mode 100644
index 0000000..3abc24c
--- /dev/null
+++ b/cinnamon.session
@@ -0,0 +1,6 @@
+[GNOME Session]
+Name=Cinnamon
+RequiredComponents=cinnamon;gnome-settings-daemon;
+IsRunnableHelper=/usr/libexec/gnome-session-check-accelerated
+FallbackSession=gnome-fallback
+DesktopName=GNOME
diff --git a/cinnamon.spec b/cinnamon.spec
new file mode 100644
index 0000000..a1ac2be
--- /dev/null
+++ b/cinnamon.spec
@@ -0,0 +1,317 @@
+%global        _internal_version  7959517
+
+Name:           cinnamon
+Version:        1.4.1
+Release:        0.7.git%{_internal_version}%{?dist}
+Summary:        Window management and application launching for GNOME
+
+Group:          User Interface/Desktops
+License:        GPLv2+
+URL:            http://cinnamon.linuxmint.com
+# To generate tarball
+# wget https://github.com/linuxmint/Cinnamon/tarball/%%{_internal_version} -O cinnamon-%%{version}.git%%{_internal_version}.tar.gz
+Source0:        http://leigh123linux.fedorapeople.org/pub/cinnamon/source/cinnamon-%{version}.git%{_internal_version}.tar.gz
+Source1:        cinnamon.desktop
+Source2:        cinnamon.session
+Source3:        cinnamon2d.desktop
+Source4:        cinnamon2d.session
+Source5:        menu.png
+
+
+# Fix menu structure
+Patch0:         cinnamon-1.4.1_menu.patch
+# I have reported this issue
+# https://github.com/linuxmint/Cinnamon/issues/515
+Patch1:         cinnamon-1.4.1_settings.patch
+# Replace mint favorites with fedora gnome-shell defaults
+Patch2:         cinnamon-1.4.1_f17_favourite-apps-firefox.patch
+
+
+# upstream patches and pending pulls
+# https://github.com/linuxmint/Cinnamon/pull/851
+Patch10:         cinnamon-1.4.1_systray.patch
+# https://github.com/linuxmint/Cinnamon/pull/929
+Patch11:         cinnamon-menu.patch
+
+%global clutter_version 1.7.5
+%global gobject_introspection_version 0.10.1
+%global muffin_version 1.0.4
+%global eds_version 2.91.6
+%global json_glib_version 0.13.2
+
+
+BuildRequires:  clutter-devel >= %{clutter_version}
+BuildRequires:  dbus-glib-devel
+BuildRequires:  desktop-file-utils
+BuildRequires:  gjs-devel >= 0.7.14-6
+BuildRequires:  glib2-devel
+BuildRequires:  GConf2-devel
+BuildRequires:  gnome-menus-devel >= 3.1.5-2.fc16
+BuildRequires:  gnome-desktop3-devel
+BuildRequires:  gobject-introspection >= %{gobject_introspection_version}
+BuildRequires:  json-glib-devel >= %{json_glib_version}
+BuildRequires:  upower-devel
+BuildRequires:  NetworkManager-glib-devel
+BuildRequires:  polkit-devel
+BuildRequires:  telepathy-glib-devel
+BuildRequires:  telepathy-logger-devel >= 0.2.6
+BuildRequires:  libgudev1-devel
+# for screencast recorder functionality
+BuildRequires:  gstreamer-devel
+BuildRequires:  gtk3-devel
+BuildRequires:  intltool
+BuildRequires:  libcanberra-devel
+BuildRequires:  libcroco-devel
+BuildRequires:  folks-devel
+
+# for barriers
+BuildRequires:  libXfixes-devel >= 5.0
+# used in unused BigThemeImage
+BuildRequires:  librsvg2-devel
+BuildRequires:  muffin-devel >= %{muffin_version}
+BuildRequires:  pulseaudio-libs-devel
+%ifnarch s390 s390x
+BuildRequires:  gnome-bluetooth-libs-devel >= 2.91
+BuildRequires:  gnome-bluetooth >= 2.91
+%endif
+# Bootstrap requirements
+BuildRequires: gtk-doc gnome-common
+Requires:       gnome-menus%{?_isa} >= 3.0.0-2
+# wrapper script uses to restart old GNOME session if run --replace
+# from the command line
+Requires:       gobject-introspection%{?_isa} >= %{gobject_introspection_version}
+# needed for loading SVG's via gdk-pixbuf
+Requires:       librsvg2%{?_isa}
+# needed as it is now split from Clutter
+Requires:       json-glib%{?_isa} >= %{json_glib_version}
+# might be still be needed.
+Requires:       muffin%{?_isa} >= %{muffin_version}
+Requires:       upower%{?_isa}
+Requires:       polkit%{?_isa} >= 0.100
+# needed for session files
+Requires:       gnome-session
+# needed for schemas
+Requires:       at-spi2-atk%{?_isa}
+# needed for on-screen keyboard
+Requires:       caribou%{?_isa}
+# needed for settings
+Requires:       pygobject2
+Requires:       dbus-python
+Requires:       dbus-x11
+
+%description
+Cinnamon is a Linux desktop which provides advanced
+ innovative features and a traditional user experience.
+
+The desktop layout is similar to Gnome 2. 
+The underlying technology is forked from Gnome Shell.
+The emphasis is put on making users feel at home and providing
+ them with an easy to use and comfortable desktop experience.
+
+%prep
+%setup -q -n linuxmint-Cinnamon-%{_internal_version}
+%patch0 -p1
+%patch1 -p1
+%patch2 -p1
+# upstream patches and pending pulls
+%patch10 -p1
+%patch11 -p1
+
+
+# remove gschema
+rm -rf data/org.cinnamon.gschema.xml
+# make changes for settings move to /usr/share
+mv files/usr/lib/cinnamon-settings files%{_datadir}
+sed -i -e 's@/usr/lib@/usr/share at g' files%{_bindir}/cinnamon-settings \
+  files%{_datadir}/cinnamon-settings/cinnamon-settings.py
+# make changes for menu-editor move to /usr/share
+mv files/usr/lib/cinnamon-menu-editor files%{_datadir}
+rm -rf files/usr/lib
+sed -i -e 's@/usr/lib@/usr/share at g' files%{_bindir}/cinnamon-menu-editor \
+  files%{_datadir}/cinnamon-menu-editor/Alacarte/MainWindow.py
+# remove and replace the session files as they don't work with fedora (can't be bothered to patch it)
+rm -f files%{_bindir}/gnome-session-cinnamon  \
+ files%{_datadir}/xsessions/cinnamon*.desktop \
+ files%{_datadir}/gnome-session/sessions/cinnamon*.session
+install -m 644 %SOURCE1 %SOURCE3 files%{_datadir}/xsessions/
+install -m 644 %SOURCE2 %SOURCE4 files%{_datadir}/gnome-session/sessions/
+# replace menu image
+rm -f data/theme/menu.png
+install %SOURCE5 data/theme/menu.png
+# files replaced with fedora files
+rm -f files%{_datadir}/desktop-directories/cinnamon-{menu-applications,utility,utility-accessibility,development,education,game,graphics,network,audio-video,office,system-tools,other}.directory
+# adjust font size
+sed -i -e 's,font-size: 9.5pt,font-size: 10pt,g' data/theme/cinnamon.css
+sed -i -e 's,font-size: 9pt,font-size: 10pt,g' data/theme/cinnamon.css
+sed -i -e 's,font-size: 8.5pt,font-size: 10pt,g' data/theme/cinnamon.css
+sed -i -e 's,font-size: 8pt,font-size: 10pt,g' data/theme/cinnamon.css
+sed -i -e 's,font-size: 7.5pt,font-size: 10pt,g' data/theme/cinnamon.css
+rm -f configure
+
+
+%build
+export CFLAGS="$RPM_OPT_FLAGS -Wno-error=deprecated-declarations"
+autoreconf -fi
+intltoolize -f
+#NOCONFIGURE=1 ./autogen.sh
+%configure --disable-static --enable-compile-warnings=minimum
+make V=1 %{?_smp_mflags}
+
+%install
+make install DESTDIR=$RPM_BUILD_ROOT INSTALL='install -p'
+
+# Remove .la file
+rm -rf $RPM_BUILD_ROOT/%{_libdir}/cinnamon/libcinnamon.la
+
+# Remove firefox plugin
+rm -rf $RPM_BUILD_ROOT/%{_libdir}/mozilla
+
+desktop-file-validate $RPM_BUILD_ROOT%{_datadir}/applications/cinnamon.desktop
+desktop-file-validate $RPM_BUILD_ROOT%{_datadir}/applications/cinnamon2d.desktop
+
+desktop-file-install                                 \
+ --add-category="Utility"                            \
+ --remove-category="DesktopSettings"                 \
+ --remove-key="Encoding"                             \
+ --add-only-show-in="GNOME"                          \
+ --delete-original                                   \
+ --dir=$RPM_BUILD_ROOT%{_datadir}/applications       \
+ $RPM_BUILD_ROOT%{_datadir}/applications/cinnamon-settings.desktop
+
+
+%find_lang %{name}
+
+%postun
+if [ $1 -eq 0 ] ; then
+    /usr/bin/glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
+fi
+
+%posttrans
+    /usr/bin/glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
+
+%files -f %{name}.lang
+%doc COPYING README
+%{_bindir}/cinnamon
+%{_bindir}/cinnamon2d
+%{_bindir}/gnome-session-cinnamon2d
+%exclude %{_bindir}/cinnamon-launcher
+%{_bindir}/cinnamon-menu-editor
+%{_bindir}/cinnamon-settings
+%{_bindir}/cinnamon-extension-tool
+%{_sysconfdir}/xdg/menus/cinnamon-applications.menu
+%{_sysconfdir}/xdg/menus/cinnamon-settings.menu
+%{_datadir}/desktop-directories/cinnamon-*.directory
+%{_datadir}/glib-2.0/schemas/*.xml
+%{_datadir}/applications/cinnamon.desktop
+%{_datadir}/applications/cinnamon2d.desktop
+%{_datadir}/applications/cinnamon-settings.desktop
+%{_datadir}/xsessions/cinnamon*.desktop
+%{_datadir}/gnome-session/sessions/cinnamon*.session
+%dir %{_datadir}/cinnamon
+%{_datadir}/cinnamon/applets/
+%{_datadir}/cinnamon/js/
+%{_datadir}/cinnamon/search_providers/
+%{_datadir}/cinnamon/shaders/
+%{_datadir}/cinnamon/theme/
+%{_datadir}/cinnamon-menu-editor/
+%{_datadir}/cinnamon-settings/
+%{_datadir}/dbus-1/services/org.Cinnamon.HotplugSniffer.service
+%{_libdir}/cinnamon/
+%{_libexecdir}/cinnamon-perf-helper
+%{_libexecdir}/cinnamon-hotplug-sniffer
+%{_mandir}/man1/%{name}.1.*
+
+
+%changelog
+* Fri Jul 20 2012 Leigh Scott <leigh123linux at googlemail.com> - 1.4.1-0.7.git7959517
+- Remove %%define and rebase settings patch
+- Hardcode version for patches
+- Rearrange patches
+- Use install rather than cp
+- Fix scriptlets
+- Remove hardcoded file name from %%prep
+- Preserve timestamps in %%install
+- Remove extension from manpage in %%files
+- Add requires dbus-x11
+
+* Fri Jul 20 2012 Leigh Scott <leigh123linux at googlemail.com> - 1.4.1-0.6.git7959517
+- Fix macro in comment rpmlint error
+
+* Thu Jul 19 2012 Leigh Scott <leigh123linux at googlemail.com> - 1.4.1-0.5.git7959517
+- Correct spelling mistake
+- Add descriptions for patches 
+
+* Wed Jul 18 2012 Leigh Scott <leigh123linux at googlemail.com> - 1.4.1-0.4.git7959517
+- bump spec version to fix repo issue
+
+* Wed Jul 18 2012 Leigh Scott <leigh123linux at googlemail.com> - 1.4.1-0.3.git7959517
+- bump spec version to fix repo issue
+
+* Wed Jul 18 2012 Leigh Scott <leigh123linux at googlemail.com> - 1.4.1-0.2.git7959517
+- bump spec version to fix repo issue
+
+* Wed Jul 18 2012 Leigh Scott <leigh123linux at googlemail.com> - 1.4.1-0.1.git7959517
+- Update to the latest snapshot
+
+* Mon May 28 2012 Leigh Scott <leigh123linux at fedoraproject.org> - 1.4.0-5.UP1
+- Silence glib-compile-schemas scriplets
+- fix firefox patch for f17
+- fix power applet for f16
+
+* Mon May 28 2012 Leigh Scott <leigh123linux at fedoraproject.org> - 1.4.0-4.UP1
+- add notification patch
+
+* Mon May 28 2012 Leigh Scott <leigh123linux at fedoraproject.org> - 1.4.0-3.UP1
+- change %%define to %%global
+- fix files listed twice in %%files section
+- version patches
+- remove %%config from files (gnome-shell and gnome-menus doesn't use them
+  for the equivalent files)
+- drop login theme patch
+
+* Sun May 27 2012 Leigh Scott <leigh123linux at fedoraproject.org> - 1.4.0-2.UP1
+- add configure option so it compiles on F17
+- fix release tag
+
+* Sun May 27 2012 Leigh Scott <leigh123linux at fedoraproject.org> - 1.4.0-1.UP1
+- update to 1.4.0.UP1-1
+
+* Wed Mar 14 2012 Leigh Scott <leigh123linux at fedoraproject.org> - 1.4.0-2
+- fix un-themed shutdown
+
+* Tue Mar 13 2012 Leigh Scott <leigh123linux at fedoraproject.org> - 1.4.0-1
+- update to 1.4.0
+
+* Mon Feb 20 2012 Leigh Scott <leigh123linux at fedoraproject.org> - 1.3.1-1
+- update to 1.3.1
+- remove static lib
+- remove mozilla plugin
+
+* Fri Feb 17 2012 Leigh Scott <leigh123linux at fedoraproject.org> - 1.3.0-1
+- update to 1.3.0 release
+
+* Mon Jan 22 2012 Leigh Scott <leigh123linux at fedoraproject.org> - 1.2.0-1
+- update to 1.2.0 release
+- add build requires muffin-devel
+- add Br libgudev1-devel
+- add only-show-in=GNOME to settings desktop file
+- make changes for source changes, applets, settings and session added
+- delete session files and use my own
+- move settings from lib to usr (it had no libs)
+- replace menu icon
+- change description
+
+* Wed Jan 04 2012 Leigh Scott <leigh123linux at fedoraproject.org> - 1.1.3-2
+- add requires gnome-session
+- clean up spec file ready for review
+
+* Mon Jan 02 2012 Leigh Scott <leigh123linux at fedoraproject.org> - 1.1.3-1
+- update to version 1.1.3
+
+* Sun Jan 01 2012 Leigh Scott <leigh123linux at fedoraproject.org> - 1.1.2-2
+- fix firefox launchers
+
+* Fri Dec 30 2011 Leigh Scott <leigh123linux at fedoraproject.org> - 1.1.2-1
+- first build based on gnome-shell srpm
+- add session files
+
diff --git a/cinnamon2d.desktop b/cinnamon2d.desktop
new file mode 100644
index 0000000..68934e4
--- /dev/null
+++ b/cinnamon2d.desktop
@@ -0,0 +1,7 @@
+[Desktop Entry]
+Name=Cinnamon 2D
+Comment=This session logs you into Cinnamon (using software rendering)
+Exec=gnome-session-cinnamon2d
+TryExec=/usr/bin/cinnamon2d
+Icon=
+Type=Application
diff --git a/cinnamon2d.session b/cinnamon2d.session
new file mode 100644
index 0000000..516e944
--- /dev/null
+++ b/cinnamon2d.session
@@ -0,0 +1,4 @@
+[GNOME Session]
+Name=Cinnamon 2D
+RequiredComponents=cinnamon2d;gnome-settings-daemon;
+DesktopName=GNOME
diff --git a/menu.png b/menu.png
new file mode 100644
index 0000000..19225d9
Binary files /dev/null and b/menu.png differ
diff --git a/sources b/sources
index e69de29..3524bb5 100644
--- a/sources
+++ b/sources
@@ -0,0 +1 @@
+8b6fecfc2ca44366222e54fb44269600  cinnamon-1.4.1.git7959517.tar.gz


More information about the scm-commits mailing list