ltkx

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

commit 1207520e0aa5ec1696924646f850b1c4a8bc57ed
parent d6e2f851b663e5db6957c3fb5c41f595c139c3c6
Author: lumidify <nobody@lumidify.org>
Date:   Thu, 28 May 2020 19:24:11 +0200

Only clear changed area before redrawing

Diffstat:
Mgrid.c | 2+-
Mltk.c | 211++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Mltk.h | 14++++++++------
Mtext_edit.c | 3+--
4 files changed, 144 insertions(+), 86 deletions(-)

diff --git a/grid.c b/grid.c @@ -41,7 +41,7 @@ void ltk_set_column_weight(LtkGrid * grid, int column, int weight) ltk_recalculate_grid(grid); } -void ltk_draw_grid(LtkGrid * grid) +void ltk_draw_grid(LtkGrid *grid) { int i; for (i = 0; i < grid->rows * grid->columns; i++) { diff --git a/ltk.c b/ltk.c @@ -1,6 +1,6 @@ /* * This file is part of the Lumidify ToolKit (LTK) - * Copyright (c) 2016, 2017, 2018 lumidify <nobody@lumidify.org> + * Copyright (c) 2016, 2017, 2018, 2020 lumidify <nobody@lumidify.org> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -38,8 +38,62 @@ Ltk *ltk_global; -void ltk_init(const char *theme_path) -{ +struct ltk_redraw_queue { + LtkWindow *window; + LtkRect rect; +}; + +static struct ltk_redraw_queue *redraw_queue = NULL; +static int num_redraws = 0; +static int redraw_queue_bufsize = 0; + +static LtkRect +ltk_rect_union(LtkRect r1, LtkRect r2) { + LtkRect u; + u.x = r1.x < r2.x ? r1.x : r2.x; + u.y = r1.y < r2.y ? r1.y : r2.y; + int x2 = r1.x + r1.w < r2.x + r2.w ? r2.x + r2.w : r1.x + r1.w; + int y2 = r1.y + r1.h < r2.y + r2.h ? r2.y + r2.h : r1.y + r1.h; + u.w = x2 - u.x; + u.h = y2 - u.y; + return u; +} + +void +ltk_window_invalidate_rect(LtkWindow *window, LtkRect rect) { + int index = -1; + if (redraw_queue) { + for (int i = 0; i < num_redraws; i++) { + if (redraw_queue[i].window == window) { + index = i; + break; + } + } + } + if (index == -1) { + if (num_redraws == redraw_queue_bufsize) { + struct ltk_redraw_queue *tmp = realloc( + redraw_queue, sizeof(struct ltk_redraw_queue) * (redraw_queue_bufsize + 1)); + if (!tmp) goto error; + redraw_queue = tmp; + redraw_queue_bufsize++; + } + index = num_redraws; + num_redraws++; + redraw_queue[index].window = window; + redraw_queue[index].rect = rect; + } else { + redraw_queue[index].rect = ltk_rect_union(rect, redraw_queue[index].rect); + } + + return; +error: + (void)fprintf(stderr, "Out of memory\n"); + exit(1); +} + +void +ltk_init(const char *theme_path) { ltk_global = malloc(sizeof(Ltk)); Ltk *ltk = ltk_global; /* For convenience */ ltk->display = XOpenDisplay(NULL); @@ -51,8 +105,8 @@ void ltk_init(const char *theme_path) ltk->tm = ltk_init_text(ltk->theme->window->font); } -void ltk_clean_up(void) -{ +void +ltk_clean_up(void) { LtkWindow *window; for (int k = kh_begin(ltk_global->window_hash); k != kh_end(ltk_global->window_hash); k++) { if (kh_exist(ltk_global->window_hash, k)) { @@ -64,23 +118,24 @@ void ltk_clean_up(void) ltk_destroy_theme(ltk_global->theme); ltk_destroy_text_manager(ltk_global->tm); free(ltk_global); + if (redraw_queue) free(redraw_queue); } -void ltk_quit(void) -{ +void +ltk_quit(void) { ltk_clean_up(); exit(0); } -void ltk_fatal(const char *msg) -{ +void +ltk_fatal(const char *msg) { (void)fprintf(stderr, msg); ltk_clean_up(); exit(1); }; -XColor ltk_create_xcolor(const char *hex) -{ +XColor +ltk_create_xcolor(const char *hex) { XColor color; XParseColor(ltk_global->display, ltk_global->colormap, hex, &color); @@ -89,44 +144,43 @@ XColor ltk_create_xcolor(const char *hex) return color; } -void ltk_mainloop(void) -{ +void +ltk_mainloop(void) { XEvent event; KeySym key; char text[255]; - int redraw = 0; - LtkWindow *window = NULL; /* FIXME: compress motion events */ while (1) { - if (XPending(ltk_global->display) || !redraw) { + if (XPending(ltk_global->display) || !num_redraws) { XNextEvent(ltk_global->display, &event); - redraw = ltk_handle_event(event, &window) || redraw; - } else if (redraw && window) { - ltk_redraw_window(window); - redraw = 0; - window = NULL; + ltk_handle_event(event); + } else if (num_redraws) { + for (int i = 0; i < num_redraws; i++) + ltk_redraw_window(redraw_queue[i].window, redraw_queue[i].rect); + num_redraws = 0; } } } -void ltk_redraw_window(LtkWindow * window) -{ +void +ltk_redraw_window(LtkWindow *window, LtkRect rect) { LtkWidget *ptr; - if (!window) { - return; - } - XClearWindow(ltk_global->display, window->xwindow); - if (!window->root_widget) { - return; - } + if (!window) return; + if (rect.x >= window->rect.w) return; + if (rect.y >= window->rect.h) return; + if (rect.x + rect.w > window->rect.w) + rect.w -= rect.x + rect.w - window->rect.w; + if (rect.y + rect.h > window->rect.h) + rect.h -= rect.y + rect.h - window->rect.h; + XClearArea(ltk_global->display, window->xwindow, rect.x, rect.y, rect.w, rect.h, False); + if (!window->root_widget) return; ptr = window->root_widget; ptr->draw(ptr); } -LtkWindow *ltk_create_window(const char *title, int x, int y, - unsigned int w, unsigned int h) -{ +LtkWindow * +ltk_create_window(const char *title, int x, int y, unsigned int w, unsigned int h) { LtkWindow *window = malloc(sizeof(LtkWindow)); if (!window) ltk_fatal("Not enough memory left for window!\n"); @@ -167,15 +221,16 @@ LtkWindow *ltk_create_window(const char *title, int x, int y, return window; } -void ltk_remove_window(LtkWindow *window) -{ +void +ltk_remove_window(LtkWindow *window) { + /* FIXME: also remove from event queue */ ltk_destroy_window(window); if (ltk_global->window_num == 0) ltk_quit(); } -void ltk_destroy_window(LtkWindow * window) -{ +void +ltk_destroy_window(LtkWindow * window) { int k = kh_get(winhash, ltk_global->window_hash, window->xwindow); kh_del(winhash, ltk_global->window_hash, k); LtkWidget *ptr = window->root_widget; @@ -186,8 +241,8 @@ void ltk_destroy_window(LtkWindow * window) ltk_global->window_num--; } -int ltk_window_other_event(LtkWindow *window, XEvent event) -{ +void +ltk_window_other_event(LtkWindow *window, XEvent event) { LtkWidget *ptr = window->root_widget; int retval = 0; if (event.type == ConfigureNotify) { @@ -203,19 +258,22 @@ int ltk_window_other_event(LtkWindow *window, XEvent event) ptr->rect.w = w; ptr->rect.h = h; ptr->resize(ptr, orig_w, orig_h); - retval = 1; } } else if (event.type == Expose && event.xexpose.count == 0) { - retval = 1; + LtkRect r; + r.x = event.xexpose.x; + r.y = event.xexpose.y; + r.w = event.xexpose.width; + r.h = event.xexpose.height; + ltk_window_invalidate_rect(window, r); } 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) -{ +void +ltk_window_ini_handler(LtkTheme *theme, const char *prop, const char *value) { if (strcmp(prop, "border_width") == 0) { theme->window->border_width = atoi(value); } else if (strcmp(prop, "bg") == 0) { @@ -227,8 +285,8 @@ void ltk_window_ini_handler(LtkTheme *theme, const char *prop, const char *value } } -int ltk_ini_handler(void *theme, const char *widget, const char *prop, const char *value) -{ +int +ltk_ini_handler(void *theme, const char *widget, const char *prop, const char *value) { if (strcmp(widget, "window") == 0) { ltk_window_ini_handler(theme, prop, value); } else if (strcmp(widget, "button") == 0) { @@ -236,8 +294,8 @@ int ltk_ini_handler(void *theme, const char *widget, const char *prop, const cha } } -LtkTheme *ltk_load_theme(const char *path) -{ +LtkTheme * +ltk_load_theme(const char *path) { LtkTheme *theme = malloc(sizeof(LtkTheme)); theme->window = malloc(sizeof(LtkWindowTheme)); theme->button = NULL; @@ -249,15 +307,15 @@ LtkTheme *ltk_load_theme(const char *path) return theme; } -void ltk_destroy_theme(LtkTheme * theme) -{ +void +ltk_destroy_theme(LtkTheme * theme) { free(theme->button); free(theme->window); free(theme); } -char *ltk_read_file(const char *path, unsigned long *len) -{ +char * +ltk_read_file(const char *path, unsigned long *len) { FILE *f; char *file_contents; f = fopen(path, "rb"); @@ -272,14 +330,14 @@ char *ltk_read_file(const char *path, unsigned long *len) return file_contents; } -int ltk_collide_rect(LtkRect rect, int x, int y) -{ +int +ltk_collide_rect(LtkRect rect, int x, int y) { return (rect.x <= x && (rect.x + rect.w) >= x && rect.y <= y && (rect.y + rect.h) >= y); } -void ltk_remove_active_widget(void *widget) -{ +void +ltk_remove_active_widget(void *widget) { if (!widget) return; LtkWidget *parent = widget; @@ -294,8 +352,8 @@ void ltk_remove_active_widget(void *widget) } } -void ltk_change_active_widget_state(void *widget, LtkWidgetState state) -{ +void +ltk_change_active_widget_state(void *widget, LtkWidgetState state) { if (!widget) return; LtkWidget *ptr = widget; @@ -305,8 +363,8 @@ void ltk_change_active_widget_state(void *widget, LtkWidgetState state) } } -void ltk_remove_hover_widget(void *widget) -{ +void +ltk_remove_hover_widget(void *widget) { if (!widget) return; LtkWidget *parent = widget; @@ -322,9 +380,9 @@ void ltk_remove_hover_widget(void *widget) } } -void ltk_fill_widget_defaults(LtkWidget *widget, LtkWindow *window, - void (*draw) (void *), void (*destroy) (void *), unsigned int needs_redraw) -{ +void +ltk_fill_widget_defaults(LtkWidget *widget, LtkWindow *window, + void (*draw) (void *), void (*destroy) (void *), unsigned int needs_redraw) { widget->window = window; widget->active_widget = NULL; widget->hover_widget = NULL; @@ -355,8 +413,8 @@ void ltk_fill_widget_defaults(LtkWidget *widget, LtkWindow *window, widget->sticky = 0; } -void ltk_mouse_press_event(void *widget, XEvent event) -{ +void +ltk_mouse_press_event(void *widget, XEvent event) { LtkWidget *ptr = widget; if (!ptr || ptr->state == LTK_DISABLED) return; @@ -375,8 +433,8 @@ void ltk_mouse_press_event(void *widget, XEvent event) } } -void ltk_mouse_release_event(void *widget, XEvent event) -{ +void +ltk_mouse_release_event(void *widget, XEvent event) { LtkWidget *ptr = widget; if (!ptr || ptr->state == LTK_DISABLED) return; @@ -390,8 +448,8 @@ void ltk_mouse_release_event(void *widget, XEvent event) } } -void ltk_motion_notify_event(void *widget, XEvent event) -{ +void +ltk_motion_notify_event(void *widget, XEvent event) { LtkWidget *ptr = widget; LtkWidget *parent; if (!ptr) @@ -413,13 +471,13 @@ void ltk_motion_notify_event(void *widget, XEvent event) ptr->motion_notify(ptr, event); } -int ltk_handle_event(XEvent event, LtkWindow **window) -{ +void +ltk_handle_event(XEvent event) { 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 0; - root_widget = (*window)->root_widget; + LtkWindow *window = kh_value(ltk_global->window_hash, k); + if (!window) return; + root_widget = window->root_widget; switch (event.type) { case KeyPress: break; @@ -439,8 +497,7 @@ int ltk_handle_event(XEvent event, LtkWindow **window) break; default: /* FIXME: users should be able to register other events like closing the window */ - if ((*window)->other_event) - return (*window)->other_event(*window, event); + if (window->other_event) + window->other_event(window, event); } - return 0; } diff --git a/ltk.h b/ltk.h @@ -119,6 +119,8 @@ typedef struct { Atom wm_delete_msg; } Ltk; +void ltk_window_invalidate_rect(LtkWindow *window, LtkRect rect); + void ltk_init(const char *theme_path); void ltk_fatal(const char *msg); @@ -130,15 +132,15 @@ void ltk_mainloop(void); LtkWindow *ltk_create_window(const char *title, int x, int y, unsigned int w, unsigned int h); -void ltk_redraw_window(LtkWindow * window); +void ltk_redraw_window(LtkWindow *window, LtkRect rect); -void ltk_remove_window(LtkWindow * window); +void ltk_remove_window(LtkWindow *window); -void ltk_destroy_window(LtkWindow * window); +void ltk_destroy_window(LtkWindow *window); -int ltk_window_other_event(LtkWindow *window, XEvent event); +void ltk_window_other_event(LtkWindow *window, XEvent event); -void ltk_destroy_theme(LtkTheme * theme); +void ltk_destroy_theme(LtkTheme *theme); int ltk_collide_rect(LtkRect rect, int x, int y); @@ -159,6 +161,6 @@ void ltk_mouse_release_event(void *widget, XEvent event); void ltk_motion_notify_event(void *widget, XEvent event); -int ltk_handle_event(XEvent event, LtkWindow **window); +void ltk_handle_event(XEvent event); #endif diff --git a/text_edit.c b/text_edit.c @@ -110,8 +110,7 @@ ltk_text_edit_insert_text(LtkTextEdit *te, const char *text) { /* FIXME */ ltk_text_line_insert_utf8(te->tl, 0, text); ltk_text_edit_resize(te, 0, 0); - /* FIXME: Need to "queue redraw" for whole window */ - ltk_text_edit_draw(te); + ltk_window_invalidate_rect(te->widget.window, te->widget.rect); } void ltk_text_edit_destroy(LtkTextEdit *te) {