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