draw.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "vnc.h"
  10. #include "vncv.h"
  11. static struct {
  12. char *name;
  13. int num;
  14. } enctab[] = {
  15. "copyrect", EncCopyRect,
  16. "corre", EncCorre,
  17. "hextile", EncHextile,
  18. "raw", EncRaw,
  19. "rre", EncRre,
  20. "mousewarp", EncMouseWarp,
  21. };
  22. static uint8_t *pixbuf;
  23. static uint8_t *linebuf;
  24. static int vpixb;
  25. static int pixb;
  26. static void (*pixcp)(uint8_t*, uint8_t*);
  27. static void
  28. vncrdcolor(Vnc *v, uint8_t *color)
  29. {
  30. vncrdbytes(v, color, vpixb);
  31. if(cvtpixels)
  32. (*cvtpixels)(color, color, 1);
  33. }
  34. void
  35. sendencodings(Vnc *v)
  36. {
  37. char *f[10];
  38. int enc[10], nenc, i, j, nf;
  39. nf = tokenize(encodings, f, nelem(f));
  40. nenc = 0;
  41. for(i=0; i<nf; i++){
  42. for(j=0; j<nelem(enctab); j++)
  43. if(strcmp(f[i], enctab[j].name) == 0)
  44. break;
  45. if(j == nelem(enctab)){
  46. print("warning: unknown encoding %s\n", f[i]);
  47. continue;
  48. }
  49. enc[nenc++] = enctab[j].num;
  50. }
  51. vnclock(v);
  52. vncwrchar(v, MSetEnc);
  53. vncwrchar(v, 0);
  54. vncwrshort(v, nenc);
  55. for(i=0; i<nenc; i++)
  56. vncwrlong(v, enc[i]);
  57. vncflush(v);
  58. vncunlock(v);
  59. }
  60. void
  61. requestupdate(Vnc *v, int incremental)
  62. {
  63. int x, y;
  64. lockdisplay(display);
  65. x = Dx(screen->r);
  66. y = Dy(screen->r);
  67. unlockdisplay(display);
  68. if(x > v->dim.x)
  69. x = v->dim.x;
  70. if(y > v->dim.y)
  71. y = v->dim.y;
  72. vnclock(v);
  73. vncwrchar(v, MFrameReq);
  74. vncwrchar(v, incremental);
  75. vncwrrect(v, Rpt(ZP, Pt(x, y)));
  76. vncflush(v);
  77. vncunlock(v);
  78. }
  79. static Rectangle
  80. clippixbuf(Rectangle r, int maxx, int maxy)
  81. {
  82. int y, h, stride1, stride2;
  83. if(r.min.x > maxx || r.min.y > maxy){
  84. r.max.x = 0;
  85. return r;
  86. }
  87. if(r.max.y > maxy)
  88. r.max.y = maxy;
  89. if(r.max.x <= maxx)
  90. return r;
  91. stride2 = Dx(r) * pixb;
  92. r.max.x = maxx;
  93. stride1 = Dx(r) * pixb;
  94. h = Dy(r);
  95. for(y = 0; y < h; y++)
  96. memmove(&pixbuf[y * stride1], &pixbuf[y * stride2], stride1);
  97. return r;
  98. }
  99. /* must be called with display locked */
  100. static void
  101. updatescreen(Rectangle r)
  102. {
  103. Image* img;
  104. int b, bb;
  105. lockdisplay(display);
  106. if(r.max.x > Dx(screen->r) || r.max.y > Dy(screen->r)){
  107. r = clippixbuf(r, Dx(screen->r), Dy(screen->r));
  108. if(r.max.x == 0){
  109. unlockdisplay(display);
  110. return;
  111. }
  112. }
  113. /*
  114. * assume load image fails only because of resize
  115. */
  116. img = allocimage(display, r, screen->chan, 0, DNofill);
  117. if(img == nil)
  118. sysfatal("updatescreen: %r");
  119. b = Dx(r) * pixb * Dy(r);
  120. bb = loadimage(img, r, pixbuf, b);
  121. if(bb != b && verbose)
  122. fprint(2, "loadimage %d on %R for %R returned %d: %r\n", b, rectaddpt(r, screen->r.min), screen->r, bb);
  123. draw(screen, rectaddpt(r, screen->r.min), img, nil, r.min);
  124. freeimage(img);
  125. unlockdisplay(display);
  126. }
  127. static void
  128. fillrect(Rectangle r, int stride, uint8_t *color)
  129. {
  130. int x, xe, y, off;
  131. y = r.min.y;
  132. off = y * stride;
  133. for(; y < r.max.y; y++){
  134. xe = off + r.max.x * pixb;
  135. for(x = off + r.min.x * pixb; x < xe; x += pixb)
  136. (*pixcp)(&pixbuf[x], color);
  137. off += stride;
  138. }
  139. }
  140. static void
  141. loadbuf(Vnc *v, Rectangle r, int stride)
  142. {
  143. int off, y;
  144. if(cvtpixels){
  145. y = r.min.y;
  146. off = y * stride;
  147. for(; y < r.max.y; y++){
  148. vncrdbytes(v, linebuf, Dx(r) * vpixb);
  149. (*cvtpixels)(&pixbuf[off + r.min.x * pixb], linebuf, Dx(r));
  150. off += stride;
  151. }
  152. }else{
  153. y = r.min.y;
  154. off = y * stride;
  155. for(; y < r.max.y; y++){
  156. vncrdbytes(v, &pixbuf[off + r.min.x * pixb], Dx(r) * pixb);
  157. off += stride;
  158. }
  159. }
  160. }
  161. static Rectangle
  162. hexrect(uint16_t u)
  163. {
  164. int x, y, w, h;
  165. x = u>>12;
  166. y = (u>>8)&15;
  167. w = ((u>>4)&15)+1;
  168. h = (u&15)+1;
  169. return Rect(x, y, x+w, y+h);
  170. }
  171. static void
  172. dohextile(Vnc *v, Rectangle r, int stride)
  173. {
  174. uint32_t bg, fg, c;
  175. int enc, nsub, sx, sy, w, h, th, tw;
  176. Rectangle sr, ssr;
  177. fg = bg = 0;
  178. h = Dy(r);
  179. w = Dx(r);
  180. for(sy = 0; sy < h; sy += HextileDim){
  181. th = h - sy;
  182. if(th > HextileDim)
  183. th = HextileDim;
  184. for(sx = 0; sx < w; sx += HextileDim){
  185. tw = w - sx;
  186. if(tw > HextileDim)
  187. tw = HextileDim;
  188. sr = Rect(sx, sy, sx + tw, sy + th);
  189. enc = vncrdchar(v);
  190. if(enc & HextileRaw){
  191. loadbuf(v, sr, stride);
  192. continue;
  193. }
  194. if(enc & HextileBack)
  195. vncrdcolor(v, (uint8_t*)&bg);
  196. fillrect(sr, stride, (uint8_t*)&bg);
  197. if(enc & HextileFore)
  198. vncrdcolor(v, (uint8_t*)&fg);
  199. if(enc & HextileRects){
  200. nsub = vncrdchar(v);
  201. (*pixcp)((uint8_t*)&c, (uint8_t*)&fg);
  202. while(nsub-- > 0){
  203. if(enc & HextileCols)
  204. vncrdcolor(v, (uint8_t*)&c);
  205. ssr = rectaddpt(hexrect(vncrdshort(v)), sr.min);
  206. fillrect(ssr, stride, (uint8_t*)&c);
  207. }
  208. }
  209. }
  210. }
  211. }
  212. static void
  213. dorectangle(Vnc *v)
  214. {
  215. uint32_t type;
  216. int32_t n, stride;
  217. uint32_t color;
  218. Point p;
  219. Rectangle r, subr, maxr;
  220. r = vncrdrect(v);
  221. if(r.min.x == r.max.x || r.min.y == r.max.y)
  222. return;
  223. if(!rectinrect(r, Rpt(ZP, v->dim)))
  224. sysfatal("bad rectangle from server: %R not in %R", r, Rpt(ZP, v->dim));
  225. stride = Dx(r) * pixb;
  226. type = vncrdlong(v);
  227. switch(type){
  228. default:
  229. sysfatal("bad rectangle encoding from server");
  230. break;
  231. case EncRaw:
  232. loadbuf(v, Rpt(ZP, Pt(Dx(r), Dy(r))), stride);
  233. updatescreen(r);
  234. break;
  235. case EncCopyRect:
  236. p = vncrdpoint(v);
  237. lockdisplay(display);
  238. p = addpt(p, screen->r.min);
  239. r = rectaddpt(r, screen->r.min);
  240. draw(screen, r, screen, nil, p);
  241. unlockdisplay(display);
  242. break;
  243. case EncRre:
  244. case EncCorre:
  245. maxr = Rpt(ZP, Pt(Dx(r), Dy(r)));
  246. n = vncrdlong(v);
  247. vncrdcolor(v, (uint8_t*)&color);
  248. fillrect(maxr, stride, (uint8_t*)&color);
  249. while(n-- > 0){
  250. vncrdcolor(v, (uint8_t*)&color);
  251. if(type == EncRre)
  252. subr = vncrdrect(v);
  253. else
  254. subr = vncrdcorect(v);
  255. if(!rectinrect(subr, maxr))
  256. sysfatal("bad encoding from server");
  257. fillrect(subr, stride, (uint8_t*)&color);
  258. }
  259. updatescreen(r);
  260. break;
  261. case EncHextile:
  262. dohextile(v, r, stride);
  263. updatescreen(r);
  264. break;
  265. case EncMouseWarp:
  266. mousewarp(r.min);
  267. break;
  268. }
  269. }
  270. static void
  271. pixcp8(uint8_t *dst, uint8_t *src)
  272. {
  273. *dst = *src;
  274. }
  275. static void
  276. pixcp16(uint8_t *dst, uint8_t *src)
  277. {
  278. *(uint16_t*)dst = *(uint16_t*)src;
  279. }
  280. static void
  281. pixcp32(uint8_t *dst, uint8_t *src)
  282. {
  283. *(uint32_t*)dst = *(uint32_t*)src;
  284. }
  285. static void
  286. pixcp24(uint8_t *dst, uint8_t *src)
  287. {
  288. dst[0] = src[0];
  289. dst[1] = src[1];
  290. dst[2] = src[2];
  291. }
  292. static int
  293. calcpixb(int bpp)
  294. {
  295. if(bpp / 8 * 8 != bpp)
  296. sysfatal("can't handle your screen");
  297. return bpp / 8;
  298. }
  299. void
  300. readfromserver(Vnc *v)
  301. {
  302. uint8_t type;
  303. uint8_t junk[100];
  304. int32_t n;
  305. vpixb = calcpixb(v->bpp);
  306. pixb = calcpixb(screen->depth);
  307. switch(pixb){
  308. case 1:
  309. pixcp = pixcp8;
  310. break;
  311. case 2:
  312. pixcp = pixcp16;
  313. break;
  314. case 3:
  315. pixcp = pixcp24;
  316. break;
  317. case 4:
  318. pixcp = pixcp32;
  319. break;
  320. default:
  321. sysfatal("can't handle your screen: bad depth %d", pixb);
  322. }
  323. linebuf = malloc(v->dim.x * vpixb);
  324. pixbuf = malloc(v->dim.x * pixb * v->dim.y);
  325. if(linebuf == nil || pixbuf == nil)
  326. sysfatal("can't allocate pix decompression storage");
  327. for(;;){
  328. type = vncrdchar(v);
  329. switch(type){
  330. default:
  331. sysfatal("bad message from server");
  332. break;
  333. case MFrameUpdate:
  334. vncrdchar(v);
  335. n = vncrdshort(v);
  336. while(n-- > 0)
  337. dorectangle(v);
  338. flushimage(display, 1);
  339. requestupdate(v, 1);
  340. break;
  341. case MSetCmap:
  342. vncrdbytes(v, junk, 3);
  343. n = vncrdshort(v);
  344. vncgobble(v, n*3*2);
  345. break;
  346. case MBell:
  347. break;
  348. case MSAck:
  349. break;
  350. case MSCut:
  351. vncrdbytes(v, junk, 3);
  352. n = vncrdlong(v);
  353. writesnarf(v, n);
  354. break;
  355. }
  356. }
  357. }