From cc595a73cf45ee8b0f0444b844b10bc021d02572 Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Sun, 25 Feb 2024 23:16:05 -0500
Subject: kernel: vcons: Add cursor support

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/dev/vcons/vcons.c         | 78 +++++++++++++++++++++++++++++++++++++------
 sys/dev/vcons/vcons_io.c      |  8 ++++-
 sys/include/dev/vcons/vcons.h |  1 +
 3 files changed, 75 insertions(+), 12 deletions(-)

diff --git a/sys/dev/vcons/vcons.c b/sys/dev/vcons/vcons.c
index 4858110..1c69cf3 100644
--- a/sys/dev/vcons/vcons.c
+++ b/sys/dev/vcons/vcons.c
@@ -39,11 +39,32 @@ __KERNEL_META("$Hyra$: kern_vcons.c, Ian Marco Moffett, "
               "Hyra video console code");
 
 /* Get x or y values in pixels */
-#define PIX_CPY_X(scrptr) (scr->cpy_x * FONT_WIDTH)
-#define PIX_CPY_Y(scrptr) (scr->cpy_y * FONT_HEIGHT)
+#define PIX_CPY_X(scrptr) ((scrptr)->cpy_x * FONT_WIDTH)
+#define PIX_CPY_Y(scrptr) ((scrptr)->cpy_y * FONT_HEIGHT)
 
 static struct vcons_screen *screen = NULL;
 
+static void
+vcons_draw_cursor(struct vcons_screen *scr, uint32_t color)
+{
+    struct vcons_cursor *cursor = &scr->cursor;
+    struct fbdev fbdev = scr->fbdev;
+
+    uint32_t *fbdev_mem = fbdev.mem;
+    uint32_t fbdev_idx = 0;
+    uint32_t cx, cy;
+
+    for (size_t y = VCONS_CURSOR_HEIGHT; y > 0; --y) {
+        for (size_t x = VCONS_CURSOR_WIDTH; x > 0; --x) {
+            cx = cursor->old_xpos + x;
+            cy = cursor->old_ypos + y;
+
+            fbdev_idx = fbdev_get_index(&fbdev, cx, cy);
+            fbdev_mem[fbdev_idx] = color;
+        }
+    }
+}
+
 static void
 vcons_clear_scr(struct vcons_screen *scr)
 {
@@ -52,6 +73,7 @@ vcons_clear_scr(struct vcons_screen *scr)
     scr->cpy_x = 0, scr->cpy_y = 0;
 
     memset(scr->fbdev_mem, scr->bg, (fbdev.pitch * fbdev.height));
+    vcons_update_cursor(scr);
 }
 
 /*
@@ -80,11 +102,35 @@ vcons_draw_char(struct vcons_screen *scr, char c, uint32_t x, uint32_t y)
     }
 }
 
+void
+vcons_update_cursor(struct vcons_screen *scr)
+{
+    struct vcons_cursor *cursor = &scr->cursor;
+
+    cursor->is_drawing = true;
+
+    if (cursor->is_drawn) {
+        /* Clear old cursor */
+        vcons_draw_cursor(scr, scr->bg);
+    }
+
+    cursor->old_xpos = cursor->xpos;
+    cursor->old_ypos = cursor->ypos;
+    vcons_draw_cursor(scr, scr->fg);
+
+    cursor->is_drawn = true;
+    cursor->is_drawing = false;
+}
+
 int
 vcons_putch(struct vcons_screen *scr, char c)
 {
     uint32_t x = PIX_CPY_X(scr);
     uint32_t y = PIX_CPY_Y(scr);
+    struct vcons_cursor *cursor = &scr->cursor;
+    bool cursor_newline = false;
+
+    while (cursor->is_drawing);
 
     if (scr == NULL) {
         return 1;
@@ -95,25 +141,35 @@ vcons_putch(struct vcons_screen *scr, char c)
         return 0;
     }
 
-    /*
-     * Check text bounds
-     *
-     * We must subtract ncols,nrows by FONT_WIDTH,FONT_HEIGHT
-     * as each char is of that width,height and we need to account for
-     * that.
-     */
-    if (x >= (scr->ncols - FONT_WIDTH)) {
+    /* Check cursor bounds */
+    if (cursor->xpos >= PIX_BOUNDS_MAX_X(scr)) {
+        cursor->xpos = FONT_WIDTH;
+        cursor->ypos += FONT_HEIGHT;
+        cursor_newline = true;
+    }
+    if (cursor->ypos >= PIX_BOUNDS_MAX_Y(scr)) {
+        cursor->xpos = FONT_WIDTH;
+        cursor->ypos = 0;
+    }
+
+    /* Check text bounds */
+    if (x >= PIX_BOUNDS_MAX_X(scr)) {
         /* Wrap to the next row */
         ++scr->cpy_y, scr->cpy_x = 0;
         x = PIX_CPY_X(scr), y = PIX_CPY_Y(scr);
     }
-    if (y >= (scr->nrows - FONT_HEIGHT)) {
+    if (y >= PIX_BOUNDS_MAX_Y(scr)) {
         scr->cpy_y = 0;
         scr->cpy_x = 0;
         vcons_clear_scr(scr);
         x = PIX_CPY_X(scr), y = PIX_CPY_Y(scr);
     }
 
+    if (!cursor_newline) {
+        cursor->xpos += FONT_WIDTH;
+    }
+
+    vcons_update_cursor(scr);
     vcons_draw_char(scr, c, x, y);
     ++scr->cpy_x;
     return 0;
diff --git a/sys/dev/vcons/vcons_io.c b/sys/dev/vcons/vcons_io.c
index 569cce6..a3d6042 100644
--- a/sys/dev/vcons/vcons_io.c
+++ b/sys/dev/vcons/vcons_io.c
@@ -53,15 +53,20 @@ int
 vcons_process_output(struct vcons_screen *scr, int c)
 {
     struct termios termios = scr->termios;
+    struct vcons_cursor *cursor = &scr->cursor;
 
     switch (c) {
     case ASCII_LF:
-        if (__TEST(termios.c_oflag, OCRNL))
+        if (__TEST(termios.c_oflag, OCRNL)) {
             scr->cpy_x = 0;
+            cursor->xpos = 0;
+        }
         scr->cpy_y++;
+        cursor->ypos += FONT_HEIGHT;
         break;
     case ASCII_CR:
         scr->cpy_x = 0;
+        cursor->xpos = 0;
         break;
     case ASCII_HT:
         vcons_expand_tab(scr);
@@ -70,5 +75,6 @@ vcons_process_output(struct vcons_screen *scr, int c)
         return -1;
     }
 
+    vcons_update_cursor(scr);
     return c;
 }
diff --git a/sys/include/dev/vcons/vcons.h b/sys/include/dev/vcons/vcons.h
index fc59f6e..737651f 100644
--- a/sys/include/dev/vcons/vcons.h
+++ b/sys/include/dev/vcons/vcons.h
@@ -67,5 +67,6 @@ struct vcons_screen {
 
 void vcons_attach(struct vcons_screen *scr);
 int vcons_putch(struct vcons_screen *scr, char c);
+void vcons_update_cursor(struct vcons_screen *scr);
 
 #endif  /* !_DEV_VCONS_H_ */
-- 
cgit v1.2.3