e_gen_menu: New python version
Quite a bit easier to read, IMO. Looks like twice as fast as the old perl one.
This commit is contained in:
parent
8c6817fd99
commit
5e000d0d4e
|
@ -1,5 +1,5 @@
|
|||
scriptdir = $(pkgdatadir)/scripts
|
||||
|
||||
script_SCRIPTS = e_gen_menu.pl e_cache_clean e_cache_query session.sh
|
||||
script_SCRIPTS = e_gen_menu e_cache_clean e_cache_query session.sh
|
||||
|
||||
EXTRA_DIST = $(script_SCRIPTS)
|
||||
|
|
|
@ -0,0 +1,514 @@
|
|||
#!/usr/bin/python3
|
||||
#
|
||||
# generates menus for e16 from .desktop files
|
||||
#
|
||||
import os, sys
|
||||
import getopt
|
||||
import subprocess
|
||||
|
||||
|
||||
dbg = 0
|
||||
N = 0
|
||||
dtis = {}
|
||||
dt_seen = {}
|
||||
|
||||
|
||||
class DTI: # .desktop item
|
||||
def __init__(self, file, name, exec, icon, cats, type):
|
||||
self.file = file
|
||||
self.name = name
|
||||
self.exec = exec
|
||||
self.icon = icon
|
||||
self.cats = cats
|
||||
self.type = type
|
||||
|
||||
|
||||
def D(str):
|
||||
if dbg > 0:
|
||||
print(str)
|
||||
|
||||
|
||||
def D2(str):
|
||||
if dbg >= 2:
|
||||
print(str)
|
||||
|
||||
|
||||
def D3(str):
|
||||
if dbg >= 3:
|
||||
print(str)
|
||||
|
||||
|
||||
def getenv(env):
|
||||
if env in os.environ:
|
||||
return os.environ[env]
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
def FileExt(file):
|
||||
return os.path.splitext(file)[1]
|
||||
|
||||
|
||||
# Make directory list, check that they exist
|
||||
def MkDirList(pfxs, sufs, sep=''):
|
||||
r = []
|
||||
for pfx in pfxs:
|
||||
for suf in sufs:
|
||||
dir = f'{pfx}{sep}{suf}'
|
||||
if os.path.isdir(dir):
|
||||
r += [dir]
|
||||
return r
|
||||
|
||||
|
||||
# Remove duplicates and nulls in dir list
|
||||
def RemoveDuplicates(arr):
|
||||
r = []
|
||||
for itm in arr:
|
||||
if itm == '' or itm in r:
|
||||
continue
|
||||
r.append(itm)
|
||||
return r
|
||||
|
||||
|
||||
# Make dir if non-existing
|
||||
def MkDir(dir):
|
||||
if not os.path.isdir(dir):
|
||||
os.makedirs(dir, 0o755)
|
||||
D(f'mkdir {dir}')
|
||||
|
||||
|
||||
# Make simple menus
|
||||
def MakeMenu(name, tmpl):
|
||||
file = EdirMenus + '/' + name
|
||||
D(f'Generating {name} -> {file}')
|
||||
if os.path.exists(file):
|
||||
return
|
||||
|
||||
f = open(file, 'w')
|
||||
for line in tmpl:
|
||||
(t, n, p) = line.split(':')
|
||||
if t == 't':
|
||||
f.write(f'"{n}"\n')
|
||||
elif t == 'm':
|
||||
f.write(f'"{n}" NULL menu "{p}"\n')
|
||||
elif t == 'x':
|
||||
f.write(f'"{n}" NULL exec "{p}"\n')
|
||||
elif t == 'c':
|
||||
f.write(f'"{n}" NULL "{p}"\n')
|
||||
f.close()
|
||||
|
||||
|
||||
# Make the Epplets menu
|
||||
def MakeEppsMenu(name):
|
||||
dirs = []
|
||||
file = EdirMenus + '/' + name
|
||||
D(f'Generating {name} -> {file}')
|
||||
|
||||
f = open(file, 'w')
|
||||
f.write('"Enlightenment Epplets"\n')
|
||||
|
||||
for dir in os.environ['PATH'].split(':'):
|
||||
# D(f'P = {dir}')
|
||||
if dir in dirs:
|
||||
continue
|
||||
dirs.append(dir)
|
||||
D2(f'Looking for epplets in {dir}')
|
||||
for file in os.listdir(dir):
|
||||
if not file.endswith('.epplet'):
|
||||
continue
|
||||
epp = file.removesuffix('.epplet')
|
||||
f.write(f'"{epp}" "{EdirRoot}/epplet_icons/{epp}.icon" exec "{dir}/{file}"\n')
|
||||
f.close()
|
||||
|
||||
|
||||
# Process a .desktop file
|
||||
def ProcessFile(file, cats, type):
|
||||
global N
|
||||
global dtis
|
||||
|
||||
D(f'- File {file}')
|
||||
|
||||
if not os.path.isfile(file):
|
||||
print(f'Not found: {file}')
|
||||
exit(1)
|
||||
|
||||
# Global ref no
|
||||
N += 1
|
||||
|
||||
Name = Exec = Icon = Ndis = ''
|
||||
Nam1 = Nam2 = Nam3 = ''
|
||||
Cats = []
|
||||
if cats:
|
||||
Cats.append(cats)
|
||||
Type = type
|
||||
|
||||
f = open(file, 'r')
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
# print(line)
|
||||
if len(line) == 0:
|
||||
continue
|
||||
if line.startswith('#'):
|
||||
continue
|
||||
if line.startswith('['):
|
||||
if line != '[Desktop Entry]':
|
||||
D2(f'Break: {line}')
|
||||
break
|
||||
continue
|
||||
|
||||
(tok, val) = line.split('=', 1)
|
||||
|
||||
if tok.startswith('Name'):
|
||||
if tok == 'Name':
|
||||
Name = val
|
||||
elif loc1 and tok == f'Name[{loc1}]':
|
||||
Nam1 = val
|
||||
elif loc2 and tok == f'Name[{loc2}]':
|
||||
Nam2 = val
|
||||
elif loc3 and tok == f'Name[{loc3}]':
|
||||
Nam3 = val
|
||||
|
||||
if Nam1 or Nam2 or Nam3:
|
||||
if Nam1:
|
||||
Name = Nam1
|
||||
elif Nam2:
|
||||
Name = Nam2
|
||||
else:
|
||||
Name = Nam3
|
||||
|
||||
elif tok == 'Exec':
|
||||
Exec = val
|
||||
|
||||
elif tok == 'Icon':
|
||||
Icon = val
|
||||
|
||||
elif tok == 'OnlyShowIn':
|
||||
Type = val.split(';')[0]
|
||||
|
||||
elif tok == 'Categories':
|
||||
if cats:
|
||||
continue
|
||||
for cat in val.split(';'):
|
||||
if cat == 'KDE':
|
||||
Type = 'KDE'
|
||||
continue
|
||||
if cat in CatsRemove:
|
||||
continue
|
||||
if cat.startswith('X-'):
|
||||
continue
|
||||
Cats.append(cat)
|
||||
|
||||
elif tok == 'Type':
|
||||
if val == 'Application':
|
||||
continue
|
||||
Name = ''
|
||||
break
|
||||
|
||||
elif tok == 'NoDisplay':
|
||||
Ndis = val
|
||||
|
||||
f.close()
|
||||
|
||||
if Ndis == 'true' or Name == '' or Exec == '' or len(Cats) == 0:
|
||||
D3('Skipped: %-24s %-4s %-24s %-20s %-20s %s' %
|
||||
(file, Name, Ndis, Exec, Icon, Cats))
|
||||
return
|
||||
|
||||
# Basename
|
||||
File = os.path.basename(file)
|
||||
|
||||
D3('%-24s: %-24s %-20s %-20s %s\n' % (File, Name, Exec, Icon, Cats))
|
||||
|
||||
if not Type:
|
||||
if File.startswith('gnome'):
|
||||
Type = 'GNOME'
|
||||
elif File.startswith('kde'):
|
||||
Type = 'KDE'
|
||||
else:
|
||||
Type = 'Other'
|
||||
|
||||
ndti = f'{Name}-{N}' # Make key unique
|
||||
ndti = ndti.lower() # To lower case (for sorting)
|
||||
# $Exec =~ s/\s*%(f|F|i|k|m|n|N|u|U|v)//g; # Strip unwanted args
|
||||
# $Exec =~ s/\s*-\w+\s*"%c"//g; # Strip option with caption
|
||||
## $Exec =~ s/"%c"/'$Name'/g; # Alternatively - Substitute caption
|
||||
Exec = Exec.split('%', 1)[0].strip() # Strip all args
|
||||
dti = DTI(File, Name, Exec, Icon, Cats, Type)
|
||||
dtis[ndti] = dti
|
||||
|
||||
|
||||
# Process all .desktop files in a directory
|
||||
def ProcessDir(dir, cats, type):
|
||||
global dt_seen
|
||||
|
||||
for name in os.listdir(dir):
|
||||
if not name.endswith('.desktop'):
|
||||
continue
|
||||
if name in dt_seen:
|
||||
D(f'Skip duplicate {name} (in {dir})')
|
||||
continue
|
||||
dt_seen[name] = 1
|
||||
|
||||
file = f'{dir}/{name}'
|
||||
ProcessFile(file, cats, type)
|
||||
|
||||
|
||||
# Process old style GNOME/KDE directories
|
||||
def ProcessOldStyle(type, dirs):
|
||||
for dir in dirs:
|
||||
D(f'Processing directory: {dir}')
|
||||
if not os.path.isdir(dir):
|
||||
D(f'- Not found')
|
||||
confinue
|
||||
for file in os.listdir(dir):
|
||||
dir2 = f'{dir}/{file}'
|
||||
D(f' Subdir: {dir2}')
|
||||
if not os.path.isdir(dir2):
|
||||
continue
|
||||
ProcessDir(dir2, file, type)
|
||||
|
||||
|
||||
# Find that $#@! thing
|
||||
def FindIcon(icon):
|
||||
if not icon:
|
||||
return icon
|
||||
if icon.startswith('/'):
|
||||
if os.path.isfile(icon):
|
||||
return icon
|
||||
return ''
|
||||
|
||||
for dir in IconDirs:
|
||||
file = f'{dir}/{icon}'
|
||||
D2(f'Check icon: {icon} : {file}')
|
||||
if os.path.isfile(file):
|
||||
return file
|
||||
if not FileExt(icon) in ['png', 'xpm', 'svg']:
|
||||
for ext in ['png']:
|
||||
fil2 = f'{file}.{ext}'
|
||||
D2(f'Check icon: {icon} : {fil2}')
|
||||
if os.path.isfile(fil2):
|
||||
return fil2
|
||||
|
||||
for dir in IconDirs2:
|
||||
for sz in IconSizes:
|
||||
sdir = f'{dir}/{sz}'
|
||||
if not os.path.isdir(sdir):
|
||||
continue
|
||||
D2(f'Check icon: {icon} in {sdir}')
|
||||
if icon.startswith('stock'):
|
||||
glob = f'{sdir}/stock/*/{icon}.png'
|
||||
D2(f'Check icon: {icon} in {glob}')
|
||||
# FIXME
|
||||
# $ii = glob("$i");
|
||||
# return $ii if (-f $ii);
|
||||
else:
|
||||
for icat in IconCats:
|
||||
idir = f'{sdir}/{icat}'
|
||||
if not os.path.isdir(idir):
|
||||
continue
|
||||
file = f'{idir}/{icon}'
|
||||
if FileExt(icon) in ['png', 'xpm', 'svg']:
|
||||
D2(f'Check icon: {icon}: {file}')
|
||||
if os.path.isfile(file):
|
||||
return file
|
||||
else:
|
||||
for ext in ['png', 'xpm']:
|
||||
fil2 = f'{file}.{ext}'
|
||||
D2(f'Check icon: {icon}: {fil2}')
|
||||
if os.path.isfile(fil2):
|
||||
return fil2
|
||||
D(f'Icon not found: {icon}')
|
||||
return icon
|
||||
|
||||
|
||||
# Make the menu for a given app type
|
||||
def MakeAppsMenu(type):
|
||||
mdir = f'menus_{type}'
|
||||
dir = f'{EdirMenus}/{mdir}'
|
||||
D(f'Generating menu: {type} in {dir}')
|
||||
MkDir(dir)
|
||||
|
||||
# Sort the apps into categories
|
||||
menus = {}
|
||||
for ndti in sorted(dtis):
|
||||
dti = dtis[ndti]
|
||||
# if dti.type != type: continue
|
||||
cat = dti.cats[0] # First category
|
||||
if cat not in menus:
|
||||
menus[cat] = []
|
||||
menus[cat].append(ndti)
|
||||
|
||||
# Make top- and sub-menus
|
||||
ftop = open(f'{dir}/index.menu', 'w')
|
||||
ftop.write(f'"{type} Menu"\n')
|
||||
for cat in sorted(menus):
|
||||
fsub = open(f'{dir}/{cat}.menu', 'w')
|
||||
D(f'- Submenu: {cat}')
|
||||
ftop.write(f'"{cat}" "" menu "{mdir}/{cat}.menu"\n')
|
||||
fsub.write(f'"{cat}"\n')
|
||||
for ndti in sorted(menus[cat]):
|
||||
dti = dtis[ndti]
|
||||
D2(f' - Item: {ndti}: {dti.file}')
|
||||
icon = FindIcon(dti.icon)
|
||||
fsub.write('"%s" "%s" exec "%s"\n' % (dti.name, icon, dti.exec))
|
||||
fsub.close()
|
||||
ftop.close()
|
||||
|
||||
|
||||
def EeshCall(cmd):
|
||||
# os.system(f'eesh -e "{cmd}" >/dev/null')
|
||||
subprocess.run(["eesh", "-e", cmd], stdout=subprocess.DEVNULL)
|
||||
|
||||
|
||||
# Close all windows named "Message" (we assume they are E dialogs)
|
||||
def EeshCloseMessageWindows():
|
||||
EeshCall('wop Message* close')
|
||||
|
||||
|
||||
##############################################################################
|
||||
# Here we go
|
||||
##############################################################################
|
||||
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'd', ['debug'])
|
||||
for opt, val in opts:
|
||||
if opt in ['-d', '--debug']:
|
||||
dbg += 1
|
||||
|
||||
# Likely prefixes
|
||||
Prefixes = ['/usr/local', '/usr', '/opt']
|
||||
Prefixes += ['/opt/kde', '/opt/kde3', getenv('KDEDIR')]
|
||||
Prefixes += ['/opt/gnome'] # SUSE
|
||||
Prefixes += [getenv('HOME') + '/.local']
|
||||
D(f'Prefixes = "{Prefixes}"')
|
||||
Prefixes = RemoveDuplicates(Prefixes)
|
||||
D(f'Prefixes = "{Prefixes}"')
|
||||
|
||||
SufDirs = ['/share/applications', '/share/applications/kde', '/share/applications/kde4']
|
||||
|
||||
# Where to look for GNOME/KDE stuff
|
||||
AppDirs = MkDirList(Prefixes, SufDirs)
|
||||
|
||||
D(f'AppDirs = "{AppDirs}"')
|
||||
|
||||
IconDirs = MkDirList(Prefixes, ['/share/pixmaps', '/share/icons'])
|
||||
IconDirs2 = MkDirList(Prefixes, ['/share/icons'])
|
||||
Themes = ['default.kde', 'gnome', 'hicolor', 'Adwaita']
|
||||
IconDirs2 = MkDirList(IconDirs2, Themes, sep='/')
|
||||
IconCats = ['apps', 'filesystems', 'actions', 'devices', 'categories', 'places', 'mimetypes']
|
||||
IconSizes = ['48x48', '32x32', '24x24', '16x16']
|
||||
|
||||
D(f'IconDirs = "{IconDirs}"')
|
||||
D(f'IconDirs2 = "{IconDirs2}"')
|
||||
|
||||
# Where to look for GNOME1 apps
|
||||
OldGnomeDirs = MkDirList(Prefixes, ['/share/gnome/apps'])
|
||||
D(f'OldGnomeDirs = "{OldGnomeDirs}"')
|
||||
|
||||
# Where to look for KDE1/2 apps
|
||||
OldKdeDirs = MkDirList(Prefixes, ['/share/applnk'])
|
||||
D(f'OldKdeDirs = "{OldKdeDirs}"')
|
||||
|
||||
# Pick up env vars
|
||||
EdirUser = getenv('ECONFDIR')
|
||||
EdirRoot = getenv('EROOT')
|
||||
EdirBin = getenv('EBIN')
|
||||
|
||||
if EdirUser == '':
|
||||
EdirUser = getenv('HOME') + '/.e16'
|
||||
if EdirRoot == '':
|
||||
EdirRoot = '/usr/share/e16'
|
||||
if EdirBin == '':
|
||||
EdirBin = '/usr/bin'
|
||||
D(f'EdirUser = "{EdirUser}"')
|
||||
D(f'EdirRoot = "{EdirRoot}"')
|
||||
D(f'EdirBin = "{EdirBin}"')
|
||||
|
||||
EdirMenus = EdirUser + '/menus'
|
||||
D(f'EdirMenus = "{EdirMenus}"')
|
||||
|
||||
# Localization bits. There may be better ways to do this.
|
||||
Lang = getenv('LANG')
|
||||
loc1 = Lang
|
||||
loc2 = Lang.split('.')[0].split('@')[0]
|
||||
loc3 = Lang.split('_')[0]
|
||||
if loc1 == loc2:
|
||||
loc1 = ''
|
||||
D(f'Locale = "{Lang}:{loc1}:{loc2}:{loc3}"')
|
||||
|
||||
# Put EBIN first in path
|
||||
os.environ['PATH'] = f"{EdirBin}:{os.environ['PATH']}"
|
||||
|
||||
CatsRemove = [
|
||||
'ConsoleOnly',
|
||||
'Qt',
|
||||
'QT',
|
||||
'GTK',
|
||||
'GNOME',
|
||||
'KDE',
|
||||
'UtilityApplication',
|
||||
'Applications',
|
||||
'Application',
|
||||
#'X-.*',
|
||||
]
|
||||
|
||||
MainMenu = [
|
||||
't:User Menus:',
|
||||
'm:User Application List:user_apps.menu',
|
||||
'm:Applications:menus_apps/index.menu',
|
||||
'm:Epplets:epplets.menu',
|
||||
'c:Restart:exit restart',
|
||||
'c:Log Out:exit logout'
|
||||
]
|
||||
|
||||
UserAppsMenu = [
|
||||
't:User Application List:',
|
||||
'x:Eterm:Eterm',
|
||||
'x:Terminal:Terminal',
|
||||
'x:XTerm:xterm',
|
||||
'x:rxvt:rxvt',
|
||||
'x:urxvt:urxvt',
|
||||
'x:Firefox:firefox',
|
||||
'x:Thunderbird:thunderbird',
|
||||
'x:Seamonkey:seamonkey',
|
||||
'x:Shotwell:shotwell',
|
||||
'x:Pidgin:pidgin',
|
||||
'x:Gmplayer:gmplayer',
|
||||
'x:Xine:xine',
|
||||
'x:The GIMP:gimp',
|
||||
'x:Geeqie:geeqie',
|
||||
'x:XV:xv',
|
||||
'x:XMag:xmag',
|
||||
'x:Grip:grip',
|
||||
'x:Audacious:audacious',
|
||||
'x:XMMS:xmms'
|
||||
]
|
||||
|
||||
EeshCloseMessageWindows()
|
||||
EeshCall('dialog_ok Menus are being generated... Please Wait')
|
||||
|
||||
# Process old style GNOME directories
|
||||
ProcessOldStyle('GNOME', OldGnomeDirs)
|
||||
|
||||
# Process old style KDE directories
|
||||
ProcessOldStyle('KDE', OldKdeDirs)
|
||||
|
||||
# Process new style (GNOME2, KDE2/3) directories
|
||||
for dir in AppDirs:
|
||||
D(f'Processing directory: {dir}')
|
||||
if not os.path.isdir(dir):
|
||||
D(f'- Not found')
|
||||
continue
|
||||
ProcessDir(dir, None, None)
|
||||
|
||||
# Make menu dir and scaled icon dir
|
||||
MkDir(EdirMenus)
|
||||
|
||||
# Make the menus
|
||||
MakeMenu('file.menu', MainMenu)
|
||||
MakeMenu('user_apps.menu', UserAppsMenu)
|
||||
MakeEppsMenu('epplets.menu')
|
||||
MakeAppsMenu('apps')
|
||||
|
||||
EeshCloseMessageWindows()
|
||||
EeshCall('menus reload')
|
||||
EeshCall('dialog_ok Menu generation complete')
|
Loading…
Reference in New Issue