URI: 
       tFix and add bugs - ltkx - GUI toolkit for X11 (WIP)
  HTML git clone git://lumidify.org/ltkx.git
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 30f6302a0a754c310140abbb88f467492586be68
   DIR parent e6a8ecf9116eb9cec8ed1da33d69c91988f55e86
  HTML Author: lumidify <nobody@lumidify.org>
       Date:   Thu, 14 May 2020 15:35:58 +0200
       
       Fix and add bugs
       
       Diffstat:
         M array.h                             |       5 ++++-
         M ltkx.h                              |       2 ++
         M test1.c                             |      19 ++++++++++---------
         M text-hb.c                           |       2 --
         M text_buffer.c                       |     131 ++++++++++++++++++++-----------
         M text_buffer.h                       |       1 -
         M text_edit.c                         |       9 +++++++--
       
       7 files changed, 106 insertions(+), 63 deletions(-)
       ---
   DIR diff --git a/array.h b/array.h
       t@@ -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);                                                                        \
       t@@ -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);                                                                \
       t@@ -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);                                                                        \
        }
        
   DIR diff --git a/ltkx.h b/ltkx.h
       t@@ -12,3 +12,5 @@
        #include "text-hb.h"
        #include "button.h"
        #include "grid.h"
       +#include "array.h"
       +#include "text_edit.h"
   DIR diff --git a/test1.c b/test1.c
       t@@ -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();
        }
   DIR diff --git a/text-hb.c b/text-hb.c
       t@@ -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;
       t@@ -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;
   DIR diff --git a/text_buffer.c b/text_buffer.c
       t@@ -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);
       t@@ -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++) {
       t@@ -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;
       t@@ -138,6 +176,7 @@ ltk_render_text_line_new(
                        }
                        cur = cur->next;
                }
       +        return img;
        }
        
        /* Begin stuff stolen from raqm */
       t@@ -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
       t@@ -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;
       t@@ -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) {
       t@@ -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);
       t@@ -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);
       t@@ -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;
       t@@ -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);
       t@@ -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);
       t@@ -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);
       t@@ -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
       t@@ -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 */
       t@@ -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);
   DIR diff --git a/text_buffer.h b/text_buffer.h
       t@@ -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;
   DIR diff --git a/text_edit.c b/text_edit.c
       t@@ -34,6 +34,7 @@
        #include "array.h"
        #include "text_buffer.h"
        #include "text_edit.h"
       +#include "grid.h"
        
        extern Ltk *ltk_global;
        
       t@@ -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) {
       t@@ -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);