WMVNCView.Mod 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. MODULE WMVNCView; (** AUTHOR "TF"; PURPOSE "VNC Viewport"; *)
  2. IMPORT
  3. Raster, Rect := WMRectangles, WMWindowManager, VNCServer, Modules, KernelLog, Commands,
  4. Graphics := WMGraphics, Messages := WMMessages, Strings, Texts, TextUtilities;
  5. TYPE
  6. Window = WMWindowManager.Window;
  7. Rectangle = Rect.Rectangle;
  8. String = Strings.String;
  9. VNCView = OBJECT (WMWindowManager.ViewPort)
  10. VAR
  11. server: VNCServer.Server;
  12. error:BOOLEAN;
  13. backbuffer* : Graphics.Image;
  14. c : Graphics.BufferCanvas;
  15. state : Graphics.CanvasState;
  16. navig : BOOLEAN;
  17. scrollLock : BOOLEAN;
  18. fx, fy, inffx, inffy, factor, intfactor : REAL;
  19. active : BOOLEAN;
  20. PROCEDURE &New*(manager:WMWindowManager.WindowManager; port, dx, dy, w, h:LONGINT; name, password:ARRAY OF CHAR);
  21. VAR str : ARRAY 16 OF CHAR;
  22. BEGIN
  23. NEW(backbuffer);
  24. Raster.Create(backbuffer, w, h, Raster.BGR565);
  25. NEW(c, backbuffer);
  26. c.SetFont(Graphics.GetDefaultFont());
  27. c.SaveState(state);
  28. SetExtents(w, h);
  29. width0 := w; height0 := h;
  30. range.l := dx; range.t := dy; range.r := dx + w; range.b := dy + h;
  31. Strings.IntToStr(port, str);
  32. desc := "VNC view on port "; Strings.Append(desc, str);
  33. factor := 1; intfactor := 1;
  34. fx := factor; fy := factor; inffx := 1 ; inffy := inffx;
  35. active := FALSE;
  36. server := VNCServer.OpenServer(port, backbuffer, name, password, MouseEvent, KeyEvent, ClipboardEvent, CheckActive);
  37. IF server # NIL THEN
  38. manager.AddView(SELF);
  39. manager.RefreshView(SELF);
  40. error := FALSE
  41. ELSE error := TRUE
  42. END;
  43. Texts.clipboard.onTextChanged.Add(ClipboardChanged)
  44. END New;
  45. PROCEDURE CheckActive(nof : LONGINT);
  46. BEGIN
  47. IF ~active & (nof > 0) THEN
  48. active := TRUE;
  49. manager.RefreshView(SELF)
  50. END
  51. END CheckActive;
  52. PROCEDURE Update*(r : Rectangle; top : WMWindowManager.Window);
  53. BEGIN
  54. IF ~active THEN RETURN END;
  55. Draw(Rect.ResizeRect(r, 1), top.prev)
  56. END Update;
  57. PROCEDURE Refresh*(top : Window);
  58. BEGIN
  59. Update(Rect.MakeRect(ENTIER(range.l)-1, ENTIER(range.t)-1, ENTIER(range.r) + 1, ENTIER(range.b) + 1), top)
  60. END Refresh;
  61. (* in wm coordinates *)
  62. PROCEDURE Draw(r : Rectangle; top : Window);
  63. VAR cur : Window;
  64. wr, nr : Rectangle;
  65. PROCEDURE InternalDraw(r : Rectangle; cur : Window);
  66. VAR nr, cb, tnr, dsr : Rectangle;
  67. BEGIN
  68. IF cur.useAlpha & (cur.prev # NIL) THEN Draw(r, cur.prev)
  69. ELSE
  70. WHILE cur # NIL DO (* draw r in wm coordinates in all the windows from cur to top *)
  71. nr := r; cb := cur.bounds; Rect.ClipRect(nr, cb);
  72. dsr.l := ENTIER((nr.l - range.l) * fx) ; dsr.t := ENTIER((nr.t - range.t) * fy);
  73. dsr.r := ENTIER((nr.r - range.l) * fx + 0.5); dsr.b := ENTIER((nr.b - range.t) * fy + 0.5);
  74. IF ~Rect.RectEmpty(dsr) THEN
  75. c.SetClipRect(dsr); (* Set clip rect to dsr, clipped at current window *)
  76. c.ClipRectAsNewLimits(ENTIER((cur.bounds.l - range.l) * fx), ENTIER((cur.bounds.t - range.t) * fy));
  77. (* range can not be factored out because of rounding *)
  78. IF navig THEN
  79. cur.Draw(c, ENTIER((cb.r - range.l)* fx) - ENTIER((cb.l - range.l) * fx),
  80. ENTIER((cb.b - range.t) * fy) - ENTIER((cb.t - range.t) * fy), 0);
  81. ELSE
  82. cur.Draw(c, ENTIER((cb.r - range.l)* fx) - ENTIER((cb.l - range.l) * fx),
  83. ENTIER((cb.b - range.t) * fy) - ENTIER((cb.t - range.t) * fy), 1);
  84. END;
  85. c.RestoreState(state);
  86. END;
  87. cur := cur.next
  88. END;
  89. tnr.l := ENTIER((r.l - range.l) * fx); tnr.t := ENTIER((r.t - range.t) * fy);
  90. tnr.r := ENTIER((r.r - range.l) * fx + 0.5); tnr.b := ENTIER((r.b - range.t) * fy + 0.5);
  91. ClipAtImage(tnr, backbuffer);
  92. server.AddDirty(tnr)
  93. END
  94. END InternalDraw;
  95. BEGIN
  96. cur := top;
  97. IF (cur # NIL) & (~Rect.RectEmpty(r)) THEN
  98. wr := cur.bounds;
  99. IF ~Rect.IsContained(wr, r) THEN
  100. IF Rect.Intersect(r, wr) THEN
  101. (* r contains wr calculate r - wr and recursively call for resulting rectangles*)
  102. (* calculate top rectangle *)
  103. IF wr.t > r.t THEN Rect.SetRect(nr, r.l, r.t, r.r, wr.t); Draw(nr, cur.prev) END;
  104. (* calculate bottom rectangle *)
  105. IF wr.b < r.b THEN Rect.SetRect(nr, r.l, wr.b, r.r, r.b); Draw(nr, cur.prev) END;
  106. (* calculate left rectangle *)
  107. IF wr.l > r.l THEN Rect.SetRect(nr, r.l, MAX(r.t, wr.t), wr.l, MIN(r.b, wr.b)); Draw(nr, cur.prev) END;
  108. (* calculate left rectangle *)
  109. IF wr.r < r.r THEN Rect.SetRect(nr, wr.r, MAX(r.t, wr.t), r.r, MIN(r.b, wr.b)); Draw(nr, cur.prev) END;
  110. (* calculate overlapping *)
  111. nr := r; Rect.ClipRect(nr, wr);
  112. IF ~Rect.RectEmpty(nr) THEN InternalDraw(nr, cur) END
  113. ELSE Draw(r, cur.prev)
  114. END
  115. ELSE InternalDraw(r, cur)
  116. END
  117. END
  118. END Draw;
  119. PROCEDURE SetExtents(w, h : LONGINT);
  120. BEGIN
  121. range.r := range.l + w; range.b := range.t + h;
  122. END SetExtents;
  123. PROCEDURE SetScaleFactor(factor : REAL);
  124. VAR centerX, centerY : REAL;
  125. BEGIN
  126. centerX := (range.l + range.r) / 2; centerY := (range.t + range.b) /2;
  127. fx := factor; fy := factor; inffx := 1 / factor; inffy := inffx;
  128. SELF.factor := factor;
  129. range.l := centerX - inffx * 0.5 * backbuffer.width;
  130. range.t := centerY - inffy * 0.5 * backbuffer.height;
  131. range.r := centerX + inffx * 0.5 * backbuffer.width;
  132. range.b := centerY + inffy * 0.5 * backbuffer.height
  133. END SetScaleFactor;
  134. PROCEDURE KeyEvent(ucs: LONGINT; flags : SET; keysym : LONGINT);
  135. VAR msg : Messages.Message;
  136. BEGIN
  137. manager.lock.AcquireWrite;
  138. msg.originator := SELF;
  139. IF keysym = 0FFC9H THEN scrollLock := ~scrollLock END;
  140. msg.msgType := Messages.MsgKey;
  141. msg.x := ucs;
  142. msg.y := keysym;
  143. msg.flags := flags;
  144. manager.Handle(msg);
  145. manager.lock.ReleaseWrite
  146. END KeyEvent;
  147. PROCEDURE MouseEvent(x, y, dz: LONGINT; keys : SET);
  148. VAR msg : Messages.Message;
  149. BEGIN
  150. manager.lock.AcquireWrite;
  151. msg.originator := SELF;
  152. msg.msgType := Messages.MsgPointer;
  153. msg.x := ENTIER(range.l + x * inffx); msg.y := ENTIER(range.t + y * inffy);
  154. msg.dz := dz;
  155. msg.flags := keys;
  156. IF manager # NIL THEN manager.Handle(msg) END;
  157. manager.lock.ReleaseWrite
  158. END MouseEvent;
  159. PROCEDURE ClipboardEvent(text : String);
  160. BEGIN {EXCLUSIVE}
  161. Texts.clipboard.onTextChanged.Remove(ClipboardChanged);
  162. Texts.clipboard.AcquireWrite;
  163. Texts.clipboard.Delete(0, Texts.clipboard.GetLength());
  164. TextUtilities.StrToText(Texts.clipboard, 0, text^);
  165. Texts.clipboard.ReleaseWrite;
  166. Texts.clipboard.onTextChanged.Add(ClipboardChanged)
  167. END ClipboardEvent;
  168. PROCEDURE ClipboardChanged(sender, data : ANY);
  169. VAR text : String;
  170. BEGIN {EXCLUSIVE}
  171. NEW(text, 16 * 1024);
  172. TextUtilities.TextToStr(Texts.clipboard, text^);
  173. IF server = NIL THEN KernelLog.String("Cann not understand how this could possibly happen :-( "); KernelLog.Ln
  174. ELSE
  175. server.SendClipboard(text)
  176. END
  177. END ClipboardChanged;
  178. PROCEDURE Close;
  179. BEGIN
  180. Texts.clipboard.onTextChanged.Remove(ClipboardChanged);
  181. manager.RemoveView(SELF); server.Close
  182. END Close;
  183. END VNCView;
  184. TYPE
  185. VVList = POINTER TO RECORD
  186. v:VNCView;
  187. next:VVList
  188. END;
  189. VAR v: VVList;
  190. PROCEDURE Bound(VAR x:LONGINT; min, max:LONGINT);
  191. BEGIN
  192. IF x < min THEN x := min ELSE IF x > max THEN x := max END END
  193. END Bound;
  194. PROCEDURE ClipAtImage(VAR x: Rectangle; img:Raster.Image);
  195. BEGIN
  196. Bound(x.l, 0, img.width - 1);Bound(x.r, 0, img.width - 1);
  197. Bound(x.t, 0, img.height - 1);Bound(x.b, 0, img.height - 1)
  198. END ClipAtImage;
  199. (** name password port x y w h
  200. name and password are strings optionally in " "
  201. use "" for no password
  202. *)
  203. PROCEDURE Install*(context : Commands.Context); (** name password [port [x [ y [ width [ height ] ] ] ] ] ~ *)
  204. VAR
  205. name:ARRAY 100 OF CHAR;
  206. password: ARRAY 32 OF CHAR;
  207. port, dx, dy, w, h:LONGINT;
  208. nv:VNCView;
  209. vl:VVList;
  210. BEGIN
  211. context.arg.SkipWhitespace;
  212. context.arg.String(name);
  213. context.arg.SkipWhitespace;
  214. context.arg.String(password);
  215. context.arg.SkipWhitespace;
  216. (* port *)
  217. port := 5901;
  218. IF (context.arg.Peek() >= '0') & (context.arg.Peek() <= '9') THEN context.arg.Int(port, TRUE) END;
  219. context.arg.SkipWhitespace;
  220. (* dx *)
  221. dx := 0;
  222. IF (context.arg.Peek() >= '0') & (context.arg.Peek() <= '9') OR (context.arg.Peek()='-') THEN context.arg.Int(dx, TRUE) END;
  223. context.arg.SkipWhitespace;
  224. (* dy *)
  225. dy := 0; IF (context.arg.Peek() >= '0') & (context.arg.Peek() <= '9') OR (context.arg.Peek()='-') THEN context.arg.Int(dy, TRUE) END;
  226. context.arg.SkipWhitespace;
  227. (* w *)
  228. w := 1024; IF (context.arg.Peek() >= '0') & (context.arg.Peek() <= '9') THEN context.arg.Int(w, TRUE) END;
  229. context.arg.SkipWhitespace;
  230. (* h *)
  231. h := 768; IF (context.arg.Peek() >= '0') & (context.arg.Peek() <= '9') THEN context.arg.Int(h, TRUE) END;
  232. context.arg.SkipWhitespace;
  233. NEW(nv, WMWindowManager.GetDefaultManager(), port, dx, dy, w, h, name, password);
  234. context.out.String("VNC server started. Listening on port : "); context.out.Int(port, 4);
  235. context.out.Ln; context.out.String("Position (x, y): "); context.out.Int(dx, 4); context.out.String(", "); context.out.Int(dy, 4);
  236. context.out.Ln; context.out.String("Size (w, h): "); context.out.Int(w, 4); context.out.String(", "); context.out.Int(h, 4);
  237. IF ~nv.error THEN
  238. NEW(vl); vl.v:=nv;
  239. vl.next:=v; v:=vl
  240. END;
  241. END Install;
  242. PROCEDURE Uninstall*;
  243. BEGIN
  244. WHILE v # NIL DO v.v.Close; v := v.next END;
  245. END Uninstall;
  246. PROCEDURE Cleanup;
  247. BEGIN
  248. Uninstall;
  249. END Cleanup;
  250. BEGIN
  251. Modules.InstallTermHandler(Cleanup)
  252. END WMVNCView.
  253. System.Free WMVNCView VNCServer~
  254. Aos.Call WMVNCView.Install "Bluebottle VNC View1" "" 5903 0 0 1024 768~
  255. Aos.Call WMVNCView.Install "Bluebottle VNC View1" "" 5902 1280 0 1280 1024~
  256. Aos.Call WMVNCView.Install "Bluebottle VNC View1" "" 5903 0 0 1024 768~
  257. Aos.Call WMVNCView.Uninstall (BYE)