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