1import os
2import logging
3from functools import lru_cache
4
5import gi
6gi.require_version('GLib', '2.0')
7gi.require_version('Gtk', '3.0')
8gi.require_version('Gio', '2.0')
9gi.require_version('GdkPixbuf', '2.0')
10
11# pylint: disable=wrong-import-position
12from gi.repository import Gtk, Gio, GLib, GdkPixbuf
13from ulauncher.config import get_data_file
14
15
16icon_theme = Gtk.IconTheme.get_default()
17logger = logging.getLogger(__name__)
18
19
20@lru_cache(maxsize=50)
21def load_image(path, size):
22    """
23    :param str path:
24    :param int size:
25
26    :rtype: :class:`GtkPixbuf` or :code:`None`
27    :returns: None if :func:`new_from_file_at_size` raises error
28    """
29    path = os.path.expanduser(path)
30    # pylint: disable=broad-except
31    try:
32        return GdkPixbuf.Pixbuf.new_from_file_at_size(path, size, size)
33    except Exception as e:
34        logger.warning('Could not load image %s. E: %s', path, e)
35
36
37def get_app_icon_pixbuf(icon, icon_size, icon_name):
38    """
39    :param Gio.Icon icon:
40    :param int icon_size:
41    :param str icon_name:
42    :rtype: :class:`GtkPixbuf`
43    """
44    pixbuf_icon = None
45    # pylint: disable=broad-except
46
47    if isinstance(icon, Gio.ThemedIcon):
48        try:
49            icon_name = icon.get_names()[0]
50            if not icon_name:
51                return None
52            pixbuf_icon = get_themed_icon_by_name(icon_name, icon_size)
53        except Exception as e:
54            logger.info('Could not load icon for %s. E: %s', icon_name, e)
55
56    elif isinstance(icon, Gio.FileIcon):
57        pixbuf_icon = load_image(icon.get_file().get_path(), icon_size)
58
59    elif isinstance(icon, str):
60        pixbuf_icon = load_image(icon, icon_size)
61
62    if not pixbuf_icon:
63        pixbuf_icon = load_image(get_data_file('media', 'executable-icon.png'), icon_size)
64
65    return pixbuf_icon
66
67
68def get_themed_icon_by_name(icon_name, icon_size):
69    return icon_theme.load_icon(icon_name, icon_size, Gtk.IconLookupFlags.FORCE_SIZE)
70
71
72ULAUNCHER_FILE_ICON_DB = ['3g2', '3gp', 'ai', 'air', 'asf', 'avi', 'bib', 'cls', 'csv', 'deb', 'djvu', 'dmg', 'doc',
73                          'docx', 'dwf', 'dwg', 'eps', 'epub', 'exe', 'f77', 'f90', 'f', 'flac', 'flv', 'gif', 'gz',
74                          'ico', 'indd', 'iso', 'jpeg', 'jpg', 'log', 'm4a', 'm4v', 'midi', 'mkv', 'mov', 'mp3', 'mp4',
75                          'mpeg', 'mpg', 'msi', 'odp', 'ods', 'odt', 'oga', 'ogg', 'ogv', 'pdf', 'png', 'pps', 'ppsx',
76                          'ppt', 'pptx', 'psd', 'pub', 'py', 'qt', 'ra', 'ram', 'rar', 'rm', 'rpm', 'rtf', 'rv', 'skp',
77                          'spx', 'sql', 'sty', 'tar', 'tex', 'tgz', 'tiff', 'ttf', 'txt', 'vob', 'wav', 'wmv', 'xls',
78                          'xlsx', 'xml', 'xpi', 'zip']
79
80SPECIAL_DIRS = {
81    GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOWNLOAD): 'folder-download',
82    GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOCUMENTS): 'folder-documents',
83    GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_MUSIC): 'folder-music',
84    GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES): 'folder-pictures',
85    GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PUBLIC_SHARE): 'folder-publicshare',
86    GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_TEMPLATES): 'folder-templates',
87    GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_VIDEOS): 'folder-videos',
88    GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP): 'user-desktop',
89    os.path.expanduser('~'): 'folder-home'
90}
91
92FREEDESKTOP_STANDARD = {
93    'html': 'text-html'
94}
95
96
97def get_file_icon(path, icon_size):
98    """
99    :param ~ulauncher.utils.Path.Path path:
100    :param int icon_size:
101    """
102    # pylint: disable=broad-except
103    try:
104        if path.is_dir():
105            special_dir = SPECIAL_DIRS.get(str(path))
106            if special_dir:
107                return get_themed_icon_by_name(special_dir, icon_size)
108            return get_themed_icon_by_name('folder', icon_size)
109
110        ext = path.get_ext()
111        if ext in ULAUNCHER_FILE_ICON_DB:
112            return load_image(get_data_file('media', 'fileicons', '%s.png' % ext), icon_size)
113
114        freedesktop = FREEDESKTOP_STANDARD.get(ext)
115        if freedesktop:
116            return get_themed_icon_by_name(freedesktop, icon_size)
117
118        if path.is_exe():
119            return load_image(get_data_file('media', 'executable-icon.png'), icon_size)
120    except Exception as e:
121        logger.warning('Icon not found %s. %s: %s', path, type(e).__name__, e)
122
123    return load_image(get_data_file('media', 'unknown-file-icon.png'), icon_size)
124