commit 85b5c97bb7c4e1b85f9c322d1beccd1911f0bf09
parent 017e677d873e000aea1af57bb49d4be48ff89445
Author: lumidify <nobody@lumidify.org>
Date: Sat, 6 Jun 2020 19:17:19 +0200
Allow longer strings in commands; fix text rendering
Diffstat:
11 files changed, 98 insertions(+), 64 deletions(-)
diff --git a/LICENSE b/LICENSE
@@ -1,4 +1,4 @@
-See khash.h, ini.*, and strtonum.c for third-party licenses.
+See khash.h, ini.*, stb_truetype.*, and strtonum.c for third-party licenses.
MIT/X Consortium License
diff --git a/button.c b/button.c
@@ -43,7 +43,7 @@ static void ltk_button_destroy(ltk_button *button, int shallow);
static void ltk_grid_cmd_create(
ltk_window *window,
- char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH],
+ char **tokens,
size_t num_tokens);
void
@@ -187,7 +187,7 @@ ltk_button_destroy(ltk_button *button, int shallow) {
static void
ltk_button_cmd_create(
ltk_window *window,
- char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH],
+ char **tokens,
size_t num_tokens) {
ltk_button *button;
if (num_tokens != 4) {
@@ -204,7 +204,7 @@ ltk_button_cmd_create(
void
ltk_button_cmd(
ltk_window *window,
- char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH],
+ char **tokens,
size_t num_tokens) {
if (num_tokens < 3) {
(void)fprintf(stderr, "button: Invalid number of arguments.\n");
diff --git a/button.h b/button.h
@@ -57,7 +57,7 @@ void ltk_button_ini_handler(ltk_window *window, const char *prop, const char *va
void ltk_button_cmd(
ltk_window *window,
- char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH],
+ char **tokens,
size_t num_tokens);
#endif
diff --git a/grid.c b/grid.c
@@ -54,23 +54,23 @@ static void ltk_grid_motion_notify(ltk_grid *grid, XEvent event);
static void ltk_grid_cmd_add(
ltk_window *window,
- char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH],
+ char **tokens,
size_t num_tokens);
static void ltk_grid_cmd_ungrid(
ltk_window *window,
- char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH],
+ char **tokens,
size_t num_tokens);
static void ltk_grid_cmd_create(
ltk_window *window,
- char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH],
+ char **tokens,
size_t num_tokens);
static void ltk_grid_cmd_set_row_weight(
ltk_window *window,
- char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH],
+ char **tokens,
size_t num_tokens);
static void ltk_grid_cmd_set_column_weight(
ltk_window *window,
- char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH],
+ char **tokens,
size_t num_tokens);
static void
@@ -364,7 +364,7 @@ ltk_grid_motion_notify(ltk_grid *grid, XEvent event) {
static void
ltk_grid_cmd_add(
ltk_window *window,
- char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH],
+ char **tokens,
size_t num_tokens) {
ltk_grid *grid;
ltk_widget *widget;
@@ -410,7 +410,7 @@ ltk_grid_cmd_add(
static void
ltk_grid_cmd_ungrid(
ltk_window *window,
- char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH],
+ char **tokens,
size_t num_tokens) {
ltk_grid *grid;
ltk_widget *widget;
@@ -428,7 +428,7 @@ ltk_grid_cmd_ungrid(
static void
ltk_grid_cmd_create(
ltk_window *window,
- char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH],
+ char **tokens,
size_t num_tokens) {
int rows, columns;
ltk_grid *grid;
@@ -457,7 +457,7 @@ ltk_grid_cmd_create(
static void
ltk_grid_cmd_set_row_weight(
ltk_window *window,
- char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH],
+ char **tokens,
size_t num_tokens) {
ltk_grid *grid;
int row, weight;
@@ -485,7 +485,7 @@ ltk_grid_cmd_set_row_weight(
static void
ltk_grid_cmd_set_column_weight(
ltk_window *window,
- char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH],
+ char **tokens,
size_t num_tokens) {
ltk_grid *grid;
int column, weight;
@@ -513,7 +513,7 @@ ltk_grid_cmd_set_column_weight(
void
ltk_grid_cmd(
ltk_window *window,
- char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH],
+ char **tokens,
size_t num_tokens) {
if (num_tokens < 3) {
(void)fprintf(stderr, "grid: Invalid number of arguments.\n");
diff --git a/grid.h b/grid.h
@@ -42,6 +42,6 @@ typedef struct {
unsigned int *column_pos;
} ltk_grid;
-void ltk_grid_cmd(ltk_window *window, char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH], size_t num_tokens);
+void ltk_grid_cmd(ltk_window *window, char **tokens, size_t num_tokens);
#endif
diff --git a/ltk.c b/ltk.c
@@ -46,6 +46,12 @@ static void ltk_load_theme(ltk_window *window, const char *path);
static void ltk_destroy_theme(ltk_theme *theme);
static int running = 1;
+static char *cmd_input = NULL;
+static char **tokens = NULL;
+static size_t cmd_bufsize = 0;
+static size_t tokens_bufsize = 0;
+static size_t cmd_len = 0;
+static size_t tokens_len = 0;
char *
ltk_read_file(const char *path, unsigned long *len) {
@@ -128,7 +134,7 @@ ltk_queue_event(ltk_window *window, const char *id, const char *name) {
static void
ltk_set_root_widget_cmd(
ltk_window *window,
- char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH],
+ char **tokens,
int num_tokens) {
ltk_widget *widget;
if (num_tokens != 2) {
@@ -149,57 +155,82 @@ ltk_set_root_widget_cmd(
/* copied from suckless ii */
static int
-read_line(int fd, char *buf, size_t bufsiz)
-{
- size_t i = 0;
+read_cmdline(int fd) {
char c = '\0';
+ char *tmp = NULL;
+ cmd_len = 0;
do {
+ if (cmd_len >= cmd_bufsize) {
+ cmd_bufsize = !cmd_bufsize ? 1 : cmd_bufsize;
+ tmp = realloc(cmd_input, cmd_bufsize * 2 * sizeof(char));
+ if (!tmp) ltk_fatal("Out of memory while reading command.\n");
+ cmd_input = tmp;
+ cmd_bufsize *= 2;
+ }
if (read(fd, &c, sizeof(char)) != sizeof(char))
return -1;
- buf[i++] = c;
- } while (c != '\n' && i < bufsiz);
- buf[i - 1] = '\0'; /* eliminates '\n' */
+ cmd_input[cmd_len++] = c;
+ } while (c != '\n');
+ cmd_input[cmd_len - 1] = '\0'; /* eliminates '\n' */
return 0;
}
-static size_t
-tokenize(char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH], char *buf) {
+static int
+tokenize(void) {
char *c;
- if (!buf || buf[0] == '\0') return 0;
- for (c = buf; *c == ' '; c++)
+ if (!cmd_input || cmd_input[0] == '\0') return 0;
+ for (c = cmd_input; *c == ' '; c++)
;
+ tokens_len = 0;
size_t cur_tok = 0;
size_t cur_tok_len = 0;
+ size_t cur_tok_bufsize = 0;
+ int in_str = 0;
+ char **tmp;
+ char *tmp2;
while (*c != '\0') {
- if (cur_tok >= MAX_TOKENS) {
- return 0;
- } else if (*c == ' ') {
+ if (cur_tok >= tokens_bufsize) {
+ tokens_bufsize = !tokens_bufsize ? 1 : tokens_bufsize;
+ tmp = realloc(tokens, tokens_bufsize * 2 * sizeof(char *));
+ if (!tmp) ltk_fatal("Out of memory while parsing command.\n");
+ tokens = tmp;
+ tokens_bufsize *= 2;
+ }
+ if (cur_tok_len + 1 >= cur_tok_bufsize) {
+ cur_tok_bufsize = !cur_tok_bufsize ? 1 : cur_tok_bufsize;
+ if (cur_tok_len == 0)
+ tokens[cur_tok] = NULL; /* so realloc works the first time */
+ tmp2 = realloc(tokens[cur_tok], cur_tok_bufsize * 2 * sizeof(char));
+ if (!tmp2) ltk_fatal("Out of memory while parsing command.\n");
+ tokens[cur_tok] = tmp2;
+ cur_tok_bufsize *= 2;
+ }
+ if (*c == '"') {
+ in_str = !in_str;
+ } else if (*c == ' ' && !in_str) {
tokens[cur_tok][cur_tok_len] = '\0';
cur_tok++;
cur_tok_len = 0;
- } else if (cur_tok_len >= MAX_TOKEN_LENGTH - 1) {
- return 0;
+ cur_tok_bufsize = 0;
} else {
tokens[cur_tok][cur_tok_len++] = *c;
}
c++;
}
tokens[cur_tok][cur_tok_len] = '\0';
- return cur_tok + 1;
+ tokens_len = cur_tok + 1;
}
static void
-proc_cmds(ltk_window *window, char *buf) {
- /* FIXME: resizable */
- char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH];
- int num_tokens;
- if (!(num_tokens = tokenize(tokens, buf))) return;
+proc_cmds(ltk_window *window) {
+ if (!tokenize()) return;
+ if (!tokens_len) return;
if (strcmp(tokens[0], "grid") == 0) {
- ltk_grid_cmd(window, tokens, num_tokens);
+ ltk_grid_cmd(window, tokens, tokens_len);
} else if (strcmp(tokens[0], "button") == 0) {
- ltk_button_cmd(window, tokens, num_tokens);
+ ltk_button_cmd(window, tokens, tokens_len);
} else if (strcmp(tokens[0], "set-root-widget") == 0) {
- ltk_set_root_widget_cmd(window, tokens, num_tokens);
+ ltk_set_root_widget_cmd(window, tokens, tokens_len);
} else {
(void)fprintf(stderr, "Invalid command.\n");
}
@@ -213,7 +244,6 @@ ltk_mainloop(ltk_window *window) {
struct timeval tv;
fd_set rfds;
int fd_in = fileno(stdin);
- char buf[MAX_CMD_LENGTH];
int retval;
tick.tv_sec = 0;
tick.tv_nsec = 10000;
@@ -228,7 +258,9 @@ ltk_mainloop(ltk_window *window) {
XNextEvent(window->dpy, &event);
ltk_handle_event(window, event);
}
- if (window->dirty_rect.w != 0 && window->dirty_rect.h != 0) {
+ if (retval > 0 && !read_cmdline(fd_in)) {
+ proc_cmds(window);
+ } else if (window->dirty_rect.w != 0 && window->dirty_rect.h != 0) {
ltk_redraw_window(window);
window->dirty_rect.w = 0;
window->dirty_rect.h = 0;
@@ -244,9 +276,7 @@ ltk_mainloop(ltk_window *window) {
free(last);
} while (cur);
window->first_event = window->last_event = NULL;
- } else if (retval > 0 && !read_line(fd_in, buf, sizeof(buf))) {
- proc_cmds(window, buf);
- }
+ }
/* yes, this should be improved */
nanosleep(&tick, NULL);
diff --git a/ltk.h b/ltk.h
@@ -24,10 +24,6 @@
#ifndef _LTK_H_
#define _LTK_H_
-#define MAX_TOKENS 20
-#define MAX_TOKEN_LENGTH 20
-#define MAX_CMD_LENGTH 400
-
/* Requires the following includes: <X11/Xlib.h>, <X11/Xutil.h>, "drw.h" */
typedef struct {
diff --git a/test.gui b/test.gui
@@ -4,7 +4,7 @@ grid grd1 set-row-weight 1 1
grid grd1 set-column-weight 0 1
grid grd1 set-column-weight 1 1
set-root-widget grd1
-button btn1 create Button1
+button btn1 create "I'm a button!"
grid grd1 add btn1 0 0 1 1 0
-button btn2 create Button2
+button btn2 create "I'm also a button!"
grid grd1 add btn2 1 0 1 2 3
diff --git a/text_line.c b/text_line.c
@@ -56,15 +56,17 @@ ltk_create_ximage(Display *dpy, int w, int h, int depth, XColor bg) {
/* based on http://codemadness.org/git/dwm-font/file/drw.c.html#l315 */
static void
-ltk_text_line_draw_glyph(ltk_glyph *glyph, XImage *img, XColor fg) {
+ltk_text_line_draw_glyph(ltk_glyph *glyph, int xoff, int yoff, XImage *img, XColor fg) {
+ int x = glyph->x + xoff;
+ int y = glyph->y + yoff;
double a;
int b;
for (int i = 0; i < glyph->info->h; i++) {
for (int j = 0; j < glyph->info->w; j++) {
- if (glyph->y + i >= img->height || glyph->x + j >= img->width ||
- glyph->y + i < 0 || glyph->x + i < 0)
+ if (y + i >= img->height || x + j >= img->width ||
+ y + i < 0 || x + i < 0)
continue;
- b = (glyph->y + i) * img->bytes_per_line + (glyph->x + j) * 4;
+ 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;
@@ -91,7 +93,7 @@ ltk_text_line_render(
/* FIXME: pass old image; if it has same dimensions, just clear it */
XImage *img = ltk_create_ximage(dpy, tl->w, tl->h, depth, bg);
for (int i = 0; i < tl->glyph_len; i++) {
- ltk_text_line_draw_glyph(&tl->glyphs[i], img, fg);
+ ltk_text_line_draw_glyph(&tl->glyphs[i], -tl->x_min, -tl->y_min, img, fg);
}
return img;
}
@@ -103,7 +105,7 @@ ltk_text_line_create_glyphs(ltk_window *window, struct ltk_text_line *tl) {
int index;
char *file;
size_t inc = 0;
- int x = 0, y, x1, x2, y1, y2, kern_advance, ax;
+ int x = 0, y, kern_advance, ax;
int x1_abs, x2_abs;
float scale;
int ascent, descent, line_gap;
@@ -145,16 +147,17 @@ ltk_text_line_create_glyphs(ltk_window *window, struct ltk_text_line *tl) {
ascent *= scale;
descent *= scale;
}
- stbtt_GetGlyphBitmapBox(&font->info, gid, scale, scale, &x1, &y1, &x2, &y2);
- y = ascent + y1;
- x1_abs = x + x1;
+ ginfo = ltk_get_glyph_info(font, gid, scale, glyph_cache);
+ y = ascent + ginfo->yoff;
+ x1_abs = x + ginfo->xoff;
+
tl->glyphs[i].x = x1_abs;
tl->glyphs[i].y = y;
+
stbtt_GetGlyphHMetrics(&font->info, gid, &ax, 0);
x += (int) (ax * scale);
x2_abs = x;
- ginfo = ltk_get_glyph_info(font, gid, scale, glyph_cache);
tl->glyphs[i].info = ginfo;
if (x1_abs < x_min) x_min = x1_abs;
if (y < y_min) y_min = y;
@@ -168,6 +171,9 @@ ltk_text_line_create_glyphs(ltk_window *window, struct ltk_text_line *tl) {
}
c1 = c2;
};
+ /* for drawing the glyphs at the right position on the image */
+ tl->x_min = x_min;
+ tl->y_min = y_min;
tl->w = x_max - x_min;
tl->h = y_max - y_min;
}
diff --git a/text_line.h b/text_line.h
@@ -38,6 +38,8 @@ struct ltk_text_line {
uint16_t font_size;
int w;
int h;
+ int x_min;
+ int y_min;
};
XImage *ltk_text_line_render(struct ltk_text_line *tl,
diff --git a/theme.ini b/theme.ini
@@ -3,7 +3,7 @@ font_size = 15
border_width = 0
bg = #000000
fg = #FFFFFF
-font = Awami Nastaliq
+font = Liberation Mono
[button]
border_width = 2