ref: e6b63eabaef2185b7c788d6cbb7df939328267c6
author: qwx <qwx@sciops.net>
date: Wed Jan 8 23:41:19 EST 2020
add currently used patches
--- /dev/null
+++ b/9fs-9paste
@@ -1,0 +1,12 @@
+diff -r 2c3766a9188f rc/bin/9fs
+--- a/rc/bin/9fs Sun May 21 17:27:30 2017 +0200
++++ b/rc/bin/9fs Mon May 22 08:03:42 2017 +0200
+@@ -70,6 +70,8 @@
+ vacfs -m /n/`{basename $1 .vac} `{cat $score}
+ case wiki
+ srv -m 'net!plan9.bell-labs.com!wiki' wiki /mnt/wiki
++case 9paste
++ srv -n fs.9paste.net 9paste /n/9paste
+ case *
+ switch($#*){
+ case 1
--- /dev/null
+++ b/9nusbrc-nesusbjoy
@@ -1,0 +1,12 @@
+diff -r 5adefb206fa3 sys/src/9/boot/nusbrc
+--- a/sys/src/9/boot/nusbrc Tue Aug 07 23:46:58 2018 +0200
++++ b/sys/src/9/boot/nusbrc Wed Aug 08 06:14:09 2018 +0300
+@@ -15,6 +15,8 @@
+ if(~ $#* 5 && ! test -e /env/nousbhname)
+ id=$1:$5
+ switch($2$3){
++ case 17810a99 17810a96 05832060
++ # let nusb/joy take this one
+ case 0b957720 0b95772a 0db0a877 13b10018 15577720 20013c05 07d13c05 05ac1402
+ nusb/ether -t a88772 $etherargs $id
+ case 0b951780 14eaab11 17370039 0411006e 050d5055
--- /dev/null
+++ b/acme-col
@@ -1,0 +1,283 @@
+diff -r 49bd5e4c9bde sys/src/cmd/acme/acme.c
+--- a/sys/src/cmd/acme/acme.c Wed Feb 07 18:53:08 2018 +0000
++++ b/sys/src/cmd/acme/acme.c Sun Feb 18 20:30:34 2018 +0100
+@@ -863,18 +863,18 @@
+ Image *tmp;
+
+ /* Blue */
+- tagcols[BACK] = allocimagemix(display, DPalebluegreen, DWhite);
+- tagcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPalegreygreen);
+- tagcols[BORD] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPurpleblue);
+- tagcols[TEXT] = display->black;
+- tagcols[HTEXT] = display->black;
++ tagcols[BACK] = display->black;
++ tagcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x111111FF);
++ tagcols[BORD] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x440000FF);
++ tagcols[TEXT] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x770000FF);
++ tagcols[HTEXT] = tagcols[TEXT];
+
+ /* Yellow */
+- textcols[BACK] = allocimagemix(display, DPaleyellow, DWhite);
+- textcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkyellow);
+- textcols[BORD] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DYellowgreen);
+- textcols[TEXT] = display->black;
+- textcols[HTEXT] = display->black;
++ textcols[BACK] = display->black;
++ textcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x440000FF);
++ textcols[BORD] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x111111FF);
++ textcols[TEXT] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x884400FF);
++ textcols[HTEXT] = textcols[TEXT];
+
+ if(button){
+ freeimage(button);
+@@ -894,12 +894,12 @@
+ r.max.x -= 2;
+ border(modbutton, r, 2, tagcols[BORD], ZP);
+ r = insetrect(r, 2);
+- tmp = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DMedblue);
++ tmp = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x884400FF);
+ draw(modbutton, r, tmp, nil, ZP);
+ freeimage(tmp);
+
+ r = button->r;
+- colbutton = allocimage(display, r, screen->chan, 0, DPurpleblue);
++ colbutton = allocimage(display, r, screen->chan, 0, 0x440000FF);
+
+ but2col = allocimage(display, r, screen->chan, 1, 0xAA0000FF);
+ but3col = allocimage(display, r, screen->chan, 1, 0x006600FF);
+diff -r 49bd5e4c9bde sys/src/cmd/acme/cols.c
+--- a/sys/src/cmd/acme/cols.c Wed Feb 07 18:53:08 2018 +0000
++++ b/sys/src/cmd/acme/cols.c Sun Feb 18 20:30:34 2018 +0100
+@@ -17,7 +17,7 @@
+ Rectangle r1;
+ Text *t;
+
+- draw(screen, r, display->white, nil, ZP);
++ draw(screen, r, display->black, nil, ZP);
+ c->r = r;
+ c->w = nil;
+ c->nw = 0;
+@@ -30,7 +30,7 @@
+ t->what = Columntag;
+ r1.min.y = r1.max.y;
+ r1.max.y += Border;
+- draw(screen, r1, display->black, nil, ZP);
++ draw(screen, r1, tagcols[BORD], nil, ZP);
+ textinsert(t, 0, L"New Cut Paste Snarf Sort Zerox Delcol ", 38, TRUE);
+ textsetselect(t, t->file->nc, t->file->nc);
+ draw(screen, t->scrollr, colbutton, nil, colbutton->r.min);
+@@ -79,7 +79,7 @@
+ r1.max.y = min(y, v->body.r.min.y+v->body.nlines*v->body.font->height);
+ r1.min.y = winresize(v, r1, FALSE);
+ r1.max.y = r1.min.y+Border;
+- draw(screen, r1, display->black, nil, ZP);
++ draw(screen, r1, tagcols[BORD], nil, ZP);
+ r.min.y = r1.max.y;
+ }
+ if(w == nil){
+@@ -134,7 +134,7 @@
+ c->nw--;
+ c->w = realloc(c->w, c->nw*sizeof(Window*));
+ if(c->nw == 0){
+- draw(screen, r, display->white, nil, ZP);
++ draw(screen, r, display->black, nil, ZP);
+ return;
+ }
+ if(i == c->nw){ /* extend last window down */
+@@ -189,7 +189,7 @@
+ draw(screen, c->tag.scrollr, colbutton, nil, colbutton->r.min);
+ r1.min.y = r1.max.y;
+ r1.max.y += Border;
+- draw(screen, r1, display->black, nil, ZP);
++ draw(screen, r1, tagcols[BORD], nil, ZP);
+ r1.max.y = r.max.y;
+ for(i=0; i<c->nw; i++){
+ w = c->w[i];
+@@ -200,7 +200,7 @@
+ r1.max.y = r1.min.y+(Dy(w->r)+Border)*Dy(r)/Dy(c->r);
+ r2 = r1;
+ r2.max.y = r2.min.y+Border;
+- draw(screen, r2, display->black, nil, ZP);
++ draw(screen, r2, tagcols[BORD], nil, ZP);
+ r1.min.y = r2.max.y;
+ r1.min.y = winresize(w, r1, FALSE);
+ }
+@@ -256,7 +256,7 @@
+ r.max.y = r.min.y+Dy(w->r)+Border;
+ r1 = r;
+ r1.max.y = r1.min.y+Border;
+- draw(screen, r1, display->black, nil, ZP);
++ draw(screen, r1, tagcols[BORD], nil, ZP);
+ r.min.y = r1.max.y;
+ y = winresize(w, r, FALSE);
+ }
+@@ -358,7 +358,7 @@
+ }
+ r.min.y = v->r.max.y;
+ r.max.y += Border;
+- draw(screen, r, display->black, nil, ZP);
++ draw(screen, r, tagcols[BORD], nil, ZP);
+ y1 = r.max.y;
+ }
+ /* scan to see new size of everyone below */
+@@ -390,7 +390,7 @@
+ if(i < c->nw-1){
+ r.min.y = r.max.y;
+ r.max.y += Border;
+- draw(screen, r, display->black, nil, ZP);
++ draw(screen, r, tagcols[BORD], nil, ZP);
+ for(j=i+1; j<c->nw; j++)
+ ny[j] -= (y2-r.max.y);
+ }
+@@ -410,7 +410,7 @@
+ if(j < c->nw-1){ /* no border on last window */
+ r.min.y = v->r.max.y;
+ r.max.y += Border;
+- draw(screen, r, display->black, nil, ZP);
++ draw(screen, r, tagcols[BORD], nil, ZP);
+ }
+ y1 = r.max.y;
+ }
+@@ -498,7 +498,7 @@
+ }
+ r.min.y = v->r.max.y;
+ r.max.y = r.min.y+Border;
+- draw(screen, r, display->black, nil, ZP);
++ draw(screen, r, tagcols[BORD], nil, ZP);
+ r.min.y = r.max.y;
+ if(i == c->nw-1)
+ r.max.y = c->r.max.y;
+diff -r 49bd5e4c9bde sys/src/cmd/acme/rows.c
+--- a/sys/src/cmd/acme/rows.c Wed Feb 07 18:53:08 2018 +0000
++++ b/sys/src/cmd/acme/rows.c Sun Feb 18 20:30:34 2018 +0100
+@@ -18,7 +18,7 @@
+ Rectangle r1;
+ Text *t;
+
+- draw(screen, r, display->white, nil, ZP);
++ draw(screen, r, display->black, nil, ZP);
+ row->r = r;
+ row->col = nil;
+ row->ncol = 0;
+@@ -32,7 +32,7 @@
+ t->col = nil;
+ r1.min.y = r1.max.y;
+ r1.max.y += Border;
+- draw(screen, r1, display->black, nil, ZP);
++ draw(screen, r1, tagcols[BORD], nil, ZP);
+ textinsert(t, 0, L"Newcol Kill Putall Dump Exit ", 29, TRUE);
+ textsetselect(t, t->file->nc, t->file->nc);
+ }
+@@ -63,7 +63,7 @@
+ r = d->r;
+ if(Dx(r) < 100)
+ return nil;
+- draw(screen, r, display->white, nil, ZP);
++ draw(screen, r, display->black, nil, ZP);
+ r1 = r;
+ r1.max.x = min(x, r.max.x-50);
+ if(Dx(r1) < 50)
+@@ -71,7 +71,7 @@
+ colresize(d, r1);
+ r1.min.x = r1.max.x;
+ r1.max.x = r1.min.x+Border;
+- draw(screen, r1, display->black, nil, ZP);
++ draw(screen, r1, tagcols[BORD], nil, ZP);
+ r.min.x = r1.max.x;
+ }
+ if(c == nil){
+@@ -105,7 +105,7 @@
+ textresize(&row->tag, r1);
+ r1.min.y = r1.max.y;
+ r1.max.y += Border;
+- draw(screen, r1, display->black, nil, ZP);
++ draw(screen, r1, tagcols[BORD], nil, ZP);
+ r.min.y = r1.max.y;
+ r1 = r;
+ r1.max.x = r1.min.x;
+@@ -119,7 +119,7 @@
+ if(i > 0){
+ r2 = r1;
+ r2.max.x = r2.min.x+Border;
+- draw(screen, r2, display->black, nil, ZP);
++ draw(screen, r2, tagcols[BORD], nil, ZP);
+ r1.min.x = r2.max.x;
+ }
+ colresize(c, r1);
+@@ -178,14 +178,14 @@
+ p.x = c->r.max.x-80-Scrollwid;
+ r = d->r;
+ r.max.x = c->r.max.x;
+- draw(screen, r, display->white, nil, ZP);
++ draw(screen, r, display->black, nil, ZP);
+ r.max.x = p.x;
+ colresize(d, r);
+ r = c->r;
+ r.min.x = p.x;
+ r.max.x = r.min.x;
+ r.max.x += Border;
+- draw(screen, r, display->black, nil, ZP);
++ draw(screen, r, tagcols[BORD], nil, ZP);
+ r.min.x = r.max.x;
+ r.max.x = c->r.max.x;
+ colresize(c, r);
+@@ -210,7 +210,7 @@
+ row->ncol--;
+ row->col = realloc(row->col, row->ncol*sizeof(Column*));
+ if(row->ncol == 0){
+- draw(screen, r, display->white, nil, ZP);
++ draw(screen, r, display->black, nil, ZP);
+ return;
+ }
+ if(i == row->ncol){ /* extend last column right */
+@@ -221,7 +221,7 @@
+ c = row->col[i];
+ r.max.x = c->r.max.x;
+ }
+- draw(screen, r, display->white, nil, ZP);
++ draw(screen, r, display->black, nil, ZP);
+ colresize(c, r);
+ }
+
+@@ -543,12 +543,12 @@
+ r2.min.x = x+Border;
+ if(Dx(r1) < 50 || Dx(r2) < 50)
+ continue;
+- draw(screen, Rpt(r1.min, r2.max), display->white, nil, ZP);
++ draw(screen, Rpt(r1.min, r2.max), display->black, nil, ZP);
+ colresize(c1, r1);
+ colresize(c2, r2);
+ r2.min.x = x;
+ r2.max.x = x+Border;
+- draw(screen, r2, display->black, nil, ZP);
++ draw(screen, r2, tagcols[BORD], nil, ZP);
+ }
+ if(i >= row->ncol)
+ rowadd(row, nil, x);
+diff -r 49bd5e4c9bde sys/src/cmd/acme/text.c
+--- a/sys/src/cmd/acme/text.c Wed Feb 07 18:53:08 2018 +0000
++++ b/sys/src/cmd/acme/text.c Sun Feb 18 20:30:34 2018 +0100
+@@ -1141,12 +1141,12 @@
+ pt1 = pt0;
+ reg = region(q, p0);
+ if(reg == 0)
+- frdrawsel0(f, pt0, p0, p1, col, display->white);
++ frdrawsel0(f, pt0, p0, p1, col, display->black);
+ }
+ qt = frptofchar(f, q);
+ if(reg > 0){
+ if(q > p1)
+- frdrawsel0(f, pt1, p1, q, col, display->white);
++ frdrawsel0(f, pt1, p1, q, col, display->black);
+
+ else if(q < p1)
+ selrestore(f, qt, q, p1);
+@@ -1154,7 +1154,7 @@
+ if(q > p1)
+ selrestore(f, pt1, p1, q);
+ else
+- frdrawsel0(f, qt, q, p1, col, display->white);
++ frdrawsel0(f, qt, q, p1, col, display->black);
+ }
+ p1 = q;
+ pt1 = qt;
--- /dev/null
+++ b/colors-col
@@ -1,0 +1,23 @@
+diff -r 20a0f09456ec sys/src/cmd/colors.c
+--- a/sys/src/cmd/colors.c Sun Apr 17 07:33:35 2016 +0200
++++ b/sys/src/cmd/colors.c Mon Apr 18 06:29:26 2016 +0200
+@@ -28,7 +28,7 @@
+ }
+
+ ny = n/nx;
+- draw(screen, screen->r, display->white, nil, ZP);
++ draw(screen, screen->r, display->black, nil, ZP);
+ r = insetrect(screen->r, 5);
+ r.min.y+=20;
+ b.max.y=r.min.y;
+@@ -155,8 +155,8 @@
+ rgb&0xFF,
+ (rgb<<8) | 0xFF);
+ p = addpt(screen->r.min, Pt(2,2));
+- draw(screen, Rpt(p, addpt(p, stringsize(font, buf))), display->white, nil, p);
+- string(screen, p, display->black, ZP, font, buf);
++ draw(screen, Rpt(p, addpt(p, stringsize(font, buf))), display->black, nil, p);
++ string(screen, p, display->white, ZP, font, buf);
+ prev=i;
+ break;
+ }
--- /dev/null
+++ b/doom-autorun
@@ -1,0 +1,44 @@
+doom: add autorun configuration option
+
+an autorun option avoids having the shift key swapping mouse buttons 2
+and 3 when playing with the mouse (or remapping the run key...)
+
+diff -r bd0ff7078273 sys/src/games/doom/g_game.c
+--- a/sys/src/games/doom/g_game.c Mon Aug 28 19:45:49 2017 +0200
++++ b/sys/src/games/doom/g_game.c Wed Aug 30 11:09:52 2017 +0200
+@@ -153,6 +153,7 @@
+ int key_use;
+ int key_strafe;
+ int key_speed;
++int autorun;
+
+ int mousebfire;
+ int mousebstrafe;
+@@ -252,7 +253,7 @@
+
+ strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe]
+ || joybuttons[joybstrafe];
+- speed = gamekeydown[key_speed] || joybuttons[joybspeed];
++ speed = autorun || gamekeydown[key_speed] || joybuttons[joybspeed];
+
+ forward = side = 0;
+
+diff -r bd0ff7078273 sys/src/games/doom/m_misc.c
+--- a/sys/src/games/doom/m_misc.c Mon Aug 28 19:45:49 2017 +0200
++++ b/sys/src/games/doom/m_misc.c Wed Aug 30 11:09:52 2017 +0200
+@@ -172,6 +172,7 @@
+ extern int viewwidth;
+ extern int viewheight;
+
++extern int autorun;
+ extern int mouseSensitivity;
+ extern int showMessages;
+
+@@ -213,6 +214,7 @@
+ {"key_use",&key_use, ' '},
+ {"key_strafe",&key_strafe, KEY_RALT},
+ {"key_speed",&key_speed, KEY_RSHIFT},
++ {"autorun",&autorun, 0},
+
+ {"use_mouse",&usemouse, 1},
+ {"mouseb_fire",&mousebfire,0},
--- /dev/null
+++ b/doom-chat
@@ -1,0 +1,120 @@
+diff -Naur a/sys/src/games/doom/hu_lib.c b/sys/src/games/doom/hu_lib.c
+--- a/sys/src/games/doom/hu_lib.c Wed Jan 18 02:13:23 2012
++++ b/sys/src/games/doom/hu_lib.c Wed Aug 12 17:58:24 2015
+@@ -315,22 +315,15 @@
+ // wrapper function for handling general keyed input.
+ // returns true if it ate the key
+ boolean
+-HUlib_keyInIText
+-( hu_itext_t* it,
+- unsigned char ch )
++HUlib_keyInIText(hu_itext_t* it, uchar c)
+ {
+-
+- if (ch >= ' ' && ch <= '_')
+- HUlib_addCharToTextLine(&it->l, (char) ch);
+- else
+- if (ch == KEY_BACKSPACE)
+- HUlib_delCharFromIText(it);
+- else
+- if (ch != KEY_ENTER)
+- return false; // did not eat key
+-
+- return true; // ate the key
+-
++ if(isprint(c))
++ HUlib_addCharToTextLine(&it->l, c);
++ else if(c == KEY_BACKSPACE)
++ HUlib_delCharFromIText(it);
++ else if(c != KEY_ENTER)
++ return false;
++ return true;
+ }
+
+ void HUlib_drawIText(hu_itext_t* it)
+diff -Naur a/sys/src/games/doom/hu_stuff.c b/sys/src/games/doom/hu_stuff.c
+--- a/sys/src/games/doom/hu_stuff.c Wed Jan 18 02:13:23 2012
++++ b/sys/src/games/doom/hu_stuff.c Wed Aug 12 17:57:21 2015
+@@ -541,6 +541,9 @@
+ return false;
+ }
+
++ if(ev->type == ev_keyup)
++ return false;
++
+ if (!chat_on)
+ {
+ if (ev->data1 == HU_MSGREFRESH)
+diff -Naur a/sys/src/games/doom/i_video.c b/sys/src/games/doom/i_video.c
+--- a/sys/src/games/doom/i_video.c Wed Jul 29 13:45:35 2015
++++ b/sys/src/games/doom/i_video.c Wed Aug 12 18:03:33 2015
+@@ -5,10 +5,13 @@
+ #include "v_video.h" // screens[]
+ #include "d_main.h" // D_PostEvent
+
++#include <ctype.h>
+ #include <draw.h>
+ #include <mouse.h>
+ #include <keyboard.h>
+
++extern boolean chat_on;
++
+ static int resized;
+ static int mouseactive;
+
+@@ -245,6 +248,7 @@
+ int kfd, n;
+ Rune r;
+ event_t e;
++ int shifton = 0, lastk = 0, laste = 0;
+
+ if((kfd = open("/dev/kbd", OREAD)) < 0)
+ sysfatal("can't open kbd: %r");
+@@ -262,21 +266,32 @@
+ case 'c':
+ chartorune(&r, buf+1);
+ if(r){
++#define HU_INPUTTOGGLE 't' /* FIXME */
++ /* catch dup, but only once */
++ if((chat_on && laste == 'k' && lastk == buf[1])
++ || !chat_on && r == HU_INPUTTOGGLE)
++ continue;
+ e.data1 = r;
+ e.type = ev_char;
+ D_PostEvent(&e);
+ }
+ /* no break */
+ default:
++ laste = buf[0];
+ continue;
+ case 'k':
+ s = buf+1;
+ while(*s){
++ lastk = *s;
+ s += chartorune(&r, s);
+ if(utfrune(buf2+1, r) == nil){
+ if(e.data1 = runetokey(r)){
++ if(chat_on && shifton && isprint(lastk))
++ e.data1 = _toupper(e.data1);
+ e.type = ev_keydown;
+ D_PostEvent(&e);
++ if(r == Kshift)
++ shifton++;
+ }
+ }
+ }
+@@ -289,11 +304,14 @@
+ if(e.data1 = runetokey(r)){
+ e.type = ev_keyup;
+ D_PostEvent(&e);
++ if(r == Kshift)
++ shifton = 0;
+ }
+ }
+ }
+ break;
+ }
++ laste = buf[0];
+ strcpy(buf2, buf);
+ }
+ close(kfd);
--- /dev/null
+++ b/doom-limits
@@ -1,0 +1,173 @@
+this lifts a bunch of limits in the engine for stupid bullshit wads that
+don't honor them. this should not be merged, ever. these inflate a bunch
+of arrays, and make doom use much more memory.
+. savegame buffer overflow: for maps that are too large; does not work
+ correctly, loading several times in game will eventually crash (will not
+ corrupt anything though)
+
+diff -Naur a/sys/src/games/doom/g_game.c b/sys/src/games/doom/g_game.c
+--- a/sys/src/games/doom/g_game.c Wed Jul 29 13:45:35 2015
++++ b/sys/src/games/doom/g_game.c Tue Aug 11 15:47:02 2015
+@@ -68,7 +68,7 @@
+ #include "g_game.h"
+
+
+-#define SAVEGAMESIZE 0x2c000
++#define SAVEGAMESIZE 0x200000
+ #define SAVESTRINGSIZE 24
+
+
+@@ -137,6 +137,7 @@
+ short consistancy[MAXPLAYERS][BACKUPTICS];
+
+ byte* savebuffer;
++void *savbuf; /* FIXME */
+
+
+ //
+@@ -1261,7 +1262,10 @@
+ sprintf (name,SAVEGAMENAME"%d.dsg",savegameslot);
+ description = savedescription;
+
+- save_p = savebuffer = screens[1]+0x4000;
++// if(save_p == nil || save_p == savebuffer + SAVESTRINGSIZE)
++ if(savbuf == nil)
++ savbuf = Z_Malloc(SAVEGAMESIZE, PU_STATIC, 0);
++ save_p = savebuffer = savbuf;
+
+ memcpy (save_p, description, SAVESTRINGSIZE);
+ save_p += SAVESTRINGSIZE;
+@@ -1296,7 +1300,7 @@
+ players[consoleplayer].message = GGSAVED;
+
+ // draw the pattern into the back screen
+- R_FillBackScreen ();
++ R_FillBackScreen ();
+ }
+
+
+diff -Naur a/sys/src/games/doom/i_system.c b/sys/src/games/doom/i_system.c
+--- a/sys/src/games/doom/i_system.c Wed Jul 29 18:58:52 2015
++++ b/sys/src/games/doom/i_system.c Tue Aug 11 15:22:39 2015
+@@ -11,7 +11,7 @@
+ #include "g_game.h"
+ #include "m_misc.h"
+
+-int mb_used = 6; /* 6MB heap */
++int mb_used = 12; /* 12MB heap */
+
+ void I_Init (void)
+ {
+diff -Naur a/sys/src/games/doom/p_enemy.c b/sys/src/games/doom/p_enemy.c
+--- a/sys/src/games/doom/p_enemy.c Mon Jul 27 20:08:20 2015
++++ b/sys/src/games/doom/p_enemy.c Tue Aug 11 15:21:28 2015
+@@ -262,7 +262,7 @@
+ fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
+ fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
+
+-#define MAXSPECIALCROSS 8
++#define MAXSPECIALCROSS 128
+
+ extern line_t* spechit[MAXSPECIALCROSS];
+ extern int numspechit;
+diff -Naur a/sys/src/games/doom/p_local.h b/sys/src/games/doom/p_local.h
+--- a/sys/src/games/doom/p_local.h Sun Aug 2 19:57:59 2015
++++ b/sys/src/games/doom/p_local.h Tue Aug 11 15:21:28 2015
+@@ -153,7 +153,7 @@
+ } d;
+ } intercept_t;
+
+-#define MAXINTERCEPTS 128
++#define MAXINTERCEPTS 512
+
+ extern intercept_t intercepts[MAXINTERCEPTS];
+ extern intercept_t* intercept_p;
+diff -Naur a/sys/src/games/doom/p_map.c b/sys/src/games/doom/p_map.c
+--- a/sys/src/games/doom/p_map.c Mon Jul 27 20:08:20 2015
++++ b/sys/src/games/doom/p_map.c Tue Aug 11 15:21:28 2015
+@@ -62,7 +62,7 @@
+
+ // keep track of special lines as they are hit,
+ // but don't process them until the move is proven valid
+-#define MAXSPECIALCROSS 8
++#define MAXSPECIALCROSS 128
+
+ line_t* spechit[MAXSPECIALCROSS];
+ int numspechit;
+diff -Naur a/sys/src/games/doom/p_spec.c b/sys/src/games/doom/p_spec.c
+--- a/sys/src/games/doom/p_spec.c Mon Jul 27 20:08:20 2015
++++ b/sys/src/games/doom/p_spec.c Tue Aug 11 15:21:28 2015
+@@ -78,7 +78,7 @@
+
+
+
+-#define MAXANIMS 32
++#define MAXANIMS 256
+
+ extern anim_t anims[MAXANIMS];
+ extern anim_t* lastanim;
+@@ -321,7 +321,7 @@
+ // Note: this should be doable w/o a fixed array.
+
+ // 20 adjoining sectors max!
+-#define MAX_ADJOINING_SECTORS 20
++#define MAX_ADJOINING_SECTORS 128
+
+ fixed_t
+ P_FindNextHighestFloor
+diff -Naur a/sys/src/games/doom/r_bsp.c b/sys/src/games/doom/r_bsp.c
+--- a/sys/src/games/doom/r_bsp.c Mon Jul 27 20:08:20 2015
++++ b/sys/src/games/doom/r_bsp.c Tue Aug 11 15:21:28 2015
+@@ -85,7 +85,7 @@
+ } cliprange_t;
+
+
+-#define MAXSEGS 32
++#define MAXSEGS SCREENWIDTH/2+1
+
+ // newend is one past the last valid seg
+ cliprange_t* newend;
+diff -Naur a/sys/src/games/doom/r_defs.h b/sys/src/games/doom/r_defs.h
+--- a/sys/src/games/doom/r_defs.h Mon Jul 27 20:08:20 2015
++++ b/sys/src/games/doom/r_defs.h Tue Aug 11 15:21:28 2015
+@@ -52,7 +52,7 @@
+ #define SIL_TOP 2
+ #define SIL_BOTH 3
+
+-#define MAXDRAWSEGS 256
++#define MAXDRAWSEGS 1024
+
+
+
+diff -Naur a/sys/src/games/doom/r_plane.c b/sys/src/games/doom/r_plane.c
+--- a/sys/src/games/doom/r_plane.c Mon Jul 27 20:08:20 2015
++++ b/sys/src/games/doom/r_plane.c Tue Aug 11 15:21:28 2015
+@@ -47,14 +47,14 @@
+ //
+
+ // Here comes the obnoxious "visplane".
+-#define MAXVISPLANES 128
++#define MAXVISPLANES 1024
+ visplane_t visplanes[MAXVISPLANES];
+ visplane_t* lastvisplane;
+ visplane_t* floorplane;
+ visplane_t* ceilingplane;
+
+ // ?
+-#define MAXOPENINGS SCREENWIDTH*64
++#define MAXOPENINGS SCREENWIDTH*200
+ short openings[MAXOPENINGS];
+ short* lastopening;
+
+diff -Naur a/sys/src/games/doom/r_things.h b/sys/src/games/doom/r_things.h
+--- a/sys/src/games/doom/r_things.h Mon Jul 27 20:08:20 2015
++++ b/sys/src/games/doom/r_things.h Tue Aug 11 15:21:28 2015
+@@ -24,7 +24,7 @@
+ #define __R_THINGS__
+
+
+-#define MAXVISSPRITES 128
++#define MAXVISSPRITES 1024
+
+ extern vissprite_t vissprites[MAXVISSPRITES];
+ extern vissprite_t* vissprite_p;
--- /dev/null
+++ b/doom-mouseglitches
@@ -1,0 +1,59 @@
+doom: fix glitchy mouse movement
+
+- fix stuttering mouse movement by using all mouse deltas during a tic, not
+ just the last one (G_Responder can be called more than once per tic)
+- change mouse filtering and sensitivity calculation: divide mouse delta by
+ half, casting to double, and only then multiply by sensitivity
+
+10 * Δ * (sens+5) / 10 → Δ * 0.5 * sens
+with sens in [1;10]
+
+diff -r 121def0aed4d sys/src/games/doom/g_game.c
+--- a/sys/src/games/doom/g_game.c Thu Jul 12 09:33:33 2018 +0200
++++ b/sys/src/games/doom/g_game.c Sat Jul 14 09:32:51 2018 +0200
+@@ -566,8 +566,8 @@
+ mousebuttons[0] = ev->data1 & 1;
+ mousebuttons[1] = ev->data1 & 2;
+ mousebuttons[2] = ev->data1 & 4;
+- mousex = ev->data2*(mouseSensitivity+5)/10;
+- mousey = ev->data3*(mouseSensitivity+5)/10;
++ mousex += ev->data2*0.5*(mouseSensitivity+1);
++ mousey += ev->data3*0.5*(mouseSensitivity+1);
+ return true; // eat events
+
+ case ev_joystick:
+diff -r 121def0aed4d sys/src/games/doom/i_video.c
+--- a/sys/src/games/doom/i_video.c Thu Jul 12 09:33:33 2018 +0200
++++ b/sys/src/games/doom/i_video.c Sat Jul 14 09:32:51 2018 +0200
+@@ -362,8 +362,8 @@
+
+ e.type = ev_mouse;
+ e.data1 = m.buttons;
+- e.data2 = 10*(m.xy.x - om.xy.x);
+- e.data3 = 10*(om.xy.y - m.xy.y);
++ e.data2 = m.xy.x - om.xy.x;
++ e.data3 = om.xy.y - m.xy.y;
+ D_PostEvent(&e);
+ om = m;
+
+diff -r 121def0aed4d sys/src/games/doom/m_menu.c
+--- a/sys/src/games/doom/m_menu.c Thu Jul 12 09:33:33 2018 +0200
++++ b/sys/src/games/doom/m_menu.c Sat Jul 14 09:32:51 2018 +0200
+@@ -945,7 +945,7 @@
+ W_CacheLumpName(msgNames[showMessages],PU_CACHE));
+
+ M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(mousesens+1),
+- 10,mouseSensitivity);
++ 9,mouseSensitivity);
+
+ M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1),
+ 9,screenSize);
+@@ -1099,7 +1099,7 @@
+ mouseSensitivity--;
+ break;
+ case 1:
+- if (mouseSensitivity < 9)
++ if (mouseSensitivity < 8)
+ mouseSensitivity++;
+ break;
+ }
--- /dev/null
+++ b/doom-mousegrab
@@ -1,0 +1,32 @@
+doom: re-center mouse more often to limit it escaping
+
+when a mouse motion reaches grabout's limits without crossing them, a following
+event in which the mouse passes the remaining distance between grabout and the
+window's limits will have the mouse jump out of the window.
+this happens too frequently on terminals with a good drawing speed.
+
+to reduce this, make grabout smaller, so that the distance to cross in one
+event is larger. Dx(screen->r)/4 is sufficient for the terminals i have tested
+this on.
+
+diff -r 0a3cf47fce65 sys/src/games/doom/i_video.c
+--- a/sys/src/games/doom/i_video.c Mon Jun 27 00:36:54 2016 +0200
++++ b/sys/src/games/doom/i_video.c Thu Jun 30 17:51:32 2016 +0300
+@@ -44,7 +44,7 @@
+ draw(screen, screen->r, display->black, nil, ZP);
+
+ center = addpt(screen->r.min, Pt(Dx(screen->r)/2, Dy(screen->r)/2));
+- grabout = insetrect(screen->r, Dx(screen->r)/8);
++ grabout = insetrect(screen->r, Dx(screen->r)/4);
+
+ if((pid = rfork(RFPROC|RFMEM)) == 0){
+ kbdproc();
+@@ -102,7 +102,7 @@
+ draw(screen, screen->r, display->black, nil, ZP);
+
+ center = addpt(screen->r.min, Pt(Dx(screen->r)/2, Dy(screen->r)/2));
+- grabout = insetrect(screen->r, Dx(screen->r)/8);
++ grabout = insetrect(screen->r, Dx(screen->r)/4);
+ }
+
+ scale = Dx(screen->r)/SCREENWIDTH;
--- /dev/null
+++ b/doom-naivescaleup
@@ -1,0 +1,64 @@
+ups max scale in an idiotic way
+
+diff -r 7ee51d8d1eb9 sys/src/games/doom/i_video.c
+--- a/sys/src/games/doom/i_video.c Thu May 11 19:34:54 2017 +0000
++++ b/sys/src/games/doom/i_video.c Mon May 15 14:46:26 2017 +0200
+@@ -91,7 +91,7 @@
+ Rectangle r;
+ int y, scale;
+ uchar *s, *e, *d, *m;
+- uchar buf[SCREENWIDTH*3*4];
++ uchar buf[SCREENWIDTH*3*12];
+
+ if(resized){
+ resized = 0;
+@@ -108,8 +108,8 @@
+ scale = Dx(screen->r)/SCREENWIDTH;
+ if(scale <= 0)
+ scale = 1;
+- else if(scale > 4)
+- scale = 4;
++ else if(scale > 12)
++ scale = 12;
+
+ /* where to draw the scaled row */
+ r = rectsubpt(rectaddpt(Rect(0, 0, scale*SCREENWIDTH, scale), center),
+@@ -127,6 +127,38 @@
+ for(; s < e; s++){
+ m = &cmap[*s * 3];
+ switch(scale){
++ case 12:
++ *d++ = m[2];
++ *d++ = m[1];
++ *d++ = m[0];
++ case 11:
++ *d++ = m[2];
++ *d++ = m[1];
++ *d++ = m[0];
++ case 10:
++ *d++ = m[2];
++ *d++ = m[1];
++ *d++ = m[0];
++ case 9:
++ *d++ = m[2];
++ *d++ = m[1];
++ *d++ = m[0];
++ case 8:
++ *d++ = m[2];
++ *d++ = m[1];
++ *d++ = m[0];
++ case 7:
++ *d++ = m[2];
++ *d++ = m[1];
++ *d++ = m[0];
++ case 6:
++ *d++ = m[2];
++ *d++ = m[1];
++ *d++ = m[0];
++ case 5:
++ *d++ = m[2];
++ *d++ = m[1];
++ *d++ = m[0];
+ case 4:
+ *d++ = m[2];
+ *d++ = m[1];
--- /dev/null
+++ b/doom-nodclick
@@ -1,0 +1,99 @@
+doom: remove mouse double click and don't move forward with button 3
+
+diff -r bd0ff7078273 sys/src/games/doom/g_game.c
+--- a/sys/src/games/doom/g_game.c Mon Aug 28 19:45:49 2017 +0200
++++ b/sys/src/games/doom/g_game.c Wed Aug 30 10:20:53 2017 +0200
+@@ -187,13 +187,6 @@
+ int mousex;
+ int mousey;
+
+-int dclicktime;
+-int dclickstate;
+-int dclicks;
+-int dclicktime2;
+-int dclickstate2;
+-int dclicks2;
+-
+ // joystick values are repeated
+ int joyxmove;
+ int joyymove;
+@@ -235,7 +228,6 @@
+ {
+ int i;
+ boolean strafe;
+- boolean bstrafe;
+ int speed;
+ int tspeed;
+ int forward;
+@@ -329,11 +321,7 @@
+ cmd->buttons |= BT_ATTACK;
+
+ if (gamekeydown[key_use] || joybuttons[joybuse] )
+- {
+ cmd->buttons |= BT_USE;
+- // clear double clicks if hit use button
+- dclicks = 0;
+- }
+
+ // chainsaw overrides
+ for (i=0 ; i<NUMWEAPONS-1 ; i++)
+@@ -346,58 +334,7 @@
+
+ // mouse
+ if (mousebuttons[mousebforward])
+- forward += forwardmove[speed];
+-
+- // forward double click
+- if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1 )
+- {
+- dclickstate = mousebuttons[mousebforward];
+- if (dclickstate)
+- dclicks++;
+- if (dclicks == 2)
+- {
+- cmd->buttons |= BT_USE;
+- dclicks = 0;
+- }
+- else
+- dclicktime = 0;
+- }
+- else
+- {
+- dclicktime += ticdup;
+- if (dclicktime > 20)
+- {
+- dclicks = 0;
+- dclickstate = 0;
+- }
+- }
+-
+- // strafe double click
+- bstrafe =
+- mousebuttons[mousebstrafe]
+- || joybuttons[joybstrafe];
+- if (bstrafe != dclickstate2 && dclicktime2 > 1 )
+- {
+- dclickstate2 = bstrafe;
+- if (dclickstate2)
+- dclicks2++;
+- if (dclicks2 == 2)
+- {
+- cmd->buttons |= BT_USE;
+- dclicks2 = 0;
+- }
+- else
+- dclicktime2 = 0;
+- }
+- else
+- {
+- dclicktime2 += ticdup;
+- if (dclicktime2 > 20)
+- {
+- dclicks2 = 0;
+- dclickstate2 = 0;
+- }
+- }
++ cmd->buttons |= BT_USE;
+
+ forward += mousey;
+ if (strafe)
--- /dev/null
+++ b/doom-skywallhit
@@ -1,0 +1,76 @@
+bullet puffs and plasma splashes don't spawn, and rockets don't explode,
+when fired against a linedef bridging two sectors of differing heights but
+with a sky texture. example: ultimate doom e4m6: fire at the green
+structure surrounded by a moat of lava outside, or at the moat's walls.
+the "sky hack" is meant to show the sky (in this particular configuration)
+rather than a texture, and to make projectiles disappear when fired at this
+"sky". however, the check for the wall's attributes and the projectiles
+coordinates is wrong.
+this patches fixes that. however, it affects gameplay, and as such, demos
+will desync anytime this mechanism is encountered. it is therefore turned
+off by default.
+not sure if this should be merged.
+TODO: better explanation, more testing
+
+diff -Naur a/sys/src/games/doom/d_main.c b/sys/src/games/doom/d_main.c
+--- a/sys/src/games/doom/d_main.c Sun Aug 2 19:57:59 2015
++++ b/sys/src/games/doom/d_main.c Fri Aug 21 15:09:01 2015
+@@ -94,6 +94,8 @@
+ boolean noztele;
+ boolean nobounce;
+
++/* demo breaking bug fixes */
++boolean noskyabs;
+
+ //extern int soundVolume;
+ //extern int sfxVolume;
+@@ -743,6 +745,8 @@
+ noztele = 1;
+ if (M_CheckParm ("-nobounce") && (gamemode == commercial || gamemode == registered))
+ nobounce = 1;
++ if (M_CheckParm ("-noskyabs"))
++ noskyabs = 1;
+ if (M_CheckParm ("-altdeath"))
+ deathmatch = 2;
+ else if (M_CheckParm ("-deathmatch"))
+diff -Naur a/sys/src/games/doom/p_local.h b/sys/src/games/doom/p_local.h
+--- a/sys/src/games/doom/p_local.h Sun Aug 2 19:57:59 2015
++++ b/sys/src/games/doom/p_local.h Fri Aug 21 15:05:02 2015
+@@ -62,6 +62,7 @@
+
+ extern boolean noztele;
+ extern boolean nobounce;
++extern boolean noskyabs;
+
+
+ //
+diff -Naur a/sys/src/games/doom/p_map.c b/sys/src/games/doom/p_map.c
+--- a/sys/src/games/doom/p_map.c Mon Jul 27 20:08:20 2015
++++ b/sys/src/games/doom/p_map.c Fri Aug 21 15:10:30 2015
+@@ -958,7 +958,8 @@
+ return false;
+
+ // it's a sky hack wall
+- if (li->backsector && li->backsector->ceilingpic == skyflatnum)
++ if (li->backsector != nil && li->backsector->ceilingpic == skyflatnum
++ && (!noskyabs || z > li->backsector->ceilingheight))
+ return false;
+ }
+
+diff -Naur a/sys/src/games/doom/p_mobj.c b/sys/src/games/doom/p_mobj.c
+--- a/sys/src/games/doom/p_mobj.c Sun Aug 2 19:57:59 2015
++++ b/sys/src/games/doom/p_mobj.c Fri Aug 21 15:03:11 2015
+@@ -173,9 +173,10 @@
+ else if (mo->flags & MF_MISSILE)
+ {
+ // explode a missile
+- if (ceilingline &&
+- ceilingline->backsector &&
+- ceilingline->backsector->ceilingpic == skyflatnum)
++ if (ceilingline != nil &&
++ ceilingline->backsector != nil &&
++ ceilingline->backsector->ceilingpic == skyflatnum &&
++ (!noskyabs || mo->z > ceilingline->backsector->ceilingheight))
+ {
+ // Hack to prevent missiles exploding
+ // against the sky.
--- /dev/null
+++ b/doom-spy
@@ -1,0 +1,57 @@
+diff -Naur a/sys/src/games/doom/g_game.c b/sys/src/games/doom/g_game.c
+--- a/sys/src/games/doom/g_game.c Mon Aug 31 01:13:18 2015
++++ b/sys/src/games/doom/g_game.c Wed Sep 16 08:16:55 2015
+@@ -510,6 +510,9 @@
+ displayplayer++;
+ if (displayplayer == MAXPLAYERS)
+ displayplayer = 0;
++ /* FIXME */
++ extern player_t *plyr;
++ plyr = &players[displayplayer];
+ } while (!playeringame[displayplayer] && displayplayer != consoleplayer);
+ return true;
+ }
+diff -Naur a/sys/src/games/doom/s_sound.c b/sys/src/games/doom/s_sound.c
+--- a/sys/src/games/doom/s_sound.c Sun Jul 29 23:01:33 2012
++++ b/sys/src/games/doom/s_sound.c Wed Sep 16 08:16:08 2015
+@@ -38,6 +38,7 @@
+
+ #include "doomstat.h"
+
++extern player_t *plyr;
+
+ // Purpose?
+ const char snd_prefixen[]
+@@ -281,16 +282,16 @@
+
+ // Check to see if it is audible,
+ // and if not, modify the params
+- if (origin && origin != players[consoleplayer].mo)
++ if (origin && origin != plyr->mo)
+ {
+- rc = S_AdjustSoundParams(players[consoleplayer].mo,
++ rc = S_AdjustSoundParams(plyr->mo,
+ origin,
+ &volume,
+ &sep,
+ &pitch);
+
+- if ( origin->x == players[consoleplayer].mo->x
+- && origin->y == players[consoleplayer].mo->y)
++ if ( origin->x == plyr->mo->x
++ && origin->y == plyr->mo->y)
+ {
+ sep = NORM_SEP;
+ }
+diff -Naur a/sys/src/games/doom/st_stuff.c b/sys/src/games/doom/st_stuff.c
+--- a/sys/src/games/doom/st_stuff.c Mon Aug 17 23:00:05 2015
++++ b/sys/src/games/doom/st_stuff.c Wed Sep 16 08:14:48 2015
+@@ -264,7 +264,7 @@
+
+
+ // main player in game
+-static player_t* plyr;
++player_t* plyr;
+
+ // ST_Start() has just been called
+ static boolean st_firsttime;
--- /dev/null
+++ b/doom-udpip
@@ -1,0 +1,507 @@
+port udp/ip code from release.
+this works, but parts of the code suck and need to be altered. what sucks
+is that the doom networking protocol is shit. it's a peer-to-peer thing
+where each node needs to send frame information (ticcmd's) to every other
+node, and receive ticcmd's from every other node. any node that has a
+slower connection or is a slower machine will bring the game down for
+everyone. also, high bandwidth required.
+
+shitfuck n2: no port uses this protocol, since it sucks, and everyone
+implements their own incompatible crap, so no one port can talk to another,
+besides maybe the ports back to DOS. the code in i_net.c is unlikely to
+change too much though, unless this implementation is amended.
+one idea is to ask for chocolate-doom's networking protocol specs.
+chocolate-doom works fairly well, and supports a bunch of different OS',
+including openbsd, and being able to connect with 9front doom to another
+OS' shit is advanteageous, at least because live servers with bunches of
+players will be accessible. 9front doom and chocolate-doom _should_ be
+compatible, but idk.
+as it is, sdldoom might be able to connect to 9front doom with this patch,
+but good luck making sdldoom work.
+
+player 0 is special, and sets the game settings, sending them to the other
+nodes.
+testing this is more difficult without other patches because of the issues
+in the sound code, so try with doom-sndmus.patch and doom-sleep.patch.
+
+syntax: doom [-srv port] [-pn 0-3] [-net host!port...]
+defaults: udp port 666, player number 0
+
+example for a 3 player game, two nodes being on the same host (for shits):
+u14% games/doom -altdeath -nomonsters -warp7 -net u6!666 u14!667
+u6% games/doom -pn 1 -net u14!666 u14!667
+u14-1% games/doom -pn 2 -srv 667 -net u14!666 u6!666
+
+TODO: cf FIXME's in the code, conreq shit, more testing(?)
+
+diff -Naur a/sys/src/games/doom/i_net.c b/sys/src/games/doom/i_net.c
+--- a/sys/src/games/doom/i_net.c Wed Jan 18 01:13:24 2012
++++ b/sys/src/games/doom/i_net.c Wed Sep 16 06:45:07 2015
+@@ -20,142 +20,298 @@
+ //
+ //-----------------------------------------------------------------------------
+
+-static const char
+-rcsid[] = "$Id: m_bbox.c,v 1.1 1997/02/03 22:45:10 b1 Exp $";
+-
+ #include "doomdef.h"
+ #include "doomstat.h"
+-
+-// #include "i_system.h"
+-// #include "d_event.h"
+-#include "d_net.h"
++#include <bio.h>
++#include <ndb.h>
++#include <ip.h>
+ #include "m_argv.h"
+-
++#include "i_system.h"
++#include "d_net.h"
+ #include "i_net.h"
++#include "w_wad.h"
+
++typedef struct Addr Addr;
+
+-//
+-// I_InitNetwork
+-//
+-void I_InitNetwork (void)
+-{
+-printf("PORTME i_net.c I_InitNetwork (use 9P)\n");
++enum{
++ HDRSZ = 16+16+16+2+2 /* sizeof Udphdr w/o padding */
++};
+
+- doomcom = malloc (sizeof(*doomcom));
+- memset (doomcom, 0, sizeof(*doomcom));
++static char lsrv[6] = "666";
+
+- /* set up for network */
+- doomcom->ticdup = 1;
+- doomcom->extratics = 0;
++struct Addr{
++ Udphdr h;
++ char srv[6]; /* convenience */
++ int ready; /* is connected to udp!*!lsrv */
++ long called;
++};
++static Addr raddr[MAXNETNODES];
+
+-// netsend = PacketSend;
+-// netget = PacketGet;
+-// netgame = true;
++static int ucfd;
++static int udfd;
++static int upfd[2];
++static int upid;
+
+- /* parse player number and host list */
+-// doomcom->consoleplayer = myargv[i+1][0]-'1';
+
+- doomcom->numnodes = 1; // this node for sure
++static void
++conreq(doomdata_t *d)
++{
++ int fd;
++ long t;
++ char ip[64];
++ Addr *p;
++
++ p = &raddr[doomcom->remotenode];
++
++ t = time(nil);
++ if(t - p->called < 1)
++ return;
++
++ snprint(ip, sizeof ip, "%I", p->h.raddr);
++ if((fd = dial(netmkaddr(ip, "udp", p->srv), lsrv, nil, nil)) < 0)
++ sysfatal("dial: %r");
++ if(write(fd, d, doomcom->datalength) != doomcom->datalength)
++ sysfatal("conreq: %r");
++ close(fd);
++ p->called = t;
++}
+
+- doomcom->id = DOOMCOM_ID;
+- doomcom->numplayers = doomcom->numnodes;
++static void
++dsend(void)
++{
++ int i;
++ uchar buf[HDRSZ+sizeof(doomdata_t)];
++ doomdata_t d;
++
++ hnputl(&d.checksum, netbuffer->checksum);
++ d.player = netbuffer->player;
++ d.retransmitfrom = netbuffer->retransmitfrom;
++ d.starttic = netbuffer->starttic;
++ d.numtics = netbuffer->numtics;
++
++ for(i = 0; i < netbuffer->numtics; i++){
++ d.cmds[i].forwardmove = netbuffer->cmds[i].forwardmove;
++ d.cmds[i].sidemove = netbuffer->cmds[i].sidemove;
++ hnputs(&d.cmds[i].angleturn, netbuffer->cmds[i].angleturn);
++ hnputs(&d.cmds[i].consistancy, netbuffer->cmds[i].consistancy);
++ d.cmds[i].chatchar = netbuffer->cmds[i].chatchar;
++ d.cmds[i].buttons = netbuffer->cmds[i].buttons;
++ }
+
+-/*
+- boolean trueval = true;
+- int i;
+- int p;
+- struct hostent* hostentry; // host information entry
+-
+- doomcom = malloc (sizeof (*doomcom) );
+- memset (doomcom, 0, sizeof(*doomcom) );
+-
+- // set up for network
+- i = M_CheckParm ("-dup");
+- if (i && i< myargc-1)
+- {
+- doomcom->ticdup = myargv[i+1][0]-'0';
+- if (doomcom->ticdup < 1)
+- doomcom->ticdup = 1;
+- if (doomcom->ticdup > 9)
+- doomcom->ticdup = 9;
+- }
+- else
+- doomcom-> ticdup = 1;
+-
+- if (M_CheckParm ("-extratic"))
+- doomcom-> extratics = 1;
+- else
+- doomcom-> extratics = 0;
+-
+- p = M_CheckParm ("-port");
+- if (p && p<myargc-1)
+- {
+- DOOMPORT = atoi (myargv[p+1]);
+- printf ("using alternate port %i\n",DOOMPORT);
+- }
+-
+- // parse network game options,
+- // -net <consoleplayer> <host> <host> ...
+- i = M_CheckParm ("-net");
+- if (!i)
+- {
+- // single player game
+- netgame = false;
+- doomcom->id = DOOMCOM_ID;
+- doomcom->numplayers = doomcom->numnodes = 1;
+- doomcom->deathmatch = false;
+- doomcom->consoleplayer = 0;
+- return;
+- }
+-
+- netsend = PacketSend;
+- netget = PacketGet;
+- netgame = true;
+-
+- // parse player number and host list
+- doomcom->consoleplayer = myargv[i+1][0]-'1';
+-
+- doomcom->numnodes = 1; // this node for sure
+-
+- i++;
+- while (++i < myargc && myargv[i][0] != '-')
+- {
+- sendaddress[doomcom->numnodes].sin_family = AF_INET;
+- sendaddress[doomcom->numnodes].sin_port = htons(DOOMPORT);
+- if (myargv[i][0] == '.')
+- {
+- sendaddress[doomcom->numnodes].sin_addr.s_addr
+- = inet_addr (myargv[i]+1);
++ if(!raddr[doomcom->remotenode].ready){
++ conreq(&d);
++ return;
+ }
++ memcpy(buf, &raddr[doomcom->remotenode].h, HDRSZ);
++ memcpy(buf+HDRSZ, &d, sizeof d);
++
++ i = doomcom->datalength + HDRSZ;
++ if(write(udfd, buf, i) != i)
++ sysfatal("dsend: %r");
++}
++
++static void
++drecv(void)
++{
++ int n;
++ ushort i;
++ doomdata_t d;
++
++ if(filelength(upfd[1]) < 1){
++ doomcom->remotenode = -1;
++ return;
++ }
++ if((n = read(upfd[1], &d, sizeof d)) <= 0
++ || read(upfd[1], &i, sizeof i) <= 0)
++ sysfatal("drecv: %r");
++
++ doomcom->remotenode = i;
++ doomcom->datalength = n;
++
++ /* FIXME: proper read/write from/to struct */
++ netbuffer->checksum = nhgetl(&d.checksum);
++ netbuffer->player = d.player;
++ netbuffer->retransmitfrom = d.retransmitfrom;
++ netbuffer->starttic = d.starttic;
++ netbuffer->numtics = d.numtics;
++ for(i = 0; i < netbuffer->numtics; i++){
++ netbuffer->cmds[i].forwardmove = d.cmds[i].forwardmove;
++ netbuffer->cmds[i].sidemove = d.cmds[i].sidemove;
++ netbuffer->cmds[i].angleturn = nhgets(&d.cmds[i].angleturn);
++ netbuffer->cmds[i].consistancy = nhgets(&d.cmds[i].consistancy);
++ netbuffer->cmds[i].chatchar = d.cmds[i].chatchar;
++ netbuffer->cmds[i].buttons = d.cmds[i].buttons;
++ }
++}
++
++static void
++uproc(void)
++{
++ int n;
++ ushort i;
++ uchar buf[HDRSZ+sizeof(doomdata_t)];
++ Udphdr h;
++
++ for(;;){
++ if((n = read(udfd, buf, sizeof buf)) <= 0)
++ break;
++ memcpy(&h, buf, HDRSZ);
++
++ for(i = 0; i < doomcom->numnodes; i++)
++ if(equivip6(h.raddr, raddr[i].h.raddr)
++ && nhgets(h.rport) == nhgets(raddr[i].h.rport))
++ break;
++ if(i == doomcom->numnodes)
++ continue; /* ignore messages from strangers */
++ if(!raddr[i].ready){ /* FIXME: urgh */
++ raddr[i].ready++;
++ memcpy(&raddr[i].h, &h, sizeof h);
++ }
++
++ if(write(upfd[0], buf+HDRSZ, n - HDRSZ) != n - HDRSZ
++ || write(upfd[0], &i, sizeof i) != sizeof i)
++ break;
++ }
++}
++
++void
++I_NetCmd(void)
++{
++ if(doomcom->command == CMD_SEND)
++ dsend();
++ else if(doomcom->command == CMD_GET)
++ drecv();
+ else
+- {
+- hostentry = gethostbyname (myargv[i]);
+- if (!hostentry)
+- I_Error ("gethostbyname: couldn't find %s", myargv[i]);
+- sendaddress[doomcom->numnodes].sin_addr.s_addr
+- = *(int *)hostentry->h_addr_list[0];
+- }
+- doomcom->numnodes++;
+- }
+-
+- doomcom->id = DOOMCOM_ID;
+- doomcom->numplayers = doomcom->numnodes;
+-*/
++ I_Error("invalid netcmd %d", doomcom->command);
++}
++
++void
++I_ShutdownNet(void)
++{
++ postnote(PNPROC, upid, "shutdown");
++ close(upfd[0]);
++ close(upfd[1]);
++ close(udfd);
++ close(ucfd);
++}
++
++static void
++initudp(void)
++{
++ int pid;
++ char data[64], adir[40];
++
++ /* FIXME */
++ //if(myipaddr(raddr[0].h.raddr, nil) < 0)
++ // sysfatal("myipaddr: %r");
++
++ if((ucfd = announce(netmkaddr("*", "udp", lsrv), adir)) < 0)
++ sysfatal("announce: %r");
++ if(fprint(ucfd, "headers") < 0)
++ sysfatal("failed to set headers mode: %r");
++ snprint(data, sizeof data, "%s/data", adir);
++ if((udfd = open(data, ORDWR)) < 0)
++ sysfatal("open: %r");
++
++ if(pipe(upfd) < 0)
++ sysfatal("pipe: %r");
++ if((pid = rfork(RFPROC|RFMEM|RFFDG)) == 0){
++ uproc();
++ exits(nil);
++ }
++ upid = pid;
++}
++
++static void
++csip(char *s, Addr *a) /* raddr!rsrv */
++{
++ int fd, n;
++ char buf[128], *f[3];
++
++ /* FIXME: get netmnt... */
++
++ if((fd = open("/net/cs", ORDWR)) < 0)
++ sysfatal("open: %r");
++
++ snprint(buf, sizeof buf, "udp!%s", s);
++ n = strlen(buf);
++ if(write(fd, buf, n) != n)
++ sysfatal("translating %s: %r", s);
++
++ seek(fd, 0, 0);
++ if((n = read(fd, buf, sizeof(buf)-1)) <= 0)
++ sysfatal("reading cs tables: %r");
++ buf[n] = 0;
++ close(fd);
++
++ if(getfields(buf, f, 3, 1, " !") < 2)
++ sysfatal("bad cs entry %s", buf);
++
++ if(parseip(a->h.raddr, f[1]) < 0)
++ sysfatal("parseip: %r");
++ hnputs(a->h.rport, atoi(f[2])); /* FIXME */
++ strncpy(a->srv, f[2], sizeof(a->srv)-1);
++}
++
++static int
++netopts(void)
++{
++ int i;
++
++ if((i = M_CheckParm("-dup")) && i < myargc - 1){
++ doomcom->ticdup = myargv[i+1][0] - '0';
++ if(doomcom->ticdup < 1)
++ doomcom->ticdup = 1;
++ if(doomcom->ticdup > 9)
++ doomcom->ticdup = 9;
++ }
++
++ if(M_CheckParm("-extratic"))
++ doomcom->extratics = 1;
++
++ if((i = M_CheckParm("-srv")) && i < myargc - 1)
++ strncpy(lsrv, myargv[i+1], sizeof(lsrv)-1);
++
++ /* [0-3], default 0; player 0 is special */
++ if((i = M_CheckParm("-pn")) && i < myargc - 1)
++ doomcom->consoleplayer = myargv[i+1][0] - '0';
++
++ /* FIXME: d_net.c: don't use remoteaddr=0 as special case (max+1?) */
++ /* remote host address list: -net raddr!rsrv.. */
++ if((i = M_CheckParm("-net")) == 0){
++ /* single player game */
++ doomcom->id = DOOMCOM_ID;
++ doomcom->numplayers = doomcom->numnodes = 1;
++ doomcom->deathmatch = false;
++ netgame = false;
++ return -1;
++ }
++ doomcom->numnodes++; /* raddr[0] is special cased because ??? */
++ while(++i < myargc && myargv[i][0] != '-'){
++ csip(myargv[i], &raddr[doomcom->numnodes]);
++ doomcom->numnodes++;
++ }
++
++ return 0;
+ }
+
++void
++I_InitNetwork(void)
++{
++ doomcom = malloc(sizeof *doomcom);
++ memset(doomcom, 0, sizeof *doomcom);
++
++ doomcom->ticdup = 1;
++ doomcom->extratics = 0;
++ if(netopts() < 0)
++ return;
++ if(doomcom->numnodes < 2)
++ I_Error("netgame with a single node");
++ doomcom->id = DOOMCOM_ID;
++ doomcom->numplayers = doomcom->numnodes;
++
++ fmtinstall('I', eipfmt);
++ initudp();
+
+-void I_NetCmd (void)
+-{
+-/*
+- if (doomcom->command == CMD_SEND)
+- {
+- netsend ();
+- }
+- else if (doomcom->command == CMD_GET)
+- {
+- netget ();
+- }
+- else
+- I_Error ("Bad net cmd: %i\n",doomcom->command);
+-*/
++ netgame = true;
+ }
+diff -Naur a/sys/src/games/doom/i_net.h b/sys/src/games/doom/i_net.h
+--- a/sys/src/games/doom/i_net.h Wed Jan 18 01:13:23 2012
++++ b/sys/src/games/doom/i_net.h Wed Sep 16 06:36:09 2015
+@@ -35,6 +35,7 @@
+
+ void I_InitNetwork (void);
+ void I_NetCmd (void);
++void I_ShutdownNet (void);
+
+
+ #endif
+diff -Naur a/sys/src/games/doom/i_system.c b/sys/src/games/doom/i_system.c
+--- a/sys/src/games/doom/i_system.c Wed Feb 5 08:58:15 2014
++++ b/sys/src/games/doom/i_system.c Wed Sep 16 06:36:09 2015
+@@ -6,6 +6,7 @@
+ #include "i_system.h"
+ #include "i_sound.h"
+ #include "i_video.h"
++#include "i_net.h"
+
+ #include "d_net.h"
+ #include "g_game.h"
+@@ -41,6 +42,7 @@
+ void I_Quit (void)
+ {
+ D_QuitNetGame ();
++ I_ShutdownNet();
+ I_ShutdownSound();
+ I_ShutdownMusic();
+ M_SaveDefaults ();
+@@ -85,6 +87,7 @@
+ G_CheckDemoStatus();
+
+ D_QuitNetGame ();
++ I_ShutdownNet();
+ I_ShutdownGraphics();
+
+ exits("I_Error");
+diff -Naur a/sys/src/games/doom/w_wad.h b/sys/src/games/doom/w_wad.h
+--- a/sys/src/games/doom/w_wad.h Wed Jan 18 01:13:24 2012
++++ b/sys/src/games/doom/w_wad.h Wed Sep 16 06:38:33 2015
+@@ -67,6 +67,7 @@
+ void* W_CacheLumpNum (int lump, int tag);
+ void* W_CacheLumpName (char* name, int tag);
+
++vlong filelength(int);
+
+
+
--- /dev/null
+++ b/doomn-sawup
@@ -1,0 +1,60 @@
+does not work. second part should also be removed.
+
+diff -Naur a/sys/src/games/doom/i_sound.c b/sys/src/games/doom/i_sound.c
+--- a/sys/src/games/doom/i_sound.c Wed Jul 29 13:45:35 2015
++++ b/sys/src/games/doom/i_sound.c Sun Aug 2 23:51:32 2015
+@@ -333,33 +333,21 @@
+ int rightvol;
+ int leftvol;
+
+- /* Chainsaw troubles.
+- ** Play these sound effects only one at a time. */
+- if ( id == sfx_sawup ||
+- id == sfx_sawidl ||
+- id == sfx_sawful ||
+- id == sfx_sawhit ||
+- id == sfx_stnmov ||
+- id == sfx_pistol )
++ for (i=0 ; (i<NUM_CHANNELS) && (channels[i]) ; i++)
+ {
+- /* Loop all channels, check. */
+- for (i=0 ; i < NUM_CHANNELS ; i++)
+- {
+- /* Active and using the same SFX? */
+- if( (channels[i]) && (channelids[i] == id) )
+- {
+- /* Reset. */
++ if(id == sfx_sawidl && channelids[i] == sfx_sawup) /* don't play during sawup */
++ return 0;
++ if(channelids[i] == id)
++ switch(id){ /* to be played only one at a time */
++ case sfx_sawup:
++ case sfx_sawidl:
++ case sfx_sawful:
++ case sfx_sawhit:
++ case sfx_stnmov:
++ case sfx_pistol:
+ channels[i] = 0;
+- /* We are sure that iff,
+- ** there will only be one. */
+- break;
++ continue;
+ }
+- }
+- }
+-
+- /* Loop all channels to find oldest SFX. */
+- for (i=0 ; (i<NUM_CHANNELS) && (channels[i]) ; i++)
+- {
+ if(channelstart[i] < oldest)
+ {
+ oldestnum = i;
+@@ -383,7 +371,7 @@
+ */
+ channels[slot] = (uchar*) S_sfx[id].data;
+ /* Set pointer to end of raw data. */
+- channelsend[slot] = channels[slot] + lengths[id];
++ channelsend[slot] = channels[slot] + (id == sfx_sawful ? lengths[id] / 2 : lengths[id]);
+
+ /* Reset current handle number, limited to 0..100. */
+ if (!handlenums)
--- /dev/null
+++ b/doomn-sleep
@@ -1,0 +1,17 @@
+this is necessary with doom-sndmus.patch to prevent nsec() being called
+trillions of times per frame because the game is running too fast...
+(i think)
+
+diff -Naur a/sys/src/games/doom/d_net.c b/sys/src/games/doom/d_net.c
+--- a/sys/src/games/doom/d_net.c Fri May 15 05:42:00 2015
++++ b/sys/src/games/doom/d_net.c Wed Sep 16 07:47:17 2015
+@@ -722,7 +722,8 @@
+ {
+ M_Ticker ();
+ return;
+- }
++ }
++ sleep(1);
+ }
+
+ // run the count * ticdup dics
--- /dev/null
+++ b/doomn-waitvbl
@@ -1,0 +1,19 @@
+I_WaitVBL is used as a delay twice: once in the netcode on disconnect, to
+wait a little before sending notice to the next node, and once on exit, to
+allow playing one last sound effect.
+requires doom-sndmus.patch (since sound is handled on a different proc).
+
+diff -Naur a/sys/src/games/doom/i_video.c b/sys/src/games/doom/i_video.c
+--- a/sys/src/games/doom/i_video.c Wed Jul 29 13:45:35 2015
++++ b/sys/src/games/doom/i_video.c Tue Aug 11 14:25:16 2015
+@@ -185,8 +185,9 @@
+ {
+ }
+
+-void I_WaitVBL(int)
++void I_WaitVBL(int s)
+ {
++ sleep(s * (1000/70));
+ }
+
+
--- /dev/null
+++ b/dport-run
@@ -1,0 +1,67 @@
+--- /mnt/git/branch/heads/master/tree/run.c Thu Jun 11 15:28:29 2015
++++ run.c Sun Jan 5 12:25:02 2020
+@@ -100,15 +100,32 @@ setfb(void)
+ if(fprint(fd, "size 1280x1024x32 x8b8g8r8") < 0)
+ // if(fprint(fd, "size 1280x1024x16 r5g6b5") < 0)
+ sysfatal("fprint: %r");
+- if(fprint(fd, "addr %#ux", v) < 0)
++ if(fprint(fd, "addr %#p", v) < 0)
+ sysfatal("fprint: %r");
+ }
+
+ void
++setmouse(void *v)
++{
++ int fd;
++ static int shat;
++
++ if(shat)
++ return;
++ if((fd = open("/dev/mousectl", OWRITE)) < 0)
++ return;
++ if(fprint(fd, "addr %#p", v) < 0)
++ fprint(2, "shit: %r\n");
++ else
++ shat++;
++ close(fd);
++}
++
++void
+ main()
+ {
+ ulong *r;
+- uchar *rr, s, s1;
++ uchar *rr, s;
+ ulong addr;
+ int twolane, fast, emph, swing;
+
+@@ -140,16 +157,17 @@ main()
+ addr = getpa();
+ r[START] = addr;
+ r[END] = addr + 1280*1024*4;
+-// setfb();
++ setfb();
+
+ r[CTRL] = 1<<31;
+ //goto manual;
+ for(;;){
+ sleep(100);
+- print("%ux %x\n", r[STS], rr[0x202]);
++ setmouse(r+CURS);
++ print("%lux %x\n", r[STS], rr[0x202]);
+ }
+
+-manual:
++//manual:
+ r[CTRL] = 1 << 13 | swing << 6 | emph << 4 | twolane << 1 | fast;
+ rr[TRAINING_LANE0_SET] = emph << 4 | swing;
+ rr[LINK_BW_SET] = fast ? 0x0A : 0x06;
+@@ -177,7 +195,7 @@ manual:
+
+ for(;;){
+ sleep(1000);
+- print("%x %x %x\n", r[STS], rr[0x202], rr[0x204]);
++ print("%lx %x %x\n", r[STS], rr[0x202], rr[0x204]);
+ }
+
+ /* r[HVACT] = 1024 << 16 | 768;
--- /dev/null
+++ b/faces-col
@@ -1,0 +1,86 @@
+diff -r a620b482772f sys/src/cmd/faces/main.c
+--- a/sys/src/cmd/faces/main.c Sun Mar 18 07:53:10 2018 +0100
++++ b/sys/src/cmd/faces/main.c Wed Mar 21 02:18:49 2018 +0200
+@@ -53,8 +53,10 @@
+ 0x18, 0x00, 0x00, 0x10, 0x00
+ };
+
+-Image *blue; /* full arrow */
+-Image *bgrnd; /* pale blue background color */
++Image *arrow; /* full arrow */
++Image *smallfg;
++Image *bgrnd; /* background color */
++Image *facebg; /* background for face */
+ Image *left; /* left-pointing arrow mask */
+ Image *right; /* right-pointing arrow mask */
+ Font *tinyfont;
+@@ -97,11 +99,13 @@
+ initplumb();
+
+ /* make background color */
+- bgrnd = allocimagemix(display, DPalebluegreen, DWhite);
+- blue = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x008888FF); /* blue-green */
++ bgrnd = display->black;
++ arrow = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x550000FF);
++ smallfg = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x884400FF);
++ facebg = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xCCCCCCFF);
+ left = allocimage(display, leftright, GREY1, 0, DWhite);
+ right = allocimage(display, leftright, GREY1, 0, DWhite);
+- if(bgrnd==nil || blue==nil || left==nil || right==nil){
++ if(bgrnd==nil || arrow==nil || smallfg == nil || facebg == nil || left==nil || right==nil){
+ fprint(2, "faces: can't create images: %r\n");
+ exits("image");
+ }
+@@ -113,7 +117,7 @@
+ tinyfont = openfont(display, "/lib/font/bit/misc/ascii.5x7.font");
+ if(tinyfont == nil)
+ tinyfont = font;
+- mediumfont = openfont(display, "/lib/font/bit/misc/unicode.6x13.font");
++ mediumfont = openfont(display, "/lib/font/bit/vga/unicode.font");
+ if(mediumfont == nil)
+ mediumfont = font;
+ datefont = font;
+@@ -138,7 +142,7 @@
+ r.max.x = enddate.x;
+ r.max.y = enddate.y+datefont->height;
+ draw(screen, r, bgrnd, nil, ZP);
+- string(screen, r.min, display->black, ZP, datefont, date);
++ string(screen, r.min, smallfg, ZP, datefont, date);
+ }
+
+ void
+@@ -257,18 +261,19 @@
+ return;
+ r = facerect(i-first);
+ draw(screen, r, bgrnd, nil, ZP);
++ draw(screen, Rpt(r.min, addpt(r.min, Pt(Facesize, Facesize))), facebg, nil, ZP);
+ draw(screen, r, f->bit, f->mask, ZP);
+ r.min.y += Facesize;
+- center(mediumfont, r.min, f->str[Suser], display->black);
++ center(mediumfont, r.min, f->str[Suser], smallfg);
+ r.min.y += mediumfont->height;
+ tstr = facetime(f, &f->recent);
+- center(mediumfont, r.min, tstr, display->black);
++ center(mediumfont, r.min, tstr, facebg);
+ if(f->unknown){
+ r.min.y -= mediumfont->height + tinyfont->height + 2;
+ for(p.x=-1; p.x<=1; p.x++)
+ for(p.y=-1; p.y<=1; p.y++)
+- center(tinyfont, addpt(r.min, p), f->str[Sdomain], display->white);
+- center(tinyfont, r.min, f->str[Sdomain], display->black);
++ center(tinyfont, addpt(r.min, p), f->str[Sdomain], display->black);
++ center(tinyfont, r.min, f->str[Sdomain], facebg);
+ }
+ }
+
+@@ -307,8 +312,8 @@
+ leftr = rectaddpt(leftright, p);
+ p.x += Dx(leftright) + Facesep;
+ rightr = rectaddpt(leftright, p);
+- draw(screen, leftr, first>0? blue : bgrnd, left, leftright.min);
+- draw(screen, rightr, last<nfaces? blue : bgrnd, right, leftright.min);
++ draw(screen, leftr, first>0? arrow : bgrnd, left, leftright.min);
++ draw(screen, rightr, last<nfaces? arrow : bgrnd, right, leftright.min);
+ }
+
+ void
--- /dev/null
+++ b/file-mod
@@ -1,0 +1,11 @@
+diff -r 121def0aed4d sys/src/cmd/file.c
+--- a/sys/src/cmd/file.c Thu Jul 12 09:33:33 2018 +0200
++++ b/sys/src/cmd/file.c Fri Jul 13 13:39:52 2018 +1200
+@@ -920,6 +920,7 @@
+ } offstrs[] = {
+ 32*1024, "\001CD001\001", "ISO9660 CD image", 7, "application/x-iso9660-image",
+ 32*4, "DICM", "DICOM medical imaging data", 4, "application/dicom",
++ 1080, "M.K.", "Amiga module", 4, "audio/mod",
+ 0, 0, 0, 0, 0
+ };
+
--- /dev/null
+++ b/fplot-abs
@@ -1,0 +1,19 @@
+diff -r 82ca4d784349 sys/src/cmd/fplot.c
+--- a/sys/src/cmd/fplot.c Sun Jul 01 23:35:23 2018 -0400
++++ b/sys/src/cmd/fplot.c Thu Jul 05 04:41:48 2018 +0200
+@@ -61,6 +61,7 @@
+ void oexp(void) { *sp = exp(*sp); }
+ void olog(void) { *sp = log10(*sp); }
+ void oln(void) { *sp = log(*sp); }
++void oabs(void) { *sp = fabs(*sp); }
+
+ struct Operator {
+ char *s;
+@@ -85,6 +86,7 @@
+ "exp", OUNARY, 0, 300, oexp,
+ "log", OUNARY, 0, 300, olog,
+ "ln", OUNARY, 0, 300, oln,
++ "abs", OUNARY, 0, 300, oabs,
+ };
+
+ struct Constant {
--- /dev/null
+++ b/fplot-col
@@ -1,0 +1,117 @@
+diff -r 82ca4d784349 sys/src/cmd/fplot.c
+--- a/sys/src/cmd/fplot.c Sun Jul 01 23:35:23 2018 -0400
++++ b/sys/src/cmd/fplot.c Thu Jul 05 04:44:35 2018 +0200
+@@ -366,7 +366,9 @@
+ if(x >= picx || y >= picy || x < 0 || y < 0)
+ return;
+ p = imagedata + (picx * y + x) * 3;
+- p[0] = p[1] = p[2] = 0;
++ p[0] = 0;
++ p[1] = 0x44;
++ p[2] = 0x88;
+ } else
+ draw(screen, Rect(x, y, x + 1, y + 1), color, nil, ZP);
+ }
+@@ -450,7 +452,7 @@
+ lr = rectsubpt(lr, Pt(0, lr.min.y - ny));
+ }
+ if(rectinrect(lr, screen->r) && (lr.min.x > x || lr.max.x <= x)){
+- string(screen, lr.min, display->black, ZP, display->defaultfont, buf);
++ string(screen, lr.min, color, ZP, display->defaultfont, buf);
+ return 1;
+ }
+ return 0;
+@@ -472,7 +474,7 @@
+ lr = rectsubpt(lr, Pt(lr.min.x - nx, 0));
+ }
+ if(rectinrect(lr, screen->r) && (lr.min.y > y || lr.max.y <= y)){
+- string(screen, lr.min, display->black, ZP, display->defaultfont, buf);
++ string(screen, lr.min, color, ZP, display->defaultfont, buf);
+ return 1;
+ }
+ return 0;
+@@ -539,25 +541,25 @@
+ x = deconvx(&screen->r, 0);
+ else
+ x = screen->r.min.x+5;
+- line(screen, Pt(x, screen->r.min.y), Pt(x, screen->r.max.y), Endarrow, 0, 0, display->black, ZP);
++ line(screen, Pt(x, screen->r.min.y), Pt(x, screen->r.max.y), Endarrow, 0, 0, color, ZP);
+ if(ymin < 0 && ymax > 0)
+ y = deconvy(&screen->r, 0);
+ else
+ y = screen->r.max.y-5;
+- line(screen, Pt(screen->r.min.x, y), Pt(screen->r.max.x, y), 0, Endarrow, 0, display->black, ZP);
++ line(screen, Pt(screen->r.min.x, y), Pt(screen->r.max.x, y), 0, Endarrow, 0, color, ZP);
+ nx = ticks(xmin, xmax, &dx, &mx);
+ tickfmt(dx, mx, nx, fmt);
+ for(i = 0; i <= nx; i++){
+ p = deconvx(&screen->r, dx*i+mx);
+ if(xticklabel(fmt, dx*i+mx, p, x, y))
+- line(screen, Pt(p, y), Pt(p, y-5), 0, 0, 0, display->black, ZP);
++ line(screen, Pt(p, y), Pt(p, y-5), 0, 0, 0, color, ZP);
+ }
+ ny = ticks(ymin, ymax, &dy, &my);
+ tickfmt(dy, my, ny, fmt);
+ for(i = 0; i <= ny; i++){
+ p = deconvy(&screen->r, dy*i+my);
+ if(yticklabel(fmt, dy*i+my, p, x, y))
+- line(screen, Pt(x, p), Pt(x+5, p), 0, 0, 0, display->black, ZP);
++ line(screen, Pt(x, p), Pt(x+5, p), 0, 0, 0, color, ZP);
+ }
+ }
+
+@@ -566,7 +568,6 @@
+ {
+ int i;
+
+- color = display->black;
+ for(i = 0; i < nfns; i++)
+ drawgraph(&fns[i], &screen->r);
+ if(!aflag)
+@@ -603,7 +604,7 @@
+ xmax = xmax_;
+ ymin = ymin_;
+ ymax = ymax_;
+- draw(screen, screen->r, display->white, nil, ZP);
++ draw(screen, screen->r, display->black, nil, ZP);
+ drawgraphs();
+ }
+
+@@ -617,7 +618,7 @@
+ ymax = zoomst[nzoomst - 1].ymax;
+ zoomst = realloc(zoomst, sizeof(FRectangle) * --nzoomst);
+ if(zoomst == nil && nzoomst != 0) sysfatal("realloc: %r");
+- draw(screen, screen->r, display->white, nil, ZP);
++ draw(screen, screen->r, display->black, nil, ZP);
+ drawgraphs();
+ }
+
+@@ -687,7 +688,6 @@
+ parsefns(argc, argv);
+ if(cflag) {
+ imagedata = emalloc(picx * picy * 3);
+- memset(imagedata, 0xFF, picx * picy * 3);
+ print("%11s %11d %11d %11d %11d ", "r8g8b8", 0, 0, picx, picy);
+ r.min.x = r.min.y = 0;
+ r.max.x = picx;
+@@ -699,7 +699,11 @@
+ } else {
+ if(initdraw(nil, nil, "fplot") < 0)
+ sysfatal("initdraw: %r");
++ color = allocimage(display, Rect(0,0,1,1), RGB24, 1, 0x884400ff);
++ if(color == nil)
++ sysfatal("allocimage: %r");
+ einit(Emouse | Ekeyboard);
++ draw(screen, screen->r, display->black, nil, ZP);
+ drawgraphs();
+ for(;;) {
+ switch(event(&e)) {
+@@ -720,7 +724,7 @@
+ zoomst[nzoomst++] = (FRectangle){xmin, xmax, ymin, ymax};
+ ymin = gymin-0.05*(gymax-gymin);
+ ymax = gymax+0.05*(gymax-gymin);
+- draw(screen, screen->r, display->white, nil, ZP);
++ draw(screen, screen->r, display->black, nil, ZP);
+ drawgraphs();
+ }
+ break;
--- /dev/null
+++ b/gb-nosleep
@@ -1,0 +1,56 @@
+diff -r e899bb299ed2 sys/src/games/gb/apu.c
+--- a/sys/src/games/gb/apu.c Fri Feb 10 22:39:47 2017 +0100
++++ b/sys/src/games/gb/apu.c Sat Feb 11 20:06:13 2017 +0200
+@@ -475,7 +475,7 @@
+ if(sbufp == sbuf)
+ return 0;
+ cl = clock;
+- rc = write(fd, sbuf, (sbufp - sbuf) * 2);
++ rc = nosleep ? 1 : write(fd, sbuf, (sbufp - sbuf) * 2);
+ if(rc > 0)
+ sbufp -= (rc+1)/2;
+ if(sbufp < sbuf)
+diff -r e899bb299ed2 sys/src/games/gb/dat.h
+--- a/sys/src/games/gb/dat.h Fri Feb 10 22:39:47 2017 +0100
++++ b/sys/src/games/gb/dat.h Sat Feb 11 20:06:13 2017 +0200
+@@ -25,6 +25,7 @@
+ extern u8int mode;
+ extern u8int mbc, feat;
+ extern int keys, scale;
++extern int nosleep;
+
+ enum {
+ JOYP = 0x00,
+diff -r e899bb299ed2 sys/src/games/gb/gb.c
+--- a/sys/src/games/gb/gb.c Fri Feb 10 22:39:47 2017 +0100
++++ b/sys/src/games/gb/gb.c Sat Feb 11 20:06:13 2017 +0200
+@@ -12,7 +12,7 @@
+ Rectangle picr;
+ Image *bg, *tmp;
+ Mousectl *mc;
+-int keys, paused, framestep, backup;
++int keys, paused, framestep, backup, nosleep;
+ QLock pauselock;
+ int savefd = -1, saveframes;
+ ulong clock;
+@@ -285,6 +285,9 @@
+ }
+ framestep = !framestep;
+ break;
++ case ' ':
++ nosleep = !nosleep;
++ break;
+ }
+ }
+ k &= ~(k << 1 & 0x0a | k >> 1 & 0x05);
+@@ -352,7 +355,9 @@
+ flushimage(display, 1);
+ if(profile)
+ timing();
+- if(audioout() < 0){
++ if(nosleep)
++ old = nsec();
++ if(audioout() < 0 && !nosleep){
+ new = nsec();
+ diff = 0;
+ if(old != 0){
--- /dev/null
+++ b/ircrc-jpmfix
@@ -1,0 +1,121 @@
+from _jpm: http://www.plan9.fi/up/ircrc
+fixes hanging connections at startup
+
+diff -r 94844cc7f1fd rc/bin/ircrc
+--- a/rc/bin/ircrc Tue Mar 01 21:27:37 2016 -0500
++++ b/rc/bin/ircrc Sat Mar 05 23:05:00 2016 +0200
+@@ -6,7 +6,7 @@
+ port=6667
+ realname='<nil>'
+ target=''
+-netdir=()
++pipe=/n/ircrc
+ nick=$user
+ pass=()
+ tls=0
+@@ -17,8 +17,7 @@
+ }
+
+ fn sigint sigterm {
+- if (! ~ $#netdir 0)
+- echo QUIT : Leaving... > $netdir/data
++ echo QUIT : Leaving... > $pipe/data
+ }
+
+ fn mshift {
+@@ -33,29 +32,39 @@
+ fn work {
+ if(~ $#serverpass 1)
+ echo PASS $serverpass > $netdir/data
+- echo USER $user foo bar :$realname > $netdir/data
+- echo NICK $nick > $netdir/data
++ echo USER $user foo bar :$realname >[1=3]
++ echo NICK $nick >[1=3]
+ if (~ $#pass 1)
+- echo PRIVMSG 'nickserv :'identify $"pass > $netdir/data
++ echo PRIVMSG 'nickserv :'identify $"pass >[1=3]
+ if(! ~ $target ''){
+ title
+- echo JOIN $target > $netdir/data
++ echo JOIN $target >[1=3]
+ }
+ if(~ $target *,*)
+ target = `{echo $target | awk -F',' '{print $NF}'}
+ while (cmd=`{read}) {
+ s=$status
+ if(~ $s *eof) {
+- echo QUIT : Leaving... > $netdir/data
++ echo QUIT : Leaving... >[1=3]
+ exit
+ }
+ msg=()
+ out=()
+ switch ($cmd(1)) {
+ case /!
+- eval `{mshift $cmd} | while(rc=`{read})echo 'PRIVMSG '^$target^' :' $rc | tee $netdir/data
++ eval `{mshift $cmd} | while(rc=`{read}) echo 'PRIVMSG '^$target^' :' $rc | tee /fd/3
+ case /M
+- msg = (MODE `{mshift $cmd})
++ switch($#cmd){
++ case 1
++ if(! ~ $target '')
++ msg = (TOPIC $target)
++ case 2
++ msg = (TOPIC $cmd(2))
++ case *
++ chan = $cmd(2)
++ topic = $cmd(3-)
++ msg = (TOPIC $chan :^$"topic)
++ }
+ case /N
+ cmd = `{mshift $cmd}
+ if (! ~ $#cmd 0)
+@@ -101,7 +110,7 @@
+ case /w
+ msg = (WHO `{mshift $cmd})
+ case /x
+- echo QUIT : Leaving... > $netdir/data
++ echo QUIT : Leaving... >[1=3]
+ exit
+ case /*
+ echo unknown command
+@@ -110,7 +119,7 @@
+ out = '('^$target^') ⇐ '^$"cmd
+ }
+ if (! ~ $#msg 0)
+- echo $msg > $netdir/data
++ echo $msg >[1=3]
+ if (! ~ $#out 0)
+ echo `{etime}^' '^$out
+ }
+@@ -174,7 +183,7 @@
+ case *NOTICE*
+ line = `{echo -n $line | notice}
+ case *PING*
+- echo -n $line | sed 's/PING/PONG/' > $netdir/data
++ echo -n $line | sed 's/PING/PONG/' >[1=3]
+ line = ()
+ case *
+ line = `{echo -n $line | numeric}
+@@ -238,16 +247,13 @@
+ pass=$userpass(2)
+ }
+
+-p='/n/ircrc'
+-bind '#|' $p
++bind '#|' $pipe
+ echo connecting to tcp!$server!$port...
+ if(~ $tls 0){
+- aux/trampoline tcp!$server!$port <>$p/data1 >[1=0] &
++ aux/trampoline tcp!$server!$port <>$pipe/data1 >[1=0] &
+ }
+ if not {
+- tlsclient tcp!$server!$port <>$p/data1 >[1=0] &
++ tlsclient tcp!$server!$port <>$pipe/data1 >[1=0] &
+ }
+-netdir=$p
+-cat $netdir/data | tr -d '\x2\x8\xd\x1f' | pretty &
+-work
+-
++<$pipe/data tr -d '\x2\x8\xd\x1f' | pretty >[3]$pipe/data &
++work >[3]$pipe/data
--- /dev/null
+++ b/ircrc-print-log
@@ -1,0 +1,63 @@
+tweak how this prints messages and append to a log.
+assumes jpm's patch applied beforehand.
+
+diff -r ef9b307e9439 rc/bin/ircrc
+--- a/rc/bin/ircrc Sun Feb 26 00:27:50 2017
++++ b/rc/bin/ircrc Sun Feb 26 00:28:19 2017
+@@ -26,7 +26,11 @@
+ }
+
+ fn etime {
+- date | awk '{print $4}' | awk -F ':' '{print "[" $1 ":" $2 "]"}'
++ date -t | sed 's/-//g;s/^..(.*)T(..):(..).*/\1:\2\3/'
++}
++
++fn fmt2 { # this fucking sucks
++ sed 's/^(......:....) (J?O?I?N? *)\(?(#?[^ \)]+)\)? «([^»]+)»/\1 \2\3:\4/'
+ }
+
+ fn work {
+@@ -90,7 +94,7 @@
+ if (! ~ $#cmd 0) {
+ to = $cmd(1)
+ cmd = `{mshift $cmd}
+- out = '('^$to^') ⇐ '^$"cmd
++ out = $to^' ⇐ '^$"cmd
+ msg = 'PRIVMSG '^$to^' :'^$"cmd
+ }
+ case /n
+@@ -116,19 +120,19 @@
+ echo unknown command
+ case *
+ msg = 'PRIVMSG '^$target^' :'^$"cmd
+- out = '('^$target^') ⇐ '^$"cmd
++ out = $target^' ⇐ '^$"cmd
+ }
+ if (! ~ $#msg 0)
+ echo $msg >[1=3]
+ if (! ~ $#out 0)
+- echo `{etime}^' '^$out
++ echo `{etime}^' '^$"out | tee -a $home/tmp/irc
+ }
+ }
+
+ fn misc {
+ sed '
+ s/^://
+- s/!~?[a-zA-Z0-9_@\-|.{=\/:]+ /:/' |
++ s/!~?[a-zA-Z0-9_@\-|.{=\/:`\^]+ /:/' |
+ awk -F ':' '
+ {
+ s = $2 " «" $1 "»\t" $3;
+@@ -189,7 +193,10 @@
+ line = `{echo -n $line | numeric}
+ }
+ if (! ~ $#line 0)
+- echo `{etime} $line
++ echo `{etime} $line | fmt2
++ msg = `{echo $line | sed '/^(:|'$nick'|\([^\)]+\) «)/!d'}
++ if (! ~ $#msg 0)
++ echo `{etime} $msg | fmt2 >>$home/tmp/irc
+ }
+ exit
+ }
--- /dev/null
+++ b/kbdfs-fshalt
@@ -1,0 +1,37 @@
+diff -r 70f20d62c396 sys/src/cmd/aux/kbdfs/kbdfs.c
+--- a/sys/src/cmd/aux/kbdfs/kbdfs.c Wed Jan 08 02:35:01 2020 +0000
++++ b/sys/src/cmd/aux/kbdfs/kbdfs.c Wed Jan 08 06:23:13 2020 +0100
+@@ -306,6 +306,24 @@
+ }
+
+ void
++emergencywarp(void)
++{
++ int fd;
++
++ if(debug)
++ return;
++
++ if(access("#s/cwfs.cmd", AEXIST) == 0 && (fd = eopen("#s/cwfs.cmd", OWRITE)) >= 0){
++ fprint(fd, "halt\n");
++ close(fd);
++ }
++ if(access("#s/hjfs.cmd", AEXIST) == 0 && (fd = eopen("#s/hjfs.cmd", OWRITE)) >= 0){
++ fprint(fd, "halt\n");
++ close(fd);
++ }
++}
++
++void
+ reboot(void)
+ {
+ int fd;
+@@ -387,6 +405,8 @@
+ if(scan->caps && key.r<='z' && key.r>='a')
+ key.r += 'A' - 'a';
+
++ if(scan->ctl && scan->altgr && key.r == Kdel)
++ emergencywarp();
+ if(scan->ctl && scan->alt && key.r == Kdel)
+ reboot();
+
--- /dev/null
+++ b/kbmap-col
@@ -1,0 +1,58 @@
+diff -r 49bd5e4c9bde sys/src/cmd/kbmap.c
+--- a/sys/src/cmd/kbmap.c Wed Feb 07 18:53:08 2018 +0000
++++ b/sys/src/cmd/kbmap.c Wed Feb 14 15:12:34 2018 +0100
+@@ -14,8 +14,7 @@
+
+ KbMap *map;
+ int nmap;
+-Image *lightblue;
+-Image *justblue;
++Image *txt, *sel;
+
+ enum {
+ PAD = 3,
+@@ -86,14 +85,14 @@
+ drawmap(int i)
+ {
+ if(map[i].current)
+- draw(screen, map[i].r, justblue, nil, ZP);
++ draw(screen, map[i].r, sel, nil, ZP);
+ else
+- draw(screen, map[i].r, lightblue, nil, ZP);
++ draw(screen, map[i].r, display->black, nil, ZP);
+
+- _string(screen, addpt(map[i].r.min, Pt(2,0)), display->black, ZP,
++ _string(screen, addpt(map[i].r.min, Pt(2,0)), txt, ZP,
+ font, map[i].name, nil, strlen(map[i].name),
+ map[i].r, nil, ZP, SoverD);
+- border(screen, map[i].r, 1, display->black, ZP);
++ border(screen, map[i].r, 1, txt, ZP);
+ }
+
+ void
+@@ -116,7 +115,7 @@
+ {
+ int i;
+
+- draw(screen, screen->r, lightblue, nil, ZP);
++ draw(screen, screen->r, display->black, nil, ZP);
+ for(i=0; i<nmap; i++)
+ drawmap(i);
+ flushimage(display, 1);
+@@ -233,12 +232,10 @@
+ fprint(2, "kbmap: initdraw failed: %r\n");
+ exits("initdraw");
+ }
+- lightblue = allocimagemix(display, DPalebluegreen, DWhite);
+- if(lightblue == nil)
+- sysfatal("allocimagemix: %r");
+- justblue = allocimagemix(display, DBlue, DWhite);
+- if(justblue == nil)
+- sysfatal("allocimagemix: %r");
++ txt = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x884400FF);
++ sel = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x440000FF);
++ if(txt == nil || sel == nil)
++ sysfatal("allocimage: %r");
+
+ eresized(0);
+ einit(Emouse|Ekeyboard);
--- /dev/null
+++ b/libdraw-menucol
@@ -1,0 +1,72 @@
+mouse menu color patch
+
+diff -r d4af852fff2d sys/src/libdraw/emenuhit.c
+--- a/sys/src/libdraw/emenuhit.c Sat Aug 08 09:20:48 2015 +0200
++++ b/sys/src/libdraw/emenuhit.c Sat Aug 15 02:08:58 2015 +0300
+@@ -27,13 +27,14 @@
+ menucolors(void)
+ {
+ /* Main tone is greenish, with negative selection */
+- back = allocimagemix(display, DPalegreen, DWhite);
+- high = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DDarkgreen); /* dark green */
+- bord = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DMedgreen); /* not as dark green */
+- if(back==nil || high==nil || bord==nil)
++ text = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x884400FF);
++ high = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x884400FF);
++ bord = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x440000FF);
++ if(text==nil || high==nil || bord==nil)
+ goto Error;
+- text = display->black;
++ back = display->black;
+ htext = back;
++ menutxt = high;
+ return;
+
+ Error:
+@@ -149,10 +150,7 @@
+ if(r.max.y < r.min.y+2)
+ r.max.y = r.min.y+2;
+ border(screen, r, 1, bord, ZP);
+- if(menutxt == 0)
+- menutxt = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, DDarkgreen);
+- if(menutxt)
+- draw(screen, insetrect(r, 1), menutxt, nil, ZP);
++ draw(screen, insetrect(r, 1), menutxt, nil, ZP);
+ }
+
+ int
+diff -r d4af852fff2d sys/src/libdraw/menuhit.c
+--- a/sys/src/libdraw/menuhit.c Sat Aug 08 09:20:48 2015 +0200
++++ b/sys/src/libdraw/menuhit.c Sat Aug 15 02:08:58 2015 +0300
+@@ -28,13 +28,14 @@
+ menucolors(void)
+ {
+ /* Main tone is greenish, with negative selection */
+- back = allocimagemix(display, DPalegreen, DWhite);
+- high = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkgreen); /* dark green */
+- bord = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DMedgreen); /* not as dark green */
+- if(back==nil || high==nil || bord==nil)
++ text = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x884400FF);
++ high = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x884400FF);
++ bord = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x440000FF);
++ if(text==nil || high==nil || bord==nil)
+ goto Error;
+- text = display->black;
++ back = display->black;
+ htext = back;
++ menutxt = high;
+ return;
+
+ Error:
+@@ -146,10 +147,7 @@
+ if(r.max.y < r.min.y+2)
+ r.max.y = r.min.y+2;
+ border(m, r, 1, bord, ZP);
+- if(menutxt == 0)
+- menutxt = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DDarkgreen); /* border color; BUG? */
+- if(menutxt)
+- draw(m, insetrect(r, 1), menutxt, nil, ZP);
++ draw(m, insetrect(r, 1), menutxt, nil, ZP);
+ }
+
+ int
--- /dev/null
+++ b/man-joy
@@ -1,0 +1,39 @@
+document nusb/joy
+
+diff -r e540b0bb61c8 sys/man/4/nusb
+--- a/sys/man/4/nusb Sat Oct 03 12:19:31 2015 +0200
++++ b/sys/man/4/nusb Sun Oct 04 16:10:51 2015 +0200
+@@ -35,6 +35,12 @@
+ ]
+ .I devid
+ .PP
++.B nusb/joy
++[
++.B -d
++]
++.I devid
++.PP
+ .B nusb/serial
+ [
+ .B -d
+@@ -135,6 +141,10 @@
+ Mouse events are sent to
+ .BR /dev/mousein
+ in the same way.
++.SS Joysticks
++.I Joy
++parses data packets from a given endpoint and prints back
++any changes in the device's axes or buttons.
+ .SS Disks
+ .I Disk
+ configures and manages USB mass storage devices. It
+@@ -245,6 +255,9 @@
+ .IR shr (3),
+ .IR nusbrc (8),
+ .IR kbdfs (8)
++.SH HISTORY
++.I Joy
++first appeared in 9front (March, 2014).
+ .SH BUGS
+ The various device drivers are generic USB drivers and
+ may work only for certain devices of each class.
--- /dev/null
+++ b/midi-debug
@@ -1,0 +1,103 @@
+diff -r 02682c97b28d sys/src/games/midi.c
+--- a/sys/src/games/midi.c Fri Sep 29 21:19:12 2017 +0200
++++ b/sys/src/games/midi.c Sat Sep 30 14:21:21 2017 +0200
+@@ -13,11 +13,13 @@
+
+ typedef struct Tracker Tracker;
+
+-int fd, ofd, div, tempo = 500000, ntrack;
++int fd, ofd, div, tempo = 500000, ntrack, debug;
+ uvlong T;
+ int freq[128];
+ uchar out[8192], *outp = out;
+
++#define dprint if(debug)fprint
++
+ void *
+ emallocz(int size)
+ {
+@@ -149,9 +151,10 @@
+ readevent(Tracker *src)
+ {
+ uvlong l;
+- int n,t;
++ int c,t,n,v;
+
+- l = tconv(getvar(src));
++ c = getvar(src);
++ l = tconv(c);
+ run(src->t += l);
+ t = get8(src);
+ if((t & 0x80) == 0){
+@@ -164,35 +167,46 @@
+ switch(t >> 4){
+ case 0x8:
+ n = get8(src);
+- get8(src);
++ v = get8(src);
++ dprint(2, "t%zd %d c%d off %d %d\n", src-tr, c, t&15, n, v);
+ src->notes[t & 15][n] = 0;
+ break;
+ case 0x9:
+ n = get8(src);
+- src->notes[t & 15][n] = get8(src);
++ v = get8(src);
++ dprint(2, "t%zd %d c%d on %d %d\n", src-tr, c, t&15, n, v);
++ src->notes[t & 15][n] = v;
+ break;
+ case 0xB:
+- get16(src);
++ n = get8(src);
++ v = get8(src);
++ dprint(2, "t%zd %d c%d ctl %d %d\n", src-tr, c, t&15, n, v);
+ break;
+ case 0xC:
+- get8(src);
++ n = get8(src);
++ dprint(2, "t%zd %d c%d bank %d\n", src-tr, c, t&15, n);
+ break;
+ case 0xE:
+- get16(src);
++ n = get8(src);
++ n = get8(src) << 7 | n & 0x7f;
++ dprint(2, "t%zd %d c%d bend %d\n", src-tr, c, t&15, n);
+ break;
+ case 0xF:
+ t = get8(src);
+ n = get8(src);
+ switch(t){
+ case 0x2F:
++ dprint(2, "t%zd %d eot\n", src-tr, c);
+ src->ended = 1;
+ break;
+ case 0x51:
+ tempo = get16(src) << 8;
+ tempo |= get8(src);
++ dprint(2, "t%zd %d tempo %d\n", src-tr, c, tempo);
+ break;
+ case 5:
+- write(2, src->data, n);
++ if(!debug)
++ write(2, src->data, n);
+ skip(src, n);
+ break;
+ default:
+@@ -217,6 +231,9 @@
+ case 'c':
+ ofd = 1;
+ break;
++ case 'v':
++ debug = 1;
++ break;
+ }ARGEND;
+ if(*argv != nil)
+ fd = open(*argv, OREAD);
+@@ -229,6 +246,8 @@
+ get16(nil);
+ ntrack = get16(nil);
+ div = get16(nil);
++ if(debug)
++ fprint(2, "div %d\n", div);
+ tr = emallocz(ntrack * sizeof(*tr));
+ for(i = 0; i < ntrack; i++){
+ if(get32(nil) != 0x4D54726B)
--- /dev/null
+++ b/midi-dobend
@@ -1,0 +1,217 @@
+midi: implement pitch wheel
+
+this is an aborted attempt to implement pitch bending (event 0xe0).
+
+this maintains a list of active notes, storing note number, amplitude and bent
+frequency; this greatly reduces cpu time spent in run(), also alleviating the
+issue of delays between writes to /dev/audio being too great...
+
+it blows chunks:
+- greatly complexifies midi note handling
+- pitch steps are discrete and too noticeable, actually worsening playback
+ (blatant example: doom e2m2), but don't yet know where T % f >= f/2 is coming
+ from or how to fix this
+
+→ i don't yet know what i'm doing nor how to solve this correctly
+
+diff -r 9c4b9c67ff16 sys/src/games/midi.c
+--- a/sys/src/games/midi.c Thu Feb 16 20:11:20 2017 +0100
++++ b/sys/src/games/midi.c Wed Feb 22 01:34:39 2017 +0200
+@@ -3,19 +3,29 @@
+
+ enum { SAMPLE = 44100 };
+
++typedef struct Note Note;
++typedef struct Tracker Tracker;
++
++struct Note {
++ int nt;
++ Tracker *src;
++ int ch;
++ uchar a;
++ int f;
++ int ½f;
++ Note *n;
++} nl[256], np;
++
+ struct Tracker {
+ uchar *data;
+ char ended;
+ uvlong t;
+- uchar notes[16][128];
++ double bend[16];
+ int cmd;
+ } *tr;
+
+-typedef struct Tracker Tracker;
+-
+ int fd, ofd, div, tempo = 500000, ntrack;
+ uvlong T;
+-int freq[128];
+
+ void *
+ emallocz(int size)
+@@ -108,32 +118,23 @@
+ }
+
+ void
+-run(uvlong n)
++run(uvlong dt)
+ {
+- int samp, j, k, l, no[128];
++ int samp, l;
+ uchar *s;
+- int t, f;
++ int t;
+ short u;
+- Tracker *x;
+-
+- samp = n - T;
++ Note *n;
++
++ samp = dt - T;
+ if(samp <= 0)
+ return;
+- memset(no, 0, sizeof no);
+- for(x = tr; x < tr + ntrack; x++){
+- if(x->ended)
+- continue;
+- for(j = 0; j < 16; j++)
+- for(k = 0; k < 128; k++)
+- no[k] += x->notes[j][k];
+- }
+ s = emallocz(samp * 4);
+ for(l = 0; l < samp; l++){
+ t = 0;
+- for(k = 0; k < 128; k++){
+- f = (T % freq[k]) >= freq[k]/2 ? 1 : 0;
+- t += f * no[k];
+- }
++ for(n = np.n; n != &np; n = n->n)
++ if(T % n->f >= n->½f)
++ t += n->a;
+ u = t*10;
+ s[4 * l] = s[4 * l + 2] = u;
+ s[4 * l + 1] = s[4 * l + 3] = u >> 8;
+@@ -144,11 +145,70 @@
+ }
+
+ void
++bend(Tracker *src, int ch, int b)
++{
++ int f;
++ double d;
++ Note *n;
++
++ d = (b - 8192) / 4095.5;
++ d = pow(2, d / 12);
++ src->bend[ch] = d;
++ for(n = np.n; n != &np; n = n->n){
++ if(n->src != src || n->ch != ch)
++ continue;
++ f = SAMPLE / (440 * d * pow(1.05946, n->nt - 69));
++ n->f = f;
++ n->½f = f / 2;
++ }
++}
++
++void
++pop(Tracker *src, int ch, int nt)
++{
++ Note *n, *p;
++
++ for(p = &np, n = np.n; n != &np; p = n, n = n->n)
++ if(n->src == src && n->ch == ch && n->nt == nt){
++ p->n = n->n;
++ memset(n, 0, sizeof *n);
++ return;
++ }
++}
++
++void
++push(Tracker *src, int ch, int nt, int a)
++{
++ int f;
++ Note *n, *p;
++
++ for(p = &np, n = np.n; n != &np; p = n, n = n->n)
++ if(n->src == src && n->ch == ch && n->nt == nt){
++ n->a = a;
++ return;
++ }
++ for(n = nl; n < nl + nelem(nl); n++)
++ if(n->src == nil)
++ break;
++ if(n == nl + nelem(nl))
++ return;
++ n->src = src;
++ n->ch = ch;
++ n->nt = nt;
++ n->a = a;
++ f = SAMPLE / (440 * src->bend[ch] * pow(1.05946, nt - 69));
++ n->f = f;
++ n->½f = f / 2;
++ p->n = n;
++ n->n = &np;
++}
++
++void
+ readevent(Tracker *src)
+ {
+ uvlong l;
+ int n,t;
+-
++
+ l = tconv(getvar(src));
+ run(src->t += l);
+ t = get8(src);
+@@ -161,13 +221,12 @@
+ src->cmd = t;
+ switch(t >> 4){
+ case 0x8:
+- n = get8(src);
++ pop(src, t & 15, get8(src));
+ get8(src);
+- src->notes[t & 15][n] = 0;
+ break;
+ case 0x9:
+ n = get8(src);
+- src->notes[t & 15][n] = get8(src);
++ push(src, t & 15, n, get8(src));
+ break;
+ case 0xB:
+ get16(src);
+@@ -175,6 +234,11 @@
+ case 0xC:
+ get8(src);
+ break;
++ case 0xE:
++ n = get8(src) & 0x7f;
++ n = get8(src) << 7 & 0x3f80 | n;
++ bend(src, t & 15, n);
++ break;
+ case 0xF:
+ t = get8(src);
+ n = get8(src);
+@@ -204,7 +268,7 @@
+ void
+ main(int argc, char **argv)
+ {
+- int i, size;
++ int i, j, size;
+ uvlong t, mint;
+ Tracker *x, *minx;
+
+@@ -228,9 +292,10 @@
+ size = get32(nil);
+ tr[i].data = emallocz(size);
+ read(fd, tr[i].data, size);
++ for(j = 0; j < 16; j++)
++ tr[i].bend[j] = 1.0;
+ }
+- for(i = 0; i < 128; i++)
+- freq[i] = SAMPLE / (440 * pow(1.05946, i - 69));
++ np.n = &np;
+ for(;;){
+ minx = nil;
+ mint = 0;
--- /dev/null
+++ b/mothra-slmod
@@ -1,0 +1,341 @@
+modified diff of http://9front.org/extra/mothra.black.tgz
+
+diff -r 3f9227bd4f1d sys/src/cmd/mothra/libpanel/draw.c
+--- a/sys/src/cmd/mothra/libpanel/draw.c Mon Feb 01 22:49:20 2016 +0100
++++ b/sys/src/cmd/mothra/libpanel/draw.c Tue Feb 02 14:03:58 2016 +0100
+@@ -15,14 +15,16 @@
+ #define CKBORDER 2 /* space around X inside frame */
+ static int plldepth;
+ static Image *pl_white, *pl_light, *pl_dark, *pl_black, *pl_hilit;
++Image *txtcol;
+ int pl_drawinit(int ldepth){
+ plldepth=ldepth;
+- pl_white=allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xFFFFFFFF);
+- pl_light=allocimagemix(display, DPalebluegreen, DWhite);
+- pl_dark =allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPurpleblue);
+- pl_black=allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x000000FF);
++ pl_white=display->black;
++ pl_light=display->black;
++ pl_dark=allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x222222FF);
++ pl_black=allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x770000FF);
+ pl_hilit=allocimage(display, Rect(0,0,1,1), CHAN1(CAlpha,8), 1, 0x80);
+- if(pl_white==0 || pl_light==0 || pl_black==0 || pl_dark==0) return 0;
++ txtcol=allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x884400FF);
++ if(pl_white==0 || pl_light==0 || pl_black==0 || pl_dark==0 || txtcol==0) return 0;
+ return 1;
+ }
+ void pl_relief(Image *b, Image *ul, Image *lr, Rectangle r, int wid){
+@@ -38,6 +40,13 @@
+ }
+ Rectangle pl_boxoutline(Image *b, Rectangle r, int style, int fill){
+ if(plldepth==0) switch(style){
++ case SUP:
++ case TUP:
++ pl_relief(b, pl_white, pl_white, r, BWID);
++ r=insetrect(r, BWID);
++ if(fill) draw(b, r, pl_white, 0, ZP);
++ else border(b, r, SPACE, pl_white, ZP);
++ break;
+ case UP:
+ pl_relief(b, pl_black, pl_black, r, BWID);
+ r=insetrect(r, BWID);
+@@ -68,6 +77,13 @@
+ break;
+ }
+ else switch(style){
++ case SUP:
++ case TUP:
++ pl_relief(b, pl_white, pl_white, r, BWID);
++ r=insetrect(r, BWID);
++ if(fill) draw(b, r, pl_light, 0, ZP);
++ else border(b, r, SPACE, pl_white, ZP);
++ break;
+ case UP:
+ pl_relief(b, pl_white, pl_black, r, BWID);
+ r=insetrect(r, BWID);
+@@ -97,7 +113,10 @@
+ else border(b, r, SPACE, pl_white, ZP);
+ break;
+ }
+- return insetrect(r, SPACE);
++ switch(style){
++ case SUP: return insetrect(r, SPACE-SPACE);
++ default: return insetrect(r, SPACE);
++ }
+ }
+ Rectangle pl_outline(Image *b, Rectangle r, int style){
+ return pl_boxoutline(b, r, style, 0);
+@@ -270,7 +289,7 @@
+ draw(b, r, pl_dark, pl_hilit, ZP);
+ }
+ void pl_clr(Image *b, Rectangle r){
+- draw(b, r, display->white, 0, ZP);
++ draw(b, r, display->black, 0, ZP);
+ }
+ void pl_fill(Image *b, Rectangle r){
+ draw(b, r, plldepth==0? pl_white : pl_light, 0, ZP);
+diff -r 3f9227bd4f1d sys/src/cmd/mothra/libpanel/message.c
+--- a/sys/src/cmd/mothra/libpanel/message.c Mon Feb 01 22:49:20 2016 +0100
++++ b/sys/src/cmd/mothra/libpanel/message.c Tue Feb 02 14:03:58 2016 +0100
+@@ -29,7 +29,7 @@
+ end=s;
+ c=*end;
+ *end='\0';
+- string(b, where, display->black, ZP, f, start);
++ string(b, where, txtcol, ZP, f, start);
+ *end=c;
+ where.y+=font->height;
+ s=end;
+diff -r 3f9227bd4f1d sys/src/cmd/mothra/libpanel/panel.h
+--- a/sys/src/cmd/mothra/libpanel/panel.h Mon Feb 01 22:49:20 2016 +0100
++++ b/sys/src/cmd/mothra/libpanel/panel.h Tue Feb 02 14:03:58 2016 +0100
+@@ -108,6 +108,7 @@
+ #define PL_STR 4
+
+ Panel *plkbfocus; /* the panel in keyboard focus */
++extern Image *txtcol;
+
+ int plinit(int); /* initialization */
+ void plpack(Panel *, Rectangle); /* figure out where to put the Panel & children */
+diff -r 3f9227bd4f1d sys/src/cmd/mothra/libpanel/pldefs.h
+--- a/sys/src/cmd/mothra/libpanel/pldefs.h Mon Feb 01 22:49:20 2016 +0100
++++ b/sys/src/cmd/mothra/libpanel/pldefs.h Tue Feb 02 14:03:58 2016 +0100
+@@ -17,7 +17,9 @@
+ * States, also styles
+ */
+ enum{
+- UP,
++ SUP, // scrollbar
++ TUP, // textview
++ UP, // deprecated
+ DOWN1,
+ DOWN2,
+ DOWN3,
+diff -r 3f9227bd4f1d sys/src/cmd/mothra/libpanel/rtext.c
+--- a/sys/src/cmd/mothra/libpanel/rtext.c Mon Feb 01 22:49:20 2016 +0100
++++ b/sys/src/cmd/mothra/libpanel/rtext.c Tue Feb 02 14:03:58 2016 +0100
+@@ -11,7 +11,7 @@
+ #include "rtext.h"
+
+ #define LEAD 4 /* extra space between lines */
+-#define BORD 2 /* extra border for images */
++#define BORD 0 /* extra border for images */
+
+ Rtext *pl_rtnew(Rtext **t, int space, int indent, int voff, Image *b, Panel *p, Font *f, char *s, int flags, void *user){
+ Rtext *new;
+@@ -195,14 +195,14 @@
+ && dr.min.x<r.max.x){
+ if(t->b){
+ draw(b, insetrect(dr, BORD), t->b, 0, t->b->r.min);
+- if(t->flags&PL_HOT) border(b, dr, 1, display->black, ZP);
++ if(t->flags&PL_HOT) border(b, dr, 1, txtcol, ZP);
+ if(t->flags&PL_STR) {
+ line(b, Pt(dr.min.x, dr.min.y), Pt(dr.max.x, dr.max.y),
+ Endsquare, Endsquare, 0,
+- display->black, ZP);
++ txtcol, ZP);
+ line(b, Pt(dr.min.x, dr.max.y), Pt(dr.max.x, dr.min.y),
+ Endsquare, Endsquare, 0,
+- display->black, ZP);
++ txtcol, ZP);
+ }
+ if(t->flags&PL_SEL)
+ pl_highlight(b, dr);
+@@ -214,7 +214,7 @@
+ pl_stuffbitmap(t->p, bb);
+ }
+ else{
+- string(b, dr.min, display->black, ZP, t->font, t->text);
++ string(b, dr.min, txtcol, ZP, t->font, t->text);
+ if(t->flags&PL_SEL)
+ pl_highlight(b, dr);
+ if(t->flags&PL_STR){
+@@ -223,7 +223,7 @@
+ sp = Pt(dr.min.x, y);
+ line(b, sp, Pt(dr.max.x, y),
+ Endsquare, Endsquare, 0,
+- display->black, ZP);
++ txtcol, ZP);
+ sp = Pt(dr.max.x, y);
+ } else
+ sp = ZP;
+@@ -233,7 +233,7 @@
+ lp = Pt(dr.min.x, y);
+ line(b, lp, Pt(dr.max.x, y),
+ Endsquare, Endsquare, 0,
+- display->black, ZP);
++ txtcol, ZP);
+ lp = Pt(dr.max.x, y);
+ } else
+ lp = ZP;
+diff -r 3f9227bd4f1d sys/src/cmd/mothra/libpanel/scrollbar.c
+--- a/sys/src/cmd/mothra/libpanel/scrollbar.c Mon Feb 01 22:49:20 2016 +0100
++++ b/sys/src/cmd/mothra/libpanel/scrollbar.c Tue Feb 02 14:03:58 2016 +0100
+@@ -16,7 +16,7 @@
+ void pl_drawscrollbar(Panel *p){
+ Scrollbar *sp;
+ sp=p->data;
+- sp->interior=pl_outline(p->b, p->r, p->state);
++ sp->interior=pl_outline(p->b, p->r, SUP); /* SUP was p->state */
+ pl_sliderupd(p->b, sp->interior, sp->dir, sp->lo, sp->hi);
+ }
+ int pl_hitscrollbar(Panel *g, Mouse *m){
+diff -r 3f9227bd4f1d sys/src/cmd/mothra/libpanel/textview.c
+--- a/sys/src/cmd/mothra/libpanel/textview.c Mon Feb 01 22:49:20 2016 +0100
++++ b/sys/src/cmd/mothra/libpanel/textview.c Tue Feb 02 14:03:58 2016 +0100
+@@ -47,7 +47,7 @@
+ Point size;
+
+ tp=p->data;
+- r=pl_outline(p->b, p->r, UP);
++ r=pl_outline(p->b, p->r, TUP);
+ twid=r.max.x-r.min.x;
+ if(twid!=tp->twid){
+ tp->twid=twid;
+@@ -80,7 +80,7 @@
+ if(oldhitword==oldhitfirst)
+ pl_passon(oldhitword, m);
+ if(m->buttons&OUT)
+- p->state=UP;
++ p->state=PASSIVE;
+ else if(m->buttons&7){
+ p->state=DOWN;
+ tp->buttons=m->buttons;
+@@ -100,7 +100,7 @@
+ }
+ else{
+ if(p->state==DOWN) hitme=1;
+- p->state=UP;
++ p->state=PASSIVE;
+ }
+ if(tp->hitfirst!=oldhitfirst || tp->hitword!=oldhitword){
+ plrtseltext(tp->text, tp->hitword, tp->hitfirst);
+@@ -214,7 +214,7 @@
+ Textview *tp;
+ tp=v->data;
+ v->flags=flags|LEAF;
+- v->state=UP;
++ v->state=PASSIVE;
+ v->draw=pl_drawtextview;
+ v->hit=pl_hittextview;
+ v->type=pl_typetextview;
+diff -r 3f9227bd4f1d sys/src/cmd/mothra/libpanel/textwin.c
+--- a/sys/src/cmd/mothra/libpanel/textwin.c Mon Feb 01 22:49:20 2016 +0100
++++ b/sys/src/cmd/mothra/libpanel/textwin.c Tue Feb 02 14:03:58 2016 +0100
+@@ -136,7 +136,7 @@
+ er=t->text+last;
+ for(r=t->text+first,lp=t->loc+(first-t->top);r!=er;r++,lp++){
+ if(lp->y+t->hgt>t->r.max.y){
+- fprint(2, "chr %C, index %ld of %d, loc %d %d, off bottom\n",
++ fprint(2, "chr %C, index %zd of %d, loc %d %d, off bottom\n",
+ *r, lp-t->loc, t->bot-t->top, lp->x, lp->y);
+ return;
+ }
+@@ -155,7 +155,7 @@
+ default:
+ buf[runetochar(buf, r)]='\0';
+ /***/ pl_clr(t->b, Rpt(*lp, addpt(*lp, stringsize(t->font, buf))));
+- ur=string(t->b, *lp, display->black, ZP, t->font, buf);
++ ur=string(t->b, *lp, txtcol, ZP, t->font, buf);
+ break;
+ }
+ if(lp[1].y!=lp[0].y)
+diff -r 3f9227bd4f1d sys/src/cmd/mothra/mothra.c
+--- a/sys/src/cmd/mothra/mothra.c Mon Feb 01 22:49:20 2016 +0100
++++ b/sys/src/cmd/mothra/mothra.c Tue Feb 02 14:03:58 2016 +0100
+@@ -38,17 +38,17 @@
+ 0x10, 0x08, 0x14, 0x08, 0x14, 0x28, 0x12, 0x28,
+ 0x0A, 0x50, 0x16, 0x68, 0x20, 0x04, 0x3F, 0xFC,
+ };
+-Cursor confirmcursor={
++Cursor confirmcurs={
+ 0, 0,
+- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++ 0x0F, 0xBF, 0x0F, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF,
++ 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE,
++ 0xFF, 0xFE, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF,
++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC,
+
+ 0x00, 0x0E, 0x07, 0x1F, 0x03, 0x17, 0x73, 0x6F,
+ 0xFB, 0xCE, 0xDB, 0x8C, 0xDB, 0xC0, 0xFB, 0x6C,
+ 0x77, 0xFC, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03,
+- 0x94, 0xA6, 0x63, 0x3C, 0x63, 0x18, 0x94, 0x90,
++ 0x94, 0xA6, 0x63, 0x3C, 0x63, 0x18, 0x94, 0x90
+ };
+ Cursor readingcurs={
+ -10, -3,
+@@ -349,15 +349,15 @@
+ plinit(screen->depth);
+ if(debug) notify(dienow);
+ getfonts();
+- hrule=allocimage(display, Rect(0, 0, 1, 5), screen->chan, 1, DWhite);
++ hrule=allocimage(display, Rect(0, 0, 2048, 5), screen->chan, 1, DBlack);
+ if(hrule==0)
+ sysfatal("can't allocimage!");
+- draw(hrule, Rect(0,1,1,3), display->black, 0, ZP);
+- linespace=allocimage(display, Rect(0, 0, 1, 5), screen->chan, 1, DWhite);
++ draw(hrule, Rect(0,1,1280,3), txtcol, 0, ZP);
++ linespace=display->black;
+ if(linespace==0)
+ sysfatal("can't allocimage!");
+- bullet=allocimage(display, Rect(0,0,25, 8), screen->chan, 0, DWhite);
+- fillellipse(bullet, Pt(4,4), 3, 3, display->black, ZP);
++ bullet=allocimage(display, Rect(0,0,25, 8), screen->chan, 0, DBlack);
++ fillellipse(bullet, Pt(4,4), 3, 3, txtcol, ZP);
+ mkpanels();
+ unlockdisplay(display);
+ eresized(0);
+@@ -422,11 +422,17 @@
+ search();
+ break;
+ case Kright:
+- sidescroll(text->size.x/4, 1);
++ scrolltext(text->size.y/24, 1); /* down one line */
+ break;
+ case Kleft:
++ scrolltext(-text->size.y/24, 1); /* up one line */
++ break;
++ case Kins:
+ sidescroll(-text->size.x/4, 1);
+ break;
++ case Kdel:
++ sidescroll(text->size.x/4, 1);
++ break;
+ }
+ break;
+ case Emouse:
+@@ -449,6 +455,18 @@
+ }
+ }
+ }
++Cursor confirmcursor={
++ 0, 0,
++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++
++ 0x00, 0x0E, 0x07, 0x1F, 0x03, 0x17, 0x73, 0x6F,
++ 0xFB, 0xCE, 0xDB, 0x8C, 0xDB, 0xC0, 0xFB, 0x6C,
++ 0x77, 0xFC, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03,
++ 0x94, 0xA6, 0x63, 0x3C, 0x63, 0x18, 0x94, 0x90,
++};
+ int confirm(int b){
+ Mouse down, up;
+ esetcursor(&confirmcursor);
+diff -r 3f9227bd4f1d sys/src/cmd/mothra/mothra.h
+--- a/sys/src/cmd/mothra/mothra.h Mon Feb 01 22:49:20 2016 +0100
++++ b/sys/src/cmd/mothra/mothra.h Tue Feb 02 14:03:58 2016 +0100
+@@ -1,7 +1,7 @@
+ enum{
+ NWWW=64, /* # of pages we hold in the log */
+- NXPROC=5, /* # of parallel procs loading the pix */
+- NPIXMB=8, /* megabytes of image data to keep arround */
++ NXPROC=16, /* # of parallel procs loading the pix */
++ NPIXMB=48, /* megabytes of image data to keep arround */
+ NNAME=512,
+ NLINE=256,
+ NAUTH=128,
--- /dev/null
+++ b/mothra-unifont
@@ -1,0 +1,384 @@
+diff -r b619d1fc23f6 sys/src/cmd/mothra/libpanel/draw.c
+--- a/sys/src/cmd/mothra/libpanel/draw.c Mon Feb 11 23:43:14 2019 +0100
++++ b/sys/src/cmd/mothra/libpanel/draw.c Wed Feb 13 15:03:32 2019 +0100
+@@ -15,14 +15,16 @@
+ #define CKBORDER 2 /* space around X inside frame */
+ static int plldepth;
+ static Image *pl_white, *pl_light, *pl_dark, *pl_black, *pl_hilit;
++Image *txtcol;
+ int pl_drawinit(int ldepth){
+ plldepth=ldepth;
+- pl_white=allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xFFFFFFFF);
+- pl_light=allocimagemix(display, DPalebluegreen, DWhite);
+- pl_dark =allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPurpleblue);
+- pl_black=allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x000000FF);
++ pl_white=display->black;
++ pl_light=display->black;
++ pl_dark=allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x222222FF);
++ pl_black=allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x770000FF);
+ pl_hilit=allocimage(display, Rect(0,0,1,1), CHAN1(CAlpha,8), 1, 0x80);
+- if(pl_white==0 || pl_light==0 || pl_black==0 || pl_dark==0) return 0;
++ txtcol=allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x884400FF);
++ if(pl_white==0 || pl_light==0 || pl_black==0 || pl_dark==0 || txtcol==0) return 0;
+ return 1;
+ }
+ void pl_relief(Image *b, Image *ul, Image *lr, Rectangle r, int wid){
+@@ -38,6 +40,13 @@
+ }
+ Rectangle pl_boxoutline(Image *b, Rectangle r, int style, int fill){
+ if(plldepth==0) switch(style){
++ case SUP:
++ case TUP:
++ pl_relief(b, pl_white, pl_white, r, BWID);
++ r=insetrect(r, BWID);
++ if(fill) draw(b, r, pl_white, 0, ZP);
++ else border(b, r, SPACE, pl_white, ZP);
++ break;
+ case UP:
+ pl_relief(b, pl_black, pl_black, r, BWID);
+ r=insetrect(r, BWID);
+@@ -68,6 +77,13 @@
+ break;
+ }
+ else switch(style){
++ case SUP:
++ case TUP:
++ pl_relief(b, pl_white, pl_white, r, BWID);
++ r=insetrect(r, BWID);
++ if(fill) draw(b, r, pl_light, 0, ZP);
++ else border(b, r, SPACE, pl_white, ZP);
++ break;
+ case UP:
+ pl_relief(b, pl_white, pl_black, r, BWID);
+ r=insetrect(r, BWID);
+@@ -97,7 +113,10 @@
+ else border(b, r, SPACE, pl_white, ZP);
+ break;
+ }
+- return insetrect(r, SPACE);
++ switch(style){
++ case SUP: return insetrect(r, SPACE-SPACE);
++ default: return insetrect(r, SPACE);
++ }
+ }
+ Rectangle pl_outline(Image *b, Rectangle r, int style){
+ return pl_boxoutline(b, r, style, 0);
+@@ -269,7 +288,7 @@
+ draw(b, r, pl_dark, pl_hilit, ZP);
+ }
+ void pl_clr(Image *b, Rectangle r){
+- draw(b, r, display->white, 0, ZP);
++ draw(b, r, display->black, 0, ZP);
+ }
+ void pl_fill(Image *b, Rectangle r){
+ draw(b, r, plldepth==0? pl_white : pl_light, 0, ZP);
+diff -r b619d1fc23f6 sys/src/cmd/mothra/libpanel/message.c
+--- a/sys/src/cmd/mothra/libpanel/message.c Mon Feb 11 23:43:14 2019 +0100
++++ b/sys/src/cmd/mothra/libpanel/message.c Wed Feb 13 15:03:32 2019 +0100
+@@ -29,7 +29,7 @@
+ end=s;
+ c=*end;
+ *end='\0';
+- string(b, where, display->black, ZP, f, start);
++ string(b, where, txtcol, ZP, f, start);
+ *end=c;
+ where.y+=font->height;
+ s=end;
+diff -r b619d1fc23f6 sys/src/cmd/mothra/libpanel/panel.h
+--- a/sys/src/cmd/mothra/libpanel/panel.h Mon Feb 11 23:43:14 2019 +0100
++++ b/sys/src/cmd/mothra/libpanel/panel.h Wed Feb 13 15:03:32 2019 +0100
+@@ -108,6 +108,7 @@
+ #define PL_STR 4
+
+ Panel *plkbfocus; /* the panel in keyboard focus */
++extern Image *txtcol;
+
+ int plinit(int); /* initialization */
+ void plpack(Panel *, Rectangle); /* figure out where to put the Panel & children */
+diff -r b619d1fc23f6 sys/src/cmd/mothra/libpanel/pldefs.h
+--- a/sys/src/cmd/mothra/libpanel/pldefs.h Mon Feb 11 23:43:14 2019 +0100
++++ b/sys/src/cmd/mothra/libpanel/pldefs.h Wed Feb 13 15:03:32 2019 +0100
+@@ -17,7 +17,9 @@
+ * States, also styles
+ */
+ enum{
+- UP,
++ SUP, // scrollbar
++ TUP, // textview
++ UP, // deprecated
+ DOWN1,
+ DOWN2,
+ DOWN3,
+diff -r b619d1fc23f6 sys/src/cmd/mothra/libpanel/rtext.c
+--- a/sys/src/cmd/mothra/libpanel/rtext.c Mon Feb 11 23:43:14 2019 +0100
++++ b/sys/src/cmd/mothra/libpanel/rtext.c Wed Feb 13 15:03:32 2019 +0100
+@@ -11,7 +11,7 @@
+ #include "rtext.h"
+
+ #define LEAD 4 /* extra space between lines */
+-#define BORD 2 /* extra border for images */
++#define BORD 0 /* extra border for images */
+
+ Rtext *pl_rtnew(Rtext **t, int space, int indent, int voff, Image *b, Panel *p, Font *f, char *s, int flags, void *user){
+ Rtext *new;
+@@ -195,14 +195,14 @@
+ && dr.min.x<r.max.x){
+ if(t->b){
+ draw(b, insetrect(dr, BORD), t->b, 0, t->b->r.min);
+- if(t->flags&PL_HOT) border(b, dr, 1, display->black, ZP);
++ if(t->flags&PL_HOT) border(b, dr, 1, txtcol, ZP);
+ if(t->flags&PL_STR) {
+ line(b, Pt(dr.min.x, dr.min.y), Pt(dr.max.x, dr.max.y),
+ Endsquare, Endsquare, 0,
+- display->black, ZP);
++ txtcol, ZP);
+ line(b, Pt(dr.min.x, dr.max.y), Pt(dr.max.x, dr.min.y),
+ Endsquare, Endsquare, 0,
+- display->black, ZP);
++ txtcol, ZP);
+ }
+ if(t->flags&PL_SEL)
+ pl_highlight(b, dr);
+@@ -214,7 +214,7 @@
+ pl_stuffbitmap(t->p, bb);
+ }
+ else{
+- string(b, dr.min, display->black, ZP, t->font, t->text);
++ string(b, dr.min, txtcol, ZP, t->font, t->text);
+ if(t->flags&PL_SEL)
+ pl_highlight(b, dr);
+ if(t->flags&PL_STR){
+@@ -223,7 +223,7 @@
+ sp = Pt(dr.min.x, y);
+ line(b, sp, Pt(dr.max.x, y),
+ Endsquare, Endsquare, 0,
+- display->black, ZP);
++ txtcol, ZP);
+ sp = Pt(dr.max.x, y);
+ } else
+ sp = ZP;
+@@ -233,7 +233,7 @@
+ lp = Pt(dr.min.x, y);
+ line(b, lp, Pt(dr.max.x, y),
+ Endsquare, Endsquare, 0,
+- display->black, ZP);
++ txtcol, ZP);
+ lp = Pt(dr.max.x, y);
+ } else
+ lp = ZP;
+diff -r b619d1fc23f6 sys/src/cmd/mothra/libpanel/scrollbar.c
+--- a/sys/src/cmd/mothra/libpanel/scrollbar.c Mon Feb 11 23:43:14 2019 +0100
++++ b/sys/src/cmd/mothra/libpanel/scrollbar.c Wed Feb 13 15:03:32 2019 +0100
+@@ -16,7 +16,7 @@
+ void pl_drawscrollbar(Panel *p){
+ Scrollbar *sp;
+ sp=p->data;
+- sp->interior=pl_outline(p->b, p->r, p->state);
++ sp->interior=pl_outline(p->b, p->r, SUP); /* SUP was p->state */
+ pl_sliderupd(p->b, sp->interior, sp->dir, sp->lo, sp->hi);
+ }
+ int pl_hitscrollbar(Panel *g, Mouse *m){
+diff -r b619d1fc23f6 sys/src/cmd/mothra/libpanel/textview.c
+--- a/sys/src/cmd/mothra/libpanel/textview.c Mon Feb 11 23:43:14 2019 +0100
++++ b/sys/src/cmd/mothra/libpanel/textview.c Wed Feb 13 15:03:32 2019 +0100
+@@ -47,7 +47,7 @@
+ Point size;
+
+ tp=p->data;
+- r=pl_outline(p->b, p->r, UP);
++ r=pl_outline(p->b, p->r, TUP);
+ twid=r.max.x-r.min.x;
+ if(twid!=tp->twid){
+ tp->twid=twid;
+@@ -80,7 +80,7 @@
+ if(oldhitword==oldhitfirst)
+ pl_passon(oldhitword, m);
+ if(m->buttons&OUT)
+- p->state=UP;
++ p->state=PASSIVE;
+ else if(m->buttons&7){
+ p->state=DOWN;
+ tp->buttons=m->buttons;
+@@ -100,7 +100,7 @@
+ }
+ else{
+ if(p->state==DOWN) hitme=1;
+- p->state=UP;
++ p->state=PASSIVE;
+ }
+ if(tp->hitfirst!=oldhitfirst || tp->hitword!=oldhitword){
+ plrtseltext(tp->text, tp->hitword, tp->hitfirst);
+@@ -214,7 +214,7 @@
+ Textview *tp;
+ tp=v->data;
+ v->flags=flags|LEAF;
+- v->state=UP;
++ v->state=PASSIVE;
+ v->draw=pl_drawtextview;
+ v->hit=pl_hittextview;
+ v->type=pl_typetextview;
+diff -r b619d1fc23f6 sys/src/cmd/mothra/libpanel/textwin.c
+--- a/sys/src/cmd/mothra/libpanel/textwin.c Mon Feb 11 23:43:14 2019 +0100
++++ b/sys/src/cmd/mothra/libpanel/textwin.c Wed Feb 13 15:03:32 2019 +0100
+@@ -136,7 +136,7 @@
+ er=t->text+last;
+ for(r=t->text+first,lp=t->loc+(first-t->top);r!=er;r++,lp++){
+ if(lp->y+t->hgt>t->r.max.y){
+- fprint(2, "chr %C, index %ld of %d, loc %d %d, off bottom\n",
++ fprint(2, "chr %C, index %zd of %d, loc %d %d, off bottom\n",
+ *r, lp-t->loc, t->bot-t->top, lp->x, lp->y);
+ return;
+ }
+@@ -155,7 +155,7 @@
+ default:
+ buf[runetochar(buf, r)]='\0';
+ /***/ pl_clr(t->b, Rpt(*lp, addpt(*lp, stringsize(t->font, buf))));
+- ur=string(t->b, *lp, display->black, ZP, t->font, buf);
++ ur=string(t->b, *lp, txtcol, ZP, t->font, buf);
+ break;
+ }
+ if(lp[1].y!=lp[0].y)
+diff -r b619d1fc23f6 sys/src/cmd/mothra/mothra.c
+--- a/sys/src/cmd/mothra/mothra.c Mon Feb 11 23:43:14 2019 +0100
++++ b/sys/src/cmd/mothra/mothra.c Wed Feb 13 15:03:32 2019 +0100
+@@ -39,17 +39,17 @@
+ 0x10, 0x08, 0x14, 0x08, 0x14, 0x28, 0x12, 0x28,
+ 0x0A, 0x50, 0x16, 0x68, 0x20, 0x04, 0x3F, 0xFC,
+ };
+-Cursor confirmcursor={
++Cursor confirmcurs={
+ 0, 0,
+- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++ 0x0F, 0xBF, 0x0F, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF,
++ 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE,
++ 0xFF, 0xFE, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF,
++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC,
+
+ 0x00, 0x0E, 0x07, 0x1F, 0x03, 0x17, 0x73, 0x6F,
+ 0xFB, 0xCE, 0xDB, 0x8C, 0xDB, 0xC0, 0xFB, 0x6C,
+ 0x77, 0xFC, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03,
+- 0x94, 0xA6, 0x63, 0x3C, 0x63, 0x18, 0x94, 0x90,
++ 0x94, 0xA6, 0x63, 0x3C, 0x63, 0x18, 0x94, 0x90
+ };
+ Cursor readingcurs={
+ -10, -3,
+@@ -351,15 +351,15 @@
+ plinit(screen->depth);
+ if(debug) notify(dienow);
+ getfonts();
+- hrule=allocimage(display, Rect(0, 0, 1, 5), screen->chan, 1, DWhite);
++ hrule=allocimage(display, Rect(0, 0, 2048, 5), screen->chan, 1, DBlack);
+ if(hrule==0)
+ sysfatal("can't allocimage!");
+- draw(hrule, Rect(0,1,1,3), display->black, 0, ZP);
+- linespace=allocimage(display, Rect(0, 0, 1, 5), screen->chan, 1, DWhite);
++ draw(hrule, Rect(0,1,1280,3), txtcol, 0, ZP);
++ linespace=display->black;
+ if(linespace==0)
+ sysfatal("can't allocimage!");
+- bullet=allocimage(display, Rect(0,0,25, 8), screen->chan, 0, DWhite);
+- fillellipse(bullet, Pt(4,4), 3, 3, display->black, ZP);
++ bullet=allocimage(display, Rect(0,0,25, 8), screen->chan, 0, DBlack);
++ fillellipse(bullet, Pt(4,4), 3, 3, txtcol, ZP);
+ mkpanels();
+ unlockdisplay(display);
+ eresized(0);
+@@ -423,11 +423,17 @@
+ search();
+ break;
+ case Kright:
+- sidescroll(text->size.x/4, 1);
++ scrolltext(text->size.y/24, 1); /* down one line */
+ break;
+ case Kleft:
++ scrolltext(-text->size.y/24, 1); /* up one line */
++ break;
++ case Kins:
+ sidescroll(-text->size.x/4, 1);
+ break;
++ case Kdel:
++ sidescroll(text->size.x/4, 1);
++ break;
+ }
+ break;
+ case Emouse:
+@@ -450,6 +456,18 @@
+ }
+ }
+ }
++Cursor confirmcursor={
++ 0, 0,
++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++
++ 0x00, 0x0E, 0x07, 0x1F, 0x03, 0x17, 0x73, 0x6F,
++ 0xFB, 0xCE, 0xDB, 0x8C, 0xDB, 0xC0, 0xFB, 0x6C,
++ 0x77, 0xFC, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03,
++ 0x94, 0xA6, 0x63, 0x3C, 0x63, 0x18, 0x94, 0x90,
++};
+ int confirm(int b){
+ Mouse down, up;
+ esetcursor(&confirmcursor);
+diff -r b619d1fc23f6 sys/src/cmd/mothra/mothra.h
+--- a/sys/src/cmd/mothra/mothra.h Mon Feb 11 23:43:14 2019 +0100
++++ b/sys/src/cmd/mothra/mothra.h Wed Feb 13 15:03:32 2019 +0100
+@@ -1,7 +1,7 @@
+ enum{
+ NWWW=64, /* # of pages we hold in the log */
+- NXPROC=5, /* # of parallel procs loading the pix */
+- NPIXMB=8, /* megabytes of image data to keep arround */
++ NXPROC=16, /* # of parallel procs loading the pix */
++ NPIXMB=48, /* megabytes of image data to keep arround */
+ NNAME=512,
+ NLINE=256,
+ NAUTH=128,
+diff -r b619d1fc23f6 sys/src/cmd/mothra/rdhtml.c
+--- a/sys/src/cmd/mothra/rdhtml.c Mon Feb 11 23:43:14 2019 +0100
++++ b/sys/src/cmd/mothra/rdhtml.c Wed Feb 13 15:03:32 2019 +0100
+@@ -13,25 +13,25 @@
+ Font *font;
+ int space;
+ }fontlist[4][4]={
+- "dejavusans/unicode.12", 0, 0,
+- "dejavusans/unicode.12", 0, 0,
+- "dejavusans/unicode.14", 0, 0,
+- "dejavusans/unicode.16", 0, 0,
++ "unifont/unifont.12", 0, 0,
++ "unifont/unifont.12", 0, 0,
++ "unifont/unifont.14", 0, 0,
++ "unifont/unifont.16", 0, 0,
+
+- "dejavusansit/unicode.12", 0, 0,
+- "dejavusansit/unicode.12", 0, 0,
+- "dejavusansit/unicode.14", 0, 0,
+- "dejavusansit/unicode.16", 0, 0,
++ "unifont/unifont.12", 0, 0,
++ "unifont/unifont.12", 0, 0,
++ "unifont/unifont.14", 0, 0,
++ "unifont/unifont.16", 0, 0,
+
+- "dejavusansbd/unicode.12", 0, 0,
+- "dejavusansbd/unicode.12", 0, 0,
+- "dejavusansbd/unicode.14", 0, 0,
+- "dejavusansbd/unicode.16", 0, 0,
++ "unifont/unifont.12", 0, 0,
++ "unifont/unifont.12", 0, 0,
++ "unifont/unifont.14", 0, 0,
++ "unifont/unifont.16", 0, 0,
+
+- "terminus/unicode.12", 0, 0,
+- "terminus/unicode.14", 0, 0,
+- "terminus/unicode.16", 0, 0,
+- "terminus/unicode.18", 0, 0,
++ "unifont/unifont.12", 0, 0,
++ "unifont/unifont.14", 0, 0,
++ "unifont/unifont.16", 0, 0,
++ "unifont/unifont.18", 0, 0,
+ };
+
+ Font *pl_whichfont(int f, int s, int *space){
--- /dev/null
+++ b/nusb-ure
@@ -1,0 +1,492 @@
+patch for broken fucking ure piece of shit ass fuck
+usb ether card; incomplete since the fucking thing died
+
+diff -r ebaff70ba8fe sys/src/9/boot/nusbrc
+--- a/sys/src/9/boot/nusbrc Mon May 22 18:33:14 2017 +0200
++++ b/sys/src/9/boot/nusbrc Sat May 27 11:58:35 2017 +0200
+@@ -23,6 +23,8 @@
+ nusb/ether -t aue $etherargs $id
+ case 0bda8150
+ nusb/ether -t url $etherargs $id
++ case 0bda8151
++ nusb/ether -t ure $etherargs $id
+ case 18d14ee3 0bb40003
+ nusb/ether -t rndis $etherargs $id
+ case *
+diff -r ebaff70ba8fe sys/src/cmd/nusb/ether/ether.c
+--- a/sys/src/cmd/nusb/ether/ether.c Mon May 22 18:33:14 2017 +0200
++++ b/sys/src/cmd/nusb/ether/ether.c Sat May 27 11:58:35 2017 +0200
+@@ -808,6 +808,7 @@
+ extern int a88772init(Dev *);
+ extern int smscinit(Dev *);
+ extern int cdcinit(Dev *);
++extern int ureinit(Dev *);
+ extern int urlinit(Dev *);
+ extern int rndisinit(Dev *);
+
+@@ -820,6 +821,7 @@
+ "a88178", a88178init,
+ "a88772", a88772init,
+ "aue", aueinit,
++ "ure", ureinit,
+ "url", urlinit,
+ "rndis", rndisinit,
+ };
+diff -r ebaff70ba8fe sys/src/cmd/nusb/ether/mkfile
+--- a/sys/src/cmd/nusb/ether/mkfile Mon May 22 18:33:14 2017 +0200
++++ b/sys/src/cmd/nusb/ether/mkfile Sat May 27 11:58:35 2017 +0200
+@@ -5,7 +5,7 @@
+
+ TARG=ether
+ HFILES=
+-OFILES=ether.$O cdc.$O smsc.$O asix.$O aue.$O url.$O rndis.$O
++OFILES=ether.$O cdc.$O smsc.$O asix.$O aue.$O ure.$O url.$O rndis.$O
+
+ </sys/src/cmd/mkone
+
+diff -r ebaff70ba8fe sys/src/cmd/nusb/ether/ure.c
+--- /dev/null Thu Jan 01 00:00:00 1970 +0000
++++ b/sys/src/cmd/nusb/ether/ure.c Sat May 27 11:58:35 2017 +0200
+@@ -0,0 +1,442 @@
++/*
++ * Realtek RTL8152 10/100 USB Ethernet
++ */
++/* FIXME: note on submit: based on url.c and openbsd's ure(4) driver rev 1.3
++ * + changes to nusbrc */
++#include <u.h>
++#include <libc.h>
++#include <thread.h>
++
++#include "usb.h"
++#include "dat.h"
++
++enum {
++ Timeout = 1000,
++ Ver4c00 = 0x4c00,
++ Ver4c10 = 0x4c10,
++
++ /* requests */
++ Rqm = 0x05, /* request mem */
++ Crm = 1, /* command read mem */
++ Cwm = 2, /* command write mem */
++ Cpla = 0x100, /* indices */
++ Cusb = 0x000,
++
++ /* registers */
++ Idr = 0xc000, /* ether addr */
++ Rcr = 0xc010, /* receive configuration */
++ Ab = 1<<3,
++ Am = 1<<2,
++ Apm = 1<<1,
++ Aap = 1<<0,
++ Rfifo0 = 0xc0a0, /* rx fifo */
++ Thr1n = 0x00080002, /* thr1 normal */
++ Rfifo1 = 0xc0a4,
++ Thr2fl = 0x00000060, /* thr2 full speed */
++ Thr2hi = 0x00000038, /* thr2 high speed */
++ Rfifo2 = 0xc0a8,
++ Thr3fl = 0x00000078, /* thr3 full speed */
++ Thr3hi = 0x00000048, /* thr3 high speed */
++ Fmc = 0xc0b4, /* packet filter */
++ Fcr = 1<<0,
++ Tun = 0xc0bc, /* teredo configuration */
++ Tusel = 1<<15, /* select */
++ Tuwak = 0x7f00, /* wake mask */
++ Turs = 0x00fe, /* rs event mask */
++ Tunm = Tusel | Tuwak | Turs,
++ Mar0 = 0xcd00, /* multicast addr */
++ Mar4 = 0xcd04,
++ Bak = 0xd000, /* backup */
++ Tutm = 0xd2cc, /* teredo timer */
++ Wow = 0xd2e8, /* realwow timer */
++ Led = 0xdd92, /* led control */
++ Ledm = 7<<8, /* mode mask */
++ Phimr = 0xe022, /* gphy intr imr */
++ Ilnkch = 1<<3, /* speed down link change */
++ Irxdv = 1<<2, /* speed down rxdv */
++ Ispddn = 1<<1, /* speed down */
++ Ists = 1<<0, /* status */
++ Mcpwr = 0xe0c0, /* mac power control */
++ D3clk = 1<<14,
++ Mcuclk = 0x07010f07,
++ Mcuclkm = 0x0f0f0f0f,
++ Wdt6 = 0xe428,
++ Wdtmd = 1<<0, /* wdt6 set mode */
++ Tcr0 = 0xe610,
++ Fifoau = 1<<7, /* auto fifo */
++ Tcr1 = 0xe612,
++ Ver = 0x7cf0, /* version mask */
++ Tfifo = 0xe618, /* tx fifo */
++ Thrn = 0x00400008, /* thr normal */
++ Cr = 0xe813, /* command */
++ Sr = 1<<4, /* software reset */
++ Re = 1<<3, /* ethernet receive enable */
++ Te = 1<<2, /* ethernet transmit enable */
++ Phpwr = 0xe84c, /* phy power control */
++ Txidl = 1<<7, /* tx 10m idle */
++ Pfmpwm = 1<<6,
++ Oob = 0xe84f, /* oob control */
++ Ook = 1<<7, /* now is oob */
++ Ordy = 1<<1, /* link list ready */
++ Cpcr = 0xe854,
++ Rxvlan = 1<<6,
++ Msc1 = 0xe85a, /* misc 1 */
++ Rxdy = 1<<3,
++ Rocp = 0xe86c, /* ocp gphy base */
++ Aldps = 0x2010, /* aldps configuration */
++ Aldpsa = Aldps & 0xf000,
++ Aldpsr = Aldps & 0x0fff | 0xb000,
++ Pwsv = 1<<15, /* power save */
++ Pdnps = 1<<9,
++ Lnk = 1<<8, /* link enable */
++ Dis = 1<<4, /* dis sdsave */
++ Sff7 = 0xe8de, /* sff status 7 */
++ Inll = 1<<15,
++ Borw = 1<<14,
++
++ Ucr = 0xd406, /* usb control */
++ Noagg = 1<<4, /* disable rx aggregation */
++ Txag = 0xd40a, /* tx aggregation */
++ Maxth = 3<<0, /* max threshold */
++ Urth = 0xd40c, /* rx buf threshold */
++ Urthhi = 0x7a120180,
++ Pms = 0xd432, /* pm status */
++ Rsm = 1<<0, /* resume indicate */
++ Udma = 0xd434,
++ Txadj1 = 1<<8, /* tx size adjust 1 */
++ Tstoff = 1<<0, /* test mode disable */
++ Ups = 0xd800,
++ Cut = 1<<8 /* power cut */
++};
++
++static int
++mem(Dev *d, int cmd, int off, int index, uchar *buf, int len)
++{
++ int r, rc;
++
++ if(d == nil)
++ return 0;
++ r = Rvendor | Rdev;
++ if(cmd == Crm)
++ r |= Rd2h;
++ else
++ r |= Rh2d;
++ rc = usbcmd(d, r, Rqm, off, index, buf, len);
++ if(rc < 0){
++ fprint(2, "%s: mem(%d, %#.4x, %#.4x) failed\n",
++ argv0, cmd, off, index);
++ }
++ return rc;
++}
++
++static int
++rr8(Dev *d, int reg, int index)
++{
++ uchar v[4], m;
++
++ m = (reg & 3) << 3;
++ reg &= ~3;
++ PUT4(v, 0);
++ if(mem(d, Crm, reg, index, v, sizeof v) < 0)
++ return 0;
++ fprint(2, "rr8 %ux %ux %ux\n", reg, index, GET4(v) >> m & 0xff);
++ return GET4(v) >> m & 0xff;
++}
++
++static int
++rr16(Dev *d, int reg, int index)
++{
++ uchar v[4], m;
++
++ m = (reg & 2) << 3;
++ reg &= ~3;
++ PUT4(v, 0);
++ if(mem(d, Crm, reg, index, v, sizeof v) < 0)
++ return 0;
++ fprint(2, "rr16 %ux %ux %ux\n", reg, index, GET4(v) >> m & 0xffff);
++ return GET4(v) >> m & 0xffff;
++}
++
++static int
++rr32(Dev *d, int reg, int index)
++{
++ uchar v[4];
++
++ PUT4(v, 0);
++ if(mem(d, Crm, reg, index, v, sizeof v) < 0)
++ return 0;
++ fprint(2, "rr32 %ux %ux %ux\n", reg, index, GET4(v));
++ return GET4(v);
++}
++
++static int
++wr8(Dev *d, int reg, int index, int val)
++{
++ uchar v[4], m;
++ u16int en;
++
++ fprint(2, "wr8 %ux %ux %ux\n", reg, index, val);
++ en = 0x11;
++ m = reg & 3;
++ val &= 0xff;
++ if(reg & 3){
++ en <<= m;
++ val <<= m << 3;
++ reg &= ~3;
++ }
++ PUT4(v, val);
++ if(mem(d, Cwm, reg, index | en, v, sizeof v) < 0)
++ return -1;
++ return 0;
++}
++
++static int
++wr16(Dev *d, int reg, int index, int val)
++{
++ uchar v[4], m;
++ u16int en;
++
++ fprint(2, "wr16 %ux %ux %ux\n", reg, index, val);
++ en = 0x33;
++ m = reg & 2;
++ val &= 0xffff;
++ if(reg & 2){
++ en <<= m;
++ val <<= m << 3;
++ reg &= ~3;
++ }
++ PUT4(v, val);
++ if(mem(d, Cwm, reg, index | en, v, sizeof v) < 0)
++ return -1;
++ return 0;
++}
++
++static int
++wr32(Dev *d, int reg, int index, int val)
++{
++ uchar v[4];
++
++ fprint(2, "wr32 %ux %ux %ux\n", reg, index, val);
++ PUT4(v, val);
++ if(mem(d, Cwm, reg, index | 0xff, v, sizeof v) < 0)
++ return -1;
++ return 0;
++}
++
++static int
++csr8(Dev *d, int reg, int index, int clr, int set)
++{
++ int v;
++
++ v = rr8(d, reg, index) & ~clr | set;
++ return wr8(d, reg, index, v);
++}
++
++static int
++csr16(Dev *d, int reg, int index, int clr, int set)
++{
++ int v;
++
++ v = rr16(d, reg, index) & ~clr | set;
++ return wr16(d, reg, index, v);
++}
++
++static int
++csr32(Dev *d, int reg, int index, int clr, int set)
++{
++ int v;
++
++ v = rr32(d, reg, index) & ~clr | set;
++ return wr32(d, reg, index, v);
++}
++
++static void
++oobwait(Dev *d)
++{
++ int i;
++
++ for(i=0; i<Timeout; i++){
++ if(rr8(d, Oob, Cpla) & Ordy)
++ break;
++ sleep(10);
++ }
++ if(i == Timeout)
++ fprint(2, "%s: timeout waiting for OOB control\n", argv0);
++}
++
++static void
++reset(Dev *d)
++{
++ int i;
++
++ wr8(d, Cr, Cpla, Sr);
++ for(i=0; i<Timeout; i++) {
++ if((rr8(d, Cr, Cpla) & Sr) == 0)
++ break;
++ sleep(10);
++ }
++ if(i >= Timeout)
++ fprint(2, "%s: reset failed\n", argv0);
++ sleep(100);
++}
++
++static int
++phyinit(Dev *d)
++{
++ int r, v;
++ uchar a[8];
++
++ reset(d);
++ v = rr16(d, Tcr1, Cpla) & Ver;
++ if(!setmac){
++ r = v == Ver4c10 ? Bak : Idr;
++ if(mem(d, Crm, r, Cpla, a, sizeof a) < 0)
++ return -1;
++ memcpy(macaddr, a, sizeof macaddr);
++ }
++
++ wr16(d, Rocp, Cpla, Aldpsa);
++ wr16(d, Aldpsr, Cpla, Pwsv | Pdnps | Lnk | Dis);
++ sleep(20);
++
++ if(v == 0x4c00)
++ csr16(d, Led, Cpla, Ledm, 0);
++ csr16(d, Ups, Cusb, Cut, 0);
++ csr16(d, Pms, Cusb, Rsm, 0);
++ csr16(d, Phpwr, Cpla, 0, Txidl | Pfmpwm);
++ csr32(d, Mcpwr, Cpla, Mcuclkm, Mcuclk | D3clk);
++ wr16(d, Phimr, Cpla, Ists | Ispddn | Irxdv | Ilnkch);
++ csr16(d, Ucr, Cusb, 0, Noagg);
++
++ wr16(d, Rocp, Cpla, Aldpsa);
++ wr16(d, Aldpsr, Cpla, Pwsv | Pdnps | Lnk | Dis);
++ sleep(20);
++
++ csr16(d, Msc1, Cpla, 0, Rxdy);
++ csr32(d, Tun, Cpla, Tunm, 0);
++ wr16(d, Wdt6, Cpla, Wdtmd);
++ wr16(d, Wow, Cpla, 0);
++ wr32(d, Tutm, Cpla, 0);
++ csr32(d, Rcr, Cpla, Aap | Apm | Am | Ab, 0);
++ reset(d);
++ wr8(d, Cr, Cpla, 0);
++
++ csr8(d, Oob, Cpla, Ook, 0);
++ csr16(d, Sff7, Cpla, Borw, 0);
++ oobwait(d);
++ csr16(d, Sff7, Cpla, 0, Inll);
++ oobwait(d);
++
++ csr16(d, Cpcr, Cpla, Rxvlan, 0);
++ csr16(d, Tcr0, Cpla, Fifoau, 0);
++ wr32(d, Rfifo0, Cpla, Thr1n);
++ wr32(d, Rfifo1, Cpla, Thr2fl);
++ wr32(d, Rfifo2, Cpla, Thr3fl);
++ wr32(d, Tfifo, Cpla, Thrn);
++ wr8(d, Txag, Cusb, Maxth);
++ wr32(d, Urth, Cusb, Urthhi);
++ wr32(d, Udma, Cusb, Tstoff | Txadj1);
++ reset(d);
++ return 0;
++}
++
++static int
++urereceive(Dev *ep)
++{
++ Block *b;
++ int n;
++
++ b = allocb(Maxpkt+24);
++ if((n = read(ep->dfd, b->wp, b->lim - b->base)) < 0){
++ freeb(b);
++ return -1;
++ }
++ b->wp += n;
++ fprint(2, "urerx %d\n", n);
++ while(BLEN(b) > 24){
++ n = GET4(b->rp) & 0x7fff;
++ b->rp += 24;
++ if(n > BLEN(b))
++ break;
++ etheriq(b, 1);
++ b->rp += n;
++ }
++ freeb(b);
++ return 0;
++}
++
++static void
++uretransmit(Dev *ep, Block *b)
++{
++ int n;
++
++ n = BLEN(b);
++ fprint(2, "uretx %d\n", n);
++ b->rp -= 8;
++ PUT4(b->rp, n + 8 | 3 << 30);
++ PUT4(b->rp+4, 0);
++ write(ep->dfd, b->rp, 8+n);
++ freeb(b);
++ fprint(2, "done\n");
++}
++
++static int
++urepromiscuous(Dev *d, int on)
++{
++ int c, s;
++
++ c = 0;
++ s = 0;
++ if(on)
++ s |= Am | Aap;
++ else{
++ c = Aap;
++ if(nmulti == 0)
++ c |= Am;
++ }
++ return csr16(d, Rcr, Cpla, c, s);
++}
++
++static int
++uremulticast(Dev *d, uchar*, int)
++{
++ int c, s;
++
++ c = 0;
++ s = 0;
++ if(nmulti)
++ s |= Am;
++ else{
++ if(nprom == 0)
++ c = Am;
++ }
++ return csr16(d, Rcr, Cpla, c, s);
++}
++
++int
++ureinit(Dev *d)
++{
++ uchar a[8];
++
++ if(phyinit(d) < 0)
++ return -1;
++ memset(a, 0, sizeof a);
++ memcpy(a, macaddr, sizeof macaddr);
++ if(mem(d, Cwm, Idr, Cpla | 0x3f, a, sizeof a) < 0)
++ return -1;
++
++ csr16(d, Fmc, Cpla, Fcr, 0);
++ csr16(d, Fmc, Cpla, 0, Fcr);
++ csr8(d, Cr, Cpla, 0, Re | Te);
++ csr16(d, Msc1, Cpla, Rxdy, 0);
++ wr32(d, Rcr, Cpla, Apm);
++ wr32(d, Mar0, Cpla, 0);
++ wr32(d, Mar4, Cpla, 0);
++ wr32(d, Rcr, Cpla, Apm | Am);
++
++ epreceive = urereceive;
++ eptransmit = uretransmit;
++ eppromiscuous = urepromiscuous;
++ epmulticast = uremulticast;
++ return 0;
++}
--- /dev/null
+++ b/page-invert
@@ -1,0 +1,73 @@
+this shit sucks. that code doesn't belong there. something in pipeline would be
+better. pico?
+
+diff -r 3cb0cf9ab43a sys/src/cmd/page.c
+--- a/sys/src/cmd/page.c Mon Feb 08 20:07:56 2016 -0500
++++ b/sys/src/cmd/page.c Thu Feb 11 16:16:28 2016 +0100
+@@ -33,6 +33,7 @@
+ int imode;
+ int newwin;
+ int rotate;
++int invert;
+ int viewgen;
+ int forward; /* read ahead direction: >= 0 forwards, < 0 backwards */
+ Point resize, pos;
+@@ -67,6 +68,7 @@
+ Cfitheight,
+ Crotate90,
+ Cupsidedown,
++ Cinv,
+ Cdummy1,
+ Cnext,
+ Cprev,
+@@ -91,6 +93,7 @@
+ [Cfitheight] "fit height", 'h', 0, 0,
+ [Crotate90] "rotate 90", 'r', 0, 0,
+ [Cupsidedown] "upside down", 'u', 0, 0,
++ [Cinv] "invert", 'i', 0, 0,
+ [Cdummy1] "", 0, 0, 0,
+ [Cnext] "next", Kright, ' ', '\n',
+ [Cprev] "prev", Kleft, Kbs, 0,
+@@ -894,6 +897,23 @@
+ }
+
+ void
++inv(Image *i)
++{
++ int n;
++ uchar *buf, *p;
++
++ n = imagesize(i);
++ buf = malloc(n);
++ if(buf == 0)
++ return;
++ unloadimage(i, i->r, buf, n);
++ for(p=buf; p<buf+n; p++)
++ *p = ~*p;
++ loadimage(i, i->r, buf, n);
++ free(buf);
++}
++
++void
+ loadpage(Page *p)
+ {
+ int fd;
+@@ -912,6 +932,8 @@
+ if(p->image == nil)
+ p->open = nil;
+ else {
++ if(invert)
++ inv(p->image);
+ lockdisplay(display);
+ imemsize += imagesize(p->image);
+ unlockdisplay(display);
+@@ -1494,6 +1516,9 @@
+ resize = subpt(screen->r.max, screen->r.min);
+ resize.x = 0;
+ goto Unload;
++ case Cinv:
++ invert = !invert;
++ goto Unload;
+ case Czoomin:
+ case Czoomout:
+ if(current == nil || !canqlock(current))
--- /dev/null
+++ b/page-invertone
@@ -1,0 +1,57 @@
+diff -r 813115218568 sys/src/cmd/page.c
+--- a/sys/src/cmd/page.c Tue Jan 19 13:06:22 2016 +0100
++++ b/sys/src/cmd/page.c Sat Jan 23 01:35:43 2016 +0100
+@@ -67,6 +67,7 @@
+ Cfitheight,
+ Crotate90,
+ Cupsidedown,
++ Cinv,
+ Cdummy1,
+ Cnext,
+ Cprev,
+@@ -91,6 +92,7 @@
+ [Cfitheight] "fit height", 'h', 0, 0,
+ [Crotate90] "rotate 90", 'r', 0, 0,
+ [Cupsidedown] "upside down", 'u', 0, 0,
++ [Cinv] "invert", 'i', 0, 0,
+ [Cdummy1] "", 0, 0, 0,
+ [Cnext] "next", Kright, ' ', '\n',
+ [Cprev] "prev", Kleft, Kbs, 0,
+@@ -1375,6 +1377,23 @@
+ }
+
+ void
++inv(Image *i)
++{
++ int n;
++ uchar *buf, *p;
++
++ n = imagesize(i);
++ buf = malloc(n);
++ if(buf == 0)
++ return;
++ unloadimage(i, i->r, buf, n);
++ for(p=buf; p<buf+n; p++)
++ *p = ~*p;
++ loadimage(i, i->r, buf, n);
++ free(buf);
++}
++
++void
+ showext(Page *p)
+ {
+ char label[64], *argv[4];
+@@ -1494,6 +1513,13 @@
+ resize = subpt(screen->r.max, screen->r.min);
+ resize.x = 0;
+ goto Unload;
++ case Cinv:
++ if(current == nil || !canqlock(current))
++ break;
++ inv(current->image);
++ drawpage(current);
++ qunlock(current);
++ break;
+ case Czoomin:
+ case Czoomout:
+ if(current == nil || !canqlock(current))
--- /dev/null
+++ b/page-tempfix
@@ -1,0 +1,12 @@
+diff -r 2579c34216f2 sys/src/cmd/page.c
+--- a/sys/src/cmd/page.c Tue Jul 05 23:21:36 2016 -0500
++++ b/sys/src/cmd/page.c Fri Jul 08 10:02:17 2016 +0200
+@@ -436,7 +436,7 @@
+ "/\\<itemref/{"
+ "if(match($0, /idref\\=\\\"([^\\\"]+)\\\"/)){"
+ "ref=substr($0, RSTART+7, RLENGTH-8);"
+- "print item[ref]; fflush}}'");
++ "print item[ref]}}'");
+ s = strrchr(buf, '/')+1;
+ while((n = read(fd, s, e-s)) > 0){
+ while(n > 0 && s[n-1] == '\n')
--- /dev/null
+++ b/paint-colpick
@@ -1,0 +1,35 @@
+diff -r eb26bc92b777 sys/src/cmd/paint.c
+--- a/sys/src/cmd/paint.c Sun Jan 13 17:17:11 2019 +0100
++++ b/sys/src/cmd/paint.c Sun Jan 20 07:54:13 2019 +0100
+@@ -523,9 +523,12 @@
+ return 1;
+ }
+ if(ptinrect(m.xy, palr)){
++ int i, n;
++ char buf[32];
+ Image *col;
+
+- col = pal[(m.xy.x - palr.min.x) * nelem(pal) / Dx(palr)];
++ i = (m.xy.x - palr.min.x) * nelem(pal) / Dx(palr);
++ col = pal[i];
+ switch(m.buttons & 7){
+ case 1:
+ ink = col;
+@@ -536,6 +539,17 @@
+ drawpal();
+ update(nil);
+ break;
++ case 4:
++ buf[0] = 0;
++ if(eenter("Color", buf, sizeof(buf), &m) <= 0)
++ break;
++ n = strtol(buf, nil, 0);
++ freeimage(pal[i]);
++ pal[i] = allocimage(display, Rect(0, 0, 1, 1), RGB24, 1, n << 8 | 0xFF);
++ if(pal[i] == nil)
++ sysfatal("allocimage: %r");
++ drawpal();
++ break;
+ }
+ return 1;
+ }
--- /dev/null
+++ b/paint-reverse
@@ -1,0 +1,14 @@
+diff -r 18ea8aad3bb6 sys/src/cmd/paint.c
+--- a/sys/src/cmd/paint.c Mon Feb 25 04:36:37 2019 +0100
++++ b/sys/src/cmd/paint.c Tue Feb 26 18:27:09 2019 +0100
+@@ -625,8 +639,8 @@
+ if(pal[i] == nil)
+ sysfatal("allocimage: %r");
+ }
+- ink = pal[0];
+- back = pal[1];
++ ink = pal[1];
++ back = pal[0];
+ drawpal();
+ center();
+
--- /dev/null
+++ b/pc64-nvidia
@@ -1,0 +1,20 @@
+diff -r 2c3766a9188f sys/src/9/pc64/mkfile
+--- a/sys/src/9/pc64/mkfile Sun May 21 17:27:30 2017 +0200
++++ b/sys/src/9/pc64/mkfile Mon May 22 08:05:44 2017 +0200
+@@ -84,7 +84,7 @@
+
+ # copies generated by the rule below
+ PCHEADERS=wifi.h usbehci.h screen.h etherif.h ethermii.h mp.h io.h ahci.h \
+- yukdump.h
++ yukdump.h nv_dma.h
+
+ REPCH=`{echo $PCHEADERS | sed 's/\.h//g; s/ /|/g'}
+ ^($REPCH)\.h:R: ../pc/\1.h
+@@ -106,6 +106,7 @@
+ etheryuk.$O: yukdump.h
+ $VGA mouse.$O: screen.h /sys/include/memdraw.h
+ vgavesa.$O: /386/include/ureg.h
++vganvidia.$O: nv_dma.h
+
+ mp.$O: mp.h apbootstrap.h
+ apic.$O squidboy.$O: mp.h
--- /dev/null
+++ b/play-dmid-mod
@@ -1,0 +1,43 @@
+diff -r a1433cb28946 rc/bin/play
+--- a/rc/bin/play Sun Jul 15 06:31:45 2018 +0200
++++ b/rc/bin/play Sun Jul 15 17:58:38 2018 +0200
+@@ -23,6 +23,13 @@
+ cleanup
+ }
+
++fn midi {
++ if(test -f /mnt/wad/genmidi)
++ games/dmid | games/opl3
++ if not
++ games/midi -c
++}
++
+ fn play1 {
+ if(! ~ $#* 2){
+ tmp=(/tmp/play.$pid.$#tmp.tmp $tmp)
+@@ -57,9 +64,11 @@
+ case *audio/basic*
+ audio/sundec
+ case *audio/midi*
+- games/midi -c
++ midi
+ case *audio/mus*
+- games/mus | games/midi -c
++ games/mus | midi
++ case *audio/mod*
++ mod/decode
+ case *pls*
+ awk 'BEGIN {FS="="} /^File/{print $2}' | play1 list plain
+ case *
+@@ -75,9 +84,9 @@
+ case *.au *.AU
+ audio/sundec
+ case *.mid *.MID
+- games/midi -c
++ midi
+ case *.mus *.MUS
+- games/mus | games/midi -c
++ games/mus | midi
+ case *
+ echo $argv0: $1: unknown format: $2 >[1=2]
+ }
--- /dev/null
+++ b/png-maxmem
@@ -1,0 +1,14 @@
+wtf?
+
+diff -r 813115218568 sys/src/cmd/jpg/readpng.c
+--- a/sys/src/cmd/jpg/readpng.c Tue Jan 19 13:06:22 2016 +0100
++++ b/sys/src/cmd/jpg/readpng.c Sat Jan 23 08:13:54 2016 +0100
+@@ -10,7 +10,7 @@
+
+ enum
+ {
+- IDATSIZE = 8*1024*1024,
++ IDATSIZE = 64*1024*1024,
+
+ /* filtering algorithms */
+ FilterNone = 0, /* new[x][y] = buf[x][y] */
--- /dev/null
+++ b/png-trns-unfinished
@@ -1,0 +1,87 @@
+png: read mTRS chunks for indexed rgb24 images
+
+FIXME: UNFINISHED, surely breaks with other formats, and code is crap
+- then, don't check against apalsize (which should not exist) but
+ channel/nout/... settings
+- implement support for other modes, if we can find test pictures
+
+diff -r 321912cfedf3 sys/src/cmd/jpg/readpng.c
+--- a/sys/src/cmd/jpg/readpng.c Sun Jun 25 22:57:47 2017 +0200
++++ b/sys/src/cmd/jpg/readpng.c Mon Jun 26 23:29:03 2017 +0200
+@@ -46,6 +46,8 @@
+ int pass; /* adam7 pass#; 0 means no adam7 */
+ uchar palette[3*256]; /* color palette */
+ int palsize; /* number of palette entries */
++ uchar apalette[256]; /* optional alpha values for palette */
++ int hasapal;
+ };
+
+ struct ZlibR
+@@ -142,8 +144,18 @@
+ z->w->palsize = 256;
+ goto Again;
+ }
+- if(type[0] & PropertyBit)
+- goto Again; /* skip auxiliary chunks fornow */
++ if(type[0] & PropertyBit){
++ /* FIXME: non-3 formats are unhandled */
++ if(strcmp(type,"tRNS"))
++ goto Again; /* skip auxiliary chunks fornow */
++ if(z->w->chandesc != CRGBA32 || z->w->nchan != 1)
++ goto Again; /* unimplemented */
++ if(n > z->w->palsize)
++ sysfatal("invalid tRNS chunk len %d", n);
++ memcpy(z->w->apalette, z->p, n);
++ z->w->hasapal = 1;
++ goto Again;
++ }
+ if(strcmp(type,"IDAT")){
+ sysfatal("unrecognized mandatory chunk %s", type);
+ goto Again;
+@@ -258,7 +270,7 @@
+ j >>= 8-z->bpc;
+ if(j >= z->palsize)
+ sysfatal("index %d >= palette size %d", j, z->palsize);
+- pixel[3] = pixel[1]; /* alpha */
++ pixel[3] = z->hasapal ? z->apalette[j] : pixel[1]; /* alpha */
+ pixel[0] = z->palette[3*j];
+ pixel[1] = z->palette[3*j+1];
+ pixel[2] = z->palette[3*j+2];
+@@ -272,6 +284,12 @@
+ case CRGBA32:
+ // print("%.2x%.2x%.2x%.2x ", pixel[0], pixel[1], pixel[2], pixel[3]);
+ *w++ += pixel[3];
++ if(z->hasapal){
++ *w++ = pixel[2];
++ *w++ = pixel[1];
++ *w++ = pixel[0];
++ break;
++ }
+ *w++ += (pixel[2]*pixel[3])/255;
+ *w++ += (pixel[1]*pixel[3])/255;
+ *w++ += (pixel[0]*pixel[3])/255;
+@@ -438,9 +456,14 @@
+ case 3: /* indexed rgb with PLTE */
+ if(bpc != 1 && bpc != 2 && bpc != 4 && bpc != 8)
+ sysfatal("invalid indexed rgb bpc %d", bpc);
++ /* FIXME: conditially set CRGBA32? maybe pngmalloc directly to zw buffer, resize it
++ * as needed, and set it before returning? or perhaps alloc maximal size,
++ * and if there's no valid tRNS chunk, shrink it before returning image;
++ * so, alloc max, but use minimal params before inflating... */
++ /* FIXME: support other formats */
+ image->nchans = 1;
+- image->chandesc = CRGB24;
+- nout = 3;
++ image->chandesc = CRGBA32;
++ nout = 4;
+ nchan = 1;
+ break;
+ case 4: /* grey+alpha */
+@@ -478,6 +501,7 @@
+ zw.ndata = image->chanlen;
+ zw.chandesc = image->chandesc;
+ zw.noutchan = nout;
++ memset(zw.apalette, 0xff, sizeof zw.apalette);
+
+ zw.dx = dx;
+ zw.dy = dy;
--- /dev/null
+++ b/rio-col
@@ -1,0 +1,46 @@
+rio colors.
+
+diff -r 3cb0cf9ab43a sys/src/cmd/rio/data.c
+--- a/sys/src/cmd/rio/data.c Mon Feb 08 20:07:56 2016 -0500
++++ b/sys/src/cmd/rio/data.c Sun Feb 14 06:53:09 2016 +0100
+@@ -175,27 +175,21 @@
+ void
+ iconinit(void)
+ {
+- background = allocimage(display, Rect(0,0,1,1), RGB24, 1, 0x777777FF);
++ background = display->black;
+
+ /* greys are multiples of 0x11111100+0xFF, 14* being palest */
+- cols[BACK] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xFFFFFFFF^reverse);
+- cols[BORD] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x999999FF^reverse);
+- cols[TEXT] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x000000FF^reverse);
+- cols[HTEXT] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x000000FF);
+- if(!reverse) {
+- cols[HIGH] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCCCCCCFF);
+- titlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DGreygreen);
+- lighttitlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPalegreygreen);
+- } else {
+- cols[HIGH] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPurpleblue);
+- titlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPurpleblue);
+- lighttitlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x222222FF);
+- }
+- dholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DMedblue);
+- lightholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DGreyblue);
+- paleholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPalegreyblue);
+- paletextcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x666666FF^reverse);
+- sizecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DRed);
++ cols[BACK] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DBlack);
++ cols[BORD] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x111111FF);
++ cols[TEXT] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x884400FF);
++ cols[HTEXT] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x884400FF);
++ cols[HIGH] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x440000FF);
++ titlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x440000FF);
++ lighttitlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x111111FF);
++ dholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x666666FF);
++ lightholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x222222FF);
++ paleholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x333333FF);
++ paletextcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x550000FF);
++ sizecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x550000FF);
+
+ if(reverse == 0)
+ holdcol = dholdcol;
--- /dev/null
+++ b/rio-exit
@@ -1,0 +1,16 @@
+rio: always enable kill menu option
+
+diff -r 49bd5e4c9bde sys/src/cmd/rio/rio.c
+--- a/sys/src/cmd/rio/rio.c Wed Feb 07 18:53:08 2018 +0000
++++ b/sys/src/cmd/rio/rio.c Thu Feb 15 23:00:00 2018 +0100
+@@ -125,10 +125,6 @@
+ Image *i;
+ Rectangle r;
+
+- if(strstr(argv[0], ".out") == nil){
+- menu3str[Exit] = nil;
+- Hidden--;
+- }
+ initstr = nil;
+ kbdin = nil;
+ maxtab = 0;
--- /dev/null
+++ b/samterm-cmdrect
@@ -1,0 +1,14 @@
+diff -r 16e46e6fee1e sys/src/cmd/samterm/main.c
+--- a/sys/src/cmd/samterm/main.c Thu Oct 05 20:33:46 2017 +0200
++++ b/sys/src/cmd/samterm/main.c Sat Oct 07 06:32:03 2017 +0200
+@@ -42,7 +42,9 @@
+ scratch = alloc(100*RUNESIZE);
+ nscralloc = 100;
+ r = screen->r;
+- r.max.y = r.min.y+Dy(r)/5;
++ if(Dx(r) > 8*80+FLMARGIN+FLSCROLLWID)
++ r.max.x = r.min.x + 8*80+FLMARGIN+FLSCROLLWID;
++ r.max.y = r.min.y+Dy(r)/6;
+ flstart(screen->clipr);
+ rinit(&cmd.rasp);
+ flnew(&cmd.l[0], gettext, 1, &cmd);
--- /dev/null
+++ b/samterm-col
@@ -1,0 +1,70 @@
+samterm color patch.
+
+diff -r 0dbb01291c38 sys/src/cmd/samterm/flayer.c
+--- a/sys/src/cmd/samterm/flayer.c Thu Jan 07 15:04:56 2016 -0500
++++ b/sys/src/cmd/samterm/flayer.c Sun Jan 10 20:31:20 2016 +0100
+@@ -29,18 +29,18 @@
+ lDrect = r;
+
+ /* Main text is yellowish */
+- maincols[BACK] = allocimagemix(display, DPaleyellow, DWhite);
+- maincols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkyellow);
+- maincols[BORD] = allocimage(display, Rect(0,0,2,2), screen->chan, 1, DYellowgreen);
+- maincols[TEXT] = display->black;
+- maincols[HTEXT] = display->black;
++ maincols[BACK] = display->black;
++ maincols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x440000FF);
++ maincols[BORD] = allocimage(display, Rect(0,0,2,2), screen->chan, 1, 0x222222FF);
++ maincols[TEXT] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x884400FF);
++ maincols[HTEXT] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x884400FF);
+
+ /* Command text is blueish */
+- cmdcols[BACK] = allocimagemix(display, DPalebluegreen, DWhite);
+- cmdcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPalegreygreen);
+- cmdcols[BORD] = allocimage(display, Rect(0,0,2,2), screen->chan, 1, DPurpleblue);
+- cmdcols[TEXT] = display->black;
+- cmdcols[HTEXT] = display->black;
++ cmdcols[BACK] = display->black;
++ cmdcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x111111FF);
++ cmdcols[BORD] = allocimage(display, Rect(0,0,2,2), screen->chan, 1, 0x440000FF);
++ cmdcols[TEXT] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x770000FF);
++ cmdcols[HTEXT] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x770000FF);
+ }
+
+ void
+@@ -89,12 +89,12 @@
+ flclose(Flayer *l)
+ {
+ if(l->visible == All)
+- draw(screen, l->entire, display->white, nil, ZP);
++ draw(screen, l->entire, display->black, nil, ZP);
+ else if(l->visible == Some){
+ if(l->f.b == 0)
+ l->f.b = allocimage(display, l->entire, screen->chan, 0, DNofill);
+ if(l->f.b){
+- draw(l->f.b, l->entire, display->white, nil, ZP);
++ draw(l->f.b, l->entire, display->black, nil, ZP);
+ flrefresh(l, l->entire, 0);
+ }
+ }
+@@ -353,7 +353,7 @@
+ if(0 && Dx(dr)==Dx(olDrect) && Dy(dr)==Dy(olDrect))
+ move = 1;
+ else
+- draw(screen, lDrect, display->white, nil, ZP);
++ draw(screen, lDrect, display->black, nil, ZP);
+ for(i=0; i<nllist; i++){
+ l = llist[i];
+ l->lastsr = ZR;
+diff -r 0dbb01291c38 sys/src/cmd/samterm/plan9.c
+--- a/sys/src/cmd/samterm/plan9.c Thu Jan 07 15:04:56 2016 -0500
++++ b/sys/src/cmd/samterm/plan9.c Sun Jan 10 20:31:20 2016 +0100
+@@ -46,7 +46,7 @@
+ if(t != nil)
+ maxtab = strtoul(t, nil, 0);
+ free(t);
+- draw(screen, screen->clipr, display->white, nil, ZP);
++ draw(screen, screen->clipr, display->black, nil, ZP);
+ }
+
+ int
--- /dev/null
+++ b/samterm-flayers
@@ -1,0 +1,12 @@
+diff -r 12bbf1a60d48 sys/src/cmd/samterm/samterm.h
+--- a/sys/src/cmd/samterm/samterm.h Thu Jun 01 07:07:55 2017 +0000
++++ b/sys/src/cmd/samterm/samterm.h Mon Jun 05 15:36:48 2017 +0200
+@@ -3,7 +3,7 @@
+ #define RUNESIZE sizeof(Rune)
+ #define MAXFILES 256
+ #define READBUFSIZE 8192
+-#define NL 5
++#define NL 10
+
+ enum{
+ Up,
--- /dev/null
+++ b/spewaplay-col
@@ -1,0 +1,75 @@
+diff -Naur a/aplay.c b/aplay.c
+--- a/aplay.c Sun Feb 14 06:54:35 2016
++++ b/aplay.c Sun Feb 14 06:54:42 2016
+@@ -85,7 +85,7 @@
+ codecargs.pidchan = chancreate(sizeof(ulong), 0);
+ waitchan = threadwaitchan();
+ initdraw(nil, nil, argv0);
+- back = allocimagemix(display, DPalebluegreen, DWhite);
++ back = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x441100ff);
+ threadcreate(mousethread, &codecargs, STACK);
+ kbdargs.exit = chancreate(sizeof(char*), 0);
+ kbdargs.codecargs = &codecargs;
+@@ -262,7 +262,8 @@
+ r1.max.x = r1.min.x + ((vlong)Dx(r2) * curoff) / maxoff;
+ r2.min.x = r1.max.x;
+ draw(screen, r1, back, nil, ZP);
+- draw(screen, r2, display->white, nil, ZP);
++ draw(screen, r2, display->black, nil, ZP);
++ /*
+ if(pause)
+ strcpy(buf, "pause");
+ else
+@@ -273,9 +274,10 @@
+ r2 = rectaddpt(r2, subpt(divpt(r1.max, 2), divpt(r2.max, 2)));
+ r2 = rectaddpt(r2, screen->r.min);
+ r1 = insetrect(r2, -4);
+- draw(screen, r1, display->white, nil, ZP);
+- border(screen, insetrect(r1, 1), 2, display->black, ZP);
+- string(screen, r2.min, display->black, ZP, display->defaultfont, buf);
++ draw(screen, r1, display->black, nil, ZP);
++ border(screen, insetrect(r1, 1), 2, display->white, ZP);
++ string(screen, r2.min, display->white, ZP, display->defaultfont, buf);
++ */
+ flushimage(display, 1);
+ }
+
+diff -Naur a/volume.c b/volume.c
+--- a/volume.c Sun Feb 14 06:55:07 2016
++++ b/volume.c Sun Feb 14 06:55:10 2016
+@@ -4,8 +4,6 @@
+ #include <event.h>
+ #include <keyboard.h>
+
+-char volstr[] = "volume";
+-char mutestr[] = "muted";
+ int volume, muted;
+ Image *back;
+
+@@ -21,16 +19,7 @@
+ r1.min.y = r1.max.y - ((vlong)Dy(r2) * volume) / 100;
+ r2.max.y = r1.min.y;
+ draw(screen, r1, back, nil, ZP);
+- draw(screen, r2, display->white, nil, ZP);
+- r2.min = ZP;
+- r2.max = stringsize(display->defaultfont, muted ? mutestr : volstr);
+- r1 = rectsubpt(screen->r, screen->r.min);
+- r2 = rectaddpt(r2, subpt(divpt(r1.max, 2), divpt(r2.max, 2)));
+- r2 = rectaddpt(r2, screen->r.min);
+- r1 = insetrect(r2, -4);
+- draw(screen, r1, display->white, nil, ZP);
+- border(screen, insetrect(r1, 1), 2, display->black, ZP);
+- string(screen, r2.min, display->black, ZP, display->defaultfont, muted ? mutestr : volstr);
++ draw(screen, r2, display->black, nil, ZP);
+ flushimage(display, 1);
+ }
+
+@@ -64,7 +53,7 @@
+ if(initdraw(0, 0, "volume") < 0)
+ sysfatal("initdraw failed: %r");
+ einit(Emouse|Ekeyboard);
+- back = allocimagemix(display, DPalebluegreen, DWhite);
++ back = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x441100ff);
+ eresized(0);
+ for(;;) switch(event(&e)){
+ default:
--- /dev/null
+++ b/spred-col
@@ -1,0 +1,38 @@
+diff -r 4136602b93e9 sys/src/cmd/spred/cmdw.c
+--- a/sys/src/cmd/spred/cmdw.c Wed Nov 14 11:33:52 2018 -0800
++++ b/sys/src/cmd/spred/cmdw.c Fri Nov 23 17:25:25 2018 +0100
+@@ -332,9 +332,11 @@
+ .rmb = cmdrmb,
+ .key = cmdkey,
+ .hexcols = {
+- [BORD] DPurpleblue,
+- [DISB] 0xCCCCEEFF,
+- [BACK] 0xCCFFFFFF,
+- [HIGH] DPalegreygreen
++ [BORD] 0x440000FF,
++ [TEXT] 0x770000FF,
++ [DISB] 0x111111FF,
++ [BACK] 0x000000FF,
++ [HIGH] 0x111111FF,
++ [HTEXT] 0x770000FF,
+ }
+ };
+diff -r 4136602b93e9 sys/src/cmd/spred/win.c
+--- a/sys/src/cmd/spred/win.c Wed Nov 14 11:33:52 2018 -0800
++++ b/sys/src/cmd/spred/win.c Fri Nov 23 17:25:25 2018 +0100
+@@ -38,6 +38,7 @@
+ scr = allocscreen(screen, display->white, 0);
+ if(scr == nil)
+ sysfatal("allocscreen: %r");
++ draw(screen, screen->r, display->black, nil, ZP);
+ for(i = 0; i < NTYPES; i++)
+ for(j = 0; j < NCOLS; j++)
+ tabs[i]->cols[j] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, tabs[i]->hexcols[j]);
+@@ -254,6 +255,7 @@
+ scr = allocscreen(screen, display->white, 0);
+ if(scr == nil)
+ sysfatal("allocscreen: %r");
++ draw(screen, screen->r, display->black, nil, ZP);
+ for(w = wlist.next; w != &wlist; w = w->next){
+ r = rectsubpt(w->entire, old.min);
+ r.min.x = muldiv(r.min.x, dxn, dxo);
--- /dev/null
+++ b/stats-col
@@ -1,0 +1,89 @@
+diff -r 034743cc4f9f sys/src/cmd/stats.c
+--- a/sys/src/cmd/stats.c Thu Jun 14 21:54:42 2018 +0200
++++ b/sys/src/cmd/stats.c Sun Jun 17 07:30:50 2018 +0200
+@@ -208,6 +208,7 @@
+ };
+
+ Image *cols[Ncolor][3];
++Image *txt;
+ Graph *graph;
+ Machine *mach;
+ char *mysysname;
+@@ -271,30 +272,23 @@
+ }
+
+ void
+-mkcol(int i, int c0, int c1, int c2)
++mkcol(int i, int c0, int c1)
+ {
+- cols[i][0] = allocimagemix(display, c0, DWhite);
+- cols[i][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c1);
+- cols[i][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c2);
++ cols[i][0] = allocimagemix(display, c0, DBlack);
++ cols[i][1] = allocimagemix(display, 0x773300FF, c1);
++ cols[i][2] = allocimage(display, Rect(0,0,1,1), RGB24, 1, c1);
+ }
+
+ void
+ colinit(void)
+ {
+- /* Peach */
+- mkcol(0, 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF);
+- /* Aqua */
+- mkcol(1, DPalebluegreen, DPalegreygreen, DPurpleblue);
+- /* Yellow */
+- mkcol(2, DPaleyellow, DDarkyellow, DYellowgreen);
+- /* Green */
+- mkcol(3, DPalegreen, DMedgreen, DDarkgreen);
+- /* Blue */
+- mkcol(4, 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF);
+- /* Grey */
+- cols[5][0] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xEEEEEEFF);
+- cols[5][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCCCCCCFF);
+- cols[5][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x888888FF);
++ mkcol(0, 0x994400FF, 0x442200FF);
++ mkcol(1, 0x993C00FF, 0x441F00FF);
++ mkcol(2, 0x993300FF, 0x441C00FF);
++ mkcol(3, 0x992200FF, 0x441800FF);
++ mkcol(4, 0x991100FF, 0x441400FF);
++ mkcol(5, 0x990000FF, 0x441100FF);
++ txt = allocimage(display, Rect(0,0,1,1), RGB24, 1, 0x441100FF);
+ }
+
+ int
+@@ -437,7 +431,7 @@
+ g->overflow = 1;
+ draw(g->overtmp, g->overtmp->r, screen, nil, g->overtmp->r.min);
+ sprint(buf, "%llud", v);
+- string(screen, g->overtmp->r.min, display->black, ZP, font, buf);
++ string(screen, g->overtmp->r.min, txt, ZP, font, buf);
+ }
+ }
+
+@@ -1094,7 +1088,7 @@
+ uvlong v, vmax;
+ char buf[128], labs[Nlab][Lablen];
+
+- draw(screen, screen->r, display->white, nil, ZP);
++ draw(screen, screen->r, display->black, nil, ZP);
+
+ /* label left edge */
+ x = screen->r.min.x;
+@@ -1123,7 +1117,7 @@
+ snprint(buf, sizeof buf, "%.*s(%d)", j, mach[i].shortname, n);
+ }else
+ snprint(buf, sizeof buf, "%.*s", j, mach[i].shortname);
+- string(screen, Pt(x+Labspace, screen->r.min.y + Labspace), display->black, ZP, font, buf);
++ string(screen, Pt(x+Labspace, screen->r.min.y + Labspace), txt, ZP, font, buf);
+ }
+
+ maxx = screen->r.max.x;
+@@ -1148,7 +1142,7 @@
+ ly = y + (dy*(nlab-k)/(nlab+1));
+ draw(screen, Rect(maxx+1, ly, maxx+1+Lx, ly+1), display->black, nil, ZP);
+ ly -= font->height/2;
+- string(screen, Pt(maxx+1+Lx, ly), display->black, ZP, font, labs[k]);
++ string(screen, Pt(maxx+1+Lx, ly), txt, ZP, font, labs[k]);
+ }
+ }
+ }
--- /dev/null
+++ b/statusbar-col
@@ -1,0 +1,16 @@
+diff -r b048db97b5ea sys/src/cmd/aux/statusbar.c
+--- a/sys/src/cmd/aux/statusbar.c Fri Jan 04 02:51:29 2019 +0100
++++ b/sys/src/cmd/aux/statusbar.c Mon Jan 07 13:56:09 2019 +0100
+@@ -18,9 +18,9 @@
+ void
+ initcolor(void)
+ {
+- text = display->black;
+- light = allocimagemix(display, DPalegreen, DWhite);
+- dark = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DDarkgreen);
++ text = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x440000FF);
++ light = display->black;
++ dark = text;
+ }
+
+ Rectangle rbar;
--- /dev/null
+++ b/statusmsg-col
@@ -1,0 +1,14 @@
+diff -r c392f6b2122c sys/src/cmd/aux/statusmsg.c
+--- a/sys/src/cmd/aux/statusmsg.c Mon Feb 15 17:30:56 2016 +0100
++++ b/sys/src/cmd/aux/statusmsg.c Thu Feb 18 06:06:21 2016 +0100
+@@ -19,8 +19,8 @@
+ void
+ initcolor(void)
+ {
+- text = display->black;
+- light = allocimagemix(display, DPalegreen, DWhite);
++ text = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x440000FF);
++ light = display->black;
+ }
+
+ void
--- /dev/null
+++ b/sudoku-col
@@ -1,0 +1,75 @@
+diff -r 3b33f587ad27 sys/src/games/sudoku/sudoku.c
+--- a/sys/src/games/sudoku/sudoku.c Wed Oct 03 00:53:10 2018 +0200
++++ b/sys/src/games/sudoku/sudoku.c Sat Oct 06 16:12:35 2018 +0200
+@@ -14,10 +14,10 @@
+
+ Image *background; /* DPaleyellow */
+ Image *backselect; /* DPalebluegreen */
+-Image *blink; /* DDarkyellow */
+ Image *brdr; /* 0x55555555 */
+ Image *fixed; /* DBlue */
+ Image *wrong; /* DRed */
++Image *normal;
+ Image *dig[10]; /* digit masks */
+
+ Dir *dir;
+@@ -200,7 +200,7 @@
+ int i;
+
+ for(i = 0; i < Psize; i++) {
+- drawcell(i / Brdsize, i % Brdsize, brd[i].digit, brd[i].locked ? fixed : display->black);
++ drawcell(i / Brdsize, i % Brdsize, brd[i].digit, brd[i].locked ? fixed : normal);
+ }
+ }
+
+@@ -214,7 +214,7 @@
+ drawcell(i / Brdsize, i % Brdsize, brd[i].digit, fixed);
+ else
+ drawcell(i / Brdsize, i % Brdsize, brd[i].digit,
+- checkpossible(brd, i / Brdsize, i % Brdsize, brd[i].digit) ? display->black : wrong);
++ checkpossible(brd, i / Brdsize, i % Brdsize, brd[i].digit) ? normal : wrong);
+ }
+ }
+
+@@ -224,7 +224,7 @@
+ Point l1, l2;
+ int i;
+
+- draw(screen, screen->r, brdr, nil, ZP);
++ draw(screen, screen->r, display->black, nil, ZP);
+ draw(screen, insetrect(screen->r, Border), background, nil, ZP);
+ for(i = 0; i < Brdsize; i++) {
+ l1 = addpt(screen->r.min, Pt(i*Square, Square));
+@@ -253,7 +253,7 @@
+ r = insetrect(r, Border);
+ r.max = addpt(r.max, Pt(2, 2));
+ draw(screen, rectaddpt(r, screen->r.min), selected ? backselect : background, nil, ZP);
+- draw(screen, rectaddpt(r, screen->r.min), display->black, dig[digit-1], ZP);
++ draw(screen, rectaddpt(r, screen->r.min), normal, dig[digit-1], ZP);
+ }
+
+ void
+@@ -267,17 +267,17 @@
+ sysfatal("can't reattach to window");
+
+ if(background == nil)
+- background = eallocimage(Rect(0, 0, 1, 1), 1, DPaleyellow);
++ background = display->black;
+ if(backselect == nil)
+- backselect = eallocimage(Rect(0, 0, 1, 1), 1, DPalebluegreen);
+- if(blink == nil)
+- blink = eallocimage(Rect(0, 0, 1, 1), 1, DDarkyellow);
++ backselect = eallocimage(Rect(0, 0, 1, 1), 1, 0x440000FF);
+ if(brdr == nil)
+- brdr = eallocimage(Rect(0, 0, 1, 1), 1, 0x55555555);
++ brdr = eallocimage(Rect(0, 0, 1, 1), 1, 0x222222FF);
+ if(fixed == nil)
+- fixed = eallocimage(Rect(0, 0, 1, 1), 1, DBlue);
++ fixed = eallocimage(Rect(0, 0, 1, 1), 1, 0x550000FF);
+ if(wrong == nil)
+ wrong = eallocimage(Rect(0, 0, 1, 1), 1, DRed);
++ if(normal == nil)
++ normal = eallocimage(Rect(0, 0, 1, 1), 1, 0x884400FF);
+ if(dig[0] == nil) {
+ for(i = 0; i < 9; i++) {
+ snprint(path, 256, "%s/%d.bit", imgdir, i+1);
--- /dev/null
+++ b/troff-nchars
@@ -1,0 +1,18 @@
+troff: inflate maximum size of character set
+
+this enables one to use fonts like unifont with troff.
+
+don't use fonts like unifont with troff.
+
+diff -r 79938a709ae3 sys/src/cmd/troff/tdef.h
+--- a/sys/src/cmd/troff/tdef.h Wed Jan 30 18:22:52 2019 +0100
++++ b/sys/src/cmd/troff/tdef.h Mon Feb 11 10:44:11 2019 +0100
+@@ -190,7 +190,7 @@
+ unnamed ones and \N's)
+ */
+
+-#define NCHARS (8*1024) /* maximum size of troff character set*/
++#define NCHARS (64*1024) /* maximum size of troff character set*/
+
+
+ /* However for nroff you want only :
--- /dev/null
+++ b/vt-col
@@ -1,0 +1,12 @@
+diff -r eecec6d3b341 sys/src/cmd/vt/main.c
+--- a/sys/src/cmd/vt/main.c Mon Sep 03 20:54:26 2018 +0200
++++ b/sys/src/cmd/vt/main.c Mon Sep 03 19:11:39 2018 +0200
+@@ -326,7 +326,7 @@
+ rgbahicolors[i]);
+ }
+ bgcolor = (blkbg? display->black: display->white);
+- fgcolor = (blkbg? display->white: display->black);
++ fgcolor = (blkbg? allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x884400FF): display->black);
+ bgselected = allocimage(display, Rect(0,0,1,1), CMAP8, 1, blkbg ? 0x333333FF : 0xCCCCCCFF);
+ fgselected = allocimage(display, Rect(0,0,1,1), CMAP8, 1, blkbg ? 0xCCCCCCFF : 0x333333FF);;
+ resize();