cache.c (5114B)
1 #include <stdio.h> 2 #include <limits.h> 3 #include <stdlib.h> 4 #include <X11/Xlib.h> 5 #include <X11/Xutil.h> 6 #include <pango/pangoxft.h> 7 #include <X11/extensions/Xdbe.h> 8 9 #include "util.h" 10 #include "common.h" 11 #include "memory.h" 12 #include "cache.h" 13 #include "assert.h" 14 15 ledit_cache * 16 cache_create(Display *dpy) { 17 ledit_cache *cache = ledit_malloc(sizeof(ledit_cache)); 18 cache->dpy = dpy; 19 cache->pixmaps = ledit_reallocarray(NULL, PIXMAP_CACHE_INITIAL_SIZE, sizeof(cache_pixmap)); 20 cache->layouts = ledit_reallocarray(NULL, LAYOUT_CACHE_SIZE, sizeof(cache_layout)); 21 for (size_t i = 0; i < PIXMAP_CACHE_INITIAL_SIZE; i++) { 22 cache->pixmaps[i].pixmap = None; 23 cache->pixmaps[i].draw = NULL; 24 cache->pixmaps[i].line = 0; 25 cache->pixmaps[i].valid = 0; 26 } 27 for (size_t i = 0; i < LAYOUT_CACHE_SIZE; i++) { 28 cache->layouts[i].layout = NULL; 29 cache->layouts[i].line = 0; 30 cache->layouts[i].valid = 0; 31 } 32 cache->num_pixmaps = PIXMAP_CACHE_INITIAL_SIZE; 33 cache->num_layouts = LAYOUT_CACHE_SIZE; 34 cache->cur_pixmap_index = cache->cur_layout_index = 0; 35 return cache; 36 } 37 38 void 39 cache_flush( 40 ledit_cache *cache, void *callback_data, 41 void (*invalidate_pixmap_line)(void *, size_t), 42 void (*invalidate_layout_line)(void *, size_t)) { 43 cache_invalidate_from_line( 44 cache, 0, callback_data, invalidate_pixmap_line, invalidate_layout_line 45 ); 46 } 47 48 void 49 cache_invalidate_from_line( 50 ledit_cache *cache, size_t start, void *callback_data, 51 void (*invalidate_pixmap_line)(void *, size_t), 52 void (*invalidate_layout_line)(void *, size_t)) { 53 for (size_t i = 0; i < cache->num_pixmaps; i++) { 54 if (cache->pixmaps[i].line >= start) { 55 invalidate_pixmap_line(callback_data, cache->pixmaps[i].line); 56 cache->pixmaps[i].line = 0; 57 cache->pixmaps[i].valid = 0; 58 } 59 } 60 for (size_t i = 0; i < cache->num_layouts; i++) { 61 if (cache->layouts[i].line >= start) { 62 invalidate_layout_line(callback_data, cache->layouts[i].line); 63 cache->layouts[i].line = 0; 64 cache->layouts[i].valid = 0; 65 } 66 } 67 } 68 69 void 70 cache_destroy(ledit_cache *cache) { 71 for (size_t i = 0; i < cache->num_pixmaps; i++) { 72 if (cache->pixmaps[i].pixmap != None) 73 XFreePixmap(cache->dpy, cache->pixmaps[i].pixmap); 74 if (cache->pixmaps[i].draw != NULL) 75 XftDrawDestroy(cache->pixmaps[i].draw); 76 } 77 for (size_t i = 0; i < cache->num_layouts; i++) { 78 if (cache->layouts[i].layout != NULL) 79 g_object_unref(cache->layouts[i].layout); 80 } 81 free(cache->pixmaps); 82 free(cache->layouts); 83 free(cache); 84 } 85 86 cache_pixmap * 87 cache_get_pixmap(ledit_cache *cache, size_t index) { 88 ledit_assert(index < cache->num_pixmaps); 89 return &cache->pixmaps[index]; 90 } 91 92 cache_layout * 93 cache_get_layout(ledit_cache *cache, size_t index) { 94 ledit_assert(index < cache->num_layouts); 95 return &cache->layouts[index]; 96 } 97 98 /* FIXME: max pixmap cache size */ 99 void 100 cache_assign_pixmap_index( 101 ledit_cache *cache, size_t line, 102 void *callback_data, 103 int (*line_needed)(void *, size_t), 104 void (*set_pixmap_line)(void *, size_t, size_t), 105 void (*invalidate_pixmap_line)(void *, size_t)) { 106 size_t line_index; 107 size_t entry_index; 108 for (size_t i = 0; i <= cache->num_pixmaps; i++) { 109 entry_index = (i + cache->cur_pixmap_index) % cache->num_pixmaps; 110 line_index = cache->pixmaps[entry_index].line; 111 int valid = cache->pixmaps[entry_index].valid; 112 /* replace line when entry isn't assigned or currently assigned line is not visible */ 113 if (!valid || 114 (valid && !line_needed(callback_data, line_index))) { 115 cache->cur_pixmap_index = (entry_index + 1) % cache->num_pixmaps; 116 cache_pixmap *pix = &cache->pixmaps[entry_index]; 117 if (pix->valid) 118 invalidate_pixmap_line(callback_data, pix->line); 119 pix->line = line; 120 pix->valid = 1; 121 set_pixmap_line(callback_data, line, entry_index); 122 return; 123 } 124 } 125 126 /* no free entry found, increase cache size */ 127 /* FIXME: maybe have maximum cache size */ 128 size_t new_alloc = ideal_array_size(cache->num_pixmaps, add_sz(cache->num_pixmaps, 1)); 129 cache->pixmaps = ledit_reallocarray(cache->pixmaps, new_alloc, sizeof(cache_pixmap)); 130 entry_index = cache->num_pixmaps; 131 for (size_t i = cache->num_pixmaps; i < cache->num_pixmaps * 2; i++) { 132 cache->pixmaps[i].line = 0; 133 cache->pixmaps[i].valid = 0; 134 cache->pixmaps[i].pixmap = None; 135 cache->pixmaps[i].draw = NULL; 136 } 137 cache->num_pixmaps *= 2; 138 cache_pixmap *pix = &cache->pixmaps[entry_index]; 139 pix->line = line; 140 pix->valid = 1; 141 set_pixmap_line(callback_data, line, entry_index); 142 } 143 144 /* FIXME: perhaps use "real" clock cache management, i.e. set a bit on a cache entry 145 when it is used so it isn't invalidated yet. */ 146 void cache_assign_layout_index( 147 ledit_cache *cache, size_t line, 148 void *callback_data, 149 void (*set_layout_line)(void *, size_t, size_t), 150 void (*invalidate_layout_line)(void *, size_t)) { 151 size_t old = cache->cur_layout_index; 152 cache->cur_layout_index = (cache->cur_layout_index + 1) % cache->num_layouts; 153 cache_layout *layout = &cache->layouts[old]; 154 if (layout->valid) 155 invalidate_layout_line(callback_data, layout->line); 156 layout->valid = 1; 157 layout->line = line; 158 set_layout_line(callback_data, line, old); 159 }