2
0

WindowManager.Mod 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709
  1. MODULE WindowManager; (** AUTHOR "TF"; PURPOSE "Window manager implementation"; *)
  2. IMPORT
  3. KernelLog, Kernel, Strings, Plugins, Inputs, Modules, Displays, Graphics := WMGraphics,
  4. Messages := WMMessages, DW := WMDefaultWindows,
  5. WM := WMWindowManager, Rect := WMRectangles, Raster, WMFontManager (*Load*), Commands, Options;
  6. CONST
  7. DirtyBufSize = 128;
  8. CombineLookahead = 64;
  9. XYResizeHandleSize = 15;
  10. ZF = 0.90; ZD = 0.1;
  11. TYPE
  12. Window = WM.Window;
  13. Rectangle = Rect.Rectangle;
  14. ViewPort* = OBJECT (WM.ViewPort);
  15. VAR
  16. backbuffer : Graphics.Image;
  17. deviceRect : Rect.Rectangle;
  18. canvas : Graphics.BufferCanvas;
  19. state : Graphics.CanvasState;
  20. display : Displays.Display;
  21. internnavig, navig : BOOLEAN;
  22. lastx, lasty : LONGINT;
  23. lastKeys : SET;
  24. modifierKeys : SET;
  25. meta : BOOLEAN;
  26. fx, fy, inffx, inffy, factor, intfactor : REAL;
  27. PROCEDURE &New*(disp : Displays.Display);
  28. BEGIN
  29. display := disp;
  30. NEW(backbuffer);
  31. KernelLog.String("WindowManager: Display resolution: ");
  32. KernelLog.Int(disp.width, 0); KernelLog.Char("x"); KernelLog.Int(disp.height, 0);
  33. KernelLog.Char("x"); KernelLog.Int(disp.format * 8, 0); KernelLog.Ln;
  34. Raster.Create(backbuffer, disp.width, disp.height, Raster.DisplayFormat(disp.format));
  35. range.r := range.l + disp.width; range.b := range.t + disp.height;
  36. deviceRect.r := disp.width; deviceRect.b := disp.height;
  37. width0 := disp.width; height0 := disp.height;
  38. desc := "Graphics adapter view";
  39. NEW(canvas, backbuffer);
  40. canvas.SetFont(Graphics.GetDefaultFont());
  41. canvas.SaveState(state);
  42. factor := 1; intfactor := 1;
  43. fx := factor; fy := factor; inffx := 1 ; inffy := inffx;
  44. internnavig := FALSE;
  45. modifierKeys := {};
  46. END New;
  47. (** Return the modifier keys that are pressed in the view *)
  48. PROCEDURE GetKeyState*(VAR state : SET);
  49. BEGIN
  50. state := modifierKeys
  51. END GetKeyState;
  52. PROCEDURE KeyEvent(ucs : LONGINT; flags : SET; keysym : LONGINT);
  53. VAR msg : Messages.Message; done : BOOLEAN; r : Rectangle; originX, originY : LONGINT; w, h : REAL;
  54. BEGIN
  55. manager.lock.AcquireWrite;
  56. modifierKeys := flags;
  57. msg.originator := SELF;
  58. IF (flags * Inputs.Ctrl # {}) & (flags * Inputs.Alt # {}) & (keysym = Inputs.KsDelete) THEN
  59. manager.lock.ReleaseWrite; Modules.Shutdown(Modules.Reboot); LOOP END
  60. END;
  61. meta := (flags * Inputs.Meta # {}) OR ((flags * Inputs.Alt # {}) & (flags * Inputs.Shift # {}));
  62. msg.msgType := Messages.MsgKey;
  63. msg.x := ucs;
  64. msg.y := keysym;
  65. msg.flags := flags;
  66. done := FALSE;
  67. IF meta THEN
  68. IF keysym = 0FF50H THEN (* Home key *)
  69. manager.GetPopulatedArea(r);
  70. SetRange(r.l, r.t, r.r - r.l, r.b - r.t, TRUE);
  71. done := TRUE
  72. ELSIF keysym = 0FF57H THEN (* End key *)
  73. originX := ENTIER((range.l + range.r - display.width) / 2);
  74. originY := ENTIER((range.t + range.b - display.height) / 2);
  75. SetRange(originX, originY, display.width, display.height, TRUE);
  76. done := TRUE
  77. ELSIF keysym = 0FF53H THEN (* right *)
  78. w := range.r - range.l; SetRange(range.l + w, range.t, w, range.b - range.t, TRUE); done := TRUE
  79. ELSIF keysym = 0FF51H THEN (* left *)
  80. w := range.r - range.l; SetRange(range.l - w, range.t, w, range.b - range.t, TRUE); done := TRUE
  81. ELSIF keysym = 0FF54H THEN (* bottom *)
  82. h := range.b - range.t; SetRange(range.l, range.t + h, range.r - range.l, h, TRUE); done := TRUE
  83. ELSIF keysym = 0FF52H THEN (* top *)
  84. h := range.b - range.t; SetRange(range.l, range.t - h, range.r - range.l, h, TRUE); done := TRUE
  85. ELSIF keysym = 0FF55H THEN (* pgup *)
  86. w := range.r - range.l; h := range.b - range.t; SetRange(range.l + w /4, range.t + h / 4, w / 2, h / 2, TRUE); done := TRUE
  87. ELSIF keysym = 0FF56H THEN (* pgdn *)
  88. w := range.r - range.l; h := range.b - range.t; SetRange(range.l - w /2, range.t - h / 2, w * 2, h * 2, TRUE); done := TRUE
  89. END
  90. END;
  91. IF ~done THEN manager.Handle(msg) END;
  92. manager.lock.ReleaseWrite
  93. END KeyEvent;
  94. PROCEDURE PointerEvent(x, y, z, dx, dy, dz : LONGINT; keys : SET);
  95. VAR
  96. msg : Messages.Message; of : REAL; i : LONGINT; ignore : BOOLEAN;
  97. centerX, centerY : REAL; w : Window;
  98. BEGIN
  99. ignore := FALSE;
  100. msg.originator := SELF;
  101. msg.msgType := Messages.MsgPointer;
  102. IF meta THEN
  103. manager.lock.AcquireWrite;
  104. w := manager(WindowManager).GetPositionOwnerIntern(ENTIER(range.l + x * inffx), ENTIER(range.t + y * inffy), SELF);
  105. IF (w # NIL) & (w # manager(WindowManager).bottom) THEN
  106. IF ((0 IN lastKeys) # (0 IN keys)) & (0 IN keys) THEN
  107. ZoomToWindow(w); ignore := TRUE
  108. ELSIF ((2 IN lastKeys) # (2 IN keys)) & (2 IN keys) THEN
  109. SetInitialWindowBounds(w); ignore := TRUE
  110. END;
  111. END;
  112. IF (dz # 0) THEN
  113. navig := TRUE;
  114. of := factor;
  115. IF (dz < 0) THEN
  116. FOR i := 0 TO ABS(dz) - 1 DO intfactor := (intfactor * ZF);
  117. IF intfactor < 0.001 * 0.001 THEN intfactor := 0.001 * 0.001 END
  118. END
  119. ELSE
  120. FOR i := 0 TO ABS(dz) - 1 DO intfactor := (intfactor * 1 / ZF);
  121. IF intfactor > 50 THEN factor := 50 END
  122. END
  123. END;
  124. IF ABS(intfactor - 1) < ZD THEN factor := 1
  125. ELSIF ABS(intfactor - 0.5) < ZD THEN factor := 0.5
  126. ELSIF ABS(intfactor - ENTIER(intfactor)) < 1/10 * (intfactor) THEN factor := ENTIER(intfactor)
  127. ELSE factor := intfactor
  128. END;
  129. IF of # factor THEN
  130. centerX := range.l + x * inffx; (*fof*) (** fof: lastx -> x *)
  131. centerY := range.t + y * inffy; (** fof: lasty -> y *)
  132. fx := factor; fy := factor; inffx := 1 / factor; inffy := inffx;
  133. centerX := centerX - ((x - 0.5 * backbuffer.width) * inffx);
  134. centerY := centerY - ((y - 0.5 * backbuffer.height) * inffy);
  135. range.l := centerX - inffx * 0.5 * backbuffer.width;
  136. range.t := centerY - inffy * 0.5 * backbuffer.height;
  137. range.r := centerX + inffx * 0.5 * backbuffer.width;
  138. range.b := centerY + inffy * 0.5 * backbuffer.height;
  139. manager.RefreshView(SELF)
  140. END;
  141. lastx := x; lasty := y; ignore := TRUE
  142. ELSIF ((x = 0) OR (y = 0) OR (x = backbuffer.width - 1) OR (y = backbuffer.height - 1))
  143. (* & ((ABS(dx) >1) OR (ABS(dy) > 1)) *) THEN
  144. IF (x = 0) OR (x = backbuffer.width - 1) THEN range.l := range.l + (inffx * dx); range.r := range.r + (inffx * dx) END;
  145. IF (y = 0) OR (y = backbuffer.height - 1) THEN range.t := range.t + (inffy * dy); range.b := range.b + (inffy * dy) END;
  146. lastx := x; lasty := y;
  147. navig := TRUE; manager.RefreshView(SELF)
  148. END;
  149. manager.lock.ReleaseWrite
  150. ELSE
  151. IF ~internnavig THEN IF navig THEN navig := FALSE; manager.RefreshView(SELF) END END;
  152. lastx := x; lasty := y
  153. END;
  154. lastKeys := keys;
  155. msg.x := ENTIER(range.l + x * inffx); msg.y := ENTIER(range.t + y * inffy); msg.z := z;
  156. msg.dx := ENTIER(dx * inffx); msg.dy := ENTIER(dy * inffy); msg.dz := dz;
  157. msg.flags := keys;
  158. IF ~ignore THEN
  159. IF manager # NIL THEN manager.Handle(msg) END;
  160. END;
  161. END PointerEvent;
  162. PROCEDURE ZoomToWindow(w : Window);
  163. VAR cur : WM.DecorList; r : Rectangle;
  164. BEGIN
  165. ASSERT(manager.lock.HasWriteLock());
  166. r := w.bounds;
  167. IF w.master # NIL THEN
  168. w := w.master;
  169. r := w.bounds;
  170. cur := w.decor;
  171. (* consider decoration *)
  172. WHILE cur # NIL DO Rect.ExtendRect(r, cur.w.bounds); cur := cur.next END;
  173. END;
  174. IF (r.r - r.l < backbuffer.width) & (r.b - r.t < backbuffer.height) THEN
  175. SetRange(r.l, r.t, backbuffer.width, backbuffer.height, TRUE)
  176. ELSE
  177. SetRange(r.l, r.t, r.r - r.l, r.b - r.t, TRUE)
  178. END
  179. END ZoomToWindow;
  180. PROCEDURE SetInitialWindowBounds(w : Window);
  181. VAR width, height : LONGINT;
  182. BEGIN
  183. ASSERT(manager.lock.HasWriteLock());
  184. IF w.master # NIL THEN w := w.master END;
  185. width := w.initialBounds.r - w.initialBounds.l;
  186. height := w.initialBounds.b - w.initialBounds.t;
  187. (* set original bounds of the window *)
  188. manager.SetWindowSize(w, width, height);
  189. END SetInitialWindowBounds;
  190. (** Set the observed range. *)
  191. PROCEDURE SetRange*(x, y, w, h : REAL; showTransition : BOOLEAN);
  192. VAR
  193. sx, sy, sx2, sy2, dx, dy, dx2, dy2, x2, y2 : REAL;
  194. i, steps : LONGINT;
  195. CONST Steps = 16;
  196. PROCEDURE Set(x, y, w, h : REAL);
  197. VAR tf : REAL;
  198. BEGIN
  199. range.l := x;
  200. range.t := y;
  201. factor := (display.width) / w;
  202. tf := (display.height) / h;
  203. IF factor > tf THEN factor := tf END;
  204. fx := factor; fy := factor; inffx := 1 / factor; inffy := inffx;
  205. range.r := x + display.width * inffx;
  206. range.b := y + display.height * inffy;
  207. intfactor := factor;
  208. manager.RefreshView(SELF);
  209. END Set;
  210. BEGIN
  211. IF w = 0 THEN w := 0.001 END;
  212. IF h = 0 THEN h := 0.001 END;
  213. IF showTransition THEN
  214. sx := range.l; sy := range.t;
  215. sx2 := range.r; sy2 := range.b;
  216. x2 := x + w; y2 := y + h;
  217. steps := Steps;
  218. IF (sx = x) & (sy = y) & (sx2 - sx = w) & (sy2- sy = h) THEN steps := 1 END;
  219. dx := (x - sx) / steps;
  220. dy := (y - sy) / steps;
  221. dx2 := (x2 - sx2) / steps;
  222. dy2 := (y2 - sy2) / steps;
  223. internnavig := TRUE; navig := TRUE;
  224. FOR i := 1 TO steps-1 DO
  225. Set(sx + dx * i, sy + dy * i, (sx2 + dx2 * i) - (sx + dx * i), (sy2 + dy2 * i) - (sy + dy * i))
  226. END;
  227. internnavig := FALSE; navig := FALSE
  228. END;
  229. Set(x, y, w, h)
  230. END SetRange;
  231. (** r in wm coordinates *)
  232. PROCEDURE Update*(r : Rectangle; top : Window);
  233. BEGIN
  234. ASSERT(manager.lock.HasWriteLock());
  235. Draw(r (*fof: was Rect.ResizeRect(r, 1)*), top.prev) (* assuming the src -domain is only 1 *) (*?fof: what does this mean? For me this makes no sense *)
  236. END Update;
  237. PROCEDURE Refresh*(top : Window);
  238. BEGIN
  239. ASSERT(manager.lock.HasWriteLock());
  240. Update(Rect.MakeRect(ENTIER(range.l)-1, ENTIER(range.t)-1, ENTIER(range.r) + 1, ENTIER(range.b) + 1), top)
  241. END Refresh;
  242. PROCEDURE GetWMCoordinates*(CONST r : Rect.Rectangle) : Rect.Rectangle;
  243. VAR rect : Rect.Rectangle;
  244. BEGIN
  245. rect.l := ENTIER(range.l + r.l * inffx);
  246. rect.r := ENTIER(range.l + r.r * inffx + 0.5);
  247. rect.t := ENTIER(range.t + r.t * inffy);
  248. rect.b := ENTIER(range.t + r.b * inffy + 0.5);
  249. RETURN rect;
  250. END GetWMCoordinates;
  251. (* in wm coordinates *)
  252. PROCEDURE Draw(r : Rectangle; top : Window);
  253. VAR cur : Window;
  254. wr, nr : Rectangle;
  255. PROCEDURE InternalDraw(r : Rectangle; cur : Window);
  256. VAR nr, cb, tnr, dsr : Rectangle; width, height : LONGINT;
  257. BEGIN
  258. ASSERT(cur.isVisible);
  259. IF cur.useAlpha & (cur.prev # NIL) THEN Draw(r, cur.prev)
  260. ELSE
  261. WHILE cur # NIL DO (* draw r in wm coordinates in all the windows from cur to top *)
  262. IF cur.isVisible & (~(WM.FlagNavigation IN cur.flags) OR (cur.view = SELF)) THEN
  263. IF (WM.FlagNavigation IN cur.flags) THEN
  264. cb := GetWMCoordinates(cur.bounds);
  265. ELSE
  266. cb := cur.bounds;
  267. END;
  268. nr := r; Rect.ClipRect(nr, cb);
  269. IF (WM.FlagNavigation IN cur.flags) THEN
  270. dsr.l := ENTIER((nr.l - range.l) * fx - fx); dsr.t := ENTIER((nr.t - range.t) * fy - fy);
  271. dsr.r := ENTIER((nr.r - range.l) * fx + fx + 0.5); dsr.b := ENTIER((nr.b - range.t) * fy + fy + 0.5);
  272. ELSE
  273. dsr.l := ENTIER((nr.l - range.l) * fx) ; dsr.t := ENTIER((nr.t - range.t) * fy);
  274. dsr.r := ENTIER((nr.r - range.l) * fx + 0.5); dsr.b := ENTIER((nr.b - range.t) * fy + 0.5);
  275. END;
  276. IF (~Rect.RectEmpty(dsr)) & (Rect.Intersect(dsr, deviceRect)) THEN
  277. canvas.SetClipRect(dsr); (* Set clip rect to dsr, clipped at current window *)
  278. (* range can not be factored out because of rounding *)
  279. IF (WM.FlagNavigation IN cur.flags) THEN
  280. canvas.ClipRectAsNewLimits(cur.bounds.l, cur.bounds.t); (*ENTIER((cb.l - range.l) * fx), ENTIER((cb.t - range.t) * fy)); *)
  281. width := cur.GetWidth();
  282. height := cur.GetHeight();
  283. ELSE
  284. canvas.ClipRectAsNewLimits(ENTIER((cur.bounds.l - range.l) * fx), ENTIER((cur.bounds.t - range.t) * fy));
  285. width := ENTIER((cb.r - range.l)* fx) - ENTIER((cb.l - range.l) * fx);
  286. height := ENTIER((cb.b - range.t) * fy) - ENTIER((cb.t - range.t) * fy);
  287. END;
  288. IF navig THEN
  289. cur.Draw(canvas, width, height, Graphics.ScaleBox);
  290. ELSE
  291. cur.Draw(canvas, width, height, Graphics.ScaleBilinear);
  292. END;
  293. canvas.RestoreState(state);
  294. END;
  295. END;
  296. cur := cur.next
  297. END;
  298. tnr.l := ENTIER((r.l - range.l) * fx); tnr.t := ENTIER((r.t - range.t) * fy);
  299. tnr.r := ENTIER((r.r - range.l) * fx + 0.5); tnr.b := ENTIER((r.b - range.t) * fy + 0.5);
  300. ClipAtImage(tnr, backbuffer);
  301. IF ((tnr.l < tnr.r) & (tnr.t < tnr.b)) THEN
  302. display.Transfer(backbuffer.mem^, (tnr.l * backbuffer.fmt.bpp DIV 8) + tnr.t * backbuffer.bpr,
  303. backbuffer.bpr, tnr.l, tnr.t, tnr.r - tnr.l, tnr.b - tnr.t, Displays.set)
  304. END
  305. END
  306. END InternalDraw;
  307. BEGIN
  308. ASSERT(manager.lock.HasWriteLock());
  309. cur := top;
  310. IF (cur # NIL) & (~Rect.RectEmpty(r)) THEN
  311. IF cur.isVisible & ~((WM.FlagNavigation IN cur.flags) & (cur.view # SELF)) THEN
  312. IF (WM.FlagNavigation IN cur.flags) THEN
  313. wr := GetWMCoordinates(cur.bounds);
  314. ELSE
  315. wr := cur.bounds;
  316. END;
  317. IF ~Rect.IsContained(wr, r) THEN
  318. IF Rect.Intersect(r, wr) THEN
  319. (* r contains wr calculate r - wr and recursively call for resulting rectangles*)
  320. (* calculate top rectangle *)
  321. IF wr.t > r.t THEN Rect.SetRect(nr, r.l, r.t, r.r, wr.t); Draw(nr, cur.prev) END;
  322. (* calculate bottom rectangle *)
  323. IF wr.b < r.b THEN Rect.SetRect(nr, r.l, wr.b, r.r, r.b); Draw(nr, cur.prev) END;
  324. (* calculate left rectangle *)
  325. 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;
  326. (* calculate left rectangle *)
  327. 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;
  328. (* calculate overlapping *)
  329. nr := r; Rect.ClipRect(nr, wr);
  330. IF ~Rect.RectEmpty(nr) THEN InternalDraw(nr, cur) END
  331. ELSE Draw(r, cur.prev)
  332. END
  333. ELSE InternalDraw(r, cur)
  334. END
  335. ELSE
  336. Draw(r, cur.prev);
  337. END;
  338. END
  339. END Draw;
  340. END ViewPort;
  341. DirtyQ = OBJECT
  342. VAR
  343. dirtyHead, dirtyTail : LONGINT;
  344. dirtyBuf : ARRAY DirtyBufSize OF Rectangle;
  345. overflow : BOOLEAN;
  346. (* Between a call to Has and a call to Get no other process may do a Get *)
  347. PROCEDURE Has():BOOLEAN;
  348. BEGIN
  349. RETURN (dirtyHead # dirtyTail)
  350. END Has;
  351. PROCEDURE Get(VAR r : Rectangle);
  352. BEGIN {EXCLUSIVE}
  353. AWAIT((dirtyHead # dirtyTail));
  354. r := dirtyBuf[dirtyHead];
  355. dirtyHead := (dirtyHead + 1) MOD DirtyBufSize
  356. END Get;
  357. PROCEDURE Add(VAR r : Rectangle);
  358. VAR t : Rectangle; i: LONGINT;
  359. BEGIN {EXCLUSIVE}
  360. IF (dirtyTail + 1) MOD DirtyBufSize = dirtyHead THEN
  361. KernelLog.Enter; KernelLog.String("WindowManager: Buffer Full"); KernelLog.Exit;
  362. overflow := TRUE; t := r; i := dirtyHead;
  363. WHILE i # dirtyTail DO Rect.ExtendRect(t, dirtyBuf[i]);
  364. i := (i + 1) MOD DirtyBufSize
  365. END;
  366. dirtyHead := 0; dirtyBuf[0] := t; dirtyTail := 1;
  367. ELSE
  368. dirtyBuf[dirtyTail] := r;
  369. dirtyTail := (dirtyTail + 1) MOD DirtyBufSize
  370. END
  371. END Add;
  372. END DirtyQ;
  373. UnhitableWindow = OBJECT(WM.BufferWindow);
  374. PROCEDURE IsHit*(x, y : LONGINT) : BOOLEAN;
  375. BEGIN
  376. RETURN FALSE
  377. END IsHit;
  378. END UnhitableWindow;
  379. WindowManager* = OBJECT (WM.WindowManager)
  380. VAR
  381. top, bottom : Window; (* top is always present and is the pointer, bottom is always present and is the background *)
  382. dirtyQ : DirtyQ;
  383. patches : ARRAY CombineLookahead OF Rectangle;
  384. running : BOOLEAN;
  385. views : WM.ViewPort;
  386. (* pointer handling *)
  387. kdprev : LONGINT;
  388. pointerKeys : SET;
  389. (* used by CheckPointerImg *)
  390. pointerOwner : Window;
  391. pointerX, pointerY : LONGINT;
  392. pointerInfo : WM.PointerInfo;
  393. (* focus *)
  394. focusOwner : Window;
  395. fifi : Fifi;
  396. (* drag & drop *)
  397. dragging : BOOLEAN;
  398. dragImage : Graphics.Image;
  399. dragCursor : UnhitableWindow;
  400. dragInfo : WM.DragInfo;
  401. dragSender : Window;
  402. PROCEDURE &New*;
  403. VAR pointer : WM.BufferWindow; bg : DW.BackWindow;
  404. BEGIN
  405. Init;
  406. NEW(fifi, 4000);
  407. NEW(dirtyQ);
  408. NEW(pointer, 30, 30, TRUE); pointer.useAlpha := TRUE;
  409. top := pointer; top.flags := { WM.FlagStayOnTop, WM.FlagNonDispatched, WM.FlagHidden };
  410. NEW(bg,0); bg.manager := SELF;
  411. bottom := bg; bottom.next := top; top.prev := bottom;
  412. bg.flags := {WM.FlagHidden};
  413. SetWindowTitle(top, WM.NewString("Mouse Cursor"));
  414. SetWindowTitle(bottom, WM.NewString("Old background"));
  415. decorate := DefaultDecorator;
  416. END New;
  417. PROCEDURE ShutDown*;
  418. VAR rect: Rectangle;
  419. BEGIN
  420. lock.AcquireWrite;
  421. ShutDown^; fifi.Cleanup;
  422. WHILE bottom.next # top DO Remove(bottom.next) END;
  423. running := FALSE;
  424. dirtyQ.Add(rect); (* wake up and die *)
  425. lock.ReleaseWrite
  426. END ShutDown;
  427. PROCEDURE CheckChain*(details : BOOLEAN);
  428. VAR cur : Window; title : Strings.String;
  429. BEGIN
  430. KernelLog.Enter;
  431. KernelLog.String("WindowManager.CheckChain: Bottom up..."); KernelLog.Ln;
  432. cur := bottom;
  433. WHILE cur # NIL DO
  434. KernelLog.String("ID "); KernelLog.Int(cur.id, 0); KernelLog.String(": ");
  435. IF (cur IS DW.TopWindow) THEN KernelLog.String("[T]");
  436. ELSIF (cur IS DW.LeftWindow) THEN KernelLog.String("[L]");
  437. ELSIF (cur IS DW.RightWindow) THEN KernelLog.String("[R]");
  438. ELSIF (cur IS DW.BottomWindow) THEN KernelLog.String("[B]");
  439. ELSIF (cur IS DW.BackWindow) THEN
  440. KernelLog.String("[Back:");
  441. title := GetWindowTitle(cur);
  442. IF title # NIL THEN KernelLog.String(title^); ELSE KernelLog.String("NIL"); END;
  443. KernelLog.String("]");
  444. ELSIF (cur IS DW.DecorWindow) THEN KernelLog.String("[Decor]");
  445. ELSE
  446. title := GetWindowTitle(cur);
  447. IF title # NIL THEN KernelLog.String(title^) ELSE KernelLog.String("[NIL]") END;
  448. END;
  449. IF details THEN
  450. IF (cur.master # NIL) THEN
  451. KernelLog.String(" M={"); KernelLog.Int(cur.master.id, 0); KernelLog.String("}");
  452. END;
  453. KernelLog.String(" (");
  454. KernelLog.Bits(cur.flags, 0, 10);
  455. KernelLog.String(")"); KernelLog.Ln;
  456. END;
  457. KernelLog.String("-->");
  458. cur := cur.next
  459. END;
  460. KernelLog.String("NIL"); KernelLog.Ln;
  461. KernelLog.Exit;
  462. END CheckChain;
  463. PROCEDURE InsertAfter(old, new : Window);
  464. BEGIN
  465. ASSERT(lock.HasWriteLock());
  466. new.next := old.next;
  467. new.prev := old;
  468. old.next := new;
  469. new.next.prev := new
  470. END InsertAfter;
  471. (* below mouse *)
  472. PROCEDURE FindTopWindow(stayontop : BOOLEAN) : Window;
  473. VAR cur : Window;
  474. BEGIN
  475. ASSERT(lock.HasWriteLock());
  476. cur := top.prev;
  477. IF ~stayontop THEN
  478. WHILE (cur.prev # NIL) & (WM.FlagStayOnTop IN cur.flags) DO cur := cur.prev END
  479. END;
  480. RETURN cur
  481. END FindTopWindow;
  482. PROCEDURE FindBottomWindow(stayOnBottom : BOOLEAN) : Window;
  483. VAR cur : Window;
  484. BEGIN
  485. ASSERT(lock.HasWriteLock());
  486. cur := bottom;
  487. IF ~stayOnBottom THEN
  488. WHILE (cur.next # NIL) & (WM.FlagStayOnBottom IN cur.next.flags) DO cur := cur.next; END;
  489. END;
  490. ASSERT(cur # NIL);
  491. RETURN cur;
  492. END FindBottomWindow;
  493. PROCEDURE Broadcast*(VAR m : Messages.Message);
  494. VAR cur : Window; discard : BOOLEAN;
  495. BEGIN
  496. lock.AcquireWrite;
  497. PreviewMessage(m, discard);
  498. IF ~discard THEN
  499. cur := bottom;
  500. WHILE cur # NIL DO
  501. IF ~SendMessage(cur, m) THEN KernelLog.String("WindowManager: Broadcast did not reach all windows "); KernelLog.Ln END;
  502. cur := cur.next
  503. END;
  504. END;
  505. lock.ReleaseWrite
  506. END Broadcast;
  507. PROCEDURE Add*(left, top : LONGINT; w : Window; flags : SET);
  508. VAR plugin : Plugins.Plugin; oldPointerOwner: Window; m: Messages.Message;
  509. BEGIN
  510. ASSERT((w.next = NIL) & (w.prev = NIL)); (* window can not be inserted twice *)
  511. lock.AcquireWrite;
  512. w.flags := w.flags + flags;
  513. IF flags * { WM.FlagNonDispatched } = { } THEN NEW(w.sequencer, w.Handle) END;
  514. IF (flags * { WM.FlagNavigation } # {}) & (w.view = NIL) THEN
  515. plugin := viewRegistry.Get("");
  516. IF (plugin # NIL) & (plugin IS WM.ViewPort) THEN w.view := plugin (WM.ViewPort); END;
  517. END;
  518. Rect.MoveRel(w.bounds, left - w.bounds.l, top - w.bounds.t);
  519. InsertAfter(FindTopWindow(WM.FlagStayOnTop IN flags), w);
  520. w.manager := SELF;
  521. IF (flags * { WM.FlagFrame } # { }) & (decorate # NIL) THEN decorate(w) END;
  522. oldPointerOwner := GetPositionOwnerIntern(pointerX, pointerY, NIL);
  523. AddVisibleDirty(w, w.bounds);
  524. IF oldPointerOwner = NIL THEN
  525. pointerOwner := GetPositionOwnerIntern(pointerX, pointerY, NIL);
  526. END;
  527. CheckPointerImage; (* maybe some other window got below the cursor *)
  528. m.sender:=w; m.msgType := Messages.MsgInvalidate; m.msgSubType := Messages.MsgSubAll;
  529. IF (w.sequencer#NIL) & w.sequencer.Add(m) THEN END; (* Invalidate window contents when first put on display. *)
  530. lock.ReleaseWrite;
  531. WM.IncWTimestamp;
  532. END Add;
  533. PROCEDURE InternalRemove(w : Window);
  534. VAR rect : Rect.Rectangle;
  535. BEGIN
  536. ASSERT(lock.HasWriteLock());
  537. IF w.prev # NIL THEN w.prev.next := w.next END;
  538. IF w.next # NIL THEN w.next.prev := w.prev END;
  539. w.prev := NIL; w.next := NIL; (* some application programmers tend to remove a window more than once *)
  540. IF (WM.FlagNavigation IN w.flags) & (w.view # NIL) & (w.view IS ViewPort) THEN
  541. rect := w.view(ViewPort).GetWMCoordinates(w.bounds);
  542. dirtyQ.Add(rect);
  543. ELSE
  544. dirtyQ.Add(w.bounds)
  545. END;
  546. END InternalRemove;
  547. PROCEDURE Remove*(w : Window);
  548. VAR dl : WM.DecorList; p : Window;
  549. BEGIN
  550. lock.AcquireWrite;
  551. p := GetPrev(w);
  552. InternalRemove(w);
  553. dl := w.decor; WHILE dl # NIL DO InternalRemove(dl.w); (* dl.w.manager := NIL; *) (* fof: caused a trap in MainMenu.Window.SetOriginator while switching the skin *) dl := dl.next END;
  554. w.decor := NIL;
  555. IF w.sequencer # NIL THEN w.sequencer.Stop END;
  556. (* w.manager := NIL; *) (* fof: caused a trap in MainMenu.Window.SetOriginator while switching skin *)
  557. w.next := NIL; w.prev := NIL;
  558. IF (w = focusOwner) & (p # NIL) THEN SetFocus(p) END;
  559. IF pointerKeys = {} THEN (* otherwise the pointerOwner must remain *)
  560. pointerOwner := GetPositionOwnerIntern(pointerX, pointerY, NIL);
  561. END;
  562. CheckPointerImage; (* maybe some other window got below the cursor *)
  563. lock.ReleaseWrite;
  564. WM.IncWTimestamp;
  565. END Remove;
  566. PROCEDURE ToFront*(x : Window);
  567. VAR dl : WM.DecorList;
  568. BEGIN
  569. IF x = bottom THEN RETURN END;
  570. IF x.flags * { WM.FlagStayOnBottom } # { } THEN RETURN END;
  571. lock.AcquireWrite;
  572. IF x.flags * { WM.FlagDecorWindow } # { } THEN IF x.master # NIL THEN ToFront(x.master) END
  573. ELSE
  574. InternalRemove(x);
  575. InsertAfter(FindTopWindow(WM.FlagStayOnTop IN x.flags), x); AddVisibleDirty(x, x.bounds);
  576. dl := x.decor; WHILE dl # NIL DO InternalRemove(dl.w); InsertAfter(x, dl.w); AddVisibleDirty(dl.w, dl.w.bounds); dl := dl.next END
  577. END;
  578. CheckPointerImage; (* maybe some other window got below the cursor *)
  579. lock.ReleaseWrite
  580. END ToFront;
  581. PROCEDURE ToBack*(x : Window);
  582. VAR dl : WM.DecorList; t : Window;
  583. BEGIN
  584. lock.AcquireWrite;
  585. IF x.flags * { WM.FlagDecorWindow } # { } THEN IF x.master # NIL THEN ToBack(x.master) END
  586. ELSE
  587. InternalRemove(x);
  588. IF (WM.FlagStayOnTop IN x.flags) THEN
  589. t := FindTopWindow(FALSE);
  590. ELSE
  591. t := FindBottomWindow(WM.FlagStayOnBottom IN x.flags);
  592. END;
  593. InsertAfter(t, x); AddVisibleDirty(x, x.bounds);
  594. dl := x.decor; WHILE dl # NIL DO InternalRemove(dl.w); InsertAfter(x, dl.w); AddVisibleDirty(dl.w, dl.w.bounds); dl := dl.next END
  595. END;
  596. CheckPointerImage; (* maybe some other window got below the cursor *)
  597. lock.ReleaseWrite
  598. END ToBack;
  599. PROCEDURE SetWindowFlag*(w : Window; flag : LONGINT; include : BOOLEAN);
  600. VAR flagChanged, isAdded : BOOLEAN;
  601. PROCEDURE SetFlagInternal(w : Window; flag : LONGINT; include : BOOLEAN);
  602. VAR dl : WM.DecorList;
  603. BEGIN
  604. IF include THEN INCL(w.flags, flag); ELSE EXCL(w.flags, flag); END;
  605. dl := w.decor;
  606. WHILE (dl # NIL) DO
  607. IF include THEN INCL(dl.w.flags, flag); ELSE EXCL(dl.w.flags, flag); END;
  608. dl := dl.next;
  609. END;
  610. END SetFlagInternal;
  611. PROCEDURE AddDecorWindows(w : Window);
  612. BEGIN
  613. IF (decorate # NIL) THEN
  614. decorate(w);
  615. pointerOwner := GetPositionOwnerIntern(pointerX, pointerY, NIL);
  616. CheckPointerImage; (* maybe some other window got below the cursor *)
  617. END;
  618. END AddDecorWindows;
  619. PROCEDURE RemoveDecorWindows(w : Window);
  620. VAR dl : WM.DecorList;
  621. BEGIN
  622. dl := w.decor;
  623. WHILE (dl # NIL) DO
  624. InternalRemove(dl.w);
  625. dl.w.manager := NIL; dl.w.master := NIL;
  626. dl := dl.next;
  627. END;
  628. w.decor := NIL;
  629. RefreshViews;
  630. END RemoveDecorWindows;
  631. BEGIN
  632. SetWindowFlag^(w, flag, include);
  633. lock.AcquireWrite;
  634. IF (WM.FlagDecorWindow IN w.flags) THEN
  635. w := w.master;
  636. IF (w = NIL) THEN lock.ReleaseWrite; RETURN; END;
  637. END;
  638. flagChanged := (include # (flag IN w.flags));
  639. IF flagChanged THEN
  640. isAdded := (w.next # NIL) & (w.prev # NIL);
  641. CASE flag OF
  642. |WM.FlagFrame:
  643. IF include THEN
  644. INCL(w.flags, flag);
  645. IF isAdded THEN AddDecorWindows(w); END;
  646. ELSE
  647. EXCL(w.flags, flag);
  648. IF isAdded THEN RemoveDecorWindows(w); END;
  649. END;
  650. |WM.FlagStayOnTop:
  651. IF include THEN
  652. EXCL(w.flags, WM.FlagStayOnBottom);
  653. SetFlagInternal(w, flag, TRUE);
  654. IF isAdded THEN ToFront(w); END;
  655. ELSE
  656. SetFlagInternal(w, flag, FALSE);
  657. IF isAdded THEN ToBack(w); END;
  658. END;
  659. |WM.FlagStayOnBottom:
  660. IF include THEN
  661. SetFlagInternal(w, WM.FlagStayOnTop, FALSE);
  662. INCL(w.flags, flag);
  663. IF isAdded THEN ToBack(w); END;
  664. ELSE
  665. EXCL(w.flags, flag);
  666. IF isAdded THEN ToFront(w); END;
  667. END;
  668. |WM.FlagHidden:
  669. IF include THEN INCL(w.flags, flag); ELSE EXCL(w.flags, flag); END;
  670. ELSE
  671. lock.ReleaseWrite; HALT(99);
  672. END;
  673. END;
  674. lock.ReleaseWrite;
  675. IF flagChanged THEN WM.IncOTimestamp; END;
  676. END SetWindowFlag;
  677. PROCEDURE SetWindowPos*(w : Window; x, y : LONGINT);
  678. VAR rect : Rectangle; dx, dy : LONGINT; cur : WM.DecorList;
  679. BEGIN
  680. IF w = NIL THEN RETURN END;
  681. lock.AcquireWrite;
  682. dx := x - w.bounds.l; dy := y - w.bounds.t;
  683. IF (w.master # NIL) THEN w := w.master END;
  684. rect := w.bounds; Rect.MoveRel(w.bounds, dx, dy); Rect.ExtendRect(rect, w.bounds);
  685. cur := w.decor;
  686. WHILE cur # NIL DO
  687. Rect.ExtendRect(rect, cur.w.bounds);Rect.MoveRel(cur.w.bounds, dx, dy); Rect.ExtendRect(rect, cur.w.bounds);
  688. cur := cur.next
  689. END;
  690. CheckPointerImage; (* maybe some other window got below the cursor *)
  691. AddVisibleDirty(w, rect); (* assuming decor windows USE alpha *)
  692. lock.ReleaseWrite;
  693. WM.ResetNextPosition;
  694. END SetWindowPos;
  695. PROCEDURE SetWindowSize*(w : Window; VAR width, height : LONGINT);
  696. VAR
  697. rect : Rectangle;
  698. cw, ch, t, nw : LONGINT;
  699. PROCEDURE Set(win : Window; w, h : LONGINT);
  700. BEGIN
  701. Rect.ExtendRect(rect, win.bounds);
  702. win.Resizing(w, h); win.bounds.r := win.bounds.l + w; win.bounds.b := win.bounds.t + h;
  703. Rect.ExtendRect(rect, win.bounds)
  704. END Set;
  705. BEGIN
  706. lock.AcquireWrite;
  707. rect := w.bounds;
  708. cw := w.GetWidth(); ch := w.GetHeight();
  709. w.Resizing(width, height);
  710. IF (cw # width) OR (ch # height) THEN
  711. w.bounds.r := w.bounds.l + width;
  712. w.bounds.b := w.bounds.t + height;
  713. IF cw # width THEN
  714. IF w.topW # NIL THEN
  715. nw := width + (w.topW.GetWidth() - cw);
  716. t := w.topW.GetHeight(); Set(w.topW, nw, t);
  717. END;
  718. IF w.bottomW # NIL THEN
  719. nw := width + (w.bottomW.GetWidth() - cw);
  720. t := w.bottomW.GetHeight(); Set(w.bottomW, nw, t)
  721. END;
  722. IF w.rightW # NIL THEN
  723. Rect.ExtendRect(rect, w.rightW.bounds);
  724. Rect.MoveRel(w.rightW.bounds, width - cw, 0);
  725. Rect.ExtendRect(rect, w.rightW.bounds)
  726. END
  727. END;
  728. IF ch # height THEN
  729. IF w.leftW # NIL THEN
  730. nw := height + (w.leftW.GetHeight() - ch);
  731. t := w.leftW.GetWidth(); Set(w.leftW, t, nw)
  732. END;
  733. IF w.rightW # NIL THEN
  734. nw := height + (w.rightW.GetHeight() - ch);
  735. t := w.rightW.GetWidth(); Set(w.rightW, t, nw)
  736. END;
  737. IF w.bottomW # NIL THEN
  738. Rect.ExtendRect(rect, w.bottomW.bounds);
  739. Rect.MoveRel(w.bottomW.bounds, 0, height - ch);
  740. Rect.ExtendRect(rect, w.bottomW.bounds)
  741. END
  742. END;
  743. Rect.ExtendRect(rect, w.bounds);
  744. IF (WM.FlagNavigation IN w.flags) & (w.view # NIL) & (w.view IS ViewPort) THEN
  745. rect := w.view(ViewPort).GetWMCoordinates(rect);
  746. END;
  747. dirtyQ.Add(rect);
  748. CheckPointerImage
  749. END;
  750. lock.ReleaseWrite
  751. END SetWindowSize;
  752. (** View management *)
  753. (** Add a view *)
  754. PROCEDURE AddView*(v : WM.ViewPort);
  755. VAR res : WORD;
  756. BEGIN
  757. lock.AcquireWrite;
  758. v.manager := SELF;
  759. v.next := views; views := v;
  760. lock.ReleaseWrite;
  761. viewRegistry.Add(v, res)
  762. END AddView;
  763. (** Add the whole View.range as dirty and cause a redraw *)
  764. PROCEDURE RefreshView*(v : WM.ViewPort);
  765. BEGIN
  766. lock.AcquireWrite;
  767. v.Refresh(top);
  768. lock.ReleaseWrite
  769. END RefreshView;
  770. (* Redraw all view ranges *)
  771. PROCEDURE RefreshViews;
  772. VAR v : WM.ViewPort;
  773. BEGIN
  774. lock.AcquireWrite;
  775. v := views;
  776. WHILE (v # NIL) DO v.Refresh(top); v := v.next; END;
  777. lock.ReleaseWrite;
  778. END RefreshViews;
  779. (** RemoveView from windowmanager *)
  780. PROCEDURE RemoveView*(v : WM.ViewPort);
  781. VAR cur : WM.ViewPort;
  782. BEGIN
  783. IF v = NIL THEN RETURN END;
  784. lock.AcquireWrite;
  785. IF v = views THEN views := views.next
  786. ELSE
  787. IF views # NIL THEN
  788. cur := views; WHILE (cur.next # NIL) & (cur.next # v) DO cur := cur.next END;
  789. IF cur.next = v THEN cur.next := cur.next.next END
  790. END
  791. END;
  792. viewRegistry.Remove(v);
  793. lock.ReleaseWrite
  794. END RemoveView;
  795. PROCEDURE ReplaceBackground*(w : Window) : Window;
  796. VAR old : Window;
  797. BEGIN
  798. lock.AcquireWrite;
  799. w.manager := SELF;
  800. old := bottom; bottom := w; bottom.next := old.next; bottom.next.prev := bottom;
  801. old.next := NIL;
  802. lock.ReleaseWrite;
  803. RETURN old
  804. END ReplaceBackground;
  805. (** Return the area that is actually occupied *)
  806. PROCEDURE GetPopulatedArea*(VAR r : Rectangle);
  807. VAR first: BOOLEAN; cur : Window;
  808. BEGIN
  809. lock.AcquireWrite;
  810. first := TRUE;
  811. cur := bottom.next;
  812. WHILE (cur # NIL) & (cur # top) DO
  813. IF first THEN r := cur.bounds; first := FALSE
  814. ELSE Rect.ExtendRect(r, cur.bounds)
  815. END;
  816. cur := cur.next
  817. END;
  818. lock.ReleaseWrite;
  819. END GetPopulatedArea;
  820. (** Enumeration *)
  821. (** Get the first "user" window --> May return NIL if only background and pointer window are installed *)
  822. (** Must hold lock *)
  823. PROCEDURE GetFirst*() : Window;
  824. VAR cur : Window;
  825. BEGIN
  826. ASSERT(lock.HasWriteLock());
  827. cur := bottom; WHILE (cur # NIL) & (cur.master # NIL) DO cur := cur.next END;
  828. RETURN cur
  829. END GetFirst;
  830. (** Get the window next "user" window on top of cur *)
  831. PROCEDURE GetNext*(cur : Window) : Window;
  832. BEGIN
  833. ASSERT(lock.HasWriteLock());
  834. IF cur # NIL THEN cur := cur.next END;
  835. WHILE (cur # NIL) & (cur.master # NIL) DO cur := cur.next END;
  836. RETURN cur
  837. END GetNext;
  838. (** Get the "user" window below cur *)
  839. PROCEDURE GetPrev*(cur : Window) : Window;
  840. BEGIN
  841. ASSERT(lock.HasWriteLock());
  842. IF cur # NIL THEN cur := cur.prev END;
  843. WHILE (cur # NIL) & (cur.master # NIL) DO cur := cur.prev END;
  844. RETURN cur
  845. END GetPrev;
  846. (** Set the keyboard focus to the window w *)
  847. PROCEDURE SetFocus*(w : Window);
  848. VAR dl : WM.DecorList;
  849. PROCEDURE SendFocusMessage(dst : Window; has : BOOLEAN);
  850. VAR m : Messages.Message;
  851. BEGIN
  852. m.msgType := Messages.MsgFocus;
  853. IF ~has THEN m.msgSubType := Messages.MsgSubFocusLost ELSE m.msgSubType := Messages.MsgSubFocusGot END;
  854. IF ~SendMessage(dst, m) THEN KernelLog.String("Focus message not sent"); KernelLog.Ln END;
  855. IF ~has THEN m.msgSubType := Messages.MsgSubMasterFocusLost
  856. ELSE m.msgSubType := Messages.MsgSubMasterFocusGot
  857. END;
  858. dl := dst.decor; WHILE dl # NIL DO IF SendMessage(dl.w, m) THEN (* ignore *) END; dl := dl.next END
  859. END SendFocusMessage;
  860. BEGIN
  861. lock.AcquireWrite;
  862. IF w = focusOwner THEN lock.ReleaseWrite; RETURN END;
  863. IF w.flags * { WM.FlagNoFocus } = { } THEN
  864. IF focusOwner # NIL THEN SendFocusMessage(focusOwner, FALSE) END;
  865. focusOwner := w;
  866. SendFocusMessage(focusOwner, TRUE)
  867. ELSE
  868. IF w.master # NIL THEN SetFocus(w.master) END
  869. END;
  870. lock.ReleaseWrite;
  871. WM.IncOTimestamp;
  872. END SetFocus;
  873. (** Return the window at postition x, y in global space. *)
  874. (** Must hold WM lock *)
  875. PROCEDURE GetPositionOwnerIntern(x, y : LONGINT; owner : WM.ViewPort) : Window;
  876. VAR cur : Window; xt, yt : LONGINT; bounds : Rect.Rectangle; ignore : BOOLEAN;
  877. BEGIN
  878. lock.AcquireWrite;
  879. cur := top.prev; (* not the mouse *)
  880. WHILE cur # NIL DO
  881. ignore := FALSE;
  882. IF (WM.FlagNavigation IN cur.flags) THEN
  883. IF (owner # NIL) & (owner IS ViewPort) & (cur.view = owner) THEN
  884. bounds := owner(ViewPort).GetWMCoordinates(cur.bounds);
  885. xt := ENTIER((x - owner(ViewPort).range.l) * owner(ViewPort).fx);
  886. yt := ENTIER((y - owner(ViewPort).range.t) * owner(ViewPort).fy);
  887. ELSE
  888. ignore := TRUE;
  889. END;
  890. ELSE
  891. bounds := cur.bounds;
  892. xt := x; yt := y;
  893. END;
  894. IF ~ignore & Rect.PointInRect(x, y, bounds) THEN
  895. IF cur.isVisible & cur.IsHit(xt - cur.bounds.l, yt - cur.bounds.t) THEN
  896. lock.ReleaseWrite;
  897. RETURN cur
  898. END
  899. END;
  900. cur := cur.prev
  901. END;
  902. lock.ReleaseWrite;
  903. RETURN NIL
  904. END GetPositionOwnerIntern;
  905. PROCEDURE GetPositionOwner*(x, y : LONGINT) : Window;
  906. BEGIN
  907. RETURN GetPositionOwnerIntern(x, y, NIL);
  908. END GetPositionOwner;
  909. (** Adjust pointer to new position / check picture *)
  910. (** MUST hold wm lock *)
  911. PROCEDURE CheckPointerImage*;
  912. VAR rect : Rectangle; pi : WM.PointerInfo;
  913. BEGIN
  914. lock.AcquireWrite;
  915. ASSERT(top # NIL);
  916. IF pointerOwner # NIL THEN
  917. IF WM.FlagNoPointer IN pointerOwner.flags THEN pi := pointerNull ELSE pi := pointerOwner.pointerInfo END;
  918. (*ELSIF WM.FlagNoPointer IN top.flags THEN pi := pointerNull; pointerInfo := pi; *)
  919. ELSE pi := NIL
  920. END;
  921. IF pi = NIL THEN pi := pointerStandard END; IF pointerInfo = NIL THEN pointerInfo := pointerStandard END;
  922. IF (pi # pointerInfo) OR ((pointerX # top.bounds.l - pointerInfo.hotX) OR (pointerY # top.bounds.t - pointerInfo.hotY)) THEN
  923. rect := top.bounds;
  924. IF (pi.img # NIL) & (top IS WM.BufferWindow) THEN
  925. top(WM.BufferWindow).img := pi.img;
  926. top.bounds.l := pointerX - pi.hotX;
  927. top.bounds.t := pointerY - pi.hotY;
  928. top.bounds.r := top.bounds.l + top(WM.BufferWindow).img.width;
  929. top.bounds.b := top.bounds.t + top(WM.BufferWindow).img.height
  930. ELSE
  931. top.bounds.l := pointerX;
  932. top.bounds.t := pointerY;
  933. top.bounds.r := top.bounds.l;
  934. top.bounds.b := top.bounds.t
  935. END;
  936. dirtyQ.Add(top.bounds);
  937. dirtyQ.Add(rect);
  938. (* the dirty q handling will merge the rectangles if beneficial. Doing it here results in potential large area screen updates *)
  939. pointerInfo := pi
  940. END;
  941. lock.ReleaseWrite
  942. END CheckPointerImage;
  943. PROCEDURE GetFocusOwner*() : Window;
  944. BEGIN
  945. RETURN focusOwner;
  946. END GetFocusOwner;
  947. PROCEDURE PointerEvent(VAR msg : Messages.Message);
  948. VAR
  949. newOwner : Window;
  950. view : ViewPort;
  951. kd, i : LONGINT;
  952. m : Messages.Message;
  953. keys : SET;
  954. PROCEDURE MouseMessage(sub:LONGINT);
  955. VAR bounds : Rect.Rectangle; vp : ViewPort;
  956. BEGIN
  957. (* do not translate to local coordinates here: must be done by sequencer! *)
  958. IF (pointerOwner # NIL) THEN
  959. m.msgType := Messages.MsgPointer;
  960. m.msgSubType := sub;
  961. IF (WM.FlagNavigation IN pointerOwner.flags) THEN
  962. IF (pointerOwner.view # NIL) & (pointerOwner.view IS ViewPort) THEN
  963. vp := pointerOwner.view (ViewPort);
  964. bounds := pointerOwner.bounds;
  965. m.x := ENTIER((msg.x - vp.range.l) * vp.fx);
  966. m.y := ENTIER((msg.y - vp.range.t) * vp.fy);
  967. END;
  968. ELSE
  969. bounds := pointerOwner.bounds;
  970. m.x := msg.x; m.y := msg.y;
  971. END;
  972. m.flags := keys;
  973. IF pointerOwner.sequencer # NIL THEN IF ~pointerOwner.sequencer.Add(m) THEN END (* ignore missed mouse messages *)
  974. ELSE pointerOwner.Handle(m)
  975. END
  976. END
  977. END MouseMessage;
  978. PROCEDURE DragMessage(sub : LONGINT; dst : Window);
  979. BEGIN
  980. IF (dst # NIL) THEN
  981. m.msgType := Messages.MsgDrag;
  982. m.msgSubType := sub;
  983. m.sender := dragSender;
  984. m.ext := dragInfo;
  985. m.x := msg.x - dst.bounds.l; m.y := msg.y - dst.bounds.t;
  986. IF dst.sequencer # NIL THEN IF ~dst.sequencer.Add(m) THEN END (* ignore missed drag messages *)
  987. END
  988. END
  989. END DragMessage;
  990. PROCEDURE DragAbortMessage;
  991. BEGIN
  992. IF (dragInfo # NIL) & (dragInfo.onReject # NIL) THEN dragInfo.onReject(SELF, dragInfo) END
  993. END DragAbortMessage;
  994. PROCEDURE RemoveDragCursor;
  995. BEGIN
  996. IF dragCursor # NIL THEN Remove(dragCursor) END;
  997. END RemoveDragCursor;
  998. BEGIN
  999. ASSERT(sequencer.IsCallFromSequencer());
  1000. IF ~running THEN RETURN END;
  1001. IF (msg.originator # NIL) & (msg.originator IS ViewPort) THEN
  1002. view := msg.originator (ViewPort);
  1003. ELSE
  1004. view := NIL;
  1005. END;
  1006. m.originator := sequencer.GetOriginator();
  1007. m := msg; keys := msg.flags;
  1008. IF dragging THEN
  1009. IF keys = {} THEN DragMessage(Messages.MsgDragDropped, GetPositionOwnerIntern(msg.x, msg.y, view)); dragging := FALSE
  1010. ELSIF keys * {0, 1, 2} = {0, 1, 2} THEN dragging := FALSE; (* abort drag *)
  1011. (* fixup key state *)
  1012. kd := 0; FOR i := 0 TO 31 DO IF i IN keys THEN INC(kd) END END;
  1013. kdprev := kd; pointerKeys := keys;
  1014. DragAbortMessage
  1015. ELSE DragMessage(Messages.MsgDragOver, GetPositionOwnerIntern(msg.x, msg.y, view))
  1016. END;
  1017. IF dragging THEN SetWindowPos(dragCursor, msg.x+dragInfo.offsetX, msg.y+dragInfo.offsetY)
  1018. ELSE RemoveDragCursor
  1019. END;
  1020. pointerX := msg.x; pointerY := msg.y; CheckPointerImage;
  1021. IF dragging THEN RETURN END
  1022. END;
  1023. (* if no keys are pressed, the new pointer owner is the position owner *)
  1024. IF (keys = { })THEN newOwner := GetPositionOwnerIntern(msg.x, msg.y, view)END;
  1025. IF newOwner = NIL THEN newOwner := pointerOwner END;
  1026. (* keys changed *)
  1027. IF keys # pointerKeys THEN
  1028. kd := 0; FOR i := 0 TO 31 DO IF i IN keys THEN INC(kd) END END;
  1029. (* the number of pressed keys is less --> one is up *)
  1030. IF kd < kdprev THEN MouseMessage(Messages.MsgSubPointerUp)
  1031. ELSE SetFocus(newOwner); MouseMessage(Messages.MsgSubPointerDown); (* no check --> keys did change *)
  1032. END;
  1033. kdprev := kd; pointerKeys := keys
  1034. END;
  1035. IF newOwner # pointerOwner THEN MouseMessage(Messages.MsgSubPointerLeave); pointerOwner := newOwner END;
  1036. pointerX := msg.x; pointerY := msg.y;
  1037. IF pointerOwner # NIL THEN CheckPointerImage; MouseMessage(Messages.MsgSubPointerMove) END
  1038. END PointerEvent;
  1039. PROCEDURE KeyEvent*(VAR m : Messages.Message);
  1040. VAR p : Window;
  1041. BEGIN
  1042. ASSERT(sequencer.IsCallFromSequencer());
  1043. IF ~running THEN RETURN END;
  1044. IF (focusOwner # NIL) THEN
  1045. IF (m.flags * Inputs.Alt # {}) & (m.y = 0FF09H) THEN
  1046. p := GetPrev(focusOwner);
  1047. IF p # NIL THEN ToFront(p); SetFocus(p) END
  1048. ELSE
  1049. IF focusOwner.sequencer # NIL THEN IF ~focusOwner.sequencer.Add(m) THEN END (* ignore keyboard message *)
  1050. ELSE focusOwner.Handle(m)
  1051. END
  1052. END
  1053. END
  1054. END KeyEvent;
  1055. PROCEDURE HandleInternal*(VAR msg : Messages.Message);
  1056. BEGIN
  1057. HandleInternal^(msg);
  1058. IF msg.msgType = Messages.MsgKey THEN KeyEvent(msg)
  1059. ELSIF msg.msgType = Messages.MsgPointer THEN PointerEvent(msg)
  1060. END
  1061. END HandleInternal;
  1062. PROCEDURE StartDrag*(w : Window; sender, data : ANY; img : Graphics.Image; offsetX, offsetY: LONGINT; onAccept, onReject : Messages.CompCommand) : BOOLEAN;
  1063. VAR result : BOOLEAN;
  1064. PROCEDURE AddDragCursor;
  1065. VAR w, h : LONGINT;
  1066. BEGIN
  1067. NEW(dragCursor, 1, 1, TRUE); w := 1; h := 1;
  1068. IF dragImage # NIL THEN
  1069. dragCursor.img := dragImage; w:= dragImage.width; h := dragImage.height
  1070. END;
  1071. Add(pointerX+offsetX, pointerY+offsetY, dragCursor, { WM.FlagStayOnTop, WM.FlagNonDispatched, WM.FlagHidden });
  1072. SetWindowSize(dragCursor, w, h)
  1073. END AddDragCursor;
  1074. BEGIN
  1075. result := FALSE;
  1076. lock.AcquireWrite;
  1077. IF (w = pointerOwner) & ~dragging THEN
  1078. result := TRUE;
  1079. dragging := TRUE;
  1080. dragImage := img; dragSender := w;
  1081. NEW(dragInfo);
  1082. dragInfo.sender := sender; dragInfo.data := data;
  1083. dragInfo.onAccept := onAccept; dragInfo.onReject := onReject;
  1084. dragInfo.offsetX := offsetX; dragInfo.offsetY := offsetY;
  1085. AddDragCursor
  1086. END;
  1087. lock.ReleaseWrite;
  1088. RETURN result
  1089. END StartDrag;
  1090. (** a pointer button must be pressed *)
  1091. PROCEDURE TransferPointer*(to : Window) : BOOLEAN;
  1092. VAR ok : BOOLEAN;
  1093. BEGIN
  1094. lock.AcquireWrite;
  1095. ok := FALSE;
  1096. IF pointerKeys # {} THEN
  1097. ok := TRUE;
  1098. pointerOwner := to; CheckPointerImage;
  1099. END;
  1100. lock.ReleaseWrite;
  1101. RETURN ok
  1102. END TransferPointer;
  1103. (** Add a region to be refreshed *)
  1104. PROCEDURE AddDirty*(VAR rect:Rectangle);
  1105. BEGIN
  1106. dirtyQ.Add(rect)
  1107. END AddDirty;
  1108. (** Add a region to be refreshed, if visible through windows w and above *)
  1109. PROCEDURE AddVisibleDirty*(w : Window; rect : Rectangle);
  1110. VAR temp : Rect.Rectangle;
  1111. (* Subtract hidden regions --> i.e. pass on non hidden parts *)
  1112. PROCEDURE Sub(x : Window; VAR r : Rectangle);
  1113. VAR nr : Rectangle; bounds : Rect.Rectangle;
  1114. BEGIN
  1115. IF Rect.RectEmpty(r) THEN RETURN END;
  1116. IF (x = NIL) OR (x = top) THEN
  1117. (* there is nothing in front of this rectangle part --> must draw *)
  1118. dirtyQ.Add(r);
  1119. RETURN
  1120. END;
  1121. IF ~x.useAlpha & x.isVisible THEN
  1122. IF (WM.FlagNavigation IN x.flags) & (x.view # NIL) & (x.view IS ViewPort) THEN
  1123. bounds := w.view(ViewPort).GetWMCoordinates(x.bounds);
  1124. ELSE
  1125. bounds := x.bounds;
  1126. END;
  1127. IF Rect.IsContained(bounds, r) THEN
  1128. (* the remaining rect is completely covered by non alpha window *)
  1129. RETURN
  1130. ELSIF Rect.Intersect(bounds, r) THEN (* the rectangle intersects with the window x in front *)
  1131. (* calculate top rectangle *)
  1132. IF bounds.t > r.t THEN Rect.SetRect(nr, r.l, r.t, r.r, bounds.t); Sub(x.next, nr) END;
  1133. (* calculate bottom rectangle *)
  1134. IF bounds.b < r.b THEN Rect.SetRect(nr, r.l, bounds.b, r.r, r.b);Sub(x.next, nr) END;
  1135. (* calculate left rectangle *)
  1136. IF bounds.l > r.l THEN Rect.SetRect(nr, r.l, MAX(r.t, bounds.t), bounds.l, MIN(r.b, bounds.b)); Sub(x.next, nr) END;
  1137. (* calculate right rectangle *)
  1138. IF bounds.r < r.r THEN Rect.SetRect(nr, bounds.r, MAX(r.t, bounds.t), r.r, MIN(r.b, bounds.b)); Sub(x.next, nr) END
  1139. ELSE (* the window x is not in front *)
  1140. Sub(x.next, r)
  1141. END
  1142. ELSE (* the window x uses alpha *)
  1143. Sub(x.next, r)
  1144. END
  1145. END Sub;
  1146. BEGIN
  1147. lock.AcquireWrite;
  1148. IF (WM.FlagNavigation IN w.flags) THEN
  1149. IF (w.view # NIL) & (w.view IS ViewPort) THEN
  1150. temp := w.view(ViewPort).GetWMCoordinates(rect);
  1151. END;
  1152. ELSE
  1153. temp := rect;
  1154. END;
  1155. Sub(w.next, temp);
  1156. lock.ReleaseWrite
  1157. END AddVisibleDirty;
  1158. PROCEDURE RedrawDirty;
  1159. VAR r, m:Rectangle;
  1160. i, na, oa, nofPatches:LONGINT;
  1161. found : BOOLEAN; cv : WM.ViewPort;
  1162. BEGIN
  1163. dirtyQ.Get(patches[0]);
  1164. nofPatches := 1;
  1165. lock.AcquireWrite;
  1166. WHILE dirtyQ.Has() DO
  1167. dirtyQ.Get(r);
  1168. na := Rect.Area(r);
  1169. found := FALSE;
  1170. i := 0; WHILE (i < nofPatches) & ~found DO
  1171. m := patches[i]; oa := Rect.Area(m);
  1172. Rect.ExtendRect(m, r);
  1173. IF Rect.Area(m) <= 2 * (oa+na) THEN
  1174. patches[i] := m; found := TRUE
  1175. END;
  1176. INC(i)
  1177. END;
  1178. IF ~found THEN patches[nofPatches] := r; INC(nofPatches) END;
  1179. IF nofPatches = CombineLookahead THEN
  1180. (* update Viewports *)
  1181. cv := views;
  1182. WHILE cv # NIL DO
  1183. FOR i := 0 TO nofPatches - 1 DO cv.Update(patches[i], top) END;
  1184. cv := cv.next
  1185. END;
  1186. nofPatches := 0
  1187. END;
  1188. END;
  1189. (* update Viewports *)
  1190. cv := views;
  1191. WHILE cv # NIL DO
  1192. FOR i := 0 TO nofPatches - 1 DO
  1193. cv.Update(patches[i], top); (* tester.DrawRect(patches[i], 0FF10H); *)
  1194. END;
  1195. cv := cv.next
  1196. END;
  1197. lock.ReleaseWrite
  1198. END RedrawDirty;
  1199. PROCEDURE DefaultDecorator(w : Window);
  1200. VAR
  1201. top : DW.TopWindow;
  1202. left : DW.LeftWindow;
  1203. right : DW.RightWindow;
  1204. bottom : DW.BottomWindow;
  1205. l, t, r, b : LONGINT;
  1206. th, lw, rw, bh : LONGINT;
  1207. PROCEDURE InitW(n : Window);
  1208. BEGIN
  1209. n.manager := SELF; n.flags := n.flags + {WM.FlagNoFocus, WM.FlagHidden};
  1210. IF WM.FlagStayOnTop IN w.flags THEN INCL(n.flags, WM.FlagStayOnTop) END;
  1211. IF WM.FlagStayOnBottom IN w.flags THEN INCL(n.flags, WM.FlagStayOnBottom); END;
  1212. IF WM.FlagNavigation IN w.flags THEN
  1213. n.view := w.view;
  1214. INCL(n.flags, WM.FlagNavigation);
  1215. END;
  1216. IF WM.FlagNoResizing IN w.flags THEN INCL(n.flags, WM.FlagNoResizing); END;
  1217. InsertAfter(w, n); AddDecorWindow(w, n);
  1218. AddVisibleDirty(n, n.bounds);
  1219. n.StyleChanged
  1220. END InitW;
  1221. BEGIN
  1222. ASSERT(lock.HasWriteLock());
  1223. NEW(top, 0, 0, FALSE);NEW(left, 0, 0, FALSE); NEW(right, 0, 0, FALSE); NEW(bottom, 0, 0, FALSE);
  1224. th := 10; lw := 2; rw := 2; bh := 2;
  1225. l := w.bounds.l; t := w.bounds.t; r := w.bounds.r; b := w.bounds.b;
  1226. top.useBitmaps := FALSE; left.useBitmaps := FALSE;
  1227. right.useBitmaps := FALSE; bottom.useBitmaps := FALSE;
  1228. (* Top *)
  1229. top.bounds := Rect.MakeRect(l - lw, t - th, r + rw, t);
  1230. top.mode := 0; top.distXY := XYResizeHandleSize;
  1231. top.SetPointerInfo(pointerMove); top.vertical := FALSE;
  1232. top.threshold := 110; top.focusthreshold := 200;
  1233. (* Left *)
  1234. left.bounds := Rect.MakeRect(l - lw, t, l, b);
  1235. left.mode := 3; left.distXY := XYResizeHandleSize; left.vertical := TRUE;
  1236. left.threshold := 110; left.focusthreshold := 200;
  1237. (* Right *)
  1238. right.bounds := Rect.MakeRect(r + 1, t, r + 1 + rw, b);
  1239. right.mode := 1; right.distXY := XYResizeHandleSize; right.vertical := TRUE;
  1240. right.threshold := 110; right.focusthreshold := 200;
  1241. (* Bottom *)
  1242. bottom.bounds := Rect.MakeRect(l - lw, b + 1, r + rw, b + 1 + bh);
  1243. bottom.mode := 2; bottom.distXY := lw + XYResizeHandleSize; bottom.vertical := FALSE;
  1244. bottom.threshold := 110; bottom.focusthreshold := 200;
  1245. (* Init decor windows *)
  1246. InitW(top); w.topW := top; top.useAlpha := TRUE;
  1247. InitW(left); w.leftW := left; left.useAlpha := TRUE;
  1248. InitW(right); w.rightW := right; right.useAlpha := TRUE;
  1249. InitW(bottom); w.bottomW := bottom; bottom.useAlpha := TRUE;
  1250. END DefaultDecorator;
  1251. PROCEDURE Touch;
  1252. BEGIN
  1253. lock.AcquireWrite;
  1254. fifi.Reset;
  1255. lock.ReleaseWrite
  1256. END Touch;
  1257. BEGIN {ACTIVE, SAFE}
  1258. IF running THEN KernelLog.String("WindowManager: RESTARTED"); lock.Reset; CheckChain(FALSE) END;
  1259. running := TRUE;
  1260. WHILE running DO RedrawDirty END;
  1261. KernelLog.String("WindowManager: Window manager closed"); KernelLog.Ln;
  1262. END WindowManager;
  1263. VAR
  1264. DoubleClick: LONGINT;
  1265. TYPE
  1266. MouseObj = OBJECT (Inputs.Sink)
  1267. VAR
  1268. view : ViewPort;
  1269. x, y, z : LONGINT;
  1270. threshold, speedup: LONGINT;
  1271. enableMMEmulation : BOOLEAN;
  1272. (* double click support *)
  1273. lastTime, lastX, lastY: LONGINT;
  1274. prevKeys: SET; inDoubleClick: BOOLEAN;
  1275. (*CONST
  1276. DoubleClick = 400 (* ms *);*)
  1277. PROCEDURE &Init*(t, s:LONGINT);
  1278. BEGIN
  1279. Inputs.mouse.Register(SELF);
  1280. threshold := t; speedup := s;
  1281. enableMMEmulation := TRUE;
  1282. prevKeys := {};
  1283. lastTime := Kernel.GetTicks()-DoubleClick;
  1284. inDoubleClick := FALSE;
  1285. END Init;
  1286. PROCEDURE Handle*(VAR msg: Inputs.Message);
  1287. VAR dx, dy, dz, nx, ny, nz: LONGINT; modifierFlags : SET; time: LONGINT;
  1288. BEGIN {EXCLUSIVE}
  1289. IF (msg IS Inputs.MouseMsg) THEN
  1290. WITH msg: Inputs.MouseMsg DO
  1291. dx := msg.dx; dy := msg.dy;
  1292. IF (ABS(dx) > threshold) OR (ABS(dy) > threshold) THEN
  1293. dx := dx*speedup DIV 10; dy := dy*speedup DIV 10
  1294. END;
  1295. INC(x, dx); INC(y, dy); INC(z, msg.dz);
  1296. IF view = NIL THEN RETURN END;
  1297. IF 1 IN msg.keys THEN enableMMEmulation := FALSE END;
  1298. IF enableMMEmulation & (0 IN msg.keys) THEN
  1299. view.GetKeyState(modifierFlags);
  1300. IF (Inputs.Ctrl * modifierFlags # {}) THEN msg.keys := msg.keys - {0} + {1}; END;
  1301. END;
  1302. Bound(x, 0, view.backbuffer.width - 1); Bound(y, 0, view.backbuffer.height - 1);
  1303. view.PointerEvent(x, y, z, msg.dx, msg.dy, msg.dz, msg.keys)
  1304. END
  1305. ELSIF (msg IS Inputs.AbsMouseMsg) THEN
  1306. WITH msg: Inputs.AbsMouseMsg DO
  1307. IF Displays.reverse THEN
  1308. nx := view.display.width-msg.x-1;
  1309. ny := view.display.height-msg.y-1;
  1310. dx := -msg.dx;
  1311. dy := -msg.dy;
  1312. ELSE
  1313. nx := msg.x;
  1314. ny := msg.y;
  1315. dx := msg.dx;
  1316. dy := msg.dy;
  1317. END;
  1318. nz := msg.z; dz := msg.dz;
  1319. IF (DoubleClick > 0) & (msg.keys = {0}) & (prevKeys = {}) THEN
  1320. time := Kernel.GetTicks();
  1321. IF (time - lastTime < DoubleClick) & (ABS(nx-lastX) < 3) & (ABS(ny-lastY) <3) THEN
  1322. msg.keys := {1}; lastTime := time-DoubleClick;
  1323. inDoubleClick := TRUE;
  1324. ELSE
  1325. lastTime := time; lastX := nx; lastY := ny;
  1326. END;
  1327. ELSIF inDoubleClick & (msg.keys = {0}) THEN
  1328. msg.keys := {1};
  1329. (* no change after double click -- avoid sending a click event right after a double click event *)
  1330. ELSE
  1331. inDoubleClick := FALSE;
  1332. END;
  1333. prevKeys := msg.keys ;
  1334. IF dx # 0 THEN INC( x, dx );
  1335. ELSE dx := nx-x; x:= nx;
  1336. END;
  1337. IF dy # 0 THEN INC( y, dy );
  1338. ELSE dy := ny - y; y := ny;
  1339. END;
  1340. IF dz # 0 THEN INC( z, dz );
  1341. (*ELSE dz := nz - z; z := nz;*)
  1342. END;
  1343. IF (ABS( dx ) > threshold) OR (ABS( dy ) > threshold) THEN dx := dx * speedup DIV 10; dy := dy * speedup DIV 10
  1344. END;
  1345. IF 1 IN msg.keys THEN enableMMEmulation := FALSE END;
  1346. IF view = NIL THEN RETURN END;
  1347. IF enableMMEmulation & (0 IN msg.keys) THEN
  1348. view.GetKeyState(modifierFlags);
  1349. IF (Inputs.Ctrl * modifierFlags # {}) THEN msg.keys := msg.keys - {0} + {1}; END;
  1350. END;
  1351. Bound( x, 0, view.backbuffer.width - 1 ); Bound( y, 0, view.backbuffer.height - 1 );
  1352. view.PointerEvent( x, y, z, dx, dy, dz, msg.keys )
  1353. END;
  1354. END;
  1355. END Handle;
  1356. END MouseObj;
  1357. (** The keyboard handler *)
  1358. KeyboardObj = OBJECT (Inputs.Sink)
  1359. VAR
  1360. view : ViewPort; ch : LONGINT;
  1361. PROCEDURE Handle*(VAR msg: Inputs.Message);
  1362. BEGIN {EXCLUSIVE}
  1363. IF view = NIL THEN RETURN END;
  1364. ch := ORD(msg(Inputs.KeyboardMsg).ch);
  1365. IF (ch >= 128) &(ch <= 155) THEN MapChars(ch) END;
  1366. view.KeyEvent(ch, msg(Inputs.KeyboardMsg).flags, msg(Inputs.KeyboardMsg).keysym)
  1367. END Handle;
  1368. PROCEDURE MapChars(VAR ch : LONGINT);
  1369. BEGIN
  1370. ch := CharToUnicode[ch];
  1371. END MapChars;
  1372. PROCEDURE &Init*;
  1373. BEGIN
  1374. Inputs.keyboard.Register(SELF)
  1375. END Init;
  1376. END KeyboardObj;
  1377. Toucher = OBJECT
  1378. VAR
  1379. timer: Kernel.Timer;
  1380. alive : BOOLEAN;
  1381. BEGIN {ACTIVE}
  1382. alive := TRUE;
  1383. NEW(timer);
  1384. WHILE alive DO
  1385. timer.Sleep(500);
  1386. session.Touch;
  1387. END
  1388. END Toucher;
  1389. Fifi = OBJECT
  1390. VAR
  1391. timer: Kernel.Timer; delay: LONGINT; time: Kernel.MilliTimer; alive, done: BOOLEAN;
  1392. PROCEDURE Cleanup;
  1393. BEGIN {EXCLUSIVE}
  1394. alive := FALSE;
  1395. timer.Wakeup;
  1396. AWAIT(done)
  1397. END Cleanup;
  1398. PROCEDURE Done;
  1399. BEGIN {EXCLUSIVE}
  1400. done := TRUE
  1401. END Done;
  1402. PROCEDURE Reset;
  1403. BEGIN
  1404. Kernel.SetTimer(time, delay)
  1405. END Reset;
  1406. PROCEDURE &Init*(delay: LONGINT);
  1407. BEGIN
  1408. SELF.delay := delay;
  1409. alive := TRUE; done := FALSE;
  1410. NEW(timer)
  1411. END Init;
  1412. BEGIN {ACTIVE}
  1413. LOOP
  1414. timer.Sleep(delay);
  1415. IF ~alive THEN EXIT END;
  1416. IF Kernel.Expired(time) THEN
  1417. KernelLog.String("Fifi --> "); KernelLog.Ln;
  1418. (* session.DumpLock;*) session.CheckChain(FALSE);
  1419. alive := FALSE
  1420. END
  1421. END;
  1422. Done
  1423. END Fifi;
  1424. VAR
  1425. session : WindowManager;
  1426. toucher :Toucher;
  1427. defaultKeyboard : KeyboardObj;
  1428. defaultMouse : MouseObj;
  1429. CharToUnicode: ARRAY 256 OF LONGINT; (** mapping from Oberon character codes to Unicodes **)
  1430. PROCEDURE Bound(VAR x:LONGINT; min, max:LONGINT);
  1431. BEGIN
  1432. IF x < min THEN x := min ELSE IF x > max THEN x := max END END
  1433. END Bound;
  1434. PROCEDURE ClipAtImage(VAR x: Rectangle; img:Raster.Image);
  1435. BEGIN
  1436. Bound(x.l, 0, img.width); Bound(x.r, 0, img.width);
  1437. Bound(x.t, 0, img.height); Bound(x.b, 0, img.height)
  1438. END ClipAtImage;
  1439. PROCEDURE FillSession(wm : WindowManager; bgColor: LONGINT; noPointer: BOOLEAN);
  1440. VAR bg : DW.BackWindow; t : Window;
  1441. BEGIN
  1442. NEW(bg, bgColor);
  1443. bg.flags := {WM.FlagHidden};
  1444. IF noPointer THEN
  1445. INCL(bg.flags, WM.FlagNoPointer);
  1446. END;
  1447. wm.SetWindowTitle(bg, WM.NewString("New background"));
  1448. Rect.SetRect(bg.bounds, MIN(LONGINT), MIN(LONGINT), MAX(LONGINT), MAX(LONGINT));
  1449. wm.lock.AcquireWrite; t := wm.ReplaceBackground(bg); wm.lock.ReleaseWrite;
  1450. END FillSession;
  1451. PROCEDURE Replace*(color: LONGINT; noPointer: BOOLEAN);
  1452. VAR disp : Plugins.Plugin; view : ViewPort; r : Rectangle; res : WORD;
  1453. BEGIN
  1454. disp := Displays.registry.Await("");
  1455. IF (disp(Displays.Display).format = Displays.color8888) THEN
  1456. WM.format := Raster.BGRA8888;
  1457. KernelLog.String("WindowManager: 32-bit color"); KernelLog.Ln;
  1458. ELSIF disp(Displays.Display).format = Displays.color888 THEN
  1459. WM.format := Raster.BGR888;
  1460. KernelLog.String("WindowManager: 24-bit color"); KernelLog.Ln;
  1461. ELSE
  1462. WM.format := Raster.BGR565;
  1463. KernelLog.String("WindowManager: 16-bit color"); KernelLog.Ln;
  1464. END;
  1465. NEW (session); NEW(toucher);
  1466. NEW(view, disp(Displays.Display));
  1467. session.lock.AcquireWrite; session.AddView(view); session.lock.ReleaseWrite;
  1468. FillSession(session, color, noPointer);
  1469. IF (view.width0 > 0) & (view.height0 > 0) THEN
  1470. r := Rect.MakeRect(0, 0, view.width0, view.height0);
  1471. ELSE
  1472. r := Rect.MakeRect(0, 0, 1600, 1200);
  1473. END;
  1474. session.AddDirty(r);
  1475. WM.registry.Add(session, res);
  1476. NEW(defaultMouse, 5, 15); defaultMouse.view := view;
  1477. NEW(defaultKeyboard); defaultKeyboard.view := view;
  1478. END Replace;
  1479. PROCEDURE InitCharMaps;
  1480. VAR i: LONGINT;
  1481. BEGIN
  1482. FOR i := 0 TO 127 DO CharToUnicode[i] := i END;
  1483. CharToUnicode[128] := 0C4H;
  1484. CharToUnicode[129] := 0D6H;
  1485. CharToUnicode[130] := 0DCH;
  1486. CharToUnicode[131] := 0E4H;
  1487. CharToUnicode[132] := 0F6H;
  1488. CharToUnicode[133] := 0FCH;
  1489. CharToUnicode[134] := 0E2H;
  1490. CharToUnicode[135] := 0EAH;
  1491. CharToUnicode[136] := 0EEH;
  1492. CharToUnicode[137] := 0F4H;
  1493. CharToUnicode[138] := 0FBH;
  1494. CharToUnicode[139] := 0E0H;
  1495. CharToUnicode[140] := 0E8H;
  1496. CharToUnicode[141] := 0ECH;
  1497. CharToUnicode[142] := 0F2H;
  1498. CharToUnicode[143] := 0F9H;
  1499. CharToUnicode[144] := 0E9H;
  1500. CharToUnicode[145] := 0EBH;
  1501. CharToUnicode[146] := 0EFH;
  1502. CharToUnicode[147] := 0E7H;
  1503. CharToUnicode[148] := 0E1H;
  1504. CharToUnicode[149] := 0F1H;
  1505. CharToUnicode[150] := 0DFH;
  1506. CharToUnicode[151] := 0A3H;
  1507. CharToUnicode[152] := 0B6H;
  1508. CharToUnicode[153] := 0C7H;
  1509. CharToUnicode[154] := 2030H;
  1510. CharToUnicode[155] := 2013H;
  1511. FOR i := 156 TO 255 DO CharToUnicode[i] := i END
  1512. END InitCharMaps;
  1513. PROCEDURE CleanUp;
  1514. BEGIN
  1515. IF session # NIL THEN
  1516. IF toucher # NIL THEN toucher.alive := FALSE; toucher.timer.Wakeup END;
  1517. session.ShutDown;
  1518. END
  1519. END CleanUp;
  1520. PROCEDURE Install*(context: Commands.Context);
  1521. VAR options: Options.Options; color: LONGINT; noPointer: BOOLEAN;
  1522. CONST DefaultColor = LONGINT(8080FFFFH);
  1523. BEGIN
  1524. NEW(options);
  1525. options.Add("c","bgColor",Options.Integer);
  1526. options.Add("n","noMouseCursor",Options.Flag);
  1527. IF options.Parse(context.arg, context.error) THEN
  1528. IF ~options.GetInteger("bgColor", color) THEN color := DefaultColor END;
  1529. noPointer := options.GetFlag("noMouseCursor");
  1530. ELSE noPointer := FALSE; color := DefaultColor
  1531. END;
  1532. Replace(color, noPointer);
  1533. END Install;
  1534. PROCEDURE TraceChain*;
  1535. BEGIN
  1536. session.CheckChain(TRUE);
  1537. END TraceChain;
  1538. PROCEDURE SetDoubleClick*(context: Commands.Context);
  1539. VAR options: Options.Options; speed: LONGINT;
  1540. BEGIN
  1541. NEW(options);
  1542. options.Add("s","speed",Options.Integer);
  1543. IF options.Parse(context.arg, context.error) THEN
  1544. IF options.GetInteger("speed", speed) THEN
  1545. DoubleClick := speed
  1546. END;
  1547. END;
  1548. END SetDoubleClick;
  1549. BEGIN
  1550. WMFontManager.Install;
  1551. InitCharMaps;
  1552. Modules.InstallTermHandler(CleanUp);
  1553. DoubleClick := 500;
  1554. END WindowManager.