Package list lightdm-gtk-greeter-settings / e870f8b1-f074-4c9e-b83e-c3008bb558d4/main lightdm_gtk_greeter_settings /

Tree @e870f8b1-f074-4c9e-b83e-c3008bb558d4/main (Download .tar.gz) @e870f8b1-f074-4c9e-b83e-c3008bb558d4/mainraw · history · blame

#!/usr/bin/env python3
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
#   LightDM GTK Greeter Settings
#   Copyright (C) 2014 Andrew P. <>
#   This program is free software: you can redistribute it and/or modify it
#   under the terms of the GNU General Public License version 3, as published
#   by the Free Software Foundation.
#   This program is distributed in the hope that it will be useful, but
#   WITHOUT ANY WARRANTY; without even the implied warranties of
#   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 <>.

import configparser
import glob
import locale
import os
import pwd
import stat

from collections import (
from itertools import (
from locale import gettext as _

from gi.repository import (

__license__ = 'GPL-3'
__version__ = 'dev'
__data_directory__ = '../data/'
__config_path__ = 'lightdm/lightdm-gtk-greeter.conf'

    from . installation_config import (
except ImportError:

__all__ = [

def C_(context, message):
    separator = '\x04'
    message_with_context = '{}{}{}'.format(context, separator, message)
    result = locale.gettext(message_with_context)
    if separator in result:
        return message
    return result

def NC_(context, message):
    return message

def get_data_path(*parts):
    return os.path.abspath(os.path.join(os.path.dirname(__file__),
                                        __data_directory__, *parts))

def get_config_path():
    return os.path.abspath(__config_path__)

def get_version():
    return __version__

def get_greeter_version():
        return get_greeter_version._version
    except AttributeError:
            get_greeter_version._version = int(os.getenv('GTK_GREETER_VERSION', '0x010900'), 16)
        except ValueError:
            get_greeter_version._version = 0x010900

    return get_greeter_version._version

def bool2string(value, skip_none=False):
    if isinstance(value, str):
        value = string2bool(value)
    return 'true' if value else 'false' if not skip_none or value is not None else None

def string2bool(value, fallback=False):
    if isinstance(value, str):
        if value in ('true', 'yes', '1'):
            return True
        if value in ('false', 'no', '0'):
            return False
    return fallback

def show_message(**kwargs):
    dialog = Gtk.MessageDialog(parent=Gtk.Window.list_toplevels()[0],
                               buttons=Gtk.ButtonsType.CLOSE, **kwargs)

def pixbuf_from_file_scaled_down(path, width, height):
    pixbuf = GdkPixbuf.Pixbuf.new_from_file(path)
    scale = max(pixbuf.props.width / width, pixbuf.props.height / height)

    if scale > 1:
        return GdkPixbuf.Pixbuf.scale_simple(pixbuf,
                                             pixbuf.props.width / scale,
                                             pixbuf.props.height / scale,
    return pixbuf

def set_image_from_path(image, path):
    if not path or not os.path.isfile(path):
        image.props.icon_name = 'unknown'
            width, height = image.get_size_request()
            if -1 in (width, height):
                width, height = 64, 64
            pixbuf = pixbuf_from_file_scaled_down(path, width, height)
            return True
        except GLib.Error:
            image.props.icon_name = 'file-broken'
    return False

def check_path_accessibility(path, file=True, executable=False):
    """Return None  if file is readable by greeter and error message otherwise"""

    # LP: #1709864, Support gtk-3.* themes
    if "gtk-3.*" in path:
        for x in range(0, 40):
            if os.path.exists(path.replace("gtk-3.*", "gtk-3.%i" % x)):
                path = path.replace("gtk-3.*", "gtk-3.%i" % x)
                return check_path_accessibility(path, file, executable)

    if not os.path.exists(path):
        return _('File not found: {path}').format(path=path)

        uid, gids = check_path_accessibility.id_cached_data
    except AttributeError:
        files = glob.glob('/etc/lightdm/lightdm.d/*.conf')
        files += ['/etc/lightdm/lightdm.conf']
        config = configparser.RawConfigParser(strict=False)
        username = config.get('LightDM', 'greeter-user', fallback='lightdm')

        pw = pwd.getpwnam(username)
        uid = pw.pw_uid
        gids = set(os.getgrouplist(username, pw.pw_gid))
        check_path_accessibility.id_cached_data = uid, gids

    parts = os.path.normpath(path).split(os.path.sep)
    if not parts[0]:
        parts[0] = os.path.sep

    def check(p):
            st = os.stat(p)
        except OSError as e:
            return _('Failed to check permissions: {error}'.format(error=e.strerror))

        if stat.S_ISDIR(st.st_mode) and not stat.S_IREAD:
            return _('Directory is not readable: {path}'.format(path=p))
        if st.st_uid == uid:
            return not (st.st_mode & stat.S_IRUSR) and \
                _('LightDM does not have permissions to read path: {path}'.format(path=p))
        if st.st_gid in gids:
            return not (st.st_mode & stat.S_IRGRP) and \
                _('LightDM does not have permissions to read path: {path}'.format(path=p))
        return not (st.st_mode & stat.S_IROTH) and \
            _('LightDM does not have permissions to read path: {path}'.format(path=p))

    errors = (check(p) for p in accumulate(parts, os.path.join))
    error = next((error for error in errors if error), None)

    if not error and file and not os.path.isfile(path):
        return _('Path is not a regular file: {path}'.format(path=path))

    if not error and executable:
        st = os.stat(path)
        if st.st_uid == uid:
            if not st.st_mode & stat.S_IXUSR:
                return _('LightDM does not have permissions to execute file: {path}'
        elif st.st_gid in gids:
            if not st.st_mode & stat.S_IXGRP:
                return _('LightDM does not have permissions to execute file: {path}'
        elif not st.st_mode & stat.S_IXOTH:
            return _('LightDM does not have permissions to execute file: {path}'.format(path=path))

    return error

def get_markup_error(markup):
        Pango.parse_markup(markup, -1, '\0')
    except GLib.Error as e:
        return e.message
    return None

def clamp(v, a, b):
    if v < a:
        return a
    if v > b:
        return b
    return v

class DefaultValueDict(defaultdict):

    def __init__(self, *items, default=None, factory=None, source=None):
        super().__init__(None, source or items)
        self._value = default
        self._factory = factory

    def __missing__(self, key):
        return self._factory(key) if self._factory else self._value

class SimpleEnumMeta(type):

    def __prepare__(mcs, *args, **kwargs):
        return OrderedDict()

    def __new__(self, cls, bases, classdict):
        obj = super().__new__(self, cls, bases, classdict)
        obj._dict = OrderedDict((k, v)
                                for k, v in classdict.items() if obj._accept_member_(k, v))
        obj._tuple_type = namedtuple(obj.__class__.__name__ + 'Tuple', obj._dict.keys())
        keys = list(obj._dict.keys())
        for i in range(len(keys)):
            if obj._dict[keys[i]] is ():
                v = 0 if i == 0 else obj._dict[keys[i - 1]] + 1
                setattr(obj, keys[i], v)
                obj._dict[keys[i]] = v
        return obj

    def __contains__(self, value):
        return value in self._dict.values()

    def __iter__(self):
        return iter(self._dict.values())

    def _make(self, *args, **kwargs):
        return self._tuple_type._make(self._imake(*args, **kwargs))

    def _imake(self, *args, **kwargs):
        if args:
            return args
        elif kwargs:
            return (kwargs.get(k, v) for k, v in self._dict.items())
            return self._dict.values()

class SimpleEnum(metaclass=SimpleEnumMeta):
    _dict = None

    def __init__(self, *args, **kwargs):
        if kwargs:
            self.__dict__.update((k, args[i]) for i, k in enumerate(self._dict))

    def __iter__(self):
        return (self.__dict__[k] for k in self._dict)

    def __repr__(self):
        return repr(tuple((k, self.__dict__[k]) for k in self._dict))

    def _accept_member_(cls, name, value):
        return not name.startswith('_') and not name.endswith('_')

class WidgetsEnum(SimpleEnum):

    def __init__(self, wrapper=None, builder=None):
        getter = wrapper.__getitem__ if wrapper else builder.get_object
        for k, v in self._dict.items():
            if isinstance(v, type) and issubclass(v, WidgetsEnum):
                self.__dict__[k] = v(WidgetsWrapper(wrapper or builder, k))
                self.__dict__[k] = getter(v or k)

class WidgetsWrapper:
    _builder = None
    _prefixes = None

    def __init__(self, source, *prefixes):
        if source is None:
        if isinstance(source, Gtk.Builder):
            self._builder = source
            self._prefixes = tuple(prefixes)
        elif isinstance(source, WidgetsWrapper):
            self._builder = source._builder
            self._prefixes = source._prefixes + tuple(prefixes)
            raise TypeError(source)

    def __getitem__(self, args):
        if not self._builder:
            return None
        if not isinstance(args, tuple):
            args = (args,)
        return self._builder.get_object('_'.join(chain(self._prefixes, args)))

    def path(self):
        return '_'.join(self._prefixes) if self._prefixes else ''

class TreeStoreDataWrapper(GObject.Object):

    def __init__(self, data):
        super().__init__() = data

class SimpleDictWrapper:

    def __init__(self, getter=None, setter=None, add=None, deleter=None, itergetter=None):
        self._getter = getter
        self._setter = setter
        self._deleter = deleter
        self._itergetter = itergetter
        self._add = add

    def __getitem__(self, key):
        return self._getter(key)

    def __setitem__(self, key, value):
        return self._setter(key, value)

    def __delitem__(self, key):
        return self._deleter(key)

    def __iter__(self):
        return self._itergetter()

    def add(self, value):
        return self._add(value)