commit 88b7f6c08a1e2a47f33aa5b4d33f18df60b5011f
parent e9c86a9b95b0a349d3f34f2a15dd3afffafc3b52
Author: lumidify <nobody@lumidify.org>
Date: Sat, 10 Apr 2021 21:18:46 +0200
Modify cache to cache individual lines
Diffstat:
M | ledit.c | | | 291 | +++++++++++++++++++++++++++++-------------------------------------------------- |
1 file changed, 106 insertions(+), 185 deletions(-)
diff --git a/ledit.c b/ledit.c
@@ -32,8 +32,6 @@ struct key {
void (*func)(void); /* callback function */
};
-#define MAX_CACHE_PIXELS 100
-
static struct {
Display *dpy;
GC gc;
@@ -56,17 +54,31 @@ static struct {
Atom wm_delete_msg;
} state;
+struct cache_pixmap {
+ Pixmap pixmap;
+ XftDraw *draw;
+ int w, h;
+ int line;
+};
+
/* FIXME: possibly use at least 32 bits int? */
static struct {
- Pixmap pix;
- XftDraw *draw;
- int pix_w, pix_h;
- long start_offset;
- int valid_height;
- int begin_line, begin_softline;
- int dirty;
+ struct cache_pixmap *entries;
+ int entries_num;
+ int cur_replace_index;
} cache;
+static size_t lines_num = 0;
+static size_t lines_cap = 0;
+
+static int cur_line = 0;
+static int cur_subline = 0;
+static int cur_index = 0;
+static int trailing = 0;
+static long total_height = 0;
+static double cur_display_offset = 0;
+
+
static void mainloop(void);
static void setup(int argc, char *argv[]);
static void cleanup(void);
@@ -94,24 +106,57 @@ static struct line {
int w;
int h;
long y_offset;
- /*
- XftDraw *draw;
- Pixmap pix;
- unsigned int pix_w;
- unsigned int pix_h;
- */
+ int cache_index;
char dirty;
} *lines = NULL;
-static size_t lines_num = 0;
-static size_t lines_cap = 0;
+static void
+init_cache(void) {
+ /* FIXME: prevent overflow */
+ cache.entries = malloc(20 * sizeof(struct cache_pixmap));
+ if (!cache.entries) exit(1);
+ for (int i = 0; i < 20; i++) {
+ cache.entries[i].pixmap = None;
+ cache.entries[i].line = -1;
+ }
+ cache.entries_num = 20;
+ cache.cur_replace_index = -1;
+}
-static int cur_line = 0;
-static int cur_subline = 0;
-static int cur_index = 0;
-static int trailing = 0;
-static long total_height = 0;
-static double cur_display_offset = 0;
+static void
+assign_free_cache_index(int line) {
+ int found = 0;
+ int real_index;
+ int tmp_line;
+ /* start at 1 because the cache->cur_replace_index is actually the last entry that was replaced */
+ for (int i = 1; i <= cache.entries_num; i++) {
+ real_index = (i + cache.cur_replace_index) % cache.entries_num;
+ tmp_line = cache.entries[real_index].line;
+ /* replace line when entry isn't assigned or currently assigned line is not visible */
+ if (tmp_line == -1 ||
+ (tmp_line >= 0 &&
+ (lines[tmp_line].y_offset >= cur_display_offset + state.h ||
+ lines[tmp_line].y_offset + lines[tmp_line].h <= cur_display_offset))) {
+ if (tmp_line >= 0)
+ lines[tmp_line].cache_index = -1;
+ cache.entries[real_index].line = line;
+ cache.cur_replace_index = real_index;
+ lines[line].cache_index = real_index;
+ return;
+ }
+ }
+
+ /* no free entry found, increase cache size */
+ cache.entries = realloc(cache.entries, cache.entries_num * 2 * sizeof(struct cache_pixmap));
+ if (!cache.entries) exit(1);
+ real_index = cache.entries_num;
+ for (size_t i = cache.entries_num + 1; i < cache.entries_num * 2; i++) {
+ cache.entries[i].line = -1;
+ }
+ cache.entries_num *= 2;
+ cache.entries[real_index].line = line;
+ lines[line].cache_index = real_index;
+}
static void
init_line(struct line *l) {
@@ -122,97 +167,16 @@ init_line(struct line *l) {
pango_layout_set_wrap(l->layout, PANGO_WRAP_WORD_CHAR);
l->text = NULL;
l->cap = l->len = 0;
- /*l->pix = None;*/
+ l->cache_index = -1;
+ l->dirty = 1;
/* FIXME: does this set line height reasonably when no text yet? */
pango_layout_get_pixel_size(l->layout, &l->w, &l->h);
l->y_offset = 0;
- //l->dirty = 1;
}
static void recalc_cur_line_size(void);
static void recalc_line_size_absolute(void);
-enum CachePosition {
- CACHE_NONE,
- CACHE_BOTH,
- CACHE_TOP,
- CACHE_BOTTOM
-};
-
-static void redraw_cache_complete(enum CachePosition pos);
-static void redraw_cache_after_cur_line(void);
-static void redraw_cache_only_cur_line(void);
-
-#define MAX_INT(a, b) ((a) > (b) ? (a) : (b))
-#define MIN_INT(a, b) ((a) < (b) ? (a) : (b))
-
-/* FIXME: Implement pos */
-static void
-redraw_cache_complete(enum CachePosition pos) {
- long start = cur_display_offset > MAX_CACHE_PIXELS ? (long)(cur_display_offset) - MAX_CACHE_PIXELS : 0;
- long end = (long)(cur_display_offset) + state.h + MAX_CACHE_PIXELS;
- int start_line = 0;
- int end_line = 0;
-
- /* FIXME: make this more efficient - we can't start at cur_line
- * because that may be off screen */
- /*
- for (start_line = cur_line;
- lines[start_line].y_offset > cur_display_offset;
- start_line--) {
- }
-
- for (end_line = cur_line;
- end_line < lines_num &&
- lines[end_line].y_offset + lines[end_line].h < cur_display_offset + state.h;
- end_line++) {
- }
- */
-
- for (start_line = 0;
- start_line < lines_num - 1 &&
- lines[start_line].y_offset + lines[start_line].h <= cur_display_offset;
- start_line++) {
- /* NOP */
- }
- for (end_line = start_line;
- end_line < lines_num - 1 &&
- lines[end_line].y_offset + lines[end_line].h < cur_display_offset + state.h;
- end_line++) {
- /* NOP */
- }
-
- if (lines[start_line].y_offset < start) {
- printf("FIX THIS CODE 1!\n");
- }
- if (lines[end_line].y_offset + lines[end_line].h > end) {
- printf("FIX THIS CODE 2!\n");
- }
-
- /* FIXME: only wipe what is necessary */
- XftDrawRect(cache.draw, &state.bg, 0, 0, cache.pix_w, cache.pix_h);
- int cur_y = 0;
- for (int i = start_line; i <= end_line; i++) {
- if (lines[i].w > cache.pix_w || cur_y + lines[i].h > cache.pix_h) {
- break; /* should never happen */
- }
- pango_xft_render_layout(cache.draw, &state.fg, lines[i].layout, 0, cur_y * PANGO_SCALE);
- cur_y += lines[i].h;
- }
- cache.valid_height = cur_y;
- cache.start_offset = lines[start_line].y_offset;
- cache.begin_line = start_line;
- cache.dirty = 0;
-}
-
-static void
-redraw_cache_after_cur_line(void) {
-}
-
-static void
-redraw_cache_only_cur_line(void) {
-}
-
static void
insert_text(struct line *l, int index, char *text, int len) {
if (len == -1)
@@ -229,33 +193,35 @@ insert_text(struct line *l, int index, char *text, int len) {
l->len += len;
pango_layout_set_text(l->layout, l->text, l->len);
recalc_cur_line_size();
- cache.dirty = 1;
+ l->dirty = 1;
}
static void insert_line_entry(int index);
static void
-render_line(struct line *l) {
+render_line(int line) {
/* FIXME: check for <= 0 on size */
- /*
- if (l->pix == None) {
- l->pix = XCreatePixmap(state.dpy, state.back_buf, l->w + 10, l->h + 10, state.depth);
- l->pix_w = l->w + 10;
- l->pix_h = l->h + 10;
- l->draw = XftDrawCreate(state.dpy, l->pix, state.vis, state.cm);
- } else if (l->pix_w < l->w || l->pix_h < l->h) {
- int new_w = l->w > l->pix_w ? l->w + 10 : l->pix_w + 10;
- int new_h = l->h > l->pix_h ? l->h + 10 : l->pix_h + 10;
- XFreePixmap(state.dpy, l->pix);
- l->pix = XCreatePixmap(state.dpy, state.back_buf, new_w, new_h, state.depth);
- l->pix_w = new_w;
- l->pix_h = new_h;
- XftDrawChange(l->draw, l->pix);
- }
- XftDrawRect(l->draw, &state.bg, 0, 0, l->w, l->h);
- pango_xft_render_layout(l->draw, &state.fg, l->layout, 0, 0);
+ struct line *l = &lines[line];
+ if (l->cache_index == -1)
+ assign_free_cache_index(line);
+ struct cache_pixmap *pix = &cache.entries[l->cache_index];
+ if (pix->pixmap == None) {
+ pix->pixmap = XCreatePixmap(state.dpy, state.back_buf, l->w + 10, l->h + 10, state.depth);
+ pix->w = l->w + 10;
+ pix->h = l->h + 10;
+ pix->draw = XftDrawCreate(state.dpy, pix->pixmap, state.vis, state.cm);
+ } else if (pix->w < l->w || pix->h < l->h) {
+ int new_w = l->w > pix->w ? l->w + 10 : pix->w + 10;
+ int new_h = l->h > pix->h ? l->h + 10 : pix->h + 10;
+ XFreePixmap(state.dpy, pix->pixmap);
+ pix->pixmap = XCreatePixmap(state.dpy, state.back_buf, new_w, new_h, state.depth);
+ pix->w = new_w;
+ pix->h = new_h;
+ XftDrawChange(pix->draw, pix->pixmap);
+ }
+ XftDrawRect(pix->draw, &state.bg, 0, 0, l->w, l->h);
+ pango_xft_render_layout(pix->draw, &state.fg, l->layout, 0, 0);
l->dirty = 0;
- */
}
static void
@@ -274,7 +240,6 @@ append_line(int text_index, int line_index) {
if (text_index != -1) {
struct line *l = &lines[line_index];
int len = l->len - text_index;
- //new_l->pix = None;
new_l->len = len;
new_l->cap = len + 10;
new_l->text = malloc(new_l->cap);
@@ -328,11 +293,13 @@ set_line_cursor_attrs(int line, int index) {
} else {
pango_layout_set_attributes(lines[line].layout, basic_attrs);
}
+ lines[line].dirty = 1;
}
static void
wipe_line_cursor_attrs(int line) {
pango_layout_set_attributes(lines[line].layout, basic_attrs);
+ lines[line].dirty = 1;
}
static void
@@ -477,34 +444,16 @@ mainloop(void) {
XSetForeground(state.dpy, state.gc, state.bg.pixel);
XFillRectangle(state.dpy, state.back_buf, state.gc, 0, 0, state.w, state.h);
int h = 0;
- if (cache.dirty)
- redraw_cache_complete(CACHE_BOTH);
+
/*int cur_line_height = 0;*/
- /*
int tmp_w, tmp_h;
int cur_line_y = 0;
int cursor_displayed = 0;
for (int i = 0; i < lines_num; i++) {
- if (lines[i].dirty) {
- if (i == cur_line && cur_mode == NORMAL) {
- PangoAttribute *attr0 = pango_attr_background_new(0, 0, 0);
- PangoAttribute *attr1 = pango_attr_foreground_new(65535, 65535, 65535);
- attr0->start_index = cur_index;
- attr0->end_index = cur_index + 1;
- attr1->start_index = cur_index;
- attr1->end_index = cur_index + 1;
- PangoAttribute *attr2 = pango_attr_insert_hyphens_new(FALSE);
- PangoAttrList *list = pango_attr_list_new();
- pango_attr_list_insert(list, attr0);
- pango_attr_list_insert(list, attr1);
- pango_attr_list_insert(list, attr2);
- pango_layout_set_attributes(lines[cur_line].layout, list);
- } else {
- pango_layout_set_attributes(lines[i].layout, basic_attrs);
- }
- render_line(&lines[i]);
- }
if (h + lines[i].h > cur_display_offset) {
+ if (lines[i].dirty || lines[i].cache_index == -1) {
+ render_line(i);
+ }
int final_y = 0;
int dest_y = h - cur_display_offset;
int final_h = lines[i].h;
@@ -516,7 +465,7 @@ mainloop(void) {
if (dest_y + final_h > state.h) {
final_h -= final_y + final_h - cur_display_offset - state.h;
}
- XCopyArea(state.dpy, lines[i].pix, state.back_buf, state.gc, 0, final_y, lines[i].w, final_h, 0, dest_y);
+ XCopyArea(state.dpy, cache.entries[lines[i].cache_index].pixmap, state.back_buf, state.gc, 0, final_y, lines[i].w, final_h, 0, dest_y);
if (i == cur_line) {
cur_line_y = h - cur_display_offset;
cursor_displayed = 1;
@@ -526,32 +475,25 @@ mainloop(void) {
break;
h += lines[i].h;
}
- */
- double offset = cur_display_offset - cache.start_offset;
- if (offset < 0) {
- printf("FIX THIS CODE 3!\n");
- offset = 0;
- }
- XCopyArea(state.dpy, cache.pix, state.back_buf, state.gc, 0, (int)offset, state.w - 10, state.h, 0, 0);
need_redraw = 0;
XSetForeground(state.dpy, state.gc, state.fg.pixel);
PangoRectangle strong, weak;
pango_layout_get_cursor_pos(lines[cur_line].layout, cur_index, &strong, &weak);
/* FIXME: long, int, etc. */
- long cursor_y = strong.y / PANGO_SCALE + lines[cur_line].y_offset;
- if (cursor_y >= cur_display_offset && cursor_y < cur_display_offset + state.h) {
+ int cursor_y = strong.y / PANGO_SCALE + cur_line_y;
+ if (cursor_displayed && cursor_y >= 0) {
if (cur_mode == NORMAL && cur_index == lines[cur_line].len) {
XFillRectangle(
state.dpy, state.back_buf, state.gc,
- strong.x / PANGO_SCALE, cursor_y - (long)cur_display_offset,
+ strong.x / PANGO_SCALE, cursor_y,
10, strong.height / PANGO_SCALE
);
} else if (cur_mode == INSERT) {
XDrawLine(
state.dpy, state.back_buf, state.gc,
- strong.x / PANGO_SCALE, cursor_y - (long)cur_display_offset,
- strong.x / PANGO_SCALE, (strong.y + strong.height) / PANGO_SCALE + lines[cur_line].y_offset - (long)cur_display_offset
+ strong.x / PANGO_SCALE, cursor_y,
+ strong.x / PANGO_SCALE, (strong.y + strong.height) / PANGO_SCALE + cur_line_y
);
}
}
@@ -630,10 +572,7 @@ setup(int argc, char *argv[]) {
InputOutput, state.vis, CWBackPixel | CWColormap | CWBitGravity, &attrs);
state.back_buf = XdbeAllocateBackBufferName(state.dpy, state.win, XdbeBackground);
- cache.pix = XCreatePixmap(state.dpy, state.back_buf, 500, 500, state.depth);
- cache.pix_w = cache.pix_h = 500;
- cache.draw = XftDrawCreate(state.dpy, cache.pix, state.vis, state.cm);
- cache.dirty = 1;
+ init_cache();
memset(&gcv, 0, sizeof(gcv));
gcv.line_width = 1;
@@ -695,10 +634,8 @@ ensure_cursor_shown(void) {
long cursor_y = strong.y / PANGO_SCALE + lines[cur_line].y_offset;
if (cursor_y < cur_display_offset) {
cur_display_offset = cursor_y;
- cache.dirty = 1;
} else if (cursor_y + strong.height / PANGO_SCALE > cur_display_offset + state.h) {
cur_display_offset = cursor_y - state.h + strong.height / PANGO_SCALE;
- cache.dirty = 1;
}
}
@@ -755,16 +692,9 @@ resize_window(int w, int h) {
lines[i].h = tmp_h;
lines[i].w = tmp_w;
lines[i].y_offset = total_height;
+ lines[i].dirty = 1;
total_height += tmp_h;
}
- if (cache.pix_w < state.w - 10 || cache.pix_h < state.h + 2 * MAX_CACHE_PIXELS) {
- XFreePixmap(state.dpy, cache.pix);
- cache.pix = XCreatePixmap(state.dpy, state.back_buf, state.w, state.h + 2 * MAX_CACHE_PIXELS + 50, state.depth);
- cache.pix_w = state.w;
- cache.pix_h = state.h + 2 * MAX_CACHE_PIXELS + 50;
- XftDrawChange(cache.draw, cache.pix);
- }
- cache.dirty = 1;
}
static void
@@ -804,7 +734,6 @@ backspace(void) {
pango_layout_set_text(l->layout, l->text, l->len);
}
set_line_cursor_attrs(cur_line, cur_index);
- cache.dirty = 1;
recalc_cur_line_size();
}
@@ -831,7 +760,6 @@ delete_key(void) {
pango_layout_set_text(l->layout, l->text, l->len);
}
set_line_cursor_attrs(cur_line, cur_index);
- cache.dirty = 1;
recalc_cur_line_size();
}
@@ -858,7 +786,6 @@ move_cursor(int dir) {
cur_index = lines[cur_line].len;
}
set_line_cursor_attrs(cur_line, cur_index);
- cache.dirty = 1;
}
static void
@@ -879,7 +806,6 @@ return_key(void) {
wipe_line_cursor_attrs(cur_line);
cur_line++;
set_line_cursor_attrs(cur_line, cur_index);
- cache.dirty = 1;
cur_index = 0;
recalc_line_size_absolute();
}
@@ -899,7 +825,6 @@ escape_key(void) {
cursor_left();
}
set_line_cursor_attrs(cur_line, cur_index);
- cache.dirty = 1;
/*
if (cur_index > 0)
cursor_left();
@@ -915,7 +840,6 @@ i_key(void) {
}
*/
wipe_line_cursor_attrs(cur_line);
- cache.dirty = 1;
}
static void
@@ -946,7 +870,6 @@ line_down(void) {
if (cur_index > 0 && cur_mode == NORMAL && cur_index >= lines[cur_line].len)
cursor_left();
set_line_cursor_attrs(cur_line, cur_index);
- cache.dirty = 1;
}
static void
@@ -977,14 +900,12 @@ line_up(void) {
if (cur_index > 0 && cur_mode == NORMAL && cur_index >= lines[cur_line].len)
cursor_left();
set_line_cursor_attrs(cur_line, cur_index);
- cache.dirty = 1;
}
static void
zero_key(void) {
cur_index = 0;
set_line_cursor_attrs(cur_line, cur_index);
- cache.dirty = 1;
}
static struct key keys_en[] = {