aboutsummaryrefslogblamecommitdiffstats
path: root/src/plugins/application.py
blob: 6af72278fd4803a80b965fe7f8378ac63a565dc6 (plain) (tree)


















































































































































                                                                                                                    
# -*- python -*-
'''
xpybar – xmobar replacement written in python
Copyright © 2014, 2015  Mattias Andrée (maandree@member.fsf.org)

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