aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile7
-rw-r--r--fb-gui.c615
-rw-r--r--fb-gui.h32
-rw-r--r--fbi.c452
-rw-r--r--fs.c502
-rw-r--r--fs.h72
6 files changed, 718 insertions, 962 deletions
diff --git a/GNUmakefile b/GNUmakefile
index 471bd23..b056a25 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -106,7 +106,6 @@ fbi : LDLIBS += $(call ac_lib_mkvar,$(fbi_libs),LDLIBS)
# jpeg/exif libs
exiftran : LDLIBS += -ljpeg -lexif -lm
-genthumbnail : LDLIBS += -ljpeg -lexif -lm
thumbnail.cgi : LDLIBS += -lexif -lm
exiftran: exiftran.o genthumbnail.o jpegtools.o jpeg/transupp.o \
@@ -156,7 +155,7 @@ ida.o: Ida.ad.h logo.h
# object files
OBJS_FBI := \
- fbi.o fbtools.o fs.o fb-gui.o desktop.o \
+ fbi.o fbtools.o fb-gui.o desktop.o \
parseconfig.o fbiconfig.o \
jpegtools.o jpeg/transupp.o \
dither.o filter.o op.o
@@ -164,8 +163,9 @@ OBJS_FBI := \
OBJS_FBI += $(filter-out wr/%,$(call ac_lib_mkvar,$(fbi_libs),OBJS))
# jpeg/exif libs
+fbi : CFLAGS += $(shell pkg-config --cflags freetype2 fontconfig)
+fbi : LDLIBS += $(shell pkg-config --libs freetype2 fontconfig)
fbi : LDLIBS += -ljpeg -lexif -lm
-fs.o fb-gui.o : CFLAGS += -DX_DISPLAY_MISSING=1
fbi: $(OBJS_FBI) $(OBJS_READER)
@@ -213,4 +213,3 @@ include $(srcdir)/mk/Maintainer.mk
sync::
cp $(srcdir)/../xawtv/common/parseconfig.[ch] $(srcdir)
cp $(srcdir)/../xawtv/console/fbtools.[ch] $(srcdir)
- cp $(srcdir)/../xawtv/console/fs.[ch] $(srcdir)
diff --git a/fb-gui.c b/fb-gui.c
index 3c6328c..eb04e46 100644
--- a/fb-gui.c
+++ b/fb-gui.c
@@ -1,73 +1,277 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <math.h>
+#include <wchar.h>
+#include <sys/ioctl.h>
#include <linux/fb.h>
+#include <fontconfig/fontconfig.h>
+#include <fontconfig/fcfreetype.h>
+
#include "fbtools.h"
-#include "fs.h"
+#include "dither.h"
#include "fb-gui.h"
/* public */
int visible = 1;
-/* private */
-static struct fs_font *f;
-static char *x11_font = "10x20";
-
static int ys = 3;
static int xs = 10;
/* ---------------------------------------------------------------------- */
-/* clear screen (areas) */
+/* shadow framebuffer -- internals */
-void fb_clear_mem(void)
+static float p_gamma = 1;
+static unsigned short p_red[256], p_green[256], p_blue[256];
+static struct fb_cmap p_cmap = { 0, 256, p_red, p_green, p_blue };
+
+static int32_t s_lut_red[256], s_lut_green[256], s_lut_blue[256];
+
+static unsigned char **shadow;
+static unsigned int *sdirty,swidth,sheight;
+
+static unsigned short calc_gamma(int n, int max)
{
- if (visible)
- fb_memset(fb_mem,0,fb_fix.smem_len);
+ int ret = 65535.0 * pow((float)n/(max), 1 / p_gamma);
+ if (ret > 65535) ret = 65535;
+ if (ret < 0) ret = 0;
+ return ret;
}
-void fb_clear_screen(void)
+static void
+linear_palette(int bit)
{
- if (visible)
- fb_memset(fb_mem,0,fb_fix.line_length * fb_var.yres);
+ int i, size = 256 >> (8 - bit);
+
+ for (i = 0; i < size; i++)
+ p_red[i] = p_green[i] = p_blue[i] = calc_gamma(i,size);
}
-static void fb_clear_rect(int x1, int x2, int y1,int y2)
+static void
+dither_palette(int r, int g, int b)
{
- unsigned char *ptr;
- int y,h;
+ int rs, gs, bs, i;
+
+ rs = 256 / (r - 1);
+ gs = 256 / (g - 1);
+ bs = 256 / (b - 1);
+ for (i = 0; i < 256; i++) {
+ p_red[i] = calc_gamma(rs * ((i / (g * b)) % r), 255);
+ p_green[i] = calc_gamma(gs * ((i / b) % g), 255);
+ p_blue[i] = calc_gamma(bs * ((i) % b), 255);
+ }
+}
+
+static void shadow_lut_init_one(int32_t *lut, int bits, int shift)
+{
+ int i;
+
+ if (bits > 8)
+ for (i = 0; i < 256; i++)
+ lut[i] = (i << (bits + shift - 8));
+ else
+ for (i = 0; i < 256; i++)
+ lut[i] = (i >> (8 - bits)) << shift;
+}
+
+static void shadow_lut_init(int depth)
+{
+ if (fb_var.red.length &&
+ fb_var.green.length &&
+ fb_var.blue.length) {
+ /* fb_var.{red|green|blue} looks sane, use it */
+ shadow_lut_init_one(s_lut_red, fb_var.red.length, fb_var.red.offset);
+ shadow_lut_init_one(s_lut_green, fb_var.green.length, fb_var.green.offset);
+ shadow_lut_init_one(s_lut_blue, fb_var.blue.length, fb_var.blue.offset);
+ } else {
+ /* fallback */
+ int i;
+ switch (depth) {
+ case 15:
+ for (i = 0; i < 256; i++) {
+ s_lut_red[i] = (i & 0xf8) << 7; /* bits -rrrrr-- -------- */
+ s_lut_green[i] = (i & 0xf8) << 2; /* bits ------gg ggg----- */
+ s_lut_blue[i] = (i & 0xf8) >> 3; /* bits -------- ---bbbbb */
+ }
+ break;
+ case 16:
+ for (i = 0; i < 256; i++) {
+ s_lut_red[i] = (i & 0xf8) << 8; /* bits rrrrr--- -------- */
+ s_lut_green[i] = (i & 0xfc) << 3; /* bits -----ggg ggg----- */
+ s_lut_blue[i] = (i & 0xf8) >> 3; /* bits -------- ---bbbbb */
+ }
+ break;
+ case 24:
+ for (i = 0; i < 256; i++) {
+ s_lut_red[i] = i << 16; /* byte -r-- */
+ s_lut_green[i] = i << 8; /* byte --g- */
+ s_lut_blue[i] = i; /* byte ---b */
+ }
+ break;
+ }
+ }
+}
+
+static void shadow_render_line(int line, unsigned char *dest, char unsigned *buffer)
+{
+ unsigned char *ptr = (void*)dest;
+ unsigned short *ptr2 = (void*)dest;
+ unsigned long *ptr4 = (void*)dest;
+ int x;
+
+ switch (fb_var.bits_per_pixel) {
+ case 8:
+ dither_line(buffer, ptr, line, swidth);
+ break;
+ case 15:
+ case 16:
+ for (x = 0; x < swidth; x++) {
+ ptr2[x] = s_lut_red[buffer[x*3]] |
+ s_lut_green[buffer[x*3+1]] |
+ s_lut_blue[buffer[x*3+2]];
+ }
+ break;
+ case 24:
+ for (x = 0; x < swidth; x++) {
+ ptr[3*x+2] = buffer[3*x+0];
+ ptr[3*x+1] = buffer[3*x+1];
+ ptr[3*x+0] = buffer[3*x+2];
+ }
+ break;
+ case 32:
+ for (x = 0; x < swidth; x++) {
+ ptr4[x] = s_lut_red[buffer[x*3]] |
+ s_lut_green[buffer[x*3+1]] |
+ s_lut_blue[buffer[x*3+2]];
+ }
+ break;
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+/* shadow framebuffer -- management interface */
+
+void shadow_render(void)
+{
+ unsigned int offset = 0;
+ int i;
if (!visible)
return;
+ for (i = 0; i < sheight; i++, offset += fb_fix.line_length) {
+ if (0 == sdirty[i])
+ continue;
+ shadow_render_line(i, fb_mem + offset, shadow[i]);
+ sdirty[i] = 0;
+ }
+}
+
+void shadow_clear_lines(int first, int last)
+{
+ int i;
+
+ for (i = first; i <= last; i++) {
+ memset(shadow[i],0,3*swidth);
+ sdirty[i]++;
+ }
+}
+
+void shadow_clear(void)
+{
+ shadow_clear_lines(0, sheight-1);
+}
+
+void shadow_set_palette(int fd)
+{
+ if (fb_fix.visual != FB_VISUAL_DIRECTCOLOR && fb_var.bits_per_pixel != 8)
+ return;
+ if (-1 == ioctl(fd,FBIOPUTCMAP,&p_cmap)) {
+ perror("ioctl FBIOPUTCMAP");
+ exit(1);
+ }
+}
- if (x2 < x1)
- h = x2, x2 = x1, x1 = h;
- if (y2 < y1)
- h = y2, y2 = y1, y1 = h;
- ptr = fb_mem;
- ptr += y1 * fb_fix.line_length;
- ptr += x1 * fs_bpp;
+void shadow_init(void)
+{
+ int i;
- for (y = y1; y <= y2; y++) {
- fb_memset(ptr, 0, (x2 - x1 + 1) * fs_bpp);
- ptr += fb_fix.line_length;
+ /* init shadow fb */
+ swidth = fb_var.xres;
+ sheight = fb_var.yres;
+ shadow = malloc(sizeof(unsigned char*) * sheight);
+ sdirty = malloc(sizeof(unsigned int) * sheight);
+ for (i = 0; i < sheight; i++)
+ shadow[i] = malloc(swidth*3);
+ shadow_clear();
+
+ /* init rendering */
+ switch (fb_var.bits_per_pixel) {
+ case 8:
+ dither_palette(8, 8, 4);
+ init_dither(8, 8, 4, 2);
+ dither_line = dither_line_color;
+ break;
+ case 15:
+ case 16:
+ if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR)
+ linear_palette(5);
+ if (fb_var.green.length == 5) {
+ shadow_lut_init(15);
+ } else {
+ shadow_lut_init(16);
+ }
+ break;
+ case 24:
+ if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR)
+ linear_palette(8);
+ break;
+ case 32:
+ if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR)
+ linear_palette(8);
+ shadow_lut_init(24);
+ break;
+ default:
+ fprintf(stderr, "Oops: %i bit/pixel ???\n",
+ fb_var.bits_per_pixel);
+ exit(1);
}
}
+void shadow_fini(void)
+{
+ int i;
+
+ if (!shadow)
+ return;
+ for (i = 0; i < sheight; i++)
+ free(shadow[i]);
+ free(shadow);
+ free(sdirty);
+}
+
/* ---------------------------------------------------------------------- */
-/* draw lines */
+/* shadow framebuffer -- drawing interface */
-static void fb_setpixel(int x, int y, unsigned int color)
+static void shadow_setpixel(int x, int y)
{
- unsigned char *ptr;
+ unsigned char *dest = shadow[y] + 3*x;
- ptr = fb_mem;
- ptr += y * fb_fix.line_length;
- ptr += x * fs_bpp;
- fs_setpixel(ptr, color);
+ if (x < 0)
+ return;
+ if (x >= swidth)
+ return;
+ if (y < 0)
+ return;
+ if (y >= sheight)
+ return;
+ *(dest++) = 255;
+ *(dest++) = 255;
+ *(dest++) = 255;
+ sdirty[y]++;
}
-static void fb_line(int x1, int x2, int y1,int y2)
+void shadow_draw_line(int x1, int x2, int y1,int y2)
{
int x,y,h;
float inc;
@@ -81,84 +285,237 @@ static void fb_line(int x1, int x2, int y1,int y2)
inc = (float)(x2-x1)/(float)(y2-y1);
for (y = y1; y <= y2; y++) {
x = x1 + inc * (y - y1);
- fb_setpixel(x,y,fs_white);
+ shadow_setpixel(x,y);
}
} else {
inc = (float)(y2-y1)/(float)(x2-x1);
for (x = x1; x <= x2; x++) {
y = y1 + inc * (x - x1);
- fb_setpixel(x,y,fs_white);
+ shadow_setpixel(x,y);
}
}
}
-static void fb_rect(int x1, int x2, int y1,int y2)
+void shadow_draw_rect(int x1, int x2, int y1,int y2)
{
- fb_line(x1, x2, y1, y1);
- fb_line(x1, x2, y2, y2);
- fb_line(x1, x1, y1, y2);
- fb_line(x2, x2, y1, y2);
+ shadow_draw_line(x1, x2, y1, y1);
+ shadow_draw_line(x1, x2, y2, y2);
+ shadow_draw_line(x1, x1, y1, y2);
+ shadow_draw_line(x2, x2, y1, y2);
+}
+
+void shadow_draw_rgbdata(int x, int y, int pixels, unsigned char *rgb)
+{
+ unsigned char *dest = shadow[y] + 3*x;
+
+ memcpy(dest,rgb,3*pixels);
+ sdirty[y]++;
}
-/* ---------------------------------------------------------------------- */
-/* text stuff */
-void fb_text_init1(char *font)
+void shadow_darkify(int x1, int x2, int y1,int y2, int percent)
{
- char *fonts[2] = { font, NULL };
+ unsigned char *ptr;
+ int x,y,h;
- if (NULL == f)
- f = fs_consolefont(font ? fonts : NULL);
-#ifndef X_DISPLAY_MISSING
- if (NULL == f && 0 == fs_connect(NULL))
- f = fs_open(font ? font : x11_font);
-#endif
- if (NULL == f) {
- fprintf(stderr,"no font available\n");
- exit(1);
+ if (x2 < x1)
+ h = x2, x2 = x1, x1 = h;
+ if (y2 < y1)
+ h = y2, y2 = y1, y1 = h;
+
+ for (y = y1; y <= y2; y++) {
+ if (y < 0)
+ continue;
+ if (y >= sheight)
+ continue;
+ sdirty[y]++;
+ ptr = shadow[y];
+ for (x = x1; x <= x2; x++) {
+ if (x < 0)
+ continue;
+ if (x >= swidth)
+ continue;
+ ptr[3*x+0] = ptr[3*x+0] * percent / 100;
+ ptr[3*x+1] = ptr[3*x+1] * percent / 100;
+ ptr[3*x+2] = ptr[3*x+2] * percent / 100;
+ }
}
}
-void fb_text_init2(void)
+void shadow_reverse(int x1, int x2, int y1,int y2)
{
- fs_init_fb(255);
+ unsigned char *ptr;
+ int x,y,h;
+
+ if (x2 < x1)
+ h = x2, x2 = x1, x1 = h;
+ if (y2 < y1)
+ h = y2, y2 = y1, y1 = h;
+
+ for (y = y1; y <= y2; y++) {
+ if (y < 0)
+ continue;
+ if (y >= sheight)
+ continue;
+ sdirty[y]++;
+ ptr = shadow[y];
+ for (x = x1; x <= x2; x++) {
+ if (x < 0)
+ continue;
+ if (x >= swidth)
+ continue;
+ ptr[3*x+0] = 255-ptr[3*x+0];
+ ptr[3*x+1] = 255-ptr[3*x+1];
+ ptr[3*x+2] = 255-ptr[3*x+2];
+ }
+ }
}
-int fb_font_width(void)
+/* ---------------------------------------------------------------------- */
+/* shadow framebuffer -- text rendering */
+
+static void shadow_draw_glyph(FT_Bitmap *bitmap, int sx, int sy)
{
- return f->width;
+ unsigned char *src,*dst;
+ unsigned int bit;
+ int x,y;
+
+ src = bitmap->buffer;
+ for (y = 0; y < bitmap->rows; y++, src += bitmap->pitch) {
+ if (sy+y < 0)
+ continue;
+ if (sy+y >= sheight)
+ continue;
+ sdirty[sy+y]++;
+ dst = shadow[sy+y] + sx*3;
+ switch (bitmap->pixel_mode) {
+ case FT_PIXEL_MODE_MONO:
+ for (x = 0; x < bitmap->width; x++, dst += 3) {
+ if (sx+x < 0)
+ continue;
+ if (sx+x >= swidth)
+ continue;
+ bit = (1 << (7-(x&7)));
+ if (bit & (src[x >> 3])) {
+ dst[0] = 255;
+ dst[1] = 255;
+ dst[2] = 255;
+ }
+ }
+ break;
+ case FT_PIXEL_MODE_GRAY:
+ for (x = 0; x < bitmap->width; x++, dst += 3) {
+ if (sx+x < 0)
+ continue;
+ if (sx+x >= swidth)
+ continue;
+ if (src[x]) {
+ dst[0] += (255-dst[0]) * src[x] / 255;
+ dst[1] += (255-dst[1]) * src[x] / 255;
+ dst[2] += (255-dst[2]) * src[x] / 255;
+ }
+ }
+ break;
+ }
+ }
}
-void fb_status_line(unsigned char *msg)
+struct glyph {
+ FT_Glyph glyph;
+ int pos;
+};
+
+int shadow_draw_string(FT_Face face, int x, int y, wchar_t *str, int align)
{
- int y;
+ struct glyph *glyphs;
+ FT_UInt gi,pgi;
+ FT_Vector delta,pen;
+ FT_Glyph image;
+ FT_BitmapGlyph bit;
+ size_t len;
+ int i,ng,pos,kerning;
+
+ len = wcslen(str);
+ glyphs = malloc(sizeof(*glyphs) * len);
+ memset(glyphs,0,sizeof(*glyphs) * len);
+
+ kerning = FT_HAS_KERNING(face);
+ pgi = 0;
- if (!visible)
- return;
- y = fb_var.yres - f->height - ys;
- fb_memset(fb_mem + fb_fix.line_length * y, 0,
- fb_fix.line_length * (f->height+ys));
- fb_line(0, fb_var.xres, y, y);
- fs_puts(f, 0, y+ys, msg);
+ for (ng = 0, pos = 0, i = 0; str[i] != 0; i++) {
+ gi = FT_Get_Char_Index(face, str[i]);
+ if (kerning && pgi && gi) {
+ FT_Get_Kerning(face,pgi,gi,FT_KERNING_DEFAULT,&delta);
+ pos += delta.x;
+ }
+ glyphs[ng].pos = pos;
+ if (0 != FT_Load_Glyph(face, gi, FT_LOAD_DEFAULT))
+ continue;
+ if (0 != FT_Get_Glyph(face->glyph, &glyphs[ng].glyph))
+ continue;
+ pos += face->glyph->advance.x;
+ pgi = gi;
+ ng++;
+ }
+
+ for (i = 0; i < ng; i++) {
+ pen.x = (x << 6) + glyphs[i].pos;
+ pen.y = (sheight - y) << 6;
+ switch(align) {
+ case -1: /* left */
+ break;
+ case 0: /* center */
+ pen.x -= pos/2;
+ break;
+ case 1: /* right */
+ pen.x -= pos;
+ break;
+ }
+ image = glyphs[i].glyph;
+ if (0 != FT_Glyph_To_Bitmap(&image,FT_RENDER_MODE_NORMAL,&pen,0))
+ continue;
+ bit = (FT_BitmapGlyph)image;
+ shadow_draw_glyph(&bit->bitmap, bit->left, sheight - bit->top);
+ FT_Done_Glyph(image);
+ }
+
+ for (i = 0; i < ng; i++) {
+ FT_Done_Glyph(glyphs[i].glyph);
+ }
+ free(glyphs);
+
+ return pos >> 6;
}
-void fb_edit_line(unsigned char *str, int pos)
+void shadow_draw_string_cursor(FT_Face face, int x, int y, wchar_t *str, int pos)
{
- int x,y;
-
- if (!visible)
- return;
- y = fb_var.yres - f->height - ys;
- x = pos * f->width;
- fb_memset(fb_mem + fb_fix.line_length * y, 0,
- fb_fix.line_length * (f->height+ys));
- fb_line(0, fb_var.xres, y, y);
- fs_puts(f, 0, y+ys, str);
- fb_line(x, x + f->width, fb_var.yres-1, fb_var.yres-1);
- fb_line(x, x + f->width, fb_var.yres-2, fb_var.yres-2);
+ wchar_t save;
+ int len, left, width, y1, y2;
+
+ len = wcslen(str);
+ if (pos >= len) {
+ left = shadow_draw_string(face, x, y, str, -1);
+ width = shadow_draw_string(face, x+left, y, L" ", -1);
+ } else {
+ save = str[pos];
+ str[pos] = 0;
+ left = shadow_draw_string(face, x, y, str, -1);
+ str[pos] = save;
+
+ save = str[pos+1];
+ str[pos+1] = 0;
+ width = shadow_draw_string(face, x+left, y, str+pos, -1);
+ str[pos+1] = save;
+
+ shadow_draw_string(face, x+left+width, y, str+pos+1, -1);
+ }
+
+ y2 = y - (face->size->metrics.descender >> 6) -1;
+ y1 = y2 - (face->size->metrics.height >> 6) +1;
+ shadow_reverse(left,left+width,y1,y2);
}
-void fb_text_box(int x, int y, char *lines[], unsigned int count)
+void shadow_draw_text_box(FT_Face face, int x, int y, int percent, wchar_t *lines[], unsigned int count)
{
unsigned int i,len,max, x1, x2, y1, y2;
@@ -167,23 +524,107 @@ void fb_text_box(int x, int y, char *lines[], unsigned int count)
max = 0;
for (i = 0; i < count; i++) {
- len = strlen(lines[i]);
+ len = wcslen(lines[i]);
if (max < len)
max = len;
}
+
+ FT_Load_Glyph(face, FT_Get_Char_Index(face, 'm'), FT_LOAD_DEFAULT);
x1 = x;
- x2 = x + max * f->width;
+ x2 = x + max * (face->glyph->advance.x >> 6);
y1 = y;
- y2 = y + count * f->height;
+ y2 = y + count * (face->size->metrics.height >> 6);
x += xs; x2 += 2*xs;
y += ys; y2 += 2*ys;
+ y += (face->size->metrics.height >> 6);
+ y += (face->size->metrics.descender >> 6);
- fb_clear_rect(x1, x2, y1, y2);
- fb_rect(x1, x2, y1, y2);
+ shadow_darkify(x1, x2, y1, y2, percent);
+ shadow_draw_rect(x1, x2, y1, y2);
for (i = 0; i < count; i++) {
- fs_puts(f,x,y,lines[i]);
- y += f->height;
+ shadow_draw_string(face, x, y, lines[i], -1);
+ y += (face->size->metrics.height >> 6);
}
}
+/* ---------------------------------------------------------------------- */
+/* fontconfig + freetype font rendering */
+
+static FT_Library freetype;
+
+void font_init(void)
+{
+ int rc;
+
+ FcInit();
+ rc = FT_Init_FreeType(&freetype);
+ if (rc) {
+ fprintf(stderr,"FT_Init_FreeType() failed\n");
+ exit(1);
+ }
+}
+
+FT_Face font_open(char *fcname)
+{
+ FcResult result = 0;
+ FT_Face face = NULL;
+ FcPattern *pattern,*match;
+ char *fontname,*h;
+ FcChar8 *filename;
+ double pixelsize;
+ int rc;
+
+ /* parse + match font name */
+ pattern = FcNameParse(fcname);
+ FcConfigSubstitute(NULL, pattern, FcMatchPattern);
+ FcDefaultSubstitute(pattern);
+ match = FcFontMatch (0, pattern, &result);
+ FcPatternDestroy(pattern);
+ if (FcResultMatch != result)
+ return NULL;
+ fontname = FcNameUnparse(match);
+ h = strchr(fontname, ':');
+ if (h)
+ *h = 0;
+
+ /* try get the face directly */
+ result = FcPatternGetFTFace(match, FC_FT_FACE, 0, &face);
+ if (FcResultMatch == result) {
+ fprintf(stderr,"using \"%s\", face=%p\n",fontname,face);
+ return face;
+ }
+
+ /* failing that use the filename */
+ result = FcPatternGetString (match, FC_FILE, 0, &filename);
+ if (FcResultMatch == result) {
+ result = FcPatternGetDouble(match, FC_PIXEL_SIZE, 0, &pixelsize);
+ if (FcResultMatch != result)
+ pixelsize = 16;
+ fprintf(stderr,"using \"%s\", pixelsize=%.2lf file=%s\n",
+ fontname,pixelsize,filename);
+ rc = FT_New_Face (freetype, filename, 0, &face);
+ if (rc)
+ return NULL;
+ FT_Set_Pixel_Sizes(face, 0, (int)pixelsize);
+ return face;
+ }
+
+ /* oops, didn't work */
+ return NULL;
+}
+
+/* ---------------------------------------------------------------------- */
+/* clear screen (areas) */
+
+void fb_clear_mem(void)
+{
+ if (visible)
+ fb_memset(fb_mem,0,fb_fix.smem_len);
+}
+
+void fb_clear_screen(void)
+{
+ if (visible)
+ fb_memset(fb_mem,0,fb_fix.line_length * fb_var.yres);
+}
diff --git a/fb-gui.h b/fb-gui.h
index 1e7d7b8..4085346 100644
--- a/fb-gui.h
+++ b/fb-gui.h
@@ -1,11 +1,29 @@
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+
extern int visible;
+void shadow_render(void);
+void shadow_clear_lines(int first, int last);
+void shadow_clear(void);
+void shadow_set_palette(int fd);
+void shadow_init(void);
+void shadow_fini(void);
+
+void shadow_draw_line(int x1, int x2, int y1,int y2);
+void shadow_draw_rect(int x1, int x2, int y1,int y2);
+void shadow_draw_rgbdata(int x, int y, int pixels, unsigned char *rgb);
+void shadow_darkify(int x1, int x2, int y1,int y2, int percent);
+void shadow_reverse(int x1, int x2, int y1,int y2);
+
+int shadow_draw_string(FT_Face face, int x, int y, wchar_t *str, int align);
+void shadow_draw_string_cursor(FT_Face face, int x, int y, wchar_t *str, int pos);
+void shadow_draw_text_box(FT_Face face, int x, int y, int percent,
+ wchar_t *lines[], unsigned int count);
+
+void font_init(void);
+FT_Face font_open(char *fcname);
+
void fb_clear_mem(void);
void fb_clear_screen(void);
-
-void fb_text_init1(char *font);
-void fb_text_init2(void);
-int fb_font_width(void);
-void fb_status_line(unsigned char *msg);
-void fb_edit_line(unsigned char *str, int pos);
-void fb_text_box(int x, int y, char *lines[], unsigned int count);
diff --git a/fbi.c b/fbi.c
index af61502..bd4d9a9 100644
--- a/fbi.c
+++ b/fbi.c
@@ -19,6 +19,7 @@
#include <signal.h>
#include <ctype.h>
#include <locale.h>
+#include <wchar.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
@@ -112,9 +113,10 @@ static float fbgamma = 1;
/* Command line options. */
-int autodown = 0;
-int autoup = 0;
-int comments = 0;
+int autodown = 0;
+int autoup = 0;
+int comments = 0;
+int transparency = 30;
struct option fbi_options[] = {
{"version", no_argument, NULL, 'V'}, /* version */
@@ -146,6 +148,7 @@ struct option fbi_options[] = {
/* font handling */
static char *fontname = NULL;
+static FT_Face face;
/* ---------------------------------------------------------------------- */
@@ -335,32 +338,101 @@ static void flist_print_tagged(FILE *fp)
/* ---------------------------------------------------------------------- */
-static void status(unsigned char *desc, char *info)
+static void
+shadow_draw_image(struct ida_image *img, int xoff, int yoff,
+ unsigned int first, unsigned int last)
{
- int chars, ilen;
- char *str;
+ unsigned int dwidth = MIN(img->i.width, fb_var.xres);
+ unsigned int dheight = MIN(img->i.height, fb_var.yres);
+ unsigned int data, offset, y, xs, ys;
+
+ shadow_clear_lines(first, last);
+
+ /* offset for image data (image > screen, select visible area) */
+ offset = (yoff * img->i.width + xoff) * 3;
+
+ /* offset for video memory (image < screen, center image) */
+ xs = 0, ys = 0;
+ if (img->i.width < fb_var.xres)
+ xs += (fb_var.xres - img->i.width) / 2;
+ if (img->i.height < fb_var.yres)
+ ys += (fb_var.yres - img->i.height) / 2;
+
+ /* go ! */
+ for (data = 0, y = 0;
+ data < img->i.width * img->i.height * 3
+ && data / img->i.width / 3 < dheight;
+ data += img->i.width * 3, y++) {
+ if (ys+y < first)
+ continue;
+ if (ys+y > last)
+ continue;
+ shadow_draw_rgbdata(xs, ys+y, dwidth, img->data + data + offset);
+ }
+}
+
+static void status_prepare(struct ida_image *img)
+{
+ int y1 = fb_var.yres - (face->size->metrics.height >> 6);
+ int y2 = fb_var.yres - 1;
+
+ if (img) {
+ shadow_draw_image(img, left, top, y1, y2);
+ shadow_darkify(0, fb_var.xres-1, y1, y2, transparency);
+ } else {
+ shadow_clear_lines(y1, y2);
+ }
+ shadow_draw_line(0, fb_var.xres-1, y1-1, y1-1);
+}
+
+static void status_update(struct ida_image *img, unsigned char *desc, char *info)
+{
+ int yt = fb_var.yres + (face->size->metrics.descender >> 6);
+ wchar_t str[128];
if (!statusline)
return;
- chars = fb_var.xres / fb_font_width();
- str = malloc(chars+1);
+ status_prepare(img);
+
+ swprintf(str,sizeof(str),L"%s",desc);
+ shadow_draw_string(face, 0, yt, str, -1);
if (info) {
- ilen = strlen(info);
- sprintf(str, "%-*.*s [ %s ] H - Help",
- chars-14-ilen, chars-14-ilen, desc, info);
+ swprintf(str,sizeof(str), L"[ %s ] H - Help", info);
} else {
- sprintf(str, "%-*.*s | H - Help", chars-11, chars-11, desc);
+ swprintf(str,sizeof(str), L"| H - Help");
}
- fb_status_line(str);
- free(str);
+ shadow_draw_string(face, fb_var.xres, yt, str, 1);
+
+ shadow_render();
}
-static void show_error(unsigned char *msg)
+static void status_error(unsigned char *msg)
{
- fb_status_line(msg);
+ int yt = fb_var.yres + (face->size->metrics.descender >> 6);
+ wchar_t str[128];
+
+ status_prepare(NULL);
+
+ swprintf(str,sizeof(str), L"%s", msg);
+ shadow_draw_string(face, 0, yt, str, -1);
+
+ shadow_render();
sleep(2);
}
+static void status_edit(struct ida_image *img, unsigned char *msg, int pos)
+{
+ int yt = fb_var.yres + (face->size->metrics.descender >> 6);
+ wchar_t str[128];
+
+ status_prepare(img);
+
+ swprintf(str,sizeof(str), L"%s", msg);
+ shadow_draw_string_cursor(face, 0, yt, str, pos);
+
+ shadow_render();
+}
+
static void show_exif(struct flist *f)
{
static unsigned int tags[] = {
@@ -383,14 +455,14 @@ static void show_exif(struct flist *f)
unsigned int tag,l1,l2,len,count,i;
const char *title[ARRAY_SIZE(tags)];
char *value[ARRAY_SIZE(tags)];
- char *linebuffer[ARRAY_SIZE(tags)];
+ wchar_t *linebuffer[ARRAY_SIZE(tags)];
if (!visible)
return;
ed = exif_data_new_from_file(f->name);
if (NULL == ed) {
- status("image has no EXIF data", NULL);
+ status_error("image has no EXIF data");
return;
}
@@ -421,13 +493,16 @@ static void show_exif(struct flist *f)
for (tag = 0; tag < ARRAY_SIZE(tags); tag++) {
if (NULL == title[tag])
continue;
- linebuffer[count] = malloc(l1+l2+8);
- sprintf(linebuffer[count],"%-*.*s : %-*.*s",
- l1, l1, title[tag],
- l2, l2, value[tag]);
+ linebuffer[count] = malloc(sizeof(wchar_t)*(l1+l2+8));
+ swprintf(linebuffer[count], l1+l2+8,
+ L"%-*.*s : %-*.*s",
+ l1, l1, title[tag],
+ l2, l2, value[tag]);
count++;
}
- fb_text_box(24,16,linebuffer,count);
+ shadow_draw_text_box(face, 24, 16, transparency,
+ linebuffer, count);
+ shadow_render();
/* pass three -- free data */
for (tag = 0; tag < ARRAY_SIZE(tags); tag++)
@@ -440,29 +515,31 @@ static void show_exif(struct flist *f)
static void show_help(void)
{
- static char *help[] = {
- "keyboard commands",
- "~~~~~~~~~~~~~~~~~",
- " ESC, Q - quit",
- " pgdn, space - next image",
- " pgup - previous image",
- " +/- - zoom in/out",
- " A - autozoom image",
- " cursor keys - scroll image",
- "",
- " H - show this help text",
- " I - show EXIF info",
- " P - pause slideshow",
- " V - toggle statusline",
- "",
- "available if started with --edit switch,",
- "rotation works for jpeg images only:",
- " shift+D - delete image",
- " R - rotate clockwise",
- " L - rotate counter-clockwise",
+ static wchar_t *help[] = {
+ L"keyboard commands",
+ L"~~~~~~~~~~~~~~~~~",
+ L" ESC, Q - quit",
+ L" pgdn, space - next image",
+ L" pgup - previous image",
+ L" +/- - zoom in/out",
+ L" A - autozoom image",
+ L" cursor keys - scroll image",
+ L"",
+ L" H - show this help text",
+ L" I - show EXIF info",
+ L" P - pause slideshow",
+ L" V - toggle statusline",
+ L"",
+ L"available if started with --edit switch,",
+ L"rotation works for jpeg images only:",
+ L" shift+D - delete image",
+ L" R - rotate clockwise",
+ L" L - rotate counter-clockwise",
};
- fb_text_box(24,16,help,ARRAY_SIZE(help));
+ shadow_draw_text_box(face, 24, 16, transparency,
+ help, ARRAY_SIZE(help));
+ shadow_render();
}
/* ---------------------------------------------------------------------- */
@@ -504,7 +581,7 @@ static void debug_key(char *key)
len += sprintf(linebuffer+len, "%s%c",
key[i] < 0x20 ? "^" : "",
key[i] < 0x20 ? key[i] + 0x40 : key[i]);
- status(linebuffer, NULL);
+ status_update(NULL, linebuffer, NULL);
}
static void
@@ -522,9 +599,9 @@ console_switch(int is_busy)
visible = 1;
redraw = 1;
ioctl(fd,FBIOPAN_DISPLAY,&fb_var);
- fb_clear_screen();
+ shadow_clear();
if (is_busy)
- status("busy, please wait ...", NULL);
+ status_update(NULL, "busy, please wait ...", NULL);
break;
default:
break;
@@ -650,167 +727,6 @@ static float auto_scale(struct ida_image *img)
/* ---------------------------------------------------------------------- */
-static unsigned char *
-convert_line(int bpp, int line, int owidth,
- char unsigned *dest, char unsigned *buffer)
-{
- unsigned char *ptr = (void*)dest;
- unsigned short *ptr2 = (void*)dest;
- unsigned long *ptr4 = (void*)dest;
- int x;
-
- switch (fb_var.bits_per_pixel) {
- case 8:
- dither_line(buffer, ptr, line, owidth);
- ptr += owidth;
- return ptr;
- case 15:
- case 16:
- for (x = 0; x < owidth; x++) {
- ptr2[x] = lut_red[buffer[x*3]] |
- lut_green[buffer[x*3+1]] |
- lut_blue[buffer[x*3+2]];
- }
- ptr2 += owidth;
- return (char*)ptr2;
- case 24:
- for (x = 0; x < owidth; x++) {
- ptr[3*x+2] = buffer[3*x+0];
- ptr[3*x+1] = buffer[3*x+1];
- ptr[3*x+0] = buffer[3*x+2];
- }
- ptr += owidth * 3;
- return ptr;
- case 32:
- for (x = 0; x < owidth; x++) {
- ptr4[x] = lut_red[buffer[x*3]] |
- lut_green[buffer[x*3+1]] |
- lut_blue[buffer[x*3+2]];
- }
- ptr4 += owidth;
- return (char*)ptr4;
- default:
- /* keep compiler happy */
- return NULL;
- }
-}
-
-/* ---------------------------------------------------------------------- */
-
-static void init_one(int32_t *lut, int bits, int shift)
-{
- int i;
-
- if (bits > 8)
- for (i = 0; i < 256; i++)
- lut[i] = (i << (bits + shift - 8));
- else
- for (i = 0; i < 256; i++)
- lut[i] = (i >> (8 - bits)) << shift;
-}
-
-static void
-lut_init(int depth)
-{
- if (fb_var.red.length &&
- fb_var.green.length &&
- fb_var.blue.length) {
- /* fb_var.{red|green|blue} looks sane, use it */
- init_one(lut_red, fb_var.red.length, fb_var.red.offset);
- init_one(lut_green, fb_var.green.length, fb_var.green.offset);
- init_one(lut_blue, fb_var.blue.length, fb_var.blue.offset);
- } else {
- /* fallback */
- int i;
- switch (depth) {
- case 15:
- for (i = 0; i < 256; i++) {
- lut_red[i] = (i & 0xf8) << 7; /* bits -rrrrr-- -------- */
- lut_green[i] = (i & 0xf8) << 2; /* bits ------gg ggg----- */
- lut_blue[i] = (i & 0xf8) >> 3; /* bits -------- ---bbbbb */
- }
- break;
- case 16:
- for (i = 0; i < 256; i++) {
- lut_red[i] = (i & 0xf8) << 8; /* bits rrrrr--- -------- */
- lut_green[i] = (i & 0xfc) << 3; /* bits -----ggg ggg----- */
- lut_blue[i] = (i & 0xf8) >> 3; /* bits -------- ---bbbbb */
- }
- break;
- case 24:
- for (i = 0; i < 256; i++) {
- lut_red[i] = i << 16; /* byte -r-- */
- lut_green[i] = i << 8; /* byte --g- */
- lut_blue[i] = i; /* byte ---b */
- }
- break;
- }
- }
-}
-
-static unsigned short calc_gamma(int n, int max)
-{
- int ret =65535.0 * pow((float)n/(max), 1 / fbgamma);
- if (ret > 65535) ret = 65535;
- if (ret < 0) ret = 0;
- return ret;
-}
-
-static void
-linear_palette(int bit)
-{
- int i, size = 256 >> (8 - bit);
-
- for (i = 0; i < size; i++)
- red[i] = green[i] = blue[i] = calc_gamma(i,size);
-}
-
-static void
-svga_dither_palette(int r, int g, int b)
-{
- int rs, gs, bs, i;
-
- rs = 256 / (r - 1);
- gs = 256 / (g - 1);
- bs = 256 / (b - 1);
- for (i = 0; i < 256; i++) {
- red[i] = calc_gamma(rs * ((i / (g * b)) % r), 255);
- green[i] = calc_gamma(gs * ((i / b) % g), 255);
- blue[i] = calc_gamma(bs * ((i) % b), 255);
- }
-}
-
-static void
-svga_display_image(struct ida_image *img, int xoff, int yoff)
-{
- unsigned int dwidth = MIN(img->i.width, fb_var.xres);
- unsigned int dheight = MIN(img->i.height, fb_var.yres);
- unsigned int data, video, bank, offset, bytes, y;
-
- if (!visible)
- return;
- bytes = (fb_var.bits_per_pixel+7)/8;
-
- /* offset for image data (image > screen, select visible area) */
- offset = (yoff * img->i.width + xoff) * 3;
-
- /* offset for video memory (image < screen, center image) */
- video = 0, bank = 0;
- if (img->i.width < fb_var.xres)
- video += bytes * ((fb_var.xres - img->i.width) / 2);
- if (img->i.height < fb_var.yres)
- video += fb_fix.line_length * ((fb_var.yres - img->i.height) / 2);
-
- /* go ! */
- for (data = 0, y = 0;
- data < img->i.width * img->i.height * 3
- && data / img->i.width / 3 < dheight;
- data += img->i.width * 3, video += fb_fix.line_length) {
- convert_line(fb_var.bits_per_pixel, y++, dwidth,
- fb_mem+video, img->data + data + offset);
- }
-}
-
static int
svga_show(struct ida_image *img, int timeout, char *desc, char *info, int *nr)
{
@@ -831,8 +747,12 @@ svga_show(struct ida_image *img, int timeout, char *desc, char *info, int *nr)
/* start with centered image, if larger than screen */
if (img->i.width > fb_var.xres)
left = (img->i.width - fb_var.xres) / 2;
- if (img->i.height > fb_var.yres && !textreading)
- top = (img->i.height - fb_var.yres) / 2;
+ if (img->i.height > fb_var.yres) {
+ if (textreading)
+ top = 0;
+ else
+ top = (img->i.height - fb_var.yres) / 2;
+ }
new_image = 0;
}
@@ -856,8 +776,9 @@ svga_show(struct ida_image *img, int timeout, char *desc, char *info, int *nr)
if (left + fb_var.xres > img->i.width)
left = img->i.width - fb_var.xres;
}
- svga_display_image(img, left, top);
- status(desc, info);
+ shadow_draw_image(img, left, top, 0, fb_var.yres-1);
+ status_update(img, desc, info);
+ shadow_render();
}
if (switch_last != fb_switch_state) {
console_switch(0);
@@ -958,7 +879,7 @@ svga_show(struct ida_image *img, int timeout, char *desc, char *info, int *nr)
0 == strcmp(key, "P")) {
if (-1 != timeout) {
paused = !paused;
- status(paused ? "pause on " : "pause off", NULL);
+ status_update(img, paused ? "pause on " : "pause off", NULL);
}
} else if (0 == strcmp(key, "D")) {
@@ -1007,9 +928,8 @@ svga_show(struct ida_image *img, int timeout, char *desc, char *info, int *nr)
} else if (rc == 1 && *key >= '0' && *key <= '9') {
*nr = *nr * 10 + (*key - '0');
sprintf(linebuffer, "> %d",*nr);
- status(linebuffer, NULL);
+ status_update(img, linebuffer, NULL);
} else {
-
*nr = 0;
#if 0
debug_key(key);
@@ -1082,7 +1002,6 @@ static char *make_desc(struct ida_image_info *img, char *filename)
snprintf(linebuffer+len,sizeof(linebuffer)-len,
" (%s)", my_basename(filename));
}
-
return linebuffer;
}
@@ -1099,7 +1018,7 @@ static char *make_info(struct ida_image *img, float scale)
return linebuffer;
}
-static char edit_line(char *line, int max)
+static char edit_line(struct ida_image *img, char *line, int max)
{
int len = strlen(line);
int pos = len;
@@ -1108,7 +1027,11 @@ static char edit_line(char *line, int max)
fd_set set;
do {
+#if 0
fb_edit_line(line,pos);
+#else
+ status_edit(img,line,pos);
+#endif
FD_SET(0, &set);
rc = select(1, &set, NULL, NULL, NULL);
@@ -1180,7 +1103,7 @@ static char edit_line(char *line, int max)
} while (1);
}
-static void edit_desc(char *filename)
+static void edit_desc(struct ida_image *img, char *filename)
{
static char linebuffer[128];
char *desc;
@@ -1192,7 +1115,7 @@ static void edit_desc(char *filename)
linebuffer[0] = 0;
len = 0;
}
- rc = edit_line(linebuffer, sizeof(linebuffer)-1);
+ rc = edit_line(img, linebuffer, sizeof(linebuffer)-1);
if (0 != rc)
return;
desktop_write_entry(desc, "Directory", "Comment=", linebuffer);
@@ -1202,6 +1125,7 @@ static void edit_desc(char *filename)
static void cleanup_and_exit(int code)
{
+ shadow_fini();
fb_clear_mem();
tty_restore();
fb_cleanup();
@@ -1226,7 +1150,7 @@ main(int argc, char *argv[])
float newscale = 1;
int c, editable = 0, once = 0;
- int need_read, need_refresh;
+ int need_read;
int i, arg, key;
char *line, *info, *desc;
@@ -1338,56 +1262,17 @@ main(int argc, char *argv[])
if (randomize != -1)
flist_randomize();
fcurrent = flist_first();
-
need_read = 1;
- need_refresh = 1;
- fb_text_init1(fontname);
+ font_init();
+ face = font_open("monospace:size=16");
fd = fb_init(fbdev, fbmode, vt);
fb_catch_exit_signals();
fb_switch_init();
+ shadow_init();
+ shadow_set_palette(fd);
signal(SIGTSTP,SIG_IGN);
- fb_text_init2();
- switch (fb_var.bits_per_pixel) {
- case 8:
- svga_dither_palette(8, 8, 4);
- dither = TRUE;
- init_dither(8, 8, 4, 2);
- dither_line = dither_line_color;
- break;
- case 15:
- case 16:
- if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR)
- linear_palette(5);
- if (fb_var.green.length == 5) {
- lut_init(15);
- } else {
- lut_init(16);
- }
- break;
- case 24:
- if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR)
- linear_palette(8);
- break;
- case 32:
- if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR)
- linear_palette(8);
- lut_init(24);
- break;
- default:
- fprintf(stderr, "Oops: %i bit/pixel ???\n",
- fb_var.bits_per_pixel);
- exit(1);
- }
- if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR ||
- fb_var.bits_per_pixel == 8) {
- if (-1 == ioctl(fd,FBIOPUTCMAP,&cmap)) {
- perror("ioctl FBIOPUTCMAP");
- exit(1);
- }
- }
-
/* svga main loop */
tty_raw();
desc = NULL;
@@ -1395,14 +1280,14 @@ main(int argc, char *argv[])
for (;;) {
if (need_read) {
need_read = 0;
- need_refresh = 1;
- sprintf(linebuffer,"loading %s ...",fcurrent->name);
- status(linebuffer, NULL);
free_image(fimg);
free_image(simg);
- fimg = read_image(fcurrent->name);
+ fimg = NULL;
simg = NULL;
img = NULL;
+ sprintf(linebuffer,"loading %s ...",fcurrent->name);
+ status_update(img,linebuffer, NULL);
+ fimg = read_image(fcurrent->name);
scale = 1;
if (fimg) {
if (autoup || autodown) {
@@ -1415,7 +1300,7 @@ main(int argc, char *argv[])
if (scale != 1) {
sprintf(linebuffer,"scaling (%.0f%%) %s ...",
scale*100, fcurrent->name);
- status(linebuffer, NULL);
+ status_update(img,linebuffer, NULL);
simg = scale_image(fimg,scale);
img = simg;
} else {
@@ -1425,17 +1310,11 @@ main(int argc, char *argv[])
}
if (!img) {
sprintf(linebuffer,"%s: FAILED",fcurrent->name);
- show_error(linebuffer);
+ status_error(linebuffer);
}
}
- if (img) {
- if (need_refresh) {
- need_refresh = 0;
- if (img->i.width < fb_var.xres || img->i.height < fb_var.yres)
- fb_clear_screen();
- }
+ if (img)
info = make_info(fimg,scale);
- }
switch (key = svga_show(img, timeout, desc, info, &arg)) {
case KEY_DELETE:
if (editable) {
@@ -1450,13 +1329,10 @@ main(int argc, char *argv[])
need_read = 1;
if (list_empty(&flist)) {
/* deleted last one */
- fb_clear_mem();
- tty_restore();
- fb_cleanup();
- exit(0);
+ cleanup_and_exit(0);
}
} else {
- show_error("readonly mode, sorry [start with --edit?]");
+ status_error("readonly mode, sorry [start with --edit?]");
}
break;
case KEY_ROT_CW:
@@ -1464,7 +1340,7 @@ main(int argc, char *argv[])
{
if (editable) {
sprintf(linebuffer,"rotating %s ...",fcurrent->name);
- status(linebuffer, NULL);
+ status_update(img, linebuffer, NULL);
jpeg_transform_inplace
(fcurrent->name,
(key == KEY_ROT_CW) ? JXFORM_ROT_90 : JXFORM_ROT_270,
@@ -1477,7 +1353,7 @@ main(int argc, char *argv[])
JFLAG_UPDATE_ORIENTATION);
need_read = 1;
} else {
- show_error("readonly mode, sorry [start with --edit?]");
+ status_error("readonly mode, sorry [start with --edit?]");
}
break;
}
@@ -1507,9 +1383,7 @@ main(int argc, char *argv[])
need_read = 1;
fcurrent = flist_next(fcurrent,once,1);
if (NULL == fcurrent) {
- fb_clear_mem();
- tty_restore();
- fb_cleanup();
+ cleanup_and_exit(0);
}
/* FIXME: wrap around */
break;
@@ -1534,11 +1408,10 @@ main(int argc, char *argv[])
scale = newscale;
sprintf(linebuffer,"scaling (%.0f%%) %s ...",
scale*100, fcurrent->name);
- status(linebuffer, NULL);
+ status_update(NULL, linebuffer, NULL);
free_image(simg);
simg = scale_image(fimg,scale);
img = simg;
- need_refresh = 1;
break;
case KEY_GOTO:
if (arg > 0 && arg <= fcount) {
@@ -1555,11 +1428,10 @@ main(int argc, char *argv[])
}
#endif
statusline = !statusline;
- need_refresh = 1;
break;
case KEY_DESC:
if (!comments) {
- edit_desc(fcurrent->name);
+ edit_desc(img, fcurrent->name);
desc = make_desc(&fimg->i,fcurrent->name);
}
break;
diff --git a/fs.c b/fs.c
deleted file mode 100644
index 47864fd..0000000
--- a/fs.c
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- * text rendering for the framebuffer console
- * pick fonts from X11 font server or
- * use linux consolefont psf files.
- * (c) 2001 Gerd Knorr <kraxel@bytesex.org>
- */
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <linux/fb.h>
-
-#include "fbtools.h"
-#include "fs.h"
-
-/* ------------------------------------------------------------------ */
-
-#define BIT_ORDER BitmapFormatBitOrderMSB
-#ifdef BYTE_ORDER
-#undef BYTE_ORDER
-#endif
-#define BYTE_ORDER BitmapFormatByteOrderMSB
-#define SCANLINE_UNIT BitmapFormatScanlineUnit8
-#define SCANLINE_PAD BitmapFormatScanlinePad8
-#define EXTENTS BitmapFormatImageRectMin
-
-#define SCANLINE_PAD_BYTES 1
-#define GLWIDTHBYTESPADDED(bits, nBytes) \
- ((nBytes) == 1 ? (((bits) + 7) >> 3) /* pad to 1 byte */\
- :(nBytes) == 2 ? ((((bits) + 15) >> 3) & ~1) /* pad to 2 bytes */\
- :(nBytes) == 4 ? ((((bits) + 31) >> 3) & ~3) /* pad to 4 bytes */\
- :(nBytes) == 8 ? ((((bits) + 63) >> 3) & ~7) /* pad to 8 bytes */\
- : 0)
-
-static const unsigned fs_masktab[] = {
- (1 << 7), (1 << 6), (1 << 5), (1 << 4),
- (1 << 3), (1 << 2), (1 << 1), (1 << 0),
-};
-
-/* ------------------------------------------------------------------ */
-
-#ifndef X_DISPLAY_MISSING
-static FSServer *svr;
-#endif
-unsigned int fs_bpp, fs_black, fs_white;
-
-void (*fs_setpixel)(void *ptr, unsigned int color);
-
-static void setpixel1(void *ptr, unsigned int color)
-{
- unsigned char *p = ptr;
- *p = color;
-}
-static void setpixel2(void *ptr, unsigned int color)
-{
- unsigned short *p = ptr;
- *p = color;
-}
-static void setpixel3(void *ptr, unsigned int color)
-{
- unsigned char *p = ptr;
- *(p++) = (color >> 16) & 0xff;
- *(p++) = (color >> 8) & 0xff;
- *(p++) = color & 0xff;
-}
-static void setpixel4(void *ptr, unsigned int color)
-{
- unsigned long *p = ptr;
- *p = color;
-}
-
-int fs_init_fb(int white8)
-{
- switch (fb_var.bits_per_pixel) {
- case 8:
- fs_white = white8; fs_black = 0; fs_bpp = 1;
- fs_setpixel = setpixel1;
- break;
- case 15:
- case 16:
- if (fb_var.green.length == 6)
- fs_white = 0xffff;
- else
- fs_white = 0x7fff;
- fs_black = 0; fs_bpp = 2;
- fs_setpixel = setpixel2;
- break;
- case 24:
- fs_white = 0xffffff; fs_black = 0; fs_bpp = fb_var.bits_per_pixel/8;
- fs_setpixel = setpixel3;
- break;
- case 32:
- fs_white = 0xffffff; fs_black = 0; fs_bpp = fb_var.bits_per_pixel/8;
- fs_setpixel = setpixel4;
- break;
- default:
- fprintf(stderr, "Oops: %i bit/pixel ???\n",
- fb_var.bits_per_pixel);
- return -1;
- }
- return 0;
-}
-
-void fs_render_fb(unsigned char *ptr, int pitch,
- FSXCharInfo *charInfo, unsigned char *data)
-{
- int row,bit,bpr,x;
-
- bpr = GLWIDTHBYTESPADDED((charInfo->right - charInfo->left),
- SCANLINE_PAD_BYTES);
- for (row = 0; row < (charInfo->ascent + charInfo->descent); row++) {
- for (x = 0, bit = 0; bit < (charInfo->right - charInfo->left); bit++) {
- if (data[bit>>3] & fs_masktab[bit&7])
- fs_setpixel(ptr+x,fs_white);
- x += fs_bpp;
- }
- data += bpr;
- ptr += pitch;
- }
-}
-
-int fs_puts(struct fs_font *f, unsigned int x, unsigned int y,
- unsigned char *str)
-{
- unsigned char *pos,*start;
- int i,c,j,w;
-
- pos = fb_mem+fb_mem_offset;
- pos += fb_fix.line_length * y;
- for (i = 0; str[i] != '\0'; i++) {
- c = str[i];
- if (NULL == f->eindex[c])
- continue;
- /* clear with bg color */
- start = pos + x*fs_bpp + f->fontHeader.max_bounds.descent * fb_fix.line_length;
- w = (f->eindex[c]->width+1)*fs_bpp;
- for (j = 0; j < f->height; j++) {
- memset(start,0,w);
- start += fb_fix.line_length;
- }
- /* draw char */
- start = pos + x*fs_bpp + fb_fix.line_length * (f->height-f->eindex[c]->ascent);
- fs_render_fb(start,fb_fix.line_length,f->eindex[c],f->gindex[c]);
- x += f->eindex[c]->width;
- if (x > fb_var.xres - f->width)
- return -1;
- }
- return x;
-}
-
-int fs_textwidth(struct fs_font *f, unsigned char *str)
-{
- int width = 0;
- int i,c;
-
- for (i = 0; str[i] != '\0'; i++) {
- c = str[i];
- if (NULL == f->eindex[c])
- continue;
- width += f->eindex[c]->width;
- }
- return width;
-}
-
-void fs_render_tty(FSXCharInfo *charInfo, unsigned char *data)
-{
- int bpr,row,bit,on;
-
- bpr = GLWIDTHBYTESPADDED((charInfo->right - charInfo->left),
- SCANLINE_PAD_BYTES);
- for (row = 0; row < (charInfo->ascent + charInfo->descent); row++) {
- fprintf(stdout,"|");
- for (bit = 0; bit < (charInfo->right - charInfo->left); bit++) {
- on = data[bit>>3] & fs_masktab[bit&7];
- fprintf(stdout,"%s",on ? "##" : " ");
- }
- fprintf(stdout,"|\n");
- data += bpr;
- }
- fprintf(stdout,"--\n");
-}
-
-/* ------------------------------------------------------------------ */
-
-#ifndef X_DISPLAY_MISSING
-/* connect to font server */
-int fs_connect(char *servername)
-{
- if (NULL == servername)
- servername = getenv("FONTSERVER");
- if (NULL == servername)
- servername = "unix/:7100";
- svr = FSOpenServer(servername);
- if (NULL == svr) {
- if (NULL == FSServerName(servername)) {
- fprintf(stderr, "no font server defined\n");
- } else {
- fprintf(stderr, "unable to open server \"%s\"\n",
- FSServerName(servername));
- }
- return -1;
- }
- return 0;
-}
-
-/* load font from font server */
-struct fs_font* fs_open(char *pattern)
-{
- int nnames = 1;
- int available,high,low,encoding,bpr;
- char **fonts;
- unsigned char *glyph;
- Font dummy;
- FSBitmapFormat format;
- FSXCharInfo *charInfo;
- struct fs_font *f = NULL;
-
- if (NULL == svr) {
- fprintf(stderr,"fs: not connected\n");
- return NULL;
- }
-
- fonts = FSListFonts(svr, pattern, nnames, &available);
- if (0 == available) {
- fprintf(stderr,"fs: font not available [%s]\n",pattern);
- goto out;
- }
- fprintf(stderr,"using x11 font \"%s\"\n",fonts[0]);
-
- f = malloc(sizeof(*f));
- memset(f,0,sizeof(*f));
- f->font = FSOpenBitmapFont(svr, 0, 0, fonts[0], &dummy);
- FSFreeFontNames(fonts);
- if (0 == f->font)
- goto out;
-
- FSQueryXInfo(svr,f->font,&f->fontHeader, &f->propInfo,
- &f->propOffsets, &f->propData);
- format = BYTE_ORDER | BIT_ORDER | SCANLINE_UNIT | SCANLINE_PAD | EXTENTS;
- FSQueryXExtents16(svr, f->font, True, (FSChar2b *) 0, 0, &f->extents);
- FSQueryXBitmaps16(svr, f->font, format, True, (FSChar2b *) 0, 0,
- &f->offsets, &f->glyphs);
-
- f->maxenc = (f->fontHeader.char_range.max_char.high+1) << 8;
- f->width = f->fontHeader.max_bounds.right - f->fontHeader.min_bounds.left;
- f->height = f->fontHeader.max_bounds.ascent + f->fontHeader.max_bounds.descent;
- f->eindex = malloc(f->maxenc * sizeof(FSXCharInfo*));
- f->gindex = malloc(f->maxenc * sizeof(unsigned char*));
- memset(f->eindex,0,f->maxenc * sizeof(FSXCharInfo*));
- memset(f->gindex,0,f->maxenc * sizeof(unsigned char*));
-
- glyph = f->glyphs;
- charInfo = f->extents;
- for (high = f->fontHeader.char_range.min_char.high;
- high <= f->fontHeader.char_range.max_char.high;
- high++) {
- for (low = f->fontHeader.char_range.min_char.low;
- low <= f->fontHeader.char_range.max_char.low;
- low++) {
- bpr = GLWIDTHBYTESPADDED((charInfo->right - charInfo->left),
- SCANLINE_PAD_BYTES);
- encoding = (high<<8) + low;
-#ifdef TTY
- fprintf(stdout,"e=0x%x | w=%d l=%d r=%d | a=%d d=%d\n",
- encoding,charInfo->width,charInfo->left,
- charInfo->right,charInfo->ascent,charInfo->descent);
-#endif
- if ((charInfo->width != 0) || (charInfo->right != charInfo->left)) {
- f->gindex[encoding] = glyph;
- f->eindex[encoding] = charInfo;
-#ifdef TTY
- fs_render_tty(f->eindex[encoding],
- f->gindex[encoding]);
-#endif
- }
- glyph += (charInfo->descent + charInfo->ascent) * bpr;
- charInfo++;
- }
- }
- return f;
-
- out:
- if (f)
- fs_free(f);
- return NULL;
-}
-#endif
-
-void fs_free(struct fs_font *f)
-{
- if (f->gindex)
- free(f->gindex);
-#if 0
- if (f->extents)
- FSFree((char *) f->extents);
- if (f->offsets)
- FSFree((char *) f->offsets);
- if (f->propOffsets)
- FSFree((char *) (f->propOffsets));
- if (f->propData)
- FSFree((char *) (f->propData));
-#endif
-#if 0 /* FIXME */
- if (f->glyphs)
- FSFree((char *) f->glyphs);
-#endif
- free(f);
-}
-
-/* ------------------------------------------------------------------ */
-/* load console font file */
-
-static char *default_font[] = {
- /* why the heck every f*cking distribution picks another
- location for these fonts ??? */
- "/usr/share/consolefonts/lat1-16.psf",
- "/usr/share/consolefonts/lat1-16.psf.gz",
- "/usr/share/consolefonts/lat1-16.psfu.gz",
- "/usr/share/kbd/consolefonts/lat1-16.psf",
- "/usr/share/kbd/consolefonts/lat1-16.psf.gz",
- "/usr/share/kbd/consolefonts/lat1-16.psfu.gz",
- "/usr/lib/kbd/consolefonts/lat1-16.psf",
- "/usr/lib/kbd/consolefonts/lat1-16.psf.gz",
- "/usr/lib/kbd/consolefonts/lat1-16.psfu.gz",
- "/lib/kbd/consolefonts/lat1-16.psf",
- "/lib/kbd/consolefonts/lat1-16.psf.gz",
- "/lib/kbd/consolefonts/lat1-16.psfu.gz",
- NULL
-};
-
-struct fs_font* fs_consolefont(char **filename)
-{
- int i;
- char *h,command[256];
- struct fs_font *f = NULL;
- FILE *fp;
-
- if (NULL == filename)
- filename = default_font;
-
- for(i = 0; filename[i] != NULL; i++) {
- if (-1 == access(filename[i],R_OK))
- continue;
- break;
- }
- if (NULL == filename[i]) {
- fprintf(stderr,"can't find console font file\n");
- return NULL;
- }
-
- h = filename[i]+strlen(filename[i])-3;
- if (0 == strcmp(h,".gz")) {
- sprintf(command,"zcat %s",filename[i]);
- fp = popen(command,"r");
- } else {
- fp = fopen(filename[i], "r");
- }
- if (NULL == fp) {
- fprintf(stderr,"can't open %s: %s\n",filename[i],strerror(errno));
- return NULL;
- }
-
- if (fgetc(fp) != 0x36 ||
- fgetc(fp) != 0x04) {
- fprintf(stderr,"can't use font %s\n",filename[i]);
- return NULL;
- }
- fprintf(stderr,"using linux console font \"%s\"\n",filename[i]);
-
- f = malloc(sizeof(*f));
- memset(f,0,sizeof(*f));
-
- fgetc(fp);
- f->maxenc = 256;
- f->width = 8;
- f->height = fgetc(fp);
- f->fontHeader.min_bounds.left = 0;
- f->fontHeader.max_bounds.right = f->width;
- f->fontHeader.max_bounds.descent = 0;
- f->fontHeader.max_bounds.ascent = f->height;
-
- f->glyphs = malloc(f->height * 256);
- f->extents = malloc(sizeof(FSXCharInfo)*256);
- fread(f->glyphs, 256, f->height, fp);
- fclose(fp);
-
- f->eindex = malloc(sizeof(FSXCharInfo*) * 256);
- f->gindex = malloc(sizeof(unsigned char*) * 256);
- for (i = 0; i < 256; i++) {
- f->eindex[i] = f->extents +i;
- f->gindex[i] = f->glyphs +i * f->height;
- f->eindex[i]->left = 0;
- f->eindex[i]->right = 7;
- f->eindex[i]->width = 8;
- f->eindex[i]->descent = 0;
- f->eindex[i]->ascent = f->height;
- }
- return f;
-}
-
-
-#ifdef TESTING
-/* ------------------------------------------------------------------ */
-/* for testing */
-
-int debug;
-
-/* list fonts */
-int fs_ls(char *pattern)
-{
- int nnames = 16;
- int available,i;
- char **fonts;
-
- if (NULL == svr) {
- fprintf(stderr,"fs: not connected\n");
- return -1;
- }
-
- fonts = FSListFonts(svr, pattern, nnames, &available);
- while (nnames <= available) {
- nnames *= 2;
- FSFreeFontNames(fonts);
- fonts = FSListFonts(svr, pattern, nnames, &available);
- }
- for (i = 0; i < available; i++) {
- fprintf(stderr,"%s\n",fonts[i]);
- }
- FSFreeFontNames(fonts);
- return 0;
-}
-
-void dump_charset(struct fs_font *f)
-{
- unsigned char *pos;
- int c,x,y;
-
- x = 0, y = 0;
- for (c = 0; c < f->maxenc; c++) {
- if (NULL == f->eindex[c])
- continue;
- pos = fb_mem+fb_mem_offset;
- pos += fb_fix.line_length * (y+f->height-f->eindex[c]->ascent);
- pos += x*bpp;
- fs_render_fb(pos,fb_fix.line_length,f->eindex[c],f->gindex[c]);
- x += f->eindex[c]->right-f->eindex[c]->left+1;
- if (x > fb_var.xres - f->width) {
- x = 0;
- y += f->height+1;
- }
- if (y > fb_var.yres - f->height)
- break;
- }
-}
-
-int main(int argc, char *argv[])
-{
- struct fs_font *f = NULL;
- unsigned char dummy[42];
- int fd;
-
- if (argc < 2) {
- fprintf(stderr,"missing arg\n");
- exit(1);
- }
-
- /* try font server */
- if (-1 != fs_connect(NULL)) {
- fs_ls(argv[1]);
- f = fs_open(argv[1]);
- if (NULL == f)
- fprintf(stderr,"no such font\n");
- }
-
- /* try console font */
- if (NULL == f)
- f = fs_consolefont(NULL);
- if (NULL == f)
- exit(1);
-
-#ifdef TTY
- exit(1);
-#endif
-
- fd = fb_init(NULL, NULL, 0);
- fb_cleanup_fork();
- fb_switch_init();
- fs_init_fb();
-
- if (argc < 3) {
- dump_charset(f);
- } else {
- fs_puts(f,0,0,argv[2]);
- }
- fgets(dummy,42,stdin);
-
- return 0;
-}
-#endif
diff --git a/fs.h b/fs.h
deleted file mode 100644
index 3b5fe59..0000000
--- a/fs.h
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef X_DISPLAY_MISSING
-# include <FSlib.h>
-
-struct fs_font {
- Font font;
- FSXFontInfoHeader fontHeader;
- FSPropInfo propInfo;
- FSPropOffset *propOffsets;
- unsigned char *propData;
-
- FSXCharInfo *extents;
- FSOffset *offsets;
- unsigned char *glyphs;
-
- int maxenc,width,height;
- FSXCharInfo **eindex;
- unsigned char **gindex;
-};
-
-#else
-
-typedef struct _FSXCharInfo {
- short left;
- short right;
- short width;
- short ascent;
- short descent;
- //unsigned short attributes;
-} FSXCharInfo;
-
-typedef struct _FSXFontInfoHeader {
- //int flags;
- //FSRange char_range;
- //unsigned draw_direction;
- //FSChar2b default_char;
- FSXCharInfo min_bounds;
- FSXCharInfo max_bounds;
- short font_ascent;
- short font_descent;
-} FSXFontInfoHeader;
-
-struct fs_font {
- FSXFontInfoHeader fontHeader;
- //unsigned char *propData;
- FSXCharInfo *extents;
- unsigned char *glyphs;
- int maxenc,width,height;
- FSXCharInfo **eindex;
- unsigned char **gindex;
-};
-
-#endif
-
-/* ------------------------------------------------------------------ */
-
-extern unsigned int fs_bpp, fs_black, fs_white;
-void (*fs_setpixel)(void *ptr, unsigned int color);
-
-int fs_init_fb(int white8);
-void fs_render_fb(unsigned char *ptr, int pitch,
- FSXCharInfo *charInfo, unsigned char *data);
-int fs_puts(struct fs_font *f, unsigned int x, unsigned int y,
- unsigned char *str);
-int fs_textwidth(struct fs_font *f, unsigned char *str);
-void fs_render_tty(FSXCharInfo *charInfo, unsigned char *data);
-
-#ifndef X_DISPLAY_MISSING
-int fs_connect(char *servername);
-struct fs_font* fs_open(char *pattern);
-#endif
-struct fs_font* fs_consolefont(char **filename);
-void fs_free(struct fs_font *f);