diff --git a/.gitignore b/.gitignore index 717dac7..7bca30e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ Makefile.in aclocal.m4 autom4te.cache/ build-aux/ +build/ config.h config.h.in config.h.in~ diff --git a/Makefile.am b/Makefile.am index 8f97c06..123acf4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -30,15 +30,18 @@ MANPAGES = MANPAGES_ALIASES = TPHONY = -bin_PROGRAMS = check_PROGRAMS = noinst_PROGRAMS = lib_LTLIBRARIES = noinst_LTLIBRARIES = +bin_SCRIPTS = moduledir = $(libdir)/kmscon module_LTLIBRARIES = +helperdir = $(libexecdir)/kmscon +helper_PROGRAMS = + # # Default CFlags # Make all files include "config.h" by default. This shouldn't cause any @@ -475,7 +478,8 @@ mod_pixman_la_LDFLAGS = \ # built as part of kmscon. # -bin_PROGRAMS += kmscon +bin_SCRIPTS += scripts/kmscon +helper_PROGRAMS += kmscon check_PROGRAMS += \ test_output \ test_vt \ diff --git a/autogen.sh b/autogen.sh index 0bb5ca8..65a6fe1 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,8 +1,17 @@ #!/bin/sh set -e -mkdir -p m4 -autoreconf -i -if test ! "x$NOCONFIGURE" = "x1" ; then - exec ./configure "$@" +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +origdir=`pwd` +cd $srcdir + +mkdir -p m4 +autoreconf -is --force + +cd $origdir + +if test -z "$NOCONFIGURE" ; then + exec $srcdir/configure "$@" fi diff --git a/configure.ac b/configure.ac index eb3020f..c31911f 100644 --- a/configure.ac +++ b/configure.ac @@ -51,7 +51,7 @@ PKG_CHECK_MODULES([XKBCOMMON], [xkbcommon]) AC_SUBST(XKBCOMMON_CFLAGS) AC_SUBST(XKBCOMMON_LIBS) -PKG_CHECK_MODULES([TSM], [libtsm]) +PKG_CHECK_MODULES([TSM], [libtsm >= 4.0.0]) AC_SUBST(TSM_CFLAGS) AC_SUBST(TSM_LIBS) @@ -791,7 +791,7 @@ fi # makefiles. # -AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([Makefile scripts/kmscon]) AC_OUTPUT # diff --git a/scripts/kmscon.in b/scripts/kmscon.in new file mode 100755 index 0000000..4be288f --- /dev/null +++ b/scripts/kmscon.in @@ -0,0 +1,59 @@ +#!/bin/sh +# +# Copyright (c) 2018 Aetf +# Copyright (c) 2018 Fabian Vogt +# +# 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. + +# configuration path +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libexecdir=@libexecdir@ +helperdir=${libexecdir}/kmscon + +# Get a property from org.freedesktop.locale1 +queryLocale1() { + dbus-send --system --print-reply=literal --dest=org.freedesktop.locale1 /org/freedesktop/locale1 org.freedesktop.DBus.Properties.Get "string:org.freedesktop.locale1" "string:$1" | awk '{print $2}' +} + +# Query and setup system locale settings before start kmscon +setupLocale() { + # Fallback to do nothing if we don't have the command + if ! command -v dbus-send >/dev/null 2>/dev/null; then + return + fi + + # Don't override existing values. Also there is no point in setting only some of them + # as then they would not match anymore. + if test -n "${XKB_DEFAULT_MODEL}" -o -n "${XKB_DEFAULT_LAYOUT}" -o -n "${XKB_DEFAULT_VARIANT}" -o -n "${XKB_DEFAULT_OPTIONS}"; then + return + fi + + X11MODEL="$(queryLocale1 X11Model)" + X11LAYOUT="$(queryLocale1 X11Layout)" + X11VARIANT="$(queryLocale1 X11Variant)" + X11OPTIONS="$(queryLocale1 X11Options)" + [ -n "${X11MODEL}" ] && export XKB_DEFAULT_MODEL="${X11MODEL}" + [ -n "${X11LAYOUT}" ] && export XKB_DEFAULT_LAYOUT="${X11LAYOUT}" + [ -n "${X11VARIANT}" ] && export XKB_DEFAULT_VARIANT="${X11VARIANT}" + [ -n "${X11OPTIONS}" ] && export XKB_DEFAULT_OPTIONS="${X11OPTIONS}" +} + +setupLocale +exec ${helperdir}/kmscon "$@" diff --git a/src/font.c b/src/font.c index c6ad8c1..2b31e87 100644 --- a/src/font.c +++ b/src/font.c @@ -130,6 +130,8 @@ bool kmscon_font_attr_match(const struct kmscon_font_attr *a1, return false; if (a1->italic != a2->italic) return false; + if (a1->underline != a2->underline) + return false; if (*a1->name && *a2->name && strcmp(a1->name, a2->name)) return false; @@ -396,7 +398,7 @@ void kmscon_font_unref(struct kmscon_font *font) */ SHL_EXPORT int kmscon_font_render(struct kmscon_font *font, - uint32_t id, const uint32_t *ch, size_t len, + uint64_t id, const uint32_t *ch, size_t len, const struct kmscon_glyph **out) { if (!font || !out || !ch || !len) diff --git a/src/font.h b/src/font.h index f7e4b01..6493cad 100644 --- a/src/font.h +++ b/src/font.h @@ -52,6 +52,7 @@ struct kmscon_font_attr { unsigned int points; bool bold; bool italic; + bool underline; unsigned int height; unsigned int width; }; @@ -82,7 +83,7 @@ struct kmscon_font_ops { const struct kmscon_font_attr *attr); void (*destroy) (struct kmscon_font *font); int (*render) (struct kmscon_font *font, - uint32_t id, const uint32_t *ch, size_t len, + uint64_t id, const uint32_t *ch, size_t len, const struct kmscon_glyph **out); int (*render_empty) (struct kmscon_font *font, const struct kmscon_glyph **out); @@ -100,7 +101,7 @@ void kmscon_font_ref(struct kmscon_font *font); void kmscon_font_unref(struct kmscon_font *font); int kmscon_font_render(struct kmscon_font *font, - uint32_t id, const uint32_t *ch, size_t len, + uint64_t id, const uint32_t *ch, size_t len, const struct kmscon_glyph **out); int kmscon_font_render_empty(struct kmscon_font *font, const struct kmscon_glyph **out); diff --git a/src/font_8x16.c b/src/font_8x16.c index 830bc30..eafd631 100644 --- a/src/font_8x16.c +++ b/src/font_8x16.c @@ -81,7 +81,7 @@ static void kmscon_font_8x16_destroy(struct kmscon_font *font) } static int kmscon_font_8x16_render(struct kmscon_font *font, - uint32_t id, const uint32_t *ch, size_t len, + uint64_t id, const uint32_t *ch, size_t len, const struct kmscon_glyph **out) { if (len > 1 || *ch >= 256) diff --git a/src/font_pango.c b/src/font_pango.c index 171f3bd..26c6208 100644 --- a/src/font_pango.c +++ b/src/font_pango.c @@ -110,10 +110,11 @@ static void manager__unref() } static int get_glyph(struct face *face, struct kmscon_glyph **out, - uint32_t id, const uint32_t *ch, size_t len) + uint64_t id, const uint32_t *ch, size_t len, const struct kmscon_font_attr *attr) { struct kmscon_glyph *glyph; PangoLayout *layout; + PangoAttrList *attrlist; PangoRectangle rec; PangoLayoutLine *line; FT_Bitmap bitmap; @@ -131,7 +132,7 @@ static int get_glyph(struct face *face, struct kmscon_glyph **out, pthread_mutex_lock(&face->glyph_lock); res = shl_hashtable_find(face->glyphs, (void**)&glyph, - (void*)(long)id); + (void*)(uint64_t)id); pthread_mutex_unlock(&face->glyph_lock); if (res) { *out = glyph; @@ -150,6 +151,12 @@ static int get_glyph(struct face *face, struct kmscon_glyph **out, glyph->width = cwidth; layout = pango_layout_new(face->ctx); + attrlist = pango_layout_get_attributes(layout); + if (attrlist == NULL) { + attrlist = pango_attr_list_new(); + pango_layout_set_attributes(layout, attrlist); + pango_attr_list_unref(attrlist); + } /* render one line only */ pango_layout_set_height(layout, 0); @@ -157,6 +164,24 @@ static int get_glyph(struct face *face, struct kmscon_glyph **out, /* no line spacing */ pango_layout_set_spacing(layout, 0); + /* underline if requested */ + if (attr->underline) { + pango_attr_list_change(attrlist, + pango_attr_underline_new(PANGO_UNDERLINE_SINGLE)); + } else { + pango_attr_list_change(attrlist, + pango_attr_underline_new(PANGO_UNDERLINE_NONE)); + } + + /* italic if requested */ + if (attr->italic) { + pango_attr_list_change(attrlist, + pango_attr_style_new(PANGO_STYLE_ITALIC)); + } else { + pango_attr_list_change(attrlist, + pango_attr_style_new(PANGO_STYLE_NORMAL)); + } + val = tsm_ucs4_to_utf8_alloc(ch, len, &ulen); if (!val) { ret = -ERANGE; @@ -202,7 +227,7 @@ static int get_glyph(struct face *face, struct kmscon_glyph **out, pango_ft2_render_layout_line(&bitmap, line, -rec.x, face->baseline); pthread_mutex_lock(&face->glyph_lock); - ret = shl_hashtable_insert(face->glyphs, (void*)(long)id, glyph); + ret = shl_hashtable_insert(face->glyphs, (void*)(uint64_t)id, glyph); pthread_mutex_unlock(&face->glyph_lock); if (ret) { log_error("cannot add glyph to hashtable"); @@ -398,14 +423,14 @@ static void kmscon_font_pango_destroy(struct kmscon_font *font) manager_put_face(face); } -static int kmscon_font_pango_render(struct kmscon_font *font, uint32_t id, +static int kmscon_font_pango_render(struct kmscon_font *font, uint64_t id, const uint32_t *ch, size_t len, const struct kmscon_glyph **out) { struct kmscon_glyph *glyph; int ret; - ret = get_glyph(font->data, &glyph, id, ch, len); + ret = get_glyph(font->data, &glyph, id, ch, len, &font->attr); if (ret) return ret; diff --git a/src/font_unifont.c b/src/font_unifont.c index cdedbca..494d2d4 100644 --- a/src/font_unifont.c +++ b/src/font_unifont.c @@ -42,6 +42,7 @@ #include #include #include +#include #include "font.h" #include "shl_hashtable.h" #include "shl_log.h" @@ -105,7 +106,7 @@ static void unfold(uint8_t *dst, uint8_t val) *dst = 0xff * !!val; } -static int find_glyph(uint32_t id, const struct kmscon_glyph **out) +static int find_glyph(uint32_t ch, const struct kmscon_glyph **out) { struct kmscon_glyph *g; int ret; @@ -124,21 +125,21 @@ static int find_glyph(uint32_t id, const struct kmscon_glyph **out) } } else { res = shl_hashtable_find(cache, (void**)out, - (void*)(long)id); + (void*)(uint64_t)ch); if (res) { ret = 0; goto out_unlock; } } - if (id > 0xffff) { + if (ch > 0xffff) { ret = -ERANGE; goto out_unlock; } start = _binary_src_font_unifont_data_bin_start; end = _binary_src_font_unifont_data_bin_end; - d = &start[id]; + d = &start[ch]; if (d >= end) { ret = -ERANGE; @@ -186,7 +187,7 @@ static int find_glyph(uint32_t id, const struct kmscon_glyph **out) unfold(&g->buf.data[i * 8 + 7], d->data[i] & 0x01); } - ret = shl_hashtable_insert(cache, (void*)(long)id, g); + ret = shl_hashtable_insert(cache, (void*)(uint64_t)ch, g); if (ret) { log_error("cannot insert glyph into glyph-cache: %d", ret); goto err_data; @@ -240,14 +241,14 @@ static void kmscon_font_unifont_destroy(struct kmscon_font *font) cache_unref(); } -static int kmscon_font_unifont_render(struct kmscon_font *font, uint32_t id, +static int kmscon_font_unifont_render(struct kmscon_font *font, uint64_t id, const uint32_t *ch, size_t len, const struct kmscon_glyph **out) { if (len > 1) return -ERANGE; - return find_glyph(id, out); + return find_glyph(id & TSM_UCS4_MAX, out); } static int kmscon_font_unifont_render_inval(struct kmscon_font *font, diff --git a/src/kmscon_module.c b/src/kmscon_module.c index 2bf0576..f960c50 100644 --- a/src/kmscon_module.c +++ b/src/kmscon_module.c @@ -181,7 +181,7 @@ void kmscon_load_modules(void) { int ret; DIR *ent; - struct dirent *buf, *de; + struct dirent *de; char *file; struct kmscon_module *mod; @@ -203,18 +203,13 @@ void kmscon_load_modules(void) return; } - ret = shl_dirent(BUILD_MODULE_DIR, &buf); - if (ret) { - log_error("cannot allocate dirent object"); - closedir(ent); - return; - } - while (true) { - ret = readdir_r(ent, buf, &de); - if (ret != 0) { + errno = 0; + de = readdir(ent); + if (!de && errno != 0) { + int errsv = errno; log_error("cannot read directory %s: %d", - BUILD_MODULE_DIR, ret); + BUILD_MODULE_DIR, errsv); break; } else if (!de) { break; @@ -255,7 +250,6 @@ void kmscon_load_modules(void) shl_dlist_link(&module_list, &mod->list); } - free(buf); closedir(ent); } diff --git a/src/kmscon_terminal.c b/src/kmscon_terminal.c index cc8f003..b92d0b4 100644 --- a/src/kmscon_terminal.c +++ b/src/kmscon_terminal.c @@ -88,6 +88,7 @@ static void do_clear_margins(struct screen *scr) { unsigned int w, h, sw, sh; struct uterm_mode *mode; + struct tsm_screen_attr attr; int dw, dh; mode = uterm_display_get_current(scr->disp); @@ -101,12 +102,14 @@ static void do_clear_margins(struct screen *scr) dw = sw - w; dh = sh - h; + tsm_vte_get_def_attr(scr->term->vte, &attr); + if (dw > 0) - uterm_display_fill(scr->disp, 0, 0, 0, + uterm_display_fill(scr->disp, attr.br, attr.bg, attr.bb, w, 0, dw, h); if (dh > 0) - uterm_display_fill(scr->disp, 0, 0, 0, + uterm_display_fill(scr->disp, attr.br, attr.bg, attr.bb, 0, h, sw, dh); } diff --git a/src/pty.c b/src/pty.c index 3494104..1443f4a 100644 --- a/src/pty.c +++ b/src/pty.c @@ -299,7 +299,7 @@ static void setup_child(int master, struct winsize *ws) if (ret) log_warn("cannot reset blocked signals: %m"); - for (i = 1; i < SIGUNUSED; ++i) + for (i = 1; i < SIGSYS; ++i) signal(i, SIG_DFL); ret = grantpt(master); diff --git a/src/text.c b/src/text.c index d7e5f0e..24b579b 100644 --- a/src/text.c +++ b/src/text.c @@ -381,7 +381,7 @@ int kmscon_text_prepare(struct kmscon_text *txt) * Returns: 0 on success or negative error code if this glyph couldn't be drawn. */ int kmscon_text_draw(struct kmscon_text *txt, - uint32_t id, const uint32_t *ch, size_t len, + uint64_t id, const uint32_t *ch, size_t len, unsigned int width, unsigned int posx, unsigned int posy, const struct tsm_screen_attr *attr) @@ -438,7 +438,7 @@ void kmscon_text_abort(struct kmscon_text *txt) } int kmscon_text_draw_cb(struct tsm_screen *con, - uint32_t id, const uint32_t *ch, size_t len, + uint64_t id, const uint32_t *ch, size_t len, unsigned int width, unsigned int posx, unsigned int posy, const struct tsm_screen_attr *attr, diff --git a/src/text.h b/src/text.h index 902e3cd..570df6b 100644 --- a/src/text.h +++ b/src/text.h @@ -68,7 +68,7 @@ struct kmscon_text_ops { void (*unset) (struct kmscon_text *txt); int (*prepare) (struct kmscon_text *txt); int (*draw) (struct kmscon_text *txt, - uint32_t id, const uint32_t *ch, size_t len, + uint64_t id, const uint32_t *ch, size_t len, unsigned int width, unsigned int posx, unsigned int posy, const struct tsm_screen_attr *attr); @@ -93,7 +93,7 @@ unsigned int kmscon_text_get_rows(struct kmscon_text *txt); int kmscon_text_prepare(struct kmscon_text *txt); int kmscon_text_draw(struct kmscon_text *txt, - uint32_t id, const uint32_t *ch, size_t len, + uint64_t id, const uint32_t *ch, size_t len, unsigned int width, unsigned int posx, unsigned int posy, const struct tsm_screen_attr *attr); @@ -101,7 +101,7 @@ int kmscon_text_render(struct kmscon_text *txt); void kmscon_text_abort(struct kmscon_text *txt); int kmscon_text_draw_cb(struct tsm_screen *con, - uint32_t id, const uint32_t *ch, size_t len, + uint64_t id, const uint32_t *ch, size_t len, unsigned int width, unsigned int posx, unsigned int posy, const struct tsm_screen_attr *attr, diff --git a/src/text_bblit.c b/src/text_bblit.c index 8cf9bfd..2b5ff2c 100644 --- a/src/text_bblit.c +++ b/src/text_bblit.c @@ -62,7 +62,7 @@ static int bblit_set(struct kmscon_text *txt) } static int bblit_draw(struct kmscon_text *txt, - uint32_t id, const uint32_t *ch, size_t len, + uint64_t id, const uint32_t *ch, size_t len, unsigned int width, unsigned int posx, unsigned int posy, const struct tsm_screen_attr *attr) @@ -79,6 +79,16 @@ static int bblit_draw(struct kmscon_text *txt, else font = txt->font; + if (attr->underline) + font->attr.underline = true; + else + font->attr.underline = false; + + if (attr->italic) + font->attr.italic = true; + else + font->attr.italic = false; + if (!len) { ret = kmscon_font_render_empty(font, &glyph); } else { diff --git a/src/text_bbulk.c b/src/text_bbulk.c index 3f238c1..3801c34 100644 --- a/src/text_bbulk.c +++ b/src/text_bbulk.c @@ -111,7 +111,7 @@ static void bbulk_unset(struct kmscon_text *txt) } static int bbulk_draw(struct kmscon_text *txt, - uint32_t id, const uint32_t *ch, size_t len, + uint64_t id, const uint32_t *ch, size_t len, unsigned int width, unsigned int posx, unsigned int posy, const struct tsm_screen_attr *attr) @@ -132,6 +132,16 @@ static int bbulk_draw(struct kmscon_text *txt, else font = txt->font; + if (attr->underline) + font->attr.underline = true; + else + font->attr.underline = false; + + if (attr->italic) + font->attr.italic = true; + else + font->attr.italic = false; + if (!len) { ret = kmscon_font_render_empty(font, &glyph); } else { diff --git a/src/text_gltex.c b/src/text_gltex.c index 20f7eb3..afee079 100644 --- a/src/text_gltex.c +++ b/src/text_gltex.c @@ -381,7 +381,7 @@ err_free: } static int find_glyph(struct kmscon_text *txt, struct glyph **out, - uint32_t id, const uint32_t *ch, size_t len, bool bold) + uint64_t id, const uint32_t *ch, size_t len, const struct tsm_screen_attr *attr) { struct gltex *gt = txt->data; struct atlas *atlas; @@ -393,7 +393,7 @@ static int find_glyph(struct kmscon_text *txt, struct glyph **out, struct shl_hashtable *gtable; struct kmscon_font *font; - if (bold) { + if (attr->bold) { gtable = gt->bold_glyphs; font = txt->bold_font; } else { @@ -401,8 +401,18 @@ static int find_glyph(struct kmscon_text *txt, struct glyph **out, font = txt->font; } + if (attr->underline) + font->attr.underline = true; + else + font->attr.underline = false; + + if (attr->italic) + font->attr.italic = true; + else + font->attr.italic = false; + res = shl_hashtable_find(gtable, (void**)&glyph, - (void*)(unsigned long)id); + (void*)(uint64_t)id); if (res) { *out = glyph; return 0; @@ -505,7 +515,7 @@ static int find_glyph(struct kmscon_text *txt, struct glyph **out, glyph->atlas = atlas; glyph->texoff = atlas->fill; - ret = shl_hashtable_insert(gtable, (void*)(long)id, glyph); + ret = shl_hashtable_insert(gtable, (void*)(uint64_t)id, glyph); if (ret) goto err_free; @@ -543,7 +553,7 @@ static int gltex_prepare(struct kmscon_text *txt) } static int gltex_draw(struct kmscon_text *txt, - uint32_t id, const uint32_t *ch, size_t len, + uint64_t id, const uint32_t *ch, size_t len, unsigned int width, unsigned int posx, unsigned int posy, const struct tsm_screen_attr *attr) @@ -556,7 +566,7 @@ static int gltex_draw(struct kmscon_text *txt, if (!width) return 0; - ret = find_glyph(txt, &glyph, id, ch, len, attr->bold); + ret = find_glyph(txt, &glyph, id, ch, len, attr); if (ret) return ret; atlas = glyph->atlas; diff --git a/src/text_pixman.c b/src/text_pixman.c index fc10f71..d287088 100644 --- a/src/text_pixman.c +++ b/src/text_pixman.c @@ -262,7 +262,7 @@ static void tp_unset(struct kmscon_text *txt) } static int find_glyph(struct kmscon_text *txt, struct tp_glyph **out, - uint32_t id, const uint32_t *ch, size_t len, bool bold) + uint64_t id, const uint32_t *ch, size_t len, const struct tsm_screen_attr *attr) { struct tp_pixman *tp = txt->data; struct tp_glyph *glyph; @@ -274,7 +274,7 @@ static int find_glyph(struct kmscon_text *txt, struct tp_glyph **out, int ret, stride; bool res; - if (bold) { + if (attr->bold) { gtable = tp->bold_glyphs; font = txt->bold_font; } else { @@ -282,8 +282,18 @@ static int find_glyph(struct kmscon_text *txt, struct tp_glyph **out, font = txt->font; } + if (attr->underline) + font->attr.underline = true; + else + font->attr.underline = false; + + if (attr->italic) + font->attr.italic = true; + else + font->attr.italic = false; + res = shl_hashtable_find(gtable, (void**)&glyph, - (void*)(unsigned long)id); + (void*)(uint64_t)id); if (res) { *out = glyph; return 0; @@ -351,7 +361,7 @@ static int find_glyph(struct kmscon_text *txt, struct tp_glyph **out, goto err_free; } - ret = shl_hashtable_insert(gtable, (void*)(long)id, glyph); + ret = shl_hashtable_insert(gtable, (void*)(uint64_t)id, glyph); if (ret) goto err_pixman; @@ -387,7 +397,7 @@ static int tp_prepare(struct kmscon_text *txt) } static int tp_draw(struct kmscon_text *txt, - uint32_t id, const uint32_t *ch, size_t len, + uint64_t id, const uint32_t *ch, size_t len, unsigned int width, unsigned int posx, unsigned int posy, const struct tsm_screen_attr *attr) @@ -402,7 +412,7 @@ static int tp_draw(struct kmscon_text *txt, if (!width) return 0; - ret = find_glyph(txt, &glyph, id, ch, len, attr->bold); + ret = find_glyph(txt, &glyph, id, ch, len, attr); if (ret) return ret; diff --git a/src/uterm_drm3d_render.c b/src/uterm_drm3d_render.c index aecaf67..3f409d8 100644 --- a/src/uterm_drm3d_render.c +++ b/src/uterm_drm3d_render.c @@ -498,6 +498,14 @@ int uterm_drm3d_display_fill(struct uterm_display *disp, if (tmp > sh) height = sh - y; + /* Caution: + * opengl uses a coordinate system with the origin at _lower-left_ corner + * and positive y-axis up, while other parts uses a coordinate system + * with the origin at _upper-left_ corner and positive y-axis down. + */ + y = sh - y; // invert y-axis + y -= height; // move origin to lower left corner + glViewport(x, y, width, height); glDisable(GL_BLEND); diff --git a/src/uterm_fbdev_internal.h b/src/uterm_fbdev_internal.h index f89a199..e263e4a 100644 --- a/src/uterm_fbdev_internal.h +++ b/src/uterm_fbdev_internal.h @@ -55,6 +55,7 @@ struct fbdev_display { unsigned int stride; bool xrgb32; + bool rgb24; bool rgb16; unsigned int Bpp; unsigned int off_r; diff --git a/src/uterm_fbdev_render.c b/src/uterm_fbdev_render.c index a06bf08..2dda19a 100644 --- a/src/uterm_fbdev_render.c +++ b/src/uterm_fbdev_render.c @@ -100,6 +100,21 @@ static uint_fast32_t xrgb32_to_device(struct uterm_display *disp, return res; } +static void write_24bit(uint8_t *dst, uint_fast32_t value) +{ + #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + dst[0] = value; + dst[1] = value >> 8; + dst[2] = value >> 16; + #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + dst[0] = value >> 16; + dst[1] = value >> 8; + dst[2] = value; + #else + #error "Unknown endianness" + #endif +} + int uterm_fbdev_display_blit(struct uterm_display *disp, const struct uterm_video_buffer *buf, unsigned int x, unsigned int y) @@ -151,6 +166,16 @@ int uterm_fbdev_display_blit(struct uterm_display *disp, dst += fbdev->stride; src += buf->stride; } + } else if (fbdev->Bpp == 3) { + while (height--) { + for (i = 0; i < width; ++i) { + val = ((uint32_t*)src)[i]; + uint_fast32_t full = xrgb32_to_device(disp, val); + write_24bit(&dst[i * 3], full); + } + dst += fbdev->stride; + src += buf->stride; + } } else if (fbdev->Bpp == 4) { while (height--) { for (i = 0; i < width; ++i) { @@ -272,6 +297,35 @@ int uterm_fbdev_display_fake_blendv(struct uterm_display *disp, dst += fbdev->stride; src += req->buf->stride; } + } else if (fbdev->Bpp == 3) { + while (height--) { + for (i = 0; i < width; ++i) { + if (src[i] == 0) { + r = req->br; + g = req->bg; + b = req->bb; + } else if (src[i] == 255) { + r = req->fr; + g = req->fg; + b = req->fb; + } else { + r = req->fr * src[i] + + req->br * (255 - src[i]); + r /= 256; + g = req->fg * src[i] + + req->bg * (255 - src[i]); + g /= 256; + b = req->fb * src[i] + + req->bb * (255 - src[i]); + b /= 256; + } + val = (r << 16) | (g << 8) | b; + uint_fast32_t full = xrgb32_to_device(disp, val); + write_24bit(&dst[i * 3], full); + } + dst += fbdev->stride; + src += req->buf->stride; + } } else if (fbdev->Bpp == 4) { while (height--) { for (i = 0; i < width; ++i) { @@ -358,6 +412,13 @@ int uterm_fbdev_display_fill(struct uterm_display *disp, dst += fbdev->stride; } } + } else if (fbdev->Bpp == 3) { + while (height--) { + for (i = 0; i < width * 3; i += 3) { + write_24bit(&dst[i], full_val); + } + dst += fbdev->stride; + } } else if (fbdev->Bpp == 4) { while (height--) { for (i = 0; i < width; ++i) diff --git a/src/uterm_fbdev_video.c b/src/uterm_fbdev_video.c index 06bddca..c977b8f 100644 --- a/src/uterm_fbdev_video.c +++ b/src/uterm_fbdev_video.c @@ -132,9 +132,7 @@ static int display_activate_force(struct uterm_display *disp, struct uterm_mode *mode, bool force) { - /* TODO: Add support for 24-bpp. However, we need to check how 3-bytes - * integers are assembled in big/little/mixed endian systems. */ - static const char depths[] = { 32, 16, 0 }; + static const char depths[] = { 32, 24, 16, 0 }; struct fbdev_display *dfb = disp->data; struct uterm_mode *m; struct fbdev_mode *mfb; @@ -217,14 +215,19 @@ static int display_activate_force(struct uterm_display *disp, if (finfo->visual != FB_VISUAL_TRUECOLOR || vinfo->bits_per_pixel != 32) { for (i = 0; depths[i]; ++i) { - vinfo->bits_per_pixel = depths[i]; - vinfo->activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; + /* Try to set a new mode and if it's successful... */ + struct fb_var_screeninfo vinfo_new = *vinfo; + vinfo_new.bits_per_pixel = depths[i]; + vinfo_new.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; ret = ioctl(dfb->fd, FBIOPUT_VSCREENINFO, - vinfo); + &vinfo_new); if (ret < 0) continue; + /* ... keep it. */ + *vinfo = vinfo_new; + ret = refresh_info(disp); if (ret) goto err_close; @@ -235,6 +238,7 @@ static int display_activate_force(struct uterm_display *disp, } if (vinfo->bits_per_pixel != 32 && + vinfo->bits_per_pixel != 24 && vinfo->bits_per_pixel != 16) { log_error("device %s does not support 16/32 bpp but: %u", dfb->node, vinfo->bits_per_pixel); @@ -333,6 +337,10 @@ static int display_activate_force(struct uterm_display *disp, dfb->off_r == 11 && dfb->off_g == 5 && dfb->off_b == 0 && dfb->Bpp == 2) dfb->rgb16 = true; + else if (dfb->len_r == 8 && dfb->len_g == 8 && dfb->len_b == 8 && + dfb->off_r == 16 && dfb->off_g == 8 && dfb->off_b == 0 && + dfb->Bpp == 3) + dfb->rgb24 = true; /* TODO: make dithering configurable */ disp->flags |= DISPLAY_DITHERING; @@ -455,6 +463,8 @@ static int display_get_buffers(struct uterm_display *disp, f = UTERM_FORMAT_XRGB32; else if (dfb->rgb16) f = UTERM_FORMAT_RGB16; + else if (dfb->rgb24) + f = UTERM_FORMAT_RGB24; if (!(formats & f)) return -EOPNOTSUPP; diff --git a/src/uterm_video.h b/src/uterm_video.h index 9f516c5..fe3cb78 100644 --- a/src/uterm_video.h +++ b/src/uterm_video.h @@ -100,6 +100,7 @@ enum uterm_video_format { UTERM_FORMAT_GREY = 0x01, UTERM_FORMAT_XRGB32 = 0x02, UTERM_FORMAT_RGB16 = 0x04, + UTERM_FORMAT_RGB24 = 0x08, }; struct uterm_video_buffer { diff --git a/src/uterm_vt.c b/src/uterm_vt.c index af377f5..fbe9e76 100644 --- a/src/uterm_vt.c +++ b/src/uterm_vt.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include