1 #include <u.h> 2 #include <libc.h> 3 #include <draw.h> 4 #include <event.h> 5 6 enum { 7 Edge = 5, 8 Maxmag = 16 9 }; 10 11 Point lastp; 12 Image *red; 13 Image *tmp; 14 Image *grid; 15 Image *gridmatte; 16 Image *veil; 17 Image *chequer; 18 int screenfd; 19 int mag = 4; 20 int showgrid = 0; 21 Rectangle screenr; 22 uchar *screenbuf; 23 24 void magnify(void); 25 void makegrid(void); 26 27 void 28 drawit(void) 29 { 30 Rectangle r; 31 border(screen, screen->r, Edge, red, ZP); 32 magnify(); 33 r = insetrect(screen->r, Edge); 34 draw(screen, r, tmp, nil, tmp->r.min); 35 flushimage(display, 1); 36 } 37 38 39 int bypp; 40 41 void 42 main(int argc, char *argv[]) 43 { 44 Event e; 45 char buf[5*12]; 46 ulong chan; 47 int d; 48 49 USED(argc, argv); 50 if(initdraw(nil, nil, "lens") < 0){ 51 fprint(2, "lens: initdraw failed: %r\n"); 52 exits("initdraw"); 53 } 54 einit(Emouse|Ekeyboard); 55 red = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, DRed); 56 veil = allocimage(display, Rect(0, 0, 1, 1), GREY8, 1, 0x3f3f3fff); 57 chequer = allocimage(display, Rect(0, 0, 2, 2), GREY1, 1, DBlack); 58 draw(chequer, Rect(0, 0, 1, 1), display->white, nil, ZP); 59 draw(chequer, Rect(1, 1, 2, 2), display->white, nil, ZP); 60 lastp = divpt(addpt(screen->r.min, screen->r.max), 2); 61 screenfd = open("/dev/screen", OREAD); 62 if(screenfd < 0){ 63 fprint(2, "lens: can't open /dev/screen: %r\n"); 64 exits("screen"); 65 } 66 if(read(screenfd, buf, sizeof buf) != sizeof buf){ 67 fprint(2, "lens: can't read /dev/screen: %r\n"); 68 exits("screen"); 69 } 70 chan = strtochan(buf); 71 d = chantodepth(chan); 72 if(d < 8){ 73 fprint(2, "lens: can't handle screen format %11.11s\n", buf); 74 exits("screen"); 75 } 76 bypp = d/8; 77 screenr.min.x = atoi(buf+1*12); 78 screenr.min.y = atoi(buf+2*12); 79 screenr.max.x = atoi(buf+3*12); 80 screenr.max.y = atoi(buf+4*12); 81 screenbuf = malloc(bypp*Dx(screenr)*Dy(screenr)); 82 if(screenbuf == nil){ 83 fprint(2, "lens: buffer malloc failed: %r\n"); 84 exits("malloc"); 85 } 86 eresized(0); 87 88 for(;;) 89 switch(event(&e)){ 90 case Ekeyboard: 91 switch(e.kbdc){ 92 case 'q': 93 case '\04': 94 exits(nil); 95 case '=': 96 case '+': 97 if(mag < Maxmag){ 98 mag++; 99 makegrid(); 100 drawit(); 101 } 102 break; 103 case 'g': 104 showgrid = !showgrid; 105 makegrid(); 106 drawit(); 107 break; 108 case '-': 109 case '_': 110 if(mag > 1){ 111 mag--; 112 makegrid(); 113 drawit(); 114 } 115 break; 116 case '.': 117 case ' ': 118 drawit(); 119 break; 120 case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case'0': 121 mag = e.kbdc-'0'; 122 if(mag == 0) 123 mag = 10; 124 makegrid(); 125 drawit(); 126 break; 127 } 128 if(e.kbdc == 'q' || e.kbdc == '\04') 129 exits(nil); 130 break; 131 case Emouse: 132 if(e.mouse.buttons){ 133 lastp = e.mouse.xy; 134 drawit(); 135 } 136 break; 137 } 138 } 139 140 void 141 makegrid(void) 142 { 143 if (grid != nil) { 144 freeimage(grid); 145 grid = nil; 146 } 147 if (showgrid) { 148 if (mag < 4) { 149 grid = allocimage(display, Rect(0, 0, mag*2, mag*2), GREY1, 1, DBlack); 150 draw(grid, Rect(0, 0, mag, mag), display->white, nil, ZP); 151 draw(grid, Rect(mag, mag, mag*2, mag*2), display->white, nil, ZP); 152 gridmatte = veil; 153 } else { 154 grid = allocimage(display, Rect(0, 0, mag, mag), 155 CHAN2(CGrey, 8, CAlpha, 8), 1, DTransparent); 156 draw(grid, Rect(0, 0, mag, 1), chequer, nil, ZP); 157 draw(grid, Rect(0, 1, 1, mag), chequer, nil, ZP); 158 gridmatte = nil; 159 } 160 } 161 } 162 163 void 164 eresized(int new) 165 { 166 if(new && getwindow(display, Refnone) < 0){ 167 fprint(2, "lens: can't reattach to window: %r\n"); 168 exits("attach"); 169 } 170 freeimage(tmp); 171 tmp = allocimage(display, Rect(0, 0, Dx(screen->r)-Edge, Dy(screen->r)-Edge+Maxmag), screen->chan, 0, DNofill); 172 if(tmp == nil){ 173 fprint(2, "lens: allocimage failed: %r\n"); 174 exits("allocimage"); 175 } 176 drawit(); 177 } 178 179 void 180 magnify(void) 181 { 182 int x, y, xx, yy, dd, i; 183 int dx, dy; 184 int xoff, yoff; 185 uchar out[8192]; 186 uchar sp[4]; 187 188 dx = (Dx(tmp->r)+mag-1)/mag; 189 dy = (Dy(tmp->r)+mag-1)/mag; 190 xoff = lastp.x-Dx(tmp->r)/(mag*2); 191 yoff = lastp.y-Dy(tmp->r)/(mag*2); 192 193 yy = yoff; 194 dd = dy; 195 if(yy < 0){ 196 dd += dy; 197 yy = 0; 198 } 199 if(yy+dd > Dy(screenr)) 200 dd = Dy(screenr)-yy; 201 seek(screenfd, 5*12+bypp*yy*Dx(screenr), 0); 202 if(readn(screenfd, screenbuf+bypp*yy*Dx(screenr), bypp*Dx(screenr)*dd) != bypp*Dx(screenr)*dd){ 203 fprint(2, "lens: can't read screen: %r\n"); 204 return; 205 } 206 207 for(y=0; y<dy; y++){ 208 yy = yoff+y; 209 if(yy>=0 && yy<Dy(screenr)) 210 for(x=0; x<dx; x++){ 211 xx = xoff+x; 212 if(xx>=0 && xx<Dx(screenr)) /* snarf pixel at xx, yy */ 213 for(i=0; i<bypp; i++) 214 sp[i] = screenbuf[bypp*(yy*Dx(screenr)+xx)+i]; 215 else 216 sp[0] = sp[1] = sp[2] = sp[3] = 0; 217 218 for(xx=0; xx<mag; xx++) 219 if(x*mag+xx < tmp->r.max.x) 220 for(i=0; i<bypp; i++) 221 out[(x*mag+xx)*bypp+i] = sp[i]; 222 } 223 else 224 memset(out, 0, bypp*Dx(tmp->r)); 225 for(yy=0; yy<mag && y*mag+yy<Dy(tmp->r); yy++){ 226 werrstr("no error"); 227 if(loadimage(tmp, Rect(0, y*mag+yy, Dx(tmp->r), y*mag+yy+1), out, bypp*Dx(tmp->r)) != bypp*Dx(tmp->r)){ 228 exits("load"); 229 } 230 } 231 } 232 if (showgrid && mag) 233 draw(tmp, tmp->r, grid, gridmatte, ZP); 234 } 235