ltk

Socket-based GUI for X11 (WIP)
git clone git://lumidify.org/ltk.git (fast, but not encrypted)
git clone https://lumidify.org/git/ltk.git (encrypted, but very slow)
Log | Files | Refs | README | LICENSE

commit 38fe277a39863666574934ce221dcf9bd9ee4cad
parent 5aff106f8dd7610fe450e26880243949481ba5af
Author: lumidify <nobody@lumidify.org>
Date:   Thu, 10 Sep 2020 22:25:49 +0200

Add pango text support; break other text support :(

Diffstat:
MMakefile | 2+-
MREADME.md | 5+++++
Mbutton.c | 140++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Mbutton.h | 31++++++++++++++-----------------
Acolor.c | 17+++++++++++++++++
Acolor.h | 11+++++++++++
Mconfig.mk | 5+++--
Adefs.h | 2++
Mdraw.c | 2+-
Mgrid.c | 2+-
Mltk.c | 34++++++++++++++--------------------
Mltk.h | 4+++-
Atext.h | 16++++++++++++++++
Atext_pango.c | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atext_pango.h | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Autil.c | 46++++++++++++++++++++++++++++++++++++++++++++++
Mutil.h | 26++++++++++++++++++++++++++
17 files changed, 380 insertions(+), 109 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,6 +1,6 @@ include config.mk -OBJ = text_line.o text_common.o stb_truetype.o ltk.o ini.o grid.o button.o draw.o +OBJ += color.o util.o ltk.o ini.o grid.o button.o draw.o ltk: $(OBJ) $(COMPATOBJ) $(CC) -o $@ $(OBJ) $(COMPATOBJ) $(LDFLAGS) diff --git a/README.md b/README.md @@ -1,5 +1,10 @@ Not much to see here. +WARNING: DON'T TRY TO USE THIS! IT IS ONLY A PLACE FOR ME TO TRY OUT MY +WILDEST FANTASIES, NOT ACTUAL WORKING CODE. + +Also, it currently only works with pango, until I fix the basic text again. + To test: make diff --git a/button.c b/button.c @@ -29,9 +29,8 @@ #include <X11/Xutil.h> #include "util.h" #include "khash.h" -#include "text_common.h" #include "ltk.h" -#include "text_line.h" +#include "text.h" #include "button.h" static void ltk_button_draw(ltk_button *button); @@ -40,11 +39,6 @@ static ltk_button *ltk_button_create(ltk_window *window, const char *id, const char *text); static void ltk_button_destroy(ltk_button *button, int shallow); -static void ltk_grid_cmd_create( - ltk_window *window, - char **tokens, - size_t num_tokens); - void ltk_button_ini_handler(ltk_window *window, const char *prop, const char *value) { ltk_theme *theme = window->theme; @@ -57,23 +51,32 @@ ltk_button_ini_handler(ltk_window *window, const char *prop, const char *value) } else if (strcmp(prop, "pad") == 0) { theme->button->pad = atoi(value); } else if (strcmp(prop, "border") == 0) { - ltk_create_xcolor(window, value, &theme->button->border); + ltk_color_create(window->dpy, window->screen, window->cm, + value, &theme->button->border); } else if (strcmp(prop, "fill") == 0) { - ltk_create_xcolor(window, value, &theme->button->fill); + ltk_color_create(window->dpy, window->screen, window->cm, + value, &theme->button->fill); } else if (strcmp(prop, "border_pressed") == 0) { - ltk_create_xcolor(window, value, &theme->button->border_pressed); + ltk_color_create(window->dpy, window->screen, window->cm, + value, &theme->button->border_pressed); } else if (strcmp(prop, "fill_pressed") == 0) { - ltk_create_xcolor(window, value, &theme->button->fill_pressed); + ltk_color_create(window->dpy, window->screen, window->cm, + value, &theme->button->fill_pressed); } else if (strcmp(prop, "border_active") == 0) { - ltk_create_xcolor(window, value, &theme->button->border_active); + ltk_color_create(window->dpy, window->screen, window->cm, + value, &theme->button->border_active); } else if (strcmp(prop, "fill_active") == 0) { - ltk_create_xcolor(window, value, &theme->button->fill_active); + ltk_color_create(window->dpy, window->screen, window->cm, + value, &theme->button->fill_active); } else if (strcmp(prop, "border_disabled") == 0) { - ltk_create_xcolor(window, value, &theme->button->border_disabled); + ltk_color_create(window->dpy, window->screen, window->cm, + value, &theme->button->border_disabled); } else if (strcmp(prop, "fill_disabled") == 0) { - ltk_create_xcolor(window, value, &theme->button->fill_disabled); + ltk_color_create(window->dpy, window->screen, window->cm, + value, &theme->button->fill_disabled); } else if (strcmp(prop, "text_color") == 0) { - ltk_create_xcolor(window, value, &theme->button->text_color); + ltk_color_create(window->dpy, window->screen, window->cm, + value, &theme->button->text_color); } else { (void)printf("WARNING: Unknown property \"%s\" for button style.\n", prop); } @@ -85,64 +88,69 @@ ltk_button_draw(ltk_button *button) { ltk_button_theme *theme = window->theme->button; ltk_rect rect = button->widget.rect; int bw = theme->border_width; - XColor border; - XColor fill; - XImage *img = NULL; + LtkColor *border; + LtkColor *fill; switch (button->widget.state) { case LTK_NORMAL: - img = button->text_normal; - border = theme->border; - fill = theme->fill; + border = &theme->border; + fill = &theme->fill; break; case LTK_PRESSED: - img = button->text_pressed; - border = theme->border_pressed; - fill = theme->fill_pressed; + border = &theme->border_pressed; + fill = &theme->fill_pressed; break; case LTK_ACTIVE: - img = button->text_active; - border = theme->border_active; - fill = theme->fill_active; + border = &theme->border_active; + fill = &theme->fill_active; break; case LTK_DISABLED: - img = button->text_disabled; - border = theme->border_disabled; - fill = theme->fill_disabled; + border = &theme->border_disabled; + fill = &theme->fill_disabled; break; default: ltk_fatal("No style found for button!\n"); } - XSetForeground(window->dpy, window->gc, fill.pixel); - XFillRectangle(window->dpy, window->xwindow, window->gc, rect.x, rect.y, rect.w, rect.h); + XSetForeground(window->dpy, window->gc, fill->xcolor.pixel); + XFillRectangle(window->dpy, window->xwindow, window->gc, rect.x, + rect.y, rect.w, rect.h); /* FIXME: Why did I do this? */ if (bw < 1) return; - XSetForeground(window->dpy, window->gc, border.pixel); - XSetLineAttributes(window->dpy, window->gc, bw, LineSolid, CapButt, JoinMiter); - XDrawRectangle(window->dpy, window->xwindow, window->gc, rect.x + bw / 2, rect.y + bw / 2, rect.w - bw, rect.h - bw); - if (!img) { - img = ltk_text_line_render(button->tl, window->dpy, - window->xwindow, window->gc, window->cm, - theme->text_color, fill); - switch (button->widget.state) { - case LTK_NORMAL: - button->text_normal = img; - break; - case LTK_PRESSED: - button->text_pressed = img; - break; - case LTK_ACTIVE: - button->text_active = img; - break; - case LTK_DISABLED: - button->text_disabled = img; - break; - } - } - int text_x = rect.x + (rect.w - button->tl->w) / 2; - int text_y = rect.y + (rect.h - button->tl->h) / 2; - XPutImage(window->dpy, window->xwindow, window->gc, img, 0, 0, text_x, text_y, button->tl->w, button->tl->h); + XSetForeground(window->dpy, window->gc, border->xcolor.pixel); + XSetLineAttributes(window->dpy, window->gc, bw, LineSolid, + CapButt, JoinMiter); + XDrawRectangle(window->dpy, window->xwindow, window->gc, + rect.x + bw / 2, rect.y + bw / 2, rect.w - bw, rect.h - bw); + + int text_w, text_h; + ltk_text_line_get_size(button->tl, &text_w, &text_h); + int text_x = rect.x + (rect.w - text_w) / 2; + int text_y = rect.y + (rect.h - text_h) / 2; + ltk_text_line_draw(button->tl, window->gc, text_x, text_y); } +static void +ltk_button_change_state(ltk_button *button) { + ltk_window *window = button->widget.window; + ltk_button_theme *theme = window->theme->button; + LtkColor *fill; + switch (button->widget.state) { + case LTK_NORMAL: + fill = &theme->fill; + break; + case LTK_PRESSED: + fill = &theme->fill_pressed; + break; + case LTK_ACTIVE: + fill = &theme->fill_active; + break; + case LTK_DISABLED: + fill = &theme->fill_disabled; + break; + default: + ltk_fatal("No style found for button!\n"); + } + ltk_text_line_render(button->tl, fill, &theme->text_color); +} static void ltk_button_mouse_release(ltk_button *button, XEvent event) { @@ -155,17 +163,17 @@ ltk_button_create(ltk_window *window, const char *id, const char *text) { if (!button) ltk_fatal("ERROR: Unable to allocate memory for ltk_button.\n"); ltk_fill_widget_defaults(&button->widget, id, window, - &ltk_button_draw, &ltk_button_destroy, 1, LTK_BUTTON); + &ltk_button_draw, &ltk_button_change_state, &ltk_button_destroy, 1, LTK_BUTTON); button->widget.mouse_release = &ltk_button_mouse_release; uint16_t font_size = window->theme->window->font_size; - button->tl = ltk_text_line_create(font_size, strdup(text)); + button->tl = ltk_text_line_create(window->xwindow, font_size, strdup(text), -1); + int text_w, text_h; + ltk_text_line_get_size(button->tl, &text_w, &text_h); ltk_button_theme *theme = window->theme->button; - button->widget.rect.w = button->tl->w + theme->border_width * 2 + theme->pad * 2; - button->widget.rect.h = button->tl->h + theme->border_width * 2 + theme->pad * 2; - button->text_normal = NULL; - button->text_pressed = NULL; - button->text_active = NULL; - button->text_disabled = NULL; + button->widget.rect.w = text_w + theme->border_width * 2 + theme->pad * 2; + button->widget.rect.h = text_h + theme->border_width * 2 + theme->pad * 2; + /* render text */ + ltk_button_change_state(button); return button; } diff --git a/button.h b/button.h @@ -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 @@ -24,33 +24,30 @@ #ifndef _LTK_BUTTON_H_ #define _LTK_BUTTON_H_ -/* Requires the following includes: <X11/Xlib.h>, "ltk.h" */ +/* Requires the following includes: <X11/Xlib.h>, "ltk.h", "color.h", "text.h" */ typedef struct { ltk_widget widget; - struct ltk_text_line *tl; - XImage *text_normal; - XImage *text_active; - XImage *text_pressed; - XImage *text_disabled; + LtkTextLine *tl; + Pixmap text_pixmap; } ltk_button; typedef struct ltk_button_theme { int border_width; - XColor text_color; + LtkColor text_color; int pad; - XColor border; - XColor fill; + LtkColor border; + LtkColor fill; - XColor border_pressed; - XColor fill_pressed; + LtkColor border_pressed; + LtkColor fill_pressed; - XColor border_active; - XColor fill_active; + LtkColor border_active; + LtkColor fill_active; - XColor border_disabled; - XColor fill_disabled; + LtkColor border_disabled; + LtkColor fill_disabled; } ltk_button_theme; void ltk_button_ini_handler(ltk_window *window, const char *prop, const char *value); @@ -60,4 +57,4 @@ void ltk_button_cmd( char **tokens, size_t num_tokens); -#endif +#endif /* _LTK_BUTTON_H_ */ diff --git a/color.c b/color.c @@ -0,0 +1,17 @@ +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include "util.h" +#include "color.h" + +void +ltk_color_create(Display *dpy, int screen, Colormap cm, const char *hex, LtkColor *col) { + if (!XParseColor(dpy, cm, hex, &col->xcolor)) { + /* FIXME: better error reporting */ + ltk_err("ltk_color_create"); + } + XAllocColor(dpy, cm, &col->xcolor); + /* FIXME: replace with XftColorAllocValue; error checking */ + #ifdef USE_XFT + XftColorAllocName(dpy, DefaultVisual(dpy, screen), cm, hex, &col->xftcolor); + #endif +} diff --git a/color.h b/color.h @@ -0,0 +1,11 @@ +#include "defs.h" +#ifdef USE_XFT + #include <X11/Xft/Xft.h> +#endif + +typedef struct { + XColor xcolor; + #ifdef USE_XFT + XftColor xftcolor; + #endif +} LtkColor; diff --git a/config.mk b/config.mk @@ -1,7 +1,8 @@ VERSION = -999 -CFLAGS = -g -std=c99 -w -fcommon -Wall -Werror -Wextra `pkg-config --cflags x11 fontconfig` -pedantic -LDFLAGS = -lm `pkg-config --libs x11 fontconfig` +CFLAGS = -g -std=c99 -w -fcommon -Wall -Werror -Wextra `pkg-config --cflags x11 fontconfig pangoxft` -pedantic +LDFLAGS = -lm `pkg-config --libs x11 fontconfig pangoxft` +OBJ = text_pango.o # OpenBSD COMPATOBJ = diff --git a/defs.h b/defs.h @@ -0,0 +1,2 @@ +#define USE_PANGO +#define USE_XFT diff --git a/draw.c b/draw.c @@ -80,7 +80,7 @@ ltk_draw_create(ltk_window *window, const char *id, int w, int h, const char *co if (!draw) ltk_fatal("ERROR: Unable to allocate memory for ltk_draw.\n"); ltk_fill_widget_defaults(&draw->widget, id, window, - &ltk_draw_draw, &ltk_draw_destroy, 1, LTK_DRAW); + &ltk_draw_draw, NULL, &ltk_draw_destroy, 1, LTK_DRAW); draw->widget.resize = &ltk_draw_resize; draw->widget.rect.w = w; draw->widget.rect.h = h; diff --git a/grid.c b/grid.c @@ -100,7 +100,7 @@ ltk_grid_create(ltk_window *window, const char *id, int rows, int columns) { ltk_grid *grid = malloc(sizeof(ltk_grid)); ltk_fill_widget_defaults(&grid->widget, id, window, &ltk_grid_draw, - &ltk_grid_destroy, 0, LTK_GRID); + NULL, &ltk_grid_destroy, 0, LTK_GRID); grid->widget.mouse_press = &ltk_grid_mouse_press; grid->widget.mouse_release = &ltk_grid_mouse_release; grid->widget.motion_notify = &ltk_grid_motion_notify; diff --git a/ltk.c b/ltk.c @@ -35,10 +35,9 @@ #include "util.h" #include "khash.h" #include "ini.h" -#include "text_common.h" +#include "text.h" #include "ltk.h" #include "grid.h" -#include "text_line.h" #include "button.h" #include "draw.h" @@ -54,22 +53,6 @@ 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) { - FILE *f; - char *file_contents; - f = fopen(path, "rb"); - fseek(f, 0, SEEK_END); - *len = ftell(f); - fseek(f, 0, SEEK_SET); - file_contents = malloc(*len + 1); - fread(file_contents, 1, *len, f); - file_contents[*len] = '\0'; - fclose(f); - - return file_contents; -} - static ltk_rect ltk_rect_union(ltk_rect r1, ltk_rect r2) { ltk_rect u; @@ -322,7 +305,6 @@ ltk_create_window(const char *theme_path, const char *title, int x, int y, unsig window->wm_delete_msg = XInternAtom(window->dpy, "WM_DELETE_WINDOW", False); ltk_window_theme *wtheme = window->theme->window; - ltk_init_default_font(wtheme->font); window->xwindow = XCreateSimpleWindow(window->dpy, DefaultRootWindow(window->dpy), x, y, w, h, wtheme->border_width, @@ -335,6 +317,8 @@ ltk_create_window(const char *theme_path, const char *title, int x, int y, unsig XSetWMProtocols(window->dpy, window->xwindow, &window->wm_delete_msg, 1); window->root_widget = NULL; + ltk_init_text(wtheme->font, window->dpy, window->screen, window->cm); + window->other_event = &ltk_window_other_event; window->rect.w = 0; @@ -466,6 +450,8 @@ ltk_window_remove_active_widget(ltk_window *window) { while (widget) { widget->state = LTK_NORMAL; widget->active_widget = NULL; + if (widget->change_state) + widget->change_state(widget); if (widget->needs_redraw) ltk_window_invalidate_rect(window, widget->rect); widget = widget->parent; @@ -488,7 +474,8 @@ ltk_window_set_active_widget(ltk_window *window, ltk_widget *widget) { void ltk_fill_widget_defaults(ltk_widget *widget, const char *id, ltk_window *window, - void (*draw) (void *), void (*destroy) (void *, int), unsigned int needs_redraw, + void (*draw) (void *), void (*change_state) (void *), + void (*destroy) (void *, int), unsigned int needs_redraw, ltk_widget_type type) { widget->id = strdup(id); widget->window = window; @@ -506,6 +493,7 @@ ltk_fill_widget_defaults(ltk_widget *widget, const char *id, ltk_window *window, widget->resize = NULL; widget->draw = draw; + widget->change_state = change_state; widget->destroy = destroy; widget->needs_redraw = needs_redraw; @@ -530,6 +518,8 @@ ltk_widget_mouse_press_event(ltk_widget *widget, XEvent event) { if (event.xbutton.button == 1) { ltk_widget *parent = widget->parent; widget->state = LTK_PRESSED; + if (widget->change_state) + widget->change_state(widget); if (widget->needs_redraw) ltk_window_invalidate_rect(widget->window, widget->rect); } @@ -544,6 +534,8 @@ ltk_widget_mouse_release_event(ltk_widget *widget, XEvent event) { return; if (widget->state == LTK_PRESSED) { widget->state = LTK_ACTIVE; + if (widget->change_state) + widget->change_state(widget); if (widget->needs_redraw) ltk_window_invalidate_rect(widget->window, widget->rect); } @@ -558,6 +550,8 @@ ltk_widget_motion_notify_event(ltk_widget *widget, XEvent event) { short pressed = (event.xmotion.state & Button1Mask) == Button1Mask; if ((widget->state == LTK_NORMAL) && !pressed) { widget->state = LTK_ACTIVE; + if (widget->change_state) + widget->change_state(widget); if (widget->mouse_enter) widget->mouse_enter(widget, event); /* FIXME: do this properly */ diff --git a/ltk.h b/ltk.h @@ -73,6 +73,7 @@ typedef struct ltk_widget { void (*resize) (void *, int, int); void (*draw) (void *); + void (*change_state) (void *); void (*destroy) (void *, int); ltk_rect rect; @@ -156,7 +157,8 @@ void ltk_remove_active_widget(ltk_widget *widget); void ltk_set_active_widget(ltk_window *window, ltk_widget *widget); void ltk_fill_widget_defaults(ltk_widget *widget, const char *id, ltk_window * window, - void (*draw) (void *), void (*destroy) (void *, int), unsigned int needs_redraw, + void (*draw) (void *), void (*change_state) (void *), + void (*destroy) (void *, int), unsigned int needs_redraw, ltk_widget_type type); void ltk_widget_mouse_press_event(ltk_widget *widget, XEvent event); diff --git a/text.h b/text.h @@ -0,0 +1,16 @@ +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <stdint.h> +#include "defs.h" +#include "color.h" + +#ifdef USE_PANGO + #include <pango/pangoxft.h> + #include "text_pango.h" +#endif + +/* Basic */ +#ifdef USE_BASIC_TEXT + #include "text_common.h" + #include "text_line.h" +#endif diff --git a/text_pango.c b/text_pango.c @@ -0,0 +1,95 @@ +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xos.h> +#include <pango/pangoxft.h> +#include "color.h" +#include "text_pango.h" +#include "util.h" + +struct { + PangoFontMap *fontmap; + PangoContext *context; + char *default_font; + Display *dpy; + int screen; + Colormap cm; +} tm = {NULL, NULL, NULL, NULL, 0, 0}; + +void +ltk_init_text(const char *default_font, Display *dpy, int screen, Colormap cm) { + tm.fontmap = pango_xft_get_font_map(dpy, screen); + tm.context = pango_font_map_create_context(tm.fontmap); + tm.default_font = strdup(default_font); + if (!tm.default_font) ltk_err("ltk_init_text (pango)"); + tm.dpy = dpy; + tm.screen = screen; + tm.cm = cm; +} + +void +ltk_cleanup_text(void) { + if (tm.default_font) free(tm.default_font); + /* FIXME: destroy fontmap and context */ +} + +LtkTextLine * +ltk_text_line_create(Window window, uint16_t font_size, char *text, int width) { + if (!tm.context) + ltk_err("ltk_text_line_create (pango): text not initialized yet"); + /* FIXME: respect font size */ + /* + PangoFontDescription *desc = pango_font_description_from_string("Sans Bold 27"); + pango_layout_set_font_description(layout, desc); + pango_font_description_free(desc); + */ + LtkTextLine *line = malloc(sizeof(LtkTextLine)); + if (!line) ltk_err("ltk_text_line_create (pango)"); + line->text = text; + line->font_size = font_size; + line->layout = pango_layout_new(tm.context); + if (width > 0) { + pango_layout_set_width(line->layout, width * PANGO_SCALE); + pango_layout_set_wrap(line->layout, PANGO_WRAP_WORD_CHAR); + } + pango_layout_set_text(line->layout, text, -1); + pango_layout_get_size(line->layout, &line->w, &line->h); + line->w /= PANGO_SCALE; + line->h /= PANGO_SCALE; + XWindowAttributes attrs; + XGetWindowAttributes(tm.dpy, window, &attrs); + line->pixmap = XCreatePixmap(tm.dpy, window, line->w, line->h, attrs.depth); + line->draw = XftDrawCreate(tm.dpy, line->pixmap, DefaultVisual(tm.dpy, tm.screen), tm.cm); + line->window = window; + + return line; +} + +void +ltk_text_line_render(LtkTextLine *tl, LtkColor *bg, LtkColor *fg) { + XftDrawRect(tl->draw, &bg->xftcolor, 0, 0, tl->w, tl->h); + pango_xft_render_layout(tl->draw, &fg->xftcolor, tl->layout, 0, 0); +} + +void +ltk_text_line_draw(LtkTextLine *tl, GC gc, int x, int y) { + XCopyArea(tm.dpy, tl->pixmap, tl->window, gc, 0, 0, tl->w, tl->h, x, y); +} + +void +ltk_text_line_get_size(LtkTextLine *tl, int *w, int *h) { + *w = tl->w; + *h = tl->h; +} + +void +ltk_text_line_destroy(LtkTextLine *tl) { + g_object_unref(tl->layout); + XftDrawDestroy(tl->draw); + XFreePixmap(tm.dpy, tl->pixmap); + free(tl->text); + free(tl); +} diff --git a/text_pango.h b/text_pango.h @@ -0,0 +1,51 @@ +/* + * This file is part of the Lumidify ToolKit (LTK) + * Copyright (c) 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _TEXT_PANGO_H_ +#define _TEXT_PANGO_H_ + +/* +Requires the following includes: +<X11/Xlib.h>, <X11/Xutil.h>, <stdint.h>, <pango/pangoxft.h> +*/ + +typedef struct { + char *text; + uint16_t font_size; + int w; + int h; + Window window; + PangoLayout *layout; + XftDraw *draw; + Pixmap pixmap; +} LtkTextLine; + +void ltk_init_text(const char *default_font, Display *dpy, int screen, Colormap cm); +void ltk_cleanup_text(void); +LtkTextLine *ltk_text_line_create(Window window, uint16_t font_size, char *text, int width); +void ltk_text_line_render(LtkTextLine *tl, LtkColor *bg, LtkColor *fg); +void ltk_text_line_draw(LtkTextLine *tl, GC gc, int x, int y); +void ltk_text_line_get_size(LtkTextLine *tl, int *w, int *h); +void ltk_text_line_destroy(LtkTextLine *tl); + +#endif /* _TEXT_PANGO_H_ */ diff --git a/util.c b/util.c @@ -0,0 +1,46 @@ +/* + * This file is part of the Lumidify ToolKit (LTK) + * Copyright (c) 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <stdio.h> + +void +ltk_err(const char *msg) { + perror(msg); + exit(1); +} + +char * +ltk_read_file(const char *path, unsigned long *len) { + FILE *f; + char *file_contents; + f = fopen(path, "rb"); + fseek(f, 0, SEEK_END); + *len = ftell(f); + fseek(f, 0, SEEK_SET); + file_contents = malloc(*len + 1); + fread(file_contents, 1, *len, f); + file_contents[*len] = '\0'; + fclose(f); + + return file_contents; +} diff --git a/util.h b/util.h @@ -1,5 +1,31 @@ +/* + * This file is part of the Lumidify ToolKit (LTK) + * Copyright (c) 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #ifndef __OpenBSD__ long long strtonum(const char *numstr, long long minval, long long maxval, const char **errstrp); #endif + +void ltk_err(const char *msg); +char *ltk_read_file(const char *path, unsigned long *len);