ltkx

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

commit e6a8ecf9116eb9cec8ed1da33d69c91988f55e86
parent 1242d3b3fcdb252a60c422b8eb15396e641fd656
Author: lumidify <nobody@lumidify.org>
Date:   Thu, 14 May 2020 11:37:48 +0200

Switch from gap buffers to arrays

Diffstat:
MMakefile | 2+-
Marray.h | 39+++++++++++++++++++++++++++++++++++++++
Mtext_buffer.c | 187+++++++++++++++++++++++++++----------------------------------------------------
Mtext_buffer.h | 26+++++++++++++++-----------
Mtext_edit.c | 20++++++++++++++++++--
Mtext_edit.h | 6++++++
6 files changed, 143 insertions(+), 137 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,7 +1,7 @@ LIBS = -lm `pkg-config --libs x11 harfbuzz fontconfig fribidi` STD = -std=c99 CFLAGS = -g -w -fcommon -Wall -Werror -Wextra `pkg-config --cflags x11 harfbuzz fontconfig fribidi` -pedantic -OBJ = stb_truetype.o text-common.o text_buffer.o text-hb.o ltk.o ini.o grid.o button.o test1.o +OBJ = stb_truetype.o text_edit.o text-common.o text_buffer.o text-hb.o ltk.o ini.o grid.o button.o test1.o test1: $(OBJ) gcc $(STD) -o $@ $(OBJ) $(LIBS) diff --git a/array.h b/array.h @@ -33,7 +33,13 @@ struct ltk_array_##name { \ size_t buf_size; \ size_t len; \ }; \ + \ struct ltk_array_##name *ltk_array_create_##name(size_t initial_len); \ +type ltk_array_pop_##name(struct ltk_array_##name *ar); \ +void ltk_array_prepare_gap_##name( \ + struct ltk_array_##name *ar, size_t index, size_t len); \ +void ltk_array_insert_##name(struct ltk_array_##name *ar, size_t index, \ + type *elem, size_t len); \ void ltk_array_resize_##name(struct ltk_array_##name *ar, size_t size); \ void ltk_array_destroy_##name(struct ltk_array_##name *ar); \ void ltk_array_clear_##name(struct ltk_array_##name *ar); \ @@ -57,6 +63,39 @@ error: \ exit(1); \ } \ \ +type \ +ltk_array_pop_##name(struct ltk_array_##name *ar) { \ + if (ar->len == 0) { \ + (void)fprintf(stderr, "Array empty; cannot pop.\n"); \ + exit(1); \ + } \ + ar->len--; \ + return ar->buf[ar->len]; \ +} \ + \ +void \ +ltk_array_prepare_gap_##name(struct ltk_array_##name *ar, size_t index, size_t len) { \ + if (index > ar->len) { \ + (void)fprintf(stderr, "Array index out of bounds\n"); \ + exit(1); \ + } \ + ltk_array_resize_##name(ar, ar->len + len); \ + ar->len += len; \ + if (ar->len == index) \ + return; \ + memmove(ar->buf + index + len, ar->buf + index, ar->len - index); \ +} \ + \ +void \ +ltk_array_insert_##name(struct ltk_array_##name *ar, size_t index, \ + type *elem, size_t len) { \ + ltk_array_prepare_gap_##name(ar, index, len); \ + ltk_array_resize_##name(ar, ar->len + len); \ + for (int i = 0; i < len; i++) { \ + ar->buf[index + i] = elem[i]; \ + } \ +} \ + \ void \ ltk_array_append_##name(struct ltk_array_##name *ar, type elem) { \ if (ar->len == ar->buf_size) \ diff --git a/text_buffer.c b/text_buffer.c @@ -34,25 +34,21 @@ #include <harfbuzz/hb.h> #include <harfbuzz/hb-ot.h> #include "text-common.h" -#include "gap_buffer.h" #include "array.h" -#include "stack.h" #include "text_buffer.h" #include "ltk.h" extern Ltk *ltk_global; -LTK_GAP_BUFFER_INIT_IMPL(uint32, uint32_t) -LTK_GAP_BUFFER_INIT_IMPL(script, hb_script_t) -LTK_GAP_BUFFER_INIT_IMPL(int, int) +LTK_ARRAY_INIT_IMPL(uint32, uint32_t) +LTK_ARRAY_INIT_IMPL(script, hb_script_t) LTK_ARRAY_INIT_IMPL(level, FriBidiLevel) LTK_ARRAY_INIT_IMPL(int, int) -LTK_STACK_INIT_IMPL(script, int, hb_script_t, pair_index, script) /* based on http://codemadness.org/git/dwm-font/file/drw.c.html#l315 */ /* FIXME: rename this once everything is cleaned up (currently conflicts with the old render function */ -void +XImage * ltk_render_text_line_new( struct ltk_text_line *tl, int max_width, @@ -63,6 +59,7 @@ ltk_render_text_line_new( XColor fg, XColor bg) { + XImage *img; int cur_x = 0, cur_y = 0; int par_is_rtl = FRIBIDI_IS_RTL(tl->dir); ltk_array_clear_int(tl->wrap_indeces); @@ -91,21 +88,20 @@ ltk_render_text_line_new( } } while (cur = cur->next); - if (tl->img) XDestroyImage(tl->img); XWindowAttributes attrs; XGetWindowAttributes(dpy, window, &attrs); int depth = attrs.depth; - tl->img = XCreateImage(dpy, CopyFromParent, depth, ZPixmap, 0, NULL, max_width, tl->h * tl->wrap_indeces->len, 32, 0); - tl->img->data = calloc(tl->img->bytes_per_line, tl->img->height); - XInitImage(tl->img); + 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); int b; for (int i = 0; i < tl->h * tl->wrap_indeces->len; i++) { - b = tl->img->bytes_per_line * i; + b = img->bytes_per_line * i; for (int j = 0; j < max_width; j++) { - tl->img->data[b++] = bg.blue / 257; - tl->img->data[b++] = bg.green / 257; - tl->img->data[b++] = bg.red / 257; + img->data[b++] = bg.blue / 257; + img->data[b++] = bg.green / 257; + img->data[b++] = bg.red / 257; b++; } } @@ -132,11 +128,11 @@ ltk_render_text_line_new( y = glyph->y_abs + tl->h * cur_line; for (int i = 0; i < glyph->info->h; i++) { for (int j = 0; j < glyph->info->w; j++) { - b = (y + i) * tl->img->bytes_per_line + (x + j) * 4; + b = (y + i) * img->bytes_per_line + (x + j) * 4; a = glyph->info->alphamap[i * glyph->info->w + j] / 255.0; - tl->img->data[b] = (fg.blue * a + (1 - a) * (uint16_t)tl->img->data[b] * 257) / 257; - tl->img->data[b + 1] = (fg.green * a + (1 - a) * (uint16_t)tl->img->data[b + 1] * 257) / 257; - tl->img->data[b + 2] = (fg.red * a + (1 - a) * (uint16_t)tl->img->data[b + 2] * 257) / 257; + img->data[b] = (fg.blue * a + (1 - a) * (uint16_t)img->data[b] * 257) / 257; + img->data[b + 1] = (fg.green * a + (1 - a) * (uint16_t)img->data[b + 1] * 257) / 257; + img->data[b + 2] = (fg.red * a + (1 - a) * (uint16_t)img->data[b + 2] * 257) / 257; } } } @@ -144,31 +140,6 @@ ltk_render_text_line_new( } } -/* -NOTE: The following notes are outdated. -Notes: When inserting a character, check what the direction of the surrounding -script is - if it is the same (or a weak direction), then just insert the char -without re-doing the bidi algorithm. Only redo the whole line/paragraph is the -dir of the inserted character is different. Assume the text is LTR until a strong -character is inserted, i.e. the line should keep a flag if it already has a strong -dir set. -When reordering, the cursor needs to be kept in the right place: -a) The logical to visual mapping from FriBidi needs to be used to find the position -of the cursor in the text that gets passed to Harfbuzz. -b) The cluster values from Harfbuzz need to be used to figure out where the cursor -is on the screen. -Harfbuzz also should be given some context - maybe even completely reshape the -text until the last and next space? That would only be a problem with weird very -long words (mainly nonsense). At least maybe take up to five or so chars on each -side and pass even more with the optional context-passing feature for hb_shape. -Question: Does both the logical and visual text need to be stored? The logical text -is technically the master copy, but the visual text is what gets passed to harfbuzz. --> Actually, since the visual text has to be split into script runs anyways, maybe -just append text to that (and also add it to the master buffer simultaneously). As -soon as a different script is inserted, everything has to be redone anyways. Also, -when reshaping with context, only the text in the current run has to be passed at all. -*/ - /* Begin stuff stolen from raqm */ /* Special paired characters for script detection */ @@ -211,7 +182,7 @@ get_pair_index (const FriBidiChar ch) { return -1; } -#define STACK_IS_EMPTY(stack) ((stack)->size <= 0) +#define STACK_IS_EMPTY(stack) ((stack)->len <= 0) #define IS_OPEN(pair_index) (((pair_index) & 1) == 0) /* Resolve the script for each character in the input string, if the character @@ -225,50 +196,52 @@ ltk_resolve_scripts(struct ltk_text_line *tl) { int last_set_index = -1; hb_script_t last_script = HB_SCRIPT_INVALID; hb_script_t cur_script; - struct ltk_stack_script *stack = NULL; + struct ltk_array_script *script_stack = NULL; + struct ltk_array_int *pair_indeces = NULL; hb_unicode_funcs_t* unicode_funcs = hb_unicode_funcs_get_default(); - stack = ltk_stack_create_script(tl->len); + script_stack = ltk_array_create_script(4); + pair_indeces = ltk_array_create_int(4); for (int i = 0; i < (int) tl->len; i++) { - cur_script = ltk_gap_buffer_get_script(tl->scripts, i); + cur_script = tl->scripts->buf[i]; if (cur_script == HB_SCRIPT_COMMON && last_script_index != -1) { - int pair_index = get_pair_index(ltk_gap_buffer_get_uint32(tl->log_buf, i)); + int pair_index = get_pair_index(tl->log_buf->buf[i]); if (pair_index >= 0) { if (IS_OPEN (pair_index)) { /* is a paired character */ - ltk_gap_buffer_set_script(tl->scripts, i, last_script); + tl->scripts->buf[i] = last_script; last_set_index = i; - ltk_stack_push_script(stack, cur_script, pair_index); + ltk_array_append_script(script_stack, cur_script); + ltk_array_append_int(pair_indeces, pair_index); } else { /* is a close paired character */ /* find matching opening (by getting the last * even index for current odd index) */ - while (!STACK_IS_EMPTY(stack) && - stack->pair_index[stack->size] != (pair_index & ~1)) { - ltk_stack_pop_script(stack); + while (!STACK_IS_EMPTY(pair_indeces) && + pair_indeces->buf[pair_indeces->len-1] != (pair_index & ~1)) { + ltk_array_pop_script(script_stack); + ltk_array_pop_int(pair_indeces); } - if (!STACK_IS_EMPTY(stack)) { - ltk_gap_buffer_set_script( - tl->scripts, i, - ltk_stack_top2_script(stack, HB_SCRIPT_INVALID)); + if (!STACK_IS_EMPTY(script_stack)) { + tl->scripts->buf[i] = script_stack->buf[script_stack->len-1]; last_script = cur_script; last_set_index = i; } else { - ltk_gap_buffer_set_script(tl->scripts, i, last_script); + tl->scripts->buf[i] = last_script; last_set_index = i; } } } else { - ltk_gap_buffer_set_script(tl->scripts, i, last_script); + tl->scripts->buf[i] = last_script; last_set_index = i; } } else if (cur_script == HB_SCRIPT_INHERITED && last_script_index != -1) { - ltk_gap_buffer_set_script(tl->scripts, i, last_script); + tl->scripts->buf[i] = last_script; last_set_index = i; } else { for (int j = last_set_index + 1; j < i; ++j) - ltk_gap_buffer_set_script(tl->scripts, j, cur_script); + tl->scripts->buf[j] = cur_script; last_script = cur_script; last_script_index = i; last_set_index = i; @@ -281,14 +254,14 @@ ltk_resolve_scripts(struct ltk_text_line *tl) { */ hb_script_t scr; for (int i = tl->len - 2; i >= 0; --i) { - scr = ltk_gap_buffer_get_script(tl->scripts, i); + scr = tl->scripts->buf[i]; if (scr == HB_SCRIPT_INHERITED || scr == HB_SCRIPT_COMMON) { - ltk_gap_buffer_set_script(tl->scripts, i, - ltk_gap_buffer_get_script(tl->scripts, i + 1)); + tl->scripts->buf[i] = tl->scripts->buf[i + 1]; } } - ltk_stack_destroy_script(stack); + ltk_array_destroy_script(script_stack); + ltk_array_destroy_int(pair_indeces); return 1; } @@ -327,12 +300,12 @@ ltk_text_line_itemize(struct ltk_text_line *tl) { while (start_index < tl->len) { end_index = start_index; cur_level = last_level = tl->bidi_levels->buf[start_index]; - cur_script = last_script = ltk_gap_buffer_get_script(tl->scripts, start_index); + cur_script = last_script = tl->scripts->buf[start_index]; while (end_index < tl->len && cur_level == last_level && cur_script == last_script) { end_index++; cur_level = tl->bidi_levels->buf[end_index]; - cur_script = ltk_gap_buffer_get_script(tl->scripts, end_index); + cur_script = tl->scripts->buf[end_index]; } dir = HB_DIRECTION_LTR; if (FRIBIDI_LEVEL_IS_RTL(last_level)) @@ -466,7 +439,7 @@ ltk_text_line_shape(LtkTextManager *tm, struct ltk_text_line *tl) { FcDefaultSubstitute(pat); FcCharSet *cs = FcCharSetCreate(); for (int i = run->start_index; i < run->start_index + run->len; i++) { - FcCharSetAddChar(cs, ltk_gap_buffer_get_uint32(tl->vis_buf, i)); + FcCharSetAddChar(cs, tl->vis_buf->buf[i]); } FcPatternAddCharSet(pat, FC_CHARSET, cs); match = FcFontMatch(NULL, pat, &result); @@ -546,21 +519,10 @@ ltk_text_line_destroy_runs(struct ltk_text_run *runs) { static void ltk_text_line_recalculate(LtkTextManager *tm, struct ltk_text_line *tl) { - ltk_gap_buffer_clear_uint32(tl->vis_buf); - ltk_gap_buffer_clear_int(tl->log2vis); - ltk_gap_buffer_clear_int(tl->vis2log); - /* yeah, this is hacky */ - tl->vis_buf->len = tl->vis_buf->buf_size; - tl->log2vis->len = tl->log2vis->buf_size; - tl->vis2log->len = tl->vis2log->buf_size; - size_t gap_pos = tl->log_buf->gap_left; - size_t gap_end = tl->log_buf->buf_size - tl->log_buf->gap_size; - ltk_gap_buffer_move_gap_uint32(tl->log_buf, gap_end); fribidi_log2vis( - tl->log_buf, tl->log_buf->buf_size - tl->log_buf->gap_size, + tl->log_buf, tl->log_buf->len, &tl->dir, tl->vis_buf, tl->log2vis, tl->vis2log, tl->bidi_levels ); - ltk_gap_buffer_move_gap_uint32(tl->log_buf, gap_pos); struct ltk_text_run *old_runs = tl->first_run; ltk_text_line_itemize(tl); ltk_text_line_shape(tm, tl); @@ -573,38 +535,17 @@ ltk_text_line_recalculate(LtkTextManager *tm, struct ltk_text_line *tl) { void ltk_text_line_insert_text(struct ltk_text_line *tl, uint32_t *text, size_t len) { - /* check if any characters have a different script, only recalc then */ - /* - hb_unicode_funcs_t *uf= hb_unicode_funcs_get_default(); - struct ltk_text_run *run = tl->cur_run; - int recalc = 0; - hb_script_t script; - for (int i = 0; i < len; i++) { - scr = hb_unicode_script(uf, text[i]); - if (script != run->script && - script != HB_SCRIPT_INHERITED && - script != HB_SCRIPT_COMMON) { - recalc = 1; - } - } - */ - ltk_gap_buffer_insert_uint32(tl->log_buf, text, 0, len); - if (len > tl->scripts->gap_size) - ltk_gap_buffer_resize_gap_script(tl->scripts, len + 8); + ltk_array_insert_uint32(tl->log_buf, tl->cursor_pos, text, len); + ltk_array_prepare_gap_script(tl->scripts, tl->cursor_pos, len); hb_unicode_funcs_t *ufuncs = hb_unicode_funcs_get_default(); - for (int i = 0; i < len; i++) { - ltk_gap_buffer_insert_single_script( - tl->scripts, hb_unicode_script(ufuncs, text[i])); - } - if (len > tl->vis_buf->gap_size) - ltk_gap_buffer_resize_gap_uint32(tl->vis_buf, len + 8); - if (len > tl->log2vis->gap_size) - ltk_gap_buffer_resize_gap_int(tl->log2vis, len + 8); - if (len > tl->vis2log->gap_size) - ltk_gap_buffer_resize_gap_int(tl->vis2log, len + 8); - if (len + tl->bidi_levels->len > tl->bidi_levels->buf_size) - ltk_array_resize_level(tl->bidi_levels, tl->bidi_levels->len + len + 8); + for (int i = 0; i < len; i++) + tl->scripts->buf[tl->cursor_pos + i] = hb_unicode_script(ufuncs, text[i]); + ltk_array_resize_uint32(tl->vis_buf, tl->vis_buf->len + len); + ltk_array_resize_int(tl->log2vis, tl->log2vis->len + len); + ltk_array_resize_int(tl->vis2log, tl->vis2log->len + len); + ltk_array_resize_level(tl->bidi_levels, tl->bidi_levels->len + 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); } @@ -629,12 +570,12 @@ struct ltk_text_line * ltk_text_line_create(void) { struct ltk_text_line *line = malloc(sizeof(struct ltk_text_line)); if (!line) goto error; - line->log_buf = ltk_gap_buffer_create_uint32(); - line->scripts = ltk_gap_buffer_create_script(); - line->vis_buf = ltk_gap_buffer_create_uint32(); - line->log2vis = ltk_gap_buffer_create_int(); - line->vis2log = ltk_gap_buffer_create_int(); - line->bidi_levels = ltk_array_create_level(8); + line->log_buf = ltk_array_create_uint32(4); + line->vis_buf = ltk_array_create_uint32(4); + line->log2vis = ltk_array_create_int(4); + line->vis2log = ltk_array_create_int(4); + line->scripts = ltk_array_create_script(4); + line->bidi_levels = ltk_array_create_level(4); line->wrap_indeces = ltk_array_create_int(1); line->first_run = NULL; line->cur_run = NULL; @@ -642,6 +583,7 @@ ltk_text_line_create(void) { line->height = 0; line->dir = FRIBIDI_TYPE_ON; line->len = 0; + line->cursor_pos = 0; error: (void)fprintf(stderr, "No memory left while creating text line\n"); exit(1); @@ -661,14 +603,13 @@ ltk_text_buffer_create(void) { void ltk_text_line_destroy(struct ltk_text_line *tl) { - ltk_gap_buffer_destroy_uint32(tl->log_buf); - ltk_gap_buffer_destroy_uint32(tl->vis_buf); - ltk_gap_buffer_destroy_script(tl->scripts); - ltk_gap_buffer_destroy_int(tl->log2vis); - ltk_gap_buffer_destroy_int(tl->vis2log); + ltk_array_destroy_uint32(tl->log_buf); + ltk_array_destroy_uint32(tl->vis_buf); + ltk_array_destroy_script(tl->scripts); + ltk_array_destroy_int(tl->log2vis); + ltk_array_destroy_int(tl->vis2log); ltk_array_destroy_level(tl->bidi_levels); ltk_array_destroy_int(tl->wrap_indeces); ltk_text_line_destroy_runs(tl->first_run); - if (tl->img) XDestroyImage(tl->img); free(tl); } diff --git a/text_buffer.h b/text_buffer.h @@ -33,12 +33,10 @@ Requires the following includes: /* Note: hb_script_t and FriBidiLevel are really just uint32_t's, but I'm not sure if I should rely on that, so they're separate here */ -LTK_GAP_BUFFER_INIT_DECL(uint32, uint32_t) -LTK_GAP_BUFFER_INIT_DECL(script, hb_script_t) -LTK_GAP_BUFFER_INIT_DECL(int, int) +LTK_ARRAY_INIT_DECL(uint32, uint32_t) +LTK_ARRAY_INIT_DECL(script, hb_script_t) LTK_ARRAY_INIT_DECL(level, FriBidiLevel) LTK_ARRAY_INIT_DECL(int, int) -LTK_STACK_INIT_DECL(script, int, hb_script_t, pair_index, script) struct ltk_text_run { LtkGlyph *glyphs; @@ -58,26 +56,26 @@ struct ltk_text_run { }; struct ltk_text_line { - struct ltk_gap_buffer_uint32 *log_buf; /* buffer of the logical text */ - struct ltk_gap_buffer_script *scripts; - struct ltk_gap_buffer_uint32 *vis_buf; /* buffer of visual text */ - struct ltk_gap_buffer_int *log2vis; - struct ltk_gap_buffer_int *vis2log; + struct ltk_array_uint32 *log_buf; /* buffer of the logical text */ + struct ltk_array_script *scripts; + struct ltk_array_uint32 *vis_buf; /* buffer of visual text */ + struct ltk_array_int *log2vis; + struct ltk_array_int *vis2log; struct ltk_array_level *bidi_levels; + struct ltk_array_int *wrap_indeces; struct ltk_text_run *first_run; /* first node in the linked list of runs */ struct ltk_text_run *last_run; /* last node in the linked list of runs */ struct ltk_text_run *cur_run; /* current node in the linked list of runs */ struct ltk_text_line *next; /* next text line in the buffer */ unsigned int height; /* height of the line (including wrapping) */ FriBidiCharType dir; /* overall paragraph direction */ - struct ltk_array_int *wrap_indeces; size_t len; uint16_t font_size; int y_max; int y_min; int w; int h; - XImage *img; + size_t cursor_pos; }; struct ltk_text_buffer { @@ -86,4 +84,10 @@ struct ltk_text_buffer { unsigned int line_gap; }; +XImage *ltk_render_text_line_new(struct ltk_text_line *tl, int max_width, + Display *dpy, Window window, GC gc, Colormap colormap, XColor fg, XColor bg); +void ltk_text_line_insert_text(struct ltk_text_line *tl, uint32_t *text, size_t len); +struct ltk_text_line *ltk_text_line_create(void); +void ltk_text_line_destroy(struct ltk_text_line *tl); + #endif /* _TEXT_BUFFER_H_ */ diff --git a/text_edit.c b/text_edit.c @@ -21,6 +21,20 @@ * SOFTWARE. */ +#include <stdint.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include "khash.h" +#include "ltk.h" +#include "stb_truetype.h" +#include <fribidi.h> +#include <harfbuzz/hb.h> +#include <fontconfig/fontconfig.h> +#include "text-common.h" +#include "array.h" +#include "text_buffer.h" +#include "text_edit.h" + extern Ltk *ltk_global; void @@ -29,9 +43,9 @@ ltk_draw_text_edit(LtkTextEdit *te) { XColor bg = ltk_global->theme->window->bg; LtkRect rect = te->widget.rect; LtkWindow *window = te->widget.window; - if (!te->tl->img) + 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->tl->img, 0, 0, rect.x, rect.y, te->tl->w, te->tl->h); + XPutImage(ltk_global->display, window->xwindow, window->gc, te->img, 0, 0, rect.x, rect.y, te->tl->w, te->tl->h); } LtkTextEdit *ltk_create_text_edit(LtkWindow *window, const char *text) { @@ -41,8 +55,10 @@ LtkTextEdit *ltk_create_text_edit(LtkWindow *window, const char *text) { ltk_fill_widget_defaults(&te->widget, window, &ltk_draw_text_edit, &ltk_destroy_text_edit, 1); te->tl = ltk_text_line_create(); ltk_text_line_insert_utf8(te->tl, text); + te->img = NULL; } void ltk_destroy_text_edit(LtkTextEdit *te) { ltk_text_line_destroy(te->tl); + if (te->img) XDestroyImage(te->img); free(te); } diff --git a/text_edit.h b/text_edit.h @@ -21,8 +21,12 @@ * SOFTWARE. */ +#ifndef _LTK_TEXT_EDIT_H_ +#define _LTK_TEXT_EDIT_H_ + typedef struct { LtkWidget widget; + XImage *img; struct ltk_text_line *tl; } LtkTextEdit; @@ -30,3 +34,5 @@ typedef struct { void ltk_draw_text_edit(LtkTextEdit *te); LtkTextEdit *ltk_create_text_edit(LtkWindow *window, const char *text); void ltk_destroy_text_edit(LtkTextEdit *te); + +#endif /* _LTK_TEXT_EDIT_H_ */