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