]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/vnc/screen.c
vnc/devdraw: fix topnwindows() panic when images are not windows (thanks aiju)
[plan9front.git] / sys / src / cmd / vnc / screen.c
1 #include        <u.h>
2 #include        <libc.h>
3 #include        "compat.h"
4 #include        "kbd.h"
5 #include        "error.h"
6
7 #define Image   IMAGE
8 #include        <draw.h>
9 #include        <memdraw.h>
10 #include        <cursor.h>
11 #include        "screen.h"
12
13 enum
14 {
15         CURSORDIM = 16
16 };
17
18 Memimage        *gscreen;
19 Point           ZP;
20 int             cursorver;
21 Point           cursorpos;
22
23 static Memimage         *back;
24 static Memimage         *conscol;
25 static Memimage         *curscol;
26 static Point            curpos;
27 static Memsubfont       *memdefont;
28 static Rectangle        flushr;
29 static Rectangle        window;
30 static int              h;
31 static int              w;
32
33 static Rectangle        cursorr;
34 static Point            offscreen;
35 static uchar            cursset[CURSORDIM*CURSORDIM/8];
36 static uchar            cursclr[CURSORDIM*CURSORDIM/8];
37 static int              cursdrawvers = -1;
38 static Memimage         *cursorset;
39 static Memimage         *cursorclear;
40 static Cursor           screencursor;
41
42 void
43 screeninit(int x, int y, char *chanstr)
44 {
45         char buf[128];
46         Rectangle r;
47         int chan;
48
49         cursorver = 0;
50
51         memimageinit();
52         chan = strtochan(chanstr);
53         if(chan == 0)
54                 error("bad screen channel string");
55
56         r = Rect(0, 0, x, y);
57         gscreen = allocmemimage(r, chan);
58         if(gscreen == nil){
59                 snprint(buf, sizeof buf, "can't allocate screen image: %r");
60                 error(buf);
61         }
62
63         offscreen = Pt(x + 100, y + 100);
64         cursorr = Rect(0, 0, CURSORDIM, CURSORDIM);
65         cursorset = allocmemimage(cursorr, GREY8);
66         cursorclear = allocmemimage(cursorr, GREY1);
67         if(cursorset == nil || cursorclear == nil){
68                 freememimage(gscreen);
69                 freememimage(cursorset);
70                 freememimage(cursorclear);
71                 gscreen = nil;
72                 cursorset = nil;
73                 cursorclear = nil;
74                 snprint(buf, sizeof buf, "can't allocate cursor images: %r");
75                 error(buf);
76         }
77
78         /* a lot of work to get a grey color */
79         curscol = allocmemimage(Rect(0,0,1,1), RGBA32);
80         curscol->flags |= Frepl;
81         curscol->clipr = gscreen->r;
82         memfillcolor(curscol, 0xff0000ff);
83
84         screenwin();
85
86         setcursor(&arrow);
87 }
88
89 void
90 screenwin(void)
91 {
92         Point p;
93         char *greet;
94         Memimage *grey;
95
96         qlock(&drawlock);
97         back = memwhite;
98         conscol = memblack;
99         memfillcolor(gscreen, 0x888844FF);
100         
101         memdefont = getmemdefont();
102         h = memdefont->height;
103
104         window = insetrect(gscreen->clipr, 20);
105         memimagedraw(gscreen, window, memblack, ZP, memopaque, ZP, S);
106         window = insetrect(window, 4);
107         memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S);
108
109         /* a lot of work to get a grey color */
110         grey = allocmemimage(Rect(0,0,1,1), CMAP8);
111         grey->flags |= Frepl;
112         grey->clipr = gscreen->r;
113         memfillcolor(grey, 0xAAAAAAFF);
114         memimagedraw(gscreen, Rect(window.min.x, window.min.y,
115                         window.max.x, window.min.y+h+5+6), grey, ZP, nil, ZP, S);
116         freememimage(grey);
117         window = insetrect(window, 5);
118
119         greet = " Plan 9 Console ";
120         p = addpt(window.min, Pt(10, 0));
121         memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
122         window.min.y += h+6;
123         curpos = window.min;
124         window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;
125         flushmemscreen(gscreen->r);
126         qunlock(&drawlock);
127 }
128
129 Memdata*
130 attachscreen(Rectangle* r, ulong* chan, int* d, int* width, int *softscreen)
131 {
132         *r = gscreen->clipr;
133         *d = gscreen->depth;
134         *chan = gscreen->chan;
135         *width = gscreen->width;
136         *softscreen = 1;
137
138         gscreen->data->ref++;
139         return gscreen->data;
140 }
141
142 void
143 getcolor(ulong , ulong* pr, ulong* pg, ulong* pb)
144 {
145         *pr = 0;
146         *pg = 0;
147         *pb = 0;
148 }
149
150 int
151 setcolor(ulong , ulong , ulong , ulong )
152 {
153         return 0;
154 }
155
156 /*
157  * called with cursor unlocked, drawlock locked
158  */
159 void
160 cursordraw(Memimage *dst, Rectangle r)
161 {
162         static uchar set[CURSORDIM*CURSORDIM], clr[CURSORDIM*CURSORDIM/8];
163         static int ver = -1;
164         int i, j, n;
165
166         lock(&cursor);
167         if(ver != cursorver){
168                 n = 0;
169                 for(i = 0; i < CURSORDIM*CURSORDIM/8; i += CURSORDIM/8){
170                         for(j = 0; j < CURSORDIM; j++){
171                                 if(cursset[i + (j >> 3)] & (1 << (7 - (j & 7))))
172                                         set[n] = 0xaa;
173                                 else
174                                         set[n] = 0;
175                                 n++;
176                         }
177                 }
178                 memmove(clr, cursclr, CURSORDIM*CURSORDIM/8);
179                 ver = cursorver;
180                 unlock(&cursor);
181                 loadmemimage(cursorset, cursorr, set, CURSORDIM*CURSORDIM);
182                 loadmemimage(cursorclear, cursorr, clr, CURSORDIM*CURSORDIM/8);
183         }else
184                 unlock(&cursor);
185         memimagedraw(dst, r, memwhite, ZP, cursorclear, ZP, SoverD);
186         memimagedraw(dst, r, curscol, ZP, cursorset, ZP, SoverD);
187 }
188
189 /*
190  * called with cursor locked, drawlock possibly unlocked
191  */
192 Rectangle
193 cursorrect(void)
194 {
195         Rectangle r;
196
197         r.min.x = cursorpos.x + cursor.offset.x;
198         r.min.y = cursorpos.y + cursor.offset.y;
199         r.max.x = r.min.x + CURSORDIM;
200         r.max.y = r.min.y + CURSORDIM;
201         return r;
202 }
203
204 /*
205  * called with cursor locked, drawlock possibly unlocked
206  */
207 void
208 setcursor(Cursor* curs)
209 {
210         cursorver++;
211         memmove(cursset, curs->set, CURSORDIM*CURSORDIM/8);
212         memmove(cursclr, curs->clr, CURSORDIM*CURSORDIM/8);
213 }
214
215 void
216 cursoron(void)
217 {
218         cursorpos = mousexy();
219 }
220
221 void
222 cursoroff(void)
223 {
224         cursorpos = offscreen;
225 }
226
227 void
228 blankscreen(int blank)
229 {
230         USED(blank);
231 }
232
233 static void
234 screenflush(void)
235 {
236         flushmemscreen(flushr);
237         flushr = Rect(10000, 10000, -10000, -10000);
238 }
239
240 static void
241 addflush(Rectangle r)
242 {
243         if(flushr.min.x >= flushr.max.x)
244                 flushr = r;
245         else
246                 combinerect(&flushr, r);
247 }
248
249 static void
250 scroll(void)
251 {
252         int o;
253         Point p;
254         Rectangle r;
255
256         o = 8*h;
257         r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
258         p = Pt(window.min.x, window.min.y+o);
259         memimagedraw(gscreen, r, gscreen, p, nil, p, S);
260         r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
261         memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
262         flushmemscreen(gscreen->clipr);
263
264         curpos.y -= o;
265 }
266
267 static void
268 screenputc(char *buf)
269 {
270         Point p;
271         int w, pos;
272         Rectangle r;
273         static int *xp;
274         static int xbuf[256];
275
276         if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
277                 xp = xbuf;
278
279         switch(buf[0]){
280         case '\n':
281                 if(curpos.y+h >= window.max.y)
282                         scroll();
283                 curpos.y += h;
284                 screenputc("\r");
285                 break;
286         case '\r':
287                 xp = xbuf;
288                 curpos.x = window.min.x;
289                 break;
290         case '\t':
291                 p = memsubfontwidth(memdefont, " ");
292                 w = p.x;
293                 *xp++ = curpos.x;
294                 pos = (curpos.x-window.min.x)/w;
295                 pos = 8-(pos%8);
296                 r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y + h);
297                 memimagedraw(gscreen, r, back, back->r.min, memopaque, ZP, S);
298                 addflush(r);
299                 curpos.x += pos*w;
300                 break;
301         case '\b':
302                 if(xp <= xbuf)
303                         break;
304                 xp--;
305                 r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
306                 memimagedraw(gscreen, r, back, back->r.min, memopaque, ZP, S);
307                 addflush(r);
308                 curpos.x = *xp;
309                 break;
310         case '\0':
311                 break;
312         default:
313                 p = memsubfontwidth(memdefont, buf);
314                 w = p.x;
315
316                 if(curpos.x >= window.max.x-w)
317                         screenputc("\n");
318
319                 *xp++ = curpos.x;
320                 r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y + h);
321                 memimagedraw(gscreen, r, back, back->r.min, memopaque, ZP, S);
322                 memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
323                 addflush(r);
324                 curpos.x += w;
325         }
326 }
327
328 void
329 screenputs(char *s, int n)
330 {
331         static char rb[UTFmax+1];
332         static int nrb;
333         char *e;
334
335         qlock(&drawlock);
336         e = s + n;
337         while(s < e){
338                 rb[nrb++] = *s++;
339                 if(nrb >= UTFmax || fullrune(rb, nrb)){
340                         rb[nrb] = 0;
341                         screenputc(rb);
342                         nrb = 0;
343                 }
344         }
345         screenflush();
346         qunlock(&drawlock);
347 }