If a service property exists but the window it points to doesn't, then
[rox-lib.git] / python / rox / icon_theme.py
blob449159c74e921d3af226cd8e86e431b16deea2b5
1 """This is an internal module. Do not use it. GTK 2.4 will contain functions
2 that replace those defined here."""
3 from __future__ import generators
5 import os
6 import basedir
7 import rox
9 theme_dirs = [os.path.join(os.environ.get('HOME', '/'), '.icons')] + \
10 list(basedir.load_data_paths('icons'))
12 def _ini_parser(stream):
13 """Yields a sequence of (section, key, value) triples."""
14 section = None
15 for line in stream:
16 line = line.strip()
17 if line.startswith("#") or not line: continue
18 if line.startswith("[") and line.endswith("]"):
19 section = line[1:-1]
20 elif section:
21 key, value = map(str.strip, line.split('=', 1))
22 yield section, key, value
23 else:
24 raise Exception("Error in file '%s': Expected '[SECTION]' but got '%s'" %
25 (stream, line))
27 class Index:
28 """A theme's index.theme file."""
29 def __init__(self, dir):
30 self.dir = dir
31 self.sections = {}
32 for section, key, value in _ini_parser(file(os.path.join(dir, "index.theme"))):
33 try:
34 self.sections[section][key] = value
35 except KeyError:
36 assert section not in self.sections
37 self.sections[section] = {}
38 self.sections[section][key] = value
40 subdirs = self.get('Icon Theme', 'Directories')
42 subdirs = subdirs.replace(';', ',') # Just in case...
44 self.subdirs = [SubDir(self, d) for d in subdirs.split(',')]
46 def get(self, section, key):
47 "None if not found"
48 return self.sections.get(section, {}).get(key, None)
50 class SubDir:
51 """A subdirectory within a theme."""
52 def __init__(self, index, subdir):
53 icontype = index.get(subdir, 'Type')
54 self.name = subdir
55 self.size = int(index.get(subdir, 'Size'))
56 if icontype == "Fixed":
57 self.min_size = self.max_size = self.size
58 elif icontype == "Threshold":
59 threshold = int(index.get(subdir, 'Threshold'))
60 self.min_size = self.size - threshold
61 self.max_size = self.size + threshold
62 elif icontype == "Scaled":
63 self.min_size = int(index.get(subdir, 'MinSize'))
64 self.max_size = int(index.get(subdir, 'MaxSize'))
65 else:
66 self.min_size = self.max_size = 100000
68 class IconTheme:
69 """Icon themes are located by searching through various directories. You can use an IconTheme
70 to convert an icon name into a suitable image."""
72 def __init__(self, name):
73 """name = icon theme to load"""
74 self.name = name
76 def lookup_icon(self, iconname, size, flags=0):
77 """return path to required icon at specified size"""
78 pass
80 def load_icon(self, iconname, size, flags=0):
81 """return gdk_pixbuf of icon"""
82 pass
84 class IconThemeROX(IconTheme):
85 """Icon themes are located by searching through various directories. You can use an IconTheme
86 to convert an icon name into a suitable image. This implementation is for PyGTK 2.0 or 2.2"""
88 def __init__(self, name):
89 if not name:
90 name='ROX'
92 IconTheme.__init__(self, name)
94 self.indexes = []
95 for leaf in theme_dirs:
96 theme_dir = os.path.join(leaf, name)
97 index_file = os.path.join(theme_dir, 'index.theme')
98 if os.path.exists(os.path.join(index_file)):
99 try:
100 self.indexes.append(Index(theme_dir))
101 except:
102 rox.report_exception()
104 def lookup_icon(self, iconname, size, flags=0):
105 icon = self._lookup_this_theme(iconname, size)
106 if icon: return icon
107 # XXX: inherits
109 def _lookup_this_theme(self, iconname, size):
110 dirs = []
111 for i in self.indexes:
112 for d in i.subdirs:
113 if size < d.min_size:
114 diff = d.min_size - size
115 elif size > d.max_size:
116 diff = size - d.max_size
117 else:
118 diff = 0
119 dirs.append((diff, os.path.join(i.dir, d.name)))
121 # Sort by closeness of size
122 dirs.sort()
124 for _, subdir in dirs:
125 for extension in ("png", "svg"):
126 filename = os.path.join(subdir,
127 iconname + '.' + extension)
128 if os.path.exists(filename):
129 return filename
130 return None
132 def load_icon(self, iconname, size, flags=0):
133 path=self.lookup_icon(iconname, size, flags)
134 if path:
135 if hasattr(rox.g.gdk, 'pixbuf_new_from_file_at_size'):
136 return rox.g.gdk.pixbuf_new_from_file_at_size(path, size, size)
137 else:
138 return rox.g.gdk.pixbuf_new_from_file(path)
139 return None
141 class IconThemeGTK(IconTheme):
142 """Icon themes are located by searching through various directories. You can use an IconTheme
143 to convert an icon name into a suitable image. This implementation is for PyGTK 2.4 or later"""
145 def __init__(self, name):
146 IconTheme.__init__(self, name)
148 if not name:
149 self.gtk_theme=rox.g.icon_theme_get_default()
150 else:
151 self.gtk_theme=rox.g.IconTheme()
152 self.gtk_theme.set_custom_theme(name)
155 def lookup_icon(self, iconname, size, flags=0):
156 info=self.gtk_theme.lookup_icon(iconname, size, flags)
157 if info:
158 path=info.get_filename()
159 #if rox.g.pygtk_version[0]==2 and rox.g.pygtk_version[1]<4:
160 # info.free()
161 return path
162 return None
164 def load_icon(self, iconname, size, flags=0):
165 return self.gtk_theme.load_icon(iconname, size, flags)
167 def get_theme(name=None):
168 try:
169 theme=IconThemeGTK(name)
170 except:
171 theme=IconThemeROX(name)
173 return theme
175 rox_theme = get_theme('ROX')
176 try:
177 from rox import options
178 ogrp=options.OptionGroup('ROX-Filer', 'Options', 'rox.sourceforge.net')
179 theme_name = options.Option('icon_theme', 'ROX', ogrp)
180 ogrp.notify(warn_unused=False)
181 users_theme = get_theme(theme_name.value)
182 except:
183 users_theme = rox_theme