diff --git a/apps/SOURCES b/apps/SOURCES
index 6b72d6a..443b42f 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -105,9 +105,6 @@ gui/viewport.c
 gui/skin_engine/skin_backdrops.c
 gui/skin_engine/skin_display.c
 gui/skin_engine/skin_engine.c
-#ifdef HAVE_LCD_BITMAP
-gui/skin_engine/skin_fonts.c
-#endif
 gui/skin_engine/skin_parser.c
 gui/skin_engine/skin_render.c
 gui/skin_engine/skin_tokens.c
diff --git a/apps/filetree.c b/apps/filetree.c
index 35bb2a8..59e7343 100644
--- a/apps/filetree.c
+++ b/apps/filetree.c
@@ -404,27 +404,31 @@ int ft_load(struct tree_context* c, const char* tempdir)
 #ifdef HAVE_LCD_BITMAP
 static void ft_load_font(char *file)
 {
+    int current_font_id;
+    enum screen_type screen = SCREEN_MAIN;
 #if NB_SCREENS > 1
     MENUITEM_STRINGLIST(menu, ID2P(LANG_CUSTOM_FONT), NULL, 
                         ID2P(LANG_MAIN_SCREEN), ID2P(LANG_REMOTE_SCREEN))
     switch (do_menu(&menu, NULL, NULL, false))
     {
-        case 0: /* main lcd */        
-            splash(0, ID2P(LANG_WAIT));
-            font_load(NULL, file);
+        case 0: /* main lcd */
+            screen = SCREEN_MAIN;
             set_file(file, (char *)global_settings.font_file, MAX_FILENAME);
             break;
         case 1: /* remote */
-            splash(0, ID2P(LANG_WAIT));
-            font_load_remoteui(file);
+            screen = SCREEN_REMOTE;
             set_file(file, (char *)global_settings.remote_font_file, MAX_FILENAME);
             break;
     }
 #else
-    splash(0, ID2P(LANG_WAIT));
-    font_load(NULL, file);
     set_file(file, (char *)global_settings.font_file, MAX_FILENAME);
 #endif
+    splash(0, ID2P(LANG_WAIT));
+    current_font_id = global_status.font_id[screen];
+    if (current_font_id >= 0)
+        font_unload(current_font_id);
+    global_status.font_id[screen] = font_load(file);
+    viewportmanager_theme_changed(THEME_UI_VIEWPORT);
 }    
 #endif
 
diff --git a/apps/gui/skin_engine/skin_engine.c b/apps/gui/skin_engine/skin_engine.c
index 7a9a10e..069c346 100644
--- a/apps/gui/skin_engine/skin_engine.c
+++ b/apps/gui/skin_engine/skin_engine.c
@@ -107,9 +107,9 @@ void settings_apply_skins(void)
 {
     int i, j;
 
-    for (i=0; i<SKINNABLE_SCREENS_COUNT; i++)
+    for(j=0; j<SKINNABLE_SCREENS_COUNT; j++)
     {
-        FOR_NB_SCREENS(j)
+        FOR_NB_SCREENS(i)
             skin_data_free_buflib_allocs(&skins[j][i].data);
     }
 
@@ -117,7 +117,6 @@ void settings_apply_skins(void)
     
 #ifdef HAVE_LCD_BITMAP
     skin_backdrop_init();
-    skin_font_init();
 #endif
     gui_sync_skin_init();
 
diff --git a/apps/gui/skin_engine/skin_engine.h b/apps/gui/skin_engine/skin_engine.h
index c8104f9..310411b 100644
--- a/apps/gui/skin_engine/skin_engine.h
+++ b/apps/gui/skin_engine/skin_engine.h
@@ -25,7 +25,6 @@
 
 #ifndef PLUGIN
 
-#include "skin_fonts.h"
 #include "tag_table.h"
 
 #include "wps_internals.h" /* TODO: remove this line.. shoudlnt be needed */
@@ -44,8 +43,7 @@ enum skinnable_screens {
 
 #ifdef HAVE_LCD_BITMAP
 
-#define SKIN_BUFFER_SIZE (2048 + SKIN_FONT_SIZE) + \
-                         (WPS_MAX_TOKENS * \
+#define SKIN_BUFFER_SIZE (WPS_MAX_TOKENS * \
                          (sizeof(struct wps_token) + (sizeof(struct skin_element))))
 #endif
 
diff --git a/apps/gui/skin_engine/skin_fonts.c b/apps/gui/skin_engine/skin_fonts.c
deleted file mode 100644
index a89b762..0000000
--- a/apps/gui/skin_engine/skin_fonts.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * Copyright (C) 2010 Jonathan Gordon
- *
- * 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 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-
-#include "config.h"
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "file.h"
-#include "settings.h"
-#include "font.h"
-#include "skin_buffer.h"
-#include "skin_fonts.h"
-
-static struct skin_font_info {
-    struct font font;
-    int font_id;
-    char name[MAX_PATH];
-    char *buffer;
-    int ref_count; /* how many times has this font been loaded? */
-} font_table[MAXUSERFONTS];
-
-/* need this to know if we should be closing font fd's on the next init */
-static bool first_load = true;
-
-void skin_font_init(void)
-{
-    int i;
-    for(i=0;i<MAXUSERFONTS;i++)
-    {
-        if (!first_load)
-            font_unload(font_table[i].font_id);
-        font_table[i].font_id = -1;
-        font_table[i].name[0] = '\0';
-        font_table[i].buffer = NULL;
-        font_table[i].ref_count = 0;
-    }
-    first_load = false;
-}
-
-/* load a font into the skin buffer. return the font id. */
-int skin_font_load(char* font_name, int glyphs)
-{
-    int i;
-    int skin_font_size = 0;
-    struct font *pf;
-    struct skin_font_info *font = NULL;
-    char filename[MAX_PATH];
-    
-    if (!strcmp(font_name, global_settings.font_file))
-        return FONT_UI;
-#ifdef HAVE_REMOTE_LCD
-    if (!strcmp(font_name, global_settings.remote_font_file))
-        return FONT_UI_REMOTE;
-#endif
-    snprintf(filename, MAX_PATH, FONT_DIR "/%s.fnt", font_name);
-    
-    for(i=0;i<MAXUSERFONTS;i++)
-    {
-        if (font_table[i].font_id >= 0 && !strcmp(font_table[i].name, filename))
-        {
-            font_table[i].ref_count++;
-            return font_table[i].font_id;
-        }
-        else if (!font && font_table[i].font_id == -1)
-        {
-            font = &font_table[i];
-            strcpy(font_table[i].name, filename);
-        }
-    }
-    if (!font)
-        return -1; /* too many fonts loaded */
-    
-    pf = &font->font;
-    if (!font->buffer)
-    {
-        if (!glyphs) 
-            glyphs = GLYPHS_TO_CACHE;
-#ifndef __PCTOOL__
-        skin_font_size = font_glyphs_to_bufsize(filename, glyphs);
-#else
-        skin_font_size = 1;
-#endif
-        if ( !skin_font_size )
-            return -1;
-        pf->buffer_start = (char*)skin_buffer_alloc(skin_font_size);
-        if (!pf->buffer_start)
-            return -1;
-        font->buffer = pf->buffer_start;
-        pf->buffer_size = skin_font_size;
-    }
-    else
-    {
-        pf->buffer_start = font->buffer;
-    }
-    
-    pf->fd = -1;
-    font->font_id = font_load(pf, filename);
-    
-    if (font->font_id < 0)
-        return -1;
-    font->ref_count = 1;
-    
-    return font->font_id;
-}
-/* unload a skin font. If a font has been loaded more than once it wont actually
- * be unloaded untill all references have been unloaded */
-void skin_font_unload(int font_id)
-{
-    int i;
-    for(i=0;i<MAXUSERFONTS;i++)
-    {
-        if (font_table[i].font_id == font_id)
-        {
-            if (--font_table[i].ref_count == 0)
-            {
-                font_unload(font_id);
-                font_table[i].font_id = -1;
-                font_table[i].name[0] = '\0';
-            }
-            return;
-        }
-    }
-}
diff --git a/apps/gui/skin_engine/skin_fonts.h b/apps/gui/skin_engine/skin_fonts.h
deleted file mode 100644
index 698ed4f..0000000
--- a/apps/gui/skin_engine/skin_fonts.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * Copyright (C) 2010 Jonathan Gordon
- *
- * 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 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-
-#include "config.h"
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "file.h"
-#include "settings.h"
-#include "font.h"
-
-#ifndef _SKINFONTS_H_
-#define _SKINFONTS_H_
-
-#if LCD_HEIGHT > 160
-#define SKIN_FONT_SIZE (1024*10)
-#else
-#define SKIN_FONT_SIZE (1024*3)
-#endif
-#define GLYPHS_TO_CACHE 256
-
-void skin_font_init(void);
-
-/* load a font into the skin buffer. return the font id. 
- * reserve room for glyphs glyphs */
-int skin_font_load(char* font_name, int glyphs);
-
-/* unload a skin font. If a font has been loaded more than once it wont actually
- * be unloaded untill all references have been unloaded */
-void skin_font_unload(int font_id);
-#endif
diff --git a/apps/gui/skin_engine/skin_parser.c b/apps/gui/skin_engine/skin_parser.c
index 9c73c3e..8c87553 100644
--- a/apps/gui/skin_engine/skin_parser.c
+++ b/apps/gui/skin_engine/skin_parser.c
@@ -62,7 +62,6 @@
 #include "radio.h"
 #include "tuner.h"
 #endif
-#include "skin_fonts.h"
 
 #ifdef HAVE_LCD_BITMAP
 #include "bmp.h"
@@ -77,6 +76,12 @@
 
 #define WPS_ERROR_INVALID_PARAM         -1
 
+#if LCD_HEIGHT > 160
+#define SKIN_FONT_SIZE (1024*10)
+#else
+#define SKIN_FONT_SIZE (1024*3)
+#endif
+#define GLYPHS_TO_CACHE 256
 
 static bool isdefault(struct skin_tag_parameter *param)
 {
@@ -415,8 +420,13 @@ static int parse_font_load(struct skin_element *element,
         glyphs = element->params[2].data.number;
     else
         glyphs = GLYPHS_TO_CACHE;
+    if (id < 2)
+    {
+        DEBUGF("font id must be >= 2\n");
+        return 1;
+    }
 #if defined(DEBUG) || defined(SIMULATOR)
-    if (skinfonts[id-FONT_FIRSTUSERFONT].name != NULL)
+    if (skinfonts[id-2].name != NULL)
     {
         DEBUGF("font id %d already being used\n", id);
     }
@@ -426,9 +436,9 @@ static int parse_font_load(struct skin_element *element,
     ptr = strchr(filename, '.');
     if (!ptr || strncmp(ptr, ".fnt", 4))
         return WPS_ERROR_INVALID_PARAM;
-    skinfonts[id-FONT_FIRSTUSERFONT].id = -1;
-    skinfonts[id-FONT_FIRSTUSERFONT].name = filename;
-    skinfonts[id-FONT_FIRSTUSERFONT].glyphs = glyphs;
+    skinfonts[id-2].id = -1;
+    skinfonts[id-2].name = filename;
+    skinfonts[id-2].glyphs = glyphs;
 
     return 0;
 }
@@ -1442,6 +1452,11 @@ void skin_data_free_buflib_allocs(struct wps_data *wps_data)
             core_free(img->buflib_handle);
         list = list->next;
     }
+    if (wps_data->font_ids != NULL)
+    {
+        while (wps_data->font_count > 0)
+            font_unload(wps_data->font_ids[--wps_data->font_count]);
+    }
 #endif
 #endif
 }
@@ -1617,6 +1632,8 @@ static bool load_skin_bitmaps(struct wps_data *wps_data, char *bmpdir)
 static bool skin_load_fonts(struct wps_data *data)
 {
     /* don't spit out after the first failue to aid debugging */
+    int id_array[MAXUSERFONTS];
+    int font_count = 0;
     bool success = true;
     struct skin_element *vp_list;
     int font_id;
@@ -1628,19 +1645,20 @@ static bool skin_load_fonts(struct wps_data *data)
                 (struct skin_viewport*)vp_list->data;
         struct viewport *vp = &skin_vp->vp;
 
-
-        if (vp->font <= FONT_UI)
+        font_id = skin_vp->parsed_fontid;
+        if (font_id == 1)
         {   /* the usual case -> built-in fonts */
-#ifdef HAVE_REMOTE_LCD
-            if (vp->font == FONT_UI)
-                vp->font += curr_screen;
-#endif
+            vp->font = global_status.font_id[curr_screen];
+            continue;
+        }
+        else if (font_id <= 0)
+        {
+            vp->font = FONT_SYSFIXED;
             continue;
         }
-        font_id = vp->font;
 
         /* now find the corresponding skin_font */
-        struct skin_font *font = &skinfonts[font_id-FONT_FIRSTUSERFONT];
+        struct skin_font *font = &skinfonts[font_id-2];
         if (!font->name)
         {
             if (success)
@@ -1655,10 +1673,12 @@ static bool skin_load_fonts(struct wps_data *data)
          * multiple viewports use the same */
         if (font->id < 0)
         {
-            char *dot = strchr(font->name, '.');
-            *dot = '\0';
-            font->id = skin_font_load(font->name,
-                       skinfonts[font_id-FONT_FIRSTUSERFONT].glyphs);
+            char path[MAX_PATH];
+            snprintf(path, sizeof path, FONT_DIR "/%s", font->name);
+            font->id = font_load(path/*,
+                       skinfonts[font_id-FONT_FIRSTUSERFONT].glyphs*/);
+            //printf("[%d] %s -> %d\n",font_id, font->name, font->id);
+            id_array[font_count++] = font->id;
         }
 
         if (font->id < 0)
@@ -1667,13 +1687,24 @@ static bool skin_load_fonts(struct wps_data *data)
                     font_id, font->name);
             font->name = NULL; /* to stop trying to load it again if we fail */
             success = false;
-            font->name = NULL;
             continue;
         }
 
         /* finally, assign the font_id to the viewport */
         vp->font = font->id;
     }
+    if (success)
+    {
+        data->font_ids = skin_buffer_alloc(font_count * sizeof(int));
+        if (data->font_ids == NULL)
+        {
+            while (font_count > 0)
+                font_unload(id_array[--font_count]);
+            return false;
+        }
+        memcpy(data->font_ids, id_array, sizeof(int)*font_count);
+        data->font_count = font_count;
+    }
     return success;
 }
 
@@ -1690,17 +1721,12 @@ static int convert_viewport(struct wps_data *data, struct skin_element* element)
     skin_vp->hidden_flags = 0;
     skin_vp->label = NULL;
     skin_vp->is_infovp = false;
+    skin_vp->parsed_fontid = 1;
     element->data = skin_vp;
     curr_vp = skin_vp;
     curr_viewport_element = element;
     
     viewport_set_defaults(&skin_vp->vp, curr_screen);
-#ifdef HAVE_REMOTE_LCD
-    /* viewport_set_defaults() sets the font to FONT_UI+curr_screen.
-     * This parser requires font 1 to always be the UI font, 
-     * so force it back to FONT_UI and handle the screen number at the end */
-    skin_vp->vp.font = FONT_UI;
-#endif
     
 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
     skin_vp->start_fgcolour = skin_vp->vp.fg_pattern;
@@ -1788,9 +1814,7 @@ static int convert_viewport(struct wps_data *data, struct skin_element* element)
 #ifdef HAVE_LCD_BITMAP
     /* font */
     if (!isdefault(param))
-    {
-        skin_vp->vp.font = param->data.number;
-    }
+        skin_vp->parsed_fontid = param->data.number;
 #endif
     if ((unsigned) skin_vp->vp.x >= (unsigned) display->lcdwidth ||
         skin_vp->vp.width + skin_vp->vp.x > display->lcdwidth ||
diff --git a/apps/gui/skin_engine/skin_render.c b/apps/gui/skin_engine/skin_render.c
index 994ca23..5a64be1 100644
--- a/apps/gui/skin_engine/skin_render.c
+++ b/apps/gui/skin_engine/skin_render.c
@@ -31,6 +31,7 @@
 #ifdef HAVE_ALBUMART
 #include "albumart.h"
 #endif
+#include "settings.h"
 #include "skin_display.h"
 #include "skin_engine.h"
 #include "skin_parser.h"
@@ -650,6 +651,10 @@ void skin_render_viewport(struct skin_element* viewport, struct gui_wps *gwps,
         img->display = -1;
         imglist = imglist->next;
     }
+
+    /* fix font ID's */
+    if (skin_viewport->parsed_fontid == 1)
+        skin_viewport->vp.font = global_status.font_id[display->screen_type];
 #endif
     
     while (line)
diff --git a/apps/gui/skin_engine/wps_internals.h b/apps/gui/skin_engine/wps_internals.h
index 244d085..c16191c 100644
--- a/apps/gui/skin_engine/wps_internals.h
+++ b/apps/gui/skin_engine/wps_internals.h
@@ -182,6 +182,7 @@ struct skin_viewport {
     char hidden_flags;
     bool is_infovp;
     char* label;
+    int   parsed_fontid;
 #if LCD_DEPTH > 1
     unsigned start_fgcolour;
     unsigned start_bgcolour;
@@ -325,6 +326,8 @@ struct wps_data
     struct skin_element *tree;
 #ifdef HAVE_LCD_BITMAP
     struct skin_token_list *images;
+    int *font_ids;
+    int font_count;
 #endif
 #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
     struct {
diff --git a/apps/gui/statusbar-skinned.c b/apps/gui/statusbar-skinned.c
index 3f914bd..ad9a391 100644
--- a/apps/gui/statusbar-skinned.c
+++ b/apps/gui/statusbar-skinned.c
@@ -125,6 +125,10 @@ struct viewport *sb_skin_get_info_vp(enum screen_type screen)
         viewportmanager_theme_undo(screen, true);
     }
     vp = skin_find_item(infovp_label[screen], SKIN_FIND_UIVP, data);
+    if (!vp)
+        return NULL;
+    if (vp->parsed_fontid == 1)
+        vp->vp.font = global_status.font_id[screen];
     return &vp->vp;
 }
 
diff --git a/apps/gui/usb_screen.c b/apps/gui/usb_screen.c
index 66b7094..2b33550 100644
--- a/apps/gui/usb_screen.c
+++ b/apps/gui/usb_screen.c
@@ -41,7 +41,6 @@
 
 #ifdef HAVE_LCD_BITMAP
 #include "bitmaps/usblogo.h"
-#include "skin_engine/skin_fonts.h"
 #endif
 
 #ifdef HAVE_REMOTE_LCD
@@ -265,11 +264,9 @@ void gui_usb_screen_run(bool early_usb)
     {
         /* The font system leaves the .fnt fd's open, so we need for force close them all */
 #ifdef HAVE_LCD_BITMAP
-        font_reset(NULL);
-#ifdef HAVE_REMOTE_LCD
-        font_load_remoteui(NULL);
-#endif
-        skin_font_init(); /* unload all the skin fonts */
+        FOR_NB_SCREENS(i)
+            font_unload(global_status.font_id[i]);
+    // FIXME    skin_font_init(); /* unload all the skin fonts */
 #endif
     }
 
diff --git a/apps/gui/viewport.c b/apps/gui/viewport.c
index 34ebbf9..df8093d 100644
--- a/apps/gui/viewport.c
+++ b/apps/gui/viewport.c
@@ -272,13 +272,10 @@ void viewportmanager_theme_changed(const int which)
         screens[SCREEN_MAIN].has_buttonbar = global_settings.buttonbar;
     }
 #endif
-    if (which & THEME_UI_VIEWPORT)
-    {
-    }
     if (which & THEME_LANGUAGE)
     {
     }
-    if (which & THEME_STATUSBAR)
+    if (which & (THEME_STATUSBAR|THEME_UI_VIEWPORT))
     {
         FOR_NB_SCREENS(i)
         {
@@ -324,7 +321,7 @@ void viewport_set_fullscreen(struct viewport *vp,
 #ifndef __PCTOOL__
     set_default_align_flags(vp);
 #endif
-    vp->font = FONT_UI + screen; /* default to UI to discourage SYSFONT use */
+    vp->font = global_status.font_id[screen];
     vp->drawmode = DRMODE_SOLID;
 #if LCD_DEPTH > 1
 #ifdef HAVE_REMOTE_LCD
diff --git a/apps/main.c b/apps/main.c
index 07a8bba..babd575 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -336,6 +336,7 @@ static void init_tagcache(void)
 
 static void init(void)
 {
+    int i;
     system_init();
     core_allocator_init();
     kernel_init();
@@ -347,6 +348,8 @@ static void init(void)
 #ifdef HAVE_REMOTE_LCD
     lcd_remote_init();
 #endif
+    FOR_NB_SCREENS(i)
+        global_status.font_id[i] = FONT_SYSFIXED;
     font_init();
     show_logo();
     button_init();
@@ -451,6 +454,8 @@ static void init(void)
 #ifdef HAVE_REMOTE_LCD
     lcd_remote_init();
 #endif
+    FOR_NB_SCREENS(rc)
+        global_status.font_id[rc] = FONT_SYSFIXED;
     font_init();
 
     CHART(">show_logo");
diff --git a/apps/plugin.c b/apps/plugin.c
index 2517a71..7c75a43 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -174,7 +174,7 @@ static const struct plugin_api rockbox_api = {
     lcd_update_rect,
     lcd_set_drawmode,
     lcd_get_drawmode,
-    lcd_setfont,
+    screen_helper_setfont,
     lcd_drawpixel,
     lcd_drawline,
     lcd_hline,
@@ -230,6 +230,7 @@ static const struct plugin_api rockbox_api = {
 #endif
     font_get_bits,
     font_load,
+    font_unload,
     font_get,
     font_getstringsize,
     font_get_width,
@@ -905,7 +906,7 @@ int plugin_load(const char* plugin, const void* parameter)
 #endif
 
 #ifdef HAVE_LCD_BITMAP
-    lcd_setfont(FONT_UI);
+    screen_helper_setfont(FONT_UI);
 #if LCD_DEPTH > 1
 #ifdef HAVE_LCD_COLOR
     lcd_set_drawinfo(DRMODE_SOLID, global_settings.fg_color,
diff --git a/apps/plugin.h b/apps/plugin.h
index a33089b..e0ee951 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -272,7 +272,8 @@ struct plugin_api {
     bool (*is_diacritic)(const unsigned short char_code, bool *is_rtl);
 #endif
     const unsigned char *(*font_get_bits)( struct font *pf, unsigned short char_code );
-    int (*font_load)(struct font*, const char *path);
+    int (*font_load)(const char *path);
+    void (*font_unload)(int font_id);
     struct font* (*font_get)(int font);
     int  (*font_getstringsize)(const unsigned char *str, int *w, int *h,
                                int fontnumber);
diff --git a/apps/plugins/beatbox/beatbox.c b/apps/plugins/beatbox/beatbox.c
index b09464a..8ecbabd 100644
--- a/apps/plugins/beatbox/beatbox.c
+++ b/apps/plugins/beatbox/beatbox.c
@@ -265,7 +265,7 @@ enum plugin_status plugin_start(const void* parameter)
 {
     int retval = 0;
 
-    rb->lcd_setfont(0);
+    rb->lcd_setfont(FONT_SYSFIXED);
 
 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
     rb->cpu_boost(true);
diff --git a/apps/plugins/doom/rockdoom.c b/apps/plugins/doom/rockdoom.c
index 1c2777a..85e3225 100644
--- a/apps/plugins/doom/rockdoom.c
+++ b/apps/plugins/doom/rockdoom.c
@@ -667,7 +667,7 @@ enum plugin_status plugin_start(const void* parameter)
    rb->cpu_boost(true);
 #endif
 
-   rb->lcd_setfont(0);
+   rb->lcd_setfont(FONT_SYSFIXED);
 
    // We're using doom's memory management since it implements a proper free (and re-uses the memory)
    // and now with prboom's code: realloc and calloc
@@ -712,7 +712,7 @@ enum plugin_status plugin_start(const void* parameter)
 
    Dhandle_ver( namemap[ result ] );
 
-   rb->lcd_setfont(0);
+   rb->lcd_setfont(FONT_SYSFIXED);
 
    rb->lcd_clear_display();
 
diff --git a/apps/plugins/lua/rocklib.c b/apps/plugins/lua/rocklib.c
index 4657201..ddd4081 100644
--- a/apps/plugins/lua/rocklib.c
+++ b/apps/plugins/lua/rocklib.c
@@ -433,6 +433,11 @@ RB_WRAP(font_getstringsize)
     int fontnumber = luaL_checkint(L, 2);
     int w, h;
 
+    if (fontnumber == FONT_UI)
+        fontnumber = rb->global_status->font_id[SCREEN_MAIN];
+    else
+        fontnumber = FONT_SYSFIXED;
+
     int result = rb->font_getstringsize(str, &w, &h, fontnumber);
     lua_pushinteger(L, result);
     lua_pushinteger(L, w);
diff --git a/apps/plugins/midi/midiplay.c b/apps/plugins/midi/midiplay.c
index 9bf4d50..16d153a 100644
--- a/apps/plugins/midi/midiplay.c
+++ b/apps/plugins/midi/midiplay.c
@@ -470,7 +470,7 @@ enum plugin_status plugin_start(const void* parameter)
         rb->splash(HZ*2, " Play .MID file ");
         return PLUGIN_OK;
     }
-    rb->lcd_setfont(0);
+    rb->lcd_setfont(FONT_SYSFIXED);
 
 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
     rb->cpu_boost(true);
diff --git a/apps/plugins/mikmod/mikmod.c b/apps/plugins/mikmod/mikmod.c
index 5f19b43..a7eeb50 100644
--- a/apps/plugins/mikmod/mikmod.c
+++ b/apps/plugins/mikmod/mikmod.c
@@ -823,7 +823,7 @@ int playfile(char* filename)
                     retval = menureturn;
                 }
             }
-            rb->lcd_setfont(0);
+            rb->lcd_setfont(FONT_SYSFIXED);
             screenupdated = false;
             break;
             
@@ -877,7 +877,7 @@ enum plugin_status plugin_start(const void* parameter)
         return PLUGIN_OK;
     }
 
-    rb->lcd_setfont(0);
+    rb->lcd_setfont(FONT_SYSFIXED);
 
     rb->pcm_play_stop();
 #if INPUT_SRC_CAPS != 0
diff --git a/apps/plugins/rockboy/menu.c b/apps/plugins/rockboy/menu.c
index 54a0db7..3cd231c 100644
--- a/apps/plugins/rockboy/menu.c
+++ b/apps/plugins/rockboy/menu.c
@@ -125,7 +125,7 @@ int do_user_menu(void) {
         }
     }
 
-    rb->lcd_setfont(0); /* Reset the font */
+    rb->lcd_setfont(FONT_SYSFIXED); /* Reset the font */
     rb->lcd_clear_display(); /* Clear display for screen size changes */
     
     /* Keep the RTC in sync */
diff --git a/apps/plugins/rockboy/rockboy.c b/apps/plugins/rockboy/rockboy.c
index 4dc88fd..8882881 100644
--- a/apps/plugins/rockboy/rockboy.c
+++ b/apps/plugins/rockboy/rockboy.c
@@ -409,7 +409,7 @@ static int gnuboy_main(const char *rom)
 /* this is the plugin entry point */
 enum plugin_status plugin_start(const void* parameter)
 {
-    rb->lcd_setfont(0);
+    rb->lcd_setfont(FONT_SYSFIXED);
 
     rb->lcd_clear_display();
 
diff --git a/apps/plugins/rockpaint.c b/apps/plugins/rockpaint.c
index d1cc8f2..7938273 100644
--- a/apps/plugins/rockpaint.c
+++ b/apps/plugins/rockpaint.c
@@ -1016,7 +1016,6 @@ static bool browse_fonts( char *dst, int dst_size )
                     size_t siz;
                     reset_font = true;
                     rb->snprintf( bbuf, MAX_PATH, FONT_DIR "/%s", e->name );
-                    rb->font_load(NULL, bbuf );
                     rb->font_getstringsize( e->name, &fw, &fh, FONT_UI );
                     if( fw > LCD_WIDTH ) fw = LCD_WIDTH;
                     siz = (sizeof(struct font_preview) + fw*fh*FB_DATA_SZ+3) & ~3;
@@ -1083,7 +1082,7 @@ static bool browse_fonts( char *dst, int dst_size )
             li = tree->filesindir-1;
             if( reset_font )
             {
-                rb->font_load(NULL, bbuf_s );
+             // fixme   rb->font_load(NULL, bbuf_s );
                 reset_font = false;
             }
             if( lvi-fvi+1 < tree->filesindir )
@@ -1636,6 +1635,7 @@ static void show_grid( bool update )
 static void draw_text( int x, int y )
 {
     int selected = 0;
+    int current_font_id = rb->global_status->font_id[SCREEN_MAIN];
     buffer->text.text[0] = '\0';
     buffer->text.font[0] = '\0';
     while( 1 )
@@ -1648,9 +1648,12 @@ static void draw_text( int x, int y )
                 break;
 
             case TEXT_MENU_FONT:
-                if( browse_fonts( buffer->text.font, MAX_PATH ) )
+                if (current_font_id != rb->global_status->font_id[SCREEN_MAIN])
+                    rb->font_unload(current_font_id);
+                if(browse_fonts( buffer->text.font, MAX_PATH ) )
                 {
-                    rb->font_load(NULL, buffer->text.font );
+                    current_font_id = rb->font_load(buffer->text.font );
+                    rb->lcd_setfont(current_font_id);
                 }
                 break;
 
@@ -1704,7 +1707,9 @@ static void draw_text( int x, int y )
                     rb->snprintf( buffer->text.font, MAX_PATH,
                                   FONT_DIR "/%s.fnt",
                                   rb->global_settings->font_file );
-                    rb->font_load(NULL, buffer->text.font );
+                    if (current_font_id != rb->global_status->font_id[SCREEN_MAIN])
+                        rb->font_unload(current_font_id);
+                    rb->lcd_setfont(FONT_UI);
                 }
                 return;
         }
diff --git a/apps/plugins/text_viewer/tv_display.c b/apps/plugins/text_viewer/tv_display.c
index d38f1b5..2cf240d 100644
--- a/apps/plugins/text_viewer/tv_display.c
+++ b/apps/plugins/text_viewer/tv_display.c
@@ -255,7 +255,7 @@ void tv_set_layout(bool show_scrollbar)
     int scrollbar_height = (show_scrollbar && preferences->horizontal_scrollbar)?
                            TV_SCROLLBAR_HEIGHT + 1 : 0;
 
-    row_height = preferences->font->height;
+    row_height = rb->font_get(preferences->font_id)->height;
 
     header.x = 0;
     header.y = 0;
@@ -282,6 +282,7 @@ void tv_set_layout(bool show_scrollbar)
     vp_text.y += vertical_scrollbar.y;
     vp_text.width = horizontal_scrollbar.w;
     vp_text.height = vertical_scrollbar.h;
+    vp_text.font = preferences->font_id;
 #else
     (void) show_scrollbar;
 
@@ -334,16 +335,20 @@ static void tv_change_viewport(void)
 static bool tv_set_font(const unsigned char *font)
 {
     unsigned char path[MAX_PATH];
-
     if (font != NULL && *font != '\0')
     {
         rb->snprintf(path, MAX_PATH, "%s/%s.fnt", FONT_DIR, font);
-        if (rb->font_load(NULL, path) < 0)
+        if (preferences->font_id >= 0 &&
+            (preferences->font_id != rb->global_status->font_id[SCREEN_MAIN]))
+            rb->font_unload(preferences->font_id);
+        tv_change_fontid(rb->font_load(path));
+        if (preferences->font_id < 0)
         {
             rb->splash(HZ/2, "font load failed");
             return false;
         }
     }
+    vp_text.font = preferences->font_id;
     return true;
 }
 #endif
@@ -375,7 +380,7 @@ static int tv_change_preferences(const struct tv_preferences *oldp)
 
             return (tv_set_preferences(&new_prefs))? TV_CALLBACK_STOP : TV_CALLBACK_ERROR;
         }
-        col_width = 2 * rb->font_get_width(preferences->font, ' ');
+        col_width = 2 * rb->font_get_width(rb->font_get(preferences->font_id), ' ');
         font_changing = false;
     }
 #else
@@ -402,9 +407,10 @@ void tv_finalize_display(void)
 {
 #ifdef HAVE_LCD_BITMAP
     /* restore font */
-    if (rb->strcmp(rb->global_settings->font_file, preferences->font_name))
+    if (preferences->font_id >= 0 &&
+        (preferences->font_id != rb->global_status->font_id[SCREEN_MAIN]))
     {
-        tv_set_font(rb->global_settings->font_file);
+        rb->font_unload(preferences->font_id);
     }
 
     /* undo viewport */
diff --git a/apps/plugins/text_viewer/tv_preferences.c b/apps/plugins/text_viewer/tv_preferences.c
index 6d5c112..5901eb8 100644
--- a/apps/plugins/text_viewer/tv_preferences.c
+++ b/apps/plugins/text_viewer/tv_preferences.c
@@ -114,7 +114,7 @@ void tv_set_default_preferences(struct tv_preferences *p)
     p->footer_mode = true;
     p->statusbar   = true;
     rb->strlcpy(p->font_name, rb->global_settings->font_file, MAX_PATH);
-    p->font = rb->font_get(FONT_UI);
+    p->font_id = rb->global_status->font_id[SCREEN_MAIN];
 #else
     p->header_mode = false;
     p->footer_mode = false;
@@ -133,3 +133,8 @@ void tv_add_preferences_change_listner(int (*listner)(const struct tv_preference
     if (listner_count < TV_MAX_LISTNERS)
         listners[listner_count++] = listner;
 }
+
+void tv_change_fontid(int id)
+{
+    prefs.font_id = id;
+}
diff --git a/apps/plugins/text_viewer/tv_preferences.h b/apps/plugins/text_viewer/tv_preferences.h
index bb448b0..f3b2aeb 100644
--- a/apps/plugins/text_viewer/tv_preferences.h
+++ b/apps/plugins/text_viewer/tv_preferences.h
@@ -95,7 +95,7 @@ struct tv_preferences {
 
 #ifdef HAVE_LCD_BITMAP
     unsigned char font_name[MAX_PATH];
-    struct font *font;
+    int font_id;
 #endif
     unsigned char file_name[MAX_PATH];
 };
@@ -151,4 +151,6 @@ void tv_set_default_preferences(struct tv_preferences *p);
  */
 void tv_add_preferences_change_listner(int (*listner)(const struct tv_preferences *oldp));
 
+
+void tv_change_fontid(int id);
 #endif
diff --git a/apps/plugins/text_viewer/tv_settings.c b/apps/plugins/text_viewer/tv_settings.c
index 3ed1576..895f162 100644
--- a/apps/plugins/text_viewer/tv_settings.c
+++ b/apps/plugins/text_viewer/tv_settings.c
@@ -218,7 +218,7 @@ static bool tv_read_preferences(int pfd, int version, struct tv_preferences *pre
 #ifdef HAVE_LCD_BITMAP
     rb->strlcpy(prefs->font_name, buf + read_size - MAX_PATH, MAX_PATH);
 
-    prefs->font = rb->font_get(FONT_UI);
+    prefs->font_id = rb->global_status->font_id[SCREEN_MAIN];
 #endif
 
     return true;
diff --git a/apps/plugins/text_viewer/tv_text_processor.c b/apps/plugins/text_viewer/tv_text_processor.c
index edb2ad0..d027a9a 100644
--- a/apps/plugins/text_viewer/tv_text_processor.c
+++ b/apps/plugins/text_viewer/tv_text_processor.c
@@ -95,7 +95,7 @@ static int tv_glyph_width(int ch)
     if (rb->is_diacritic(ch, NULL))
         return 0;
 
-    return rb->font_get_width(preferences->font, ch);
+    return rb->font_get_width(rb->font_get(preferences->font_id), ch);
 #else
     return 1;
 #endif
diff --git a/apps/screen_access.c b/apps/screen_access.c
index b83e842..dd36838 100644
--- a/apps/screen_access.c
+++ b/apps/screen_access.c
@@ -67,6 +67,13 @@ static int screen_helper_getnblines(void)
     return height / screens[0].getcharheight();
 }
 
+void screen_helper_setfont(int font)
+{
+    if (font == FONT_UI)
+        font = global_status.font_id[0];
+    lcd_setfont(font);
+}
+
 #if NB_SCREENS == 2
 static int screen_helper_remote_getcharwidth(void)
 {
@@ -99,6 +106,13 @@ static int screen_helper_remote_getnblines(void)
 #endif
     return height / screens[1].getcharheight();
 }
+
+void screen_helper_remote_setfont(int font)
+{
+    if (font == FONT_UI)
+        font = global_status.font_id[1];
+    lcd_remote_setfont(font);
+}
 #endif
 
 struct screen screens[NB_SCREENS] =
@@ -129,7 +143,7 @@ struct screen screens[NB_SCREENS] =
         .getheight=&lcd_getheight,
         .getstringsize=&lcd_getstringsize,
 #ifdef HAVE_LCD_BITMAP
-        .setfont=&lcd_setfont,
+        .setfont=screen_helper_setfont,
         .getfont=&lcd_getfont,
         .mono_bitmap=&lcd_mono_bitmap,
         .mono_bitmap_part=&lcd_mono_bitmap_part,
@@ -229,7 +243,7 @@ struct screen screens[NB_SCREENS] =
         .getheight=&lcd_remote_getheight,
         .getstringsize=&lcd_remote_getstringsize,
 #if 1 /* all remote LCDs are bitmapped so far */
-        .setfont=&lcd_remote_setfont,
+        .setfont=screen_helper_setfont,
         .getfont=&lcd_remote_getfont,
         .mono_bitmap=&lcd_remote_mono_bitmap,
         .mono_bitmap_part=&lcd_remote_mono_bitmap_part,
diff --git a/apps/screen_access.h b/apps/screen_access.h
index efe232b..31ec34f 100644
--- a/apps/screen_access.h
+++ b/apps/screen_access.h
@@ -28,9 +28,11 @@
 
 #if defined(HAVE_REMOTE_LCD) && !defined (ROCKBOX_HAS_LOGF)
 #define NB_SCREENS 2
+void screen_helper_remote_setfont(int font);
 #else
 #define NB_SCREENS 1
 #endif
+void screen_helper_setfont(int font);
 
 #if NB_SCREENS == 1
 #define FOR_NB_SCREENS(i) i = 0;
diff --git a/apps/settings.c b/apps/settings.c
index 258face..c7d0a9e 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -876,30 +876,38 @@ void settings_apply(bool read_disk)
         /* fonts need to be loaded before the WPS */
         if (global_settings.font_file[0]
             && global_settings.font_file[0] != '-') {
+            const char* loaded_font = font_filename(global_status.font_id[SCREEN_MAIN]);
             
             snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
                      global_settings.font_file);
-            CHART2(">font_load ", global_settings.font_file);
-            rc = font_load(NULL, buf);
-            CHART2("<font_load ", global_settings.font_file);
-            if (rc < 0)
-                font_reset(NULL);
+            if (!loaded_font || strcmp(loaded_font, buf))
+            {
+                CHART2(">font_load ", global_settings.font_file);
+                if (global_status.font_id[SCREEN_MAIN] >= 0)
+                    font_unload(global_status.font_id[SCREEN_MAIN]);
+                rc = font_load(buf);
+                CHART2("<font_load ", global_settings.font_file);
+                global_status.font_id[SCREEN_MAIN] = rc;
+                lcd_setfont(rc);
+            }
         }
-        else
-            font_reset(NULL);
 #ifdef HAVE_REMOTE_LCD        
         if ( global_settings.remote_font_file[0]
             && global_settings.remote_font_file[0] != '-') {
+            const char* loaded_font = font_filename(global_status.font_id[SCREEN_REMOTE]);
             snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
                      global_settings.remote_font_file);
-            CHART2(">font_load_remoteui ", global_settings.remote_font_file);
-            rc = font_load_remoteui(buf);
-            CHART2("<font_load_remoteui ", global_settings.remote_font_file);
-            if (rc < 0)
-                font_load_remoteui(NULL);
+            if (!loaded_font || strcmp(loaded_font, buf))
+            {
+                CHART2(">font_load_remoteui ", global_settings.remote_font_file);
+                if (global_status.font_id[SCREEN_REMOTE] >= 0)
+                    font_unload(global_status.font_id[SCREEN_REMOTE]);
+                rc = font_load(buf);
+                CHART2("<font_load_remoteui ", global_settings.remote_font_file);
+                global_status.font_id[SCREEN_REMOTE] = rc;
+                lcd_remote_setfont(rc);
+            }
         }
-        else
-            font_load_remoteui(NULL);
 #endif
         if ( global_settings.kbd_file[0]
              && global_settings.kbd_file[0] != '-') {
@@ -1070,6 +1078,14 @@ void settings_reset(void)
 #if defined (HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
     enc_global_settings_reset();
 #endif
+    FOR_NB_SCREENS(i)
+    {
+        if (global_status.font_id[i] > FONT_SYSFIXED)
+        {
+            font_unload(global_status.font_id[i]);
+            global_status.font_id[i] = FONT_SYSFIXED;
+        }
+    }
 }
 
 /** Changing setting values **/
diff --git a/apps/settings.h b/apps/settings.h
index d7a7226..77fb7aa 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -278,6 +278,7 @@ struct system_status
     signed char last_screen;
     int  viewer_icon_count;
     int last_volume_change; /* tick the last volume change happened. skins use this */
+    int font_id[NB_SCREENS]; /* font id of the settings font for each screen */
 };
 
 struct user_settings
diff --git a/firmware/export/font.h b/firmware/export/font.h
index a85f95e..6c9e616 100644
--- a/firmware/export/font.h
+++ b/firmware/export/font.h
@@ -22,6 +22,7 @@
 #define _FONT_H
 
 #include "inttypes.h"
+#include "stdbool.h"
 
 /*
  * Incore font and image definitions
@@ -46,18 +47,14 @@
  * Fonts are specified in firmware/font.c.
  */
 enum {
-    FONT_SYSFIXED, /* system fixed pitch font*/
-    FONT_UI,       /* system porportional font*/
-#ifdef HAVE_REMOTE_LCD
-    FONT_UI_REMOTE, /* UI font for remote LCD */
-#endif
-    SYSTEMFONTCOUNT, /* Number of fonts reserved for the system and ui */
-    FONT_FIRSTUSERFONT = 2
+    FONT_SYSFIXED = -1, /* system fixed pitch font*/
+    FONT_FIRSTUSERFONT = 0, /* first id for the user fonts */
 };
 #define MAXUSERFONTS 8
 
 /* SYSFONT, FONT_UI, FONT_UI_REMOTE + MAXUSERFONTS fonts in skins */
-#define MAXFONTS (SYSTEMFONTCOUNT + MAXUSERFONTS)
+#define MAXFONTS (FONT_FIRSTUSERFONT + MAXUSERFONTS)
+#define FONT_UI MAXFONTS
 
 /*
  * .fnt loadable font file format definition
@@ -105,7 +102,7 @@ struct font {
     unsigned char *buffer_start;    /* buffer to store the font in */       
     unsigned char *buffer_position; /* position in the buffer */    
     unsigned char *buffer_end;      /* end of the buffer */
-    int          buffer_size;       /* size of the buffer in bytes */
+    int            buffer_size;     /* size of the buffer in bytes */
 #ifndef __PCTOOL__    
     struct font_cache cache;
     uint32_t file_width_offset;    /* offset to file width data    */
@@ -117,17 +114,13 @@ struct font {
 
 /* font routines*/
 void font_init(void) INIT_ATTR;
-#ifdef HAVE_REMOTE_LCD
-/* Load a font into the special remote ui font slot */
-int font_load_remoteui(const char* path);
-#endif
-int font_load(struct font* pf, const char *path);
+const char* font_filename(int font_id);
+int font_load(const char *path);
 int font_glyphs_to_bufsize(const char *path, int glyphs);
 void font_unload(int font_id);
 
 struct font* font_get(int font);
 
-void font_reset(struct font *pf);
 int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber);
 int font_get_width(struct font* ft, unsigned short ch);
 const unsigned char * font_get_bits(struct font* ft, unsigned short ch);
diff --git a/firmware/font.c b/firmware/font.c
index 0f9f453..b774f56 100644
--- a/firmware/font.c
+++ b/firmware/font.c
@@ -34,6 +34,7 @@
 #include "system.h"
 #include "font.h"
 #include "file.h"
+#include "core_alloc.h"
 #include "debug.h"
 #include "panic.h"
 #include "rbunicode.h"
@@ -74,19 +75,55 @@ extern struct font sysfont;
 
 #ifndef BOOTLOADER
 
-/* structure filled in by font_load */
-static struct font font_ui;
-/* static buffer allocation structures */
-static unsigned char main_buf[MAX_FONT_SIZE] CACHEALIGN_ATTR;
-#ifdef HAVE_REMOTE_LCD
-#define REMOTE_FONT_SIZE 10000
-static struct font remote_font_ui;
-static unsigned char remote_buf[REMOTE_FONT_SIZE] CACHEALIGN_ATTR;
-#endif
+struct buflib_alloc_data {
+    struct font font;
+    bool handle_locked;   /* is the buflib handle currently locked? */
+    int refcount;   /* how many times has this font been loaded? */
+    unsigned char buffer[MAX_FONT_SIZE] CACHEALIGN_ATTR;
+};
+static int buflib_allocations[MAXFONTS];
+static int handle_for_glyphcache;
 
-/* system font table, in order of FONT_xxx definition */
-static struct font* sysfonts[MAXFONTS] = { &sysfont, &font_ui, NULL};
+static int buflibmove_callback(int handle, void* current, void* new)
+{
+    (void)handle;
+    struct buflib_alloc_data *alloc = (struct buflib_alloc_data*)current;
+    size_t diff = new - current;
+
+    if (alloc->handle_locked)
+        return BUFLIB_CB_CANNOT_MOVE;
+
+    alloc->font.bits += diff;
+    alloc->font.offset += diff;
+    if (alloc->font.width)
+        alloc->font.width += diff;
+
+    alloc->font.buffer_start += diff;
+    alloc->font.buffer_end += diff;
+    alloc->font.buffer_position += diff;
+    return BUFLIB_CB_OK;
+}
+static void lock_font_handle(int handle, bool lock)
+{
+    struct buflib_alloc_data *alloc = core_get_data(handle);
+    alloc->handle_locked = lock;
+}
 
+static struct buflib_callbacks buflibops = {buflibmove_callback, NULL };
+
+static inline struct font *pf_from_handle(int handle)
+{
+    struct buflib_alloc_data *alloc = core_get_data(handle);
+    struct font *pf = &alloc->font;
+    return pf;
+}
+
+static inline unsigned char *buffer_from_handle(int handle)
+{
+    struct buflib_alloc_data *alloc = core_get_data(handle);
+    unsigned char* buffer = alloc->buffer;
+    return buffer;
+}
 
 /* Font cache structures */
 static void cache_create(struct font* pf);
@@ -95,13 +132,10 @@ static void glyph_cache_load(struct font* pf);
 
 void font_init(void)
 {
-    int i = SYSTEMFONTCOUNT;
+    int i = 0;
     while (i<MAXFONTS)
-        sysfonts[i++] = NULL;
-    font_reset(NULL);
-#ifdef HAVE_REMOTE_LCD
-    font_reset(&remote_font_ui);
-#endif
+        buflib_allocations[i++] = -1;
+    handle_for_glyphcache = -1;
 }
 
 /* Check if we have x bytes left in the file buffer */
@@ -139,26 +173,6 @@ static int glyph_bytes( struct font *pf, int width )
         width * ((pf->height + 7) / 8);
 }
 
-void font_reset(struct font *pf)
-{
-    unsigned char* buffer = NULL;
-    size_t buf_size = 0;
-    if (pf == NULL)
-        pf = &font_ui;
-    else
-    {
-        buffer = pf->buffer_start;
-        buf_size = pf->buffer_size;
-    }
-    memset(pf, 0, sizeof(struct font));
-    pf->fd = -1;
-    if (buffer)
-    {
-        pf->buffer_start = buffer;
-        pf->buffer_size = buf_size;
-    }
-}
-
 static struct font* font_load_header(struct font *pf)
 {
     /* Check we have enough data */
@@ -320,18 +334,27 @@ static struct font* font_load_cached(struct font* pf)
     return pf;
 }
 
-static bool internal_load_font(struct font* pf, const char *path,
+static void font_reset(int font_id)
+{
+    struct font *pf = pf_from_handle(buflib_allocations[font_id]);
+    // fixme
+    memset(pf, 0, sizeof(struct font));
+    pf->fd = -1;
+}
+
+
+static bool internal_load_font(int font_id, const char *path,
                                char *buf, size_t buf_size)
 {
     int size;
-    
+    struct font* pf = pf_from_handle(buflib_allocations[font_id]);
     /* save loaded glyphs */
     glyph_cache_save(pf);
     /* Close font file handle */
     if (pf->fd >= 0)
         close(pf->fd);
 
-    font_reset(pf);
+    font_reset(font_id);
 
     /* open and read entire font file*/
     pf->fd = open(path, O_RDONLY|O_BINARY);
@@ -393,80 +416,117 @@ static bool internal_load_font(struct font* pf, const char *path,
     return true;
 }
 
-#ifdef HAVE_REMOTE_LCD
-/* Load a font into the special remote ui font slot */
-int font_load_remoteui(const char* path)
+static int find_font_index(const char* path)
 {
-    struct font* pf = &remote_font_ui;
-    if (!path)
-    {
-        if (sysfonts[FONT_UI_REMOTE] && sysfonts[FONT_UI_REMOTE] != sysfonts[FONT_UI])
-            font_unload(FONT_UI_REMOTE);
-        sysfonts[FONT_UI_REMOTE] = NULL;
-        return FONT_UI;
-    }
-    if (!internal_load_font(pf, path, remote_buf, REMOTE_FONT_SIZE))
+    int index = 0, handle;
+
+    while (index < MAXFONTS)
     {
-        sysfonts[FONT_UI_REMOTE] = NULL;
-        return -1;
+        handle = buflib_allocations[index];
+        if (handle > 0 && !strcmp(core_get_name(handle), path))
+            return index;
+        index++;
     }
-    
-    sysfonts[FONT_UI_REMOTE] = pf;
-    return FONT_UI_REMOTE;
+    return FONT_SYSFIXED;
 }
-#endif
 
+static int alloc_and_init(int font_idx, const char* name)
+{
+    int *phandle = &buflib_allocations[font_idx];
+    int handle = *phandle;
+    struct buflib_alloc_data *pdata;
+    struct font *pf;
+    if (handle > 0)
+        return handle;
+    *phandle = core_alloc_ex(name, sizeof(struct buflib_alloc_data), &buflibops);
+    handle = *phandle;
+    if (handle < 0)
+        return handle;
+    pdata = core_get_data(handle);
+    pf = &pdata->font;
+    font_reset(font_idx);
+    pdata->handle_locked = false;
+    pdata->refcount = 1;
+    pf->buffer_position = pf->buffer_start = buffer_from_handle(handle);
+    pf->buffer_size = MAX_FONT_SIZE;
+    return handle;
+}
+
+const char* font_filename(int font_id)
+{
+    int handle = buflib_allocations[font_id];
+    if (handle > 0)
+        return core_get_name(handle);
+    return NULL;
+}
+    
 /* read and load font into incore font structure,
  * returns the font number on success, -1 on failure */
-int font_load(struct font* pf, const char *path)
+int font_load(const char *path)
 {
-    int font_id = -1;
+    int font_id = find_font_index(path);
     char *buffer;
     size_t buffer_size;
-    if (pf == NULL)
+    int *handle;
+
+    if (font_id > FONT_SYSFIXED)
     {
-        pf = &font_ui;
-        font_id = FONT_UI;
+        /* already loaded, no need to reload */
+        struct buflib_alloc_data *pd = core_get_data(buflib_allocations[font_id]);
+        pd->refcount++;
+        //printf("reusing handle %d for %s (count: %d)\n", font_id, path, pd->refcount); 
+        return font_id;
     }
-    else
+
+    for (font_id = FONT_FIRSTUSERFONT; font_id < MAXFONTS; font_id++)
     {
-        for (font_id = SYSTEMFONTCOUNT; font_id < MAXFONTS; font_id++)
+        handle = &buflib_allocations[font_id];
+        if (*handle < 0)
         {
-            if (sysfonts[font_id] == NULL)
-                break;
+            break;
         }
-        if (font_id == MAXFONTS)
-            return -1; /* too many fonts */
     }
-    
-    if (font_id == FONT_UI)
-    {
-        /* currently, font loading replaces earlier font allocation*/
-        buffer = (unsigned char *)(((intptr_t)main_buf + 3) & ~3);
-        /* make sure above doesn't exceed */
-        buffer_size = MAX_FONT_SIZE-3; 
-    }
-    else
+    handle = &buflib_allocations[font_id];
+    *handle = alloc_and_init(font_id, path);
+    if (*handle < 0)
+        return -1;
+
+    if (handle_for_glyphcache < 0)
+        handle_for_glyphcache = *handle;
+
+    buffer = buffer_from_handle(*handle);
+    buffer_size = MAX_FONT_SIZE; //FIXME
+    lock_font_handle(*handle, true);
+
+    if (!internal_load_font(font_id, path, buffer, buffer_size))
     {
-        buffer = pf->buffer_start;
-        buffer_size = pf->buffer_size;
-    }
-    
-    if (!internal_load_font(pf, path, buffer, buffer_size))
+        lock_font_handle(*handle, false);
+        core_free(*handle);
+        *handle = -1;
         return -1;
+    }
         
-    sysfonts[font_id] = pf;
+    lock_font_handle(*handle, false);
+    //printf("%s -> [%d] -> %d\n", path, font_id, *handle);
     return font_id; /* success!*/
 }
 
 void font_unload(int font_id)
 {
-    struct font* pf = sysfonts[font_id];
-    if (font_id >= SYSTEMFONTCOUNT && pf)
+    int *handle = &buflib_allocations[font_id];
+    struct buflib_alloc_data *pdata = core_get_data(*handle);
+    struct font* pf = &pdata->font;
+    pdata->refcount--;
+    if (pdata->refcount < 1)
     {
-        if (pf->fd >= 0)
+        //printf("freeing id: %d %s\n", font_id, core_get_name(*handle));
+        if (pf && pf->fd >= 0)
             close(pf->fd);
-        sysfonts[font_id] = NULL;
+        if (*handle > 0)
+            core_free(*handle);
+        if (handle_for_glyphcache == *handle)
+            handle_for_glyphcache = -1; // should find the next available handle
+        *handle = -1;
     }
 }
 
@@ -478,13 +538,18 @@ void font_unload(int font_id)
 struct font* font_get(int font)
 {
     struct font* pf;
+    if (font == FONT_UI)
+        font = MAXFONTS-1;
+    if (font <= FONT_SYSFIXED)
+        return &sysfont;
 
     while (1) {
-        pf = sysfonts[font];
+        struct buflib_alloc_data *alloc = core_get_data(buflib_allocations[font]);
+        pf = &alloc->font;
         if (pf && pf->height)
             return pf;
         if (--font < 0)
-            panicf("No font!");
+            return &sysfont;
     }
 }
 
@@ -594,7 +659,8 @@ static int cache_fd;
 static void glyph_file_write(void* data)
 {
     struct font_cache_entry* p = data;
-    struct font* pf = &font_ui;
+    int handle = handle_for_glyphcache;
+    struct font* pf = pf_from_handle(handle);
     unsigned short ch;
     unsigned char tmp[2];
 
@@ -617,9 +683,9 @@ static void glyph_file_write(void* data)
 /* save the char codes of the loaded glyphs to a file */
 void glyph_cache_save(struct font* pf)
 {
-    if (!pf)
-        pf = &font_ui;
-    if (pf->fd >= 0 && pf == &font_ui) 
+    if (pf != pf_from_handle(handle_for_glyphcache))
+        return;
+    if (pf->fd >= 0) 
     {
         cache_fd = open(GLYPH_CACHE_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0666);
         if (cache_fd < 0)
@@ -675,9 +741,10 @@ static int ushortcmp(const void *a, const void *b)
 }
 static void glyph_cache_load(struct font* pf)
 {
-
+    if (handle_for_glyphcache <= 0)
+        return;
 #define MAX_SORT 256
-    if (pf->fd >= 0) {
+    if (pf->fd >= 0 && pf == pf_from_handle(handle_for_glyphcache)) {
         int fd;
         int i, size;
         unsigned char tmp[2];
diff --git a/firmware/include/core_alloc.h b/firmware/include/core_alloc.h
index f5206c9..b2edec5 100644
--- a/firmware/include/core_alloc.h
+++ b/firmware/include/core_alloc.h
@@ -33,4 +33,11 @@ static inline void* core_get_data(int handle)
     extern struct buflib_context core_ctx;
     return buflib_get_data(&core_ctx, handle);
 }
+
+static inline const char* core_get_name(int handle)
+{
+    extern struct buflib_context core_ctx;
+    return buflib_get_name(&core_ctx, handle);
+}
+
 #endif /* __CORE_ALLOC_H__ */
