pablokal

adskmenu in tint2

Aug 8th, 2011
645
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3.  
  4. ##
  5. #  ADesk Menu
  6. #   - v0.2 : add signal , get cursor position and show menu whith it
  7. #   - v0.1 : check if 'Terminal=true' in .desktop file, always above other windows
  8. #
  9. #   by ADcomp <david.madbox@gmail.com>
  10. #      http://www.ad-comp.be/
  11. #
  12. #   This program is distributed under the terms of the GNU General Public License
  13. #   For more info see http://www.gnu.org/licenses/gpl.txt
  14. #####################################################################################
  15. #
  16. #   7/25/11
  17. #
  18. #   This script was edited from the original by sliphot and MoD from silver irc.
  19. #   I thhought it might come in handy with tint2s's new launcher feature.
  20. #   We re-worked it so it will open the menu in a designated area of the screen when the script is executed.
  21. #   by default it opens in the top left corner of the screen. To adjust go to line 369 and adjust x= and y=
  22. #   Make this script executable and move it to /usr/bin after that make a .desktop file pointing to it.
  23. #   Point tint2 to the .desktop file and presto! tint2 desktop menu. It can be a little slow to load.
  24. #   It helps to run it once in a terminal with the -s option. it saves a config file of all your .desktop files.
  25. #   If you install a new app after you have ran the -s option you will have to run it again to update the config.
  26. #
  27. #####################################################################################
  28.  
  29.  
  30. MENU_WIDTH = 380
  31.  
  32. import os
  33. import sys
  34. import gtk
  35. import signal
  36.  
  37. cat_name = {'accessories':('Utility','Accessories'),
  38.             'development':('Development'),
  39.             'engineering':(),
  40.             'games':('Game'),
  41.             'graphics':('Graphics'),
  42.             'internet':('Internet', 'Network'),
  43.             'multimedia':('AudioVideo', 'Audio', 'Video', 'Multimedia'),
  44.             'office':('Office'),
  45.             'other':('Other'),
  46.             'science':(),
  47.             'system':('System', 'Administration'),
  48.             'settings':('Settings', 'X-XFCE'),
  49.             'utilities':()
  50.             }
  51.  
  52. def exec_cmd(cmd=None):
  53.     if cmd and not cmd=='':
  54.         os.system('%s &' % cmd)
  55.  
  56. # Find the Name / Command / Icon from .desktop file
  57. def info_desktop(file):
  58.     cmd, icon, name, category = None, None, None, None
  59.     terminal = False
  60.     try:
  61.         cfile = open(file,"r")
  62.  
  63.         for line in cfile:
  64.             if 'NoDisplay=true' in line or 'OnlyShowIn=KDE' in line:
  65.                 icon, category = None, None
  66.                 break
  67.             elif 'Terminal=true' in line:
  68.                 terminal = True
  69.             elif '=' in line:
  70.                 words = line.split('=')
  71.                 if words[0] == 'Name':
  72.                     name = words[1].replace('\n','')
  73.                     # print 'Name =', name
  74.                 elif words[0] == 'Icon':
  75.                     icon = words[1].replace('\n','')
  76.                     # print 'Icon =', icon
  77.                 elif words[0] == 'Exec':
  78.                     cmd = words[1].replace('\n','')
  79.                     cmd = cmd.split('%')[0]
  80.                     # print 'Exec :', cmd
  81.                 elif words[0] == 'Categories':
  82.                     tab = words[1].replace('\n','')
  83.                     tab = tab.split(';')
  84.                     #~ category = '***************************'
  85.  
  86.                     #~ if not 'X-XFCE' in tab:
  87.  
  88.                     for cat in tab:
  89.                         found = False
  90.                         for c_name in cat_name:
  91.                             if cat in cat_name[c_name]:
  92.                                 category = c_name
  93.                                 found = True
  94.                                 break
  95.                         if found:
  96.                             break
  97.  
  98.         # if command is 'console only', launch it with terminal ..
  99.         if terminal:
  100.             cmd = "x-terminal-emulator -e %s" % cmd
  101.  
  102.         cfile.close()
  103.  
  104.     except:
  105.         #~ print("# Error : parsing %s" % file)
  106.         pass
  107.  
  108.     return (cmd, icon, name, category)
  109.  
  110. # Find the best icon with highest resolution for the launcher
  111. def find_icon(icon):
  112.     foundiconfile=None
  113.  
  114.     if icon == '':
  115.         return foundiconfile
  116.  
  117.     if icon[0] == '/':
  118.         return icon
  119.  
  120.     iconbase=('','Madbox','gnome','hicolor','locolor')
  121.     iconpath='/usr/share/icons'
  122.     sizelist =('', 'scalable', '256x256', '128x128', '64x64', '48x48', '32x32', '24x24')
  123.     categorylist=('actions', 'apps',"devices", 'categories','filesystems', 'places', 'status', '')
  124.     extensionlist = ('png', 'svg', 'xpm')
  125.  
  126.     iconimagelist=[]
  127.  
  128.     for extension in extensionlist:
  129.         if (icon.find('.'+extension) != -1):
  130.             icon = icon.replace('.'+extension,'')
  131.  
  132.     for size in sizelist:
  133.         for extension in extensionlist:
  134.             for category in categorylist:
  135.                 for iconbasecat in iconbase:
  136.                     iconfile = iconpath+"/"+iconbasecat+'/'+size+'/'+category+'/'+icon+'.'+extension
  137.                     iconimagelist.append(iconfile)
  138.  
  139.     for extension in extensionlist:
  140.         iconfile = '/usr/share/pixmaps/'+icon+'.'+extension
  141.         iconimagelist.append(iconfile)
  142.  
  143.     for extension in extensionlist:
  144.         iconfile = '/usr/share/app-install/icons/'+icon+'.'+extension
  145.         iconimagelist.append(iconfile)
  146.  
  147.     # Seek if the files in pre-generated list exists.. first match is the best
  148.     # return it
  149.     for iconimage in iconimagelist:
  150.         if os.path.exists(iconimage):
  151.             return iconimage
  152.  
  153.     return foundiconfile
  154.  
  155. def parse_desktop_dir(check_config=True):
  156.     config = {}
  157.     cfg_file = home = os.getenv('HOME') + '/.config/adesk-menu/config'
  158.  
  159.     if os.access(cfg_file, os.F_OK|os.R_OK) and check_config:
  160.         print('found user config ..')
  161.         f = open(cfg_file,'r')
  162.  
  163.         for line in f:
  164.             if line == '\n' or line.startswith('#'):
  165.                 continue
  166.             elif line.startswith('@'):
  167.                 cat = line[1:]
  168.                 cat = cat.strip('\n')
  169.                 cat = cat.strip(' ')
  170.                 config[cat] = []
  171.                 cat_index = cat
  172.             else:
  173.                 line = line.strip('\n')
  174.                 line = line.strip(' ')
  175.                 config[cat_index].append(line.split('##'))
  176.         f.close()
  177.  
  178.     else:
  179.         print('scan /usr/share/applications and parse .desktop file ..')
  180.  
  181.         APP_PATH = '/usr/share/applications/'
  182.         listdir = os.listdir(APP_PATH)
  183.  
  184.         for i in listdir:
  185.             if '.desktop' in i:
  186.                 #~ print i
  187.                 (cmd, icon, name, category) = info_desktop(APP_PATH + i)
  188.                 #~ print cmd, icon, name, category
  189.                 if category:
  190.                     if not config.has_key(category):
  191.                         #~ print "@ add :", category
  192.                         config[category] = []
  193.                     if icon:
  194.                         icon_path = find_icon(icon)
  195.                         config[category].append((cmd, icon_path, name))
  196.                     else:
  197.                         pass
  198.                         #~ print "File =", i
  199.                         #~ print '=> NO ICON ...'
  200.                 else:
  201.                     pass
  202.                     #~ print "File =", i
  203.                     #~ print '=> NO CATEGORY ...'
  204.     #~ print config
  205.     return config
  206.  
  207. def write_config():
  208.     home = os.environ['HOME']
  209.     cfg_file = "%s/.config/adesk-menu/config" % home
  210.  
  211.     if not os.path.exists("%s/.config/adesk-menu" % home):
  212.         os.makedirs("%s/.config/adesk-menu" % home)
  213.  
  214.     f = open(cfg_file,'w')
  215.     m = parse_desktop_dir(False)
  216.     m_tmp = []
  217.  
  218.     for cat in m:
  219.         m_tmp.append(cat)
  220.     m_tmp.sort()
  221.  
  222.     for cat in m_tmp:
  223.         f.write('@%s\n' % cat)
  224.         for item in m[cat]:
  225.             (cmd, icon, text) = item
  226.             f.write('%s##%s##%s\n' % item)
  227.     f.close()
  228.     print "menu saved to %s" % cfg_file
  229.  
  230. class Menu():
  231.     def __init__(self):
  232.         self.hide_me = False
  233.         self.focus_check = False
  234.         self.mode = None
  235.  
  236.         self.create_window()
  237.  
  238.         # Menu
  239.         self.popupMenu = gtk.Menu()
  240.         menuPopup = gtk.ImageMenuItem (gtk.STOCK_QUIT)
  241.         menuPopup.connect("activate", self.doquit)
  242.         self.popupMenu.add(menuPopup)
  243.         self.popupMenu.show_all()
  244.  
  245.     def doquit(self, widget=None, data=None):
  246.         gtk.main_quit()
  247.  
  248.     def run(self):
  249.         gtk.main()
  250.  
  251.     def create_window(self):
  252.         self.window = gtk.Window() #gtk.WINDOW_POPUP) ## gtk.WINDOW_TOPLEVEL)
  253.         self.window.connect("destroy", self.doquit)
  254.         #~ self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_UTILITY)
  255.         self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_NORMAL)
  256.         self.window.add_events(gtk.gdk.FOCUS_CHANGE_MASK)
  257.         self.window.connect("focus-out-event", self.lost_focus)
  258.         self.window.connect("key-press-event", self.onkeypress)
  259.         self.window.stick()
  260.         self.window.set_decorated(False)
  261.         self.window.set_keep_below(False)
  262.         self.window.set_keep_above(True)
  263.         self.window.set_resizable(True)
  264.         self.window.set_border_width(2)
  265.         self.window.set_app_paintable(True)
  266.  
  267.         self.frame = gtk.Frame()
  268.         self.frame.show()
  269.         self.frame.set_size_request(MENU_WIDTH,-1)
  270.  
  271.         self.nbook = gtk.Notebook()
  272.         self.nbook.show()
  273.         self.nbook.set_tab_pos(gtk.POS_LEFT)
  274.         self.nbook.set_border_width(2)
  275.  
  276.         self.frame.add(self.nbook)
  277.         self.window.add(self.frame)
  278.  
  279.         m = parse_desktop_dir()
  280.         m_tmp = []
  281.  
  282.         for cat in m:
  283.             m_tmp.append(cat)
  284.         m_tmp.sort()
  285.  
  286.         self.cat_but = []
  287.         self.cur_pos = 0
  288.         self.cat_visible = True
  289.  
  290.         for cat in m_tmp:
  291.             bBox = gtk.VBox()
  292.             bBox.show()
  293.             bBox.set_spacing(4)
  294.             bBox.set_border_width(2)
  295.  
  296.             scrolled = gtk.ScrolledWindow()
  297.             scrolled.show()
  298.             scrolled.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
  299.             scrolled.add_with_viewport(bBox)
  300.  
  301.             label = gtk.Label(cat[0].upper() + cat[1:])
  302.             label.show()
  303.             label.set_alignment(0, 1)
  304.             self.nbook.append_page(scrolled, label)
  305.  
  306.             for item in m[cat]:
  307.                 (cmd, icon, text) = item
  308.  
  309.                 widget = gtk.Button() # item.label)
  310.                 widget.set_relief(gtk.RELIEF_NONE)
  311.                 widget.set_border_width(0)
  312.                 widget.set_focus_on_click(False)
  313.                 #~ widget.set_property('can-focus', False)
  314.  
  315.                 image = gtk.Image()
  316.                 image.show()
  317.                 image.set_size_request(24,24)
  318.                 label = gtk.Label(text)
  319.                 label.show()
  320.                 label.set_alignment(0.2, 1)
  321.                 align = gtk.Alignment(1, 0, 0.5, 0.5)
  322.                 align.show()
  323.                 align.add(label)
  324.                 box = gtk.HBox(False, 4)
  325.                 box.show()
  326.                 box.pack_start(image, False, False)
  327.                 box.pack_start(align, False, False)
  328.                 widget.add(box)
  329.  
  330.                 try:
  331.                     pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(icon, 24, 24)
  332.                 except:
  333.                     pixbuf = gtk.gdk.pixbuf_new_from_file_at_size('/usr/share/pixmaps/debian-logo.png', 24, 24)
  334.                 image.set_from_pixbuf(pixbuf)
  335.                 image.show()
  336.  
  337.                 widget.connect("button-release-event", self.ExecuteAction, cmd)
  338.                 bBox.pack_start(widget,False,False)
  339.                 widget.show()
  340.  
  341.     def ExecuteAction(self, widget, event, cmd):
  342.         self.focus_check = False
  343.         exec_cmd(cmd)
  344.         self.doquit()
  345.  
  346.     def toggle_hide(self, widget=None, event=None):
  347.         if self.hide_me:
  348.             self.hide_me = False
  349.             self.show_menu(self.mode)
  350.             self.window.show()
  351.             self.focus_check = True
  352.         else:
  353.             self.hide_me = True
  354.             self.focus_check = False
  355.             self.window.hide()
  356.  
  357.     def show_menu(self, mode=None):
  358.        
  359.         screen_width, screen_height = gtk.gdk.screen_width(), gtk.gdk.screen_height()
  360.         rootwin = self.window.get_screen().get_root_window()
  361.         w_width , w_height = self.window.get_size()
  362.         x, y, mods = rootwin.get_pointer()
  363.         if x + MENU_WIDTH > screen_width:
  364.             x = screen_width - MENU_WIDTH
  365.         if y + w_height > screen_height:
  366.             y = screen_height - w_height
  367.         #to move the menu adjust the x= and y=    
  368.         #this should not be commented out
  369.         self.window.move(x=10, y=40)
  370.  
  371.     def lost_focus(self, widget, event):
  372.         if self.focus_check:
  373.             self.doquit()
  374.  
  375.     def onkeypress(self, widget, event):
  376.         if event.keyval == gtk.keysyms.Escape:
  377.             self.doquit()
  378.  
  379.     def status_icon_popup(self, widget, button, active_time):
  380.         self.popupMenu.popup(None, None, None, 1, 0)
  381.  
  382.     def callback_signal(self):
  383.         #~ print "callback_signal .."
  384.         self.mode = "mouse"
  385.         self.toggle_hide()
  386.         self.mode = None
  387.  
  388. ##--
  389.  
  390. global g_menu
  391.  
  392. def SigUSR1Handler(signum, frame):
  393.     """ grab signal to reload config """
  394.     # kill -10 <adesk-menu pid>
  395.     global g_menu
  396.     g_menu.callback_signal()
  397.     return
  398.  
  399. def save_pid():
  400.     home = os.environ['HOME']
  401.     pid_file = "%s/.config/adesk-menu/pid" % home
  402.     pid = os.getpid()
  403.     print "PID = %s" % pid
  404.  
  405.     if not os.path.exists("%s/.config/adesk-menu" % home):
  406.         os.makedirs("%s/.config/adesk-menu" % home)
  407.  
  408.     f = open(pid_file,'w')
  409.     f.write('%s' % pid)
  410.     f.close()
  411.     print "PID saved to %s" % pid_file
  412.  
  413. if __name__ == "__main__":
  414.  
  415.     if len(sys.argv) == 2:
  416.         if sys.argv[1] == '-s':
  417.             write_config()
  418.         elif sys.argv[1] == '-t':
  419.             cmd = "kill -10 `cat ~/.config/adesk-menu/pid`"
  420.             os.system(cmd)
  421.         else:
  422.             print "Unknow option .."
  423.             print "Usage : adesk-menu [-s|-t]"
  424.             print " -s : save menu list ( ~/.config/adesk-menu/config )"
  425.             print " -t : show menu ( cursor position )"
  426.     else:
  427.         global g_menu
  428.         signal.signal(signal.SIGUSR1, SigUSR1Handler)
  429.         save_pid()
  430.  
  431.         ## need to change directory
  432.         SRC_PATH = os.path.dirname(os.path.realpath( __file__ ))
  433.         os.chdir(SRC_PATH)
  434.  
  435.         g_menu = Menu()
  436.         # change directory to Home
  437.         os.chdir(os.getenv('HOME'))
  438.         g_menu.hide_me = False
  439.         g_menu.show_menu(g_menu.mode)
  440.         g_menu.window.show()
  441.         g_menu.focus_check = True
  442.         g_menu.run()
RAW Paste Data