#!/usr/bin/env python import gtk import gobject import os import pango import subprocess import libxml2 from os.path import exists # Font Manager # (C) 2008 Karl Pickett # License: GPLv3 # for future I18n def _(str): return unicode(str) # To install ourselves, we add an include line in the # user font config file (default ~/.fonts.conf) USER_FONT_CONF = "~/.fonts.conf" USER_FONT_CONF_BACKUP = "~/.fonts.conf.fontmanager.save" VERSION = "0.5" PRODUCT_TITLE = _("Font Manager %s") % VERSION FM_DIR = "~/.fontmanager" FM_BLOCK_CONF = os.path.join(FM_DIR, "fontmanager.conf") FM_BLOCK_CONF_TMP = FM_BLOCK_CONF + ".tmp" FM_GROUP_CONF = os.path.join(FM_DIR, "groups.xml") FC_INCLUDE_LINE = "%s" % \ FM_BLOCK_CONF TEST_TEXT = _("The Hungry Penguin Ate A Big Fish") TEST_TEXT += _("\nABCDEFGHIJKLMNOPQRSTUVWXYZ") TEST_TEXT += _("\n1234567890") TEST_TEXT += _("\nabcdefghijklmnopqrstuvwxyz") DEFAULT_CUSTOM_TEXT = _("Enter Your Text Here") SCALABLE_SIZES = (200, 150, 100, 72, 48, 36, 24, 18, 14, 12, 10) # What style gets shown first DEFAULT_STYLES = ["Regular", "Roman", "Medium", "Normal", "Book"] UI_XML = """ """ # Some globals # Names of system font families as reported by fc-list g_system_families = {} # map of family to list of filenames g_font_files = {} # map of namily name to Family object g_fonts = {} class Pattern(object): __slots__ = ("family", "style") def __init__(self): self.family = self.style = None class Collection (object): __slots__ = ("name", "fonts", "builtin", "enabled") def __init__(self, name): self.name = name self.fonts = [] self.builtin = True self.enabled = True def get_label(self): if self.enabled: return on(self.name) else: return off(self.name) def obj_exists(self, obj): for f in self.fonts: if f is obj: return True return False def add(self, obj): # check duplicate reference if self.obj_exists(obj): return self.fonts.append(obj) def get_text(self): return self.name def num_fonts_enabled(self): ret = 0 for f in self.fonts: if f.enabled: ret += 1 return ret def set_enabled(self, enabled): for f in self.fonts: f.enabled = enabled def set_enabled_from_fonts(self): self.enabled = (self.num_fonts_enabled() > 0) def remove(self, font): self.fonts.remove(font) class Family(object): __slots__ = ("family", "user", "enabled", "pango_family") def __init__(self, family): self.family = family self.user = False self.enabled = True self.pango_family = None def get_label(self): if self.enabled: return on(self.family) else: return off(self.family) def cmp_family(lhs, rhs): return cmp(lhs.family, rhs.family) # XML Helpers def add_patelt_node(parent, type, val): pi = parent.newChild(None, "patelt", None) pi.setProp("name", type) str = pi.newChild(None, "string", val) def get_fontconfig_patterns(node, patterns): for n in node.xpathEval('pattern'): p = Pattern() for c in n.xpathEval('patelt'): name = c.prop("name") if name == "family": p.family = c.xpathEval('string')[0].content if p.family: patterns.append(p) def gtk_markup_escape(str): str = str.replace("&", "&") str = str.replace("<", "<") str = str.replace(">", ">") return str def on(str): str = gtk_markup_escape(str) return "%s" % str def off(str): str = gtk_markup_escape(str) return "%s Off" % str # Font loading def strip_fontconfig_family(family): # remove alt name n = family.find(',') if n > 0: family = family[:n] family = family.replace("\\-", "-") family = family.strip() return family def load_fontconfig_files(): cmd = "fc-list : file family" for l in os.popen(cmd).readlines(): l = l.strip() if l.find(":") < 0: continue file, family = l.split(":") family = strip_fontconfig_family(family) list = g_font_files.get(family, None) if not list: list = [] g_font_files[family] = list list.append(file) def load_fontconfig_system_families(): cmd = "HOME= fc-list : family" print "Executing %s..." % cmd for l in os.popen(cmd).readlines(): l = l.strip() family = strip_fontconfig_family(l) g_system_families[family] = 1 def load_fonts(widget): ctx = widget.get_pango_context() families = ctx.list_families() for f in families: obj = Family(f.get_name()) obj.pango_family = f if not g_system_families.has_key(f.get_name()): obj.user = True g_fonts[f.get_name()] = obj def find_font(family): return g_fonts.get(family, None) # Blacklist Code def save_blacklist(): doc = libxml2.newDoc("1.0") root = doc.newChild(None, "fontconfig", None) n = root.newChild(None, "selectfont", None) n = n.newChild(None, "rejectfont", None) for font in g_fonts.itervalues(): if not font.enabled: p = n.newChild(None, "pattern", None) add_patelt_node(p, "family", font.family) print "Writing to %s" % FM_BLOCK_CONF doc.saveFormatFile(FM_BLOCK_CONF, format=1) def load_blacklist(filename): if not exists(filename): return patterns = [] doc = libxml2.parseFile(filename) rejects = doc.xpathEval('//rejectfont') for a in rejects: get_fontconfig_patterns(a, patterns) doc.freeDoc() for p in patterns: set_blacklist(p) def set_blacklist(pattern): font = find_font(pattern.family) if font: font.enabled = False def enable_blacklist(): if exists(FM_BLOCK_CONF_TMP): if exists(FM_BLOCK_CONF): os.unlink(FM_BLOCK_CONF) os.rename(FM_BLOCK_CONF_TMP, FM_BLOCK_CONF) def disable_blacklist(): if exists(FM_BLOCK_CONF): if exists(FM_BLOCK_CONF_TMP): os.unlink(FM_BLOCK_CONF_TMP) os.rename(FM_BLOCK_CONF, FM_BLOCK_CONF_TMP) def get_filenames(family): ret = [] try: pipe = subprocess.Popen(["fc-list", family, "file"], stdout=subprocess.PIPE).stdout for line in pipe: ret.append(line.split(':')[0].strip()) except Exception, e: print e return ret # Details dialog def get_font_details_text(family): filenames = g_font_files.get(family, None) str = "%s\n\n" % family if not filenames: str += "No Files Found" else: for f in filenames: st = os.stat(f) str += "%s %d KB\n" % (f, st.st_size / 1024) return str # # Gui Code # class FontBook(gtk.Window): def __init__(self, parent=None): gtk.Window.__init__(self) self.connect('destroy', lambda *w: self.action_quit(None)) self.uimanager = gtk.UIManager() accelgroup = self.uimanager.get_accel_group() self.add_accel_group(accelgroup) self.create_actions() vb = gtk.VBox(False, 0) vb.pack_start(self.menu_bar, False, False, 0) self.DRAG_TARGETS = [("test", gtk.TARGET_SAME_APP, 0)] self.DRAG_ACTIONS = gtk.gdk.ACTION_LINK self.set_title(PRODUCT_TITLE) self.set_default_size(700, 450) #self.set_border_width(8) hbox = gtk.HBox(False, 3) hbox.set_homogeneous(False) w = self.init_collections() hbox.pack_start(w, False) w = self.init_families() hbox.pack_start(w, False) w = self.init_text_view() hbox.pack_start(w) self.copy_buffer = [] self.font_tags = [] self.custom_text = DEFAULT_CUSTOM_TEXT self.preview_mode = 0 load_fontconfig_system_families() load_fontconfig_files() load_fonts(self) load_blacklist(FM_BLOCK_CONF_TMP) vb.pack_start(hbox) self.add(vb) self.create_collections() #self.show_collection(self.collections[0]) self.collection_tv.get_selection().select_path(0) self.family_tv.get_selection().select_path(0) self.show_all() def init_collections(self): sw = gtk.ScrolledWindow() sw.set_shadow_type(gtk.SHADOW_ETCHED_IN) sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_PYOBJECT, gobject.TYPE_STRING) treeview = gtk.TreeView(model) treeview.set_search_column(2) treeview.get_selection().connect("changed", self.collection_changed) #dnd treeview.connect("drag-data-received", self.drag_data_received) treeview.enable_model_drag_dest(self.DRAG_TARGETS, self.DRAG_ACTIONS) treeview.connect("row-activated", self.collection_activated) treeview.set_row_separator_func(self.is_row_separator_collection) r = gtk.CellRendererText() column = gtk.TreeViewColumn(_('Collection'), r, markup=0) #column.set_sort_column_id(0) treeview.append_column(column) self.collection_tv = treeview sw.add(treeview) return sw def init_families(self): sw = gtk.ScrolledWindow() sw.set_shadow_type(gtk.SHADOW_ETCHED_IN) sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_PYOBJECT, gobject.TYPE_STRING) treeview = gtk.TreeView(model) treeview.set_search_column(2) treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE) treeview.get_selection().connect("changed", self.font_changed) treeview.connect("row-activated", self.font_activated) # dnd #treeview.connect("drag-data-get", self.drag_data_get) treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, self.DRAG_TARGETS, self.DRAG_ACTIONS) column = gtk.TreeViewColumn(_('Font'), gtk.CellRendererText(), markup=0) column.set_sort_column_id(2) treeview.append_column(column) self.family_tv = treeview sw.add(treeview) return sw def init_text_view(self): #self.notebook = gtk.Notebook() view = gtk.TextView() sw = gtk.ScrolledWindow() sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.text_view = view self.text_view.set_left_margin(8) self.text_view.set_right_margin(8) self.text_view.set_wrap_mode(gtk.WRAP_WORD_CHAR) sw.add(view) #self.font_label = gtk.Label(_("Preview")) self.style_combo = gtk.combo_box_new_text() self.size_combo = gtk.combo_box_new_text() vb = gtk.VBox() hb = gtk.HBox() vb.pack_start(hb, False) vb.pack_start(sw) #hb.pack_start(self.font_label, False) hb.pack_end(self.style_combo, False) hb.pack_end(self.size_combo, False) self.set_scalable_sizes() self.style_combo.connect("changed", self.style_changed) self.size_combo.connect("changed", self.size_changed) return vb def create_actions(self): g = gtk.ActionGroup('global') add_action(g, "File", None, "_File", None) add_action(g, 'Collection', None, "_Collection", None) add_action(g, 'Font', None, "Font", None) add_action(g, 'View', None, "_View", None) add_action(g, 'Help', None, "_Help", None) add_action(g, 'Quit', gtk.STOCK_QUIT, None, self.action_quit) add_action(g, 'Save', gtk.STOCK_SAVE, None, self.action_save) add_action(g, 'NewCollection', gtk.STOCK_NEW, "_New Collection", self.action_new_collection) add_action(g, 'About', gtk.STOCK_ABOUT, None, self.action_about) self.uimanager.insert_action_group(g, 0) # view g.add_radio_actions([ ('ViewSample', None, "_Sample Text", "1", None, 0), ('ViewCustom', None, "_Custom Text", "2", None, 1), ('ViewDetails', None, "_Font Information", "3", None, 2), ], 0, self.preview_mode_changed) # any collection selected g = gtk.ActionGroup('collection_selected') g.set_sensitive(False) add_action(g, 'TurnOnCollection', None, "_Enable Collection", self.action_turn_on_collection) add_action(g, 'TurnOffCollection', None, "_Disable Collection", self.action_turn_off_collection) self.uimanager.insert_action_group(g, 0) self.ag_collection_selected = g # user collection selected g = gtk.ActionGroup('user-collection_selected') g.set_sensitive(False) add_action(g, 'DeleteCollection', None, "Delete Collection", self.action_delete_collection, "d") add_action(g, 'RenameCollection', None, "Rename Collection", self.action_rename_collection, "r") self.uimanager.insert_action_group(g, 0) self.ag_user_collection_selected = g g = gtk.ActionGroup('ag-paste') g.set_sensitive(False) add_action(g, 'Paste', gtk.STOCK_PASTE, None, self.action_paste) self.ag_paste = g self.uimanager.insert_action_group(g, 0) g = gtk.ActionGroup('ag-cut') g.set_sensitive(False) add_action(g, 'Cut', gtk.STOCK_CUT, None, self.action_cut) add_action(g, 'Remove', gtk.STOCK_DELETE, "Remove", self.action_remove) self.ag_cut = g self.uimanager.insert_action_group(g, 0) # font selected g = gtk.ActionGroup('font_selected') g.set_sensitive(False) add_action(g, 'TurnOn', None, "_Enable Font(s)", self.action_turn_on) add_action(g, 'TurnOff', None, "_Disable Font(s)", self.action_turn_off) add_action(g, 'Copy', gtk.STOCK_COPY, None, self.action_copy) self.ag_font_selected = g self.uimanager.insert_action_group(g, 0) self.uimanager.add_ui_from_string(UI_XML) self.menu_bar = self.uimanager.get_widget('/MenuBar') # # Actions # def action_save(self, a): self.save_config() def action_quit(self, a): self.save_config() gtk.main_quit() def collection_name_exists(self, name): for c in self.collections: if c.name == name: return True return False def action_new_collection(self, a): str = _("New Collection") while True: str = self.get_new_collection_name(str) if not str: return if not self.collection_name_exists(str): break c = Collection(str) c.builtin = False self.add_collection(c) def action_delete_collection(self, a): c = self.get_current_collection() self.ag_paste.set_sensitive(False) self.ag_collection_selected.set_sensitive(False) self.collections.remove(c) self.update_views() def action_rename_collection(self, a): c = self.get_current_collection() str = c.name while True: str = self.get_new_collection_name(str) if not str or c.name == str: return if not self.collection_name_exists(str): c.name = str self.update_collection_view() return def action_about(self, a): d = gtk.AboutDialog() d.set_name(PRODUCT_TITLE) d.set_copyright("2008 Karl Pickett/penguindev") d.set_license("GPL3") d.set_website("http://fontmanager.blogspot.com/") d.run() d.destroy() def action_turn_on_collection(self, a): self.enable_collection(True) def action_turn_off_collection(self, a): self.enable_collection(False) def collection_activated(self, tv, path, col): c = self.get_current_collection() self.enable_collection(not c.enabled) def enable_collection(self, enabled): c = self.get_current_collection() if c.builtin and not self.confirm_enable_collection(enabled): return c.set_enabled(enabled) self.update_views() def confirm_enable_collection(self, enabled): d = gtk.Dialog(_("Confirm Action"), self, gtk.DIALOG_MODAL, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)) d.set_default_response(gtk.RESPONSE_CANCEL) c = self.get_current_collection() if enabled: str = _("Are you sure you want to enable the \"%s\" built in collection?") % c.name else: str = _("Are you sure you want to disable the \"%s\" built in collection?") % c.name text = gtk.Label() text.set_text(str) d.vbox.pack_start(text, padding=10) text.show() ret = d.run() d.destroy() return (ret == gtk.RESPONSE_OK) def is_row_separator_collection(self, model, iter): obj = model.get(iter, 1)[0] #print "is_row_separator_collection", obj, iter return (obj is None) # Cut and paste def action_remove(self, a): c = self.get_current_collection() for f in self.iter_selected_fonts(): c.remove(f) self.update_views() def action_cut(self, a): self.do_copy(True) def action_copy(self, a): self.do_copy(False) def action_paste(self, a): c = self.get_current_collection() for f in self.copy_buffer: if not c.obj_exists(f): c.add(f) self.add_font_to_view(f) self.update_views() def do_copy(self, cut): c = self.get_current_collection() self.copy_buffer = [] for f in self.iter_selected_fonts(): self.copy_buffer.append(f) if cut: c.remove(f) self.update_views() if not c.builtin: self.ag_paste.set_sensitive(True) def iter_selected_fonts(self): sel = self.family_tv.get_selection() m, path_list = sel.get_selected_rows() for p in path_list: obj = m[p][1] yield obj def action_turn_on(self, a): for f in self.iter_selected_fonts(): f.enabled = True self.update_views() def action_turn_off(self, a): for f in self.iter_selected_fonts(): f.enabled = False self.update_views() def font_activated(self, tv, path, col): for f in self.iter_selected_fonts(): f.enabled = (not f.enabled) self.update_views() # # View Updating # def update_views(self): self.update_collection_view() self.update_font_view() def update_collection_view(self): for c in self.collections: c.set_enabled_from_fonts() model = self.collection_tv.get_model() iter = model.get_iter_first() while iter: label, obj = model.get(iter, 0, 1) if not obj: iter = model.iter_next(iter) continue if obj in self.collections: new_label = obj.get_label() if label != new_label: model.set(iter, 0, new_label) iter = model.iter_next(iter) else: if not model.remove(iter): return def update_font_view(self): c = self.get_current_collection() model = self.family_tv.get_model() iter = model.get_iter_first() while iter: label, obj = model.get(iter, 0, 1) if obj in c.fonts: new_label = obj.get_label() if label != new_label: model.set(iter, 0, new_label) iter = model.iter_next(iter) else: if not model.remove(iter): return def preview_mode_changed(self, a, b): if self.preview_mode == 1: self.custom_text = self.get_current_text() self.preview_mode = a.get_current_value() combos_visible = (self.preview_mode != 2) self.size_combo.set_property("visible", combos_visible) self.style_combo.set_property("visible", combos_visible) self.set_preview_text(self.current_descr, False) def get_current_text(self): print "get_current_text" b = self.text_view.get_buffer() return b.get_text(b.get_start_iter(), b.get_end_iter()) def get_current_collection(self): sel = self.collection_tv.get_selection() m, iter = sel.get_selected() if not iter: return return m.get(iter, 1)[0] def collection_changed(self, sel): c = self.get_current_collection() if c: print "collection_changed", c.name self.ag_user_collection_selected.set_sensitive(not c.builtin) self.ag_collection_selected.set_sensitive(True) if c.builtin: self.ag_paste.set_sensitive(False) elif self.copy_buffer: self.ag_paste.set_sensitive(True) self.show_collection(c) else: self.ag_user_collection_selected.set_sensitive(False) self.ag_collection_selected.set_sensitive(False) self.show_collection(None) def font_changed(self, sel): tv = self.family_tv m, path_list = tv.get_selection().get_selected_rows() rows = len(path_list) if rows == 0: self.ag_font_selected.set_sensitive(False) self.ag_cut.set_sensitive(False) return if not self.get_current_collection().builtin: self.ag_cut.set_sensitive(True) self.ag_font_selected.set_sensitive(True) if rows > 1: return obj = m[path_list[0]][1] if isinstance(obj, Family): #print "family changed", f.family self.change_font(obj) def get_new_collection_name(self, old_name): d = gtk.Dialog(_("Enter Collection Name"), self, gtk.DIALOG_MODAL, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)) d.set_default_response(gtk.RESPONSE_OK) text = gtk.Entry() if old_name: text.set_text(old_name) text.set_property("activates-default", True) d.vbox.pack_start(text) text.show() ret = d.run() d.destroy() if ret == gtk.RESPONSE_OK: return text.get_text().strip() return None # DND Stuff def drag_data_received(self, treeview, context, x, y, selection, info, timestamp): #print "drag_data_received" drop_info = treeview.get_dest_row_at_pos(x, y) #print drop_info if drop_info: model = treeview.get_model() path, position = drop_info collection = model[path][1] collection.add(self.get_dragged_font()) self.update_views() # GTK only supports dragging a single row? :( def get_dragged_font(self): for f in self.iter_selected_fonts(): return f def save_config(self): if not is_installed(): install() save_blacklist() self.save_collection() def save_collection(self): doc = libxml2.newDoc("1.0") root = doc.newChild(None, "fontmanager", None) for c in self.collections: if c.builtin: continue cn = root.newChild(None, "fontcollection", None) cn.setProp("name", c.name) for f in c.fonts: p = cn.newChild(None, "pattern", None) add_patelt_node(p, "family", f.family) doc.saveFormatFile(FM_GROUP_CONF, format=1) def create_collections(self): self.collections = [] c = Collection(_("All Fonts")) for f in sorted(g_fonts.itervalues(), Family.cmp_family): c.fonts.append(f) self.add_collection(c) c = Collection(_("System")) for f in sorted(g_fonts.itervalues(), Family.cmp_family): if not f.user: c.fonts.append(f) self.add_collection(c) c = Collection(_("User")) for f in sorted(g_fonts.itervalues(), Family.cmp_family): if f.user: c.fonts.append(f) self.add_collection(c) # add separator - hack lstore = self.collection_tv.get_model() iter = lstore.append() lstore.set(iter, 1, None) self.load_user_collections() def add_collection(self, c): c.set_enabled_from_fonts() lstore = self.collection_tv.get_model() iter = lstore.append() lstore.set(iter, 0, c.get_label()) lstore.set(iter, 1, c) lstore.set(iter, 2, c.get_text()) self.collections.append(c) def load_user_collections(self): if not exists(FM_GROUP_CONF): return doc = libxml2.parseFile(FM_GROUP_CONF) nodes = doc.xpathEval('//fontcollection') for a in nodes: patterns = [] name = a.prop("name") get_fontconfig_patterns(a, patterns) c = Collection(name) c.builtin = False for p in patterns: font = find_font(p.family) if font: c.fonts.append(font) self.add_collection(c) print "Loaded user collection %s" % name doc.freeDoc() def size_changed(self, combo): if combo.get_active() < 0: return self.change_font(self.current_font) def style_changed(self, combo): if combo.get_active() < 0: return style = combo.get_model()[combo.get_active()][0] faces = self.current_font.pango_family.list_faces() for face in faces: if face.get_face_name() == style: descr = face.describe() self.set_preview_text(descr) return def change_font(self, font): self.current_font = font self.style_combo.get_model().clear() faces = font.pango_family.list_faces() selected_face = None active = -1 i = 0 for face in faces: name = face.get_face_name() self.style_combo.append_text(name) if name in DEFAULT_STYLES or not selected_face: selected_face = face active = i i += 1 self.style_combo.set_active(active) self.set_preview_text(selected_face.describe()) def get_current_size(self): i = self.size_combo.get_active() if i < 0: return 14 model = self.size_combo.get_model() str = model[i][0] return int(str) def set_scalable_sizes(self): for size in SCALABLE_SIZES: self.size_combo.append_text(str(size)) self.size_combo.set_active(6) def set_preview_text(self, descr, update_custom=True): if update_custom and self.preview_mode == 1: self.custom_text = self.get_current_text() self.text_view.set_editable(self.preview_mode == 1) b = self.text_view.get_buffer() b.set_text("", 0) for tag in self.font_tags: b.get_tag_table().remove(tag) self.font_tags = [] # create font if self.preview_mode == 2: size = 14 tag = b.create_tag(None, size_points=size) else: size = self.get_current_size() tag = b.create_tag(None, font_desc=descr, size_points=size) self.font_tags.append(tag) if self.preview_mode == 0: b.insert_with_tags(b.get_end_iter(), descr.to_string() + "\n", tag) b.insert_with_tags(b.get_end_iter(), TEST_TEXT + "\n", tag) elif self.preview_mode == 1: b.insert_with_tags(b.get_end_iter(), self.custom_text, tag) else: text = get_font_details_text(self.current_font.family) b.insert_with_tags(b.get_end_iter(), text, tag) self.current_descr = descr def show_collection(self, c): lstore = self.family_tv.get_model() lstore.clear() if not c: return for f in c.fonts: self.add_font_to_view(f) def add_font_to_view(self, f): lstore = self.family_tv.get_model() iter = lstore.append(None) lstore.set(iter, 0, f.get_label()) lstore.set(iter, 1, f) lstore.set(iter, 2, f.family) def add_action(g, action, stock, label, cb, accel=None): g.add_actions([(action, stock, label, accel, None, cb)]) def is_installed(): if not exists(USER_FONT_CONF): print "User conf file %s does not exist" % USER_FONT_CONF return False for l in open(USER_FONT_CONF): if l.strip() == FC_INCLUDE_LINE: print "Include exists in %s" % USER_FONT_CONF return True print "Include does not exist in %s" % USER_FONT_CONF return False # put an include into ~/.fonts.conf def install(): if not exists(USER_FONT_CONF): print "Making empty user conf file %s" % USER_FONT_CONF f = open(USER_FONT_CONF, "w") f.write("\n\n") f.close() tmpname = USER_FONT_CONF + ".fontmanager.tmp" print "Starting install, adding %s to %s" % (FC_INCLUDE_LINE, USER_FONT_CONF) print "Backup will be saved as %s" % USER_FONT_CONF_BACKUP tmp = open(tmpname, "w") for l in open(USER_FONT_CONF): if l.strip() == "": tmp.write(FC_INCLUDE_LINE + "\n") tmp.write(l) print "Saving backup %s" % USER_FONT_CONF_BACKUP os.rename(USER_FONT_CONF, USER_FONT_CONF_BACKUP) print "Overwriting %s" % USER_FONT_CONF os.rename(tmpname, USER_FONT_CONF) def update_home(path): return path.replace("~", os.getenv("HOME")) def main(): if not exists(FM_DIR): print "Creating %s" % (FM_DIR) os.mkdir(FM_DIR) print "Disabling blacklist temporarily..." disable_blacklist() f = FontBook() print "Reenabling blacklist" enable_blacklist() gtk.main() if __name__ == '__main__': FM_DIR = update_home(FM_DIR) FM_BLOCK_CONF = update_home(FM_BLOCK_CONF) FM_BLOCK_CONF_TMP = update_home(FM_BLOCK_CONF_TMP) FM_GROUP_CONF = update_home(FM_GROUP_CONF) USER_FONT_CONF = update_home(USER_FONT_CONF) USER_FONT_CONF_BACKUP = update_home(USER_FONT_CONF_BACKUP) main()