shithub: fork

Download patch

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);
+}
--