WindowManager.Mod 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719
  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 : LONGINT;
  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 := Graphics.MakeRectangle(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 := Graphics.MakeRectangle(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 := Graphics.MakeRectangle(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 := Graphics.MakeRectangle(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 Min(a, b:LONGINT):LONGINT;
  1431. BEGIN
  1432. IF a < b THEN RETURN a ELSE RETURN b END;
  1433. END Min;
  1434. PROCEDURE Max(a, b:LONGINT):LONGINT;
  1435. BEGIN
  1436. IF a > b THEN RETURN a ELSE RETURN b END;
  1437. END Max;
  1438. PROCEDURE Bound(VAR x:LONGINT; min, max:LONGINT);
  1439. BEGIN
  1440. IF x < min THEN x := min ELSE IF x > max THEN x := max END END
  1441. END Bound;
  1442. PROCEDURE ClipAtImage(VAR x: Rectangle; img:Raster.Image);
  1443. BEGIN
  1444. Bound(x.l, 0, img.width); Bound(x.r, 0, img.width);
  1445. Bound(x.t, 0, img.height); Bound(x.b, 0, img.height)
  1446. END ClipAtImage;
  1447. PROCEDURE FillSession(wm : WindowManager; bgColor: LONGINT; noPointer: BOOLEAN);
  1448. VAR bg : DW.BackWindow; t : Window;
  1449. BEGIN
  1450. NEW(bg, bgColor);
  1451. bg.flags := {WM.FlagHidden};
  1452. IF noPointer THEN
  1453. INCL(bg.flags, WM.FlagNoPointer);
  1454. END;
  1455. wm.SetWindowTitle(bg, WM.NewString("New background"));
  1456. Rect.SetRect(bg.bounds, MIN(LONGINT), MIN(LONGINT), MAX(LONGINT), MAX(LONGINT));
  1457. wm.lock.AcquireWrite; t := wm.ReplaceBackground(bg); wm.lock.ReleaseWrite;
  1458. END FillSession;
  1459. PROCEDURE Replace*(color: LONGINT; noPointer: BOOLEAN);
  1460. VAR disp : Plugins.Plugin; view : ViewPort; r : Rectangle; res : LONGINT;
  1461. BEGIN
  1462. disp := Displays.registry.Await("");
  1463. IF (disp(Displays.Display).format = Displays.color8888) THEN
  1464. WM.format := Raster.BGRA8888;
  1465. KernelLog.String("WindowManager: 32-bit color"); KernelLog.Ln;
  1466. ELSIF disp(Displays.Display).format = Displays.color888 THEN
  1467. WM.format := Raster.BGR888;
  1468. KernelLog.String("WindowManager: 24-bit color"); KernelLog.Ln;
  1469. ELSE
  1470. WM.format := Raster.BGR565;
  1471. KernelLog.String("WindowManager: 16-bit color"); KernelLog.Ln;
  1472. END;
  1473. NEW (session); NEW(toucher);
  1474. NEW(view, disp(Displays.Display));
  1475. session.lock.AcquireWrite; session.AddView(view); session.lock.ReleaseWrite;
  1476. FillSession(session, color, noPointer);
  1477. IF (view.width0 > 0) & (view.height0 > 0) THEN
  1478. r := Graphics.MakeRectangle(0, 0, view.width0, view.height0);
  1479. ELSE
  1480. r := Graphics.MakeRectangle(0, 0, 1600, 1200);
  1481. END;
  1482. session.AddDirty(r);
  1483. WM.registry.Add(session, res);
  1484. NEW(defaultMouse, 5, 15); defaultMouse.view := view;
  1485. NEW(defaultKeyboard); defaultKeyboard.view := view;
  1486. END Replace;
  1487. PROCEDURE InitCharMaps;
  1488. VAR i: LONGINT;
  1489. BEGIN
  1490. FOR i := 0 TO 127 DO CharToUnicode[i] := i END;
  1491. CharToUnicode[128] := 0C4H;
  1492. CharToUnicode[129] := 0D6H;
  1493. CharToUnicode[130] := 0DCH;
  1494. CharToUnicode[131] := 0E4H;
  1495. CharToUnicode[132] := 0F6H;
  1496. CharToUnicode[133] := 0FCH;
  1497. CharToUnicode[134] := 0E2H;
  1498. CharToUnicode[135] := 0EAH;
  1499. CharToUnicode[136] := 0EEH;
  1500. CharToUnicode[137] := 0F4H;
  1501. CharToUnicode[138] := 0FBH;
  1502. CharToUnicode[139] := 0E0H;
  1503. CharToUnicode[140] := 0E8H;
  1504. CharToUnicode[141] := 0ECH;
  1505. CharToUnicode[142] := 0F2H;
  1506. CharToUnicode[143] := 0F9H;
  1507. CharToUnicode[144] := 0E9H;
  1508. CharToUnicode[145] := 0EBH;
  1509. CharToUnicode[146] := 0EFH;
  1510. CharToUnicode[147] := 0E7H;
  1511. CharToUnicode[148] := 0E1H;
  1512. CharToUnicode[149] := 0F1H;
  1513. CharToUnicode[150] := 0DFH;
  1514. CharToUnicode[151] := 0A3H;
  1515. CharToUnicode[152] := 0B6H;
  1516. CharToUnicode[153] := 0C7H;
  1517. CharToUnicode[154] := 2030H;
  1518. CharToUnicode[155] := 2013H;
  1519. FOR i := 156 TO 255 DO CharToUnicode[i] := i END
  1520. END InitCharMaps;
  1521. PROCEDURE CleanUp;
  1522. BEGIN
  1523. IF session # NIL THEN
  1524. IF toucher # NIL THEN toucher.alive := FALSE; toucher.timer.Wakeup END;
  1525. session.ShutDown;
  1526. END
  1527. END CleanUp;
  1528. PROCEDURE Install*(context: Commands.Context);
  1529. VAR options: Options.Options; color: LONGINT; noPointer: BOOLEAN;
  1530. CONST DefaultColor = LONGINT(8080FFFFH);
  1531. BEGIN
  1532. NEW(options);
  1533. options.Add("c","bgColor",Options.Integer);
  1534. options.Add("n","noMouseCursor",Options.Flag);
  1535. IF options.Parse(context.arg, context.error) THEN
  1536. IF ~options.GetInteger("bgColor", color) THEN color := DefaultColor END;
  1537. noPointer := options.GetFlag("noMouseCursor");
  1538. ELSE noPointer := FALSE; color := DefaultColor
  1539. END;
  1540. Replace(color, noPointer);
  1541. END Install;
  1542. PROCEDURE TraceChain*;
  1543. BEGIN
  1544. session.CheckChain(TRUE);
  1545. END TraceChain;
  1546. PROCEDURE SetDoubleClick*(context: Commands.Context);
  1547. VAR options: Options.Options; speed: LONGINT;
  1548. BEGIN
  1549. NEW(options);
  1550. options.Add("s","speed",Options.Integer);
  1551. IF options.Parse(context.arg, context.error) THEN
  1552. IF options.GetInteger("speed", speed) THEN
  1553. DoubleClick := speed
  1554. END;
  1555. END;
  1556. END SetDoubleClick;
  1557. BEGIN
  1558. WMFontManager.Install;
  1559. InitCharMaps;
  1560. Modules.InstallTermHandler(CleanUp);
  1561. DoubleClick := 500;
  1562. END WindowManager.