URI: 
       cache.c - ledit - Text editor (WIP)
  HTML git clone git://lumidify.org/ledit.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/ledit.git (encrypted, but very slow)
  HTML git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ledit.git (over tor)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       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 }