ref: aa255df8bd47fc2457228dcecd4ea09a5ba67a58
parent: 0eb2b4eb119429b85a42a7a765e2c070a3de5bf1
author: qwx <qwx@sciops.net>
date: Mon Mar 9 07:12:53 EDT 2026
9/pc/vga: ultimate theming
--- /dev/null
+++ b/sys/src/9/pc/vga.c
@@ -1,0 +1,266 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+#define Image IMAGE
+#include <draw.h>
+#include <memdraw.h>
+#include <cursor.h>
+#include "screen.h"
+
+static Memimage *conscol;
+static Memimage *back;
+
+static Point curpos;
+static Rectangle window;
+static int *xp;
+static int xbuf[256];
+Lock vgascreenlock;
+
+void
+vgaimageinit(ulong)
+{+ conscol = memwhite;
+ back = memblack;
+}
+
+static void
+vgascroll(VGAscr* scr)
+{+ int h, o;
+ Point p;
+ Rectangle r;
+
+ h = scr->memdefont->height;
+ o = 8*h;
+ r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
+ p = Pt(window.min.x, window.min.y+o);
+ memimagedraw(scr->gscreen, r, scr->gscreen, p, nil, p, S);
+ r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
+ memimagedraw(scr->gscreen, r, back, ZP, nil, ZP, S);
+
+ curpos.y -= o;
+}
+
+static void
+vgascreenputc(VGAscr* scr, char* buf, Rectangle *flushr)
+{+ Point p;
+ int h, w, pos;
+ Rectangle r;
+
+ if(xp < xbuf || xp >= &xbuf[nelem(xbuf)])
+ xp = xbuf;
+
+ h = scr->memdefont->height;
+ switch(buf[0]){+ case '\n':
+ if(curpos.y+h >= window.max.y){+ vgascroll(scr);
+ *flushr = window;
+ }
+ curpos.y += h;
+ vgascreenputc(scr, "\r", flushr);
+ break;
+
+ case '\r':
+ xp = xbuf;
+ curpos.x = window.min.x;
+ break;
+
+ case '\t':
+ p = memsubfontwidth(scr->memdefont, " ");
+ w = p.x;
+ if(curpos.x >= window.max.x-4*w)
+ vgascreenputc(scr, "\n", flushr);
+
+ pos = (curpos.x-window.min.x)/w;
+ pos = 4-(pos%4);
+ *xp++ = curpos.x;
+ r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y + h);
+ memimagedraw(scr->gscreen, r, back, ZP, nil, ZP, S);
+ curpos.x += pos*w;
+ break;
+
+ case '\b':
+ if(xp <= xbuf)
+ break;
+ xp--;
+ r = Rect(*xp, curpos.y, curpos.x, curpos.y+h);
+ memimagedraw(scr->gscreen, r, back, r.min, nil, ZP, S);
+ combinerect(flushr, r);
+ curpos.x = *xp;
+ break;
+
+ case '\0':
+ break;
+
+ default:
+ p = memsubfontwidth(scr->memdefont, buf);
+ w = p.x;
+
+ if(curpos.x >= window.max.x-w)
+ vgascreenputc(scr, "\n", flushr);
+
+ *xp++ = curpos.x;
+ r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y+h);
+ memimagedraw(scr->gscreen, r, back, r.min, nil, ZP, S);
+ memimagestring(scr->gscreen, curpos, conscol, ZP, scr->memdefont, buf);
+ combinerect(flushr, r);
+ curpos.x += w;
+ }
+}
+
+static void
+vgascreenputs(char* s, int n)
+{+ static char rb[UTFmax+1];
+ static int nrb;
+ char *e;
+ int gotdraw;
+ VGAscr *scr;
+ Rectangle flushr;
+
+ scr = &vgascreen[0];
+
+ if(!islo()){+ /*
+ * Don't deadlock trying to
+ * print in an interrupt.
+ */
+ if(!canlock(&vgascreenlock))
+ return;
+ }
+ else {+ while(!canlock(&vgascreenlock))
+ ;
+ }
+
+ /*
+ * Be nice to hold this, but not going to deadlock
+ * waiting for it. Just try and see.
+ */
+ gotdraw = canqlock(&drawlock);
+
+ flushr = Rect(10000, 10000, -10000, -10000);
+
+ e = s + n;
+ while(s < e){+ rb[nrb++] = *s++;
+ if(nrb >= UTFmax || fullrune(rb, nrb)){+ rb[nrb] = 0;
+ vgascreenputc(scr, rb, &flushr);
+ nrb = 0;
+ }
+ }
+ flushmemscreen(flushr);
+
+ if(gotdraw)
+ qunlock(&drawlock);
+ unlock(&vgascreenlock);
+}
+
+static Memimage*
+mkcolor(Memimage *screen, ulong color)
+{+ Memimage *i;
+
+ if(i = allocmemimage(Rect(0,0,1,1), screen->chan)){+ i->flags |= Frepl;
+ i->clipr = screen->r;
+ memfillcolor(i, color);
+ }
+ return i;
+}
+
+void
+vgascreenwin(VGAscr* scr)
+{+ Memimage *i;
+ Rectangle r;
+ Point p;
+ int h;
+
+ h = scr->memdefont->height;
+ r = scr->gscreen->r;
+
+ if(i = mkcolor(scr->gscreen, 0x0D686BFF)){+ memimagedraw(scr->gscreen, r, i, ZP, nil, ZP, S);
+ freememimage(i);
+ }
+
+ r = scr->gscreen->clipr;
+ window = insetrect(r, 20);
+ memimagedraw(scr->gscreen, window, conscol, ZP, memopaque, ZP, S);
+ window = insetrect(window, 4);
+ memimagedraw(scr->gscreen, window, back, ZP, memopaque, ZP, S);
+
+ if(i = mkcolor(scr->gscreen, 0x777777FF)){+ memimagedraw(scr->gscreen, Rect(window.min.x, window.min.y,
+ window.max.x, window.min.y+h+5+6), i, ZP, nil, ZP, S);
+ freememimage(i);
+
+ window = insetrect(window, 5);
+ p = addpt(window.min, Pt(10, 0));
+ memimagestring(scr->gscreen, p, memblack, ZP, scr->memdefont, " Plan 9 Console ");
+ window.min.y += h+6;
+ } else
+ window = insetrect(window, 5);
+
+ window.max.y = window.min.y+(Dy(window)/h)*h;
+ curpos = window.min;
+
+ flushmemscreen(r);
+ vgascreenputs(kmesg.buf, kmesg.n);
+ screenputs = vgascreenputs;
+}
+
+/*
+ * Supposedly this is the way to turn DPMS
+ * monitors off using just the VGA registers.
+ * Unfortunately, it seems to mess up the video mode
+ * on the cards I've tried.
+ */
+void
+vgablank(VGAscr*, int blank)
+{+ uchar seq1, crtc17;
+
+ if(blank) {+ seq1 = 0x00;
+ crtc17 = 0x80;
+ } else {+ seq1 = 0x20;
+ crtc17 = 0x00;
+ }
+
+ outs(Seqx, 0x0100); /* synchronous reset */
+ seq1 |= vgaxi(Seqx, 1) & ~0x20;
+ vgaxo(Seqx, 1, seq1);
+ crtc17 |= vgaxi(Crtx, 0x17) & ~0x80;
+ delay(10);
+ vgaxo(Crtx, 0x17, crtc17);
+ outs(Crtx, 0x0300); /* end synchronous reset */
+}
+
+void
+addvgaseg(char *name, uvlong pa, vlong size)
+{+ Physseg seg;
+
+ if((uintptr)pa != pa || size <= 0 || -(uintptr)pa < size){+ print("addvgaseg %s: bad address %llux-%llux pc %#p\n",+ name, pa, pa+size, getcallerpc(&name));
+ return;
+ }
+ memset(&seg, 0, sizeof seg);
+ seg.attr = SG_PHYSICAL | SG_DEVICE | SG_NOEXEC;
+ seg.name = name;
+ seg.pa = (uintptr)pa;
+ seg.size = size;
+ addphysseg(&seg);
+}
--
⑨