#!/usr/bin/python2

import locale
import gc
import gettext
import os
import sys
import traceback

import gi
gi.require_version("Gtk", "3.0")
gi.require_version('MatePanelApplet', '4.0')
from gi.repository import Gtk, GdkPixbuf, Gdk, GObject
from gi.repository import MatePanelApplet
from gi.repository import Gio

import xdg.Config

import keybinding
import pointerMonitor
import setproctitle
from plugins.execute import Execute

GObject.threads_init()

# Rename the process
setproctitle.setproctitle('mintmenu')

# i18n
gettext.install("mintmenu", "/usr/share/linuxmint/locale")
locale.bindtextdomain("mintmenu", "/usr/share/linuxmint/locale")
locale.textdomain("mintmenu")

NAME = _("Menu")
PATH = os.path.abspath(os.path.dirname(sys.argv[0]))

sys.path.append(os.path.join(PATH , "plugins"))

windowManager = os.getenv("DESKTOP_SESSION")
if not windowManager:
    windowManager = "MATE"
xdg.Config.setWindowManager(windowManager.upper())


class MainWindow(object):
    """This is the main class for the application"""

    def __init__(self, toggleButton, settings, de):

        self.settings = settings
        self.path = PATH
        sys.path.append(os.path.join(self.path, "plugins"))

        self.de = de
        self.icon = "/usr/lib/linuxmint/mintMenu/visualisation-logo.png"

        self.toggle = toggleButton
        builder = Gtk.Builder()
        builder.set_translation_domain("mintmenu")
        builder.add_from_file("/usr/share/linuxmint/mintmenu/main.ui")
        self.window     = builder.get_object("mainWindow")
        self.paneholder = builder.get_object("paneholder")

        builder.connect_signals(self)

        self.panesToColor = []
        self.headingsToColor = []

        self.window.connect("key-press-event", self.onKeyPress)
        self.window.connect("focus-in-event", self.onFocusIn)
        self.loseFocusId = self.window.connect("focus-out-event", self.onFocusOut)
        self.loseFocusBlocked = False

        self.window.stick()

        plugindir = os.path.join(os.path.expanduser("~"), ".linuxmint/mintMenu/plugins")
        sys.path.append(plugindir)

        self.settings.connect("changed::plugins-list", self.RegenPlugins)
        self.settings.connect("changed::start-with-favorites", self.toggleStartWithFavorites)
        self.settings.connect("changed::tooltips-enabled", self.toggleTooltipsEnabled)
        self.settings.connect("changed::use-custom-color", self.toggleUseCustomColor)
        self.settings.connect("changed::custom-heading-color", self.toggleCustomHeadingColor)
        self.settings.connect("changed::custom-color", self.toggleCustomBackgroundColor)

        self.getSetGSettingEntries()

        self.tooltipsWidgets = []

        self.PopulatePlugins()
        self.toggleTooltipsEnabled(self.settings, "tooltips-enabled")
        self.firstTime = True

    @classmethod
    def on_window1_destroy (widget, data=None):
        Gtk.main_quit()
        sys.exit(0)

    def wakePlugins(self):
        # Call each plugin and let them know we're showing up
        for plugin in self.plugins.values():
            if hasattr(plugin, "wake"):
                plugin.wake()

    def toggleTooltipsEnabled(self, settings, key, args=None):
        enableTooltips = settings.get_boolean(key)
        for widget in self.tooltipsWidgets:
            widget.set_has_tooltip(enableTooltips)

    def toggleStartWithFavorites(self, settings, key):
        self.startWithFavorites = settings.get_boolean(key)

    def toggleUseCustomColor(self, settings, key):
        self.usecustomcolor = settings.get_boolean(key)
        self.loadTheme()

    def toggleCustomBackgroundColor(self, settings, key):
        self.customcolor = settings.get_string(key)
        self.setCustomColors()

    def toggleCustomHeadingColor(self, settings, key):
        self.customheadingcolor = settings.get_string(key)
        self.setCustomColors()

    def getSetGSettingEntries(self):
        self.dottedfile          = os.path.join(self.path, "dotted.png")
        self.pluginlist           = self.settings.get_strv("plugins-list")
        self.usecustomcolor       = self.settings.get_boolean("use-custom-color")
        self.customcolor          = self.settings.get_string("custom-color")
        self.customheadingcolor   = self.settings.get_string("custom-heading-color")
        self.offset               = self.settings.get_int("offset")
        self.enableTooltips       = self.settings.get_boolean("tooltips-enabled")
        self.startWithFavorites   = self.settings.get_boolean("start-with-favorites")

    def PopulatePlugins(self):
        self.panesToColor = []
        self.headingsToColor = []
        PluginPane = Gtk.EventBox()
        PluginPane.show()
        PaneLadder = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        PluginPane.add(PaneLadder)
        ImageBox = Gtk.EventBox()
        ImageBox.show()
        self.panesToColor.extend([PluginPane, ImageBox])

        seperatorImage = GdkPixbuf.Pixbuf.new_from_file(self.dottedfile)

        self.plugins = {}

        for plugin in self.pluginlist:
            if plugin in self.plugins:
                print("Duplicate plugin in list: %s" % plugin)
                continue

            if plugin != "newpane":
                try:
                    X = __import__(plugin)
                    # If no parameter passed to plugin it is autonomous
                    if X.pluginclass.__init__.func_code.co_argcount == 1:
                        MyPlugin = X.pluginclass()
                    else:
                        # pass mintMenu and togglebutton instance so that the plugin can use it
                        MyPlugin = X.pluginclass(self, self.toggle, self.de)

                    if not MyPlugin.icon:
                        MyPlugin.icon = "mate-logo-icon.png"

                    #if hasattr(MyPlugin, "hideseparator") and not MyPlugin.hideseparator:
                    #    Image1 = Gtk.Image()
                    #    Image1.set_from_pixbuf(seperatorImage)
                    #    if not ImageBox.get_child():
                    #        ImageBox.add(Image1)
                    #        Image1.show()

                    #print u"Loading plugin '" + plugin + "' : sucessful"
                except Exception:
                    MyPlugin = Gtk.EventBox() #Fake class for MyPlugin
                    MyPlugin.heading = _("Couldn't load plugin:") + " " + plugin
                    MyPlugin.content_holder = Gtk.EventBox()

                    # create traceback
                    info = sys.exc_info()

                    errorLabel = Gtk.Label("\n".join(traceback.format_exception(info[0], info[1], info[2])).replace("\\n", "\n"))
                    errorLabel.set_selectable(True)
                    errorLabel.set_line_wrap(True)
                    errorLabel.set_alignment(0.0, 0.0)
                    errorLabel.set_padding(5, 5)
                    errorLabel.show()

                    MyPlugin.content_holder.add(errorLabel)
                    MyPlugin.add(MyPlugin.content_holder)
                    MyPlugin.width = 270
                    MyPlugin.icon = 'mate-logo-icon.png'
                    print("Unable to load %s plugin" % plugin)

                self.panesToColor.append(MyPlugin.content_holder)
                MyPlugin.content_holder.show()

                VBox1 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
                if MyPlugin.heading != "":
                    label1 = Gtk.Label()
                    label1.set_markup("<span size=\"12000\" weight=\"bold\">%s</span>" % MyPlugin.heading)
                    Align1 = Gtk.Alignment.new(0, 0, 0, 0)
                    Align1.set_padding(10, 5, 10, 0)
                    Align1.add(label1)
                    self.headingsToColor.append(label1)
                    Align1.show()
                    label1.show()
                    heading = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
                    heading.set_size_request(MyPlugin.width, -1)

                    heading.add(Align1)
                    heading.show()
                    VBox1.pack_start(heading, False, False, 0)
                VBox1.show()
                #Add plugin to Plugin Box under heading button
                MyPlugin.content_holder.get_parent().remove(MyPlugin.content_holder)
                VBox1.add(MyPlugin.content_holder)

                #Add plugin to main window
                PaneLadder.pack_start(VBox1 , True, True, 0)
                PaneLadder.show()

                try:
                    MyPlugin.get_window().destroy()
                except AttributeError:
                    pass

                try:
                    if hasattr(MyPlugin, 'do_plugin'):
                        MyPlugin.do_plugin()
                    if hasattr(MyPlugin, 'height'):
                        MyPlugin.content_holder.set_size_request(-1, MyPlugin.height)
                    if hasattr(MyPlugin, 'itemstocolor'):
                        self.panesToColor.extend(MyPlugin.itemstocolor)
                    if hasattr(MyPlugin, 'headingstocolor'):
                        self.headingsToColor.extend(MyPlugin.headingstocolor)
                except:
                    # create traceback
                    info = sys.exc_info()

                    error = _("Couldn't initialize plugin") + " " + plugin + " : " + "\n".join(traceback.format_exception(info[0], info[1], info[2])).replace("\\n", "\n")
                    msgDlg = Gtk.MessageDialog(None, Gtk.DialogFlags.MODAL, Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, error)
                    msgDlg.run()
                    msgDlg.destroy()

                self.plugins[plugin] = MyPlugin

            else:
                self.paneholder.pack_start(ImageBox, False, False, 0)
                self.paneholder.pack_start(PluginPane, False, False, 0)
                PluginPane = Gtk.EventBox()
                PaneLadder = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
                PluginPane.add(PaneLadder)
                ImageBox = Gtk.EventBox()
                self.panesToColor.extend([PluginPane, ImageBox])
                ImageBox.show()
                PluginPane.show_all()

                if self.plugins and hasattr(MyPlugin, 'hideseparator') and not MyPlugin.hideseparator:
                    Image1 = Gtk.Image()
                    Image1.set_from_pixbuf(seperatorImage)
                    Image1.show()
                    #ImageBox.add(Image1)

                    Align1 = Gtk.Alignment.new(0, 0, 0, 0)
                    Align1.set_padding(0, 0, 6, 6)
                    Align1.add(Image1)
                    ImageBox.add(Align1)
                    ImageBox.show_all()


        self.paneholder.pack_start(ImageBox, False, False, 0)
        self.paneholder.pack_start(PluginPane, False, False, 0)

    # A little bit hacky but works.
    @staticmethod
    def getDefaultColors():
        widget = Gtk.EventBox()
        widget.show()

        context = widget.get_style_context()
        context.set_state(Gtk.StateFlags.NORMAL)
        context.add_class(Gtk.STYLE_CLASS_DEFAULT)
        context.add_class(Gtk.STYLE_CLASS_BACKGROUND)

        fgColor = context.get_color(context.get_state())
        bgColor = context.get_background_color(context.get_state())

        return {"fg": fgColor, "bg": bgColor}

    def loadTheme(self):
        self.setCustomColors()

    def setCustomColors(self):
        # Panes
        for item in self.panesToColor:
            context = item.get_style_context()
            if self.usecustomcolor:
                color = Gdk.RGBA()
                color.parse(self.customcolor)
                item.override_background_color(context.get_state(), color)
            else:
                colors = self.getDefaultColors()
                item.override_background_color(context.get_state(), colors["bg"])
        # Headings
        for item in self.headingsToColor:
            context = item.get_style_context()
            if self.usecustomcolor:
                color = Gdk.RGBA()
                color.parse(self.customheadingcolor)
                item.override_color(context.get_state(), color)
            else:
                colors = self.getDefaultColors()
                item.override_color(context.get_state(), colors["fg"])

    def setTooltip(self, widget, tip):
        self.tooltipsWidgets.append(widget)
        widget.set_tooltip_text(tip)

    def RegenPlugins(self, *args, **kargs):
        #print u"Reloading Plugins..."
        for item in self.paneholder:
            item.destroy()

        for plugin in self.plugins.values():
            if hasattr(plugin, "destroy"):
                plugin.destroy()

        try:
            del plugin
        except:
            pass

        try:
            del self.plugins
        except:
            pass

        gc.collect()

        self.getSetGSettingEntries()
        self.PopulatePlugins()
        self.toggleTooltipsEnabled(self.settings, "tooltips-enabled")
        self.loadTheme()

        #print NAME+u" reloaded"

    def onKeyPress(self, widget, event):
        if event.keyval == Gdk.KEY_Escape:
            self.hide()
            return True
        return False

    def show(self):
        self.window.present()

        # Hack for opacity not showing on first composited draw
        if self.firstTime:
            self.firstTime = False
            self.window.set_opacity(1.0)

        self.window.get_window().focus(Gdk.CURRENT_TIME)

        for plugin in self.plugins.values():
            if hasattr(plugin, "onShowMenu"):
                plugin.onShowMenu()

        if "applications" in self.plugins and hasattr(self.plugins["applications"], "focusSearchEntry"):
            if self.startWithFavorites:
                self.plugins["applications"].changeTab(0)
            self.plugins["applications"].focusSearchEntry()

    def hide(self):
        for plugin in self.plugins.values():
            if hasattr(plugin, "onHideMenu"):
                plugin.onHideMenu()

        self.window.hide()

    def onFocusIn(self, *args):
        if self.loseFocusBlocked:
            self.window.handler_unblock(self.loseFocusId)
            self.loseFocusBlocked = False

        return False

    def onFocusOut(self, *args):
        if self.window.get_visible():
            self.hide()
        return False

    def stopHiding(self):
        if not self.loseFocusBlocked:
            self.window.handler_block(self.loseFocusId)
            self.loseFocusBlocked = True

class MenuWin(object):

    def __init__(self, applet, iid):
        self.applet = applet
        self.detect_desktop_environment()
        self.settings = Gio.Settings.new("com.linuxmint.mintmenu")
        self.icon_theme = Gtk.IconTheme.get_default()
        self.loadSettings()

        self.createPanelButton()

        self.mate_settings = Gio.Settings.new("org.mate.interface")
        self.mate_settings.connect("changed::gtk-theme", self.changeTheme)

        self.settings.connect("changed::applet-text", self.reloadSettings)
        self.settings.connect("changed::theme-name", self.changeTheme)
        self.settings.connect("changed::hot-key", self.reloadSettings)
        self.settings.connect("changed::applet-icon", self.reloadSettings)
        self.settings.connect("changed::show-applet-icon", self.reloadSettings)
        self.settings.connect("changed::applet-icon-size", self.reloadSettings)

        self.applet.set_flags(MatePanelApplet.AppletFlags.EXPAND_MINOR)
        self.applet.connect("button-press-event", self.showMenu)
        self.applet.connect("change-orient", self.changeOrientation)
        self.applet.connect("enter-notify-event", self.enter_notify)
        self.applet.connect("leave-notify-event", self.leave_notify)

        self.mainwin = MainWindow(self.button_box, self.settings, self.de)
        self.mainwin.window.connect("map-event", self.onWindowMap)
        self.mainwin.window.connect("unmap-event", self.onWindowUnmap)
        self.mainwin.window.connect("size-allocate", lambda *args: self.positionMenu())

        self.mainwin.window.set_name("mintmenu") # Name used in Gtk RC files
        self.applyTheme()
        self.mainwin.loadTheme()

        if self.mainwin.icon:
            Gtk.Window.set_default_icon_name(self.mainwin.icon)

        try:
            self.keybinder = keybinding.GlobalKeyBinding()
            if self.hotkeyText != "":
                self.keybinder.grab(self.hotkeyText)
            self.keybinder.connect("activate", self.onBindingPress)
            self.keybinder.start()
            self.settings.connect("changed::hot-key", self.hotkeyChanged)
            print("Binding to Hot Key: %s" % self.hotkeyText)
        except Exception as e:
            self.keybinder = None
            print("** WARNING ** - Keybinder Error")
            print("Error Report :\n", e)

        self.applet.set_can_focus(False)

        try:
            self.pointerMonitor = pointerMonitor.PointerMonitor()
            self.pointerMonitor.connect("activate", self.onPointerOutside)
            self.mainwin.window.connect("realize", self.onRealize)
        except Exception as e:
            print("** WARNING ** - Pointer Monitor Error")
            print("Error Report :\n", e)

    def onWindowMap(self, *args):
        self.applet.get_style_context().set_state(Gtk.StateFlags.SELECTED)
        self.button_box.get_style_context().set_state(Gtk.StateFlags.SELECTED)
        if self.keybinder is not None:
            self.keybinder.set_focus_window(self.mainwin.window.get_window())
        return False

    def onWindowUnmap(self, *args):
        self.applet.get_style_context().set_state(Gtk.StateFlags.NORMAL)
        self.button_box.get_style_context().set_state(Gtk.StateFlags.NORMAL)
        if self.keybinder is not None:
            self.keybinder.set_focus_window()
        return False

    def onRealize(self, *args):
        self.pointerMonitor.addWindowToMonitor(self.mainwin.window.get_window())
        self.pointerMonitor.addWindowToMonitor(self.applet.get_window())
        self.pointerMonitor.start()
        return False

    def onPointerOutside(self, *args):
        self.mainwin.hide()
        return True

    def onBindingPress(self, binder):
        self.toggleMenu()
        return True

    def enter_notify(self, applet, event):
        self.set_applet_icon(True)

    def leave_notify(self, applet, event):
        # Hack for mate-panel-test-applets focus issue (this can be commented)
        # if event.state & Gdk.ModifierType.BUTTON1_MASK and applet.get_style_context().get_state() & Gtk.StateFlags.SELECTED:
        #     if event.x >= 0 and event.y >= 0 and event.x < applet.get_window().get_width() and event.y < applet.get_window().get_height():
        #         self.mainwin.stopHiding()

        self.set_applet_icon()

    def set_applet_icon(self, saturate=False):
        if saturate:
            self.button_icon.set_from_pixbuf(self.saturated_pixbuf)
        else:
            self.button_icon.set_from_pixbuf(self.pixbuf)

    def createPanelButton(self):
        self.button_icon = Gtk.Image()
        self.set_applet_icon()
        self.systemlabel = Gtk.Label(label= "%s " % self.buttonText)
        if os.path.isfile("/etc/linuxmint/info"):
            with open("/etc/linuxmint/info") as info:
                for line in info:
                    line = line.decode("utf-8")
                    if line.startswith("DESCRIPTION="):
                        tooltip = line.split("=",1)[1].strip('"\n')
                        self.systemlabel.set_tooltip_text(tooltip)
                        self.button_icon.set_tooltip_text(tooltip)
                        break
        if self.applet.get_orient() == MatePanelApplet.AppletOrient.UP or self.applet.get_orient() == MatePanelApplet.AppletOrient.DOWN:
            self.button_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
            self.button_box.pack_start(self.button_icon, False, False, 0)
            self.button_box.pack_start(self.systemlabel, False, False, 0)
            self.button_icon.set_padding(5, 0)
        # if we have a vertical panel
        elif self.applet.get_orient() == MatePanelApplet.AppletOrient.LEFT:
            self.button_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
            self.systemlabel.set_angle(270)
            self.button_box.pack_start(self.button_icon , False, False, 0)
            self.button_box.pack_start(self.systemlabel , False, False, 0)
            self.button_icon.set_padding(0, 5)
        elif self.applet.get_orient() == MatePanelApplet.AppletOrient.RIGHT:
            self.button_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
            self.systemlabel.set_angle(90)
            self.button_box.pack_start(self.systemlabel , False, False, 0)
            self.button_box.pack_start(self.button_icon , False, False, 0)
            self.button_icon.set_padding(0, 5)

        self.button_box.set_homogeneous(False)
        self.button_box.show_all()
        self.sizeButton()
        self.button_box.get_style_context().add_class('mintmenu')
        self.applet.add(self.button_box)
        self.applet.set_background_widget(self.applet)

    def loadSettings(self, *args, **kargs):
        self.showIcon   =  self.settings.get_boolean("show-applet-icon")
        self.buttonText =  self.settings.get_string("applet-text")
        self.theme_name =  self.settings.get_string("theme-name")
        self.hotkeyText =  self.settings.get_string("hot-key")

        applet_icon = self.settings.get_string("applet-icon")
        if not (os.path.exists(applet_icon) or self.icon_theme.has_icon(applet_icon)):
            self.settings.reset("applet-icon")
        applet_icon = self.settings.get_string("applet-icon")
        if "/" in applet_icon:
            if applet_icon.endswith(".svg"):
                self.pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(applet_icon, -1, 22)
            else:
                self.pixbuf = GdkPixbuf.Pixbuf.new_from_file(applet_icon)
        else:
            self.pixbuf = self.icon_theme.load_icon(applet_icon, 22, 0)
        self.saturated_pixbuf = self.pixbuf.copy()
        GdkPixbuf.Pixbuf.saturate_and_pixelate(self.saturated_pixbuf, self.saturated_pixbuf, 1.5, False)
        self.buttonIcon =  self.settings.get_string("applet-icon")
        self.iconSize = self.settings.get_int("applet-icon-size")

    def changeTheme(self, *args):
        self.reloadSettings()
        self.applyTheme()
        self.mainwin.loadTheme()

    def applyTheme(self):
        style_settings = Gtk.Settings.get_default()
        desktop_theme = self.mate_settings.get_string('gtk-theme')
        if self.theme_name == "default":
            style_settings.set_property("gtk-theme-name", desktop_theme)
        else:
            try:
                style_settings.set_property("gtk-theme-name", self.theme_name)
            except:
                style_settings.set_property("gtk-theme-name", desktop_theme)

    def changeOrientation(self, *args, **kargs):
        if self.applet.get_orient() == MatePanelApplet.AppletOrient.UP or self.applet.get_orient() == MatePanelApplet.AppletOrient.DOWN:
            tmpbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
            self.systemlabel.set_angle(0)
            self.button_box.reorder_child(self.button_icon, 0)
            self.button_icon.set_padding(5, 0)
        elif self.applet.get_orient() == MatePanelApplet.AppletOrient.LEFT:
            tmpbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
            self.systemlabel.set_angle(270)
            self.button_box.reorder_child(self.button_icon, 0)
            self.button_icon.set_padding(0, 5)
        elif self.applet.get_orient() == MatePanelApplet.AppletOrient.RIGHT:
            tmpbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
            self.systemlabel.set_angle(90)
            self.button_box.reorder_child(self.button_icon, 1)
            self.button_icon.set_padding(0, 5)

        tmpbox.set_homogeneous(False)

        # reparent all the hboxes to the new tmpbox
        for i in self.button_box:
            i.reparent(tmpbox)

        self.button_box.destroy()

        self.button_box = tmpbox
        self.button_box.show()

        # this call makes sure width stays intact
        self.updateButton()
        self.applet.add(self.button_box)

    def updateButton(self):
        self.systemlabel.set_text(self.buttonText)
        self.button_icon.clear()
        self.set_applet_icon()
        self.sizeButton()

    def hotkeyChanged (self, schema, key):
        self.hotkeyText =  self.settings.get_string("hot-key")
        self.keybinder.rebind(self.hotkeyText)

    def sizeButton(self):
        if self.showIcon:
            self.button_icon.show()
        else:
            self.button_icon.hide()

        # This code calculates width and height for the button_box
        # and takes the orientation and scale factor in account
        bi_req = self.button_icon.get_preferred_size()[1]
        bi_scale = self.button_icon.get_scale_factor()
        sl_req = self.systemlabel.get_preferred_size()[1]
        sl_scale = self.systemlabel.get_scale_factor()
        if self.applet.get_orient() == MatePanelApplet.AppletOrient.UP or self.applet.get_orient() == MatePanelApplet.AppletOrient.DOWN:
            if self.showIcon:
                self.applet.set_size_request(sl_req.width / sl_scale + bi_req.width / bi_scale + 5, bi_req.height)
            else:
                self.applet.set_size_request(sl_req.width / sl_scale + 2, bi_req.height)
        else:
            if self.showIcon:
                self.applet.set_size_request(bi_req.width, sl_req.height / sl_scale + bi_req.height / bi_scale + 5)
            else:
                self.applet.set_size_request(bi_req.width, sl_req.height / sl_scale + 2)

    def reloadSettings(self, *args):
        self.loadSettings()
        self.updateButton()

    def showAboutDialog(self, action, userdata = None):
        about = Gtk.AboutDialog()
        about.set_name("mintMenu")
        about.set_version("__DEB_VERSION__")
        try:
            gpl = open('/usr/share/common-licenses/GPL','r').read()
            about.set_license(gpl)
        except Exception as e:
            print(e)
        about.set_comments(_("Advanced MATE Menu"))
        # about.set_authors(["Clement Lefebvre <clem@linuxmint.com>", "Lars-Peter Clausen <lars@laprican.de>"])
        about.set_translator_credits(("translator-credits"))
        # about.set_copyright(_("Based on USP from S.Chanderbally"))
        about.set_logo(GdkPixbuf.Pixbuf.new_from_file("/usr/lib/linuxmint/mintMenu/icon.svg"))
        about.connect("response", lambda dialog, r: dialog.destroy())
        about.show()

    def showPreferences(self, action, userdata = None):
        Execute("/usr/lib/linuxmint/mintMenu/preferences.py")

    def showMenuEditor(self, action, userdata = None):
        Execute("mozo")

    def showMenu(self, widget=None, event=None):
        if event == None or event.button == 1:
            self.toggleMenu()
        # show right click menu
        elif event.button == 3:
            self.create_menu()
        # allow middle click and drag
        elif event.button == 2:
            self.mainwin.hide()

    def toggleMenu(self):
        if self.applet.get_style_context().get_state() & Gtk.StateFlags.SELECTED:
            self.mainwin.hide()
        else:
            self.positionMenu()
            self.mainwin.show()
            self.wakePlugins()

    def wakePlugins(self):
        self.mainwin.wakePlugins()

    def positionMenu(self):
        # Get our own dimensions & position
        ourWidth  = self.mainwin.window.get_size()[0]
        ourHeight = self.mainwin.window.get_size()[1] + self.mainwin.offset

        # Get the dimensions/position of the widgetToAlignWith
        try:
            entryX = self.applet.get_window().get_origin().x
            entryY = self.applet.get_window().get_origin().y
        except:
            # In Betsy get_origin returns an unamed tuple so the code above fails
            entryX = self.applet.get_window().get_origin()[1]
            entryY = self.applet.get_window().get_origin()[2]

        entryWidth, entryHeight =  self.applet.get_allocation().width, self.applet.get_allocation().height
        entryHeight = entryHeight + self.mainwin.offset

        # Get the monitor dimensions
        display = self.applet.get_display()
        if (Gtk.MAJOR_VERSION, Gtk.MINOR_VERSION) >= (3, 22):
            monitor = display.get_monitor_at_window(self.applet.get_window())
            monitorGeometry = monitor.get_geometry()
        else:
            screen = display.get_default_screen()
            monitor = screen.get_monitor_at_window(self.applet.get_window())
            monitorGeometry = screen.get_monitor_geometry(monitor)

        applet_orient = self.applet.get_orient()
        if applet_orient == MatePanelApplet.AppletOrient.UP:
            newX = entryX
            newY = entryY - ourHeight
        elif applet_orient == MatePanelApplet.AppletOrient.DOWN:
            newX = entryX
            newY = entryY + entryHeight
        elif applet_orient == MatePanelApplet.AppletOrient.RIGHT:
            newX = entryX + entryWidth
            newY = entryY
        elif applet_orient == MatePanelApplet.AppletOrient.LEFT:
            newX = entryX - ourWidth
            newY = entryY

        # Adjust for offset if we reach the end of the screen
        # Bind to the right side
        if newX + ourWidth > (monitorGeometry.x + monitorGeometry.width):
            newX = (monitorGeometry.x + monitorGeometry.width) - ourWidth
            if applet_orient == MatePanelApplet.AppletOrient.LEFT:
                newX -= entryWidth

        # Bind to the left side
        if newX < monitorGeometry.x:
            newX = monitorGeometry.x
            if applet_orient == MatePanelApplet.AppletOrient.RIGHT:
                newX -= entryWidth

        # Bind to the bottom
        if newY + ourHeight > (monitorGeometry.y + monitorGeometry.height):
            newY = (monitorGeometry.y + monitorGeometry.height) - ourHeight
            if applet_orient == MatePanelApplet.AppletOrient.UP:
                newY -= entryHeight

        # Bind to the top
        if newY < monitorGeometry.y:
            newY = monitorGeometry.y
            if applet_orient == MatePanelApplet.AppletOrient.DOWN:
                newY -= entryHeight

        # Move window
        self.mainwin.window.move(newX, newY)

    # this callback is to create a context menu
    def create_menu(self):
        action_group = Gtk.ActionGroup(name="context-menu")
        action = Gtk.Action(name="MintMenuPrefs", label=_("Preferences"), tooltip=None, stock_id="gtk-preferences")
        action.connect("activate", self.showPreferences)
        action_group.add_action(action)
        action = Gtk.Action(name="MintMenuEdit", label=_("Edit menu"), tooltip=None, stock_id="gtk-edit")
        action.connect("activate", self.showMenuEditor)
        action_group.add_action(action)
        action = Gtk.Action(name="MintMenuReload", label=_("Reload plugins"), tooltip=None, stock_id="gtk-refresh")
        action.connect("activate", self.mainwin.RegenPlugins)
        action_group.add_action(action)
        action = Gtk.Action(name="MintMenuAbout", label=_("About"), tooltip=None, stock_id="gtk-about")
        action.connect("activate", self.showAboutDialog)
        action_group.add_action(action)
        action_group.set_translation_domain ("mintmenu")

        xml = os.path.join(os.path.join(os.path.dirname(__file__)), "popup.xml")
        self.applet.setup_menu_from_file(xml, action_group)

    def detect_desktop_environment (self):
        self.de = "mate"
        try:
            de = os.environ["XDG_CURRENT_DESKTOP"].lower()
            if de in ["gnome", "gnome-shell", "mate", "kde", "xfce"]:
                self.de = de
            elif de in ['cinnamon', 'x-cinnamon']:
                self.de = 'cinnamon'
            else:
                if os.path.exists("/usr/bin/caja"):
                    self.de = "mate"
                elif os.path.exists("/usr/bin/thunar"):
                    self.de = "xfce"
        except Exception as e:
            print(e)

def applet_factory(applet, iid, data):
    MenuWin(applet, iid)
    applet.show()
    return True

def quit_all(widget):
    Gtk.main_quit()
    sys.exit(0)

MatePanelApplet.Applet.factory_main("MintMenuAppletFactory", True,
                                    MatePanelApplet.Applet.__gtype__,
                                    applet_factory, None)
