WMMessages.Mod 18 KB

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