WMMessages.Mod 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. MODULE WMMessages; (** AUTHOR "TF"; PURPOSE "Support for messages and events"; *)
  2. IMPORT
  3. Strings, KernelLog, Objects, Kernel, Locks, Modules, Reflection, SYSTEM;
  4. CONST
  5. InitialMsgQSize = 64;
  6. MaxMsgQSize = 32*1024; (* this is too huge anyway *)
  7. (** Predefined Messages *)
  8. MsgPointer* = 0; MsgKey* = 2; MsgClose* = 3; MsgStyleChanged* = 4;
  9. MsgFocus* = 5; MsgExt* = 6; MsgDrag* = 7;
  10. MsgInvokeEvent* = 8;
  11. MsgResized* = 9;
  12. MsgSetLanguage* = 10;
  13. MsgInvalidate*= 11;
  14. MsgSerialize*=12;
  15. MsgSubPointerMove* = 0; MsgSubPointerDown* = 1; MsgSubPointerUp* = 2; MsgSubPointerLeave* = 3;
  16. MsgSubFocusGot* = 0; MsgSubFocusLost* = 1; MsgSubMasterFocusGot* = 2; MsgSubMasterFocusLost* = 3;
  17. MsgSubAll*=0; MsgSubRectangle*=1; MsgSubNothing*=2; (* regions: all or rectangle as defined by x, y, dx, dy *)
  18. MsgDragOver* = 0; MsgDragDropped* = 1;
  19. (** Gather statistics about added/discarded messages? *)
  20. Statistics* = FALSE;
  21. TraceQueue = FALSE;
  22. TraceOverflows = TRUE;
  23. MsgTypeMax* = 13;
  24. TYPE
  25. (** Generic Component Command *)
  26. CompCommand* = PROCEDURE { DELEGATE } (sender, par : ANY);
  27. String* = Strings.String;
  28. (** Generic message structure *)
  29. Message* = RECORD
  30. originator*, (** the originator if # NIL passes information about the view that directly or indirectely lead to the msg *)
  31. sender* : ANY; (** is the sender component. If the message is originated form a component *)
  32. token* : AsyncToken;
  33. event* : CompCommand;
  34. msgType*, msgSubType* : LONGINT; (** generic message type *)
  35. x*, y*, z*, dx*, dy*, dz* : LONGINT; (** in keyboard messages : ucs value in x, keysym in y *)
  36. flags* : SET; (** in pointer messages : keys in flags *)
  37. ext* : ANY; (** extended message *)
  38. END;
  39. MessageExtension* = POINTER TO RECORD END;
  40. (** AsyncToken can be used to synchronize asynchronous method invocation *)
  41. AsyncToken* = OBJECT
  42. VAR
  43. ready : BOOLEAN;
  44. result* : ANY;
  45. (** Reset is called in case the token was recycled *)
  46. PROCEDURE Reset*;
  47. BEGIN {EXCLUSIVE}
  48. ready := FALSE;
  49. END Reset;
  50. (** wait until the result is completed *)
  51. PROCEDURE AwaitCompletion*;
  52. BEGIN {EXCLUSIVE}
  53. AWAIT(ready)
  54. END AwaitCompletion;
  55. (** Return if the result is completed *)
  56. PROCEDURE IsCompleted*():BOOLEAN;
  57. BEGIN {EXCLUSIVE}
  58. RETURN ready
  59. END IsCompleted;
  60. (** Called by the asynchronous process to indicate the result is available *)
  61. PROCEDURE Completed*;
  62. BEGIN {EXCLUSIVE}
  63. ready := TRUE
  64. END Completed;
  65. END AsyncToken;
  66. (** Message handler that can be called from the sequencer *)
  67. MessageHandler* = PROCEDURE {DELEGATE} (VAR msg : Message);
  68. (** The TrapHandler must return TRUE if the process should restart. Otherwise the process is stopped *)
  69. TrapHandler* = PROCEDURE {DELEGATE} () : BOOLEAN;
  70. (** Message sequencer *)
  71. MsgSequencer* = OBJECT
  72. VAR
  73. head, num : LONGINT;
  74. msgQ : POINTER TO ARRAY (* MsgQSize*) OF Message;
  75. alive, continue, hadOverflow , waiting, stopped: BOOLEAN;
  76. msg : Message;
  77. handler : MessageHandler;
  78. originator : ANY;
  79. me : ANY; (* Thread for caller identification *)
  80. lock- : Locks.RWLock;
  81. th, traphandler : TrapHandler;
  82. name* : String;
  83. trapOnOverflow* : BOOLEAN;
  84. overflows: LONGINT;
  85. PROCEDURE &New*(handler : MessageHandler);
  86. BEGIN
  87. SELF.handler := handler;
  88. NEW(lock);
  89. head := 0; num := 0;
  90. originator := NIL; me := NIL; th := NIL; traphandler := NIL;
  91. name := NIL;
  92. alive := FALSE; continue := TRUE; hadOverflow := FALSE; trapOnOverflow := FALSE;
  93. waiting := FALSE; stopped := FALSE;
  94. NEW(msgQ, InitialMsgQSize);
  95. END New;
  96. (** Add a trap handler for this process. This handler only decides whether to continue or to abort the process.
  97. If continued, the lock will be reset *)
  98. PROCEDURE SetTrapHandler*(th : TrapHandler);
  99. BEGIN {EXCLUSIVE}
  100. traphandler := th
  101. END SetTrapHandler;
  102. (** Return true if called from (this) sequencer *)
  103. PROCEDURE IsCallFromSequencer*() : BOOLEAN;
  104. BEGIN
  105. RETURN Objects.ActiveObject() = me
  106. END IsCallFromSequencer;
  107. (** RETURN the originator (view) of the message that lead directly or indirectly to this request.
  108. Returns NIL if the call is not from the sequencer *)
  109. PROCEDURE GetOriginator*() : ANY;
  110. BEGIN
  111. IF Objects.ActiveObject() = me THEN RETURN originator
  112. ELSE RETURN NIL
  113. END
  114. END GetOriginator;
  115. PROCEDURE Grow;
  116. VAR new: POINTER TO ARRAY (* MsgQSize*) OF Message; i: LONGINT; name: ARRAY 128 OF CHAR; VAR pc: ADDRESS;
  117. type: Modules.TypeDesc; msg: Message;
  118. BEGIN
  119. NEW(new, LEN(msgQ) * 3 DIV 2);
  120. IF stopped THEN TRACE("!!!!!!!!!!!!!", stopped) END;
  121. FOR i := 0 TO LEN(msgQ)-1 DO
  122. new[i] := msgQ[(head+i) MOD LEN(msgQ)];
  123. IF TraceOverflows OR stopped THEN
  124. msg := new[i];
  125. IF msg.msgType < LEN(MsgName) THEN COPY(MsgName[msg.msgType], name) ELSE name := "" END;
  126. TRACE(i,"***************", name);
  127. TRACE(i, msg.msgType, msg.msgSubType);
  128. TRACE(msg.x, msg.y, msg.dx, msg.dy, msg.flags);
  129. IF msg.sender # NIL THEN
  130. type := Modules.TypeOf(msg.sender);
  131. IF (type # NIL) THEN
  132. COPY(type.mod.name, name); Strings.Append(name, "."); Strings.Append(name, type.name);
  133. TRACE(msg.sender, name);
  134. ELSE
  135. TRACE(msg.sender);
  136. END;
  137. END;
  138. IF msg.msgType = MsgInvokeEvent THEN
  139. Reflection.GetProcedureName(SYSTEM.VAL(ADDRESS, msg.event), name, pc );
  140. TRACE("Event procedure ", name);
  141. END;
  142. IF msg.ext # NIL THEN
  143. type := Modules.TypeOf(msg.ext);
  144. IF (type # NIL) THEN
  145. COPY(type.mod.name, name); Strings.Append(name, "."); Strings.Append(name, type.name);
  146. TRACE(msg.ext, name);
  147. ELSE
  148. TRACE(msg.ext);
  149. END;
  150. END;
  151. END;
  152. END;
  153. msgQ := new; head := 0;
  154. KernelLog.String("MessageQ increased: "); KernelLog.Int(LEN(msgQ),1); KernelLog.Ln;
  155. END Grow;
  156. (** Add a message to a queue. Discards the message if the queue is full *)
  157. PROCEDURE Add*(VAR msg : Message): BOOLEAN;
  158. VAR i, pos: LONGINT; name: ARRAY 256 OF CHAR; pc: ADDRESS;
  159. module: Modules.Module; type: Modules.TypeDesc;
  160. CONST
  161. MergePointers = TRUE;
  162. MergeInvalidates = TRUE;
  163. MergeInvokeEvents = TRUE;
  164. PROCEDURE Merge(VAR x,y,dx,dy: LONGINT; X,Y,dX,dY: LONGINT);
  165. VAR nx, ny, ndx, ndy: LONGINT;
  166. BEGIN
  167. nx := MIN(x,X);
  168. ny := MIN(y,Y);
  169. ndx := MAX(x+dx, X+dX) - nx;
  170. ndy := MAX(y+dy, Y+dY) - ny;
  171. x := nx;
  172. y := ny;
  173. dx := ndx;
  174. dy := ndy;
  175. END Merge;
  176. BEGIN {EXCLUSIVE}
  177. IF debug = SELF THEN
  178. KernelLog.String("<----");
  179. IF msg.msgType < LEN(MsgName) THEN COPY(MsgName[msg.msgType], name) ELSE name := "" END;
  180. TRACE("WMMessages.MsgSequencer.Add", name);
  181. TRACE(i, msg.msgType, msg.msgSubType);
  182. TRACE(msg.x, msg.y, msg.dx, msg.dy);
  183. IF msg.sender # NIL THEN
  184. type := Modules.TypeOf(msg.sender);
  185. IF (type # NIL) THEN
  186. COPY(type.mod.name, name); Strings.Append(name, "."); Strings.Append(name, type.name);
  187. TRACE(msg.sender, name);
  188. ELSE
  189. TRACE(msg.sender);
  190. END;
  191. END;
  192. IF msg.msgType = MsgInvokeEvent THEN
  193. Reflection.GetProcedureName(SYSTEM.VAL(ADDRESS, msg.event), name, pc );
  194. TRACE("Event procedure ", name);
  195. END;
  196. IF msg.ext # NIL THEN
  197. type := Modules.TypeOf(msg.ext);
  198. IF (type # NIL) THEN
  199. COPY(type.mod.name, name); Strings.Append(name, "."); Strings.Append(name, type.name);
  200. TRACE(msg.ext, name);
  201. ELSE
  202. TRACE(msg.ext);
  203. END;
  204. END;
  205. END;
  206. IF MergePointers & (msg.msgType = MsgPointer) & (msg.msgSubType = MsgSubPointerMove) & (num > 0) THEN (* reduce pointer moves in buffer *)
  207. i := num - 1;
  208. WHILE i >= 0 DO
  209. pos := (head + i) MOD LEN(msgQ);
  210. IF (msgQ[pos].msgType = MsgPointer) & (msgQ[pos].msgSubType = MsgSubPointerMove) & (msgQ[pos].flags = msg.flags) THEN
  211. msgQ[pos].x := msg.x;
  212. msgQ[pos].y := msg.y;
  213. msgQ[pos].z := msg.z;
  214. RETURN TRUE
  215. END;
  216. DEC(i)
  217. END
  218. END;
  219. (* PH *)
  220. IF MergeInvokeEvents & (msg.msgType = MsgInvokeEvent) & (msg.msgSubType = 0) & (num > 0) THEN
  221. i := num - 1;
  222. WHILE i >= 0 DO
  223. pos := (head + i) MOD LEN(msgQ);
  224. IF (msgQ[pos].msgType = MsgInvokeEvent) & (msgQ[pos].msgSubType = 0) & (msgQ[pos].event = msg.event)& (msgQ[pos].sender = msg.sender) & (msgQ[pos].ext = msg.ext) THEN
  225. RETURN TRUE
  226. END;
  227. DEC(i)
  228. END
  229. END;
  230. (* /PH*)
  231. IF MergeInvalidates & (msg.msgType = MsgInvalidate) & (num > 0) THEN
  232. i := num-1;
  233. pos := (head + i) MOD LEN(msgQ);
  234. IF (msgQ[pos].sender = msg.sender) & (msgQ[pos].msgType = MsgInvalidate) & (msgQ[pos].msgSubType = msg.msgSubType) THEN
  235. IF msg.msgSubType= MsgSubRectangle THEN
  236. IF Contained(msgQ[pos], msg) THEN
  237. IF TraceQueue OR (debug = SELF) THEN
  238. TRACE("container first ", msg.x, msg.dx, msg.y, msg.dy);
  239. TRACE(msgQ[pos].x, msgQ[pos].dx, msgQ[pos].y, msgQ[pos].dy);
  240. KernelLog.Ln;
  241. END;
  242. (* replace *)
  243. msgQ[pos].x := msg.x; msgQ[pos].y := msg.y; msgQ[pos].dx := msg.dx; msgQ[pos].dy := msg.dy;
  244. RETURN TRUE;
  245. ELSIF Contained(msg, msgQ[pos]) THEN
  246. IF TraceQueue OR (debug = SELF) THEN
  247. TRACE("contained first ", msg.x, msg.dx, msg.y, msg.dy);
  248. TRACE(msgQ[pos].x, msgQ[pos].dx, msgQ[pos].y, msgQ[pos].dy);
  249. KernelLog.Ln;
  250. END;
  251. (* keep *)
  252. RETURN TRUE;
  253. ELSE (* we assume that invaidates on the same component
  254. that immediately follow each other are very close to each other
  255. If this turns out to be untrue, we could add a heuristics here *)
  256. Merge(msgQ[pos].x, msgQ[pos].y, msgQ[pos].dx, msgQ[pos].dy, msg.x, msg.y, msg.dx, msg.dy);
  257. (* keep *)
  258. RETURN TRUE;
  259. END;
  260. ELSIF msg.msgSubType = MsgSubAll THEN
  261. (* keep *)
  262. IF TraceQueue OR (debug = SELF) THEN
  263. TRACE("keep first");
  264. KernelLog.Ln;
  265. END;
  266. RETURN TRUE;
  267. END;
  268. END;
  269. DEC(i);
  270. WHILE i >= 0 DO
  271. pos := (head + i) MOD LEN(msgQ);
  272. IF (msgQ[pos].sender = msg.sender) & (msgQ[pos].msgType = MsgInvalidate) & (msgQ[pos].msgSubType = msg.msgSubType) THEN
  273. IF msg.msgSubType= MsgSubRectangle THEN
  274. IF Contained(msgQ[pos], msg) THEN
  275. IF TraceQueue OR (debug = SELF) THEN
  276. TRACE("container ", pos);
  277. TRACE( msg.x, msg.dx, msg.y, msg.dy);
  278. TRACE(msgQ[pos].x, msgQ[pos].dx, msgQ[pos].y, msgQ[pos].dy);
  279. END;
  280. msgQ[pos].msgSubType := MsgSubNothing;
  281. i := 0;
  282. ELSIF Contained(msg, msgQ[pos]) THEN
  283. IF TraceQueue OR (debug = SELF) THEN
  284. TRACE("contained ", pos);
  285. TRACE(msg.x, msg.dx, msg.y, msg.dy);
  286. TRACE(msgQ[pos].x, msgQ[pos].dx, msgQ[pos].y, msgQ[pos].dy);
  287. END;
  288. msg.x := msgQ[pos].x; msg.y := msgQ[pos].y; msg.dx := msgQ[pos].dx; msg.dy := msgQ[pos].dy;
  289. msgQ[pos].msgSubType := MsgSubNothing;
  290. i := 0;
  291. (*ELSE
  292. Merge(msg.x, msg.y, msg.dx, msg.dy, msgQ[pos].x, msgQ[pos].y, msgQ[pos].dx, msgQ[pos].dy);
  293. msgQ[pos].msgSubType := MsgSubNothing;
  294. *)
  295. END;
  296. ELSIF msgQ[pos].msgSubType = MsgSubAll THEN
  297. IF TraceQueue OR (debug = SELF) THEN
  298. TRACE("replace ", pos);
  299. END;
  300. msgQ[pos].msgSubType := MsgSubNothing;
  301. i := 0;
  302. END;
  303. END;
  304. DEC(i);
  305. END;
  306. END;
  307. IF num >= MaxMsgQSize THEN RETURN FALSE END;
  308. IF num >= LEN(msgQ) THEN
  309. Grow
  310. END;
  311. IF Statistics THEN
  312. INC(messagesAdded);
  313. IF (msg.msgType >= 0) & (msg.msgType < MsgTypeMax) THEN
  314. INC(messagesAddedByType[msg.msgType]);
  315. END;
  316. END;
  317. msgQ[(head + num) MOD LEN(msgQ)] := msg; INC(num);
  318. overflows := 0;
  319. IF debug = SELF THEN
  320. KernelLog.Ln;
  321. END;
  322. RETURN TRUE;
  323. END Add;
  324. PROCEDURE Handle(VAR msg : Message) : BOOLEAN;
  325. BEGIN
  326. (* if asynchronous call --> synchronize *)
  327. IF ~IsCallFromSequencer() THEN
  328. IF Add(msg) THEN RETURN TRUE END;
  329. ELSE
  330. (*
  331. IF debug = SELF THEN
  332. D.Enter;
  333. D.Ln;
  334. D.String("-- WMMessages.MsgSequencer.Handle --"); D.Ln;
  335. D.String("msg type "); D.Int(msg.msgType,1); D.Ln;
  336. D.String("time "); D.Int(Kernel.GetTicks(),1);D.Ln;
  337. D.Exit;
  338. END;
  339. *)
  340. IF msg.msgType = MsgInvokeEvent THEN (* MsgInvokeEvent *)
  341. IF msg.event # NIL THEN
  342. msg.event(msg.sender, msg.ext);
  343. IF msg.token # NIL THEN msg.token.Completed END
  344. END
  345. ELSE handler(msg) (* Generic message *)
  346. END;
  347. (* clear references *)
  348. msg.originator := NIL;
  349. msg.sender := NIL;
  350. msg.ext := NIL;
  351. originator := NIL;
  352. RETURN TRUE
  353. END;
  354. RETURN FALSE
  355. END Handle;
  356. (* put event into message queue *)
  357. PROCEDURE ScheduleEvent*(event : CompCommand; sender, par : ANY);
  358. VAR invokeMsg : Message;
  359. BEGIN
  360. invokeMsg.msgType := MsgInvokeEvent;
  361. invokeMsg.sender := sender; invokeMsg.ext := par;
  362. invokeMsg.event := event;
  363. IF ~Handle(invokeMsg) THEN END
  364. END ScheduleEvent;
  365. (** Stop the message sequencer. Must be called if the queue is no longer needed *)
  366. PROCEDURE Stop*;
  367. BEGIN {EXCLUSIVE}
  368. alive := FALSE; stopped := TRUE;
  369. END Stop;
  370. PROCEDURE WaitFree*;
  371. BEGIN {EXCLUSIVE}
  372. AWAIT (waiting & (num=0) OR ~alive)
  373. END WaitFree;
  374. (* Remove a message from the queue. Block if no message is available but awake if queue is terminated by call to Stop *)
  375. (* return if alive *)
  376. PROCEDURE Get(VAR msg : Message) : BOOLEAN;
  377. VAR i, pos: LONGINT; name: ARRAY 256 OF CHAR; pc: ADDRESS;
  378. module: Modules.Module; type: Modules.TypeDesc;
  379. BEGIN {EXCLUSIVE}
  380. IF hadOverflow THEN KernelLog.String(" - Recovered"); hadOverflow := FALSE END;
  381. waiting := TRUE;
  382. AWAIT((num # 0) OR ~alive);
  383. waiting := FALSE;
  384. IF ~alive THEN RETURN FALSE END;
  385. msg := msgQ[head];
  386. (* clear references from the queue *)
  387. msgQ[head].originator := NIL;
  388. msgQ[head].sender := NIL;
  389. msgQ[head].ext := NIL;
  390. head := (head + 1) MOD LEN(msgQ);
  391. DEC(num);
  392. originator := msg.originator;
  393. IF debug = SELF THEN
  394. KernelLog.String("---->");
  395. IF msg.msgType < LEN(MsgName) THEN COPY(MsgName[msg.msgType], name) ELSE name := "" END;
  396. TRACE("WMMessages.MsgSequencer.Get", name);
  397. TRACE(i, msg.msgType, msg.msgSubType);
  398. TRACE(msg.x, msg.y, msg.dx, msg.dy);
  399. IF msg.sender # NIL THEN
  400. type := Modules.TypeOf(msg.sender);
  401. IF (type # NIL) THEN
  402. COPY(type.mod.name, name); Strings.Append(name, "."); Strings.Append(name, type.name);
  403. TRACE(msg.sender, name);
  404. ELSE
  405. TRACE(msg.sender);
  406. END;
  407. END;
  408. IF msg.msgType = MsgInvokeEvent THEN
  409. Reflection.GetProcedureName(SYSTEM.VAL(ADDRESS, msg.event), name, pc );
  410. TRACE("Event procedure ", name);
  411. END;
  412. IF msg.ext # NIL THEN
  413. type := Modules.TypeOf(msg.ext);
  414. IF (type # NIL) THEN
  415. COPY(type.mod.name, name); Strings.Append(name, "."); Strings.Append(name, type.name);
  416. TRACE(msg.ext, name);
  417. ELSE
  418. TRACE(msg.ext);
  419. END;
  420. END;
  421. KernelLog.Ln;
  422. END;
  423. RETURN TRUE
  424. END Get;
  425. BEGIN {ACTIVE, SAFE}
  426. (* trap occured *)
  427. IF alive THEN
  428. th := traphandler; KernelLog.String("WMMessages: [TRAP]"); KernelLog.Ln;
  429. IF th # NIL THEN continue := th() ELSE continue := FALSE END;
  430. IF continue THEN lock.Reset ELSE RETURN END;
  431. END;
  432. alive := TRUE; me := Objects.ActiveObject();
  433. (* Message processing loop *)
  434. WHILE Get(msg) DO
  435. lock.AcquireWrite;
  436. (* Check alive again for the case that the sequencer has been stopped just after Get(msg) returned
  437. but before the lock could be acquired (WMComponents.FormWindow holds that lock when calling Sequencer.Stop) *)
  438. IF alive THEN
  439. IF ~Handle(msg) THEN KernelLog.String("WMMessages: A msg was not handled... "); KernelLog.Ln; END;
  440. END;
  441. lock.ReleaseWrite
  442. END
  443. END MsgSequencer;
  444. VAR
  445. tokenCache : Kernel.FinalizedCollection;
  446. ttoken : AsyncToken;
  447. (* Statistics *)
  448. messagesAddedByType- : ARRAY MsgTypeMax OF LONGINT;
  449. messagesAdded- : LONGINT;
  450. messagesDiscarded- : LONGINT;
  451. debug*: ANY;
  452. MsgName: ARRAY 32 OF ARRAY 32 OF CHAR;
  453. PROCEDURE TokenEnumerator(obj: ANY; VAR cont: BOOLEAN);
  454. BEGIN
  455. cont := FALSE; ttoken := obj(AsyncToken)
  456. END TokenEnumerator;
  457. (** Get an AsyncToken from the pool. Create a new one if the pool is empty *)
  458. PROCEDURE GetAsyncToken*() : AsyncToken;
  459. BEGIN {EXCLUSIVE}
  460. ttoken := NIL;
  461. tokenCache.Enumerate(TokenEnumerator);
  462. IF ttoken = NIL THEN NEW(ttoken)
  463. ELSE tokenCache.Remove(ttoken)
  464. END;
  465. ttoken.Reset;
  466. RETURN ttoken
  467. END GetAsyncToken;
  468. (** Recycle an AsyncToken. Must be unused. (is only used to disburden the garbage collector) *)
  469. PROCEDURE RecycleAsyncToken*(t : AsyncToken);
  470. BEGIN
  471. (* only recycle the token if the result is complete *)
  472. IF t.IsCompleted() THEN tokenCache.Add(t, NIL) END;
  473. END RecycleAsyncToken;
  474. PROCEDURE Contained(CONST this, container: Message): BOOLEAN;
  475. BEGIN
  476. RETURN (container.x <= this.x) & (container.dx >= this.dx) & (container.y <= this.y) & (container.dy >= this.dy)
  477. END Contained;
  478. BEGIN
  479. NEW(tokenCache);
  480. MsgName[MsgPointer] := "MsgPointer";
  481. MsgName[MsgKey] := "MsgKey";
  482. MsgName[MsgClose] := "MsgClose";
  483. MsgName[MsgStyleChanged] := "MsgStyleChanged";
  484. MsgName[MsgFocus] := "MsgFocus";
  485. MsgName[MsgExt] := "MsgExt";
  486. MsgName[MsgDrag] := "MsgDrag";
  487. MsgName[MsgInvokeEvent] := "MsgInvokeEvent";
  488. MsgName[MsgResized] := "MsgResized" ;
  489. MsgName[MsgSetLanguage] := "MsgSetLanguage";
  490. MsgName[MsgInvalidate] := "MsgInvalidate";
  491. MsgName[MsgSerialize] := "MsgSerialize";
  492. END WMMessages.