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
drawit(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
main(int argc,char * argv[])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
makegrid(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
eresized(int new)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
magnify(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