sysarm.c 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394
  1. #error this version is no longer supported. The file is left in case
  2. it ever proves a useful prototype for anything else.
  3. /* sysarm.c Copyright (C) 1989-93 Codemist Ltd */
  4. /*
  5. * Acorn Archimedes-specific code
  6. */
  7. /* Signature: 4f2fd4ee 07-Mar-2000 */
  8. #include <stdarg.h>
  9. #include <string.h>
  10. #include <ctype.h>
  11. #include "bbc.h"
  12. #include "akbd.h"
  13. #include "flex.h"
  14. #include "os.h"
  15. #include "wimp.h"
  16. #include "wimpt.h"
  17. #include "werr.h"
  18. #include "win.h"
  19. #include "menu.h"
  20. #define template acorn_template /* To avoid clash with C++ */
  21. #include "template.h"
  22. #include "dbox.h"
  23. #include "txt.h"
  24. #include "saveas.h"
  25. #include "event.h"
  26. #include "res.h"
  27. #include "resspr.h"
  28. #include "baricon.h"
  29. #include "colourtran.h"
  30. #include "xferrecv.h"
  31. #include "xfersend.h"
  32. #include "sprite.h"
  33. #include "msgs.h"
  34. /* #include <swis.h> */
  35. #define Wimp_SendMessage 0x0400e7
  36. #define OS_EvaluateExpression 0x00002d
  37. #define OS_Claim 0x00001f
  38. #define OS_Release 0x000020
  39. #define OS_DelinkApplication 0x00004d
  40. #define OS_RelinkApplication 0x00004e
  41. #define Hourglass_On 0x0406c0
  42. #define Hourglass_Off 0x0406c1
  43. #define Wimp_ReadSysInfo 0x0400f2
  44. #include "machine.h"
  45. #include "version.h"
  46. #include "tags.h"
  47. #include "cslerror.h"
  48. #include "externs.h"
  49. #include "arith.h"
  50. #include "read.h"
  51. #include "entries.h"
  52. #ifdef TIMEOUT
  53. #include "timeout.h"
  54. #endif
  55. static void get_home_directory(char *b, int length);
  56. static void get_users_home_directory(char *b, int length);
  57. #include "filename.c"
  58. int create_directory(char *filename, char *old, size_t n)
  59. {
  60. process_file_name(filename, old, n);
  61. if (*filename == 0) return 1;
  62. return mkdir(filename);
  63. }
  64. int delete_file(char *filename, char *old, size_t n)
  65. {
  66. process_file_name(filename, old, n);
  67. if (*filename == 0) return NULL;
  68. return remove(filename);
  69. }
  70. CSLbool file_exists(char *filename, char *old, size_t n, char *tt)
  71. {
  72. os_filestr b;
  73. time_t t;
  74. unsigned int load, exec, w;
  75. process_file_name(filename, old, n);
  76. if (*filename == 0) return NO;
  77. b.action = 5;
  78. b.name = filename;
  79. if (os_file(&b) != 0) return NO;
  80. load = b.loadaddr; exec = b.execaddr;
  81. if ((load & 0xfff00000) != 0xfff00000) return NO;
  82. load = load & 0xff;
  83. /* Now I need to divide the datestamp by 100 */
  84. w = (load << 16) | ((exec >> 16) & 0xffff);
  85. exec = (exec & 0xffff) | ((w % 100) << 16);
  86. w = w / 100;
  87. t = (w << 16) | (exec / 100);
  88. strcpy(tt, ctime(&t));
  89. return YES;
  90. }
  91. /*
  92. * This is a dummy definition of get_truename, here so that everything
  93. * will link. Both the calling convention used here and the exact
  94. * meaning and implementation may be under gentle review!
  95. */
  96. char *get_truename(char *filename, char *old, size_t n)
  97. {
  98. char *w;
  99. process_file_name(filename, old, n);
  100. if (*filename == 0)
  101. { aerror("truename");
  102. return NULL;
  103. }
  104. w = (char *)malloc(1+strlen(filename));
  105. if (w == NULL) return w;
  106. strcpy(w, filename);
  107. return w;
  108. }
  109. char *my_getenv(char *s)
  110. {
  111. return getenv(s);
  112. }
  113. static void delink(void), relink(void);
  114. int my_system(char *s)
  115. {
  116. int w;
  117. delink();
  118. w = system(s);
  119. relink();
  120. return w;
  121. }
  122. /*
  123. * RISCOS does not support the idea of home directories for
  124. * users, so in case anybody still wants to use the notation "~" that
  125. * would indicate a home directory under Unix I implement something
  126. * in terms of environment variables.
  127. */
  128. static void get_home_directory(char *b, int length)
  129. {
  130. char *w = my_getenv("home");
  131. if (w != NULL) strcpy(b, w);
  132. else
  133. strcpy(b, "@");
  134. }
  135. static void get_users_home_directory(char *b, int length)
  136. {
  137. char *w, h[LONGEST_LEGAL_FILENAME];
  138. sprintf(h, "home$%s", b);
  139. w = my_getenv(h);
  140. if (w != NULL) strcpy(b, w);
  141. else
  142. strcpy(b, "@");
  143. }
  144. /*
  145. * The following structure MUST match the layout of a FILE as used by
  146. * the library that is linked with.
  147. */
  148. #define FILEHANDLE int
  149. struct FILE_COPY
  150. { int icnt; /* two separate _cnt fields so we can police ... */
  151. unsigned char *ptr;
  152. int ocnt; /* ... restrictions that read/write are fseek separated */
  153. int flag;
  154. unsigned char *base; /* buffer base */
  155. int file; /* RISCOS/Arthur/Brazil file handle */
  156. long pos; /* position in file */
  157. int bufsiz; /* maximum buffer size */
  158. int signature; /* used with temporary files */
  159. unsigned char lilbuf[2]; /* single byte buffer for them that want it */
  160. /* plus an unget char is put in __lilbuf[1] */
  161. long lspos; /* what __pos should be (set after lazy seek)*/
  162. unsigned char *extent; /* extent of writes into the current buffer */
  163. int buflim; /* used size of buffer */
  164. int icnt_save; /* after unget contains old icnt */
  165. int ocnt_save; /* after unget contains old ocnt */
  166. };
  167. static int pipe_ptr = 0;
  168. static unsigned char pipe_buffer[20+256];
  169. static CSLbool under_wimp = NO;
  170. FILE *my_popen(char *cmd, char *dirn)
  171. {
  172. if (!under_wimp) return NULL;
  173. pipe_ptr = 20;
  174. return (FILE *)1;
  175. }
  176. void my_pipe_putc(int c, FILE *f)
  177. {
  178. if (pipe_ptr >= 20 && pipe_ptr < sizeof(pipe_buffer)-1)
  179. { if (c == '\n') my_pipe_flush(f);
  180. else pipe_buffer[pipe_ptr++] = c;
  181. }
  182. }
  183. void my_pipe_flush(FILE *f)
  184. {
  185. if (pipe_ptr > 20 && pipe_ptr < sizeof(pipe_buffer)-1)
  186. { int32 *w = (int32 *)pipe_buffer;
  187. remove_ticker();
  188. delink();
  189. pipe_buffer[pipe_ptr] = 0;
  190. w[0] = (pipe_ptr + 4) & ~3;
  191. w[1] = 0;
  192. w[2] = 0;
  193. w[3] = 0; /* An original message, this one */
  194. w[4] = 0x0c1202; /* A magic number for GNUPLOT, I am told! */
  195. os_swi3(Wimp_SendMessage, 17, (int)w, 0);
  196. relink();
  197. add_ticker();
  198. /* here w[2] is my reference for the message */
  199. accept_tick();
  200. }
  201. pipe_ptr = 20;
  202. return;
  203. }
  204. void my_pclose(FILE *f)
  205. {
  206. return;
  207. }
  208. int batchp()
  209. {
  210. return (((struct FILE_COPY *)stdin)->file != 0);
  211. }
  212. /*
  213. * The following function controls memory allocation policy
  214. */
  215. int32 ok_to_grab_memory(int32 current)
  216. {
  217. return 3*current + 2;
  218. }
  219. /*
  220. * The next procedure is responsible for establishing information about
  221. * where the main checkpoint image should be recovered from, and where
  222. * and fasl files should come from.
  223. */
  224. static char appname[16] = "!CSL";
  225. static char CSL_version_string[64];
  226. static char LOADSTART[16] = "(rdf \"";
  227. static char LOADEND[16] = "\")";
  228. char *find_image_directory(int argc, char *argv[])
  229. {
  230. char image[LONGEST_LEGAL_FILENAME];
  231. char pgmname[LONGEST_LEGAL_FILENAME];
  232. char *w;
  233. CSLbool riscos_application = NO;
  234. int i;
  235. /*
  236. * For RISCOS there are a number of possibilities that can support
  237. * either window-launched uses or command-line driven uses of this code.
  238. *
  239. * When launched from the window manager I will be called with a full
  240. * path name for by executable binary available in argv[0], and this will
  241. * always be of the form xxx.yyy.!zzz.!runimage
  242. * In this case I will use
  243. * xxx.yyy.!zzz.-runimage
  244. * as the name for my checkpoint file, and I will treate zzz as the name
  245. * of the application, using that name to control what appears in menus
  246. * and what sprites I use to display things.
  247. *
  248. * The second possibility is that I am called from a command-line. In that
  249. * case if the command line request was of the form
  250. * !zzz.!qqq
  251. * then I view zzz as the application name, and use !zzz.-qqq as the
  252. * checkpoint file. The use of things like xxx.yyy.!zzz.!qqq will be
  253. * supported in this case too.
  254. *
  255. * A final strategy is used if the command line shows only one component
  256. * of a file name, or if either of the two final components in the path
  257. * fail to start with '!'. In this case if the final component of the
  258. * name (i.e. of argv[0]) is xxx or !xxx then I look up the value of a shell
  259. * variable xxx$dir, and if look for a file called "-runimage" in that
  260. * directory. If argv[0] is null I take it to be "csl" and if the
  261. * environment variable indicated here is unset I look for -runimage in
  262. * the current directory. In such cases the application name is taken as xxx.
  263. */
  264. if (argc > 0 && argv[0] != NULL)
  265. { int j, r0, r1;
  266. w = argv[0];
  267. sprintf(pgmname, "\"%s\"\n", w);
  268. /*
  269. * The following line expands any shell-variables mentioned in the
  270. * command that launched me. E.g. typically from the window manager
  271. * the raw command-line will have been
  272. * <Obey$Dir>.!RunImage ...
  273. * and I need to expand <Obey$Dir>
  274. */
  275. os_swi3r(OS_EvaluateExpression,
  276. (int)pgmname, (int)image, LONGEST_LEGAL_FILENAME,
  277. &r0, &r1, &i);
  278. if (r1 == 0) sprintf(image, "%d", i);
  279. else image[i] = 0;
  280. w = image;
  281. i = strlen(w);
  282. while (i > 0 && w[i-1] != '.') i--;
  283. j = i-1;
  284. while (j > 0 && w[j-1] != '.') j--;
  285. if (j >= 0 && w[i] == '!' && w[j] == '!')
  286. { w[i] = '-';
  287. if (i > j+16) i = j+16; /* Truncate name if necessary */
  288. sprintf(appname, "%.*s", i-j-1, &w[j]);
  289. riscos_application = YES;
  290. }
  291. else
  292. { strcpy(pgmname, &w[i]);
  293. strcpy(image, pgmname);
  294. }
  295. }
  296. else strcpy(image, "!csl"); /* even argv[0] is not available! */
  297. if (!riscos_application)
  298. {
  299. /*
  300. * If I get here then image contains the final component of the application
  301. * name, and I must use it to build the name of an environment variable to
  302. * check.
  303. */
  304. if (image[0] == '!')
  305. { sprintf(pgmname, "%s$dir", &image[1]);
  306. sprintf(appname, "%.15s", image);
  307. }
  308. else
  309. { sprintf(pgmname, "%s$dir", image);
  310. sprintf(appname, "!%.15s", image);
  311. }
  312. w = my_getenv(pgmname);
  313. if (w == NULL) w = "@";
  314. sprintf(image, "%s.-runimage", w);
  315. }
  316. w = appname; /* Force application name into upper case */
  317. while ((i = *w) != 0)
  318. { if (islower(i)) i = toupper(i);
  319. *w++ = i;
  320. }
  321. if (strcmp(appname, "!CSL") != 0)
  322. { strcpy(LOADSTART, "in \"");
  323. strcpy(LOADEND, "\";");
  324. }
  325. /*
  326. * I copy from local vectors into malloc'd space to hand my
  327. * answer back.
  328. */
  329. w = (char *)malloc(1+strlen(image));
  330. /*
  331. * The error exit here seem unsatisfactory...
  332. */
  333. if (w == NULL)
  334. { fprintf(stderr, "\n+++ Panic - run out of space\n");
  335. exit(EXIT_FAILURE);
  336. }
  337. strcpy(w, image);
  338. sprintf(CSL_version_string, "%s %s (%s)", appname+1, VERSION, __DATE__);
  339. return w;
  340. }
  341. #ifdef PROFILED
  342. /*
  343. * The following are really part of the ARM C library, but are included here
  344. * first as prototypes in case the ideas are useful with other architectures.
  345. *
  346. * Support for gathering various sorts of information that shows where time
  347. * may be going in this system. Un Unix machines try prof/monitor and friends.
  348. */
  349. extern void *__RO_Base, *__RO_Limit;
  350. extern void _count(void);
  351. extern void _count1(void);
  352. typedef union count_position
  353. /*
  354. * This defines the format of the word that follows on from a call
  355. * to _count1(). The related constant values are related to the way that
  356. * file-name decoding tables are packed away.
  357. */
  358. {
  359. int i;
  360. struct s
  361. { unsigned int posn:12,
  362. line:16,
  363. file:4;
  364. } s;
  365. } count_position;
  366. #define file_name_map_start 0xfff12340 /* Magic number */
  367. #define file_name_map_end 0x31415926 /* Magic number */
  368. #define word_roundup(s) ((char *)(((int)s + 3) & (~3)))
  369. static char *find_file_map(int p)
  370. {
  371. int i, w;
  372. char *s;
  373. while (((w = *(int *)p) & 0xfffffff0) != file_name_map_start)
  374. { if (p >= (int)__RO_Limit) return "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
  375. p += 4;
  376. }
  377. s = (char *)(p + 4);
  378. for ( i = 0; i<=(w & 0xf); i++)
  379. { s += 1 + strlen(s);
  380. s = word_roundup(s);
  381. }
  382. if (*(int *)s != file_name_map_end) return find_file_map((int)s);
  383. return (char *)(p + 4);
  384. }
  385. void show_counts(void)
  386. {
  387. int count = (int)_count; /* address of the function as an int */
  388. int p, onthisline = 0, w1 = 0, w2 = 0;
  389. myprintf("\nCounts from %p to %p\n", __RO_Base, __RO_Limit);
  390. for (p = (int)__RO_Base; p<(int)__RO_Limit; p += 4)
  391. { int w = *(int *)p;
  392. if ((w & 0xff000000) == 0xeb000000) /* Unconditional BL instruction */
  393. { int dest = (p + 8 + 4*(w & 0x00ffffff)) & 0x03fffffc;
  394. if (dest == count)
  395. { myprintf("%.6x: %-10u ", p, *(int *)(p + 4));
  396. if (onthisline == 3) onthisline = 0, myprintf("\n");
  397. else onthisline++, myprintf(" ");
  398. }
  399. }
  400. if ((w & 0xfffe0000) == 0xe92c0000 && /* STMFD sp!, sp = r12 or r13 */
  401. w1 == 0xe1a0b00c && /* MOV ip, sp @@@@@ */
  402. (w2 & 0xffff0000) == 0xff000000)
  403. { char *name = (char *)(p - 8 - (w2 & 0xffff));
  404. int len = 0;
  405. char *temp = name;
  406. /* I do not use strlen() here to keep the library more modular */
  407. while (*temp++ != 0) len++;
  408. if (len >= 10 && onthisline == 3)
  409. { onthisline = 0;
  410. myprintf("\n");
  411. }
  412. myprintf( "%.6x: %s", p - 4, name);
  413. len = 11 - strlen(name);
  414. while (len < 0) len += 20, onthisline++;
  415. while (len > 0) len--, myprintf(" ");
  416. if (onthisline >= 3) onthisline = 0, myprintf("\n");
  417. else onthisline++, myprintf(" ");
  418. }
  419. w2 = w1;
  420. w1 = w;
  421. }
  422. if (onthisline != 0) myprintf(" ");
  423. }
  424. void write_profile(char *filename)
  425. {
  426. /* Create a (binary) file containing execution profile information for */
  427. /* the current program. The format is eccentric, and must be kept in step */
  428. /* with (a) parts of armgen.c that generate code that collects statistics */
  429. /* and (b) code in misc.c that reads in the binary file created here and */
  430. /* displays the counts attached to a source listing of the original code. */
  431. int count1 = (int)_count1;
  432. int p, w1 = 0, w2 = 0, pass, nfiles = 0, namebytes = 0, ncounts = 0;
  433. int global_name_offset[256];
  434. char *global_file_map[256]; /* Limits total number of files allowed */
  435. FILE *map_file = fopen(filename, "wb");
  436. char *file_map;
  437. if (map_file == NULL)
  438. { myprintf("\nUnable to open %s for execution profile log\n",
  439. filename);
  440. return;
  441. }
  442. for (pass = 1; pass <=2; pass++)
  443. {
  444. if (pass == 2)
  445. /* Write file header indicating size of sub-parts */
  446. { fwrite("\xff*COUNTFILE*", 4, 3, map_file);
  447. fwrite(&namebytes, 4, 1, map_file);
  448. fwrite(&nfiles, 4, 1, map_file);
  449. fwrite(&ncounts, 4, 1, map_file);
  450. for (p = 0; p < nfiles; p++)
  451. { char *ss = global_file_map[p];
  452. int len = 1 + strlen(ss);
  453. len = ((len + 3) & (~3)) / 4;
  454. fwrite(ss, 4, len, map_file);
  455. }
  456. for (p = 0; p < nfiles; p++)
  457. fwrite(&global_name_offset[p], 4, 1, map_file);
  458. }
  459. file_map = NULL;
  460. for (p = (int)__RO_Base; p<(int)__RO_Limit; p += 4)
  461. { int w = *(int *)p;
  462. if ((w & 0xff000000) == 0xeb000000) /* BL instruction */
  463. { int dest = (p + 8 + 4*(w & 0x00ffffff)) & 0x03fffffc;
  464. if (dest == count1)
  465. { count_position k;
  466. int i;
  467. char *s;
  468. if (file_map == NULL ||
  469. (int)file_map <= p) file_map = find_file_map(p+12);
  470. s = file_map;
  471. k.i = *(int *)(p + 8);
  472. for (i = 0; i<k.s.file; i++)
  473. { s += 1 + strlen(s);
  474. s = word_roundup(s);
  475. }
  476. if (pass == 1)
  477. { int i;
  478. for (i = 0;;i++)
  479. { if (i >= nfiles)
  480. { global_name_offset[nfiles] = namebytes;
  481. global_file_map[nfiles++] = s;
  482. namebytes += 1 + strlen(s);
  483. namebytes = (namebytes + 3) & (~3);
  484. break;
  485. }
  486. else if (strcmp(s,global_file_map[i]) ==0) break;
  487. }
  488. ncounts++;
  489. }
  490. else
  491. { int i;
  492. for (i = 0; strcmp(s, global_file_map[i]) !=0; i++);
  493. fwrite((int *)(p + 4), 4, 1, map_file);
  494. i = (k.s.line & 0xffff) | (i << 16);
  495. fwrite(&i, 4, 1, map_file);
  496. }
  497. p += 8;
  498. }
  499. }
  500. w2 = w1;
  501. w1 = w;
  502. }
  503. }
  504. fwrite("\xff*ENDCOUNT*\n", 4, 3, map_file); /* Trailer data */
  505. fclose(map_file);
  506. myprintf("\nProfile information written to %s\n", filename);
  507. }
  508. #endif /* PROFILED */
  509. /*
  510. * Wimp interfaces...
  511. */
  512. static CSLbool CSL_window_open = NO;
  513. static menu Iconbar_menu = 0, Main_menu = 0;
  514. static txt session;
  515. static txt_marker session_marker;
  516. #define MInfo 1 /* Icon-bar menu items */
  517. #define MQuit 2
  518. #define Vfield 4 /* version number field in "about" box */
  519. #define MMInt 1 /* main window menu items */
  520. #define MMAbort 2
  521. #define MMQuit 3
  522. #define MMSave 4
  523. #define MMSelAll 5
  524. #define MMCopy 6
  525. #define MMDelete 7
  526. #define MMClear 8
  527. #define BUFLEN 256
  528. /*
  529. * Text window event handling
  530. */
  531. static char *clipboard = NULL;
  532. static int clipboard_size = 0, clipboard_p, clipboard_n;
  533. typedef enum wimp_source_t
  534. {
  535. from_keyboard = 0,
  536. from_clipboard,
  537. from_file
  538. } wimp_source_t;
  539. static wimp_source_t wimp_source = from_keyboard;
  540. #define TTYBUF_SIZE 256
  541. static CSLbool tty_ready = NO;
  542. static int tty_icount = 0;
  543. static char tty_ibuffer[TTYBUF_SIZE];
  544. #ifdef TICK_STREAM
  545. extern void wimp_tick(void);
  546. /*
  547. * wimp_tick behaves roughly as shown in the following code, but is
  548. * in assembly code (in asmarm.s) since it is an interrupt routine and I
  549. * am required to adhere to rigid register-use etc conventions...
  550. *
  551. * void wimp_tick()
  552. * {
  553. * polltick_pending = YES;
  554. * if (tick_pending) return;
  555. * else if (already_in_gc) tick_on_gc_exit = YES;
  556. * else
  557. * { Lisp_Object nil = C_nil;
  558. * tick_pending = YES;
  559. * saveheaplimit = heaplimit;
  560. * heaplimit = fringe;
  561. * savevheaplimit = vheaplimit;
  562. * vheaplimit = vfringe;
  563. * savecodelimit = codelimit;
  564. * codelimit = codefringe;
  565. * savestacklimit = stacklimit;
  566. * stacklimit = stackbase;
  567. * }
  568. * return;
  569. * }
  570. */
  571. static CSLbool ticker_active = NO;
  572. void remove_ticker()
  573. {
  574. if (!ticker_active) return;
  575. #ifndef SOFTWARE_TICKS
  576. os_swi3(OS_Release, 0x1c, (int)wimp_tick, 0x91494530);
  577. #endif
  578. ticker_active = NO;
  579. }
  580. void add_ticker()
  581. {
  582. if (ticker_active) return;
  583. #ifdef SOFTWARE_TICKS
  584. countdown = SOFTWARE_TICKS;
  585. #else
  586. os_swi3(OS_Claim, 0x1c, (int)wimp_tick, 0x91494530);
  587. #endif
  588. ticker_active = YES;
  589. }
  590. #endif /* TICK_STREAM */
  591. static char task_links[61];
  592. static void delink()
  593. {
  594. os_swi2(OS_DelinkApplication, (int)&task_links[0], sizeof(task_links));
  595. }
  596. static void relink()
  597. {
  598. os_swi1(OS_RelinkApplication, (int)&task_links[0]);
  599. }
  600. static int selstart = -1, selend = -1, dragstart = -1;
  601. static int done_something = 0;
  602. static BOOL enlarge_clipboard(char **bufp, int *lenp)
  603. {
  604. if (!flex_extend((flex_ptr)&clipboard, clipboard_size+128))
  605. return FALSE;
  606. clipboard_size += 128;
  607. *bufp = clipboard;
  608. *lenp = clipboard_size;
  609. return TRUE;
  610. }
  611. static void clip_selection()
  612. {
  613. int p1 = txt_selectstart(session), p2 = txt_selectend(session), i;
  614. clipboard_p = clipboard_n = 0;
  615. wimp_source = from_clipboard;
  616. for (i=p1; i<p2; i++)
  617. { int c = txt_charat(session, i);
  618. if (clipboard_n >= clipboard_size)
  619. { if (!flex_extend((flex_ptr)&clipboard, clipboard_size+128)) return;
  620. clipboard_size += 128;
  621. }
  622. clipboard[clipboard_n++] = c;
  623. }
  624. }
  625. static void CSL_txthandler(txt t, void *handle)
  626. {
  627. txt_eventcode e;
  628. CSL_IGNORE(t); /* I only have one txt, so I use its global handle */
  629. CSL_IGNORE(handle);
  630. e = txt_get(session);
  631. /*
  632. * An event is either a mouse one or it involves the keyboard.
  633. * The latter is taken to include all sorts of special cases such as
  634. * hits on various buttons.
  635. * For mouse hits I need to support region selection as well as just
  636. * positioning.
  637. */
  638. if (e & txt_MOUSECODE)
  639. { int mousepos = e & 0xffffff;
  640. if (mousepos == 0xffffff) return;
  641. if (e & txt_MSELECT)
  642. { txt_setdot(session, mousepos);
  643. if ((e & txt_MSELOLD) && (dragstart >= 0))
  644. { if (mousepos >= dragstart)
  645. selstart = dragstart, selend = mousepos;
  646. else selstart = mousepos, selend = dragstart;
  647. wimp_source = from_keyboard;
  648. }
  649. else dragstart = mousepos;
  650. }
  651. else if ((e & txt_MSELOLD) && (dragstart >= 0))
  652. { if (mousepos >= dragstart)
  653. selstart = dragstart, selend = mousepos;
  654. else selstart = mousepos, selend = dragstart;
  655. dragstart = -1;
  656. wimp_source = from_keyboard;
  657. }
  658. else if ((e & txt_MEXTEND) && (selstart >= 0))
  659. { if (2*mousepos <= (selstart+selend)) selstart = mousepos;
  660. else selend = mousepos;
  661. wimp_source = from_keyboard;
  662. }
  663. if (selstart != selend) txt_setselect(session, selstart, selend);
  664. else txt_setselect(session, 0, 0); /* Unset any selection */
  665. done_something = 1;
  666. }
  667. else switch(e)
  668. {
  669. case txt_EXTRACODE + akbd_Sh + akbd_Ctl + akbd_UpK: /* Scroll up one line */
  670. txt_movevertical(session, -1, 1);
  671. break;
  672. case txt_EXTRACODE + akbd_Sh + akbd_UpK: /* Scroll up one page */
  673. txt_movevertical(session, -txt_visiblelinecount(session), 1);
  674. break;
  675. case txt_EXTRACODE + akbd_Sh + akbd_Ctl + akbd_DownK: /* Down one line */
  676. txt_movevertical(session, 1, 1);
  677. break;
  678. case txt_EXTRACODE + akbd_Sh + akbd_DownK: /* Down one page */
  679. txt_movevertical(session, txt_visiblelinecount(session), 1);
  680. break;
  681. case akbd_LeftK: /* left arrow key */
  682. txt_movehorizontal(session, -1);
  683. break;
  684. case akbd_RightK: /* right arrow key */
  685. txt_movehorizontal(session, 1);
  686. break;
  687. case akbd_UpK: /* up arrow key */
  688. txt_movevertical(session, -1, 0);
  689. break;
  690. case akbd_DownK: /* down arrow key */
  691. txt_movevertical(session, 1, 0);
  692. break;
  693. case txt_EXTRACODE + akbd_Fn +akbd_Sh + 2: /* Insert drag file */
  694. { char *filename;
  695. int filetype, len;
  696. if ((filetype = xferrecv_checkinsert(&filename)) != -1)
  697. { len = strlen(LOADSTART) + strlen(filename) + strlen(LOADEND);
  698. if (tty_icount + len < TTYBUF_SIZE)
  699. { sprintf(&tty_ibuffer[tty_icount], "%s%s%s",
  700. LOADSTART, filename, LOADEND);
  701. tty_icount += len;
  702. txt_setdot(session, txt_size(session));
  703. txt_insertstring(session, LOADSTART);
  704. txt_setdot(session, txt_size(session));
  705. txt_insertstring(session, filename);
  706. txt_setdot(session, txt_size(session));
  707. txt_insertstring(session, LOADEND);
  708. txt_setdot(session, txt_size(session));
  709. }
  710. xferrecv_insertfileok();
  711. }
  712. else if ((filetype = xferrecv_checkimport(&len)) != -1)
  713. { clipboard_p = 0;
  714. clipboard_n = xferrecv_doimport(clipboard, clipboard_size,
  715. enlarge_clipboard);
  716. xferrecv_insertfileok();
  717. if (clipboard_n > 0) wimp_source = from_clipboard;
  718. txt_setdot(session, txt_size(session));
  719. }
  720. }
  721. break;
  722. case txt_EXTRACODE + akbd_Fn + 127: /* close icon */
  723. case akbd_Fn + akbd_Ctl + 2: /* Ctl-F2 also quits */
  724. txt_dispose(&session);
  725. exit(0);
  726. break;
  727. case 127: /* backspace and ^H */
  728. case 8:
  729. txt_setdot(session, txt_size(session));
  730. txt_movehorizontal(session, -1);
  731. txt_delete(session, 1);
  732. if (tty_icount > 0) tty_icount--;
  733. break;
  734. default:
  735. if (e & txt_EXTRACODE)
  736. { sprintf(&tty_ibuffer[tty_icount], "<%.8x>", e);
  737. tty_ibuffer[tty_icount+10] = 0;
  738. txt_setdot(session, txt_size(session));
  739. txt_insertstring(session, &tty_ibuffer[tty_icount]);
  740. txt_setdot(session, txt_size(session));
  741. tty_icount += 10;
  742. }
  743. else if (e >= 256) wimp_processkey(e); /* give back to wimp */
  744. else switch (e)
  745. {
  746. case 'C' & 0x1f: /* ^C = copy selection */
  747. if (selstart == selend || selstart < 0) break;
  748. clip_selection();
  749. break;
  750. case 'X' & 0x1f: /* ^X = delete selection */
  751. if (selstart == selend || selstart < 0) break;
  752. txt_movemarker(session, &session_marker, txt_dot(session));
  753. txt_setdot(session, txt_selectstart(session));
  754. txt_delete(session, txt_selectend(session)-txt_selectstart(session));
  755. txt_movedottomarker(session, &session_marker);
  756. wimp_source = from_keyboard;
  757. break;
  758. case 'Z' & 0x1f: /* ^Z = cancel selection */
  759. selstart = selend = -1;
  760. txt_setselect(session, 0, 0); /* Unset any selection */
  761. wimp_source = from_keyboard;
  762. break;
  763. default:
  764. if (e == 4 || e == 13 ||
  765. e == 7 || e == 0x1b || /* bell and <escape> */
  766. e >= 32 && e < 127)
  767. {
  768. if (e == 13) e = 10; /* newline char is special case */
  769. txt_setdot(session, txt_size(session));
  770. txt_insertchar(session, e); /* insert the char */
  771. txt_movedot(session, 1); /* advance the dot */
  772. /*
  773. * I ignore characters (with no comment) if the user types in > 256
  774. * of them on one line.
  775. */
  776. if (tty_icount < TTYBUF_SIZE)
  777. { tty_ibuffer[tty_icount++] = e;
  778. if (e == 10) tty_ready = YES;
  779. }
  780. }
  781. }
  782. break;
  783. }
  784. }
  785. #define SCROLLBACK 4000
  786. #define STDOUT_BUFSIZE 1024
  787. #define LONGEST_PRINTF 120
  788. static char stdout_buffer[STDOUT_BUFSIZE];
  789. static char *stdout_p;
  790. static int stdout_n;
  791. static BOOL saveproc(char *filename, void *handle)
  792. {
  793. FILE *f = fopen(filename, "w");
  794. int i;
  795. CSL_IGNORE(handle);
  796. if (f == NULL) return FALSE;
  797. if (selstart == selend || selstart < 0) return FALSE;
  798. for (i=txt_selectstart(session); i<=txt_selectend(session); i++)
  799. putc(txt_charat(session, i), f);
  800. fclose(f);
  801. return TRUE;
  802. }
  803. static BOOL sendproc(void *handle, int *maxbuf)
  804. {
  805. int i;
  806. char buf[4];
  807. CSL_IGNORE(handle); CSL_IGNORE(maxbuf);
  808. for (i=txt_selectstart(session); i<=txt_selectend(session); i++)
  809. { buf[0] = txt_charat(session, i);
  810. if (!xfersend_sendbuf(buf, 1)) return FALSE;
  811. }
  812. return TRUE;
  813. }
  814. /*
  815. * Menu to be generated by "menu" button when mouse is over our main
  816. * text window
  817. */
  818. static void Main_menuproc(void *handle, char *hit)
  819. {
  820. CSL_IGNORE(handle);
  821. switch (hit[0])
  822. {
  823. case MMInt:
  824. #ifdef SOFTWARE_TICKS
  825. countdown = -1;
  826. #endif
  827. interrupt_pending = YES;
  828. wimp_source = from_keyboard;
  829. break;
  830. case MMAbort:
  831. #ifdef SOFTWARE_TICKS
  832. countdown = -1;
  833. #endif
  834. interrupt_pending = YES;
  835. wimp_source = from_keyboard;
  836. break;
  837. case MMQuit:
  838. exit(0);
  839. break;
  840. case MMSave:
  841. wimp_source = from_keyboard;
  842. saveas(0xfff, "savetext", txt_size(session),
  843. saveproc, sendproc, NULL, NULL);
  844. break;
  845. case MMSelAll:
  846. selstart = 0;
  847. selend = txt_size(session) - 1;
  848. if (selstart != selend) txt_setselect(session, selstart, selend);
  849. break;
  850. case MMCopy:
  851. if (selstart == selend || selstart < 0) break;
  852. clip_selection();
  853. break;
  854. case MMDelete:
  855. if (selstart == selend || selstart < 0) break;
  856. txt_movemarker(session, &session_marker, txt_dot(session));
  857. txt_setdot(session, txt_selectstart(session));
  858. txt_delete(session, txt_selectend(session)-txt_selectstart(session));
  859. txt_movedottomarker(session, &session_marker);
  860. wimp_source = from_keyboard;
  861. break;
  862. case MMClear:
  863. selstart = selend = -1;
  864. txt_setselect(session, 0, 0); /* Unset any selection */
  865. wimp_source = from_keyboard;
  866. break;
  867. }
  868. }
  869. static CSLbool CSL_create_txt(char *title)
  870. /*
  871. * returns YES if all went well
  872. */
  873. {
  874. /* Create a new txt object. The title passed here over-rides one in the
  875. template file (a bit of a pity, that?) */
  876. if ((session = txt_new(title)) == 0) return NO;
  877. txt_newmarker(session, &session_marker);
  878. clipboard_size = 128;
  879. if (!flex_alloc((flex_ptr)&clipboard, clipboard_size)) return NO;
  880. CSL_window_open = YES;
  881. if ((Main_menu = menu_new(appname+1,
  882. "Interrupt,Abort,Quit|>Save,SelectAll,Copy ^C,Delete ^X,Clear ^Z"
  883. )) == NULL)
  884. return NO;
  885. if (!event_attachmenu(txt_syshandle(session), Main_menu, Main_menuproc, 0))
  886. return NO;
  887. /* Attach an event handler for the txt */
  888. txt_eventhandler(session, CSL_txthandler, 0);
  889. /* Show the txt to the user */
  890. txt_show(session);
  891. /* Set "dot" at beginning */
  892. txt_setdot(session, 0);
  893. stdout_p = stdout_buffer;
  894. stdout_n = 0;
  895. win_claim_idle_events(txt_syshandle(session));
  896. event_setmask((wimp_emask)0); /* permits null events to show up */
  897. return YES;
  898. }
  899. /*
  900. * Icon Bar Icon.
  901. */
  902. static void CSL_clickproc(wimp_i i)
  903. {
  904. CSL_IGNORE(i);
  905. if (!CSL_window_open)
  906. { if (!CSL_create_txt(appname+1))
  907. werr(YES, "Unable to create text object - exiting");
  908. }
  909. }
  910. static void Iconbar_menuproc(void *handle, char *hit)
  911. {
  912. CSL_IGNORE(handle);
  913. switch (hit[0])
  914. {
  915. case MInfo:
  916. { dbox d;
  917. d = dbox_new("ProgInfo");
  918. if (d == 0) return;
  919. dbox_setfield(d, Vfield, CSL_version_string);
  920. dbox_show(d);
  921. dbox_fillin(d);
  922. dbox_dispose(&d);
  923. }
  924. break;
  925. case MQuit:
  926. exit(0);
  927. break;
  928. }
  929. }
  930. /*
  931. * Arrange that files can be loaded into CSL by dragging
  932. */
  933. static void CSL_load_events(wimp_eventstr *e, void *handle)
  934. {
  935. CSL_IGNORE(handle);
  936. if (e->e == wimp_ESEND || e->e == wimp_ESENDWANTACK)
  937. {
  938. if (CSL_window_open && e->data.msg.hdr.action == wimp_MDATALOAD)
  939. { char *filename;
  940. int filetype, len;
  941. filetype = xferrecv_checkinsert(&filename);
  942. if (filetype != -1)
  943. { len = strlen(LOADSTART) + strlen(filename) + strlen(LOADEND);
  944. if (tty_icount + len < TTYBUF_SIZE)
  945. { sprintf(&tty_ibuffer[tty_icount], "%s%s%s",
  946. LOADSTART, filename, LOADEND);
  947. tty_icount += len;
  948. txt_setdot(session, txt_size(session));
  949. txt_insertstring(session, LOADSTART);
  950. txt_setdot(session, txt_size(session));
  951. txt_insertstring(session, filename);
  952. txt_setdot(session, txt_size(session));
  953. txt_insertstring(session, LOADEND);
  954. txt_setdot(session, txt_size(session));
  955. }
  956. xferrecv_insertfileok();
  957. }
  958. }
  959. }
  960. }
  961. /*
  962. * Output procedures
  963. */
  964. static clock_t last_output_time;
  965. void flush_screen()
  966. /*
  967. * Bring screen up to date
  968. */
  969. {
  970. int n;
  971. if (!under_wimp)
  972. { fflush(stdout);
  973. return;
  974. }
  975. if (stdout_n == 0)
  976. { last_output_time = clock();
  977. return;
  978. }
  979. remove_ticker();
  980. delink();
  981. n = txt_size(session);
  982. /*
  983. * This code is intended to keep about around SCROLLBACK characters
  984. * buffered for the user to scroll back to. If I have more than SCROLLBACK
  985. * stored when I come to update the display I will discard some.
  986. */
  987. if (n > SCROLLBACK)
  988. { txt_setcharoptions(session, txt_DISPLAY, (txt_charoption)0);
  989. txt_setdot(session, 0);
  990. txt_delete(session, SCROLLBACK - n + stdout_n);
  991. txt_setdot(session, txt_size(session));
  992. txt_setcharoptions(session, txt_DISPLAY, txt_DISPLAY);
  993. n = txt_size(session);
  994. }
  995. if (n != txt_dot(session)) txt_setdot(session, txt_size(session));
  996. txt_insertstring(session, stdout_buffer);
  997. txt_setdot(session, txt_size(session));
  998. stdout_p = stdout_buffer;
  999. stdout_n = 0;
  1000. last_output_time = clock();
  1001. relink();
  1002. add_ticker();
  1003. }
  1004. static void remove_hourglass(void);
  1005. void pause_for_user()
  1006. /*
  1007. * This is called at the end of a run so that the user gets a chance to read
  1008. * the final screen-full of output. It pops up a dialog box that will
  1009. * wait for a button push. I take the view that if output is going to a
  1010. * file then the delay is not needed, since the user can always check for
  1011. * messages there. This has the effect that non-interactive build sequences
  1012. * will often run without the pause - a good thing! Note however that this
  1013. * mean that you MUST use the close box to exit from a wimp session. Just
  1014. * "quit;" or "(stop 0)" will not do. At least "quit;" etc pops up the
  1015. * dialog box you see here...
  1016. */
  1017. {
  1018. dbox d;
  1019. if (spool_file != NULL || !use_wimp) return;
  1020. ensure_screen();
  1021. remove_ticker();
  1022. delink();
  1023. remove_hourglass();
  1024. d = dbox_new("finished");
  1025. if (d == 0) return; /* Unable to find the "finish" dialog box */
  1026. dbox_show(d);
  1027. dbox_fillin(d);
  1028. dbox_dispose(&d);
  1029. return;
  1030. }
  1031. void putc_stdout(int c)
  1032. {
  1033. if (under_wimp)
  1034. { *stdout_p++ = c;
  1035. *stdout_p = 0;
  1036. stdout_n++;
  1037. if (stdout_n > STDOUT_BUFSIZE - LONGEST_PRINTF) ensure_screen();
  1038. if (polltick_pending) accept_tick();
  1039. }
  1040. else putchar(c);
  1041. }
  1042. static char txt_title[64];
  1043. static int last_gc_count=-1, last_t=-1, last_gct=-1;
  1044. static double last_percent;
  1045. void report_time(int32 t, int32 gct)
  1046. {
  1047. int pos;
  1048. if (!under_wimp) return;
  1049. sprintf(txt_title, "%s", appname+1);
  1050. pos = strlen(txt_title);
  1051. last_t = t;
  1052. last_gct = gct;
  1053. if (last_t != -1)
  1054. sprintf(&txt_title[pos], " time %ld.%.2ld+%ld.%.2ld secs",
  1055. last_t/100L, last_t%100L, last_gct/100L, last_gct%100L);
  1056. pos = strlen(txt_title);
  1057. if (last_gc_count != -1)
  1058. sprintf(&txt_title[pos], " GC %d [%.2f%% full]", last_gc_count, last_percent);
  1059. txt_settitle(session, txt_title);
  1060. }
  1061. void report_space(int gc_count, double percent)
  1062. {
  1063. last_gc_count = gc_count;
  1064. last_percent = percent;
  1065. report_time(last_t, last_gct);
  1066. }
  1067. /*
  1068. * Input procedures
  1069. */
  1070. static CSLbool hourglass_showing;
  1071. static void remove_hourglass()
  1072. {
  1073. if (hourglass_showing)
  1074. { os_swi0(Hourglass_Off);
  1075. hourglass_showing = NO;
  1076. }
  1077. }
  1078. int wimpget(char *tty_buffer)
  1079. /*
  1080. * This is the main call from the body of CSL into the window manager
  1081. * to obtain input from the user. It is expected to copy some input
  1082. * characters into tty_buffer and return the number of characters
  1083. * provided. In this implementation I keep a separate buffer called
  1084. * tty_ibuffer that characters are collected into - when either this
  1085. * gets full or a newline is inserted into it I copy it to tty_buffer
  1086. * and return.
  1087. * I will cancel copies from a selection if I have almost any mouse
  1088. * activity.
  1089. */
  1090. {
  1091. int n;
  1092. if (stdout_n != 0) ensure_screen();
  1093. mouse_directed_input:
  1094. switch (wimp_source)
  1095. {
  1096. case from_clipboard:
  1097. while (wimp_source == from_clipboard)
  1098. { int c = clipboard[clipboard_p++];
  1099. txt_setdot(session, txt_size(session));
  1100. txt_insertchar(session, c); /* insert the char */
  1101. txt_movedot(session, 1); /* advance the dot */
  1102. if (clipboard_p >= clipboard_n) wimp_source = from_keyboard;
  1103. tty_ibuffer[tty_icount++] = c;
  1104. /*
  1105. * If the line ended at buffer full or with a newline I return
  1106. * the completed buffer. Otherwise I will drop through to wait for
  1107. * keyboard input to finish off the line.
  1108. */
  1109. if (c == '\n' || tty_icount == TTYBUF_SIZE)
  1110. { memcpy(tty_buffer, tty_ibuffer, TTYBUF_SIZE);
  1111. n = tty_icount;
  1112. tty_icount = 0;
  1113. tty_ready = NO;
  1114. return n;
  1115. }
  1116. }
  1117. break;
  1118. case from_file:
  1119. case from_keyboard:
  1120. break;
  1121. }
  1122. remove_ticker();
  1123. delink();
  1124. remove_hourglass();
  1125. win_claim_idle_events(txt_syshandle(session));
  1126. event_setmask((wimp_emask)0); /* permits null events to show up */
  1127. while (!tty_ready && wimp_source == from_keyboard) event_process();
  1128. memcpy(tty_buffer, tty_ibuffer, TTYBUF_SIZE);
  1129. relink();
  1130. add_ticker();
  1131. if (wimp_source != from_keyboard) goto mouse_directed_input;
  1132. n = tty_icount;
  1133. tty_icount = 0;
  1134. tty_ready = NO;
  1135. return n;
  1136. }
  1137. /*
  1138. * Start-up code for the window manager
  1139. */
  1140. static int CSL_initialise()
  1141. {
  1142. wimp_save_fp_state_on_poll();
  1143. wimpt_init("Codemist Lisp");
  1144. flex_init();
  1145. res_init(appname+1);
  1146. msgs_init();
  1147. resspr_init();
  1148. template_use_fancyfonts();
  1149. template_init();
  1150. dbox_init();
  1151. txt_init();
  1152. /*
  1153. * Create menu to associate with icon-bar object and attach it
  1154. */
  1155. if ((Iconbar_menu = menu_new(appname+1, ">Info,Quit")) == NULL) return NO;
  1156. baricon(appname, 1, CSL_clickproc);
  1157. if (!event_attachmenu(win_ICONBAR, Iconbar_menu, Iconbar_menuproc, 0))
  1158. return NO;
  1159. /*
  1160. * Register function to get "unknown" events
  1161. */
  1162. win_register_event_handler(win_ICONBARLOAD, CSL_load_events, 0);
  1163. win_claim_unknown_events(win_ICONBARLOAD);
  1164. tty_count = tty_icount = 0;
  1165. tty_ready = NO;
  1166. return YES;
  1167. }
  1168. void accept_tick()
  1169. /*
  1170. * My clock ticks ensure that this procedure is called fairly regularly...
  1171. */
  1172. {
  1173. if (under_wimp)
  1174. {
  1175. clock_t c0 = clock();
  1176. /*
  1177. * Here I ensure that the screen is brought up to date at least every 3
  1178. * seconds or so.
  1179. */
  1180. if (last_output_time == 0 || c0 > last_output_time + 3*CLOCKS_PER_SEC)
  1181. { int t, gct;
  1182. if (clock_stack == &consolidated_time[0])
  1183. { consolidated_time[0] += (double)(c0 - base_time)/(double)CLOCKS_PER_SEC;
  1184. base_time = c0;
  1185. }
  1186. t = (int)(100.0 * consolidated_time[0]);
  1187. gct = (int)(100.0 * gc_time);
  1188. report_time(t, gct);
  1189. push_clock();
  1190. ensure_screen();
  1191. }
  1192. else push_clock();
  1193. /*
  1194. * I also poll the window manager so that other tasks can get a look in
  1195. * and so that my window responds to drag events and is generally kept
  1196. * up to date on the screen.
  1197. */
  1198. remove_ticker();
  1199. delink();
  1200. win_claim_idle_events(txt_syshandle(session));
  1201. event_setmask((wimp_emask)0); /* permits null events to show up */
  1202. do
  1203. { done_something = 0;
  1204. event_process();
  1205. } while (done_something);
  1206. relink();
  1207. add_ticker();
  1208. /*
  1209. * Time spent doing all of this is counted as "overhead" or "system time"
  1210. * and not included in the times that I will report to my users...
  1211. */
  1212. pop_clock();
  1213. polltick_pending = NO;
  1214. }
  1215. }
  1216. void start_up_window_manager(int use_wimp)
  1217. {
  1218. int i, r0;
  1219. if (!use_wimp)
  1220. { under_wimp = NO;
  1221. last_output_time = clock();
  1222. return;
  1223. }
  1224. os_swi1r(Wimp_ReadSysInfo, 0, &r0);
  1225. if (r0 == 0) under_wimp = NO;
  1226. else
  1227. { under_wimp = YES;
  1228. if (!CSL_initialise())
  1229. { fprintf(stderr, "\nFailed to start the window manager - stopping\n");
  1230. exit(EXIT_FAILURE);
  1231. }
  1232. /*
  1233. * Now I hang, doing not a lot, until the main window gets opened...
  1234. */
  1235. while (!CSL_window_open) event_process();
  1236. os_swi0(Hourglass_On);
  1237. hourglass_showing = YES;
  1238. atexit(remove_hourglass);
  1239. win_claim_idle_events(txt_syshandle(session));
  1240. event_setmask((wimp_emask)0); /* permits null events to show up */
  1241. for (i=0; i<5; i++) event_process();
  1242. /* Maybe helps things become visible? */
  1243. last_output_time = clock();
  1244. }
  1245. }
  1246. #include "fileops.c"
  1247. /* end of sysarm.c */