#!/usr/bin/python3 # -*- coding: utf-8 -*- import os import xdg.DesktopEntry as dent import os.path as path import subprocess import re from os import environ as env from sys import argv from collections import OrderedDict import ipc def which(f): if path.isabs(f) and path.isfile(f) and os.access(f, os.X_OK): return f for d in env.get("PATH").split(':'): p = path.join(d, f) if path.isabs(p) and path.isfile(p) and os.access(p, os.X_OK): return p return None def uniq_list(l): return list(OrderedDict.fromkeys(l)) def quote(s): res = re.sub(r'[`$\\]', lambda match: '\\'+match.group(0) , s) res = u"\"" + res + u"\"" if res!=s or s==u"" else s return res def main(argv): localdir = env.get("XDG_DATA_HOME", None) or path.join(env["HOME"], ".local", "share") globaldir = (env.get("XDG_DATA_DIRS", None) or "/usr/local/share/:/usr/share/").split(':') searchdirs = uniq_list([path.join(d, "applications") for d in [localdir] + globaldir]) desktops = [] for d in searchdirs: for base, dirs, files in os.walk(d): for name in files: if name.endswith(".desktop"): desktops.append(path.join(base, name)) pick = {} for f in desktops: dsk = dent.DesktopEntry(f) if not(dsk.getType()=="Application" or dsk.getExec()): continue if dsk.getNoDisplay() or dsk.getHidden(): continue tryexec = dsk.getTryExec() if tryexec and not which(tryexec): continue generic = dsk.getGenericName() if not isinstance(generic, str): generic = generic.decode("utf-8") name = dsk.getName() if not isinstance(name, str): name = name.decode("utf-8") dsk.name = name # ugly, sure label = name if generic: label = name + u" - " + generic i = 2 while label in pick: label = u"%s [%d]" % (name, i) i += 1 pick[label] = dsk dmenu = subprocess.Popen(['dmenu']+argv[1:], stdin=subprocess.PIPE, stdout=subprocess.PIPE) dmenulist = "\n".join(sorted(pick.keys())).encode("utf-8") dmenustdout = dmenu.communicate(dmenulist)[0] picked = dmenustdout.rstrip(b"\n").decode("utf-8") if picked: try: dsk = pick[picked] cmd = dsk.getExec() cmd = re.sub(r'%[fFuUdDnNivm]', '', cmd) cmd = cmd.replace(u'%c', quote(dsk.name)) cmd = cmd.replace(u'%k', quote(dsk.filename)) cmd = cmd.replace(u'%%', u'%') except KeyError: cmd = quote(picked) ipc.i3().command(ipc.COMMAND, "exec %s" % cmd) if __name__=="__main__": main(argv)