WMSearchTool.Mod 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. (* Aos, Copyright 2005, U. Glavitsch, ETH Zurich *)
  2. MODULE WMSearchTool; (** AUTHOR "ug"; PURPOSE "Search tool for text files"; *)
  3. IMPORT Files, Modules, WMGraphics, WMSystemComponents, WMComponents, WMStandardComponents,
  4. WMWindowManager, WMEditors, WMRectangles, WMMessages, WMRestorable, Strings, Inputs;
  5. CONST
  6. RListSize = 1000;
  7. TYPE
  8. KillerMsg = OBJECT
  9. END KillerMsg;
  10. Editor = OBJECT (WMEditors.Editor)
  11. VAR
  12. nextFocus, prevFocus: WMComponents.VisualComponent;
  13. withShift: BOOLEAN;
  14. PROCEDURE FocusNext;
  15. BEGIN
  16. IF withShift THEN
  17. FocusPrev;
  18. ELSE
  19. IF nextFocus # NIL THEN
  20. nextFocus.SetFocus;
  21. IF (nextFocus IS WMEditors.Editor) THEN
  22. WITH nextFocus: WMEditors.Editor DO
  23. (* unset any possible own selection *)
  24. SELF.tv.selection.SetFromTo(0, 0);
  25. (* select all text in the next field *)
  26. nextFocus.tv.SelectAll();
  27. END;
  28. END;
  29. END;
  30. END;
  31. END FocusNext;
  32. PROCEDURE FocusPrev;
  33. BEGIN
  34. IF prevFocus # NIL THEN
  35. prevFocus.SetFocus;
  36. IF (prevFocus IS WMEditors.Editor) THEN
  37. WITH prevFocus: WMEditors.Editor DO
  38. (* unset any possible own selection *)
  39. SELF.tv.selection.SetFromTo(0, 0);
  40. (* select all text in the next field *)
  41. prevFocus.tv.SelectAll();
  42. END;
  43. END;
  44. END;
  45. END FocusPrev;
  46. PROCEDURE KeyPressed(ucs : LONGINT; flags : SET; VAR keySym : LONGINT; VAR handled : BOOLEAN);
  47. BEGIN
  48. IF (flags # {}) & (flags - Inputs.Shift = {}) THEN
  49. withShift := TRUE;
  50. ELSE
  51. withShift := FALSE;
  52. END;
  53. IF (keySym = Inputs.KsTab) & (flags - Inputs.Shift = {}) THEN (* SHIFT-Tab or Tab *)
  54. keySym := 0FF0DH; (* CR *)
  55. END;
  56. KeyPressed^(ucs, flags, keySym, handled);
  57. END KeyPressed;
  58. (* Chain the next editor together for the focus with this editor *)
  59. PROCEDURE SetDoubleLinkedNextFocus(next: Editor);
  60. BEGIN
  61. SELF.nextFocus := next;
  62. next.prevFocus := SELF;
  63. END SetDoubleLinkedNextFocus;
  64. END Editor;
  65. Window = OBJECT(WMComponents.FormWindow)
  66. VAR
  67. status : WMStandardComponents.Panel;
  68. statusLabel : WMStandardComponents.Label;
  69. pathEdit, fmaskEdit, contentEdit : Editor;
  70. searchBtn, stopBtn : WMStandardComponents.Button;
  71. filelist : WMSystemComponents.FileList;
  72. lb : ListBuffer;
  73. s : Searcher;
  74. d : GridDisplayer;
  75. PROCEDURE &New*(c : WMRestorable.Context);
  76. VAR vc : WMComponents.VisualComponent;
  77. BEGIN
  78. IncCount;
  79. vc := CreateForm();
  80. Init(vc.bounds.GetWidth(), vc.bounds.GetHeight(), FALSE);
  81. SetContent(vc);
  82. SetTitle(Strings.NewString("Search Tool"));
  83. SetIcon(WMGraphics.LoadImage("WMIcons.tar://WMSearchTool.png", TRUE));
  84. pathEdit.tv.SelectAll();
  85. pathEdit.SetFocus();
  86. form.Invalidate();
  87. IF c # NIL THEN
  88. (* restore the desktop *)
  89. WMRestorable.AddByContext(SELF, c);
  90. ELSE
  91. WMWindowManager.DefaultAddWindow(SELF);
  92. END;
  93. NEW(lb);
  94. NEW(s, lb);
  95. NEW(d, lb, filelist.DisplayGrid, SearchStartHandler, SearchDoneHandler)
  96. END New;
  97. PROCEDURE Close;
  98. BEGIN
  99. Close^;
  100. DecCount
  101. END Close;
  102. PROCEDURE CreateForm(): WMComponents.VisualComponent;
  103. VAR panel : WMStandardComponents.Panel;
  104. toolbarPath, toolbarFMask, toolbar, toolbarSearch : WMStandardComponents.Panel;
  105. pathLabel, fmaskLabel, contentLabel : WMStandardComponents.Label;
  106. filledPathString : ARRAY 1024 OF CHAR;
  107. BEGIN
  108. NEW(panel); panel.bounds.SetExtents(700, 500); panel.fillColor.Set(LONGINT(0FFFFFFFFH)); panel.takesFocus.Set(TRUE);
  109. NEW(toolbarPath); toolbarPath.fillColor.Set(LONGINT(0FFFFFFFFH)); toolbarPath.bounds.SetHeight(25);
  110. toolbarPath.alignment.Set(WMComponents.AlignTop);
  111. panel.AddContent(toolbarPath);
  112. NEW(toolbarFMask); toolbarFMask.fillColor.Set(LONGINT(0FFFFFFFFH)); toolbarFMask.bounds.SetHeight(25);
  113. toolbarFMask.alignment.Set(WMComponents.AlignTop);
  114. panel.AddContent(toolbarFMask);
  115. NEW(toolbar); toolbar.fillColor.Set(LONGINT(0FFFFFFFFH)); toolbar.bounds.SetHeight(25);
  116. toolbar.alignment.Set(WMComponents.AlignTop);
  117. panel.AddContent(toolbar);
  118. NEW(toolbarSearch); toolbarSearch.fillColor.Set(LONGINT(0FFFFFFFFH)); toolbarSearch.bounds.SetHeight(20);
  119. toolbarSearch.alignment.Set(WMComponents.AlignTop);
  120. panel.AddContent(toolbarSearch);
  121. NEW(pathLabel); pathLabel.alignment.Set(WMComponents.AlignLeft);
  122. pathLabel.bounds.SetWidth(70); pathLabel.fillColor.Set(LONGINT(0FFFFFFFFH));
  123. pathLabel.SetCaption(" Path:");
  124. toolbarPath.AddContent(pathLabel);
  125. FillFirstMountedFS(filledPathString);
  126. NEW(pathEdit); pathEdit.SetAsString(filledPathString); pathEdit.alignment.Set(WMComponents.AlignLeft);
  127. pathEdit.bounds.SetWidth(300); pathEdit.multiLine.Set(FALSE);
  128. pathEdit.tv.textAlignV.Set(WMGraphics.AlignCenter);
  129. pathEdit.tv.borders.Set(WMRectangles.MakeRect(3, 3, 1, 1));
  130. pathEdit.tv.showBorder.Set(TRUE);
  131. pathEdit.fillColor.Set(LONGINT(0FFFFFFFFH));
  132. toolbarPath.AddContent(pathEdit);
  133. NEW(pathLabel); pathLabel.alignment.Set(WMComponents.AlignLeft);
  134. pathLabel.bounds.SetWidth(300); pathLabel.fillColor.Set(LONGINT(0FFFFFFFFH));
  135. pathLabel.SetCaption(" e.g. FS:, FS:/subDir, FS:/subDir/subSubDir, etc.");
  136. toolbarPath.AddContent(pathLabel);
  137. NEW(fmaskLabel); fmaskLabel.alignment.Set(WMComponents.AlignLeft);
  138. fmaskLabel.bounds.SetWidth(70); fmaskLabel.fillColor.Set(LONGINT(0FFFFFFFFH));
  139. fmaskLabel.SetCaption(" Files:");
  140. toolbarFMask.AddContent(fmaskLabel);
  141. NEW(fmaskEdit); fmaskEdit.alignment.Set(WMComponents.AlignLeft);
  142. fmaskEdit.SetAsString("*.Mod");
  143. fmaskEdit.bounds.SetWidth(300); fmaskEdit.multiLine.Set(FALSE);
  144. fmaskEdit.tv.textAlignV.Set(WMGraphics.AlignCenter);
  145. fmaskEdit.tv.borders.Set(WMRectangles.MakeRect(3, 3, 1, 1));
  146. fmaskEdit.tv.showBorder.Set(TRUE);
  147. fmaskEdit.fillColor.Set(LONGINT(0FFFFFFFFH));
  148. toolbarFMask.AddContent(fmaskEdit);
  149. NEW(contentLabel); contentLabel.alignment.Set(WMComponents.AlignLeft);
  150. contentLabel.bounds.SetWidth(70); contentLabel.fillColor.Set(LONGINT(0FFFFFFFFH));
  151. contentLabel.SetCaption(" Content:");
  152. toolbar.AddContent(contentLabel);
  153. NEW(contentEdit); contentEdit.alignment.Set(WMComponents.AlignLeft);
  154. contentEdit.bounds.SetWidth(300); contentEdit.multiLine.Set(FALSE);
  155. contentEdit.tv.textAlignV.Set(WMGraphics.AlignCenter);
  156. contentEdit.tv.borders.Set(WMRectangles.MakeRect(3, 3, 1, 1));
  157. contentEdit.tv.showBorder.Set(TRUE);
  158. contentEdit.fillColor.Set(LONGINT(0FFFFFFFFH));
  159. toolbar.AddContent(contentEdit);
  160. NEW(searchBtn);
  161. searchBtn.caption.SetAOC("Go");
  162. searchBtn.alignment.Set(WMComponents.AlignLeft);
  163. searchBtn.bounds.SetWidth(80);
  164. searchBtn.onClick.Add(SearchHandler);
  165. toolbarSearch.AddContent(searchBtn);
  166. NEW(stopBtn);
  167. stopBtn.caption.SetAOC("Stop");
  168. stopBtn.alignment.Set(WMComponents.AlignLeft);
  169. stopBtn.bounds.SetWidth(80);
  170. stopBtn.onClick.Add(StopHandler);
  171. toolbarSearch.AddContent(stopBtn);
  172. NEW(status); status.alignment.Set(WMComponents.AlignBottom); status.bounds.SetHeight(20);
  173. panel.AddContent(status); status.fillColor.Set(LONGINT(0CCCCCCFFH));
  174. NEW(statusLabel); statusLabel.bounds.SetWidth(panel.bounds.GetWidth());
  175. statusLabel.caption.SetAOC("Status : Ready"); statusLabel.alignment.Set(WMComponents.AlignLeft);
  176. status.AddContent(statusLabel);
  177. NEW(filelist);
  178. filelist.SetSearchReqFlag;
  179. filelist.alignment.Set(WMComponents.AlignClient);
  180. panel.AddContent(filelist);
  181. (* Link the Editors for the Focus Chain *)
  182. pathEdit.SetDoubleLinkedNextFocus(fmaskEdit);
  183. fmaskEdit.SetDoubleLinkedNextFocus(contentEdit);
  184. pathEdit.onEnter.Add(OnEnterHandler);
  185. fmaskEdit.onEnter.Add(OnEnterHandler);
  186. contentEdit.onEnter.Add(OnEnterHandler);
  187. pathEdit.onEscape.Add(OnEscapeHandler);
  188. fmaskEdit.onEscape.Add(OnEscapeHandler);
  189. contentEdit.onEscape.Add(OnEscapeHandler);
  190. RETURN panel
  191. END CreateForm;
  192. PROCEDURE OnEnterHandler(sender, data: ANY); (* Handles also Tab events for Type Editor *)
  193. BEGIN
  194. IF sender = pathEdit THEN
  195. pathEdit.FocusNext();
  196. ELSIF sender = fmaskEdit THEN
  197. fmaskEdit.FocusNext();
  198. ELSIF sender = contentEdit THEN
  199. IF contentEdit.withShift THEN
  200. contentEdit.FocusPrev();
  201. ELSE
  202. (* stop current search, start new one *)
  203. stopBtn.onClick.Call(NIL);
  204. searchBtn.onClick.Call(NIL);
  205. END;
  206. END;
  207. END OnEnterHandler;
  208. (* stop searching when Escape is pressed *)
  209. PROCEDURE OnEscapeHandler(sender, data: ANY);
  210. BEGIN
  211. stopBtn.onClick.Call(NIL);
  212. END OnEscapeHandler;
  213. PROCEDURE FillFirstMountedFS(VAR s : ARRAY OF CHAR);
  214. VAR list: Files.FileSystemTable;
  215. BEGIN
  216. Files.GetList(list);
  217. IF LEN(list) > 0 THEN
  218. COPY(list[0].prefix, s); Strings.Append(s, ":")
  219. ELSE
  220. s := "";
  221. END
  222. END FillFirstMountedFS;
  223. PROCEDURE SearchDoneHandler;
  224. BEGIN
  225. statusLabel.caption.SetAOC("Status : Ready");
  226. END SearchDoneHandler;
  227. PROCEDURE SearchStartHandler;
  228. BEGIN
  229. statusLabel.caption.SetAOC("Status : Processing ...")
  230. END SearchStartHandler;
  231. PROCEDURE SearchHandler(sender, data : ANY);
  232. VAR
  233. searchPar : SearchPar;
  234. BEGIN
  235. pathEdit.GetAsString(searchPar.path); fmaskEdit.GetAsString(searchPar.fmask); contentEdit.GetAsString(searchPar.content);
  236. StopSearcherAndDisplayer();
  237. filelist.ResetGrid;
  238. s.Start(searchPar);
  239. d.Start()
  240. END SearchHandler;
  241. PROCEDURE StopHandler(sender, data : ANY);
  242. BEGIN
  243. StopSearcherAndDisplayer()
  244. END StopHandler;
  245. PROCEDURE StopSearcherAndDisplayer;
  246. BEGIN
  247. s.Stop();
  248. d.Stop()
  249. END StopSearcherAndDisplayer;
  250. PROCEDURE Handle(VAR x: WMMessages.Message);
  251. BEGIN
  252. IF (x.msgType = WMMessages.MsgExt) & (x.ext # NIL) THEN
  253. IF (x.ext IS KillerMsg) THEN Close
  254. ELSIF (x.ext IS WMRestorable.Storage) THEN
  255. x.ext(WMRestorable.Storage).Add("WMSearchTool", "WMSearchTool.Restore", SELF, NIL)
  256. ELSE Handle^(x)
  257. END
  258. ELSE Handle^(x)
  259. END
  260. END Handle;
  261. END Window;
  262. TYPE
  263. SearchPar = RECORD
  264. path, fmask, content : ARRAY 256 OF CHAR
  265. END;
  266. Searcher = OBJECT
  267. VAR
  268. newlyStarted, stopped : BOOLEAN;
  269. currentPar, newPar : SearchPar;
  270. lb : ListBuffer;
  271. PROCEDURE &Init*(lb : ListBuffer);
  272. BEGIN
  273. newlyStarted := FALSE;
  274. stopped := FALSE;
  275. SELF.lb := lb;
  276. END Init;
  277. PROCEDURE Start(searchPar : SearchPar);
  278. BEGIN {EXCLUSIVE}
  279. newPar := searchPar;
  280. newlyStarted := TRUE;
  281. END Start;
  282. PROCEDURE AwaitNewStart;
  283. BEGIN {EXCLUSIVE}
  284. AWAIT(newlyStarted = TRUE);
  285. newlyStarted := FALSE;
  286. stopped := FALSE;
  287. END AwaitNewStart;
  288. PROCEDURE CopySearchParams;
  289. BEGIN {EXCLUSIVE}
  290. currentPar := newPar
  291. END CopySearchParams;
  292. PROCEDURE Stop;
  293. BEGIN {EXCLUSIVE}
  294. stopped := TRUE;
  295. END Stop;
  296. PROCEDURE IsStopped() : BOOLEAN;
  297. BEGIN {EXCLUSIVE}
  298. RETURN stopped;
  299. END IsStopped;
  300. (* Boyer-Moore match for streams *)
  301. PROCEDURE ContainsStr(CONST filename, content : ARRAY OF CHAR) : BOOLEAN;
  302. VAR r : Files.Reader;
  303. f : Files.File;
  304. d : ARRAY 256 OF LONGINT;
  305. cb : Strings.String;
  306. cpos, i, j, k, m, shift : LONGINT;
  307. BEGIN
  308. m := Strings.Length(content);
  309. f := Files.Old(filename);
  310. IF f # NIL THEN
  311. Files.OpenReader(r, f, 0);
  312. NEW(cb, m);
  313. WHILE (r.res # 0) & (cpos < m) DO
  314. cb[cpos] := r.Get();
  315. INC(cpos);
  316. END;
  317. IF r.res = 0 THEN
  318. FOR i := 0 TO 255 DO d[i] := m END;
  319. FOR i := 0 TO m-2 DO d[ORD(content[i])] := m - i - 1 END;
  320. i := m;
  321. REPEAT j := m; k := i;
  322. REPEAT DEC(k); DEC(j);
  323. UNTIL (j < 0) OR (content[j] # cb[k MOD m]);
  324. shift := d[ORD(cb[(i-1) MOD m])];
  325. i := i + shift;
  326. WHILE (cpos < i) & (r.res = 0) DO
  327. cb[cpos MOD m] := r.Get();
  328. INC(cpos);
  329. END;
  330. IF IsStopped() THEN RETURN FALSE END
  331. UNTIL (j < 0) OR (r.res # 0);
  332. IF j < 0 THEN RETURN TRUE END
  333. END;
  334. RETURN FALSE
  335. ELSE RETURN FALSE
  336. END
  337. END ContainsStr;
  338. PROCEDURE Match(CONST name : ARRAY OF CHAR);
  339. VAR d : WMSystemComponents.DirEntry;
  340. p, filename : ARRAY 1024 OF CHAR;
  341. l : LONGINT;
  342. BEGIN
  343. IF (currentPar.content = "") OR ContainsStr(name, currentPar.content) THEN
  344. Files.SplitPath(name, p, filename);
  345. l := Strings.Length(p);
  346. p[l] := Files.PathDelimiter; p[l + 1] := 0X;
  347. NEW(d, Strings.NewString(filename), Strings.NewString(p), 0, 0, 0, {});
  348. lb.Put(d)
  349. END;
  350. END Match;
  351. PROCEDURE SearchPath;
  352. VAR mask, name : ARRAY 1024 OF CHAR;
  353. flags : SET;
  354. time, date, size, len : LONGINT;
  355. e : Files.Enumerator;
  356. BEGIN
  357. COPY(currentPar.path, mask);
  358. len := Strings.Length(mask);
  359. IF (mask[len-1] = ':') OR (mask[len-1] = '/') THEN
  360. Strings.Append(mask, currentPar.fmask)
  361. ELSE
  362. Strings.Append(mask, '/'); Strings.Append(mask, currentPar.fmask)
  363. END;
  364. NEW(e);
  365. e.Open(mask, {});
  366. WHILE e.HasMoreEntries() DO
  367. IF IsStopped() THEN RETURN END;
  368. IF e.GetEntry(name, flags, time, date, size) THEN
  369. IF ~(Files.Directory IN flags) THEN
  370. Match(name)
  371. END;
  372. END
  373. END
  374. END SearchPath;
  375. BEGIN {ACTIVE}
  376. LOOP
  377. AwaitNewStart;
  378. CopySearchParams;
  379. lb.Reset;
  380. SearchPath;
  381. lb.Finished;
  382. END
  383. END Searcher;
  384. GridDisplayHandler = PROCEDURE {DELEGATE} (CONST data : ARRAY OF WMSystemComponents.DirEntry; noEl : LONGINT);
  385. SearchStatusHandler = PROCEDURE {DELEGATE};
  386. GridDisplayer= OBJECT
  387. VAR rl : RetrievedList;
  388. display : GridDisplayHandler;
  389. startHandler, stopHandler : SearchStatusHandler;
  390. newlyStarted, stopped : BOOLEAN;
  391. lb : ListBuffer;
  392. PROCEDURE &Init*(lb : ListBuffer; display : GridDisplayHandler; sh, dh : SearchStatusHandler);
  393. BEGIN
  394. SELF.lb := lb;
  395. SELF.display := display;
  396. startHandler := sh;
  397. stopHandler := dh;
  398. newlyStarted := FALSE;
  399. stopped := FALSE
  400. END Init;
  401. PROCEDURE Start;
  402. BEGIN {EXCLUSIVE}
  403. newlyStarted := TRUE;
  404. END Start;
  405. PROCEDURE AwaitNewStart;
  406. BEGIN {EXCLUSIVE}
  407. AWAIT(newlyStarted);
  408. newlyStarted := FALSE;
  409. stopped := FALSE
  410. END AwaitNewStart;
  411. PROCEDURE Stop;
  412. BEGIN {EXCLUSIVE}
  413. stopped := TRUE
  414. END Stop;
  415. BEGIN {ACTIVE}
  416. LOOP
  417. AwaitNewStart;
  418. startHandler;
  419. LOOP
  420. lb.Get(rl);
  421. IF (rl.noEl = 0) OR stopped THEN EXIT END; (* either done or stopped *)
  422. display(rl.data, rl.noEl)
  423. END;
  424. stopHandler;
  425. END
  426. END GridDisplayer;
  427. TYPE
  428. RetrievedList = RECORD
  429. data : ARRAY RListSize OF WMSystemComponents.DirEntry;
  430. noEl : INTEGER;
  431. END;
  432. ListBuffer = OBJECT
  433. VAR
  434. data : ARRAY RListSize OF WMSystemComponents.DirEntry;
  435. in, out, maxNoEl : INTEGER;
  436. finished : BOOLEAN;
  437. PROCEDURE &Init*;
  438. BEGIN
  439. Reset
  440. END Init;
  441. PROCEDURE Reset;
  442. BEGIN {EXCLUSIVE}
  443. in := 0; out := 0; maxNoEl := 1;
  444. finished := FALSE
  445. END Reset;
  446. PROCEDURE Put(d : WMSystemComponents.DirEntry);
  447. BEGIN {EXCLUSIVE}
  448. AWAIT(((in + 1) MOD RListSize) # (out MOD RListSize));
  449. data[in MOD RListSize] := d;
  450. INC(in)
  451. END Put;
  452. PROCEDURE Finished;
  453. BEGIN {EXCLUSIVE}
  454. finished := TRUE;
  455. END Finished;
  456. PROCEDURE Get(VAR rlist : RetrievedList);
  457. VAR i, j : INTEGER;
  458. BEGIN {EXCLUSIVE}
  459. AWAIT((in - out >= maxNoEl) OR finished);
  460. i := 0;
  461. FOR j := out TO in -1 DO
  462. rlist.data[i] := data[j MOD RListSize];
  463. INC(i);
  464. END;
  465. rlist.noEl := i;
  466. IF i > maxNoEl THEN maxNoEl := i END;
  467. out := in
  468. END Get;
  469. END ListBuffer;
  470. VAR
  471. nofWindows : LONGINT;
  472. PROCEDURE Restore*(context : WMRestorable.Context);
  473. VAR w : Window;
  474. BEGIN
  475. NEW(w, context)
  476. END Restore;
  477. PROCEDURE Open*;
  478. VAR inst : Window;
  479. BEGIN
  480. NEW(inst, NIL);
  481. END Open;
  482. PROCEDURE IncCount;
  483. BEGIN {EXCLUSIVE}
  484. INC(nofWindows);
  485. END IncCount;
  486. PROCEDURE DecCount;
  487. BEGIN {EXCLUSIVE}
  488. DEC(nofWindows);
  489. END DecCount;
  490. PROCEDURE Cleanup;
  491. VAR die : KillerMsg; msg : WMMessages.Message; m : WMWindowManager.WindowManager;
  492. BEGIN {EXCLUSIVE}
  493. NEW(die); msg.ext := die; msg.msgType := WMMessages.MsgExt;
  494. m := WMWindowManager.GetDefaultManager();
  495. m.Broadcast(msg);
  496. AWAIT(nofWindows = 0)
  497. END Cleanup;
  498. BEGIN
  499. Modules.InstallTermHandler(Cleanup)
  500. END WMSearchTool.
  501. SystemTools.Free WMSystemComponents WMSearchTool WMFileManager~
  502. WMSearchTool.Open ~