#!/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 '' # magic header else: print '' # 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 = "" for app in catList: progStr = "" % app.Exec print progStr print "" print "" # magic footer pass # done/debug break