ltkx

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

commit d6e2f851b663e5db6957c3fb5c41f595c139c3c6
parent 288e467a6083a547a3996e69b6ba0ea1d430e70b
Author: lumidify <nobody@lumidify.org>
Date:   Wed, 27 May 2020 21:19:10 +0200

Somewhat improve drawing

Diffstat:
MNOTES | 3+++
Mltk.c | 42+++++++++++++++++++++++++-----------------
Mltk.h | 6+++---
Mtext_buffer.c | 36------------------------------------
Mtext_common.c | 80-------------------------------------------------------------------------------
Mtext_common.h | 7-------
6 files changed, 31 insertions(+), 143 deletions(-)

diff --git a/NOTES b/NOTES @@ -36,3 +36,6 @@ and creates a "failsafe" error window (just using basic XDrawString, etc.) to show errors (like index out of bounds, etc.). Still print the error, of course, in case creating a window doesn't work. + +Idea: Make interface primarily key-driven; store keybindings +in config so they can easily be configured diff --git a/ltk.c b/ltk.c @@ -94,10 +94,19 @@ void ltk_mainloop(void) XEvent event; KeySym key; char text[255]; + int redraw = 0; + LtkWindow *window = NULL; + /* FIXME: compress motion events */ while (1) { - XNextEvent(ltk_global->display, &event); - ltk_handle_event(event); + if (XPending(ltk_global->display) || !redraw) { + XNextEvent(ltk_global->display, &event); + redraw = ltk_handle_event(event, &window) || redraw; + } else if (redraw && window) { + ltk_redraw_window(window); + redraw = 0; + window = NULL; + } } } @@ -177,10 +186,10 @@ void ltk_destroy_window(LtkWindow * window) ltk_global->window_num--; } -void ltk_window_other_event(void *widget, XEvent event) +int ltk_window_other_event(LtkWindow *window, XEvent event) { - LtkWindow *window = (LtkWindow *) widget; LtkWidget *ptr = window->root_widget; + int retval = 0; if (event.type == ConfigureNotify) { unsigned int w, h; w = event.xconfigure.width; @@ -194,16 +203,15 @@ void ltk_window_other_event(void *widget, XEvent event) ptr->rect.w = w; ptr->rect.h = h; ptr->resize(ptr, orig_w, orig_h); - ltk_redraw_window(window); + retval = 1; } - } - if (event.type == Expose && event.xexpose.count == 0) { - ltk_redraw_window(window); - } - if (event.type == ClientMessage + } else if (event.type == Expose && event.xexpose.count == 0) { + retval = 1; + } else if (event.type == ClientMessage && event.xclient.data.l[0] == ltk_global->wm_delete_msg) { ltk_remove_window(window); } + return retval; } void ltk_window_ini_handler(LtkTheme *theme, const char *prop, const char *value) @@ -405,14 +413,13 @@ void ltk_motion_notify_event(void *widget, XEvent event) ptr->motion_notify(ptr, event); } -void ltk_handle_event(XEvent event) +int ltk_handle_event(XEvent event, LtkWindow **window) { - LtkWindow *window; LtkWidget *root_widget; int k = kh_get(winhash, ltk_global->window_hash, event.xany.window); - window = kh_value(ltk_global->window_hash, k); - if (!window) return; - root_widget = window->root_widget; + *window = kh_value(ltk_global->window_hash, k); + if (!*window) return 0; + root_widget = (*window)->root_widget; switch (event.type) { case KeyPress: break; @@ -432,7 +439,8 @@ void ltk_handle_event(XEvent event) break; default: /* FIXME: users should be able to register other events like closing the window */ - if (window->other_event) - window->other_event(window, event); + if ((*window)->other_event) + return (*window)->other_event(*window, event); } + return 0; } diff --git a/ltk.h b/ltk.h @@ -83,7 +83,7 @@ typedef struct LtkWindow { Window xwindow; GC gc; void *root_widget; - void (*other_event) (void *, XEvent event); + int (*other_event) (LtkWindow *, XEvent event); LtkRect rect; } LtkWindow; @@ -136,7 +136,7 @@ void ltk_remove_window(LtkWindow * window); void ltk_destroy_window(LtkWindow * window); -void ltk_window_other_event(void *widget, XEvent event); +int ltk_window_other_event(LtkWindow *window, XEvent event); void ltk_destroy_theme(LtkTheme * theme); @@ -159,6 +159,6 @@ void ltk_mouse_release_event(void *widget, XEvent event); void ltk_motion_notify_event(void *widget, XEvent event); -void ltk_handle_event(XEvent event); +int ltk_handle_event(XEvent event, LtkWindow **window); #endif diff --git a/text_buffer.c b/text_buffer.c @@ -21,7 +21,6 @@ * SOFTWARE. */ -#include <sys/time.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> @@ -79,10 +78,6 @@ ltk_text_line_cleanup_soft_lines(struct ltk_array_line *soft_lines, int old_len) void ltk_text_line_wrap(struct ltk_text_line *tl, int max_width) { - struct timeval t1, t2; - gettimeofday(&t1, NULL); - printf("wrap1: %d, %d\n", t1.tv_sec, t1.tv_usec); - tl->w_wrapped = max_width; int old_len = tl->soft_lines->len; tl->soft_lines->len = 0; @@ -252,9 +247,6 @@ ltk_text_line_wrap(struct ltk_text_line *tl, int max_width) { else tl->w_wrapped = max_width; tl->h_wrapped = tl->soft_lines->len * tl->h; - - gettimeofday(&t2, NULL); - printf("wrap2: %d, %d, diff: %d\n", t2.tv_sec, t2.tv_usec, t2.tv_usec - t1.tv_usec); } XImage * @@ -309,9 +301,6 @@ ltk_text_line_render( XColor fg, XColor bg) { - struct timeval t1, t2; - gettimeofday(&t1, NULL); - printf("render1: %d, %d\n", t1.tv_sec, t1.tv_usec); LtkGlyph *glyph; int par_is_rtl = tl->dir == HB_DIRECTION_RTL; @@ -389,8 +378,6 @@ ltk_text_line_render( ltk_array_resize_int(sl->glyph_pos, sl->glyph_pos->len); ltk_array_resize_uint32(sl->glyph_clusters, sl->glyph_clusters->len); } - gettimeofday(&t2, NULL); - printf("render2: %d, %d, diff: %d\n", t2.tv_sec, t2.tv_usec, t2.tv_usec - t1.tv_usec); return img; } @@ -638,8 +625,6 @@ ltk_text_line_itemize(struct ltk_text_line *tl) { 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) { - struct timeval t1, t2; - gettimeofday(&t1, NULL); khash_t(glyphinfo) *glyph_cache; khint_t k; @@ -668,8 +653,6 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr, hb_shape(tr->font->hb, buf, NULL, 0); ginf = hb_buffer_get_glyph_infos(buf, &tr->num_glyphs); gpos = hb_buffer_get_glyph_positions(buf, &tr->num_glyphs); - gettimeofday(&t2, NULL); - printf("hb_shape: %d, %d, diff: %d\n", t2.tv_sec, t2.tv_usec, t2.tv_usec - t1.tv_usec); float scale = stbtt_ScaleForMappingEmToPixels(&tr->font->info, font_size); int x_min = INT_MAX, x_max = INT_MIN, y_min = INT_MAX, y_max = INT_MIN; @@ -721,8 +704,6 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr, *ret_y_max = y_max; tr->font->refs++; - gettimeofday(&t2, NULL); - printf("run_shape: %d\n", t2.tv_usec - t1.tv_usec); } static void @@ -732,10 +713,8 @@ ltk_text_line_shape(LtkTextManager *tm, struct ltk_text_line *tl) { int y_max; int y_max_overall = INT_MIN; int y_min_overall = INT_MAX; - struct timeval t1, t2; while (run) { /* Question: Why does this not work with FcPatternDuplicate? */ - gettimeofday(&t1, NULL); FcPattern *pat = FcPatternCreate(); FcPattern *match; FcResult result; @@ -756,8 +735,6 @@ ltk_text_line_shape(LtkTextManager *tm, struct ltk_text_line *tl) { run->font = kh_value(tm->font_cache, k); FcPatternDestroy(match); FcPatternDestroy(pat); - gettimeofday(&t2, NULL); - printf("fontconfig: %d\n", t2.tv_usec - t1.tv_usec); ltk_text_run_shape(tm, run, tl, tl->font_size, font_id, &y_max); if (y_max_overall < y_max) y_max_overall = y_max; @@ -828,31 +805,18 @@ ltk_text_line_destroy_runs(struct ltk_text_run *runs) { static void ltk_text_line_recalculate(LtkTextManager *tm, struct ltk_text_line *tl) { FriBidiCharType par_dir = FRIBIDI_TYPE_ON; - struct timeval t1, t2; - gettimeofday(&t1, NULL); - printf("fribidi1: %d, %d\n", t1.tv_sec, t1.tv_usec); fribidi_log2vis( tl->log_buf->buf, tl->log_buf->len, &par_dir, tl->vis_buf->buf, tl->log2vis->buf, tl->vis2log->buf, tl->bidi_levels->buf ); - gettimeofday(&t2, NULL); - printf("fribidi2: %d, %d, diff: %d\n", t2.tv_sec, t2.tv_usec, t2.tv_usec - t1.tv_usec); if (FRIBIDI_IS_RTL(par_dir)) tl->dir = HB_DIRECTION_RTL; else tl->dir = HB_DIRECTION_LTR; struct ltk_text_run *old_runs = tl->first_run; - gettimeofday(&t1, NULL); - printf("itemize1: %d, %d\n", t1.tv_sec, t1.tv_usec); ltk_text_line_itemize(tl); - gettimeofday(&t2, NULL); - printf("itemize2: %d, %d, diff: %d\n", t2.tv_sec, t2.tv_usec, t2.tv_usec - t1.tv_usec); struct ltk_text_run *cur = tl->first_run; - gettimeofday(&t1, NULL); - printf("shape1: %d, %d\n", t1.tv_sec, t1.tv_usec); ltk_text_line_shape(tm, tl); - gettimeofday(&t2, NULL); - printf("shape2: %d, %d, diff: %d\n", t2.tv_sec, t2.tv_usec, t2.tv_usec - t1.tv_usec); /* this needs to be done after shaping so the fonts, etc. aren't removed if their reference counts drop and then loaded again right afterwards */ diff --git a/text_common.c b/text_common.c @@ -328,83 +328,3 @@ ltk_destroy_glyph(LtkGlyph *glyph, khash_t(glyphinfo) *cache) } free(glyph); } - -#if 0 -/* based on http://codemadness.org/git/dwm-font/file/drw.c.html#l315 */ -XImage * -ltk_render_text_line( - LtkTextLine *tl, - Display *dpy, - Window window, - GC gc, - Colormap colormap, - XColor fg, - XColor bg) -{ - XWindowAttributes attrs; - XGetWindowAttributes(dpy, window, &attrs); - int depth = attrs.depth; - XImage *img = XCreateImage(dpy, CopyFromParent, depth, ZPixmap, 0, NULL, tl->w, tl->h, 32, 0); - img->data = calloc(img->bytes_per_line, img->height); - XInitImage(img); - int b; - for (int i = 0; i < tl->h; i++) { - b = img->bytes_per_line * i; - for (int j = 0; j < tl->w; j++) { - img->data[b++] = bg.blue / 257; - img->data[b++] = bg.green / 257; - img->data[b++] = bg.red / 257; - b++; - } - } - - LtkTextSegment *ts = tl->start_segment; - int x = 0; - int y = 0; - int is_hor = HB_DIRECTION_IS_HORIZONTAL(ts->dir); - do { - if (is_hor) { - y = tl->h - tl->y_max; - ltk_render_text_segment(ts, x + ts->start_x, y, img, fg); - x += ts->w; - } else { - x = tl->w - tl->x_max; - ltk_render_text_segment(ts, x, y + ts->start_y, img, fg); - y += ts->h; - } - } while (ts = ts->next); - - return img; -} - -void -ltk_render_text_segment( - LtkTextSegment *ts, - unsigned int start_x, - unsigned int start_y, - XImage *img, - XColor fg) -{ - LtkGlyph *glyph = ts->start_glyph; - int x_cur = start_x; - int y_cur = start_y; - int x, y; - double a; - int b; - do { - x = x_cur + glyph->info->xoff + glyph->x_offset; - y = y_cur + glyph->info->yoff - glyph->y_offset; - 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; - a = glyph->info->alphamap[i * glyph->info->w + j] / 255.0; - 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; - } - } - x_cur += glyph->x_advance; - y_cur -= glyph->y_advance; - } while (glyph = glyph->next); -} -#endif diff --git a/text_common.h b/text_common.h @@ -61,7 +61,6 @@ typedef struct _LtkGlyph { int x_abs; int y_abs; uint32_t cluster; /* index of char in original text - from harfbuzz */ - struct _LtkGlyph *next; } LtkGlyph; /* Hash definitions */ @@ -116,10 +115,4 @@ uint16_t ltk_get_font(LtkTextManager *tm, char *path); void ltk_destroy_glyph(LtkGlyph *glyph, khash_t(glyphinfo) *cache); -/* -XImage *ltk_render_text_line(LtkTextLine *tl, Display *dpy, Window window, GC gc, Colormap colormap, XColor fg, XColor bg); - -void ltk_render_text_segment(LtkTextSegment *ts, unsigned int start_x, unsigned int start_y, XImage *img, XColor fg); -*/ - #endif /* _TEXT_COMMON_H_ */