URI: 
       tSlightly improve graphics and text interface - ltk - Socket-based GUI for X11 (WIP)
  HTML git clone git://lumidify.org/ltk.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/git/ltk.git (encrypted, but very slow)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit d1f0903f23c0887590329483d8993cbefb1b6189
   DIR parent 00cefe189580f8332951122af1f6d6230d9652c3
  HTML Author: lumidify <nobody@lumidify.org>
       Date:   Thu,  5 May 2022 13:14:22 +0200
       
       Slightly improve graphics and text interface
       
       Diffstat:
         M Makefile                            |       3 ++-
         M src/box.h                           |       4 +++-
         M src/button.c                        |      37 +++++--------------------------
         M src/color.h                         |       8 +++++---
         A src/compat.h                        |       9 +++++++++
         M src/graphics.h                      |      29 ++++++++++++++++-------------
         M src/graphics_xlib.c                 |      95 +++++++++++++++++++------------
         M src/label.c                         |      12 +++++-------
         M src/ltk.h                           |       6 ++++++
         M src/ltkd.c                          |       9 +++++----
         M src/scrollbar.c                     |       8 ++++----
         M src/text.h                          |      37 ++++++++++++++++++++++---------
         M src/text_pango.c                    |     111 ++++++++++++++-----------------
         M src/text_stb.c                      |     254 ++++++++++++++-----------------
       
       14 files changed, 311 insertions(+), 311 deletions(-)
       ---
   DIR diff --git a/Makefile b/Makefile
       t@@ -18,7 +18,8 @@ LDFLAGS += -lm `pkg-config --libs x11 fontconfig xext`
        # Note: this macro magic for debugging and pango rendering seems ugly; it should probably be changed
        
        # debug
       -DEV_1 = -g -Wall -Werror -Wextra -pedantic
       +DEV_1 = -g -Wall -Wextra -pedantic
       +#-Werror
        
        # stb rendering
        EXTRA_OBJ_0 = src/stb_truetype.o src/text_stb.o
   DIR diff --git a/src/box.h b/src/box.h
       t@@ -1,5 +1,5 @@
        /*
       - * Copyright (c) 2021 lumidify <nobody@lumidify.org>
       + * Copyright (c) 2021, 2022 lumidify <nobody@lumidify.org>
         *
         * Permission to use, copy, modify, and/or distribute this software for any
         * purpose with or without fee is hereby granted, provided that the above
       t@@ -22,6 +22,8 @@
        typedef struct {
                ltk_widget widget;
                ltk_scrollbar *sc;
       +        ltk_widget *pressed_widget;
       +        ltk_widget *active_widget;
                ltk_widget **widgets;
                size_t num_alloc;
                size_t num_widgets;
   DIR diff --git a/src/button.c b/src/button.c
       t@@ -37,7 +37,7 @@
        static void ltk_button_draw(ltk_widget *self, ltk_rect clip);
        static int ltk_button_mouse_release(ltk_widget *self, XEvent event);
        static ltk_button *ltk_button_create(ltk_window *window,
       -    const char *id, const char *text);
       +    const char *id, char *text);
        static void ltk_button_destroy(ltk_widget *self, int shallow);
        static void ltk_button_change_state(ltk_widget *self);
        static void ltk_button_redraw_surface(ltk_button *button, ltk_surface *s);
       t@@ -142,12 +142,11 @@ ltk_button_draw(ltk_widget *self, ltk_rect clip) {
                ltk_surface *s;
                if (!ltk_surface_cache_get_surface(self->surface_key, &s) || self->dirty)
                        ltk_button_redraw_surface(button, s);
       -        ltk_surface_copy_to_window(s, self->window, ltk_rect_relative(rect, clip_final), clip_final.x, clip_final.y);
       +        ltk_surface_copy(s, self->window->surface, ltk_rect_relative(rect, clip_final), clip_final.x, clip_final.y);
        }
        
        static void
        ltk_button_redraw_surface(ltk_button *button, ltk_surface *s) {
       -        ltk_window *window = button->widget.window;
                ltk_rect rect = button->widget.rect;
                int bw = theme.border_width;
                ltk_color *border = NULL, *fill = NULL;
       t@@ -181,33 +180,12 @@ ltk_button_redraw_surface(ltk_button *button, ltk_surface *s) {
                ltk_text_line_get_size(button->tl, &text_w, &text_h);
                int text_x = (rect.w - text_w) / 2;
                int text_y = (rect.h - text_h) / 2;
       -        /* FIXME: Remove clipping rect from text line - this is just used here as a dummy
       -           because it is completely ignored */
       -        ltk_text_line_draw(button->tl, s, window->gc, text_x, text_y, rect);
       +        ltk_text_line_draw(button->tl, s, &theme.text_color, text_x, text_y);
                button->widget.dirty = 0;
        }
        
        static void
        ltk_button_change_state(ltk_widget *self) {
       -        ltk_button *button = (ltk_button *)self;
       -        ltk_color *fill = NULL;
       -        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_change_colors(button->tl, &theme.text_color, fill);
                self->dirty = 1;
        }
        
       t@@ -220,20 +198,17 @@ ltk_button_mouse_release(ltk_widget *self, XEvent event) {
        }
        
        static ltk_button *
       -ltk_button_create(ltk_window *window, const char *id, const char *text) {
       -        char *text_copy;
       +ltk_button_create(ltk_window *window, const char *id, char *text) {
                ltk_button *button = ltk_malloc(sizeof(ltk_button));
        
                uint16_t font_size = window->theme.font_size;
       -        text_copy = ltk_strdup(text);
       -        button->tl = ltk_text_line_create(window->xwindow, font_size, text_copy, -1, &theme.text_color, &theme.fill);
       +        button->tl = ltk_text_line_create(window->text_context, font_size, text, 0, -1);
                int text_w, text_h;
                ltk_text_line_get_size(button->tl, &text_w, &text_h);
                button->widget.ideal_w = text_w + theme.border_width * 2 + theme.pad * 2;
                button->widget.ideal_h = text_h + theme.border_width * 2 + theme.pad * 2;
                ltk_fill_widget_defaults(&button->widget, id, window, &vtable, button->widget.ideal_w, button->widget.ideal_h);
       -        /* render text */
       -        ltk_button_change_state((ltk_widget *)button);
       +        button->widget.dirty = 1;
        
                return button;
        }
   DIR diff --git a/src/color.h b/src/color.h
       t@@ -1,5 +1,5 @@
        /*
       - * Copyright (c) 2021 lumidify <nobody@lumidify.org>
       + * Copyright (c) 2021, 2022 lumidify <nobody@lumidify.org>
         *
         * Permission to use, copy, modify, and/or distribute this software for any
         * purpose with or without fee is hereby granted, provided that the above
       t@@ -17,13 +17,15 @@
        #ifndef _LTK_COLOR_H_
        #define _LTK_COLOR_H_
        
       -#if USE_PANGO == 1
       +#include "compat.h"
       +
       +#if USE_XFT == 1
          #include <X11/Xft/Xft.h>
        #endif
        
        typedef struct {
                XColor xcolor;
       -        #if USE_PANGO == 1
       +        #if USE_XFT == 1
                XftColor xftcolor;
                #endif
        } ltk_color;
   DIR diff --git a/src/compat.h b/src/compat.h
       t@@ -0,0 +1,9 @@
       +#ifdef _LTK_COMPAT_H_
       +#define _LTK_COMPAT_H_
       +
       +#if USE_PANGO == 1
       +#undef USE_XFT
       +#define USE_XFT 1
       +#endif
       +
       +#endif
   DIR diff --git a/src/graphics.h b/src/graphics.h
       t@@ -17,30 +17,31 @@
        #ifndef _LTK_GRAPHICS_H_
        #define _LTK_GRAPHICS_H_
        
       +/* FIXME: make this global and use it elsewhere */
       +#define USE_XLIB_GRAPHICS 1
       +
        /* FIXME: Is it faster to take ltk_color* or ltk_color? */
        
        #include <X11/Xft/Xft.h>
        #include "rect.h"
        #include "color.h"
        #include "ltk.h"
       +#include "compat.h"
        
       -typedef struct ltk_surface ltk_surface;
       +/* typedef struct ltk_surface ltk_surface; */
        
        /* FIXME: graphics context */
        ltk_surface *ltk_surface_create(ltk_window *window, int w, int h);
        void ltk_surface_destroy(ltk_surface *s);
       -void ltk_surface_resize(ltk_surface *s, int w, int h);
       -void ltk_surface_copy(ltk_surface *src, ltk_surface *dst, ltk_rect src_rect, int dst_x, int dst_y);
       -void ltk_surface_copy_to_window(ltk_surface *src, ltk_window *dst, ltk_rect src_rect, int dst_x, int dst_y);
       +/* returns 0 if successful, 1 if not resizable */
       +int ltk_surface_resize(ltk_surface *s, int w, int h);
       +/* FIXME: kind of hacky */
       +void ltk_surface_update_size(ltk_surface *s, int w, int h);
       +ltk_surface *ltk_surface_from_window(ltk_window *window);
        void ltk_surface_get_size(ltk_surface *s, int *w, int *h);
       -
       -/* The ltk_surface* and ltk_window* functions do the same things, but a window cannot
       -   be wrapped in an ltk_surface since the resize function wouldn't make sense there */
       -/* FIXME: avoid this ugliness */
       +void ltk_surface_copy(ltk_surface *src, ltk_surface *dst, ltk_rect src_rect, int dst_x, int dst_y);
        void ltk_surface_draw_rect(ltk_surface *s, ltk_color *c, ltk_rect rect, int line_width);
        void ltk_surface_fill_rect(ltk_surface *s, ltk_color *c, ltk_rect rect);
       -void ltk_window_draw_rect(ltk_window *window, ltk_color *c, ltk_rect rect, int line_width);
       -void ltk_window_fill_rect(ltk_window *window, ltk_color *c, ltk_rect rect);
        
        /* TODO */
        /*
       t@@ -50,10 +51,12 @@ void ltk_surface_draw_circle(ltk_surface *s, ltk_color *c, int xc, int yc, int r
        void ltk_surface_fill_circle(ltk_surface *s, ltk_color *c, int xc, int yc, int r);
        */
        
       -#if USE_PANGO == 1
       +/* FIXME: only generate draw if needed */
       +#if USE_XFT == 1
        XftDraw *ltk_surface_get_xft_draw(ltk_surface *s);
        #endif
       -/* FIXME: only expose this when needed */
       -Pixmap ltk_surface_get_pixmap(ltk_surface *s);
       +#if USE_XLIB_GRAPHICS == 1
       +Drawable ltk_surface_get_drawable(ltk_surface *s);
       +#endif
        
        #endif /* _LTK_GRAPHICS_H_ */
   DIR diff --git a/src/graphics_xlib.c b/src/graphics_xlib.c
       t@@ -23,14 +23,16 @@
        #include "widget.h"
        #include "ltk.h"
        #include "memory.h"
       +#include "compat.h"
        
        struct ltk_surface {
       -        int w, h;
       -        ltk_window *window;
       -        Pixmap p;
       -        #if USE_PANGO == 1
       -        XftDraw *xftdraw;
       -        #endif
       +        int w, h;
       +        ltk_window *window;
       +        Drawable d;
       +        #if USE_XFT == 1
       +        XftDraw *xftdraw;
       +        #endif
       +        char resizable;
        };
        
        ltk_surface *
       t@@ -39,31 +41,56 @@ ltk_surface_create(ltk_window *window, int w, int h) {
                s->w = w;
                s->h = h;
                s->window = window;
       -        s->p = XCreatePixmap(window->dpy, window->xwindow, w, h, window->depth);
       -        #if USE_PANGO == 1
       -        s->xftdraw = XftDrawCreate(window->dpy, s->p, window->vis, window->cm);
       +        s->d = XCreatePixmap(window->dpy, window->xwindow, w, h, window->depth);
       +        #if USE_XFT == 1
       +        s->xftdraw = XftDrawCreate(window->dpy, s->d, window->vis, window->cm);
                #endif
       +        s->resizable = 1;
       +        return s;
       +}
       +
       +ltk_surface *
       +ltk_surface_from_window(ltk_window *window) {
       +        ltk_surface *s = ltk_malloc(sizeof(ltk_surface));
       +        s->w = window->rect.w;
       +        s->h = window->rect.h;
       +        s->window = window;
       +        s->d = window->drawable;
       +        #if USE_XFT == 1
       +        s->xftdraw = XftDrawCreate(window->dpy, s->d, window->vis, window->cm);
       +        #endif
       +        s->resizable = 0;
                return s;
        }
        
        void
        ltk_surface_destroy(ltk_surface *s) {
       -        #if USE_PANGO == 1
       +        #if USE_XFT == 1
                XftDrawDestroy(s->xftdraw);
                #endif
       -        XFreePixmap(s->window->dpy, s->p);
       +        if (s->resizable)
       +                XFreePixmap(s->window->dpy, (Pixmap)s->d);
                ltk_free(s);
        }
        
        void
       +ltk_surface_update_size(ltk_surface *s, int w, int h) {
       +        s->w = w;
       +        s->h = h;
       +}
       +
       +int
        ltk_surface_resize(ltk_surface *s, int w, int h) {
       +        if (!s->resizable)
       +                return 1;
                s->w = w;
                s->h = h;
       -        XFreePixmap(s->window->dpy, s->p);
       -        s->p = XCreatePixmap(s->window->dpy, s->window->xwindow, w, h, s->window->depth);
       -        #if USE_PANGO == 1
       -        XftDrawChange(s->xftdraw, s->p);
       +        XFreePixmap(s->window->dpy, (Pixmap)s->d);
       +        s->d = XCreatePixmap(s->window->dpy, s->window->xwindow, w, h, s->window->depth);
       +        #if USE_XFT == 1
       +        XftDrawChange(s->xftdraw, s->d);
                #endif
       +        return 0;
        }
        
        void
       t@@ -76,13 +103,13 @@ void
        ltk_surface_draw_rect(ltk_surface *s, ltk_color *c, ltk_rect rect, int line_width) {
                XSetForeground(s->window->dpy, s->window->gc, c->xcolor.pixel);
                XSetLineAttributes(s->window->dpy, s->window->gc, line_width, LineSolid, CapButt, JoinMiter);
       -        XDrawRectangle(s->window->dpy, s->p, s->window->gc, rect.x, rect.y, rect.w, rect.h);
       +        XDrawRectangle(s->window->dpy, s->d, s->window->gc, rect.x, rect.y, rect.w, rect.h);
        }
        
        void
        ltk_surface_fill_rect(ltk_surface *s, ltk_color *c, ltk_rect rect) {
                XSetForeground(s->window->dpy, s->window->gc, c->xcolor.pixel);
       -        XFillRectangle(s->window->dpy, s->p, s->window->gc, rect.x, rect.y, rect.w, rect.h);
       +        XFillRectangle(s->window->dpy, s->d, s->window->gc, rect.x, rect.y, rect.w, rect.h);
        }
        
        void
       t@@ -98,6 +125,14 @@ ltk_window_fill_rect(ltk_window *window, ltk_color *c, ltk_rect rect) {
                XFillRectangle(window->dpy, window->drawable, window->gc, rect.x, rect.y, rect.w, rect.h);
        }
        
       +void
       +ltk_surface_copy(ltk_surface *src, ltk_surface *dst, ltk_rect src_rect, int dst_x, int dst_y) {
       +        XCopyArea(
       +            src->window->dpy, src->d, dst->d, src->window->gc,
       +            src_rect.x, src_rect.y, src_rect.w, src_rect.h, dst_x, dst_y
       +        );
       +}
       +
        /* TODO */
        /*
        void
       t@@ -117,30 +152,16 @@ ltk_surface_fill_circle(ltk_surface *s, ltk_color *c, int xc, int yc, int r) {
        }
        */
        
       -void
       -ltk_surface_copy(ltk_surface *src, ltk_surface *dst, ltk_rect src_rect, int dst_x, int dst_y) {
       -        XCopyArea(
       -            src->window->dpy, src->p, dst->p, src->window->gc,
       -            src_rect.x, src_rect.y, src_rect.w, src_rect.h, dst_x, dst_y
       -        );
       -}
       -
       -void
       -ltk_surface_copy_to_window(ltk_surface *src, ltk_window *dst, ltk_rect src_rect, int dst_x, int dst_y) {
       -        XCopyArea(
       -            src->window->dpy, src->p, dst->drawable, src->window->gc,
       -            src_rect.x, src_rect.y, src_rect.w, src_rect.h, dst_x, dst_y
       -        );
       -}
       -
       -#if USE_PANGO == 1
       +#if USE_XFT == 1
        XftDraw *
        ltk_surface_get_xft_draw(ltk_surface *s) {
                return s->xftdraw;
        }
        #endif
        
       -Pixmap
       -ltk_surface_get_pixmap(ltk_surface *s) {
       -        return s->p;
       +#if USE_XLIB_GRAPHICS == 1
       +Drawable
       +ltk_surface_get_drawable(ltk_surface *s) {
       +        return s->d;
        }
       +#endif
   DIR diff --git a/src/label.c b/src/label.c
       t@@ -36,7 +36,7 @@
        
        static void ltk_label_draw(ltk_widget *self, ltk_rect clip);
        static ltk_label *ltk_label_create(ltk_window *window,
       -    const char *id, const char *text);
       +    const char *id, char *text);
        static void ltk_label_destroy(ltk_widget *self, int shallow);
        static void ltk_label_redraw_surface(ltk_label *label, ltk_surface *s);
        
       t@@ -86,7 +86,7 @@ ltk_label_draw(ltk_widget *self, ltk_rect clip) {
                ltk_surface *s;
                if (!ltk_surface_cache_get_surface(self->surface_key, &s) || self->dirty)
                        ltk_label_redraw_surface(label, s);
       -        ltk_surface_copy_to_window(s, self->window, ltk_rect_relative(rect, clip_final), clip_final.x, clip_final.y);
       +        ltk_surface_copy(s, self->window->surface, ltk_rect_relative(rect, clip_final), clip_final.x, clip_final.y);
        }
        
        static void
       t@@ -100,17 +100,15 @@ ltk_label_redraw_surface(ltk_label *label, ltk_surface *s) {
                ltk_text_line_get_size(label->tl, &text_w, &text_h);
                int text_x = (r.w - text_w) / 2;
                int text_y = (r.h - text_h) / 2;
       -        ltk_text_line_draw(label->tl, s, label->widget.window->gc, text_x, text_y, r);
       +        ltk_text_line_draw(label->tl, s, &theme.text_color, text_x, text_y);
        }
        
        static ltk_label *
       -ltk_label_create(ltk_window *window, const char *id, const char *text) {
       -        char *text_copy;
       +ltk_label_create(ltk_window *window, const char *id, char *text) {
                ltk_label *label = ltk_malloc(sizeof(ltk_label));
        
                uint16_t font_size = window->theme.font_size;
       -        text_copy = ltk_strdup(text);
       -        label->tl = ltk_text_line_create(window->xwindow, font_size, text_copy, -1, &theme.text_color, &theme.bg_color);
       +        label->tl = ltk_text_line_create(window->text_context, font_size, text, 0, -1);
                int text_w, text_h;
                ltk_text_line_get_size(label->tl, &text_w, &text_h);
                label->widget.ideal_w = text_w + theme.pad * 2;
   DIR diff --git a/src/ltk.h b/src/ltk.h
       t@@ -56,10 +56,16 @@ struct ltk_event_queue {
          though, so it's just going to stay that way.
        */
        
       +/* FIXME: fix this ugliness; remove circular dependencies */
       +typedef struct ltk_text_context ltk_text_context;
       +typedef struct ltk_surface ltk_surface;
       +
        typedef struct ltk_window {
                Display *dpy;
                Visual *vis;
                ltk_surface_cache *surface_cache;
       +        ltk_text_context *text_context;
       +        ltk_surface *surface;
                Colormap cm;
                GC gc;
                int screen;
   DIR diff --git a/src/ltkd.c b/src/ltkd.c
       t@@ -506,6 +506,7 @@ ltk_window_other_event(ltk_window *window, XEvent event) {
                                window->rect.w = w;
                                window->rect.h = h;
                                ltk_window_invalidate_rect(window, window->rect);
       +                        ltk_surface_update_size(window->surface, w, h);
                                if (ptr) {
                                        ptr->rect.w = w;
                                        ptr->rect.h = h;
       t@@ -616,10 +617,7 @@ ltk_create_window(const char *title, int x, int y, unsigned int w, unsigned int 
        
                window->surface_cache = ltk_surface_cache_create(window);
        
       -        ltk_init_text(window->theme.font, window->dpy, window->screen, window->cm);
       -
                window->other_event = &ltk_window_other_event;
       -
                window->first_event = window->last_event = NULL;
        
                window->rect.w = 0;
       t@@ -630,6 +628,9 @@ ltk_create_window(const char *title, int x, int y, unsigned int w, unsigned int 
                window->dirty_rect.h = 0;
                window->dirty_rect.x = 0;
                window->dirty_rect.y = 0;
       +        window->surface = ltk_surface_from_window(window);
       +
       +        window->text_context = ltk_text_context_create(window, window->theme.font);
        
                XClearWindow(window->dpy, window->xwindow);
                XMapRaised(window->dpy, window->xwindow);
       t@@ -639,8 +640,8 @@ ltk_create_window(const char *title, int x, int y, unsigned int w, unsigned int 
        
        static void
        ltk_destroy_window(ltk_window *window) {
       +        ltk_text_context_destroy(window->text_context);
                XDestroyWindow(window->dpy, window->xwindow);
       -        ltk_cleanup_text();
                XCloseDisplay(window->dpy);
                /* FIXME: This doesn't work because it can sometimes be a readonly
                   string from ltk_window_setup_theme_defaults! */
   DIR diff --git a/src/scrollbar.c b/src/scrollbar.c
       t@@ -160,7 +160,7 @@ ltk_scrollbar_draw(ltk_widget *self, ltk_rect clip) {
                }
                ltk_surface_fill_rect(s, fg, (ltk_rect){handle_x, handle_y, handle_w, handle_h});
                ltk_rect clip_final = ltk_rect_intersect(clip, rect);
       -        ltk_surface_copy_to_window(s, self->window, ltk_rect_relative(rect, clip_final), clip_final.x, clip_final.y);
       +        ltk_surface_copy(s, self->window->surface, ltk_rect_relative(rect, clip_final), clip_final.x, clip_final.y);
        }
        
        static int
       t@@ -200,11 +200,12 @@ static int
        ltk_scrollbar_motion_notify(ltk_widget *self, XEvent event) {
                (void)self;
                (void)event;
       -        /*
       +        ltk_scrollbar *sc = (ltk_scrollbar *)self;
                double scale;
                int delta, max_pos;
       -        if (sc->widget.state != LTK_PRESSED)
       +        if (self->state != LTK_PRESSED) {
                        return 1;
       +        }
                if (sc->orient == LTK_HORIZONTAL) {
                        delta = event.xbutton.x - sc->last_mouse_x;
                        max_pos = sc->virtual_size > sc->widget.rect.w ? sc->virtual_size - sc->widget.rect.w : 0;
       t@@ -223,7 +224,6 @@ ltk_scrollbar_motion_notify(ltk_widget *self, XEvent event) {
                sc->last_mouse_y = event.xbutton.y;
                if (delta > 0)
                        sc->callback(sc->callback_data);
       -        */
                return 1;
        }
        
   DIR diff --git a/src/text.h b/src/text.h
       t@@ -19,22 +19,39 @@
        
        #include "color.h"
        #include "graphics.h"
       +#include "ltk.h"
        
        typedef struct ltk_text_line ltk_text_line;
       +/* typedef struct ltk_text_context ltk_text_context; */
        
       -/* FIXME: remove x-specific stuff from interface */
       -void ltk_init_text(const char *default_font, Display *dpy, int screen, Colormap cm);
       -void ltk_cleanup_text(void);
       -ltk_text_line *ltk_text_line_create(Window window, uint16_t font_size, char *text, int width, ltk_color *fg, ltk_color *bg);
       -/* FIXME: either implement clip rect or remove it from arguments */
       -void ltk_text_line_draw(ltk_text_line *tl, ltk_surface *s, GC gc, int x, int y, ltk_rect clip);
       +/* FIXME: something to hold display, etc. to avoid circular reference between window and text context */
       +
       +ltk_text_context *ltk_text_context_create(ltk_window *window, char *default_font);
       +void ltk_text_context_destroy(ltk_text_context *ctx);
       +
       +/* FIXME: allow to give length of text */
       +ltk_text_line *ltk_text_line_create(ltk_text_context *ctx, uint16_t font_size, char *text, int take_over_text, int width);
        void ltk_text_line_set_width(ltk_text_line *tl, int width);
        void ltk_text_line_get_size(ltk_text_line *tl, int *w, int *h);
        void ltk_text_line_destroy(ltk_text_line *tl);
       -void ltk_text_line_change_colors(ltk_text_line *tl, ltk_color *fg, ltk_color *bg);
        
       -#if USE_PANGO == 1
       -  #include <pango/pangoxft.h>
       -#endif
       +/* Draw the entire line to a surface. */
       +void ltk_text_line_draw(ltk_text_line *tl, ltk_surface *s, ltk_color *color, int x, int y);
       +
       +/* Get the smallest rectangle of the line that can be drawn while covering 'clip'.
       + * The Pango backend will currently always return the full rectangle for the line
       + * because it doesn't support clipping. Other backends may just return a slightly
       + * larger rectangle so they can draw full glyphs. */
       +ltk_rect ltk_text_line_get_minimal_clip_rect(ltk_text_line *tl, ltk_rect clip);
       +
       +/* Draw a line onto a surface at position x,y and clipped to 'clip'. Note that
       + * clipping isn't supported properly, so the drawn part of the line may be
       + * larger than 'clip'. In order to find out the exact size of the drawn section,
       + * use ltk_rect_line_get_minimal_clip_rect. */
       +void ltk_text_line_draw_clipped(ltk_text_line *tl, ltk_surface *s, ltk_color *color, int x, int y, ltk_rect clip);
       +
       +/* FIXME: Any way to implement clipping properly? The text would need to be drawn
       +   to an intermediate surface, but then we lose alpha blending with the background
       +   (unless another library like cairo is used, which I want to avoid). */
        
        #endif /* _LTK_TEXT_H_ */
   DIR diff --git a/src/text_pango.c b/src/text_pango.c
       t@@ -35,96 +35,87 @@
        #include "text.h"
        
        struct ltk_text_line {
       +        ltk_text_context *ctx;
                char *text;
       -        uint16_t font_size;
       -        int w;
       -        int h;
       -        Window window;
                PangoLayout *layout;
       -        ltk_color *fg;
       -        ltk_color *bg;
       +        uint16_t font_size;
        };
        
       -struct {
       +struct ltk_text_context {
       +        ltk_window *window;
                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 = ltk_strdup(default_font);
       -        tm.dpy = dpy;
       -        tm.screen = screen;
       -        tm.cm = cm;
       +ltk_text_context_create(ltk_window *window, const char *default_font) {
       +        ltk_text_context *ctx = ltk_malloc(sizeof(ltk_text_context));
       +        ctx->window = window;
       +        ctx->fontmap = pango_xft_get_font_map(window->dpy, window->screen);
       +        ctx->context = pango_font_map_create_context(ctx->fontmap);
       +        ctx->default_font = ltk_strdup(default_font);
        }
        
        void
       -ltk_cleanup_text(void) {
       -        if (tm.default_font) ltk_free(tm.default_font);
       -        /* FIXME: destroy fontmap and context */
       +ltk_text_context_destroy(ltk_text_context *ctx) {
       +        ltk_free(ctx->default_font);
       +        g_object_unref(ctx->fontmap);
       +        g_object_unref(ctx->context);
       +        ltk_free(ctx);
        }
        
        void
        ltk_text_line_set_width(ltk_text_line *tl, int width) {
                pango_layout_set_width(tl->layout, width * PANGO_SCALE);
       -        /* FIXME: this is very inefficient because it immediately
       -           accesses the size, forcing pango to recalculate it even
       -           if it may never be needed before e.g. changing text */
       -        pango_layout_get_size(tl->layout, &tl->w, &tl->h);
       -        tl->w /= PANGO_SCALE;
       -        tl->h /= PANGO_SCALE;
       -        tl->w = tl->w == 0 ? 1 : tl->w;
       -        tl->h = tl->h == 0 ? 1 : tl->h;
       -}
       -
       -void
       -ltk_text_line_change_colors(ltk_text_line *tl, ltk_color *fg, ltk_color *bg) {
       -        tl->fg = fg;
       -        tl->bg = bg;
        }
        
        ltk_text_line *
       -ltk_text_line_create(Window window, uint16_t font_size, char *text, int width, ltk_color *fg, ltk_color *bg) {
       -        if (!tm.context)
       -                ltk_fatal("ltk_text_line_create (pango): text not initialized yet");
       -        ltk_text_line *line = ltk_malloc(sizeof(ltk_text_line));
       -        line->text = text;
       -        line->font_size = font_size;
       -        line->layout = pango_layout_new(tm.context);
       -
       -        PangoFontDescription *desc = pango_font_description_from_string(tm.default_font);
       +ltk_text_line_create(ltk_text_context *ctx, uint16_t font_size, char *text, int take_over_text, int width) {
       +        ltk_text_line *tl = ltk_malloc(sizeof(ltk_text_line));
       +        if (take_over_text)
       +                tl->text = text;
       +        else
       +                tl->text = ltk_strdup(text);
       +        tl->font_size = font_size;
       +        tl->layout = pango_layout_new(ctx->context);
       +
       +        PangoFontDescription *desc = pango_font_description_from_string(ctx->default_font);
                pango_font_description_set_size(desc, font_size * PANGO_SCALE);
       -        pango_layout_set_font_description(line->layout, desc);
       +        pango_layout_set_font_description(tl->layout, desc);
                pango_font_description_free(desc);
       -        line->window = window;
       -        pango_layout_set_wrap(line->layout, PANGO_WRAP_WORD_CHAR);
       -        pango_layout_set_text(line->layout, text, -1);
       -        ltk_text_line_set_width(line, width);
       -        line->fg = fg;
       -        line->bg = bg;
       -
       -        return line;
       +        tl->ctx = ctx;
       +        pango_layout_set_wrap(tl->layout, PANGO_WRAP_WORD_CHAR);
       +        pango_layout_set_text(tl->layout, text, -1);
       +        ltk_text_line_set_width(tl, width * PANGO_SCALE);
       +
       +        return tl;
        }
        
       -/* FIXME: bg isn't used right now */
        void
       -ltk_text_line_draw(ltk_text_line *tl, ltk_surface *s, GC gc, int x, int y, ltk_rect clip) {
       -        (void)clip; /* FIXME: use this */
       -        (void)gc;
       +ltk_text_line_draw(ltk_text_line *tl, ltk_surface *s, ltk_color *color, int x, int y) {
                XftDraw *d = ltk_surface_get_xft_draw(s);
       -        pango_xft_render_layout(d, &tl->fg->xftcolor, tl->layout, x * PANGO_SCALE, y * PANGO_SCALE);
       +        pango_xft_render_layout(d, &color->xftcolor, tl->layout, x * PANGO_SCALE, y * PANGO_SCALE);
       +}
       +
       +/* FIXME: any way to actually implement clipping with pango? */
       +void
       +ltk_text_line_draw_clipped(ltk_text_line *tl, ltk_surface *s, ltk_color *color, int x, int y, ltk_rect clip) {
       +        (void)clip;
       +        ltk_text_line_draw(tl, s, color, x, y);
       +}
       +
       +ltk_rect
       +ltk_text_line_get_minimal_clip_rect(ltk_text_line *tl, ltk_rect clip) {
       +        (void)clip;
       +        int w, h;
       +        ltk_text_line_get_size(tl, &w, &h);
       +        return (ltk_rect){0, 0, w, h};
        }
        
        void
        ltk_text_line_get_size(ltk_text_line *tl, int *w, int *h) {
       -        *w = tl->w;
       -        *h = tl->h;
       +        pango_layout_get_pixel_size(tl->layout, w, h);
        }
        
        void
   DIR diff --git a/src/text_stb.c b/src/text_stb.c
       t@@ -1,5 +1,3 @@
       -/* FIXME: more dirty flags; cache ximages so not too much ram is used
       -   when a lot of text is displayed */
        /*
         * Copyright (c) 2017, 2018, 2020, 2022 lumidify <nobody@lumidify.org>
         *
       t@@ -70,7 +68,7 @@ typedef struct {
        } ltk_glyph;
        
        struct ltk_text_line {
       -        XImage *img;
       +        ltk_text_context *ctx;
                char *text;
                ltk_glyph *glyphs;
                size_t glyph_len;
       t@@ -79,18 +77,14 @@ struct ltk_text_line {
                int lines;
                int lines_alloc;
        
       -        Window window;
       -
                int w_max;
                int w;
                int h;
                int line_h;
                int x_min;
                int y_min;
       -        uint16_t font_size;
                int dirty;
       -        ltk_color *fg;
       -        ltk_color *bg;
       +        uint16_t font_size;
        };
        
        /* Hash definitions */
       t@@ -99,7 +93,8 @@ KHASH_MAP_INIT_INT(glyphinfo, ltk_glyph_info*)
        /* font path, size -> glyph cache hash */
        KHASH_MAP_INIT_INT(glyphcache, khash_t(glyphinfo)*)
        
       -static struct {
       +struct ltk_text_context {
       +        ltk_window *window;
                khash_t(glyphcache) *glyph_cache;
                ltk_font **fonts;
                int num_fonts;
       t@@ -107,33 +102,28 @@ static struct {
                FcPattern *fcpattern;
                ltk_font *default_font;
                uint16_t font_id_cur;
       -        Display *dpy;
       -        int screen;
       -        Colormap cm;
       -} tm = {NULL, NULL, 0, 0, NULL, NULL, 1, NULL, 0, 0};
       -
       +};
        
       -static ltk_font *ltk_get_font(char *path, int index);
       +static ltk_font *ltk_get_font(ltk_text_context *ctx, char *path, int index);
        static ltk_glyph_info *ltk_create_glyph_info(ltk_font *font, int id,
            float scale);
        static void ltk_destroy_glyph_info(ltk_glyph_info *gi);
        static ltk_glyph_info *ltk_get_glyph_info(ltk_font *font, int id,
            float scale, khash_t(glyphinfo) *cache);
       -static khash_t(glyphinfo) *ltk_get_glyph_cache(uint16_t font_id,
       +static khash_t(glyphinfo) *ltk_get_glyph_cache(ltk_text_context *ctx, uint16_t font_id,
            uint16_t font_size);
       -static khint_t ltk_create_glyph_cache(uint16_t font_id, uint16_t font_size);
       +static khint_t ltk_create_glyph_cache(ltk_text_context *ctx, uint16_t font_id, uint16_t font_size);
        static void ltk_destroy_glyph_cache(khash_t(glyphinfo) *cache);
       -static void ltk_load_default_font(const char *name);
        static ltk_font *ltk_create_font(char *path, uint16_t id, int index);
        static void ltk_destroy_font(ltk_font *font);
       -static ltk_font *ltk_load_font(char *path, int index);
       -static ltk_font *ltk_get_font(char *path, int index);
       -static void ltk_text_to_glyphs(ltk_glyph *glyphs, int num_glyphs, char *text,
       +static ltk_font *ltk_load_font(ltk_text_context *ctx, char *path, int index);
       +static void ltk_load_default_font(ltk_text_context *ctx, char *default_font);
       +static void ltk_text_to_glyphs(ltk_text_context *ctx, ltk_glyph *glyphs, int num_glyphs, char *text,
            uint16_t font_size, int *x_min, int *y_min, int *x_max, int *y_max);
        static void ltk_text_line_create_glyphs(ltk_text_line *tl);
        static void ltk_text_line_draw_glyph(ltk_glyph *glyph, int x, int y,
            XImage *img, XColor fg);
       -static XImage *ltk_create_ximage(int w, int h, int depth, XColor bg);
       +/*static XImage *ltk_create_ximage(int w, int h, int depth, XColor bg);*/
        
        
        /* These unicode routines are taken from
       t@@ -210,29 +200,33 @@ static size_t u8_wc_toutf8(char *dest, uint32_t ch) {
        }
        */
        
       -void
       -ltk_init_text(const char *default_font, Display *dpy, int screen, Colormap cm) {
       -        tm.fonts_bufsize = 1;
       -        tm.glyph_cache = kh_init(glyphcache);
       -        tm.fonts = ltk_malloc(sizeof(ltk_font *));
       -        ltk_load_default_font(default_font);
       -        tm.dpy = dpy;
       -        tm.screen = screen;
       -        tm.cm = cm;
       +ltk_text_context *
       +ltk_text_context_create(ltk_window *window, char *default_font) {
       +        ltk_text_context *ctx = ltk_malloc(sizeof(ltk_text_context));
       +        ctx->window = window;
       +        ctx->glyph_cache = kh_init(glyphcache);
       +        ctx->fonts = ltk_malloc(sizeof(ltk_font *));
       +        ctx->num_fonts = 0;
       +        ctx->fonts_bufsize = 1;
       +        ctx->fcpattern = NULL;
       +        ltk_load_default_font(ctx, default_font);
       +        ctx->font_id_cur = 1;
       +        return ctx;
        }
        
        void
       -ltk_cleanup_text(void) {
       -        for (int i = 0; i < tm.num_fonts; i++) {
       -                ltk_destroy_font(tm.fonts[i]);
       +ltk_text_context_destroy(ltk_text_context *ctx) {
       +        /* FIXME: destroy fcpattern */
       +        for (int i = 0; i < ctx->num_fonts; i++) {
       +                ltk_destroy_font(ctx->fonts[i]);
                }
       -        if (!tm.glyph_cache) return;
       -        for (khint_t k = kh_begin(tm.glyph_cache); k != kh_end(tm.glyph_cache); k++) {
       -                if (kh_exist(tm.glyph_cache, k)) {
       -                        ltk_destroy_glyph_cache(kh_value(tm.glyph_cache, k));
       +        if (!ctx->glyph_cache) return;
       +        for (khint_t k = kh_begin(ctx->glyph_cache); k != kh_end(ctx->glyph_cache); k++) {
       +                if (kh_exist(ctx->glyph_cache, k)) {
       +                        ltk_destroy_glyph_cache(kh_value(ctx->glyph_cache, k));
                        }
                }
       -        kh_destroy(glyphcache, tm.glyph_cache);
       +        kh_destroy(glyphcache, ctx->glyph_cache);
        }
        
        static ltk_glyph_info *
       t@@ -274,24 +268,24 @@ ltk_get_glyph_info(ltk_font *font, int id, float scale, khash_t(glyphinfo) *cach
        }
        
        static khash_t(glyphinfo) *
       -ltk_get_glyph_cache(uint16_t font_id, uint16_t font_size) {
       +ltk_get_glyph_cache(ltk_text_context *ctx, uint16_t font_id, uint16_t font_size) {
                khint_t k;
                uint32_t attr = ((uint32_t)font_id << 16) + font_size;
       -        k = kh_get(glyphcache, tm.glyph_cache, attr);
       -        if (k == kh_end(tm.glyph_cache)) {
       -                k = ltk_create_glyph_cache(font_id, font_size);
       +        k = kh_get(glyphcache, ctx->glyph_cache, attr);
       +        if (k == kh_end(ctx->glyph_cache)) {
       +                k = ltk_create_glyph_cache(ctx, font_id, font_size);
                }
       -        return kh_value(tm.glyph_cache, k);
       +        return kh_value(ctx->glyph_cache, k);
        }
        
        static khint_t
       -ltk_create_glyph_cache(uint16_t font_id, uint16_t font_size) {
       +ltk_create_glyph_cache(ltk_text_context *ctx, uint16_t font_id, uint16_t font_size) {
                khash_t(glyphinfo) *cache = kh_init(glyphinfo);
                int ret;
                khint_t k;
                /* I guess I can just ignore ret for now */
       -        k = kh_put(glyphcache, tm.glyph_cache, ((uint32_t)font_id << 16) + font_size, &ret);
       -        kh_value(tm.glyph_cache, k) = cache;
       +        k = kh_put(glyphcache, ctx->glyph_cache, ((uint32_t)font_id << 16) + font_size, &ret);
       +        kh_value(ctx->glyph_cache, k) = cache;
        
                return k;
        }
       t@@ -307,24 +301,24 @@ ltk_destroy_glyph_cache(khash_t(glyphinfo) *cache) {
        }
        
        static void
       -ltk_load_default_font(const char *name) {
       +ltk_load_default_font(ltk_text_context *ctx, char *name) {
                FcPattern *match;
                FcResult result;
                char *file;
                int index;
        
                /* FIXME: Get rid of this stupid cast somehow */
       -        tm.fcpattern = FcNameParse((const FcChar8 *)name);
       -        /*tm.fcpattern = FcPatternCreate();*/
       -        FcPatternAddString(tm.fcpattern, FC_FONTFORMAT, (const FcChar8 *)"truetype");
       -        FcConfigSubstitute(NULL, tm.fcpattern, FcMatchPattern);
       -        FcDefaultSubstitute(tm.fcpattern);
       -        match = FcFontMatch(NULL, tm.fcpattern, &result);
       +        ctx->fcpattern = FcNameParse((const FcChar8 *)name);
       +        /*ctx->fcpattern = FcPatternCreate();*/
       +        FcPatternAddString(ctx->fcpattern, FC_FONTFORMAT, (const FcChar8 *)"truetype");
       +        FcConfigSubstitute(NULL, ctx->fcpattern, FcMatchPattern);
       +        FcDefaultSubstitute(ctx->fcpattern);
       +        match = FcFontMatch(NULL, ctx->fcpattern, &result);
        
                FcPatternGetString(match, FC_FILE, 0, (FcChar8 **) &file);
                FcPatternGetInteger(match, FC_INDEX, 0, &index);
        
       -        tm.default_font = ltk_get_font(file, index);
       +        ctx->default_font = ltk_get_font(ctx, file, index);
        
                FcPatternDestroy(match);
        }
       t@@ -354,35 +348,35 @@ ltk_destroy_font(ltk_font *font) {
        }
        
        static ltk_font *
       -ltk_load_font(char *path, int index) {
       -        ltk_font *font = ltk_create_font(path, tm.font_id_cur++, index);
       -        if (tm.num_fonts == tm.fonts_bufsize) {
       -                ltk_font **new = ltk_realloc(tm.fonts, tm.fonts_bufsize * 2 * sizeof(ltk_font *));
       -                tm.fonts = new;
       -                tm.fonts_bufsize *= 2;
       +ltk_load_font(ltk_text_context *ctx, char *path, int index) {
       +        ltk_font *font = ltk_create_font(path, ctx->font_id_cur++, index);
       +        if (ctx->num_fonts == ctx->fonts_bufsize) {
       +                ltk_font **new = ltk_realloc(ctx->fonts, ctx->fonts_bufsize * 2 * sizeof(ltk_font *));
       +                ctx->fonts = new;
       +                ctx->fonts_bufsize *= 2;
                }
       -        tm.fonts[tm.num_fonts] = font;
       -        tm.num_fonts++;
       +        ctx->fonts[ctx->num_fonts] = font;
       +        ctx->num_fonts++;
                return font;
        }
        
        static ltk_font *
       -ltk_get_font(char *path, int index) {
       +ltk_get_font(ltk_text_context *ctx, char *path, int index) {
                ltk_font *font = NULL;
       -        for (int i = 0; i < tm.num_fonts; i++) {
       -                if (tm.fonts[i]->index == index &&
       -                    strcmp(tm.fonts[i]->path, path) == 0) {
       -                        font = tm.fonts[i];
       +        for (int i = 0; i < ctx->num_fonts; i++) {
       +                if (ctx->fonts[i]->index == index &&
       +                    strcmp(ctx->fonts[i]->path, path) == 0) {
       +                        font = ctx->fonts[i];
                                break;
                        }
                }
                if (!font)
       -                font = ltk_load_font(path, index);
       +                font = ltk_load_font(ctx, path, index);
                return font;
        }
        
        static void
       -ltk_text_to_glyphs(ltk_glyph *glyphs, int num_glyphs, char *text, uint16_t font_size,
       +ltk_text_to_glyphs(ltk_text_context *ctx, ltk_glyph *glyphs, int num_glyphs, char *text, uint16_t font_size,
            int *x_min, int *y_min, int *x_max, int *y_max) {
                uint32_t c1, c2 = 0;
                int gid;
       t@@ -396,8 +390,8 @@ ltk_text_to_glyphs(ltk_glyph *glyphs, int num_glyphs, char *text, uint16_t font_
                *x_min = INT_MAX, *x_max = INT_MIN, *y_min = INT_MAX, *y_max = INT_MIN;
                ltk_glyph_info *ginfo;
        
       -        ltk_font *font = tm.default_font;
       -        khash_t(glyphinfo) *glyph_cache = ltk_get_glyph_cache(font->id, font_size);
       +        ltk_font *font = ctx->default_font;
       +        khash_t(glyphinfo) *glyph_cache = ltk_get_glyph_cache(ctx, font->id, font_size);
        
                scale = stbtt_ScaleForPixelHeight(&font->info, font_size);
                stbtt_GetFontVMetrics(&font->info, &ascent, &descent, &line_gap);
       t@@ -421,8 +415,8 @@ ltk_text_to_glyphs(ltk_glyph *glyphs, int num_glyphs, char *text, uint16_t font_
                                match = FcFontMatch(NULL, pat, &result);
                                FcPatternGetString(match, FC_FILE, 0, &file);
                                FcPatternGetInteger(match, FC_INDEX, 0, &index);
       -                        font = ltk_get_font((char *)file, index);
       -                        glyph_cache = ltk_get_glyph_cache(font->id, font_size);
       +                        font = ltk_get_font(ctx, (char *)file, index);
       +                        glyph_cache = ltk_get_glyph_cache(ctx, font->id, font_size);
                                FcPatternDestroy(match);
                                FcPatternDestroy(pat);
                                gid = stbtt_FindGlyphIndex(&font->info, c1);
       t@@ -477,8 +471,7 @@ ltk_unref_glyphs(ltk_glyph *glyphs, int num_glyphs) {
        }
        */
        
       -/* FIXME: Error checking that tm has been initialized */
       -
       +/*
        static void
        ltk_fill_ximage(XImage *img, int w, int h, XColor bg) {
                int b;
       t@@ -502,9 +495,11 @@ ltk_create_ximage(int w, int h, int depth, XColor bg) {
        
                return img;
        }
       +*/
        
        /* based on http://codemadness.org/git/dwm-font/file/drw.c.html#l315 */
        /* FIXME: make this work with other pixel representations */
       +/* FIXME: will fail horribly if depth is not 32 */
        static void
        ltk_text_line_draw_glyph(ltk_glyph *glyph, int x, int y, XImage *img, XColor fg) {
                double a;
       t@@ -562,26 +557,20 @@ ltk_text_line_break_lines(ltk_text_line *tl) {
                        i++;
                }
                tl->h = tl->line_h * tl->lines;
       +        tl->dirty = 0;
        }
        
       -static void
       -ltk_text_line_render(
       -        ltk_text_line *tl,
       -        ltk_color *bg,
       -        ltk_color *fg)
       -{
       -        /* FIXME: just keep reference to ltk_window so this isn't necessary */
       -        XWindowAttributes attrs;
       -        XGetWindowAttributes(tm.dpy, tl->window, &attrs);
       -        int depth = attrs.depth;
       -        /* FIXME: maybe don't destroy if old image is big enough? */
       -        if (!tl->img || tl->img->width != tl->w || tl->img->height != tl->h) {
       -                if (tl->img)
       -                        XDestroyImage(tl->img);
       -                tl->img = ltk_create_ximage(tl->w, tl->h, depth, bg->xcolor);
       -        } else {
       -                ltk_fill_ximage(tl->img, tl->w, tl->h, bg->xcolor);
       -        }
       +/* FIXME: improve color handling - where passed as pointer, where as value?
       +   In certain cases, it's important to deallocate the color in the end
       +   (if the x server doesn't support truecolor - I'm not sure right now if
       +   this is the right terminology, but it's something like that) */
       +
       +void
       +ltk_text_line_draw(ltk_text_line *tl, ltk_surface *s, ltk_color *color, int x, int y) {
       +        if (tl->dirty)
       +                ltk_text_line_break_lines(tl);
       +        Drawable d = ltk_surface_get_drawable(s);
       +        XImage *img = XGetImage(tl->ctx->window->dpy, d, x, y, tl->w, tl->h, 0xFFFFFF, ZPixmap);
        
                int last_break = 0;
                for (int i = 0; i < tl->lines; i++) {
       t@@ -593,55 +582,42 @@ ltk_text_line_render(
                        for (int j = last_break; j < next_break; j++) {
                                int x = tl->glyphs[j].x - tl->glyphs[last_break].x;
                                int y = tl->glyphs[j].y - tl->y_min + tl->line_h * i;
       -                        ltk_text_line_draw_glyph(&tl->glyphs[j], x, y, tl->img, fg->xcolor);
       +                        ltk_text_line_draw_glyph(&tl->glyphs[j], x, y, img, color->xcolor);
                        }
                        last_break = next_break;
                }
       -        tl->dirty = 0;
       +        XPutImage(tl->ctx->window->dpy, d, tl->ctx->window->gc, img, 0, 0, x, y, tl->w, tl->h);
       +        XDestroyImage(img);
        }
        
       -/* FIXME: improve color handling - where passed as pointer, where as value?
       -   In certain cases, it's important to deallocate the color in the end
       -   (if the x server doesn't support truecolor - I'm not sure right now if
       -   this is the right terminology, but it's something like that) */
       +/* FIXME: ACTUALLY IMPLEMENT!!! */
        void
       -ltk_text_line_change_colors(ltk_text_line *tl, ltk_color *fg, ltk_color *bg) {
       -        tl->fg = fg;
       -        tl->bg = bg;
       -        tl->dirty = 1;
       -
       +ltk_text_line_draw_clipped(ltk_text_line *tl, ltk_surface *s, ltk_color *color, int x, int y, ltk_rect clip) {
       +        (void)clip;
       +        ltk_text_line_draw(tl, s, color, x, y);
        }
        
       -/* FIXME: error checking if img is rendered yet, tm initialized, etc. */
       -void
       -ltk_text_line_draw(ltk_text_line *tl, ltk_surface *s, GC gc, int x, int y, ltk_rect clip) {
       +ltk_rect
       +ltk_text_line_get_minimal_clip_rect(ltk_text_line *tl, ltk_rect clip) {
                (void)clip;
                if (tl->dirty)
       -                ltk_text_line_render(tl, tl->bg, tl->fg);
       -        /*
       -        int xoff = clip.x - x;
       -        int yoff = clip.y - y;
       -        xoff = xoff >= 0 ? xoff : 0;
       -        yoff = yoff >= 0 ? yoff : 0;
       -        int w = clip.w > tl->w - xoff ? tl->w - xoff : clip.w;
       -        int h = clip.h > tl->h - yoff ? tl->h - yoff : clip.h;
       -        XPutImage(tm.dpy, tl->window, gc, tl->img, xoff, yoff, x + xoff, y + yoff, w, h);
       -        */
       -        Pixmap p = ltk_surface_get_pixmap(s);
       -        XPutImage(tm.dpy, p, gc, tl->img, 0, 0, x, y, tl->w, tl->h);
       +                ltk_text_line_break_lines(tl);
       +        return (ltk_rect){0, 0, tl->w, tl->h};
        }
        
        void
        ltk_text_line_set_width(ltk_text_line *tl, int width) {
                /* FIXME: clarify what the difference between w_max and w is */
       +        /* FIXME: tl->w could be made slightly less than tl->w_max depending on breaking */
                tl->w_max = width;
                tl->w = width;
       -        ltk_text_line_break_lines(tl);
                tl->dirty = 1;
        }
        
        void
        ltk_text_line_get_size(ltk_text_line *tl, int *w, int *h) {
       +        if (tl->dirty)
       +                ltk_text_line_break_lines(tl);
                *w = tl->w;
                *h = tl->h;
        }
       t@@ -649,7 +625,7 @@ ltk_text_line_get_size(ltk_text_line *tl, int *w, int *h) {
        static void
        ltk_text_line_create_glyphs(ltk_text_line *tl) {
                int x_min, x_max, y_min, y_max;
       -        ltk_text_to_glyphs(tl->glyphs, tl->glyph_len, tl->text, tl->font_size,
       +        ltk_text_to_glyphs(tl->ctx, tl->glyphs, tl->glyph_len, tl->text, tl->font_size,
                    &x_min, &y_min, &x_max, &y_max);
                /* for drawing the glyphs at the right position on the image */
                tl->x_min = x_min;
       t@@ -659,28 +635,26 @@ ltk_text_line_create_glyphs(ltk_text_line *tl) {
        }
        
        ltk_text_line *
       -ltk_text_line_create(Window window, uint16_t font_size, char *text, int width, ltk_color *fg, ltk_color *bg) {
       -        ltk_text_line *line = ltk_malloc(sizeof(ltk_text_line));
       -        line->window = window;
       -        line->img = NULL;
       -        line->text = text;
       -        line->glyph_len = u8_strlen(text);
       -        line->glyphs = ltk_malloc(line->glyph_len * sizeof(ltk_glyph));
       -        line->font_size = font_size;
       -        line->w_max = width;
       -        ltk_text_line_create_glyphs(line);
       -        line->lines_alloc = line->lines = 0;
       -        line->line_indeces = NULL;
       -        ltk_text_line_break_lines(line);
       -        line->dirty = 1;
       -        line->fg = fg;
       -        line->bg = bg;
       -        return line;
       +ltk_text_line_create(ltk_text_context *ctx, uint16_t font_size, char *text, int take_over_text, int width) {
       +        ltk_text_line *tl = ltk_malloc(sizeof(ltk_text_line));
       +        tl->ctx = ctx;
       +        if (take_over_text)
       +                tl->text = text;
       +        else
       +                tl->text = ltk_strdup(text);
       +        tl->glyph_len = u8_strlen(text);
       +        tl->glyphs = ltk_malloc(tl->glyph_len * sizeof(ltk_glyph));
       +        tl->font_size = font_size;
       +        tl->w_max = width;
       +        ltk_text_line_create_glyphs(tl);
       +        tl->lines_alloc = tl->lines = 0;
       +        tl->line_indeces = NULL;
       +        tl->dirty = 1;
       +        return tl;
        }
        
        void
        ltk_text_line_destroy(ltk_text_line *tl) {
       -        XDestroyImage(tl->img);
                ltk_free(tl->text);
                /* FIXME: Reference count glyph infos */
                ltk_free(tl->glyphs);