aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/application.py
blob: 59280cfaf5f0a19eb3f1e2c200ba5dee60e85eb2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# -*- python -*-
'''
xpybar – xmobar replacement written in python
Copyright © 2014, 2015, 2016, 2017, 2018, 2019  Mattias Andrée (maandree@kth.se)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
'''


class Application:
    '''
    Applications and .desktop files
    
    @variable  desktop_file:str                                 The .desktop file for the application
    @variable  settings:dict<str?, dict<str, dict<str?, str>>>  Section → key → locale → value map of settings
    '''
    
    
    def __init__(self, file):
        '''
        Constructor
        
        @param  file:str  The .desktop file if it contains '/', otherwise the name of the application
        '''
        import os
        if '/' not in file:
            import pwd
            directories = []
            home = pwd.getpwuid(os.getuid()).pw_dir
            directories.append('%s/.local/share/applications' % home)
            if 'HOME' in os.environ:
                if not os.environ['HOME'] == home:
                    home = os.environ['HOME']
                    directories.append('%s/.local/share/applications' % home)
            directories += ['/usr/local/share/applications', '/usr/share/applications', '/share/applications']
            directories = [d for d in directories if os.path.exists(d) and os.path.isdir(d)]
            
            file = ['%s/%s.desktop' % (d, file) for d in directories]
            file = [f for f in file if os.path.exists(f) and os.path.isfile(f)]
            if len(file) == 0:
                raise Exception('Application not found')
            file = file[0]
        
        self.desktop_file = file
        with open(self.desktop_file, 'rb') as file:
            data = file.read()
        data = [l for l in data.decode('utf-8', 'replace').replace('\r', '\n').split('\n') if not l == '']
        
        section = None
        self.settings = {}
        for line in data:
            line = line.strip()
            if line.startswith('[') and line.endswith(']'):
                section = line[1 : -1]
            elif line.startswith(';') or line.startswith('#'):
                pass
            elif (':' in line) or ('=' in line):
                line_e = line.split('=')
                line_c = line.split(':')
                if len(line_e[0]) < len(line_c[0]):
                    first = '='
                    line = line_e
                else:
                    first = ':'
                    line = line_c
                key, value = line[0].rstrip(), first.join(line[1:]).lstrip()
                locale = None
                if ('[' in key) and key.endswith(']'):
                    key = key[:-1].split('[')
                    key, locale = '['.join(key[:-1]), key[-1]
                if section not in self.settings:
                    self.settings[section] = {}
                section_map = self.settings[section]
                if key not in section_map:
                    section_map[key] = {}
                key_map = section_map[key]
                if locale not in key_map:
                    key_map[locale] = value
        
        self.locales = [None]
        if 'LANG' in os.environ:
            locale = os.environ['LANG']
        elif 'LOCALE' in os.environ:
            locale = os.environ['LOCALE']
        else:
            return
        locale = locale.split(' ')[0].split('.')[0].split('_')
        for i in range(len(locale)):
            self.locales.append('_'.join(locale[:i]))
        self.locales.reverse()
    
    
    def get_setting(self, key, section = 'Desktop Entry', locales = None):
        '''
        Read a setting in the application's .desktop file
        
        @param  key:str             The key
        @param  section:str?        The section where the key is located
        @param  locale:list<str?>?  Acceptable locales in order of preference,
                                    `None` to use the default for your locale
        '''
        map = self.settings
        if section not in map:
            return None
        map = map[section]
        if key not in map:
            return None
        map = map[key]
        if locales is None:
            locales = self.locales
        for locale in locales:
            if locale in map:
                return map[locale]
        return None
    
    
    @staticmethod
    def strip_placeholders(text):
        '''
        Remove placeholders form an exec string
        
        @param   text:str  The exec string with placeholders
        @return  :str      The exec string without placeholders
        '''
        buf, esc = '', False
        for c in text:
            if esc:
                esc = False
                if c == '%':
                    buf += c
            elif c == '%':
                esc = True
            else:
                buf += c
        return buf