211 lines
6.8 KiB
Python
Executable File
211 lines
6.8 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Version 1.1.7
|
|
# ---- config ---
|
|
applications_dirs = ("/usr/share/applications", )
|
|
image_dir_base = "/usr/share" # without "pixmaps" -/usr/local/share in FreeBSD, /usr/share on linux
|
|
icon_Theme = "Humanity"
|
|
image_cat_prefix = "applications-" # if empty will create no icon text only menu
|
|
application_groups = ("Office", "Development", "Graphics", "Internet", "Games", "System", "Multimedia", "Utilities", "Settings")
|
|
group_aliases = {"Audio":"Multimedia","AudioVideo":"Multimedia","Network":"Internet","Game":"Games", "Utility":"Utilities", "GTK":"", "GNOME":""}
|
|
ignoreList = ("evince-previewer", "Ted", "wingide3.2", "python3.4", "feh","xfce4-power-manager-settings" )
|
|
terminal_string = "evte -e" # your favourites terminal exec string
|
|
simpleOBheader = False # print full xml style OB header
|
|
# --- End of user config ---
|
|
|
|
import glob
|
|
|
|
class dtItem(object):
|
|
def __init__(self, fName):
|
|
self.fileName = fName
|
|
self.Name = ""
|
|
self.Comment = ""
|
|
self.Exec = ""
|
|
self.Terminal = None
|
|
self.Type = ""
|
|
self.Icon = ""
|
|
self.Categories = ()
|
|
|
|
def addName(self, data):
|
|
self.Name = xescape(data)
|
|
|
|
def addComment(self, data):
|
|
self.Comment = data
|
|
|
|
def addExec(self, data):
|
|
if len(data) > 3 and data[-2] == '%': # get rid of filemanager arguments in dt files
|
|
data = data[:-2].strip()
|
|
self.Exec = data
|
|
|
|
def addIcon(self, data):
|
|
self.Icon = ""
|
|
if image_cat_prefix == "":
|
|
return
|
|
image_dir = image_dir_base + "/pixmaps/"
|
|
di = data.strip()
|
|
if len(di) < 3:
|
|
#"Error in %s: Invalid or no icon '%s'" % (self.fileName, di)
|
|
return
|
|
dix = di.find("/") # is it a full path?
|
|
if dix >= 0 and dix <= 2: # yes, its a path (./path or ../path or /path ...)
|
|
self.Icon = di
|
|
return
|
|
#else a short name like "myapp"
|
|
tmp = image_dir + di + ".*"
|
|
tmp = glob.glob(tmp)
|
|
if len(tmp) > 0:
|
|
self.Icon = tmp[0]
|
|
return
|
|
|
|
def addTerminal(self, data):
|
|
if data == "True" or data == "true":
|
|
self.Terminal = True
|
|
else:
|
|
self.Terminal = False
|
|
|
|
def addType(self, data):
|
|
self.Type = data
|
|
|
|
def addCategories(self, data):
|
|
self.Categories = data
|
|
|
|
def getCatIcon(cat):
|
|
iconDir = image_dir_base + "/icons/" + icon_Theme + "/categories/24/"
|
|
cat = image_cat_prefix + cat.lower()
|
|
tmp = glob.glob(iconDir + cat + ".*")
|
|
if len(tmp) > 0:
|
|
return tmp[0]
|
|
return ""
|
|
|
|
def xescape(s):
|
|
Rep = {"&":"&", "<":"<", ">":">", "'":"'", "\"":"""}
|
|
for p in ("&", "<", ">", "'","\""):
|
|
sl = len(s); last = -1
|
|
while last < sl:
|
|
i = s.find(p, last+1)
|
|
if i < 0:
|
|
done = True
|
|
break
|
|
last = i
|
|
l = s[:i]
|
|
r = s[i+1:]
|
|
s = l + Rep[p] + r
|
|
return s
|
|
|
|
def process_category(cat, curCats, appGroups = application_groups, aliases = group_aliases ):
|
|
# first process aliases
|
|
if aliases.has_key(cat):
|
|
if aliases[cat] == "":
|
|
return "" # ignore this one
|
|
cat = aliases[cat]
|
|
if cat in appGroups and cat not in curCats: # valid categories only and no doublettes, please
|
|
curCats.append(cat)
|
|
return cat
|
|
return ""
|
|
|
|
|
|
def process_dtfile(dtf, catDict): # process this file & extract relevant info
|
|
active = False # parse only after "[Desktop Entry]" line
|
|
fh = open(dtf, "r")
|
|
lines = fh.readlines()
|
|
this = dtItem(dtf)
|
|
for l in lines:
|
|
l = l.strip()
|
|
if l == "[Desktop Entry]":
|
|
active = True
|
|
continue
|
|
if active == False: # we don't care about licenses or other comments
|
|
continue
|
|
if l == None or len(l) < 1 or l[0] == '#':
|
|
continue
|
|
if l[0]== '[' and l != "[Desktop Entry]":
|
|
active = False
|
|
continue
|
|
# else
|
|
eqi = l.split('=')
|
|
if len(eqi) < 2:
|
|
print "Error: Invalid .desktop line'" + l + "'"
|
|
continue
|
|
# Check what it is ...
|
|
if eqi[0] == "Name":
|
|
this.addName(eqi[1])
|
|
elif eqi[0] == "Comment":
|
|
this.addComment(eqi[1])
|
|
elif eqi[0] == "Exec":
|
|
this.addExec(eqi[1])
|
|
elif eqi[0] == "Icon":
|
|
this.addIcon(eqi[1])
|
|
elif eqi[0] == "Terminal":
|
|
this.addTerminal(eqi[1])
|
|
elif eqi[0] == "Type":
|
|
if eqi[1] != "Application":
|
|
continue
|
|
this.addType(eqi[1])
|
|
elif eqi[0] == "Categories":
|
|
if eqi[1][-1] == ';':
|
|
eqi[1] = eqi[1][0:-1]
|
|
cats = []
|
|
# DEBUG
|
|
dtCats = eqi[1].split(';')
|
|
for cat in dtCats:
|
|
result = process_category(cat, cats)
|
|
this.addCategories(cats)
|
|
else:
|
|
continue
|
|
# add to catDict
|
|
#this.dprint()
|
|
if len(this.Categories) > 0: # don't care about stuff w/o category
|
|
for cat in this.Categories:
|
|
catDict[cat].append(this)
|
|
|
|
categoryDict = {}
|
|
|
|
if __name__ == "__main__":
|
|
# init the application group dict (which will contain list of apps)
|
|
for appGroup in application_groups:
|
|
categoryDict[appGroup] = []
|
|
|
|
# now let's look into the app dirs ...
|
|
for appDir in applications_dirs:
|
|
appDir += "/*.desktop"
|
|
dtFiles = glob.glob(appDir)
|
|
|
|
# process each .desktop file in dir
|
|
for dtf in dtFiles:
|
|
skipFlag = False
|
|
for ifn in ignoreList:
|
|
if dtf.find(ifn) >= 0:
|
|
skipFlag = True
|
|
if skipFlag == False:
|
|
process_dtfile(dtf, categoryDict)
|
|
|
|
# now, generate jwm menu include
|
|
if simpleOBheader == True:
|
|
print '<openbox_pipe_menu>' # magic header
|
|
else:
|
|
print '<?xml version="1.0" encoding="UTF-8" ?><openbox_pipe_menu xmlns="http://openbox.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://openbox.org/" >' # magic header
|
|
appGroupLen = len(application_groups)
|
|
for ag in range(appGroupLen ):
|
|
catList = categoryDict[application_groups[ag]]
|
|
if len(catList) < 1:
|
|
continue # don't create empty menus
|
|
catStr = "<menu id=\"openbox-%s\" label=\"%s\" " % (application_groups[ag], application_groups[ag])
|
|
tmp = getCatIcon(application_groups[ag])
|
|
if tmp != "":
|
|
catStr += "icon=\"%s\"" % tmp
|
|
print catStr, ">"
|
|
for app in catList:
|
|
progStr = "<item "
|
|
progStr += "label=\"%s\" " % app.Name
|
|
if app.Icon != "":
|
|
progStr += "icon=\"%s\" " % app.Icon
|
|
progStr += "><action name=\"Execute\"><command><![CDATA["
|
|
if app.Terminal == True:
|
|
progStr += terminal_string + " "
|
|
progStr += "%s]]></command></action></item>" % app.Exec
|
|
print progStr
|
|
print "</menu>"
|
|
print "</openbox_pipe_menu>" # magic footer
|
|
pass # done/debug break
|