OberonDisplay.Mod 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
  2. MODULE OberonDisplay;
  3. (** AUTHOR "pjm"; PURPOSE "Aos display driver for WM window"; *)
  4. IMPORT SYSTEM, Machine, Commands, Displays, Inputs, Modules, Plugins, Raster,
  5. WMRectangles, WMGraphics,
  6. WM := WMWindowManager;
  7. CONST
  8. DefaultDisplayName = "Oberon";
  9. DefaultWidth = 1024;
  10. DefaultHeight = 768;
  11. AlphaCursor = 10;
  12. KeyBufSize = 64;
  13. Flip = FALSE;
  14. Cache = TRUE;
  15. VAR
  16. nilpix : Raster.Pixel;
  17. TYPE
  18. OberonWindow = OBJECT (WM.BufferWindow)
  19. VAR
  20. input : OberonInput; (* initialized from outside *)
  21. curKeys : SET;
  22. curX, curY : LONGINT; (* Coordinates of the mouse pointer while moving or when released. *)
  23. keyhead, keytail : LONGINT;
  24. keybuf : ARRAY KeyBufSize OF CHAR;
  25. keys : SET;
  26. break : BOOLEAN;
  27. fixMM : BOOLEAN; (* Value TRUE denotes the presence of a 2-button mouse, Ctrl-key acts then as middle button. *)
  28. lastCtrl : BOOLEAN; (* Value TRUE denotes Ctrl-key pressed. *)
  29. PROCEDURE IsHit*(x, y : LONGINT) : BOOLEAN;
  30. BEGIN RETURN TRUE;
  31. END IsHit;
  32. PROCEDURE Mouse(VAR x, y : INTEGER; VAR keys : SET);
  33. BEGIN {EXCLUSIVE}
  34. keys := {};
  35. IF 0 IN curKeys THEN INCL(keys, 2) END;
  36. IF 1 IN curKeys THEN INCL(keys, 1) END;
  37. IF 2 IN curKeys THEN INCL(keys, 0) END;
  38. IF 30 IN curKeys THEN IF curKeys={30} THEN INCL(keys, 30); END; curKeys := curKeys - {30} END; (*fof*)
  39. IF 31 IN curKeys THEN IF curKeys={31} THEN INCL(keys, 31); END; curKeys := curKeys - {31} END;
  40. x := SHORT(curX);
  41. y := SHORT(curY)
  42. END Mouse;
  43. PROCEDURE PointerMove*(x, y : LONGINT; keys :SET);
  44. BEGIN {EXCLUSIVE}
  45. curX := x; curY := y; curKeys := curKeys * {30, 31} + keys;
  46. IF fixMM &lastCtrl THEN INCL(curKeys, 1) END;
  47. IF input # NIL THEN input.timer.Wakeup END (* have to check, because upcalls to us can start immediately *)
  48. END PointerMove;
  49. PROCEDURE WheelMove*(dz : LONGINT); (*fof*)
  50. BEGIN
  51. IF dz > 0 THEN
  52. INCL(curKeys, 30);
  53. ELSIF dz < 0 THEN
  54. INCL(curKeys, 31);
  55. END;
  56. IF input # NIL THEN input.timer.Wakeup END (* have to check, because upcalls to us can start immediately *)
  57. END WheelMove;
  58. PROCEDURE PointerUp*(x, y : LONGINT; keys : SET);
  59. BEGIN {EXCLUSIVE}
  60. curX := x; curY := y; curKeys := keys;
  61. IF input # NIL THEN input.timer.Wakeup END
  62. END PointerUp;
  63. (* Keyboard handling *)
  64. PROCEDURE InsertKey(ch : CHAR; keysym : LONGINT; flags : SET);
  65. BEGIN
  66. keys := {};
  67. IF flags * Inputs.Shift # {} THEN INCL(keys, Inputs.SHIFT) END;
  68. IF flags * Inputs.Ctrl # {} THEN INCL(keys, Inputs.CTRL) END;
  69. IF flags * Inputs.Alt # {} THEN INCL(keys, Inputs.ALT) END;
  70. IF ch # 0X THEN
  71. IF (keytail+1) MOD KeyBufSize # keyhead THEN
  72. keybuf[keytail] := ch; keytail := (keytail+1) MOD KeyBufSize
  73. END;
  74. (*timer.WakeUp*) (* always do wakeup because of race with Sleep *)
  75. ELSIF keysym = Inputs.KsBreak THEN (* Break *)
  76. break := TRUE
  77. (*timer.WakeUp *)
  78. ELSE
  79. (* skip *)
  80. END
  81. END InsertKey;
  82. PROCEDURE Close*;
  83. BEGIN {EXCLUSIVE}
  84. InsertKey(0FFX, 0, {})
  85. END Close;
  86. PROCEDURE KeyEvent*(ucs : LONGINT; flags : SET; keysym : LONGINT);
  87. BEGIN {EXCLUSIVE}
  88. IF fixMM & ((flags * Inputs.Ctrl # {}) # lastCtrl) THEN
  89. lastCtrl := flags * Inputs.Ctrl # {};
  90. IF lastCtrl THEN INCL(curKeys, 1) ELSE EXCL(curKeys, 1) END;
  91. IF input # NIL THEN input.timer.Wakeup END
  92. ELSE
  93. InsertKey(CHR(ucs), keysym, flags);
  94. IF input # NIL THEN input.timer.Wakeup END
  95. END;
  96. END KeyEvent;
  97. PROCEDURE Read(VAR ch : CHAR; VAR b : BOOLEAN);
  98. BEGIN {EXCLUSIVE}
  99. AWAIT(keyhead # keytail);
  100. ch := keybuf[keyhead]; keyhead := (keyhead+1) MOD KeyBufSize;
  101. b := break; break := FALSE
  102. END Read;
  103. PROCEDURE Available(VAR num : INTEGER; VAR b : BOOLEAN);
  104. BEGIN {EXCLUSIVE}
  105. num := SHORT((keytail-keyhead) MOD KeyBufSize);
  106. b := break; break := FALSE
  107. END Available;
  108. PROCEDURE KeyState(VAR k : SET);
  109. BEGIN {EXCLUSIVE}
  110. k := keys
  111. END KeyState;
  112. END OberonWindow;
  113. TYPE
  114. OberonInput = OBJECT (Inputs.OberonInput)
  115. VAR window : OberonWindow;
  116. PROCEDURE Mouse*(VAR x, y : INTEGER; VAR keys : SET);
  117. BEGIN
  118. window.Mouse(x, y, keys)
  119. END Mouse;
  120. PROCEDURE Read*(VAR ch : CHAR; VAR b : BOOLEAN);
  121. BEGIN
  122. window.Read(ch, b)
  123. END Read;
  124. PROCEDURE Available*(VAR num : INTEGER; VAR b : BOOLEAN);
  125. BEGIN
  126. window.Available(num, b)
  127. END Available;
  128. PROCEDURE KeyState*(VAR k : SET);
  129. BEGIN
  130. window.KeyState(k)
  131. END KeyState;
  132. END OberonInput;
  133. TYPE
  134. (* Implementation of the virtual display driver.
  135. A concrete Display must implement at least the Transfer function
  136. or initialize a linear frame buffer and call the InitFrameBuffer method.
  137. *)
  138. Display* = OBJECT (Displays.Display) (* custom display object only accessed by Oberon (no EXCLUSIVE) *)
  139. VAR
  140. disp : OberonWindow;
  141. inp : OberonInput;
  142. bufimg : Raster.Image;
  143. mode, mode1 : Raster.Mode;
  144. ml, mt, mr, mb : LONGINT;
  145. PROCEDURE LocalAddDirty(l, t, r, b : LONGINT);
  146. BEGIN
  147. IF Cache THEN
  148. IF l < ml THEN ml := l END; (* enlarge dirty rectangle *)
  149. IF t < mt THEN mt := t END;
  150. IF r > mr THEN mr := r END;
  151. IF b > mb THEN mb := b END
  152. ELSE
  153. disp.Invalidate(WMRectangles.MakeRect(l, t, r, b))
  154. END
  155. END LocalAddDirty;
  156. PROCEDURE Update*;
  157. BEGIN
  158. IF Cache & (ml # MAX(LONGINT)) THEN
  159. disp.Invalidate(WMRectangles.MakeRect(ml, mt, mr, mb)); (* updated dirty rectangle *)
  160. ml := MAX(LONGINT); mt := MAX(LONGINT); mr := MIN(LONGINT); mb := MIN(LONGINT)
  161. END
  162. END Update;
  163. PROCEDURE Transfer*(VAR buf : ARRAY OF CHAR; ofs, stride, x, y, w, h, op : LONGINT);
  164. BEGIN
  165. Raster.InitMode(mode, Raster.srcCopy);
  166. IF Flip THEN
  167. Raster.Init(bufimg, w, h, disp.img.fmt, -stride, ADDRESSOF(buf[ofs]) + (h-1)*stride);
  168. IF op = Displays.get THEN
  169. Raster.Copy(disp.img, bufimg, x, height-y-h, x+w, height-y, 0, 0, mode)
  170. ELSIF op = Displays.set THEN
  171. Raster.Copy(bufimg, disp.img, 0, 0, w, h, x, height-y-h, mode);
  172. LocalAddDirty(x, height-y-h, x+w, height-y)
  173. ELSE (* skip *)
  174. END
  175. ELSE
  176. Raster.Init(bufimg, w, h, disp.img.fmt, stride, ADDRESSOF(buf[ofs]));
  177. IF op = Displays.get THEN
  178. Raster.Copy(disp.img, bufimg, x, y, x+w, y+h, 0, 0, mode)
  179. ELSIF op = Displays.set THEN
  180. Raster.Copy(bufimg, disp.img, 0, 0, w, h, x, y, mode);
  181. LocalAddDirty(x, y, x+w, y+h)
  182. ELSE (* skip *)
  183. END
  184. END
  185. END Transfer;
  186. PROCEDURE Fill*(col, x, y, w, h : LONGINT);
  187. VAR pixel: Raster.Pixel;
  188. BEGIN
  189. IF Flip THEN
  190. Fill^(col, x, y, w, h) (* supermethod not exclusive *)
  191. ELSE
  192. Raster.InitMode(mode, Raster.srcCopy);
  193. IF ASH(col, 1) < 0 THEN (* invert *)
  194. Raster.InitMode(mode, Raster.InvDst);
  195. Raster.Fill(disp.img, x, y, x+w, y+h, nilpix, mode)
  196. ELSE
  197. Raster.InitMode(mode, Raster.srcCopy);
  198. Raster.SetRGB(pixel, col DIV 10000H, col DIV 100H, col);
  199. Raster.Fill(disp.img, x, y, x+w, y+h, pixel, mode)
  200. END;
  201. LocalAddDirty(x, y, x+w, y+h)
  202. END
  203. END Fill;
  204. PROCEDURE Dot*(col, x, y : LONGINT);
  205. VAR pixel: Raster.Pixel;
  206. BEGIN
  207. IF Flip THEN
  208. Dot^(col, x, y) (* supermethod not exclusive *)
  209. ELSE
  210. IF ASH(col, 1) < 0 THEN (* invert *)
  211. Raster.InitMode(mode, Raster.InvDst);
  212. Raster.Put(disp.img, x, y, nilpix, mode)
  213. ELSE
  214. Raster.InitMode(mode, Raster.srcCopy);
  215. Raster.SetRGB(pixel, col DIV 10000H, col DIV 100H, col);
  216. Raster.Put(disp.img, x, y, pixel, mode)
  217. END;
  218. LocalAddDirty(x, y, x+1, y+1)
  219. END
  220. END Dot;
  221. PROCEDURE Mask*(VAR buf : ARRAY OF CHAR; bitofs, stride, fg, bg, x, y, w, h : LONGINT);
  222. VAR p: ADDRESS; i, y0, h0 : LONGINT; s : SET; pixel, fgp, bgp : Raster.Pixel;
  223. BEGIN
  224. IF Flip THEN
  225. Mask^(buf, bitofs, stride, fg, bg, x, y, w, h) (* supermethod not exclusive *)
  226. ELSE
  227. IF (w > 0) & (h > 0) THEN
  228. i := SYSTEM.VAL (LONGINT, ADDRESSOF(buf[0])) MOD 4;
  229. INC(bitofs, i * 8);
  230. p := ADDRESSOF(buf[0])-i + bitofs DIV 32 * 4; (* p always aligned to 32-bit boundary *)
  231. bitofs := bitofs MOD 32; stride := stride*8;
  232. IF ASH(fg, 1) < 0 THEN (* invert *)
  233. Raster.InitMode(mode, Raster.InvDst)
  234. ELSE
  235. Raster.InitMode(mode, Raster.srcCopy);
  236. Raster.SetRGB(fgp, fg DIV 10000H, fg DIV 100H, fg);
  237. END;
  238. IF ASH(bg, 1) < 0 THEN (* invert *)
  239. Raster.InitMode(mode1, Raster.InvDst)
  240. ELSE
  241. Raster.InitMode(mode1, Raster.srcCopy);
  242. Raster.SetRGB(bgp, bg DIV 10000H, bg DIV 100H, bg);
  243. END;
  244. y0 := y; h0 := h;
  245. LOOP
  246. SYSTEM.GET(p, s); i := bitofs;
  247. LOOP
  248. IF (i MOD 32) IN s THEN
  249. IF fg >= 0 THEN Raster.Put(disp.img, x+i-bitofs, y, fgp, mode) END
  250. ELSE
  251. IF bg >= 0 THEN Raster.Put(disp.img, x+i-bitofs, y, bgp, mode1) END
  252. END;
  253. INC(i);
  254. IF i-bitofs = w THEN EXIT END;
  255. IF i MOD 32 = 0 THEN SYSTEM.GET(p+i DIV 8, s) END
  256. END;
  257. DEC(h);
  258. IF h = 0 THEN EXIT END;
  259. INC(y); INC(bitofs, stride);
  260. IF (bitofs >= 32) OR (bitofs < 0) THEN (* moved outside s *)
  261. INC(p, bitofs DIV 32 * 4); bitofs := bitofs MOD 32
  262. END
  263. END;
  264. LocalAddDirty(x, y0, x+w, y0+h0)
  265. END
  266. END
  267. END Mask;
  268. PROCEDURE Copy*(sx, sy, w, h, dx, dy : LONGINT);
  269. BEGIN
  270. IF Flip THEN
  271. Copy^(sx, sy, w, h, dx, dy) (* supermethod not exclusive *)
  272. ELSE
  273. Raster.InitMode(mode, Raster.srcCopy);
  274. Raster.Copy(disp.img, disp.img, sx, sy, sx+w, sy+h, dx, dy, mode);
  275. LocalAddDirty(dx, dy, dx+w, dy+h)
  276. END
  277. END Copy;
  278. PROCEDURE &Init*(name : ARRAY OF CHAR; w, h, x, y : LONGINT);
  279. VAR res : LONGINT; ptr : WM.PointerInfo; pixel : Raster.Pixel; mode : Raster.Mode;
  280. s : ARRAY 16 OF CHAR;
  281. BEGIN
  282. ml := MAX(LONGINT); mt := MAX(LONGINT); mr := MIN(LONGINT); mb := MIN(LONGINT);
  283. width := w; height := h; offscreen := 0; unit := 10000;
  284. NEW(bufimg);
  285. NEW(disp, w, h, FALSE);
  286. Machine.GetConfig("MB", s);
  287. disp.fixMM := (s = "2") OR (s = "-2");
  288. NEW(inp);
  289. inp.window := disp; disp.input := inp; (* "multiple inheritance" *)
  290. CASE disp.img.fmt.code OF
  291. | Raster.d8 : format := Displays.index8
  292. | Raster.bgr565 : format := Displays.color565
  293. | Raster.bgr888 : format := Displays.color888
  294. | Raster.bgra8888 : format := Displays.color8888
  295. END;
  296. IF ~Flip THEN
  297. NEW(ptr); ptr.hotX := 2; ptr.hotY := 2;
  298. NEW(ptr.img); Raster.Create(ptr.img, 4, 4, Raster.BGRA8888);
  299. Raster.SetRGBA(pixel, 255, 255, 255, AlphaCursor);
  300. Raster.InitMode(mode, Raster.srcCopy);
  301. Raster.Fill(ptr.img, 0, 0, 4, 4, pixel, mode);
  302. Raster.SetRGBA(pixel, 0, 0, 0, AlphaCursor);
  303. Raster.Fill(ptr.img, 1, 1, 3, 3, pixel, mode);
  304. disp.SetPointerInfo(ptr)
  305. END;
  306. IF Flip THEN
  307. disp.SetTitle(WM.NewString("Oberon for Bluebottle down under"))
  308. ELSE
  309. disp.SetTitle(WM.NewString("Oberon for Bluebottle"))
  310. END;
  311. disp.SetIcon(WMGraphics.LoadImage("WMIcons.tar://OberonDisplay.png", TRUE));
  312. WM.AddWindow(disp, x, y);
  313. (* Register virtual display driver *)
  314. SELF.desc := "WM virtual display driver";
  315. SELF.SetName(name);
  316. Displays.registry.Add(SELF, res);
  317. ASSERT(res = 0);
  318. (* Register virtual input driver *)
  319. inp.desc := "WM virtual input driver";
  320. inp.SetName(name);
  321. Inputs.oberonInput.Add(inp, res);
  322. ASSERT(res = 0)
  323. END Init;
  324. PROCEDURE Finalize*;
  325. BEGIN
  326. IF disp = NIL THEN RETURN END;
  327. Inputs.oberonInput.Remove(inp); (* Unregister virtual input driver *)
  328. Displays.registry.Remove(SELF); (* Unregister virtual display driver *)
  329. disp.manager.Remove(disp); (* close window *)
  330. (* bufimg := NIL; disp := NIL; inp := NIL; remove the potentially endless traps *)(* cause further drawing calls to trap *)
  331. IF win = SELF THEN win := NIL END
  332. END Finalize;
  333. END Display;
  334. VAR
  335. win : Display;
  336. (** Usage: OberonDisplay.Install [ name ] width [ character ] height ~
  337. Default name: Oberon
  338. character: single character e.g. blank or "x" *)
  339. PROCEDURE Install*(context : Commands.Context);
  340. VAR
  341. w, h : LONGINT; name : ARRAY 32 OF CHAR;
  342. dw, dh : LONGINT; disp : Plugins.Plugin;
  343. x, y : LONGINT;
  344. BEGIN
  345. IF win = NIL THEN
  346. w := 0; h := 0; name := "";
  347. context.arg.SkipWhitespace; context.arg.String(name);
  348. context.arg.SkipWhitespace; context.arg.Int(w, FALSE);
  349. context.arg.SkipBytes(1); (* skip "x" or single space *)
  350. context.arg.SkipWhitespace; context.arg.Int(h, FALSE);
  351. x := 0; y := 0;
  352. context.arg.SkipWhitespace; context.arg.Int(x, FALSE);
  353. context.arg.SkipWhitespace; context.arg.Int(y, FALSE);
  354. IF name = "" THEN name := DefaultDisplayName END;
  355. IF (w <= 0) OR (h <= 0) THEN
  356. dw := DefaultWidth; dh := DefaultHeight;
  357. disp := Displays.registry.Get("");
  358. IF disp # NIL THEN
  359. WITH disp: Displays.Display DO
  360. dw := disp.width;
  361. dh := disp.height;
  362. END;
  363. END;
  364. END;
  365. IF w <= 0 THEN w := dw END;
  366. IF h <= 0 THEN h := dh END;
  367. NEW(win, name, w, h, x, y)
  368. END;
  369. END Install;
  370. PROCEDURE Remove*;
  371. BEGIN
  372. IF win # NIL THEN win.disp.Close END;
  373. END Remove;
  374. PROCEDURE SwitchToWM*;
  375. BEGIN
  376. IF win # NIL THEN
  377. (* send magic key to Oberon (assume Oberon.Loop will read it) *)
  378. win.disp.InsertKey(0FEX, Inputs.KsNil, {})
  379. END
  380. END SwitchToWM;
  381. PROCEDURE Cleanup;
  382. BEGIN
  383. Remove;
  384. END Cleanup;
  385. BEGIN
  386. Modules.InstallTermHandler(Cleanup);
  387. END OberonDisplay.
  388. OberonDisplay.Install Oberon 1024x768;Oberon.Call System.Init Oberon ~
  389. OberonDisplay.Install 1024 768;Oberon.Call System.Init ~
  390. OberonDisplay.Remove ~
  391. SystemTools.Free OberonDisplay ~
  392. (*
  393. o mode set every time?
  394. o clean up at exit
  395. o optimization: remove exclusive, factor out all modes (src, dst, mode combinations) [what about finalize?]
  396. *)
  397. Now OberonInput.Mod is to be removed and Aos.System.Mod simplified (OberonInput.Remove
  398. is commentarized in LoadWM)