ltkx

GUI toolkit for X11 (WIP)
git clone git://lumidify.org/ltkx.git
Log | Files | Refs | README | LICENSE

commit 30f6302a0a754c310140abbb88f467492586be68
parent e6a8ecf9116eb9cec8ed1da33d69c91988f55e86
Author: lumidify <nobody@lumidify.org>
Date:   Thu, 14 May 2020 15:35:58 +0200

Fix and add bugs

Diffstat:
Marray.h | 5++++-
Mltkx.h | 2++
Mtest1.c | 19++++++++++---------
Mtext-hb.c | 2--
Mtext_buffer.c | 131++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Mtext_buffer.h | 1-
Mtext_edit.c | 9+++++++--
7 files changed, 106 insertions(+), 63 deletions(-)

diff --git a/array.h b/array.h @@ -58,6 +58,7 @@ ltk_array_create_##name(size_t initial_len) { \ if (!ar->buf) goto error; \ ar->buf_size = initial_len; \ ar->len = 0; \ + return ar; \ error: \ (void)fprintf(stderr, "Out of memory while trying to allocate array\n"); \ exit(1); \ @@ -120,7 +121,7 @@ ltk_array_resize_##name(struct ltk_array_##name *ar, size_t len) { \ } else { \ return; \ } \ - type *new = realloc(ar->buf, new_size); \ + type *new = realloc(ar->buf, new_size * sizeof(type)); \ if (!new) { \ (void)fprintf(stderr, "Cannot realloc array\n"); \ exit(1); \ @@ -132,7 +133,9 @@ ltk_array_resize_##name(struct ltk_array_##name *ar, size_t len) { \ \ void \ ltk_array_destroy_##name(struct ltk_array_##name *ar) { \ + printf("%p %p %d\n", ar->buf, ar, ar->buf_size); \ free(ar->buf); \ + ar->buf = NULL; \ free(ar); \ } diff --git a/ltkx.h b/ltkx.h @@ -12,3 +12,5 @@ #include "text-hb.h" #include "button.h" #include "grid.h" +#include "array.h" +#include "text_edit.h" diff --git a/test1.c b/test1.c @@ -25,17 +25,18 @@ int main(int argc, char *argv[]) ltk_set_column_weight(grid1, 0, 1); ltk_set_column_weight(grid1, 1, 1); /* Test callback functions */ - LtkButton *button1 = ltk_create_button(window1, "I'm a button!", &bob1); - ltk_grid_widget(button1, grid1, 0, 0, 1, 1, LTK_STICKY_LEFT | LTK_STICKY_RIGHT); + //LtkButton *button1 = ltk_create_button(window1, "I'm a button!", &bob1); + //ltk_grid_widget(button1, grid1, 0, 0, 1, 1, LTK_STICKY_LEFT | LTK_STICKY_RIGHT); /* Test manual callback functions */ - LtkButton *button2 = ltk_create_button(window1, "I'm a button!", NULL); - button2->widget.mouse_release = &bob2; - ltk_grid_widget(button2, grid1, 0, 1, 1, 1, LTK_STICKY_TOP | LTK_STICKY_BOTTOM); - LtkButton *button3 = ltk_create_button(window1, "I'm a button!", NULL); - ltk_grid_widget(button3, grid1, 1, 0, 1, 1, LTK_STICKY_TOP | LTK_STICKY_BOTTOM | LTK_STICKY_RIGHT); + //LtkButton *button2 = ltk_create_button(window1, "I'm a button!", NULL); + //button2->widget.mouse_release = &bob2; + //ltk_grid_widget(button2, grid1, 0, 1, 1, 1, LTK_STICKY_TOP | LTK_STICKY_BOTTOM); + //LtkButton *button3 = ltk_create_button(window1, "I'm a button!", NULL); + //ltk_grid_widget(button3, grid1, 1, 0, 1, 1, LTK_STICKY_TOP | LTK_STICKY_BOTTOM | LTK_STICKY_RIGHT); //LtkButton *button4 = ltk_create_button(window1, "I'm a button!", NULL); - LtkButton *button4 = ltk_create_button(window1, "ہمارے بارے میں blablabla", NULL); + //LtkButton *button4 = ltk_create_button(window1, "ہمارے بارے میں blablabla", NULL); //LtkButton *button4 = ltk_create_button(window1, "پَیدایش", NULL); - ltk_grid_widget(button4, grid1, 1, 1, 1, 1, LTK_STICKY_LEFT | LTK_STICKY_BOTTOM); + LtkTextEdit *edit = ltk_create_text_edit(window1, "ہمارے بارے میں blablabla"); + ltk_grid_widget(edit, grid1, 1, 1, 1, 1, LTK_STICKY_LEFT | LTK_STICKY_BOTTOM); ltk_mainloop(); } diff --git a/text-hb.c b/text-hb.c @@ -365,7 +365,6 @@ ltk_render_text_line( int is_hor = HB_DIRECTION_IS_HORIZONTAL(ts->dir); do { if (is_hor) { - printf("%d\n", ts->start_x); y = tl->h - tl->y_max; ltk_render_text_segment(ts, x + ts->start_x, y, img, fg); x += ts->w; @@ -396,7 +395,6 @@ ltk_render_text_segment( do { x = x_cur + glyph->info->xoff + glyph->x_offset; y = y_cur + glyph->info->yoff - glyph->y_offset; - printf("%d %d; %d %d\n", x, y, glyph->x_abs, glyph->y_abs); for (int i = 0; i < glyph->info->h; i++) { for (int j = 0; j < glyph->info->w; j++) { b = (y + i) * img->bytes_per_line + (x + j) * 4; diff --git a/text_buffer.c b/text_buffer.c @@ -60,30 +60,53 @@ ltk_render_text_line_new( XColor bg) { XImage *img; - int cur_x = 0, cur_y = 0; int par_is_rtl = FRIBIDI_IS_RTL(tl->dir); + int cur_y = 0; + int cur_x = par_is_rtl ? max_width : 0; ltk_array_clear_int(tl->wrap_indeces); ltk_array_append_int(tl->wrap_indeces, 0); /* FIXME: wrap bidi text properly */ + /* FIXME: THIS IS UGLY */ struct ltk_text_run *cur = tl->first_run; do { - for (int i = 0; i < cur->num_glyphs; i++) { - cur_x += cur->glyphs[i].x_advance; - if (cur_x > max_width) { - int j = 0; - for (j = i; j >= 0; j--) { - if (cur->glyphs[j].cluster != cur->glyphs[i].cluster) { - /* must increase one again so the actual - next character is used */ - j++; - break; + if (par_is_rtl) { + for (int i = cur->num_glyphs - 1; i >= 0; i--) { + cur_x -= cur->glyphs[i].x_advance; + if (cur_x < 0) { + int j = 0; + for (j = i; j < cur->num_glyphs; j++) { + if (cur->glyphs[j].cluster != cur->glyphs[i].cluster) { + /* must decrease one again so the actual + last character is used */ + j--; + break; + } } + i = j; + /* FIXME: handle case that this is the same as the last index */ + ltk_array_append_int(tl->wrap_indeces, cur->glyphs[i].cluster); + cur_x = max_width; + } + } + } else { + for (int i = 0; i < cur->num_glyphs; i++) { + cur_x += cur->glyphs[i].x_advance; + if (cur_x > max_width) { + int j = 0; + for (j = i; j >= 0; j--) { + if (cur->glyphs[j].cluster != cur->glyphs[i].cluster) { + /* must increase one again so the actual + next character is used */ + j++; + break; + } + } + i = j; + /* FIXME: handle case that this is the same as the last index */ + ltk_array_append_int(tl->wrap_indeces, cur->glyphs[i].cluster); + cur_x = 0; } - i = j; - /* FIXME: handle case that this is the same as the last index */ - ltk_array_append_int(tl->wrap_indeces, cur->glyphs[i].cluster); - cur_x = 0; } } } while (cur = cur->next); @@ -91,9 +114,11 @@ ltk_render_text_line_new( XWindowAttributes attrs; XGetWindowAttributes(dpy, window, &attrs); int depth = attrs.depth; + printf("%d --- %d\n", max_width, tl->h * tl->wrap_indeces->len); img = XCreateImage(dpy, CopyFromParent, depth, ZPixmap, 0, NULL, max_width, tl->h * tl->wrap_indeces->len, 32, 0); img->data = calloc(img->bytes_per_line, img->height); XInitImage(img); + printf("%d +++ %d\n", img->width, img->height); int b; for (int i = 0; i < tl->h * tl->wrap_indeces->len; i++) { @@ -112,20 +137,33 @@ ltk_render_text_line_new( int cur_line_x = 0; int cur_line = 0; LtkGlyph *glyph; - /* FIXME: Ints are compared with size_t's in various places. Maybe I should fix that. */ + /* FIXME: ints are compared with size_t's in various places. Maybe I should fix that. */ /* FIXME: how should an empty line be handled? This doesn't use a do-for loop in case tl->first_run is NULL, but I should probably decide what to do in that case */ + int index; while (cur) { - for (int k = 0; k < cur->len; k++) { + for (int k = 0; k < cur->num_glyphs; k++) { + index = par_is_rtl ? cur->num_glyphs - k - 1 : k; glyph = &cur->glyphs[k]; if (cur_line < tl->wrap_indeces->len - 1 && - glyph->cluster >= tl->wrap_indeces->buf[cur_line + 1]) { + ((!par_is_rtl && glyph->cluster >= tl->wrap_indeces->buf[cur_line + 1]) || + (par_is_rtl && glyph->cluster <= tl->wrap_indeces->buf[cur_line + 1]))) { cur_line++; cur_line_x += glyph->x_abs - cur_line_x; } - x = glyph->x_abs - cur_line_x; + x = par_is_rtl ? max_width - (glyph->x_abs - cur_line_x) - glyph->info->w: glyph->x_abs - cur_line_x; y = glyph->y_abs + tl->h * cur_line; + printf("%d,%d\n", x, y); + fflush(stdout); + if (x < 0) + x = 0; + if (x > max_width - glyph->info->w) + x = max_width - glyph->info->w; + if (y < 0) + y = 0; + if (y > img->height - glyph->info->h) + y = img->height - glyph->info->h; for (int i = 0; i < glyph->info->h; i++) { for (int j = 0; j < glyph->info->w; j++) { b = (y + i) * img->bytes_per_line + (x + j) * 4; @@ -138,6 +176,7 @@ ltk_render_text_line_new( } cur = cur->next; } + return img; } /* Begin stuff stolen from raqm */ @@ -280,8 +319,8 @@ ltk_text_run_create(size_t start_index, size_t len, hb_script_t script, hb_direc run->len = len; run->script = script; run->dir = dir; - run->last = NULL; run->next = NULL; + return run; } static void @@ -289,6 +328,7 @@ ltk_text_line_itemize(struct ltk_text_line *tl) { ltk_resolve_scripts(tl); struct ltk_text_run *first_run = NULL; struct ltk_text_run *cur_run = NULL; + struct ltk_text_run *new = NULL; FriBidiLevel last_level; FriBidiLevel cur_level; hb_script_t last_script; @@ -310,27 +350,22 @@ ltk_text_line_itemize(struct ltk_text_line *tl) { dir = HB_DIRECTION_LTR; if (FRIBIDI_LEVEL_IS_RTL(last_level)) dir = HB_DIRECTION_RTL; - struct ltk_text_run *new = ltk_text_run_create( + new = ltk_text_run_create( start_index, end_index - start_index, last_script, dir); if (!first_run) { - first_run = cur_run = new; + first_run = new; } else { - if (par_is_rtl) { + if (par_is_rtl) new->next = cur_run; - cur_run->last = new; - } else { + else cur_run->next = new; - new->last = cur_run; - } - cur_run = new; } + cur_run = new; start_index = end_index; } - tl->first_run = tl->cur_run = first_run; - tl->last_run = cur_run; + tl->first_run = par_is_rtl ? cur_run : first_run; } -/* FIXME: return start_x, etc. instead of saving in struct text run */ static void ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr, struct ltk_text_line *tl, uint16_t font_size, uint16_t font_id, int *ret_y_max) { @@ -338,6 +373,7 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr, khint_t k; tr->font_id = font_id; + tr->font_size = font_size; uint32_t attr = font_id << 16 + font_size; /* FIXME: turn this into ltk_get_glyph_cache */ k = kh_get(glyphcache, tm->glyph_cache, attr); @@ -355,7 +391,7 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr, hb_buffer_set_direction(buf, tr->dir); hb_buffer_set_script(buf, tr->script); /* WARNING: vis_buf has to be normalized (without gap) for this! */ - hb_buffer_add_codepoints(buf, tl->vis_buf, tl->len, tr->start_index, tr->len); + hb_buffer_add_codepoints(buf, tl->vis_buf->buf, tl->len, tr->start_index, tr->len); /* According to https://harfbuzz.github.io/the-distinction-between-levels-0-and-1.html * this should be level 1 clustering instead of level 0 */ hb_buffer_set_cluster_level(buf, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS); @@ -392,14 +428,6 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr, /* Calculate position in order to determine full size of text segment */ x1_abs = x_abs + glyph->info->xoff + glyph->x_offset; y1_abs = y_abs + glyph->info->yoff - glyph->y_offset; - /* Okay, wait, so should I check if the script is horizontal, and then add - x_advance instead of glyph->info->w? It seems that the glyph width is - usually smaller than x_advance, and spaces etc. are completely lost - because their glyph width is 0. I have to distinguish between horizontal - and vertical scripts, though because to calculate the maximum y position - for horizontal scripts, I still need to use the glyph height since - y_advance doesn't really do much there. I dunno, at least *something* - works now... */ /* FIXME: THIS PROBABLY DOESN'T REALLY WORK */ if (HB_DIRECTION_IS_HORIZONTAL(tr->dir)) { x2_abs = x1_abs + glyph->x_advance; @@ -434,11 +462,12 @@ ltk_text_line_shape(LtkTextManager *tm, struct ltk_text_line *tl) { FcPattern *pat = FcPatternDuplicate(tm->fcpattern); FcPattern *match; FcResult result; + printf("%p\n", pat); FcPatternAddBool(pat, FC_SCALABLE, 1); FcConfigSubstitute(NULL, pat, FcMatchPattern); FcDefaultSubstitute(pat); FcCharSet *cs = FcCharSetCreate(); - for (int i = run->start_index; i < run->start_index + run->len; i++) { + for (size_t i = run->start_index; i < run->start_index + run->len; i++) { FcCharSetAddChar(cs, tl->vis_buf->buf[i]); } FcPatternAddCharSet(pat, FC_CHARSET, cs); @@ -448,6 +477,7 @@ ltk_text_line_shape(LtkTextManager *tm, struct ltk_text_line *tl) { uint16_t font_id = ltk_get_font(tm, file); khint_t k = kh_get(fontstruct, tm->font_cache, font_id); run->font = kh_value(tm->font_cache, k); + fflush(stdout); FcPatternDestroy(match); FcPatternDestroy(pat); ltk_text_run_shape(tm, run, tl, tl->font_size, font_id, &y_max); @@ -488,7 +518,7 @@ ltk_text_run_destroy(struct ltk_text_run *tr) { khint_t k; k = kh_get(glyphinfo, ltk_global->tm->glyph_cache, tr->font_id << 16 + tr->font_size); gcache = kh_value(ltk_global->tm->glyph_cache, k); - for (int i = 0; i < tr->len; i++) { + for (int i = 0; i < tr->num_glyphs; i++) { glyph = &tr->glyphs[i]; if (--glyph->info->refs < 1) { k = kh_get(glyphinfo, gcache, glyph->info->id); @@ -508,23 +538,25 @@ ltk_text_run_destroy(struct ltk_text_run *tr) { void ltk_text_line_destroy_runs(struct ltk_text_run *runs) { - struct ltk_text_run *cur, *last; + struct ltk_text_run *cur, *next; cur = runs; while (cur) { - last = cur; + next = cur->next; ltk_text_run_destroy(cur); - cur = last->next; + cur = next; } } static void ltk_text_line_recalculate(LtkTextManager *tm, struct ltk_text_line *tl) { + printf("%d,%d,%d,%d,%d\n", tl->log_buf->buf_size, tl->vis_buf->buf_size, tl->log2vis->buf_size, tl->vis2log->buf_size, tl->bidi_levels->buf_size); fribidi_log2vis( - tl->log_buf, tl->log_buf->len, - &tl->dir, tl->vis_buf, tl->log2vis, tl->vis2log, tl->bidi_levels + tl->log_buf->buf, tl->log_buf->len, + &tl->dir, tl->vis_buf->buf, tl->log2vis->buf, tl->vis2log->buf, tl->bidi_levels->buf ); struct ltk_text_run *old_runs = tl->first_run; ltk_text_line_itemize(tl); + struct ltk_text_run *cur = tl->first_run; ltk_text_line_shape(tm, tl); /* this needs to be done after shaping so the fonts, etc. aren't removed if their reference counts drop and then loaded again @@ -547,7 +579,7 @@ ltk_text_line_insert_text(struct ltk_text_line *tl, uint32_t *text, size_t len) tl->len += len; tl->cursor_pos += len; /* FIXME: Why am I passing tm? It's global anyways */ - ltk_text_line_recalculate(tl, ltk_global->tm); + ltk_text_line_recalculate(ltk_global->tm, tl); } /* must be NULL-terminated */ @@ -584,6 +616,9 @@ ltk_text_line_create(void) { line->dir = FRIBIDI_TYPE_ON; line->len = 0; line->cursor_pos = 0; + /* FIXME */ + line->font_size = 15; + return line; error: (void)fprintf(stderr, "No memory left while creating text line\n"); exit(1); diff --git a/text_buffer.h b/text_buffer.h @@ -42,7 +42,6 @@ struct ltk_text_run { LtkGlyph *glyphs; unsigned int num_glyphs; struct ltk_text_run *next; - struct ltk_text_run *last; size_t start_index; size_t len; /* FIXME: THIS IS NOT THE NUMBER OF GLYPHS; IT IS THE ACTUAL NUMBER OF CHARACTERS REPRESENTED BY THIS RUN */ int start_x; diff --git a/text_edit.c b/text_edit.c @@ -34,6 +34,7 @@ #include "array.h" #include "text_buffer.h" #include "text_edit.h" +#include "grid.h" extern Ltk *ltk_global; @@ -44,8 +45,11 @@ ltk_draw_text_edit(LtkTextEdit *te) { LtkRect rect = te->widget.rect; LtkWindow *window = te->widget.window; if (!te->img) - ltk_render_text_line_new(te->tl, rect.w, ltk_global->display, window->xwindow, window->gc, ltk_global->colormap, fg, bg); - XPutImage(ltk_global->display, window->xwindow, window->gc, te->img, 0, 0, rect.x, rect.y, te->tl->w, te->tl->h); + te->img = ltk_render_text_line_new(te->tl, rect.w, ltk_global->display, window->xwindow, window->gc, ltk_global->colormap, fg, bg); + printf("%p\n", te->img); + fflush(stdout); + printf("%d,%d;%d,%d;%d,%d\n", rect.x, rect.y, rect.w, rect.h, te->img->width, te->img->height); + XPutImage(ltk_global->display, window->xwindow, window->gc, te->img, 0, 0, rect.x, rect.y, te->img->width, te->img->height); } LtkTextEdit *ltk_create_text_edit(LtkWindow *window, const char *text) { @@ -56,6 +60,7 @@ LtkTextEdit *ltk_create_text_edit(LtkWindow *window, const char *text) { te->tl = ltk_text_line_create(); ltk_text_line_insert_utf8(te->tl, text); te->img = NULL; + return te; } void ltk_destroy_text_edit(LtkTextEdit *te) { ltk_text_line_destroy(te->tl);