This is the v2 patch series. There are some reordering, squashing, and minor changes compared to previously proposed patch series.

An all-in-one patch for quilt is also attached, which can be directly applied to the git repo. (Same as the merge request it self)
From c8de527c0c0ff5b8e2a3c10c1d26e5674ffccf50 Mon Sep 17 00:00:00 2001
From: Zhang Boyang <zhangboyang...@gmail.com>
Date: Tue, 24 May 2022 01:27:10 +0800
Subject: [PATCH v2 1/8] Better quit handling

Previous SIGCHLD handler is not async-signal-safe because it calls
exit(), and it also doesn't save-restore errno. Using _exit() will be
async-signal-safe safe but will result in unclean quit. In the end, this
patch will set a flag variable in signal handler, then defer real
cleanup and quitting to main loop.
---
 bterm.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/bterm.c b/bterm.c
index d7b574f..605644f 100644
--- a/bterm.c
+++ b/bterm.c
@@ -64,7 +64,7 @@ static const unsigned char palette[16][3] =
 
 static int child_pid = 0;
 static struct termios ttysave;
-static int quit = 0;
+static volatile int quit = 0, quit_status = 0;
 
 /* Out of memory.  Give up. */
 static void out_of_memory (void)
@@ -144,24 +144,29 @@ void send_hangup(void)
 
 void sigchld(int sig)
 {
+  int errsv = errno;
   int status;
   if (waitpid(child_pid, &status, WNOHANG) > 0) {
     child_pid = 0;
     /* Reset ownership and permissions of ttyfd device? */
     tcsetattr(0, TCSAFLUSH, &ttysave);
     if (WIFEXITED (status))
-      exit(WEXITSTATUS (status));
-    if (WIFSIGNALED (status))
-      exit(128 + WTERMSIG (status));
-    if (WIFSTOPPED (status))
-      exit(128 + WSTOPSIG (status));
-    exit(status);
+      quit_status = WEXITSTATUS (status);
+    else if (WIFSIGNALED (status))
+      quit_status = 128 + WTERMSIG (status);
+    else if (WIFSTOPPED (status))
+      quit_status = 128 + WSTOPSIG (status);
+    else
+      quit_status = status;
+    quit = 1;
   }
   signal(SIGCHLD, sigchld);
+  errno = errsv;
 }
 
 void sigterm(int sig)
 {
+	quit_status = 128 + SIGTERM;
 	quit = 1;
 }
 
@@ -420,5 +425,5 @@ int main(int argc, char *argv[])
     }
   }
 
-  return 0;
+  exit(quit_status);
 }
-- 
2.30.2

From 302952c64952197d694039358df407ec3ffa418a Mon Sep 17 00:00:00 2001
From: Zhang Boyang <zhangboyang...@gmail.com>
Date: Mon, 23 May 2022 14:10:52 +0800
Subject: [PATCH v2 2/8] Better font reload handling

Previous font reload code will leak a mmap on each reload. This patch
adds the ability to munmap old font after reload. However, this also
introduces a bug, if font reload is triggered while drawing in progress,
after signal handler returns, the drawing code will continue to use old
font which has been freed, causing crash. This will be fixed in next
patch.
---
 bogl-bgf.c | 61 +++++++++++++++++++++++++++++++++++++++++++-----------
 bogl-bgf.h |  1 +
 bterm.c    |  6 +-----
 3 files changed, 51 insertions(+), 17 deletions(-)

diff --git a/bogl-bgf.c b/bogl-bgf.c
index 1032028..0383f4f 100644
--- a/bogl-bgf.c
+++ b/bogl-bgf.c
@@ -5,38 +5,55 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <stddef.h>
 
 #include "bogl.h"
 #include "boglP.h"
 #include "bogl-font.h"
+#include "bogl-bgf.h"
+
+struct bogl_bgf {
+  void *f;    /* mmap area */
+  off_t size; /* size of mmap area */
+  struct bogl_font font; /* font descriptor */
+};
+#define bgf_of(font) \
+  ((struct bogl_bgf *)((char *)(font) - offsetof(struct bogl_bgf, font)))
 
 struct bogl_font *bogl_mmap_font(char *file)
 {
-  int fd;
+  struct bogl_bgf *bgf = NULL;
+  struct bogl_font *font = NULL;
+  int fd = -1;
   struct stat buf;
-  void *f;
-  struct bogl_font *font;
+  void *f = (void *)-1;
+
+  bgf = (struct bogl_bgf *)malloc(sizeof(struct bogl_bgf));
+  if (!bgf)
+    goto fail;
+  font = &bgf->font;
 
   fd = open(file, O_RDONLY);
   if (fd == -1)
-    return 0;
+    goto fail;
 
   if (bogl_cloexec(fd) < 0)
-    return 0;
+    goto fail;
 
   if (fstat(fd, &buf))
-    return 0;
+    goto fail;
+  bgf->size = buf.st_size;
+
+  if (buf.st_size < 4)
+    goto fail;
 
   f = mmap(0, buf.st_size, PROT_READ, MAP_SHARED, fd, 0);
   if (f == (void *)-1)
-    return 0;
+    goto fail;
+  bgf->f = f;
 
   if (memcmp("BGF1", f, 4))
-    return 0;
-
-  font = (struct bogl_font *)malloc(sizeof(struct bogl_font));
-  if (!font)
-    return 0;
+    goto fail;
 
   memcpy(font, f + 4, sizeof(*font));
   font->name = ((void *)font->name - (void *)0) + f;
@@ -44,5 +61,25 @@ struct bogl_font *bogl_mmap_font(char *file)
   font->index = ((void *)font->index - (void *)0) + f;
   font->content = ((void *)font->content - (void *)0) + f;
 
+done:
+  if (fd != -1)
+    close(fd);
   return font;
+
+fail:
+  if (bgf) {
+    free(bgf);
+    bgf = NULL;
+    font = NULL;
+  }
+  if (f != (void *)-1)
+    munmap(f, buf.st_size);
+  goto done;
+}
+
+void bogl_munmap_font(struct bogl_font *font)
+{
+  struct bogl_bgf *bgf = bgf_of(font);
+  munmap(bgf->f, bgf->size);
+  free(bgf);
 }
diff --git a/bogl-bgf.h b/bogl-bgf.h
index e9fb994..f14a260 100644
--- a/bogl-bgf.h
+++ b/bogl-bgf.h
@@ -1,2 +1,3 @@
 
 struct bogl_font *bogl_mmap_font(char *file);
+void bogl_munmap_font(struct bogl_font *font);
diff --git a/bterm.c b/bterm.c
index 605644f..28ccb53 100644
--- a/bterm.c
+++ b/bterm.c
@@ -224,11 +224,7 @@ void reload_font(int sig)
       return;
     }
   
-  /* This leaks a mmap.  Since the font reloading feature is only expected
-     to be used once per session (for instance, in debian-installer, after
-     the font is replaced with a larger version containing more characters),
-     we don't worry about the leak.  */
-  free(term->font);
+  bogl_munmap_font(term->font);
 
   term->font = font;
   term->xstep = bogl_font_glyph(term->font, ' ', 0);
-- 
2.30.2

From 4b2e0651edf19cab4b162c686c21e81682c854a0 Mon Sep 17 00:00:00 2001
From: Zhang Boyang <zhangboyang...@gmail.com>
Date: Tue, 24 May 2022 12:58:01 +0800
Subject: [PATCH v2 3/8] Fix incorrect signal handling

There are problems in signal handlers. Signal handlers must not call any
non-async-signal-safe functions, and they must save-restore errno if
errno is modified inside signal handlers. This patch fixes these
problems by deferring real tasks to main loop. This also fixes crashes
caused by font reloading which was mentioned in previous patch.
---
 bogl.c  | 35 +++++++++++------------------------
 bogl.h  |  2 ++
 bterm.c | 26 ++++++++++++++++++++++----
 3 files changed, 35 insertions(+), 28 deletions(-)

diff --git a/bogl.c b/bogl.c
index 6b9996b..f1486f9 100644
--- a/bogl.c
+++ b/bogl.c
@@ -65,6 +65,7 @@
 /* Global variables. */
 int bogl_xres, bogl_yres, bogl_bpp;	/* bogl.h */
 int bogl_refresh;
+volatile int vt_switch_pending = 0;
 volatile char *bogl_frame;		/* boglP.h */
 int bogl_drawing;
 int bogl_line_len;
@@ -120,7 +121,7 @@ static void draw_disable (void);
 static void kbd_init (void);
 static void kbd_done (void);
 
-static void vt_switch (int);
+static void sigusr2 (int);
 
 static struct fb_fix_screeninfo fb_fix;
 /* Initialize BOGL. */
@@ -181,7 +182,7 @@ bogl_init (void)
   mode.relsig = SIGUSR2;
   mode.acqsig = SIGUSR2;
 
-  signal (SIGUSR2, vt_switch);
+  signal (SIGUSR2, sigusr2);
 
   if (-1 == ioctl (tty, VT_SETMODE, &mode))
     return bogl_fail ("can't set VT mode: %s", strerror (errno));
@@ -583,32 +584,18 @@ draw_disable (void)
 /* Signal handler called whenever the kernel wants to switch to or
    from our tty. */
 static void
-vt_switch (int sig unused)
+sigusr2 (int sig unused)
 {
-  signal (SIGUSR2, vt_switch);
+  vt_switch_pending = 1;
+}
+void
+vt_switch (void)
+{
+  vt_switch_pending = 0;
 
-  /* If a BOGL drawing function is in progress then we cannot mode
-     switch right now because the drawing function would continue to
-     scribble on the screen after the switch.  So disable further
-     drawing and schedule an alarm to try again in .1 second. */
   if (bogl_drawing)
     {
-      draw_disable ();
-
-      signal (SIGALRM, vt_switch);
-      
-      {
-	struct itimerval duration;
-	
-	duration.it_interval.tv_sec = 0;
-	duration.it_interval.tv_usec = 0;
-	duration.it_value.tv_sec = 0;
-	duration.it_value.tv_usec = 100000;
-	if (-1 == setitimer (ITIMER_REAL, &duration, NULL))
-	  bogl_fail ("can't set timer: %s", strerror (errno));
-      }
-      
-      return;
+      abort();
     }
       
   if (visible)
diff --git a/bogl.h b/bogl.h
index 3b2cb83..4d99788 100644
--- a/bogl.h
+++ b/bogl.h
@@ -69,6 +69,8 @@ extern int bogl_xres, bogl_yres, bogl_ncols;
 
 /* 1=Must refresh screen due to tty change. */
 extern int bogl_refresh;
+extern volatile int vt_switch_pending;
+extern void vt_switch (void);
 
 /* Generic routines. */
 int bogl_init (void);
diff --git a/bterm.c b/bterm.c
index 28ccb53..b0a1189 100644
--- a/bterm.c
+++ b/bterm.c
@@ -160,7 +160,6 @@ void sigchld(int sig)
       quit_status = status;
     quit = 1;
   }
-  signal(SIGCHLD, sigchld);
   errno = errsv;
 }
 
@@ -212,10 +211,16 @@ void set_window_size(int ttyfd, int x, int y)
 
 static char *font_name;
 static struct bogl_term *term;
+static volatile int reload_font_pending = 0;
 
-void reload_font(int sig)
+void sighup(int sig)
+{
+  reload_font_pending = 1;
+}
+void reload_font(void)
 {
   struct bogl_font *font;
+  reload_font_pending = 0;
 
   font = bogl_mmap_font (font_name);
   if (font == NULL)
@@ -229,6 +234,9 @@ void reload_font(int sig)
   term->font = font;
   term->xstep = bogl_font_glyph(term->font, ' ', 0);
   term->ystep = bogl_font_height(term->font);
+
+  /* Request redraw */
+  bogl_refresh = 2;
 }
 
 /*
@@ -240,6 +248,7 @@ int main(int argc, char *argv[])
 {
   struct termios ntio;
   int ret;
+  int errsv;
   char buf[8192];
   struct timeval tv;
   int ptyfd, ttyfd;
@@ -339,7 +348,7 @@ int main(int argc, char *argv[])
   }
   spawn_shell(ptyfd, ttyfd, command_args);
 
-  signal(SIGHUP, reload_font);
+  signal(SIGHUP, sighup);
   signal(SIGTERM, sigterm);
 
   ntio = ttysave;
@@ -360,6 +369,10 @@ int main(int argc, char *argv[])
 
     if (quit)
 	    break;
+    if (reload_font_pending)
+	    reload_font();
+    if (vt_switch_pending)
+	    vt_switch();
     
     if(pending)
     {
@@ -377,9 +390,14 @@ int main(int argc, char *argv[])
     if (ptyfd > max)
       max = ptyfd;
     ret = select(max+1, &fds, NULL, NULL, &tv);
+    errsv = errno;
 
     if (quit)
 	    break;
+    if (reload_font_pending)
+	    reload_font();
+    if (vt_switch_pending)
+	    vt_switch();
 
     if (bogl_refresh) {
       /* Handle VT switching.  */
@@ -394,7 +412,7 @@ int main(int argc, char *argv[])
       bogl_refresh = 0;
       bogl_term_redraw(term);
     }
-    if (ret == 0 || (ret < 0 && errno == EINTR))
+    if (ret == 0 || (ret < 0 && errsv == EINTR))
     {
       if(pending)
       {
-- 
2.30.2

From e7fe989fbbda4acfd9971604b7ffa84899cb343a Mon Sep 17 00:00:00 2001
From: Zhang Boyang <zhangboyang...@gmail.com>
Date: Mon, 23 May 2022 22:07:37 +0800
Subject: [PATCH v2 4/8] Use ioctl(FBIOPAN_DISPLAY) to update screen after
 drawing

Some framebuffer driver like i915 need explicit notify after drawing,
otherwise modifications in graphics buffer will not be reflected on
screen, so use FBIOPAN_DISPLAY to do this notify.
---
 bogl-term.c |  1 +
 bogl.c      | 19 ++++++++++++++++++-
 bogl.h      |  1 +
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/bogl-term.c b/bogl-term.c
index d5780d3..1f68523 100644
--- a/bogl-term.c
+++ b/bogl-term.c
@@ -863,4 +863,5 @@ bogl_term_redraw (struct bogl_term *term)
     {
         show_cursor(term, 1);
     }        
+    bogl_update();
 }
diff --git a/bogl.c b/bogl.c
index f1486f9..5cbe96e 100644
--- a/bogl.c
+++ b/bogl.c
@@ -124,12 +124,12 @@ static void kbd_done (void);
 static void sigusr2 (int);
 
 static struct fb_fix_screeninfo fb_fix;
+static struct fb_var_screeninfo fb_var;
 /* Initialize BOGL. */
 int
 bogl_init (void)
 {
   unsigned long bogl_frame_offset, bogl_frame_len;
-  struct fb_var_screeninfo fb_var;
   struct vt_stat vts;
   int PAGE_MASK = ~(sysconf(_SC_PAGESIZE) - 1);
 
@@ -457,6 +457,23 @@ bogl_fb_set_palette (int c, int nc, const unsigned char palette[][3])
   ioctl (fb, FBIOPUTCMAP, &cmap);
 }
 
+/* Update screen, some framebuffer driver require this explicit notify after
+   modifying screen contents */
+void
+bogl_update (void)
+{
+#if BOGL_VGA16_FB
+  if (type == FB_TYPE_VGA_PLANES)
+    {
+      /* There is no need to call FBIOPAN_DISPLAY when using vga16fb driver.
+         What's worse, it may cause screen flicker on certain hardwares.
+	 So make bogl_update() a no-op here. */
+      return;
+    }
+#endif
+  ioctl (fb, FBIOPAN_DISPLAY, &fb_var);
+}
+
 /* Returns the oldest error message since this function was last
    called.  Clears the error state.  Returns a null pointer if no
    errors have occurred.  The caller must free the returned
diff --git a/bogl.h b/bogl.h
index 4d99788..61b0275 100644
--- a/bogl.h
+++ b/bogl.h
@@ -79,6 +79,7 @@ const char *bogl_error (void);
 
 void bogl_gray_scale (int make_gray);
 void bogl_fb_set_palette (int c, int nc, const unsigned char palette[][3]);
+void bogl_update(void);
 void bogl_rectangle (int x1, int y1, int x2, int y2, int c);
 int bogl_metrics (const char *s, int n, const struct bogl_font *font);
 
-- 
2.30.2

From 04d88a6ff7114750c67cdb58e07122bb430763a9 Mon Sep 17 00:00:00 2001
From: Zhang Boyang <zhangboyang...@gmail.com>
Date: Tue, 24 May 2022 23:49:31 +0800
Subject: [PATCH v2 5/8] Font scaler

Current fonts is too small to see on HiDPI displays. This patch
introduces a BGF font scaler, which can scale font glyphs on the fly
when loading. The scale factor can be automatically determined by screen
resolution or specified by a new command line argument '-s'. This patch
also add support for BGF fonts wider than 32 pixels.
---
 bogl-bgf.c   | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 bogl-bgf.h   |   2 +-
 bogl-pcfb.c  |   8 ++--
 bogl-tcfb.c  |   8 ++--
 bogl-vga16.c |  33 +++++++++------
 bterm.1      |   4 ++
 bterm.c      |  30 ++++++++++----
 7 files changed, 167 insertions(+), 29 deletions(-)

diff --git a/bogl-bgf.c b/bogl-bgf.c
index 0383f4f..1a8b9d9 100644
--- a/bogl-bgf.c
+++ b/bogl-bgf.c
@@ -20,7 +20,113 @@ struct bogl_bgf {
 #define bgf_of(font) \
   ((struct bogl_bgf *)((char *)(font) - offsetof(struct bogl_bgf, font)))
 
-struct bogl_font *bogl_mmap_font(char *file)
+/* Scale the font (both width and height)
+   Declare as inline function, will run faster if scale factor is constant */
+static inline void __attribute__((always_inline))
+bgf_scale_inline(struct bogl_bgf *bgf, int scale)
+{
+  void *new_f = (void *)-1;
+  off_t new_size;
+  struct bogl_font new_font;
+
+  /* old_size*pow(scale,2) should enough and have some waste here */
+  new_size = bgf->size * scale * scale;
+
+  /* Allocate new memory */
+  new_f = mmap(0, new_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (new_f == (void *)-1) {
+    /* If memory allocation failed, skip scaling silently */
+    goto fail;
+  }
+
+  /* Copy old font data to new memory */
+  memcpy(new_f, bgf->f, bgf->size);
+
+  /* Set font metadata */
+  struct bogl_font *font = &new_font;
+  memcpy(font, new_f + 4, sizeof(*font));
+  font->name = ((void *)font->name - (void *)0) + new_f;
+  font->offset = ((void *)font->offset - (void *)0) + new_f;
+  font->index = ((void *)font->index - (void *)0) + new_f;
+  font->content = ((void *)font->content - (void *)0) + new_f;
+  font->height = bgf->font.height * scale;
+
+  /* Scale each glyph */
+  int mask = font->index_mask;
+  for (int j = 0; j <= mask; j++) {
+    for (int i = font->offset[j]; font->index[i]; i += 2) {
+      int old_height = bgf->font.height;
+      int old_width = (font->index[i] & mask);
+      if (old_width * scale > mask) {
+        /* Scaled glyph width can't fit in mask, fail */
+        goto fail;
+      }
+      font->index[i] = (font->index[i] & ~mask) | (old_width * scale);
+      font->index[i + 1] *= scale * scale;
+      u_int32_t *in_bitmap = &bgf->font.content[bgf->font.index[i + 1]];
+      int in_pitch = (old_width + 31) / 32;
+      u_int32_t *out_bitmap = &font->content[font->index[i + 1]];
+      int out_pitch = (old_width * scale + 31) / 32;
+      for (int y = 0; y < old_height * scale; y++) {
+        const int outlined = 0; /* Useful for debugging */
+        if (y % scale == 0 || outlined) {
+          u_int32_t *in_ptr = in_bitmap + in_pitch * (y / scale);
+          u_int32_t *out_ptr = out_bitmap + out_pitch * y;
+          memset(out_ptr, 0, sizeof(u_int32_t) * out_pitch);
+          for (int x = 0; x < old_width * scale; x++) {
+            int in_off = (x / scale) / 32, in_bit = 31 - (x / scale) % 32;
+            int out_off = x / 32, out_bit = 31 - x % 32;
+            u_int32_t pixel = (in_ptr[in_off] >> in_bit) & 1;
+            if (outlined)
+              if (0 < x % scale && x % scale < scale - 1)
+                if (0 < y % scale && y % scale < scale - 1)
+                  pixel = 0;
+            out_ptr[out_off] |= pixel << out_bit;
+          }
+        } else {
+          u_int32_t *last_line = out_bitmap + out_pitch * (y - 1);
+          u_int32_t *curr_line = out_bitmap + out_pitch * y;
+          memcpy(curr_line, last_line, sizeof(u_int32_t) * out_pitch);
+        }
+      }
+    }
+  }
+
+  /* Replace old font with new font */
+  munmap(bgf->f, bgf->size);
+  bgf->f = new_f;
+  bgf->size = new_size;
+  bgf->font = new_font;
+  return;
+fail:
+  if (new_f != (void *)-1)
+    munmap(new_f, new_size);
+}
+static void __attribute__((noinline))
+bgf_scale_noinline(struct bogl_bgf *bgf, int scale)
+{
+  bgf_scale_inline(bgf, scale);
+}
+static void __attribute__((noinline)) bgf_scale_2x(struct bogl_bgf *bgf)
+{
+  bgf_scale_inline(bgf, 2);
+}
+static void __attribute__((noinline)) bgf_scale_4x(struct bogl_bgf *bgf)
+{
+  bgf_scale_inline(bgf, 4);
+}
+static void bgf_scale(struct bogl_bgf *bgf, int scale)
+{
+  switch (scale) {
+    /* Use fast implementation if possible */
+    case 2: bgf_scale_2x(bgf); return;
+    case 4: bgf_scale_4x(bgf); return;
+    /* Universal implementation as fallback */
+    default: bgf_scale_noinline(bgf, scale); return;
+  }
+}
+
+struct bogl_font *bogl_mmap_font(char *file, int scale)
 {
   struct bogl_bgf *bgf = NULL;
   struct bogl_font *font = NULL;
@@ -61,6 +167,9 @@ struct bogl_font *bogl_mmap_font(char *file)
   font->index = ((void *)font->index - (void *)0) + f;
   font->content = ((void *)font->content - (void *)0) + f;
 
+  if (scale >= 2)
+    bgf_scale(bgf, scale);
+
 done:
   if (fd != -1)
     close(fd);
diff --git a/bogl-bgf.h b/bogl-bgf.h
index f14a260..978da61 100644
--- a/bogl-bgf.h
+++ b/bogl-bgf.h
@@ -1,3 +1,3 @@
 
-struct bogl_font *bogl_mmap_font(char *file);
+struct bogl_font *bogl_mmap_font(char *file, int scale);
 void bogl_munmap_font(struct bogl_font *font);
diff --git a/bogl-pcfb.c b/bogl-pcfb.c
index c737d38..b16c804 100644
--- a/bogl-pcfb.c
+++ b/bogl-pcfb.c
@@ -142,6 +142,7 @@ bogl_pcfb_text (int xx, int yy, const char *s, int n, int fg, int bg, int ul,
 
       u_int32_t *character = NULL;
       int w = bogl_font_glyph (font, wc, &character);
+      int pitch = (w + 31) / 32;
 
       int x, y, h1 = ul ? h - 1 : h;
 
@@ -153,16 +154,15 @@ bogl_pcfb_text (int xx, int yy, const char *s, int n, int fg, int bg, int ul,
       
       for (y = 0; y < h1; y++)
 	{
-	  u_int32_t c = *character++;
+	  u_int32_t *c = character;
+	  character += pitch;
 	  
 	  for (x = 0; x < w; x++)
 	    {
-	      if (c & 0x80000000)
+	      if ((c[x / 32] & (1 << (31 - x % 32))))
 		put_var (dst, xx+x, cmap_lookup(fg), bpp);
 	      else if (bg != -1)
 		put_var (dst, xx+x, cmap_lookup(bg), bpp);
-
-	      c <<= 1;
 	    }
 
 	  dst += bogl_line_len;
diff --git a/bogl-tcfb.c b/bogl-tcfb.c
index 895d298..cd23b77 100644
--- a/bogl-tcfb.c
+++ b/bogl-tcfb.c
@@ -169,6 +169,7 @@ bogl_tcfb_text (int xx, int yy, const char *s, int n, int fg, int bg, int ul,
 
       u_int32_t *character = NULL;
       int w = bogl_font_glyph (font, wc, &character);
+      int pitch = (w + 31) / 32;
 
       int x, y, h1 = ul ? h - 1 : h;
       unsigned cfg = cmap_lookup (fg), cbg = cmap_lookup (bg);
@@ -181,16 +182,15 @@ bogl_tcfb_text (int xx, int yy, const char *s, int n, int fg, int bg, int ul,
       
       for (y = 0; y < h1; y++)
 	{
-	  u_int32_t c = *character++;
+	  u_int32_t *c = character;
+	  character += pitch;
 	  
 	  for (x = 0; x < w; x++)
 	    {
-	      if (c & 0x80000000)
+	      if ((c[x / 32] & (1 << (31 - x % 32))))
 		put_var (dst, xx+x, cfg, bpp);
 	      else if (bg != -1)
 		put_var (dst, xx+x, cbg, bpp);
-
-	      c <<= 1;
 	    }
 
 	  dst += bogl_line_len;
diff --git a/bogl-vga16.c b/bogl-vga16.c
index bb81803..6c2cbcf 100644
--- a/bogl-vga16.c
+++ b/bogl-vga16.c
@@ -394,25 +394,34 @@ bogl_vga16_text (int xx, int yy, const char *s, int n, int fg, int bg, int ul,
     {
       u_int32_t *character = NULL;
       int width = bogl_font_glyph (font, wc, &character);
+      int pitch = (width + ul_bits - 1) / ul_bits;
 
       if (character == NULL)
 	continue;
 
-      for (y = 0; y < h; y++)
-	bits[y] |= character[y] >> x;
-      x += width;
-
-      if (x >= (int) ul_bits)
-	{
-	  plot (bg);
+      int i, w;
+      for (i = 0; i < pitch; i++)
+        {
+	  w = width - i * ul_bits;
+	  if (w > ul_bits)
+	    w = ul_bits;
 
-	  x -= ul_bits;
 	  for (y = 0; y < h; y++)
-	    bits[y] = character[y] << (width - x);
+	    bits[y] |= character[y * pitch + i] >> x;
+	  x += w;
 
-	  xx += ul_bits;
-	  if (xx >= bogl_xres)
-	    goto done;
+	  if (x >= (int) ul_bits)
+	    {
+	      plot (bg);
+
+	      x -= ul_bits;
+	      for (y = 0; y < h; y++)
+		bits[y] = character[y * pitch + i] << (w - x - 1) << 1;
+
+	      xx += ul_bits;
+	      if (xx >= bogl_xres)
+		goto done;
+	    }
 	}
     }
   plot (bg);
diff --git a/bterm.1 b/bterm.1
index 8b96b99..e62d3ee 100644
--- a/bterm.1
+++ b/bterm.1
@@ -21,6 +21,7 @@ bterm - framebuffer terminal emulator
 .B bterm
 .B -f
 .RI font.bgf
+.RI "[-s " scale "]"
 .RI "[-l " locale "]"
 .RI "[" program "]"
 .SH DESCRIPTION
@@ -36,6 +37,9 @@ Specify the font.  BGF fonts are produced by
 .BR bdftobogl (1)
 from standard BDF font files.
 .TP
+.B -s scale
+Specify the font scale factor, 0 for auto.
+.TP
 .B -l locale
 Specify a locale for
 .B bterm
diff --git a/bterm.c b/bterm.c
index b0a1189..610d588 100644
--- a/bterm.c
+++ b/bterm.c
@@ -210,6 +210,7 @@ void set_window_size(int ttyfd, int x, int y)
 }
 
 static char *font_name;
+static int font_scale;
 static struct bogl_term *term;
 static volatile int reload_font_pending = 0;
 
@@ -222,7 +223,7 @@ void reload_font(void)
   struct bogl_font *font;
   reload_font_pending = 0;
 
-  font = bogl_mmap_font (font_name);
+  font = bogl_mmap_font (font_name, font_scale);
   if (font == NULL)
     {
       fprintf(stderr, "Bad font\n");
@@ -265,6 +266,7 @@ int main(int argc, char *argv[])
           switch (argv[i][1])
           {
               case 'f':
+              case 's':
               case 'l':
                   o = argv[i][1];
                   break;
@@ -288,6 +290,11 @@ int main(int argc, char *argv[])
                     o = ' ';
                     break;
 
+                case 's':
+                    font_scale = atoi(argv[i]);
+                    o = ' ';
+                    break;
+
                 case 'l':
                     locale = argv[i];
                     o = ' ';
@@ -301,16 +308,11 @@ int main(int argc, char *argv[])
   setlocale(LC_CTYPE, locale);
 
   if (font_name == NULL) {
-    fprintf(stderr, "Usage: %s -f font.bgf [ -l locale ] [ program ]\n", argv[0]);
+    fprintf(stderr, "Usage: %s -f font.bgf [ -s scale ] [ -l locale ] [ program ]\n", argv[0]);
  
     return 1;
   }
 
-  if ((font = bogl_mmap_font(font_name)) == NULL) {
-    fprintf(stderr, "Bad font\n");
-    return 1;
-  }
-
   tcgetattr(0, &ttysave);
 
   if (!bogl_init()) {
@@ -318,6 +320,20 @@ int main(int argc, char *argv[])
     return 1;
   }
 
+  if (font_scale == 0) {
+    if (bogl_xres > 3840 && bogl_yres > 2160)
+      font_scale = 4;
+    else if (bogl_xres > 1920 && bogl_yres > 1080)
+      font_scale = 2;
+    else
+      font_scale = 1;
+  }
+
+  if ((font = bogl_mmap_font(font_name, font_scale)) == NULL) {
+    fprintf(stderr, "Bad font\n");
+    return 1;
+  }
+
   term = bogl_term_new(font);
   if (!term)
     exit(1);
-- 
2.30.2

From effb30989015cf760aa152de79ff51212caec91a Mon Sep 17 00:00:00 2001
From: Zhang Boyang <zhangboyang...@gmail.com>
Date: Wed, 25 May 2022 13:45:14 +0800
Subject: [PATCH v2 6/8] Fix character occasionally disappears from right edge
 of screen

Sometimes when a line is full, the right most character disappears. The
is because term->xpos may equals to term->xsize and this condition
confuses some code. Reported by AddressSanitizer.
---
 bogl-term.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bogl-term.c b/bogl-term.c
index 1f68523..2d35d1d 100644
--- a/bogl-term.c
+++ b/bogl-term.c
@@ -283,7 +283,7 @@ static void
 clear_left (struct bogl_term *term)
 {
     int j, i = SCR(term->xpos, term->ypos);
-    if (!term->screen[i])
+    if (term->xpos < term->xsize && !term->screen[i])
     {
         for (j = i - 1; !term->screen[j]; j--)
         {
@@ -577,7 +577,7 @@ bogl_term_out (struct bogl_term *term, char *s, int n)
 
             if (wc == 'K')
             {                   /* el=\E[K */
-                if (term->state == 1 && !term->arg[0])
+                if (term->state == 1 && !term->arg[0] && term->xpos < term->xsize)
                 {
                     clear_left (term);
                     for (i = SCR (term->xpos, term->ypos); i < SCR (term->xsize, term->ypos); i++)
-- 
2.30.2

From 61b6c2b21e31268037b4dd1ead7f6088b8a583a4 Mon Sep 17 00:00:00 2001
From: Zhang Boyang <zhangboyang...@gmail.com>
Date: Wed, 25 May 2022 14:42:50 +0800
Subject: [PATCH v2 7/8] Fix out-of-bound read in tcfb's cmap_lookup()

When bogl_tcfb_text() is called with bg = -1, it will call
cmap_lookup(-1), resulting in out-of-bound read, although the return
value is not used. Reported by AddressSanitizer.
---
 bogl-tcfb.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bogl-tcfb.c b/bogl-tcfb.c
index cd23b77..5e14892 100644
--- a/bogl-tcfb.c
+++ b/bogl-tcfb.c
@@ -48,7 +48,7 @@ static struct fb_var_screeninfo var;
 static inline unsigned int
 cmap_lookup (int entry)
 {
-  if (entry >= cmap_size)
+  if (entry < 0 || entry >= cmap_size)
     return 0;
   
   return cmap[entry];
-- 
2.30.2

From 9d64dee5d6aa80d7836815541a59581f8c1e898c Mon Sep 17 00:00:00 2001
From: Zhang Boyang <zhangboyang...@gmail.com>
Date: Sat, 28 May 2022 16:39:23 +0800
Subject: [PATCH v2 8/8] Fix rightmost pixel of each line not cleared by
 bogl_vga16_text()

The bogl_vga16_clear() function use [x1, x2) as clear range, so there is
no need to minus x2 by 1.
---
 bogl-vga16.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bogl-vga16.c b/bogl-vga16.c
index 6c2cbcf..3fcbe51 100644
--- a/bogl-vga16.c
+++ b/bogl-vga16.c
@@ -373,7 +373,7 @@ bogl_vga16_text (int xx, int yy, const char *s, int n, int fg, int bg, int ul,
     {
       int x2 = xx + bogl_metrics (s, n, font);
       if (x2 >= bogl_xres)
-	x2 = bogl_xres - 1;
+	x2 = bogl_xres;
       
       bogl_vga16_clear (xx, yy, x2, yy + h, bg);
     }
-- 
2.30.2

From 7c2a57c741e656e3327b4bc4a8471481d1a48d8a Mon Sep 17 00:00:00 2001
From: Zhang Boyang <zhangboyang...@gmail.com>
Date: Sun, 29 May 2022 13:20:42 +0800
Subject: [PATCH v2] Several improvements for bogl-bterm

Please refer to commit message in each patch for details.

This is the v2 patch series. There are some reordering, squashing, and
minor changes compared to previously proposed patch series.
---
 debian/patches/better-font-reload-handling    | 143 +++++++
 debian/patches/better-quit-handling           |  73 ++++
 ...nally-disappears-from-right-edge-of-screen |  38 ++
 debian/patches/fix-incorrect-signal-handling  | 195 +++++++++
 ...ix-out-of-bound-read-in-tcfb-s-cmap_lookup |  28 ++
 ...f-each-line-not-cleared-by-bogl_vga16_text |  28 ++
 debian/patches/font-scaler                    | 378 ++++++++++++++++++
 debian/patches/series                         |   8 +
 ...pan_display-to-update-screen-after-drawing |  82 ++++
 9 files changed, 973 insertions(+)
 create mode 100644 debian/patches/better-font-reload-handling
 create mode 100644 debian/patches/better-quit-handling
 create mode 100644 debian/patches/fix-character-occasionally-disappears-from-right-edge-of-screen
 create mode 100644 debian/patches/fix-incorrect-signal-handling
 create mode 100644 debian/patches/fix-out-of-bound-read-in-tcfb-s-cmap_lookup
 create mode 100644 debian/patches/fix-rightmost-pixel-of-each-line-not-cleared-by-bogl_vga16_text
 create mode 100644 debian/patches/font-scaler
 create mode 100644 debian/patches/use-ioctl-fbiopan_display-to-update-screen-after-drawing

diff --git a/debian/patches/better-font-reload-handling b/debian/patches/better-font-reload-handling
new file mode 100644
index 0000000..a1598aa
--- /dev/null
+++ b/debian/patches/better-font-reload-handling
@@ -0,0 +1,143 @@
+From 302952c64952197d694039358df407ec3ffa418a Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang...@gmail.com>
+Date: Mon, 23 May 2022 14:10:52 +0800
+Subject: [PATCH v2 2/8] Better font reload handling
+
+Previous font reload code will leak a mmap on each reload. This patch
+adds the ability to munmap old font after reload. However, this also
+introduces a bug, if font reload is triggered while drawing in progress,
+after signal handler returns, the drawing code will continue to use old
+font which has been freed, causing crash. This will be fixed in next
+patch.
+---
+ bogl-bgf.c | 61 +++++++++++++++++++++++++++++++++++++++++++-----------
+ bogl-bgf.h |  1 +
+ bterm.c    |  6 +-----
+ 3 files changed, 51 insertions(+), 17 deletions(-)
+
+diff --git a/bogl-bgf.c b/bogl-bgf.c
+index 1032028..0383f4f 100644
+--- a/bogl-bgf.c
++++ b/bogl-bgf.c
+@@ -5,38 +5,55 @@
+ #include <sys/stat.h>
+ #include <sys/types.h>
+ #include <unistd.h>
++#include <stddef.h>
+ 
+ #include "bogl.h"
+ #include "boglP.h"
+ #include "bogl-font.h"
++#include "bogl-bgf.h"
++
++struct bogl_bgf {
++  void *f;    /* mmap area */
++  off_t size; /* size of mmap area */
++  struct bogl_font font; /* font descriptor */
++};
++#define bgf_of(font) \
++  ((struct bogl_bgf *)((char *)(font) - offsetof(struct bogl_bgf, font)))
+ 
+ struct bogl_font *bogl_mmap_font(char *file)
+ {
+-  int fd;
++  struct bogl_bgf *bgf = NULL;
++  struct bogl_font *font = NULL;
++  int fd = -1;
+   struct stat buf;
+-  void *f;
+-  struct bogl_font *font;
++  void *f = (void *)-1;
++
++  bgf = (struct bogl_bgf *)malloc(sizeof(struct bogl_bgf));
++  if (!bgf)
++    goto fail;
++  font = &bgf->font;
+ 
+   fd = open(file, O_RDONLY);
+   if (fd == -1)
+-    return 0;
++    goto fail;
+ 
+   if (bogl_cloexec(fd) < 0)
+-    return 0;
++    goto fail;
+ 
+   if (fstat(fd, &buf))
+-    return 0;
++    goto fail;
++  bgf->size = buf.st_size;
++
++  if (buf.st_size < 4)
++    goto fail;
+ 
+   f = mmap(0, buf.st_size, PROT_READ, MAP_SHARED, fd, 0);
+   if (f == (void *)-1)
+-    return 0;
++    goto fail;
++  bgf->f = f;
+ 
+   if (memcmp("BGF1", f, 4))
+-    return 0;
+-
+-  font = (struct bogl_font *)malloc(sizeof(struct bogl_font));
+-  if (!font)
+-    return 0;
++    goto fail;
+ 
+   memcpy(font, f + 4, sizeof(*font));
+   font->name = ((void *)font->name - (void *)0) + f;
+@@ -44,5 +61,25 @@ struct bogl_font *bogl_mmap_font(char *file)
+   font->index = ((void *)font->index - (void *)0) + f;
+   font->content = ((void *)font->content - (void *)0) + f;
+ 
++done:
++  if (fd != -1)
++    close(fd);
+   return font;
++
++fail:
++  if (bgf) {
++    free(bgf);
++    bgf = NULL;
++    font = NULL;
++  }
++  if (f != (void *)-1)
++    munmap(f, buf.st_size);
++  goto done;
++}
++
++void bogl_munmap_font(struct bogl_font *font)
++{
++  struct bogl_bgf *bgf = bgf_of(font);
++  munmap(bgf->f, bgf->size);
++  free(bgf);
+ }
+diff --git a/bogl-bgf.h b/bogl-bgf.h
+index e9fb994..f14a260 100644
+--- a/bogl-bgf.h
++++ b/bogl-bgf.h
+@@ -1,2 +1,3 @@
+ 
+ struct bogl_font *bogl_mmap_font(char *file);
++void bogl_munmap_font(struct bogl_font *font);
+diff --git a/bterm.c b/bterm.c
+index 605644f..28ccb53 100644
+--- a/bterm.c
++++ b/bterm.c
+@@ -224,11 +224,7 @@ void reload_font(int sig)
+       return;
+     }
+   
+-  /* This leaks a mmap.  Since the font reloading feature is only expected
+-     to be used once per session (for instance, in debian-installer, after
+-     the font is replaced with a larger version containing more characters),
+-     we don't worry about the leak.  */
+-  free(term->font);
++  bogl_munmap_font(term->font);
+ 
+   term->font = font;
+   term->xstep = bogl_font_glyph(term->font, ' ', 0);
+-- 
+2.30.2
+
diff --git a/debian/patches/better-quit-handling b/debian/patches/better-quit-handling
new file mode 100644
index 0000000..fce02ee
--- /dev/null
+++ b/debian/patches/better-quit-handling
@@ -0,0 +1,73 @@
+From c8de527c0c0ff5b8e2a3c10c1d26e5674ffccf50 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang...@gmail.com>
+Date: Tue, 24 May 2022 01:27:10 +0800
+Subject: [PATCH v2 1/8] Better quit handling
+
+Previous SIGCHLD handler is not async-signal-safe because it calls
+exit(), and it also doesn't save-restore errno. Using _exit() will be
+async-signal-safe safe but will result in unclean quit. In the end, this
+patch will set a flag variable in signal handler, then defer real
+cleanup and quitting to main loop.
+---
+ bterm.c | 21 +++++++++++++--------
+ 1 file changed, 13 insertions(+), 8 deletions(-)
+
+diff --git a/bterm.c b/bterm.c
+index d7b574f..605644f 100644
+--- a/bterm.c
++++ b/bterm.c
+@@ -64,7 +64,7 @@ static const unsigned char palette[16][3] =
+ 
+ static int child_pid = 0;
+ static struct termios ttysave;
+-static int quit = 0;
++static volatile int quit = 0, quit_status = 0;
+ 
+ /* Out of memory.  Give up. */
+ static void out_of_memory (void)
+@@ -144,24 +144,29 @@ void send_hangup(void)
+ 
+ void sigchld(int sig)
+ {
++  int errsv = errno;
+   int status;
+   if (waitpid(child_pid, &status, WNOHANG) > 0) {
+     child_pid = 0;
+     /* Reset ownership and permissions of ttyfd device? */
+     tcsetattr(0, TCSAFLUSH, &ttysave);
+     if (WIFEXITED (status))
+-      exit(WEXITSTATUS (status));
+-    if (WIFSIGNALED (status))
+-      exit(128 + WTERMSIG (status));
+-    if (WIFSTOPPED (status))
+-      exit(128 + WSTOPSIG (status));
+-    exit(status);
++      quit_status = WEXITSTATUS (status);
++    else if (WIFSIGNALED (status))
++      quit_status = 128 + WTERMSIG (status);
++    else if (WIFSTOPPED (status))
++      quit_status = 128 + WSTOPSIG (status);
++    else
++      quit_status = status;
++    quit = 1;
+   }
+   signal(SIGCHLD, sigchld);
++  errno = errsv;
+ }
+ 
+ void sigterm(int sig)
+ {
++	quit_status = 128 + SIGTERM;
+ 	quit = 1;
+ }
+ 
+@@ -420,5 +425,5 @@ int main(int argc, char *argv[])
+     }
+   }
+ 
+-  return 0;
++  exit(quit_status);
+ }
+-- 
+2.30.2
+
diff --git a/debian/patches/fix-character-occasionally-disappears-from-right-edge-of-screen b/debian/patches/fix-character-occasionally-disappears-from-right-edge-of-screen
new file mode 100644
index 0000000..64f55c5
--- /dev/null
+++ b/debian/patches/fix-character-occasionally-disappears-from-right-edge-of-screen
@@ -0,0 +1,38 @@
+From effb30989015cf760aa152de79ff51212caec91a Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang...@gmail.com>
+Date: Wed, 25 May 2022 13:45:14 +0800
+Subject: [PATCH v2 6/8] Fix character occasionally disappears from right edge
+ of screen
+
+Sometimes when a line is full, the right most character disappears. The
+is because term->xpos may equals to term->xsize and this condition
+confuses some code. Reported by AddressSanitizer.
+---
+ bogl-term.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/bogl-term.c b/bogl-term.c
+index 1f68523..2d35d1d 100644
+--- a/bogl-term.c
++++ b/bogl-term.c
+@@ -283,7 +283,7 @@ static void
+ clear_left (struct bogl_term *term)
+ {
+     int j, i = SCR(term->xpos, term->ypos);
+-    if (!term->screen[i])
++    if (term->xpos < term->xsize && !term->screen[i])
+     {
+         for (j = i - 1; !term->screen[j]; j--)
+         {
+@@ -577,7 +577,7 @@ bogl_term_out (struct bogl_term *term, char *s, int n)
+ 
+             if (wc == 'K')
+             {                   /* el=\E[K */
+-                if (term->state == 1 && !term->arg[0])
++                if (term->state == 1 && !term->arg[0] && term->xpos < term->xsize)
+                 {
+                     clear_left (term);
+                     for (i = SCR (term->xpos, term->ypos); i < SCR (term->xsize, term->ypos); i++)
+-- 
+2.30.2
+
diff --git a/debian/patches/fix-incorrect-signal-handling b/debian/patches/fix-incorrect-signal-handling
new file mode 100644
index 0000000..51abddc
--- /dev/null
+++ b/debian/patches/fix-incorrect-signal-handling
@@ -0,0 +1,195 @@
+From 4b2e0651edf19cab4b162c686c21e81682c854a0 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang...@gmail.com>
+Date: Tue, 24 May 2022 12:58:01 +0800
+Subject: [PATCH v2 3/8] Fix incorrect signal handling
+
+There are problems in signal handlers. Signal handlers must not call any
+non-async-signal-safe functions, and they must save-restore errno if
+errno is modified inside signal handlers. This patch fixes these
+problems by deferring real tasks to main loop. This also fixes crashes
+caused by font reloading which was mentioned in previous patch.
+---
+ bogl.c  | 35 +++++++++++------------------------
+ bogl.h  |  2 ++
+ bterm.c | 26 ++++++++++++++++++++++----
+ 3 files changed, 35 insertions(+), 28 deletions(-)
+
+diff --git a/bogl.c b/bogl.c
+index 6b9996b..f1486f9 100644
+--- a/bogl.c
++++ b/bogl.c
+@@ -65,6 +65,7 @@
+ /* Global variables. */
+ int bogl_xres, bogl_yres, bogl_bpp;	/* bogl.h */
+ int bogl_refresh;
++volatile int vt_switch_pending = 0;
+ volatile char *bogl_frame;		/* boglP.h */
+ int bogl_drawing;
+ int bogl_line_len;
+@@ -120,7 +121,7 @@ static void draw_disable (void);
+ static void kbd_init (void);
+ static void kbd_done (void);
+ 
+-static void vt_switch (int);
++static void sigusr2 (int);
+ 
+ static struct fb_fix_screeninfo fb_fix;
+ /* Initialize BOGL. */
+@@ -181,7 +182,7 @@ bogl_init (void)
+   mode.relsig = SIGUSR2;
+   mode.acqsig = SIGUSR2;
+ 
+-  signal (SIGUSR2, vt_switch);
++  signal (SIGUSR2, sigusr2);
+ 
+   if (-1 == ioctl (tty, VT_SETMODE, &mode))
+     return bogl_fail ("can't set VT mode: %s", strerror (errno));
+@@ -583,32 +584,18 @@ draw_disable (void)
+ /* Signal handler called whenever the kernel wants to switch to or
+    from our tty. */
+ static void
+-vt_switch (int sig unused)
++sigusr2 (int sig unused)
+ {
+-  signal (SIGUSR2, vt_switch);
++  vt_switch_pending = 1;
++}
++void
++vt_switch (void)
++{
++  vt_switch_pending = 0;
+ 
+-  /* If a BOGL drawing function is in progress then we cannot mode
+-     switch right now because the drawing function would continue to
+-     scribble on the screen after the switch.  So disable further
+-     drawing and schedule an alarm to try again in .1 second. */
+   if (bogl_drawing)
+     {
+-      draw_disable ();
+-
+-      signal (SIGALRM, vt_switch);
+-      
+-      {
+-	struct itimerval duration;
+-	
+-	duration.it_interval.tv_sec = 0;
+-	duration.it_interval.tv_usec = 0;
+-	duration.it_value.tv_sec = 0;
+-	duration.it_value.tv_usec = 100000;
+-	if (-1 == setitimer (ITIMER_REAL, &duration, NULL))
+-	  bogl_fail ("can't set timer: %s", strerror (errno));
+-      }
+-      
+-      return;
++      abort();
+     }
+       
+   if (visible)
+diff --git a/bogl.h b/bogl.h
+index 3b2cb83..4d99788 100644
+--- a/bogl.h
++++ b/bogl.h
+@@ -69,6 +69,8 @@ extern int bogl_xres, bogl_yres, bogl_ncols;
+ 
+ /* 1=Must refresh screen due to tty change. */
+ extern int bogl_refresh;
++extern volatile int vt_switch_pending;
++extern void vt_switch (void);
+ 
+ /* Generic routines. */
+ int bogl_init (void);
+diff --git a/bterm.c b/bterm.c
+index 28ccb53..b0a1189 100644
+--- a/bterm.c
++++ b/bterm.c
+@@ -160,7 +160,6 @@ void sigchld(int sig)
+       quit_status = status;
+     quit = 1;
+   }
+-  signal(SIGCHLD, sigchld);
+   errno = errsv;
+ }
+ 
+@@ -212,10 +211,16 @@ void set_window_size(int ttyfd, int x, int y)
+ 
+ static char *font_name;
+ static struct bogl_term *term;
++static volatile int reload_font_pending = 0;
+ 
+-void reload_font(int sig)
++void sighup(int sig)
++{
++  reload_font_pending = 1;
++}
++void reload_font(void)
+ {
+   struct bogl_font *font;
++  reload_font_pending = 0;
+ 
+   font = bogl_mmap_font (font_name);
+   if (font == NULL)
+@@ -229,6 +234,9 @@ void reload_font(int sig)
+   term->font = font;
+   term->xstep = bogl_font_glyph(term->font, ' ', 0);
+   term->ystep = bogl_font_height(term->font);
++
++  /* Request redraw */
++  bogl_refresh = 2;
+ }
+ 
+ /*
+@@ -240,6 +248,7 @@ int main(int argc, char *argv[])
+ {
+   struct termios ntio;
+   int ret;
++  int errsv;
+   char buf[8192];
+   struct timeval tv;
+   int ptyfd, ttyfd;
+@@ -339,7 +348,7 @@ int main(int argc, char *argv[])
+   }
+   spawn_shell(ptyfd, ttyfd, command_args);
+ 
+-  signal(SIGHUP, reload_font);
++  signal(SIGHUP, sighup);
+   signal(SIGTERM, sigterm);
+ 
+   ntio = ttysave;
+@@ -360,6 +369,10 @@ int main(int argc, char *argv[])
+ 
+     if (quit)
+ 	    break;
++    if (reload_font_pending)
++	    reload_font();
++    if (vt_switch_pending)
++	    vt_switch();
+     
+     if(pending)
+     {
+@@ -377,9 +390,14 @@ int main(int argc, char *argv[])
+     if (ptyfd > max)
+       max = ptyfd;
+     ret = select(max+1, &fds, NULL, NULL, &tv);
++    errsv = errno;
+ 
+     if (quit)
+ 	    break;
++    if (reload_font_pending)
++	    reload_font();
++    if (vt_switch_pending)
++	    vt_switch();
+ 
+     if (bogl_refresh) {
+       /* Handle VT switching.  */
+@@ -394,7 +412,7 @@ int main(int argc, char *argv[])
+       bogl_refresh = 0;
+       bogl_term_redraw(term);
+     }
+-    if (ret == 0 || (ret < 0 && errno == EINTR))
++    if (ret == 0 || (ret < 0 && errsv == EINTR))
+     {
+       if(pending)
+       {
+-- 
+2.30.2
+
diff --git a/debian/patches/fix-out-of-bound-read-in-tcfb-s-cmap_lookup b/debian/patches/fix-out-of-bound-read-in-tcfb-s-cmap_lookup
new file mode 100644
index 0000000..acb26d9
--- /dev/null
+++ b/debian/patches/fix-out-of-bound-read-in-tcfb-s-cmap_lookup
@@ -0,0 +1,28 @@
+From 61b6c2b21e31268037b4dd1ead7f6088b8a583a4 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang...@gmail.com>
+Date: Wed, 25 May 2022 14:42:50 +0800
+Subject: [PATCH v2 7/8] Fix out-of-bound read in tcfb's cmap_lookup()
+
+When bogl_tcfb_text() is called with bg = -1, it will call
+cmap_lookup(-1), resulting in out-of-bound read, although the return
+value is not used. Reported by AddressSanitizer.
+---
+ bogl-tcfb.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/bogl-tcfb.c b/bogl-tcfb.c
+index cd23b77..5e14892 100644
+--- a/bogl-tcfb.c
++++ b/bogl-tcfb.c
+@@ -48,7 +48,7 @@ static struct fb_var_screeninfo var;
+ static inline unsigned int
+ cmap_lookup (int entry)
+ {
+-  if (entry >= cmap_size)
++  if (entry < 0 || entry >= cmap_size)
+     return 0;
+   
+   return cmap[entry];
+-- 
+2.30.2
+
diff --git a/debian/patches/fix-rightmost-pixel-of-each-line-not-cleared-by-bogl_vga16_text b/debian/patches/fix-rightmost-pixel-of-each-line-not-cleared-by-bogl_vga16_text
new file mode 100644
index 0000000..4deb4d0
--- /dev/null
+++ b/debian/patches/fix-rightmost-pixel-of-each-line-not-cleared-by-bogl_vga16_text
@@ -0,0 +1,28 @@
+From 9d64dee5d6aa80d7836815541a59581f8c1e898c Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang...@gmail.com>
+Date: Sat, 28 May 2022 16:39:23 +0800
+Subject: [PATCH v2 8/8] Fix rightmost pixel of each line not cleared by
+ bogl_vga16_text()
+
+The bogl_vga16_clear() function use [x1, x2) as clear range, so there is
+no need to minus x2 by 1.
+---
+ bogl-vga16.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/bogl-vga16.c b/bogl-vga16.c
+index 6c2cbcf..3fcbe51 100644
+--- a/bogl-vga16.c
++++ b/bogl-vga16.c
+@@ -373,7 +373,7 @@ bogl_vga16_text (int xx, int yy, const char *s, int n, int fg, int bg, int ul,
+     {
+       int x2 = xx + bogl_metrics (s, n, font);
+       if (x2 >= bogl_xres)
+-	x2 = bogl_xres - 1;
++	x2 = bogl_xres;
+       
+       bogl_vga16_clear (xx, yy, x2, yy + h, bg);
+     }
+-- 
+2.30.2
+
diff --git a/debian/patches/font-scaler b/debian/patches/font-scaler
new file mode 100644
index 0000000..a02a3f5
--- /dev/null
+++ b/debian/patches/font-scaler
@@ -0,0 +1,378 @@
+From 04d88a6ff7114750c67cdb58e07122bb430763a9 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang...@gmail.com>
+Date: Tue, 24 May 2022 23:49:31 +0800
+Subject: [PATCH v2 5/8] Font scaler
+
+Current fonts is too small to see on HiDPI displays. This patch
+introduces a BGF font scaler, which can scale font glyphs on the fly
+when loading. The scale factor can be automatically determined by screen
+resolution or specified by a new command line argument '-s'. This patch
+also add support for BGF fonts wider than 32 pixels.
+---
+ bogl-bgf.c   | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++-
+ bogl-bgf.h   |   2 +-
+ bogl-pcfb.c  |   8 ++--
+ bogl-tcfb.c  |   8 ++--
+ bogl-vga16.c |  33 +++++++++------
+ bterm.1      |   4 ++
+ bterm.c      |  30 ++++++++++----
+ 7 files changed, 167 insertions(+), 29 deletions(-)
+
+diff --git a/bogl-bgf.c b/bogl-bgf.c
+index 0383f4f..1a8b9d9 100644
+--- a/bogl-bgf.c
++++ b/bogl-bgf.c
+@@ -20,7 +20,113 @@ struct bogl_bgf {
+ #define bgf_of(font) \
+   ((struct bogl_bgf *)((char *)(font) - offsetof(struct bogl_bgf, font)))
+ 
+-struct bogl_font *bogl_mmap_font(char *file)
++/* Scale the font (both width and height)
++   Declare as inline function, will run faster if scale factor is constant */
++static inline void __attribute__((always_inline))
++bgf_scale_inline(struct bogl_bgf *bgf, int scale)
++{
++  void *new_f = (void *)-1;
++  off_t new_size;
++  struct bogl_font new_font;
++
++  /* old_size*pow(scale,2) should enough and have some waste here */
++  new_size = bgf->size * scale * scale;
++
++  /* Allocate new memory */
++  new_f = mmap(0, new_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
++  if (new_f == (void *)-1) {
++    /* If memory allocation failed, skip scaling silently */
++    goto fail;
++  }
++
++  /* Copy old font data to new memory */
++  memcpy(new_f, bgf->f, bgf->size);
++
++  /* Set font metadata */
++  struct bogl_font *font = &new_font;
++  memcpy(font, new_f + 4, sizeof(*font));
++  font->name = ((void *)font->name - (void *)0) + new_f;
++  font->offset = ((void *)font->offset - (void *)0) + new_f;
++  font->index = ((void *)font->index - (void *)0) + new_f;
++  font->content = ((void *)font->content - (void *)0) + new_f;
++  font->height = bgf->font.height * scale;
++
++  /* Scale each glyph */
++  int mask = font->index_mask;
++  for (int j = 0; j <= mask; j++) {
++    for (int i = font->offset[j]; font->index[i]; i += 2) {
++      int old_height = bgf->font.height;
++      int old_width = (font->index[i] & mask);
++      if (old_width * scale > mask) {
++        /* Scaled glyph width can't fit in mask, fail */
++        goto fail;
++      }
++      font->index[i] = (font->index[i] & ~mask) | (old_width * scale);
++      font->index[i + 1] *= scale * scale;
++      u_int32_t *in_bitmap = &bgf->font.content[bgf->font.index[i + 1]];
++      int in_pitch = (old_width + 31) / 32;
++      u_int32_t *out_bitmap = &font->content[font->index[i + 1]];
++      int out_pitch = (old_width * scale + 31) / 32;
++      for (int y = 0; y < old_height * scale; y++) {
++        const int outlined = 0; /* Useful for debugging */
++        if (y % scale == 0 || outlined) {
++          u_int32_t *in_ptr = in_bitmap + in_pitch * (y / scale);
++          u_int32_t *out_ptr = out_bitmap + out_pitch * y;
++          memset(out_ptr, 0, sizeof(u_int32_t) * out_pitch);
++          for (int x = 0; x < old_width * scale; x++) {
++            int in_off = (x / scale) / 32, in_bit = 31 - (x / scale) % 32;
++            int out_off = x / 32, out_bit = 31 - x % 32;
++            u_int32_t pixel = (in_ptr[in_off] >> in_bit) & 1;
++            if (outlined)
++              if (0 < x % scale && x % scale < scale - 1)
++                if (0 < y % scale && y % scale < scale - 1)
++                  pixel = 0;
++            out_ptr[out_off] |= pixel << out_bit;
++          }
++        } else {
++          u_int32_t *last_line = out_bitmap + out_pitch * (y - 1);
++          u_int32_t *curr_line = out_bitmap + out_pitch * y;
++          memcpy(curr_line, last_line, sizeof(u_int32_t) * out_pitch);
++        }
++      }
++    }
++  }
++
++  /* Replace old font with new font */
++  munmap(bgf->f, bgf->size);
++  bgf->f = new_f;
++  bgf->size = new_size;
++  bgf->font = new_font;
++  return;
++fail:
++  if (new_f != (void *)-1)
++    munmap(new_f, new_size);
++}
++static void __attribute__((noinline))
++bgf_scale_noinline(struct bogl_bgf *bgf, int scale)
++{
++  bgf_scale_inline(bgf, scale);
++}
++static void __attribute__((noinline)) bgf_scale_2x(struct bogl_bgf *bgf)
++{
++  bgf_scale_inline(bgf, 2);
++}
++static void __attribute__((noinline)) bgf_scale_4x(struct bogl_bgf *bgf)
++{
++  bgf_scale_inline(bgf, 4);
++}
++static void bgf_scale(struct bogl_bgf *bgf, int scale)
++{
++  switch (scale) {
++    /* Use fast implementation if possible */
++    case 2: bgf_scale_2x(bgf); return;
++    case 4: bgf_scale_4x(bgf); return;
++    /* Universal implementation as fallback */
++    default: bgf_scale_noinline(bgf, scale); return;
++  }
++}
++
++struct bogl_font *bogl_mmap_font(char *file, int scale)
+ {
+   struct bogl_bgf *bgf = NULL;
+   struct bogl_font *font = NULL;
+@@ -61,6 +167,9 @@ struct bogl_font *bogl_mmap_font(char *file)
+   font->index = ((void *)font->index - (void *)0) + f;
+   font->content = ((void *)font->content - (void *)0) + f;
+ 
++  if (scale >= 2)
++    bgf_scale(bgf, scale);
++
+ done:
+   if (fd != -1)
+     close(fd);
+diff --git a/bogl-bgf.h b/bogl-bgf.h
+index f14a260..978da61 100644
+--- a/bogl-bgf.h
++++ b/bogl-bgf.h
+@@ -1,3 +1,3 @@
+ 
+-struct bogl_font *bogl_mmap_font(char *file);
++struct bogl_font *bogl_mmap_font(char *file, int scale);
+ void bogl_munmap_font(struct bogl_font *font);
+diff --git a/bogl-pcfb.c b/bogl-pcfb.c
+index c737d38..b16c804 100644
+--- a/bogl-pcfb.c
++++ b/bogl-pcfb.c
+@@ -142,6 +142,7 @@ bogl_pcfb_text (int xx, int yy, const char *s, int n, int fg, int bg, int ul,
+ 
+       u_int32_t *character = NULL;
+       int w = bogl_font_glyph (font, wc, &character);
++      int pitch = (w + 31) / 32;
+ 
+       int x, y, h1 = ul ? h - 1 : h;
+ 
+@@ -153,16 +154,15 @@ bogl_pcfb_text (int xx, int yy, const char *s, int n, int fg, int bg, int ul,
+       
+       for (y = 0; y < h1; y++)
+ 	{
+-	  u_int32_t c = *character++;
++	  u_int32_t *c = character;
++	  character += pitch;
+ 	  
+ 	  for (x = 0; x < w; x++)
+ 	    {
+-	      if (c & 0x80000000)
++	      if ((c[x / 32] & (1 << (31 - x % 32))))
+ 		put_var (dst, xx+x, cmap_lookup(fg), bpp);
+ 	      else if (bg != -1)
+ 		put_var (dst, xx+x, cmap_lookup(bg), bpp);
+-
+-	      c <<= 1;
+ 	    }
+ 
+ 	  dst += bogl_line_len;
+diff --git a/bogl-tcfb.c b/bogl-tcfb.c
+index 895d298..cd23b77 100644
+--- a/bogl-tcfb.c
++++ b/bogl-tcfb.c
+@@ -169,6 +169,7 @@ bogl_tcfb_text (int xx, int yy, const char *s, int n, int fg, int bg, int ul,
+ 
+       u_int32_t *character = NULL;
+       int w = bogl_font_glyph (font, wc, &character);
++      int pitch = (w + 31) / 32;
+ 
+       int x, y, h1 = ul ? h - 1 : h;
+       unsigned cfg = cmap_lookup (fg), cbg = cmap_lookup (bg);
+@@ -181,16 +182,15 @@ bogl_tcfb_text (int xx, int yy, const char *s, int n, int fg, int bg, int ul,
+       
+       for (y = 0; y < h1; y++)
+ 	{
+-	  u_int32_t c = *character++;
++	  u_int32_t *c = character;
++	  character += pitch;
+ 	  
+ 	  for (x = 0; x < w; x++)
+ 	    {
+-	      if (c & 0x80000000)
++	      if ((c[x / 32] & (1 << (31 - x % 32))))
+ 		put_var (dst, xx+x, cfg, bpp);
+ 	      else if (bg != -1)
+ 		put_var (dst, xx+x, cbg, bpp);
+-
+-	      c <<= 1;
+ 	    }
+ 
+ 	  dst += bogl_line_len;
+diff --git a/bogl-vga16.c b/bogl-vga16.c
+index bb81803..6c2cbcf 100644
+--- a/bogl-vga16.c
++++ b/bogl-vga16.c
+@@ -394,25 +394,34 @@ bogl_vga16_text (int xx, int yy, const char *s, int n, int fg, int bg, int ul,
+     {
+       u_int32_t *character = NULL;
+       int width = bogl_font_glyph (font, wc, &character);
++      int pitch = (width + ul_bits - 1) / ul_bits;
+ 
+       if (character == NULL)
+ 	continue;
+ 
+-      for (y = 0; y < h; y++)
+-	bits[y] |= character[y] >> x;
+-      x += width;
+-
+-      if (x >= (int) ul_bits)
+-	{
+-	  plot (bg);
++      int i, w;
++      for (i = 0; i < pitch; i++)
++        {
++	  w = width - i * ul_bits;
++	  if (w > ul_bits)
++	    w = ul_bits;
+ 
+-	  x -= ul_bits;
+ 	  for (y = 0; y < h; y++)
+-	    bits[y] = character[y] << (width - x);
++	    bits[y] |= character[y * pitch + i] >> x;
++	  x += w;
+ 
+-	  xx += ul_bits;
+-	  if (xx >= bogl_xres)
+-	    goto done;
++	  if (x >= (int) ul_bits)
++	    {
++	      plot (bg);
++
++	      x -= ul_bits;
++	      for (y = 0; y < h; y++)
++		bits[y] = character[y * pitch + i] << (w - x - 1) << 1;
++
++	      xx += ul_bits;
++	      if (xx >= bogl_xres)
++		goto done;
++	    }
+ 	}
+     }
+   plot (bg);
+diff --git a/bterm.1 b/bterm.1
+index 8b96b99..e62d3ee 100644
+--- a/bterm.1
++++ b/bterm.1
+@@ -21,6 +21,7 @@ bterm - framebuffer terminal emulator
+ .B bterm
+ .B -f
+ .RI font.bgf
++.RI "[-s " scale "]"
+ .RI "[-l " locale "]"
+ .RI "[" program "]"
+ .SH DESCRIPTION
+@@ -36,6 +37,9 @@ Specify the font.  BGF fonts are produced by
+ .BR bdftobogl (1)
+ from standard BDF font files.
+ .TP
++.B -s scale
++Specify the font scale factor, 0 for auto.
++.TP
+ .B -l locale
+ Specify a locale for
+ .B bterm
+diff --git a/bterm.c b/bterm.c
+index b0a1189..610d588 100644
+--- a/bterm.c
++++ b/bterm.c
+@@ -210,6 +210,7 @@ void set_window_size(int ttyfd, int x, int y)
+ }
+ 
+ static char *font_name;
++static int font_scale;
+ static struct bogl_term *term;
+ static volatile int reload_font_pending = 0;
+ 
+@@ -222,7 +223,7 @@ void reload_font(void)
+   struct bogl_font *font;
+   reload_font_pending = 0;
+ 
+-  font = bogl_mmap_font (font_name);
++  font = bogl_mmap_font (font_name, font_scale);
+   if (font == NULL)
+     {
+       fprintf(stderr, "Bad font\n");
+@@ -265,6 +266,7 @@ int main(int argc, char *argv[])
+           switch (argv[i][1])
+           {
+               case 'f':
++              case 's':
+               case 'l':
+                   o = argv[i][1];
+                   break;
+@@ -288,6 +290,11 @@ int main(int argc, char *argv[])
+                     o = ' ';
+                     break;
+ 
++                case 's':
++                    font_scale = atoi(argv[i]);
++                    o = ' ';
++                    break;
++
+                 case 'l':
+                     locale = argv[i];
+                     o = ' ';
+@@ -301,16 +308,11 @@ int main(int argc, char *argv[])
+   setlocale(LC_CTYPE, locale);
+ 
+   if (font_name == NULL) {
+-    fprintf(stderr, "Usage: %s -f font.bgf [ -l locale ] [ program ]\n", argv[0]);
++    fprintf(stderr, "Usage: %s -f font.bgf [ -s scale ] [ -l locale ] [ program ]\n", argv[0]);
+  
+     return 1;
+   }
+ 
+-  if ((font = bogl_mmap_font(font_name)) == NULL) {
+-    fprintf(stderr, "Bad font\n");
+-    return 1;
+-  }
+-
+   tcgetattr(0, &ttysave);
+ 
+   if (!bogl_init()) {
+@@ -318,6 +320,20 @@ int main(int argc, char *argv[])
+     return 1;
+   }
+ 
++  if (font_scale == 0) {
++    if (bogl_xres > 3840 && bogl_yres > 2160)
++      font_scale = 4;
++    else if (bogl_xres > 1920 && bogl_yres > 1080)
++      font_scale = 2;
++    else
++      font_scale = 1;
++  }
++
++  if ((font = bogl_mmap_font(font_name, font_scale)) == NULL) {
++    fprintf(stderr, "Bad font\n");
++    return 1;
++  }
++
+   term = bogl_term_new(font);
+   if (!term)
+     exit(1);
+-- 
+2.30.2
+
diff --git a/debian/patches/series b/debian/patches/series
index b4157e5..336910a 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -21,3 +21,11 @@ cub
 warnings
 no-common
 flags
+better-quit-handling
+better-font-reload-handling
+fix-incorrect-signal-handling
+use-ioctl-fbiopan_display-to-update-screen-after-drawing
+font-scaler
+fix-character-occasionally-disappears-from-right-edge-of-screen
+fix-out-of-bound-read-in-tcfb-s-cmap_lookup
+fix-rightmost-pixel-of-each-line-not-cleared-by-bogl_vga16_text
diff --git a/debian/patches/use-ioctl-fbiopan_display-to-update-screen-after-drawing b/debian/patches/use-ioctl-fbiopan_display-to-update-screen-after-drawing
new file mode 100644
index 0000000..b56475e
--- /dev/null
+++ b/debian/patches/use-ioctl-fbiopan_display-to-update-screen-after-drawing
@@ -0,0 +1,82 @@
+From e7fe989fbbda4acfd9971604b7ffa84899cb343a Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang...@gmail.com>
+Date: Mon, 23 May 2022 22:07:37 +0800
+Subject: [PATCH v2 4/8] Use ioctl(FBIOPAN_DISPLAY) to update screen after
+ drawing
+
+Some framebuffer driver like i915 need explicit notify after drawing,
+otherwise modifications in graphics buffer will not be reflected on
+screen, so use FBIOPAN_DISPLAY to do this notify.
+---
+ bogl-term.c |  1 +
+ bogl.c      | 19 ++++++++++++++++++-
+ bogl.h      |  1 +
+ 3 files changed, 20 insertions(+), 1 deletion(-)
+
+diff --git a/bogl-term.c b/bogl-term.c
+index d5780d3..1f68523 100644
+--- a/bogl-term.c
++++ b/bogl-term.c
+@@ -863,4 +863,5 @@ bogl_term_redraw (struct bogl_term *term)
+     {
+         show_cursor(term, 1);
+     }        
++    bogl_update();
+ }
+diff --git a/bogl.c b/bogl.c
+index f1486f9..5cbe96e 100644
+--- a/bogl.c
++++ b/bogl.c
+@@ -124,12 +124,12 @@ static void kbd_done (void);
+ static void sigusr2 (int);
+ 
+ static struct fb_fix_screeninfo fb_fix;
++static struct fb_var_screeninfo fb_var;
+ /* Initialize BOGL. */
+ int
+ bogl_init (void)
+ {
+   unsigned long bogl_frame_offset, bogl_frame_len;
+-  struct fb_var_screeninfo fb_var;
+   struct vt_stat vts;
+   int PAGE_MASK = ~(sysconf(_SC_PAGESIZE) - 1);
+ 
+@@ -457,6 +457,23 @@ bogl_fb_set_palette (int c, int nc, const unsigned char palette[][3])
+   ioctl (fb, FBIOPUTCMAP, &cmap);
+ }
+ 
++/* Update screen, some framebuffer driver require this explicit notify after
++   modifying screen contents */
++void
++bogl_update (void)
++{
++#if BOGL_VGA16_FB
++  if (type == FB_TYPE_VGA_PLANES)
++    {
++      /* There is no need to call FBIOPAN_DISPLAY when using vga16fb driver.
++         What's worse, it may cause screen flicker on certain hardwares.
++	 So make bogl_update() a no-op here. */
++      return;
++    }
++#endif
++  ioctl (fb, FBIOPAN_DISPLAY, &fb_var);
++}
++
+ /* Returns the oldest error message since this function was last
+    called.  Clears the error state.  Returns a null pointer if no
+    errors have occurred.  The caller must free the returned
+diff --git a/bogl.h b/bogl.h
+index 4d99788..61b0275 100644
+--- a/bogl.h
++++ b/bogl.h
+@@ -79,6 +79,7 @@ const char *bogl_error (void);
+ 
+ void bogl_gray_scale (int make_gray);
+ void bogl_fb_set_palette (int c, int nc, const unsigned char palette[][3]);
++void bogl_update(void);
+ void bogl_rectangle (int x1, int y1, int x2, int y2, int c);
+ int bogl_metrics (const char *s, int n, const struct bogl_font *font);
+ 
+-- 
+2.30.2
+
-- 
2.30.2

Reply via email to