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:
M | grid.c | | | 2 | +- |
M | ltk.c | | | 211 | ++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------- |
M | ltk.h | | | 14 | ++++++++------ |
M | text_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) {