1 | /* |
---|
2 | Copyright 1991 by the Massachusetts Institute of Technology |
---|
3 | |
---|
4 | Permission to use, copy, modify, and distribute this |
---|
5 | software and its documentation for any purpose and without |
---|
6 | fee is hereby granted, provided that the above copyright |
---|
7 | notice appear in all copies and that both that copyright |
---|
8 | notice and this permission notice appear in supporting |
---|
9 | documentation, and that the name of M.I.T. not be used in |
---|
10 | advertising or publicity pertaining to distribution of the |
---|
11 | software without specific, written prior permission. |
---|
12 | M.I.T. makes no representations about the suitability of |
---|
13 | this software for any purpose. It is provided "as is" |
---|
14 | without express or implied warranty. |
---|
15 | */ |
---|
16 | |
---|
17 | #include <unistd.h> |
---|
18 | #include <stdio.h> |
---|
19 | #include <string.h> |
---|
20 | #include <fcntl.h> |
---|
21 | |
---|
22 | #include <X11/IntrinsicP.h> |
---|
23 | #include <X11/StringDefs.h> |
---|
24 | #include <X11/CoreP.h> |
---|
25 | |
---|
26 | #include <X11/Xaw/MenuButton.h> |
---|
27 | #include <X11/Xaw/SimpleMenu.h> |
---|
28 | #include <X11/Xaw/Sme.h> |
---|
29 | #include <X11/Xaw/SmeBSB.h> |
---|
30 | #include <X11/Xaw/Cardinals.h> |
---|
31 | |
---|
32 | #include <X11/Xaw/List.h> |
---|
33 | #include <X11/Xaw/SimpleMenP.h> |
---|
34 | #include <X11/Xaw/Paned.h> |
---|
35 | #include <X11/Xaw/Command.h> |
---|
36 | #include <X11/Xaw/Box.h> |
---|
37 | #include <X11/Xaw/AsciiText.h> |
---|
38 | #include <X11/Xaw/TextP.h> |
---|
39 | #include <X11/Xaw/TextSinkP.h> |
---|
40 | #include <X11/Xaw/Dialog.h> |
---|
41 | #include <X11/Xaw/Form.h> |
---|
42 | #include <X11/Xaw/Label.h> |
---|
43 | |
---|
44 | #include "xdsc.h" |
---|
45 | |
---|
46 | static char rcsid[] = "$Id: xdsc.c,v 1.35 1999-12-16 01:58:24 danw Exp $"; |
---|
47 | |
---|
48 | /* |
---|
49 | ** Globals |
---|
50 | */ |
---|
51 | |
---|
52 | char *RunCommand(); |
---|
53 | TextWidget toptextW, bottextW; |
---|
54 | Boolean debug = False; |
---|
55 | char filebase[50]; |
---|
56 | int topscreen = MAIN; |
---|
57 | Widget topW, paneW; |
---|
58 | void RemoveLetterC(); |
---|
59 | int char_width; |
---|
60 | char axis[10]; |
---|
61 | void TopSelect(), BotSelect(); |
---|
62 | void Update(), Stub(); |
---|
63 | void PrintEvent(); |
---|
64 | int simplemode = 0; |
---|
65 | int edscversion; |
---|
66 | Boolean nocache; |
---|
67 | |
---|
68 | /* |
---|
69 | ** External functions |
---|
70 | */ |
---|
71 | |
---|
72 | extern void PutUpHelp(); |
---|
73 | extern void SubmitTransaction(); |
---|
74 | extern void WriteTransaction(); |
---|
75 | extern char *tempnam(); |
---|
76 | extern int PopdownCB(); |
---|
77 | extern char *getenv(); |
---|
78 | extern void TriggerAdd(), TriggerNum(), TriggerDelete(); |
---|
79 | extern void TriggerWrite(), TriggerPopdown(), TriggerSend(); |
---|
80 | extern void TriggerFocusMove(); |
---|
81 | extern void DispatchClick(); |
---|
82 | extern void FetchIfNecessary(); |
---|
83 | extern int HighlightedTransaction(); |
---|
84 | |
---|
85 | /* |
---|
86 | ** Private functions |
---|
87 | */ |
---|
88 | |
---|
89 | static void MenuCallback(); |
---|
90 | static void KeyCallback(); |
---|
91 | static void QuitCB(), HelpCB(); |
---|
92 | static void BuildUserInterface(); |
---|
93 | static void DoTheRightThing(); |
---|
94 | static void DoTheRightThingInReverse(); |
---|
95 | static void CheckEdscVersion(); |
---|
96 | static void BuildSkeleton(); |
---|
97 | static unsigned long GetFontWidth(); |
---|
98 | |
---|
99 | /* |
---|
100 | ** Private globals |
---|
101 | */ |
---|
102 | |
---|
103 | static int filedesparent[2], filedeschild[2]; |
---|
104 | static FILE *inputfile, *outputfile; |
---|
105 | static char *meetinglist; |
---|
106 | |
---|
107 | static Widget topboxW, botboxW; |
---|
108 | static Widget label1W; |
---|
109 | static int prevfirst = 0; |
---|
110 | static XawTextPosition startOfCurrentMeeting = -1; |
---|
111 | Display *dpy; |
---|
112 | Window root_window; |
---|
113 | static XawTextPosition oldarrow = -1; |
---|
114 | |
---|
115 | /* |
---|
116 | ** Data for top row of buttons |
---|
117 | */ |
---|
118 | |
---|
119 | static char * menu_labels0[MAX_BUTTONS] = { |
---|
120 | "Down", "Up", "update", "configure", "mode", |
---|
121 | "show", "HELP", "QUIT"}; |
---|
122 | |
---|
123 | static char * menu_names0[MAX_BUTTONS] = { |
---|
124 | "downbutton", "upbutton", "updatebutton", "configurebutton", |
---|
125 | "modebutton", "showbutton", "helpbutton", "quitbutton"}; |
---|
126 | |
---|
127 | static char * submenu_labels0[MAX_BUTTONS][MAX_MENU_LEN] = { |
---|
128 | { NULL, NULL, NULL, NULL }, |
---|
129 | { NULL, NULL, NULL, NULL }, |
---|
130 | { NULL, NULL, NULL, NULL }, |
---|
131 | { "add meeting", "delete meeting", NULL, NULL }, |
---|
132 | { "transactions", "meetings", NULL, NULL }, |
---|
133 | { "unread", "all", "back ten", NULL }, |
---|
134 | { NULL, NULL, NULL, NULL }, |
---|
135 | { NULL, NULL, NULL, NULL }}; |
---|
136 | |
---|
137 | static char * submenu_names0[MAX_BUTTONS][MAX_MENU_LEN] = { |
---|
138 | { NULL, NULL, NULL, NULL }, |
---|
139 | { NULL, NULL, NULL, NULL }, |
---|
140 | { NULL, NULL, NULL, NULL }, |
---|
141 | { "addbutton", "deletebutton", NULL, NULL }, |
---|
142 | { "transbutton", "meetingbutton", NULL, NULL }, |
---|
143 | { "unreadbutton", "allbutton", "backbutton", NULL }, |
---|
144 | { NULL, NULL, NULL, NULL }, |
---|
145 | { NULL, NULL, NULL, NULL }}; |
---|
146 | |
---|
147 | /* |
---|
148 | ** Data for bottom row of buttons |
---|
149 | */ |
---|
150 | |
---|
151 | static char * menu_labels1[MAX_BUTTONS] = { |
---|
152 | "next", "prev", "Next in chain", "Prev in chain", |
---|
153 | "goto", "enter", "write", NULL }; |
---|
154 | |
---|
155 | static char * menu_names1[MAX_BUTTONS] = { |
---|
156 | "nextbutton", "prevbutton", "nchainbutton", "pchainbutton", |
---|
157 | "gotobutton", "enterbutton", "writebutton", NULL }; |
---|
158 | |
---|
159 | static char * submenu_labels1[MAX_BUTTONS][MAX_MENU_LEN] = { |
---|
160 | { NULL, NULL, NULL, NULL }, |
---|
161 | { NULL, NULL, NULL, NULL }, |
---|
162 | { NULL, NULL, NULL, NULL }, |
---|
163 | { NULL, NULL, NULL, NULL }, |
---|
164 | { "number", "first", "last", "start of chain", "end of chain", NULL }, |
---|
165 | { "reply", "new transaction", NULL }, |
---|
166 | { "write to file", "mail to someone", NULL }}; |
---|
167 | |
---|
168 | static char * submenu_names1[MAX_BUTTONS][MAX_MENU_LEN] = { |
---|
169 | { NULL, NULL, NULL, NULL }, |
---|
170 | { NULL, NULL, NULL, NULL }, |
---|
171 | { NULL, NULL, NULL, NULL }, |
---|
172 | { NULL, NULL, NULL, NULL }, |
---|
173 | { "numberbutton", "firstbutton", "lastbutton", "frefbutton", "lrefbutton",NULL }, |
---|
174 | { "replybutton", "newbutton", NULL }, |
---|
175 | { "writebutton", "mailbutton", NULL }}; |
---|
176 | |
---|
177 | |
---|
178 | EntryRec toplevelbuttons[2][MAX_BUTTONS]; |
---|
179 | |
---|
180 | void |
---|
181 | main(argc, argv) |
---|
182 | int argc; |
---|
183 | char *argv[]; |
---|
184 | { |
---|
185 | int pid; |
---|
186 | char *oldpath, *newpath, *myname; |
---|
187 | Arg args[1]; |
---|
188 | int width; |
---|
189 | char commandline[100]; |
---|
190 | |
---|
191 | if (argc > 1 && !strcmp(argv[1], "-debug")) |
---|
192 | debug = True; |
---|
193 | |
---|
194 | myname = (myname = strrchr(argv[0], '/')) ? myname + 1 : argv[0]; |
---|
195 | |
---|
196 | if (!strcmp (myname, "lucy")) |
---|
197 | simplemode = True; |
---|
198 | else |
---|
199 | simplemode = False; |
---|
200 | |
---|
201 | if (simplemode) { |
---|
202 | topW = XtInitialize("topwidget", "Lucy", NULL, 0, &argc, argv); |
---|
203 | } |
---|
204 | else |
---|
205 | topW = XtInitialize("topwidget", "Xdsc", NULL, 0, &argc, argv); |
---|
206 | |
---|
207 | BuildSkeleton(); |
---|
208 | |
---|
209 | /* |
---|
210 | ** Set our width to 80 chars wide in the current font. Min value of 500 |
---|
211 | ** means that all the lower buttons will fit. |
---|
212 | |
---|
213 | original code |
---|
214 | char_width = (((TextSinkObject) (toptextW->text.sink))-> |
---|
215 | text_sink.font->max_bounds.width); |
---|
216 | |
---|
217 | removed because font parameter is either private or nonexistent (private in |
---|
218 | mit Xaw include files, nonexistent in others). |
---|
219 | |
---|
220 | borrowed code from Xaw/TextSink.c to write a generic GetFontWidth routine. |
---|
221 | rearranged some to use font resource, rather than accessing internals. |
---|
222 | |
---|
223 | mdb 7/26/96 |
---|
224 | |
---|
225 | */ |
---|
226 | |
---|
227 | char_width = (int)GetFontWidth(toptextW); |
---|
228 | width = 80 * char_width; |
---|
229 | XtSetArg(args[0], XtNwidth, width < 500 ? 500 : width); |
---|
230 | XtSetValues(topW, args, 1); |
---|
231 | |
---|
232 | /* |
---|
233 | XtRealizeWidget(topW); |
---|
234 | XSync(XtDisplay(topW), False); |
---|
235 | */ |
---|
236 | |
---|
237 | if (debug) |
---|
238 | fprintf (stderr, "Debugging is on\n"); |
---|
239 | |
---|
240 | sprintf (filebase,"/var/tmp/xdsc%d",getpid()); |
---|
241 | |
---|
242 | if (debug) |
---|
243 | fprintf (stderr, "filebase is %s\n", filebase); |
---|
244 | |
---|
245 | pipe (filedesparent); |
---|
246 | pipe (filedeschild); |
---|
247 | |
---|
248 | pid = fork(); |
---|
249 | |
---|
250 | if (pid == 0) |
---|
251 | SetUpEdsc(); |
---|
252 | |
---|
253 | close (filedesparent[1]); |
---|
254 | close (filedeschild[0]); |
---|
255 | |
---|
256 | inputfile = fdopen (filedesparent[0], "r"); |
---|
257 | outputfile = fdopen (filedeschild[1], "w"); |
---|
258 | |
---|
259 | CheckEdscVersion(); |
---|
260 | ParseMeetingsFile(); |
---|
261 | |
---|
262 | oldpath = getenv("XFILESEARCHPATH"); |
---|
263 | |
---|
264 | BuildUserInterface(); |
---|
265 | XtRealizeWidget(topW); |
---|
266 | |
---|
267 | dpy = XtDisplay(topW); |
---|
268 | root_window = XtWindow(topW); |
---|
269 | |
---|
270 | (void) MoveToMeeting(INITIALIZE); |
---|
271 | /* |
---|
272 | ** If running in simplemode, switch to reading transactions and put up |
---|
273 | ** the list of unread ones. |
---|
274 | */ |
---|
275 | if (simplemode) { |
---|
276 | TopSelect (NULL, 4, NULL); |
---|
277 | BotSelect (NULL, 0, NULL); |
---|
278 | } |
---|
279 | CheckButtonSensitivity(BUTTONS_UPDATE); |
---|
280 | XtMainLoop(); |
---|
281 | } |
---|
282 | |
---|
283 | SetUpEdsc() |
---|
284 | { |
---|
285 | int retval; |
---|
286 | char commandtorun[50]; |
---|
287 | char machtype[20]; |
---|
288 | char *envcommand; |
---|
289 | |
---|
290 | envcommand = getenv("EDSC"); |
---|
291 | strcpy (commandtorun, envcommand ? envcommand : EDSC_PATH); |
---|
292 | |
---|
293 | close (filedesparent[0]); |
---|
294 | close (filedeschild[1]); |
---|
295 | |
---|
296 | dup2 (filedeschild[0], 0); |
---|
297 | dup2 (filedesparent[1], 1); |
---|
298 | |
---|
299 | if (debug) |
---|
300 | fprintf (stderr,"commandtorun = '%s'\n", commandtorun); |
---|
301 | |
---|
302 | retval = execlp (commandtorun, commandtorun, 0); |
---|
303 | |
---|
304 | fprintf (stderr, "Fatal error: Unable to exec '%s'\n",commandtorun); |
---|
305 | _exit (-1); |
---|
306 | } |
---|
307 | |
---|
308 | /* |
---|
309 | ** Put up enough of the application that the user doesn't think it's hung... |
---|
310 | */ |
---|
311 | |
---|
312 | static void |
---|
313 | BuildSkeleton() |
---|
314 | { |
---|
315 | Arg args[5]; |
---|
316 | unsigned int n; |
---|
317 | static XtActionsRec actions[] = { |
---|
318 | {"FetchIfNecessary", FetchIfNecessary}, |
---|
319 | {"MenuCallback", MenuCallback}, |
---|
320 | {"KeyCallback", KeyCallback}, |
---|
321 | {"Update", Update}, |
---|
322 | {"DispatchClick", DispatchClick}, |
---|
323 | {"TriggerAdd", TriggerAdd}, |
---|
324 | {"TriggerDelete", TriggerDelete}, |
---|
325 | {"TriggerFocusMove", TriggerFocusMove}, |
---|
326 | {"TriggerNum", TriggerNum}, |
---|
327 | {"TriggerPopdown", TriggerPopdown}, |
---|
328 | {"TriggerSend", TriggerSend}, |
---|
329 | {"TriggerWrite", TriggerWrite}, |
---|
330 | {"DoTheRightThing", DoTheRightThing}, |
---|
331 | {"DoTheRightThingInReverse", DoTheRightThingInReverse}, |
---|
332 | {"HelpCB", HelpCB}, |
---|
333 | {"QuitCB", QuitCB}, |
---|
334 | {"PopdownCB", (XtActionProc) PopdownCB}, |
---|
335 | {"Stub", Stub}, |
---|
336 | {"PrintEvent", PrintEvent}}; |
---|
337 | |
---|
338 | |
---|
339 | n = 0; |
---|
340 | paneW = XtCreateManagedWidget( |
---|
341 | "pane", |
---|
342 | panedWidgetClass, |
---|
343 | topW, |
---|
344 | args, |
---|
345 | n); |
---|
346 | |
---|
347 | n = 0; |
---|
348 | topboxW = XtCreateManagedWidget( |
---|
349 | "topbox", |
---|
350 | boxWidgetClass, |
---|
351 | paneW, |
---|
352 | args, |
---|
353 | n); |
---|
354 | |
---|
355 | XtAppAddActions ( XtWidgetToApplicationContext(topboxW), |
---|
356 | actions, XtNumber(actions)); |
---|
357 | |
---|
358 | XawSimpleMenuAddGlobalActions(XtWidgetToApplicationContext(topboxW)); |
---|
359 | |
---|
360 | AddChildren (topboxW, 0); |
---|
361 | |
---|
362 | n = 0; |
---|
363 | XtSetArg(args[n], XtNstring, "Please wait..."); n++; |
---|
364 | XtSetArg(args[n], XtNeditType, XawtextEdit); n++; |
---|
365 | XtSetArg(args[n], XtNuseStringInPlace, False); n++; |
---|
366 | |
---|
367 | toptextW = (TextWidget) XtCreateManagedWidget( |
---|
368 | "toptext", |
---|
369 | asciiTextWidgetClass, |
---|
370 | paneW, |
---|
371 | args, |
---|
372 | n); |
---|
373 | |
---|
374 | n = 0; |
---|
375 | XtSetArg(args[n], XtNeditType, XawtextRead); n++; |
---|
376 | label1W = XtCreateManagedWidget( |
---|
377 | "label", |
---|
378 | asciiTextWidgetClass, |
---|
379 | paneW, |
---|
380 | args, |
---|
381 | n); |
---|
382 | |
---|
383 | n = 0; |
---|
384 | botboxW = XtCreateWidget( |
---|
385 | "botbox", |
---|
386 | boxWidgetClass, |
---|
387 | paneW, |
---|
388 | args, |
---|
389 | n); |
---|
390 | |
---|
391 | AddChildren (botboxW, 1); |
---|
392 | |
---|
393 | if (!simplemode) |
---|
394 | XtManageChild (botboxW); |
---|
395 | |
---|
396 | n = 0; |
---|
397 | XtSetArg(args[n], XtNeditType, XawtextRead); n++; |
---|
398 | bottextW = (TextWidget) XtCreateManagedWidget( |
---|
399 | "bottext", |
---|
400 | asciiTextWidgetClass, |
---|
401 | paneW, |
---|
402 | args, |
---|
403 | n); |
---|
404 | } |
---|
405 | |
---|
406 | static void |
---|
407 | BuildUserInterface() |
---|
408 | { |
---|
409 | Arg args[5]; |
---|
410 | unsigned int n; |
---|
411 | Dimension foo; |
---|
412 | |
---|
413 | static XtActionsRec actions[] = { |
---|
414 | {"FetchIfNecessary", FetchIfNecessary}, |
---|
415 | {"MenuCallback", MenuCallback}, |
---|
416 | {"KeyCallback", KeyCallback}, |
---|
417 | {"Update", Update}, |
---|
418 | {"DispatchClick", DispatchClick}, |
---|
419 | {"TriggerAdd", TriggerAdd}, |
---|
420 | {"TriggerDelete", TriggerDelete}, |
---|
421 | {"TriggerFocusMove", TriggerFocusMove}, |
---|
422 | {"TriggerNum", TriggerNum}, |
---|
423 | {"TriggerPopdown", TriggerPopdown}, |
---|
424 | {"TriggerSend", TriggerSend}, |
---|
425 | {"TriggerWrite", TriggerWrite}, |
---|
426 | {"DoTheRightThing", DoTheRightThing}, |
---|
427 | {"DoTheRightThingInReverse", DoTheRightThingInReverse}, |
---|
428 | {"HelpCB", HelpCB}, |
---|
429 | {"QuitCB", QuitCB}, |
---|
430 | {"PopdownCB", (XtActionProc) PopdownCB}, |
---|
431 | {"Stub", Stub}, |
---|
432 | {"PrintEvent", PrintEvent}}; |
---|
433 | |
---|
434 | /* |
---|
435 | n = 0; |
---|
436 | paneW = XtCreateManagedWidget( |
---|
437 | "pane", |
---|
438 | panedWidgetClass, |
---|
439 | topW, |
---|
440 | args, |
---|
441 | n); |
---|
442 | |
---|
443 | |
---|
444 | n = 0; |
---|
445 | topboxW = XtCreateManagedWidget( |
---|
446 | "topbox", |
---|
447 | boxWidgetClass, |
---|
448 | paneW, |
---|
449 | args, |
---|
450 | n); |
---|
451 | |
---|
452 | XtAppAddActions ( XtWidgetToApplicationContext(topboxW), |
---|
453 | actions, XtNumber(actions)); |
---|
454 | |
---|
455 | XawSimpleMenuAddGlobalActions(XtWidgetToApplicationContext(topboxW)); |
---|
456 | |
---|
457 | AddChildren (topboxW, 0); |
---|
458 | */ |
---|
459 | |
---|
460 | n = 0; |
---|
461 | XtSetArg(args[n], XtNstring, meetinglist); n++; |
---|
462 | XtSetValues(toptextW, args, n); |
---|
463 | |
---|
464 | /* |
---|
465 | n = 0; |
---|
466 | XtSetArg(args[n], XtNstring, meetinglist); n++; |
---|
467 | XtSetArg(args[n], XtNeditType, XawtextEdit); n++; |
---|
468 | XtSetArg(args[n], XtNuseStringInPlace, False); n++; |
---|
469 | |
---|
470 | toptextW = (TextWidget) XtCreateManagedWidget( |
---|
471 | "toptext", |
---|
472 | asciiTextWidgetClass, |
---|
473 | paneW, |
---|
474 | args, |
---|
475 | n); |
---|
476 | */ |
---|
477 | |
---|
478 | /* |
---|
479 | n = 0; |
---|
480 | XtSetArg(args[n], XtNeditType, XawtextRead); n++; |
---|
481 | label1W = XtCreateManagedWidget( |
---|
482 | "label", |
---|
483 | asciiTextWidgetClass, |
---|
484 | paneW, |
---|
485 | args, |
---|
486 | n); |
---|
487 | |
---|
488 | n = 0; |
---|
489 | botboxW = XtCreateWidget( |
---|
490 | "botbox", |
---|
491 | boxWidgetClass, |
---|
492 | paneW, |
---|
493 | args, |
---|
494 | n); |
---|
495 | |
---|
496 | AddChildren (botboxW, 1); |
---|
497 | |
---|
498 | if (!simplemode) { |
---|
499 | XtManageChild (botboxW); |
---|
500 | } |
---|
501 | |
---|
502 | n = 0; |
---|
503 | XtSetArg(args[n], XtNeditType, XawtextRead); n++; |
---|
504 | bottextW = (TextWidget) XtCreateManagedWidget( |
---|
505 | "bottext", |
---|
506 | asciiTextWidgetClass, |
---|
507 | paneW, |
---|
508 | args, |
---|
509 | n); |
---|
510 | */ |
---|
511 | |
---|
512 | /* |
---|
513 | ** Add the pane's accelerators to the text widgets and the other kids. |
---|
514 | */ |
---|
515 | XtInstallAccelerators(toptextW, paneW); |
---|
516 | XtInstallAccelerators(bottextW, paneW); |
---|
517 | XtInstallAllAccelerators(paneW, paneW); |
---|
518 | |
---|
519 | } |
---|
520 | |
---|
521 | /* |
---|
522 | ** MenuCallback is called for key hits on menu entries. |
---|
523 | ** It gets two parameters: First, the number of the menubutton |
---|
524 | ** secondly, the index of the entry in the menu. It |
---|
525 | ** packs the two parameters into an int and manually calls TopSelect(). |
---|
526 | */ |
---|
527 | |
---|
528 | static void |
---|
529 | MenuCallback(w, event, params, num_params) |
---|
530 | Widget w; |
---|
531 | XEvent *event; |
---|
532 | String *params; |
---|
533 | int *num_params; |
---|
534 | { |
---|
535 | int buttonnum, entrynum; |
---|
536 | int whichrow; |
---|
537 | |
---|
538 | if (*num_params != 2) |
---|
539 | goto ABORT; |
---|
540 | |
---|
541 | for (buttonnum = 0; buttonnum < MAX_BUTTONS; buttonnum++) { |
---|
542 | if ( menu_names0[buttonnum] && |
---|
543 | !strcmp(menu_names0[buttonnum], params[0])) { |
---|
544 | whichrow = 0; |
---|
545 | break; |
---|
546 | } |
---|
547 | if ( menu_names1[buttonnum] && |
---|
548 | !strcmp(menu_names1[buttonnum], params[0])) { |
---|
549 | whichrow = 1; |
---|
550 | break; |
---|
551 | } |
---|
552 | } |
---|
553 | |
---|
554 | if (buttonnum == MAX_BUTTONS) |
---|
555 | goto ABORT; |
---|
556 | |
---|
557 | for (entrynum = 0; entrynum < MAX_MENU_LEN; entrynum++) { |
---|
558 | if (whichrow == 0) { |
---|
559 | if ( submenu_names0[buttonnum][entrynum] && |
---|
560 | !strcmp(submenu_names0[buttonnum][entrynum], |
---|
561 | params[1])) |
---|
562 | break; |
---|
563 | } |
---|
564 | else { |
---|
565 | if ( submenu_names1[buttonnum][entrynum] && |
---|
566 | !strcmp(submenu_names1[buttonnum][entrynum], |
---|
567 | params[1])) |
---|
568 | break; |
---|
569 | } |
---|
570 | } |
---|
571 | |
---|
572 | if (entrynum == MAX_MENU_LEN) |
---|
573 | goto ABORT; |
---|
574 | |
---|
575 | /* |
---|
576 | ** If a menu item was selected, popdown the menu and relinquish keyboard focus. |
---|
577 | */ |
---|
578 | if (whichrow == 0) |
---|
579 | TopSelect (NULL, buttonnum + (entrynum << 4)); |
---|
580 | else |
---|
581 | BotSelect (NULL, buttonnum + (entrynum << 4)); |
---|
582 | |
---|
583 | if (XtIsSubclass (w, simpleMenuWidgetClass)) |
---|
584 | XtPopdown(w); |
---|
585 | XtSetKeyboardFocus(topW, paneW); |
---|
586 | return; |
---|
587 | |
---|
588 | ABORT: |
---|
589 | |
---|
590 | if (XtIsSubclass (w, simpleMenuWidgetClass)) |
---|
591 | XtPopdown(w); |
---|
592 | XtSetKeyboardFocus(topW, paneW); |
---|
593 | } |
---|
594 | |
---|
595 | /* |
---|
596 | ** TopSelect is called either automatically through the select callback |
---|
597 | ** on a button, or manually through TopCallback when triggered by a |
---|
598 | ** key hit. |
---|
599 | */ |
---|
600 | |
---|
601 | void |
---|
602 | TopSelect(w, client_data, call_data) |
---|
603 | Widget w; /*IGNORED*/ |
---|
604 | XtPointer client_data; |
---|
605 | XtPointer call_data; |
---|
606 | { |
---|
607 | int buttonnum, entrynum; |
---|
608 | Arg args[5]; |
---|
609 | unsigned int n; |
---|
610 | |
---|
611 | entrynum = ((int) client_data) >> 4; |
---|
612 | buttonnum = ((int) client_data) & 0x0F; |
---|
613 | |
---|
614 | switch (buttonnum) { |
---|
615 | /* |
---|
616 | ** Move to next or previous meeting if topscreen is showing meetings, |
---|
617 | ** to next or previous transaction otherwise |
---|
618 | */ |
---|
619 | case 0: |
---|
620 | if (topscreen == MAIN) { |
---|
621 | (void) MoveToMeeting(NEXTNEWS); |
---|
622 | } |
---|
623 | else { |
---|
624 | BotSelect (NULL, 0, NULL); |
---|
625 | } |
---|
626 | break; |
---|
627 | |
---|
628 | case 1: |
---|
629 | if (topscreen == MAIN) { |
---|
630 | (void) MoveToMeeting(PREVNEWS); |
---|
631 | } |
---|
632 | else { |
---|
633 | BotSelect (NULL, 1, NULL); |
---|
634 | } |
---|
635 | break; |
---|
636 | /* |
---|
637 | ** Check for changed meetings |
---|
638 | */ |
---|
639 | case 2: |
---|
640 | MarkLastRead(); |
---|
641 | PutUpTempMessage("Rereading meeting list..."); |
---|
642 | ParseMeetingsFile(); |
---|
643 | n = 0; |
---|
644 | XtSetArg(args[n], XtNstring, meetinglist); n++; |
---|
645 | XtSetValues(toptextW, args, n); |
---|
646 | TakeDownTempMessage(); |
---|
647 | InvalidateHeaders(); |
---|
648 | MoveToMeeting(INITIALIZE); |
---|
649 | break; |
---|
650 | |
---|
651 | /* |
---|
652 | ** configure |
---|
653 | */ |
---|
654 | case 3: |
---|
655 | switch (entrynum) { |
---|
656 | case 0: |
---|
657 | AddMeeting(); |
---|
658 | break; |
---|
659 | case 1: |
---|
660 | DeleteMeeting(); |
---|
661 | break; |
---|
662 | } |
---|
663 | break; |
---|
664 | |
---|
665 | /* |
---|
666 | ** mode |
---|
667 | */ |
---|
668 | case 4: |
---|
669 | switch (entrynum) { |
---|
670 | case 0: |
---|
671 | /* |
---|
672 | ** Put up list of transactions within the current meeting |
---|
673 | */ |
---|
674 | prevfirst = TransactionNum(CURRENT); |
---|
675 | PutUpTransactionList( TransactionNum(CURRENT), |
---|
676 | TransactionNum(LAST)); |
---|
677 | topscreen = LISTTRNS; |
---|
678 | UpdateHighlightedTransaction(TransactionNum(CURRENT),True); |
---|
679 | break; |
---|
680 | case 1: |
---|
681 | /* |
---|
682 | ** Put up list of meetings |
---|
683 | */ |
---|
684 | topscreen = MAIN; |
---|
685 | RestoreTopTextWidget(); |
---|
686 | if ( TransactionNum(HIGHESTSEEN) == |
---|
687 | TransactionNum(LAST)) |
---|
688 | RemoveLetterC(); |
---|
689 | break; |
---|
690 | } |
---|
691 | break; |
---|
692 | |
---|
693 | /* |
---|
694 | ** show |
---|
695 | */ |
---|
696 | case 5: |
---|
697 | if (topscreen != LISTTRNS) |
---|
698 | break; |
---|
699 | switch (entrynum) { |
---|
700 | case 0: |
---|
701 | PutUpTransactionList( |
---|
702 | TransactionNum(HIGHESTSEEN), TransactionNum(LAST)); |
---|
703 | prevfirst = TransactionNum(HIGHESTSEEN); |
---|
704 | UpdateHighlightedTransaction(TransactionNum(CURRENT),True); |
---|
705 | break; |
---|
706 | case 1: |
---|
707 | PutUpTransactionList( |
---|
708 | TransactionNum(FIRST), TransactionNum(LAST)); |
---|
709 | prevfirst = TransactionNum(FIRST); |
---|
710 | UpdateHighlightedTransaction(TransactionNum(CURRENT),True); |
---|
711 | break; |
---|
712 | case 2: |
---|
713 | PutUpTransactionList( prevfirst <= 10 ? 1 : prevfirst - 10, |
---|
714 | TransactionNum(LAST)); |
---|
715 | UpdateHighlightedTransaction(prevfirst - 1,True); |
---|
716 | |
---|
717 | prevfirst -= 10; |
---|
718 | if (prevfirst <=0) prevfirst = 1; |
---|
719 | break; |
---|
720 | } |
---|
721 | break; |
---|
722 | |
---|
723 | case 6: |
---|
724 | PutUpHelp(); |
---|
725 | break; |
---|
726 | case 7: |
---|
727 | QuitCB (NULL, NULL, NULL); |
---|
728 | break; |
---|
729 | } |
---|
730 | } |
---|
731 | |
---|
732 | void |
---|
733 | BotSelect(w, client_data, call_data) |
---|
734 | Widget w; /*IGNORED*/ |
---|
735 | XtPointer client_data; |
---|
736 | XtPointer call_data; |
---|
737 | { |
---|
738 | int buttonnum, entrynum; |
---|
739 | |
---|
740 | entrynum = ((int) client_data) >> 4; |
---|
741 | buttonnum = ((int) client_data) & 0x0F; |
---|
742 | |
---|
743 | switch (buttonnum) { |
---|
744 | |
---|
745 | case 0: |
---|
746 | if (TransactionNum(CURRENT) < TransactionNum(LAST)) |
---|
747 | GoToTransaction(NEXT, True); |
---|
748 | else |
---|
749 | GoToTransaction(CURRENT, True); |
---|
750 | break; |
---|
751 | |
---|
752 | case 1: |
---|
753 | GoToTransaction(PREV, True); |
---|
754 | break; |
---|
755 | case 2: |
---|
756 | GoToTransaction(NREF, True); |
---|
757 | break; |
---|
758 | case 3: |
---|
759 | GoToTransaction(PREF, True); |
---|
760 | break; |
---|
761 | case 4: |
---|
762 | switch (entrynum) { |
---|
763 | case 0: |
---|
764 | GetTransactionNum(); |
---|
765 | break; |
---|
766 | case 1: |
---|
767 | GoToTransaction(FIRST, True); |
---|
768 | break; |
---|
769 | case 2: |
---|
770 | GoToTransaction(LAST, True); |
---|
771 | break; |
---|
772 | case 3: |
---|
773 | GoToTransaction(FREF, True); |
---|
774 | break; |
---|
775 | case 4: |
---|
776 | GoToTransaction(LREF, True); |
---|
777 | break; |
---|
778 | } |
---|
779 | break; |
---|
780 | case 5: |
---|
781 | switch (entrynum) { |
---|
782 | case 0: |
---|
783 | if (axis[0] != ' ') |
---|
784 | SubmitTransaction(TransactionNum(CURRENT)); |
---|
785 | break; |
---|
786 | case 1: |
---|
787 | if (axis[6] != ' ') |
---|
788 | SubmitTransaction(0); |
---|
789 | break; |
---|
790 | } |
---|
791 | /* |
---|
792 | ** This makes the buttons update to reflect the new transaction. |
---|
793 | */ |
---|
794 | GoToTransaction(CURRENT, False); |
---|
795 | break; |
---|
796 | case 6: |
---|
797 | switch (entrynum) { |
---|
798 | case 0: |
---|
799 | WriteTransaction(TransactionNum(CURRENT)); |
---|
800 | break; |
---|
801 | case 1: |
---|
802 | break; |
---|
803 | } |
---|
804 | break; |
---|
805 | default: |
---|
806 | fprintf (stderr,"Stub function\n"); |
---|
807 | } |
---|
808 | |
---|
809 | } |
---|
810 | |
---|
811 | RestoreTopTextWidget() |
---|
812 | { |
---|
813 | Arg args[1]; |
---|
814 | unsigned int n; |
---|
815 | |
---|
816 | CheckButtonSensitivity(BUTTONS_ON); |
---|
817 | |
---|
818 | n = 0; |
---|
819 | XtSetArg(args[n], XtNstring, meetinglist); n++; |
---|
820 | XtSetValues (toptextW, args, n); |
---|
821 | PutUpArrow(toptextW, startOfCurrentMeeting, True); |
---|
822 | } |
---|
823 | |
---|
824 | |
---|
825 | |
---|
826 | static void |
---|
827 | QuitCB(w, client_data, call_data) |
---|
828 | Widget w; |
---|
829 | XtPointer client_data; |
---|
830 | XtPointer call_data; |
---|
831 | { |
---|
832 | (void) SaveMeetingNames("", ""); |
---|
833 | |
---|
834 | fputs("(quit)\n", outputfile); |
---|
835 | fflush (outputfile); |
---|
836 | exit (0); |
---|
837 | } |
---|
838 | |
---|
839 | static void |
---|
840 | HelpCB(w, client_data, call_data) |
---|
841 | Widget w; |
---|
842 | XtPointer client_data; |
---|
843 | XtPointer call_data; |
---|
844 | { |
---|
845 | PutUpHelp(); |
---|
846 | } |
---|
847 | |
---|
848 | /* |
---|
849 | ** HighlightNewItem...Change the highlighted line in the passed textwidget |
---|
850 | ** in the direction requested. Return 0 if successful, -1 if there was |
---|
851 | ** no meeting in that direction. |
---|
852 | */ |
---|
853 | |
---|
854 | HighlightNewItem(textW, mode, flag) |
---|
855 | Widget textW; /* list of meetings */ |
---|
856 | int mode; /* one of { NEXTNEWS, PREVNEWS, UPDATE, INITIALIZE} */ |
---|
857 | Boolean flag; /* update current meeting? */ |
---|
858 | { |
---|
859 | Arg args[5]; |
---|
860 | unsigned int n; |
---|
861 | XawTextPosition start, end, inspoint; |
---|
862 | char *tempstring, *foo, *tempptr; |
---|
863 | int length; |
---|
864 | char statusline[LONGNAMELEN + 25]; |
---|
865 | char longmtg[LONGNAMELEN]; |
---|
866 | char shortmtg[SHORTNAMELEN]; |
---|
867 | |
---|
868 | inspoint = XawTextGetInsertionPoint(textW); |
---|
869 | |
---|
870 | n = 0; |
---|
871 | XtSetArg(args[n], XtNstring, &tempstring); n++; |
---|
872 | XtGetValues (textW, args, n); |
---|
873 | |
---|
874 | if (tempstring[inspoint] == '\0') |
---|
875 | return (-1); |
---|
876 | |
---|
877 | /* |
---|
878 | ** Find start and end of current line. |
---|
879 | */ |
---|
880 | |
---|
881 | for (start = inspoint; start && tempstring[start-1] != '\n'; start--) |
---|
882 | ; |
---|
883 | for ( end = inspoint; |
---|
884 | tempstring[end] != '\0' && tempstring[end] != '\n'; |
---|
885 | end++) |
---|
886 | ; |
---|
887 | |
---|
888 | /* |
---|
889 | ** Special case for initializing: change mode to NEXTNEWS unless we're |
---|
890 | ** already on a line with unread transactions. Do nothing in simplemode, |
---|
891 | ** because we always want to stay on the first line. |
---|
892 | */ |
---|
893 | if (mode == INITIALIZE && simplemode != True) { |
---|
894 | if ( tempstring[start + 2] != 'c') |
---|
895 | mode = NEXTNEWS; |
---|
896 | } |
---|
897 | |
---|
898 | if (mode == NEXTNEWS) { |
---|
899 | |
---|
900 | if (start == end || tempstring[end] == '\0') { |
---|
901 | PutUpWarning( "", |
---|
902 | "Nothing more to read", False); |
---|
903 | return(-1); |
---|
904 | } |
---|
905 | |
---|
906 | do { |
---|
907 | if (tempstring[end] == '\n') { |
---|
908 | start = end + 1; |
---|
909 | } |
---|
910 | end = start + strcspn (tempstring + start, "\n\0"); |
---|
911 | } while ( tempstring[end] != '\0' && |
---|
912 | tempstring[start + 2] != 'c'); |
---|
913 | |
---|
914 | |
---|
915 | if ( tempstring[start] == '\0') { |
---|
916 | PutUpWarning( "", |
---|
917 | "Nothing more to read", False); |
---|
918 | return(-1); |
---|
919 | } |
---|
920 | |
---|
921 | } |
---|
922 | |
---|
923 | else if (mode == PREVNEWS) { |
---|
924 | if (start == 0) { |
---|
925 | PutUpWarning( "", |
---|
926 | "no previous meeting with unread news", False); |
---|
927 | return(-1); |
---|
928 | } |
---|
929 | do { |
---|
930 | end = start - 1; |
---|
931 | for ( start = end - 1; |
---|
932 | start > 0 && tempstring[start] != '\n'; |
---|
933 | start--) |
---|
934 | ; |
---|
935 | if (start != 0) start++; |
---|
936 | } while ( start && |
---|
937 | tempstring[start + 2] != 'c'); |
---|
938 | if ( tempstring[start + 2] != 'c' ) { |
---|
939 | PutUpWarning( "", |
---|
940 | "no previous meeting with unread news", False); |
---|
941 | return(-1); |
---|
942 | } |
---|
943 | } |
---|
944 | |
---|
945 | else if (mode == UPDATE) { |
---|
946 | /* |
---|
947 | ** Just need to update current meeting to match highlighted item. |
---|
948 | */ |
---|
949 | } |
---|
950 | |
---|
951 | PutUpArrow(textW, start, True); |
---|
952 | |
---|
953 | if (flag) { |
---|
954 | length = (end - start); |
---|
955 | foo = (char *) calloc (length + 1, sizeof(char)); |
---|
956 | strncpy (foo, tempstring + start + 8, length - 8); |
---|
957 | tempptr = strchr (foo, ','); |
---|
958 | *tempptr = '\0'; |
---|
959 | strcpy (longmtg, foo); |
---|
960 | strcpy (shortmtg, tempptr + 2); |
---|
961 | |
---|
962 | free (foo); |
---|
963 | } |
---|
964 | |
---|
965 | if (SaveMeetingNames(longmtg, shortmtg) == -1) { |
---|
966 | PutUpStatusMessage("No current meeting"); |
---|
967 | CheckButtonSensitivity(BUTTONS_OFF); |
---|
968 | return (-1); |
---|
969 | } |
---|
970 | CheckButtonSensitivity(BUTTONS_ON); |
---|
971 | |
---|
972 | sprintf (statusline, "Reading %s [%d-%d]", |
---|
973 | longmtg, |
---|
974 | TransactionNum(FIRST), |
---|
975 | TransactionNum(LAST)); |
---|
976 | |
---|
977 | PutUpStatusMessage(statusline); |
---|
978 | |
---|
979 | XFlush(XtDisplay(textW)); |
---|
980 | return(0); |
---|
981 | } |
---|
982 | |
---|
983 | |
---|
984 | /* |
---|
985 | ** Run the command. If textW and filename are passed, |
---|
986 | ** read the contents of filename after running the command |
---|
987 | ** and put them into textW. |
---|
988 | ** |
---|
989 | ** If returnvalue is NULL, don't wait for a response from the |
---|
990 | ** command. Otherwise, return a pointer to the return value, |
---|
991 | ** which must be freed by the calling routine. |
---|
992 | ** |
---|
993 | ** This version uses byte-by-byte i/o so it can recognize \n |
---|
994 | ** as end-of-data. Can't use fgets because we don't know |
---|
995 | ** how long the data stream is, and need to keep reallocing. |
---|
996 | ** |
---|
997 | ** Return -1 on error. |
---|
998 | */ |
---|
999 | |
---|
1000 | char * |
---|
1001 | RunCommand (command, textW, filename, returnvalue) |
---|
1002 | char *command; |
---|
1003 | Widget textW; |
---|
1004 | char *filename; |
---|
1005 | Boolean returnvalue; |
---|
1006 | { |
---|
1007 | char *message; |
---|
1008 | int cursize = BUFSIZE; |
---|
1009 | int curbyte = 0; |
---|
1010 | |
---|
1011 | /* |
---|
1012 | ** Send command to child's input stream |
---|
1013 | */ |
---|
1014 | if (fputs(command, outputfile) == EOF) { |
---|
1015 | fprintf (stderr, "Error on fputs\n"); |
---|
1016 | return ((char *)-1); |
---|
1017 | } |
---|
1018 | fflush (outputfile); |
---|
1019 | |
---|
1020 | if (debug) |
---|
1021 | fprintf (stderr, "appl: %s\n",command); |
---|
1022 | fflush (stderr); |
---|
1023 | |
---|
1024 | if (!returnvalue) |
---|
1025 | return (NULL); |
---|
1026 | /* |
---|
1027 | ** Look for child's (one-line) response |
---|
1028 | */ |
---|
1029 | |
---|
1030 | READLINE: |
---|
1031 | |
---|
1032 | message = (char *) malloc (BUFSIZE); |
---|
1033 | |
---|
1034 | while (( message [cursize - BUFSIZE + curbyte] = |
---|
1035 | fgetc (inputfile)) != '\n') { |
---|
1036 | |
---|
1037 | curbyte++; |
---|
1038 | if (curbyte == BUFSIZE) { |
---|
1039 | cursize += BUFSIZE; |
---|
1040 | curbyte = 0; |
---|
1041 | message = (char *) realloc (message, cursize); |
---|
1042 | } |
---|
1043 | } |
---|
1044 | |
---|
1045 | message[cursize - BUFSIZE + curbyte] = '\0'; |
---|
1046 | |
---|
1047 | if (debug) |
---|
1048 | fprintf (stderr, "edsc: %s\n",message); |
---|
1049 | |
---|
1050 | if (message[0] == ';' ) { |
---|
1051 | PutUpWarning("ERROR", message + 1, False); |
---|
1052 | myfree (message); |
---|
1053 | return ((char *)-1); |
---|
1054 | } |
---|
1055 | |
---|
1056 | if (message[0] == '-') { |
---|
1057 | PutUpWarning("WARNING", message + 1, False); |
---|
1058 | myfree (message); |
---|
1059 | curbyte = 0; |
---|
1060 | cursize = BUFSIZE; |
---|
1061 | goto READLINE; |
---|
1062 | } |
---|
1063 | /* |
---|
1064 | ** Read the verbose response and put it into the text widget |
---|
1065 | */ |
---|
1066 | if (filename && textW) |
---|
1067 | FileIntoWidget(filename, textW); |
---|
1068 | |
---|
1069 | return (message); |
---|
1070 | } |
---|
1071 | |
---|
1072 | |
---|
1073 | FileIntoWidget(filename, textW) |
---|
1074 | char *filename; |
---|
1075 | TextWidget textW; |
---|
1076 | { |
---|
1077 | unsigned int fd; |
---|
1078 | Arg args[5]; |
---|
1079 | char *message; |
---|
1080 | int cursize = BUFSIZE; |
---|
1081 | int numread = 1, n; |
---|
1082 | char errormsg[80]; |
---|
1083 | |
---|
1084 | fd = open(filename, O_RDONLY); |
---|
1085 | |
---|
1086 | if (fd == -1) { |
---|
1087 | sprintf (errormsg,"Error opening file %s\n",filename); |
---|
1088 | PutUpWarning("WARNING", errormsg, False); |
---|
1089 | return (-1); |
---|
1090 | } |
---|
1091 | |
---|
1092 | /* |
---|
1093 | ** Make certain we don't try to erase the (now nonexistant) plus sign. |
---|
1094 | */ |
---|
1095 | if (textW == toptextW) |
---|
1096 | oldarrow = -1; |
---|
1097 | |
---|
1098 | message = (char*) malloc (cursize); |
---|
1099 | |
---|
1100 | while (!HELL_FROZEN_OVER) { |
---|
1101 | numread = read (fd, message + cursize - BUFSIZE, BUFSIZE); |
---|
1102 | if (numread == -1) { |
---|
1103 | sprintf (errormsg,"Error reading from file %s\n",filename); |
---|
1104 | PutUpWarning("WARNING", errormsg, False); |
---|
1105 | close (fd); |
---|
1106 | return(-1); |
---|
1107 | } |
---|
1108 | if (numread < BUFSIZE) |
---|
1109 | break; |
---|
1110 | |
---|
1111 | cursize += BUFSIZE; |
---|
1112 | message = (char*) realloc (message, cursize); |
---|
1113 | } |
---|
1114 | |
---|
1115 | if (*message) { |
---|
1116 | message[cursize - BUFSIZE + numread] = '\0'; |
---|
1117 | n = 0; |
---|
1118 | XtSetArg (args[n], XtNstring, message); n++; |
---|
1119 | XtSetValues (textW, args, n); |
---|
1120 | } |
---|
1121 | else { |
---|
1122 | PutUpWarning( "", |
---|
1123 | "No text in this transaction", False); |
---|
1124 | XBell (XtDisplay(textW), 0); |
---|
1125 | |
---|
1126 | } |
---|
1127 | |
---|
1128 | XFlush(XtDisplay(textW)); |
---|
1129 | |
---|
1130 | myfree (message); |
---|
1131 | close (fd); |
---|
1132 | return(0); |
---|
1133 | } |
---|
1134 | |
---|
1135 | static void |
---|
1136 | CheckEdscVersion() |
---|
1137 | { |
---|
1138 | char *version; |
---|
1139 | |
---|
1140 | version = RunCommand ("(gpv)\n", NULL, NULL, True); |
---|
1141 | |
---|
1142 | if ((int) version == -1) { |
---|
1143 | fprintf (stderr, "Cannot communicate with edsc.\n"); |
---|
1144 | exit (-1); |
---|
1145 | } |
---|
1146 | |
---|
1147 | edscversion = atoi(version + 1); |
---|
1148 | |
---|
1149 | if (edscversion < 24) { |
---|
1150 | fprintf (stderr, "Caution...using edsc version %1.1f. ",(float) edscversion/10.0); |
---|
1151 | fprintf (stderr, "Should be using at least 2.4.\n"); |
---|
1152 | } |
---|
1153 | |
---|
1154 | nocache = (edscversion >= 25) ? True : False; |
---|
1155 | } |
---|
1156 | |
---|
1157 | ParseMeetingsFile() |
---|
1158 | { |
---|
1159 | char *fulllist; |
---|
1160 | char *movingptr; |
---|
1161 | char *firstquote, *secondquote; |
---|
1162 | int status; |
---|
1163 | char fullname[100], shortname[100]; |
---|
1164 | int i; |
---|
1165 | |
---|
1166 | fulllist = RunCommand ("(gml)\n", NULL, NULL, True); |
---|
1167 | if ((int) fulllist <= 0) return; |
---|
1168 | |
---|
1169 | if (meetinglist) |
---|
1170 | myfree (meetinglist); |
---|
1171 | |
---|
1172 | i = strlen(fulllist) * 2; |
---|
1173 | meetinglist = (char *) calloc (i, sizeof(char)); |
---|
1174 | if (debug) fprintf (stderr, "Allocated %x, %d long\n", meetinglist, i); |
---|
1175 | |
---|
1176 | secondquote = fulllist; |
---|
1177 | |
---|
1178 | for (i = 0; ; i++) { |
---|
1179 | |
---|
1180 | movingptr = strchr (secondquote + 1, '('); |
---|
1181 | |
---|
1182 | if (!movingptr) |
---|
1183 | break; |
---|
1184 | |
---|
1185 | movingptr++; |
---|
1186 | |
---|
1187 | status = atoi(movingptr); |
---|
1188 | |
---|
1189 | firstquote = strchr(movingptr, '"'); |
---|
1190 | secondquote = strchr(firstquote+1, '"'); |
---|
1191 | *secondquote = '\0'; |
---|
1192 | strcpy (fullname, firstquote + 1); |
---|
1193 | |
---|
1194 | if (*(secondquote + 1) == ')') { |
---|
1195 | *shortname = '\0'; |
---|
1196 | } |
---|
1197 | |
---|
1198 | else { |
---|
1199 | firstquote = strchr(secondquote+1, '"'); |
---|
1200 | secondquote = strchr(firstquote+1, '"'); |
---|
1201 | *secondquote = '\0'; |
---|
1202 | strcpy (shortname, firstquote + 1); |
---|
1203 | } |
---|
1204 | |
---|
1205 | if (debug) |
---|
1206 | fprintf (stderr, "Got %d, '%s', '%s'\n", |
---|
1207 | status, fullname, shortname); |
---|
1208 | |
---|
1209 | sprintf (meetinglist, "%s %c %s, %s\n", |
---|
1210 | meetinglist, |
---|
1211 | status ? 'c' : ' ', |
---|
1212 | fullname, shortname); |
---|
1213 | } |
---|
1214 | |
---|
1215 | sprintf (meetinglist, "%s\0",meetinglist); |
---|
1216 | myfree(fulllist); |
---|
1217 | if (debug) fprintf (stderr, "Actually used %d\n", strlen(meetinglist)); |
---|
1218 | } |
---|
1219 | |
---|
1220 | myfree(ptr) |
---|
1221 | char *ptr; |
---|
1222 | { |
---|
1223 | if ((int)ptr > 0) { |
---|
1224 | if (debug) fprintf (stderr, "Freeing %x\n",ptr); |
---|
1225 | free(ptr); |
---|
1226 | } |
---|
1227 | else if (debug) fprintf (stderr, "Not freeing %x\n",ptr); |
---|
1228 | } |
---|
1229 | |
---|
1230 | /* |
---|
1231 | ** An item in the upper text window has been clicked on. If it is a |
---|
1232 | ** meeting, move there and put the first transaction on the screen. |
---|
1233 | ** If it's a transaction, we display it in the lower window. |
---|
1234 | */ |
---|
1235 | |
---|
1236 | void |
---|
1237 | Update() |
---|
1238 | { |
---|
1239 | if (topscreen == MAIN) { |
---|
1240 | (void) MoveToMeeting(UPDATE); |
---|
1241 | } |
---|
1242 | else if (topscreen == LISTTRNS) { |
---|
1243 | GoToTransaction(HighlightedTransaction(), True); |
---|
1244 | } |
---|
1245 | } |
---|
1246 | |
---|
1247 | |
---|
1248 | void |
---|
1249 | Stub() |
---|
1250 | { |
---|
1251 | } |
---|
1252 | |
---|
1253 | void |
---|
1254 | PrintEvent(w, event, params, num_params) |
---|
1255 | Widget w; |
---|
1256 | XEvent *event; |
---|
1257 | String *params; |
---|
1258 | int *num_params; |
---|
1259 | { |
---|
1260 | fprintf(stderr, "event type %d for widget %s\n", |
---|
1261 | event->type, XtName(w)); |
---|
1262 | } |
---|
1263 | |
---|
1264 | |
---|
1265 | /* |
---|
1266 | ** If we're reading a transaction, scroll it one page down. |
---|
1267 | ** If we're at the end of a transaction, go to the next one. |
---|
1268 | ** If we're at the end of a meeting, find the next one with unread |
---|
1269 | ** transactions. |
---|
1270 | */ |
---|
1271 | |
---|
1272 | static void |
---|
1273 | DoTheRightThing() |
---|
1274 | { |
---|
1275 | if (PopdownCB(NULL, NULL, NULL)) |
---|
1276 | return; |
---|
1277 | |
---|
1278 | if (!TryToScrollAPage(bottextW,1)) { |
---|
1279 | return; |
---|
1280 | } |
---|
1281 | |
---|
1282 | /* |
---|
1283 | ** Are we at the end of a meeting? |
---|
1284 | */ |
---|
1285 | if (TransactionNum(NEXT) != 0) { |
---|
1286 | /* |
---|
1287 | ** No, read the next transaction |
---|
1288 | */ |
---|
1289 | BotSelect(NULL, 0, NULL); |
---|
1290 | } |
---|
1291 | else { |
---|
1292 | /* |
---|
1293 | ** Yes, go to the next meeting and read its next transaction. |
---|
1294 | */ |
---|
1295 | if ((simplemode != True) && (MoveToMeeting(NEXTNEWS) == 0)) { |
---|
1296 | BotSelect(NULL, 0, NULL); |
---|
1297 | } |
---|
1298 | } |
---|
1299 | } |
---|
1300 | |
---|
1301 | static void |
---|
1302 | DoTheRightThingInReverse() |
---|
1303 | { |
---|
1304 | if (!TryToScrollAPage(bottextW,-1)) { |
---|
1305 | return; |
---|
1306 | } |
---|
1307 | |
---|
1308 | /* |
---|
1309 | ** Are we at the start of a meeting? |
---|
1310 | */ |
---|
1311 | if (TransactionNum(CURRENT) > TransactionNum(FIRST)) { |
---|
1312 | /* |
---|
1313 | ** No, read the prev transaction |
---|
1314 | */ |
---|
1315 | BotSelect(NULL, (XtPointer)1, NULL); |
---|
1316 | } |
---|
1317 | else { |
---|
1318 | /* |
---|
1319 | ** Yes, go to the prev meeting and read its next transaction. |
---|
1320 | */ |
---|
1321 | TopSelect(NULL, (XtPointer)1, NULL); |
---|
1322 | } |
---|
1323 | } |
---|
1324 | |
---|
1325 | /* |
---|
1326 | ** Code stolen from Text.c and TextAction.c to scroll the text widget. |
---|
1327 | ** Many text functions are static, so I had to take what I could get. |
---|
1328 | */ |
---|
1329 | |
---|
1330 | TryToScrollAPage(ctx, direction) |
---|
1331 | TextWidget ctx; |
---|
1332 | int direction; |
---|
1333 | { |
---|
1334 | int scroll_val = (ctx->text.lt.lines - 1) * direction; |
---|
1335 | |
---|
1336 | /* |
---|
1337 | ** Don't scroll off the bottom |
---|
1338 | */ |
---|
1339 | if (ctx->text.lt.info[ctx->text.lt.lines].position > |
---|
1340 | ctx->text.lastPos && |
---|
1341 | direction > 0) { |
---|
1342 | return (-1); |
---|
1343 | } |
---|
1344 | /* |
---|
1345 | ** Don't scroll off the top |
---|
1346 | */ |
---|
1347 | if (ctx->text.lt.top == 0 && |
---|
1348 | direction < 0) { |
---|
1349 | return (-1); |
---|
1350 | } |
---|
1351 | |
---|
1352 | _XawTextPrepareToUpdate(ctx); |
---|
1353 | _XawTextVScroll(ctx, scroll_val); |
---|
1354 | |
---|
1355 | ctx->text.insertPos = ctx->text.lt.top; |
---|
1356 | _XawTextCheckResize(ctx); |
---|
1357 | _XawTextExecuteUpdate(ctx); |
---|
1358 | ctx->text.mult = 1; |
---|
1359 | return (0); |
---|
1360 | } |
---|
1361 | |
---|
1362 | |
---|
1363 | static char oldline[80]; |
---|
1364 | |
---|
1365 | PutUpTempMessage(string) |
---|
1366 | char *string; |
---|
1367 | { |
---|
1368 | char *returndata; |
---|
1369 | Arg args[1]; |
---|
1370 | |
---|
1371 | XtSetArg(args[0], XtNstring, &returndata); |
---|
1372 | XtGetValues (label1W, args, 1); |
---|
1373 | strcpy (oldline, returndata); |
---|
1374 | |
---|
1375 | XtSetArg(args[0], XtNstring, string); |
---|
1376 | XtSetValues (label1W, args, 1); |
---|
1377 | XFlush(XtDisplay(label1W)); |
---|
1378 | } |
---|
1379 | |
---|
1380 | TakeDownTempMessage() |
---|
1381 | { |
---|
1382 | Arg args[1]; |
---|
1383 | |
---|
1384 | XtSetArg(args[0], XtNstring, oldline); |
---|
1385 | XtSetValues (label1W, args, 1); |
---|
1386 | } |
---|
1387 | |
---|
1388 | PutUpStatusMessage(string) |
---|
1389 | char *string; |
---|
1390 | { |
---|
1391 | Arg args[1]; |
---|
1392 | |
---|
1393 | XtSetArg(args[0], XtNstring, string); |
---|
1394 | XtSetValues (label1W, args, 1); |
---|
1395 | XFlush(XtDisplay(label1W)); |
---|
1396 | } |
---|
1397 | |
---|
1398 | /* |
---|
1399 | ** PutUpArrow assumes that "start" is the first character position of a line |
---|
1400 | ** in a text widget. It puts a marker "+" on this line, and if moveinsert |
---|
1401 | ** is True, moves the insert point there. |
---|
1402 | */ |
---|
1403 | |
---|
1404 | PutUpArrow(textW, start, moveinsert) |
---|
1405 | TextWidget textW; |
---|
1406 | XawTextPosition start; |
---|
1407 | Boolean moveinsert; |
---|
1408 | { |
---|
1409 | XawTextBlock textblock; |
---|
1410 | static int oldtopscreen = -1; |
---|
1411 | int offset; |
---|
1412 | XawTextPosition oldinspoint; |
---|
1413 | |
---|
1414 | offset = (topscreen == MAIN) ? 7 : 0; |
---|
1415 | |
---|
1416 | oldinspoint = XawTextGetInsertionPoint(textW); |
---|
1417 | |
---|
1418 | /* |
---|
1419 | ** Don't try to erase an arrow on another top screen |
---|
1420 | */ |
---|
1421 | if (topscreen != oldtopscreen) |
---|
1422 | oldarrow = -1; |
---|
1423 | |
---|
1424 | oldtopscreen = topscreen; |
---|
1425 | |
---|
1426 | textblock.firstPos = 0; |
---|
1427 | textblock.length = 1; |
---|
1428 | textblock.format = FMT8BIT; |
---|
1429 | |
---|
1430 | if (oldarrow != -1) { |
---|
1431 | textblock.ptr = " "; |
---|
1432 | XawTextReplace ( textW, oldarrow + offset, |
---|
1433 | oldarrow + offset + 1, &textblock); |
---|
1434 | } |
---|
1435 | |
---|
1436 | textblock.ptr = "+"; |
---|
1437 | |
---|
1438 | XawTextReplace ( textW, start + offset, |
---|
1439 | start + offset + 1, &textblock); |
---|
1440 | |
---|
1441 | if (moveinsert) |
---|
1442 | XawTextSetInsertionPoint (textW, start); |
---|
1443 | else |
---|
1444 | XawTextSetInsertionPoint (textW, oldinspoint); |
---|
1445 | |
---|
1446 | if (topscreen == MAIN) |
---|
1447 | startOfCurrentMeeting = start; |
---|
1448 | |
---|
1449 | XFlush(XtDisplay(textW)); |
---|
1450 | |
---|
1451 | oldarrow = start; |
---|
1452 | } |
---|
1453 | |
---|
1454 | /* |
---|
1455 | ** This assumes the insert position is at the start of the line containing |
---|
1456 | ** the letter 'c'. |
---|
1457 | */ |
---|
1458 | |
---|
1459 | /* |
---|
1460 | ** If UseStringInPlace were True for toptextW, we |
---|
1461 | ** wouldn't need both the XawTextReplace and the setting of |
---|
1462 | ** the char in meetinglist, but setting it to True causes weird |
---|
1463 | ** memory overlaps I haven't figured out yet. |
---|
1464 | */ |
---|
1465 | |
---|
1466 | void |
---|
1467 | RemoveLetterC() |
---|
1468 | { |
---|
1469 | XawTextBlock textblock; |
---|
1470 | XawTextPosition inspoint; |
---|
1471 | |
---|
1472 | textblock.firstPos = 0; |
---|
1473 | textblock.length = 1; |
---|
1474 | textblock.format = FMT8BIT; |
---|
1475 | textblock.ptr = " "; |
---|
1476 | |
---|
1477 | inspoint = startOfCurrentMeeting; |
---|
1478 | |
---|
1479 | if (inspoint > strlen (meetinglist)) |
---|
1480 | return; |
---|
1481 | |
---|
1482 | XawTextReplace (toptextW, inspoint + 2, inspoint + 3, &textblock); |
---|
1483 | |
---|
1484 | *(meetinglist + inspoint + 2) = ' '; |
---|
1485 | |
---|
1486 | XFlush(XtDisplay(toptextW)); |
---|
1487 | } |
---|
1488 | |
---|
1489 | AddChildren (parent, whichone) |
---|
1490 | Widget parent; |
---|
1491 | int whichone; |
---|
1492 | { |
---|
1493 | Widget command, menu, entry; |
---|
1494 | int i, j, n; |
---|
1495 | char *name, *label; |
---|
1496 | Arg args[5]; |
---|
1497 | EntryRec *toprec, *newrec; |
---|
1498 | void (*mycallback)(); |
---|
1499 | |
---|
1500 | char **buttonlabels; |
---|
1501 | char **buttonnames; |
---|
1502 | |
---|
1503 | if (whichone == 0) { |
---|
1504 | buttonlabels = menu_labels0; |
---|
1505 | buttonnames = menu_names0; |
---|
1506 | mycallback = TopSelect; |
---|
1507 | } |
---|
1508 | else { |
---|
1509 | buttonlabels = menu_labels1; |
---|
1510 | buttonnames = menu_names1; |
---|
1511 | mycallback = BotSelect; |
---|
1512 | } |
---|
1513 | |
---|
1514 | for (i = 0; i < MAX_BUTTONS && buttonnames[i]; i++) { |
---|
1515 | n = 0; |
---|
1516 | XtSetArg(args[n], XtNmenuName, buttonlabels[i]); n++; |
---|
1517 | XtSetArg(args[n], XtNlabel, buttonlabels[i]); n++; |
---|
1518 | |
---|
1519 | if (whichone == 0) { |
---|
1520 | label = submenu_labels0[i][0]; |
---|
1521 | name = submenu_names0[i][0]; |
---|
1522 | } |
---|
1523 | else { |
---|
1524 | label = submenu_labels1[i][0]; |
---|
1525 | name = submenu_names1[i][0]; |
---|
1526 | } |
---|
1527 | toprec = &(toplevelbuttons[whichone][i]); |
---|
1528 | |
---|
1529 | if (name) { |
---|
1530 | command = XtCreateManagedWidget( |
---|
1531 | buttonnames[i], |
---|
1532 | menuButtonWidgetClass, parent, |
---|
1533 | args, n); |
---|
1534 | } |
---|
1535 | else { |
---|
1536 | command = XtCreateManagedWidget( |
---|
1537 | buttonnames[i], |
---|
1538 | commandWidgetClass, parent, |
---|
1539 | args, n); |
---|
1540 | XtAddCallback( command, XtNcallback, |
---|
1541 | mycallback, (XtPointer) i); |
---|
1542 | } |
---|
1543 | |
---|
1544 | toprec->button = command; |
---|
1545 | toprec->nextrec = NULL; |
---|
1546 | |
---|
1547 | XtInstallAccelerators(topW, command); |
---|
1548 | |
---|
1549 | if (!name) |
---|
1550 | continue; |
---|
1551 | |
---|
1552 | /* |
---|
1553 | ** Add menus to menu buttons. |
---|
1554 | */ |
---|
1555 | |
---|
1556 | n = 0; |
---|
1557 | menu = XtCreatePopupShell( |
---|
1558 | buttonlabels[i], |
---|
1559 | simpleMenuWidgetClass, |
---|
1560 | parent, |
---|
1561 | args, n); |
---|
1562 | |
---|
1563 | for (j = 0; j < MAX_MENU_LEN; j++) { |
---|
1564 | if (whichone == 0) { |
---|
1565 | label = submenu_labels0[i][j]; |
---|
1566 | name = submenu_names0[i][j]; |
---|
1567 | } |
---|
1568 | else { |
---|
1569 | label = submenu_labels1[i][j]; |
---|
1570 | name = submenu_names1[i][j]; |
---|
1571 | } |
---|
1572 | if (!name) |
---|
1573 | break; |
---|
1574 | |
---|
1575 | newrec = (EntryRec *) malloc (sizeof (EntryRec)); |
---|
1576 | toprec->nextrec = newrec; |
---|
1577 | newrec->nextrec = NULL; |
---|
1578 | n = 0; |
---|
1579 | XtSetArg(args[n], XtNlabel, label); n++; |
---|
1580 | |
---|
1581 | entry = XtCreateManagedWidget( |
---|
1582 | name, smeBSBObjectClass, menu, |
---|
1583 | args, n); |
---|
1584 | XtAddCallback( entry, XtNcallback, |
---|
1585 | mycallback, |
---|
1586 | (XtPointer) (i + (j << 4))); |
---|
1587 | newrec->button = entry; |
---|
1588 | toprec = newrec; |
---|
1589 | } |
---|
1590 | } |
---|
1591 | } |
---|
1592 | |
---|
1593 | /* |
---|
1594 | ** A keyboard equivalent has been hit. For normal command widgets, send |
---|
1595 | ** them a button-one-down and button-one-up. For menu buttons, just send |
---|
1596 | ** them the button-down, and their child will send the button-up. |
---|
1597 | */ |
---|
1598 | |
---|
1599 | static void |
---|
1600 | KeyCallback(w, event, params, num_params) |
---|
1601 | Widget w; |
---|
1602 | XEvent *event; |
---|
1603 | String *params; |
---|
1604 | int *num_params; |
---|
1605 | { |
---|
1606 | Widget button; |
---|
1607 | XButtonEvent MyEvent; |
---|
1608 | int i, whichrow; |
---|
1609 | |
---|
1610 | if (*num_params < 1) |
---|
1611 | return; |
---|
1612 | |
---|
1613 | for (i = 0; i < MAX_BUTTONS; i++) { |
---|
1614 | |
---|
1615 | if (menu_names0[i] && !strcmp (params[0], menu_names0[i])) { |
---|
1616 | whichrow = 0; |
---|
1617 | break; |
---|
1618 | } |
---|
1619 | |
---|
1620 | if (menu_names1[i] && !strcmp (params[0], menu_names1[i])) { |
---|
1621 | whichrow = 1; |
---|
1622 | break; |
---|
1623 | } |
---|
1624 | } |
---|
1625 | |
---|
1626 | if (i == MAX_BUTTONS) { |
---|
1627 | fprintf (stderr, "Key not found. Aborting.\n"); |
---|
1628 | return; |
---|
1629 | } |
---|
1630 | |
---|
1631 | button = (toplevelbuttons[whichrow][i]).button; |
---|
1632 | |
---|
1633 | MyEvent.type = ButtonPress; |
---|
1634 | MyEvent.display = dpy; |
---|
1635 | MyEvent.window = XtWindow(button); |
---|
1636 | MyEvent.button = 1; |
---|
1637 | MyEvent.x = 1; |
---|
1638 | MyEvent.y = 1; |
---|
1639 | MyEvent.state = ButtonPressMask; |
---|
1640 | XSendEvent( dpy, |
---|
1641 | XtWindow(button), |
---|
1642 | False, |
---|
1643 | ButtonPressMask, |
---|
1644 | (XEvent *) &MyEvent); |
---|
1645 | |
---|
1646 | XSync(dpy, False); |
---|
1647 | if (!(toplevelbuttons[whichrow][i]).nextrec) { |
---|
1648 | MyEvent.type = ButtonRelease; |
---|
1649 | MyEvent.state = ButtonReleaseMask; |
---|
1650 | XSendEvent( dpy, |
---|
1651 | XtWindow(button), |
---|
1652 | False, |
---|
1653 | ButtonReleaseMask, |
---|
1654 | (XEvent *) &MyEvent); |
---|
1655 | } |
---|
1656 | |
---|
1657 | } |
---|
1658 | |
---|
1659 | /* |
---|
1660 | ** Check time interval between mouse clicks. If it's less than the |
---|
1661 | ** intrinsics' multi-click timer, call my own "Update" procedure. |
---|
1662 | ** Otherwise, pass the click on to the text widget. |
---|
1663 | */ |
---|
1664 | |
---|
1665 | void |
---|
1666 | DispatchClick(w, event, params, num_params) |
---|
1667 | Widget w; |
---|
1668 | XEvent *event; |
---|
1669 | String *params; /* unused */ |
---|
1670 | Cardinal *num_params; /* unused */ |
---|
1671 | { |
---|
1672 | static Time lasttime = 0; |
---|
1673 | |
---|
1674 | if ( lasttime == 0 || |
---|
1675 | (XtLastTimestampProcessed(XtDisplay(w)) - lasttime) > |
---|
1676 | (Time) XtGetMultiClickTime(XtDisplay(w))) { |
---|
1677 | XtCallActionProc(w, "select-start", event, |
---|
1678 | params, *num_params); |
---|
1679 | } |
---|
1680 | else { |
---|
1681 | XtCallActionProc(w, "Update", event, |
---|
1682 | params, *num_params); |
---|
1683 | } |
---|
1684 | lasttime = XtLastTimestampProcessed(XtDisplay(w)); |
---|
1685 | } |
---|
1686 | |
---|
1687 | /* |
---|
1688 | * Function: GetFontWidth(widget) |
---|
1689 | * based on code from Xaw/TextSink.c |
---|
1690 | * mdb 7/26/96 |
---|
1691 | */ |
---|
1692 | |
---|
1693 | static unsigned long |
---|
1694 | GetFontWidth(w) |
---|
1695 | Widget w; |
---|
1696 | { |
---|
1697 | TextSinkObject sink = (TextSinkObject) w; |
---|
1698 | Atom XA_FIGURE_WIDTH; |
---|
1699 | unsigned long figure_width = 0; |
---|
1700 | XFontStruct *font; |
---|
1701 | Arg args[1]; |
---|
1702 | |
---|
1703 | XtSetArg(args[0], XtNfont, &font); |
---|
1704 | XtGetValues (w, args, 1); |
---|
1705 | |
---|
1706 | /* |
---|
1707 | * Find the figure width of the current font. |
---|
1708 | */ |
---|
1709 | |
---|
1710 | XA_FIGURE_WIDTH = XInternAtom(XtDisplayOfObject(w), "FIGURE_WIDTH", FALSE); |
---|
1711 | if ( XA_FIGURE_WIDTH != None && |
---|
1712 | ( (!XGetFontProperty(font, XA_FIGURE_WIDTH, &figure_width)) || |
---|
1713 | (figure_width == 0)) ) |
---|
1714 | if (font->per_char && font->min_char_or_byte2 <= '$' && |
---|
1715 | font->max_char_or_byte2 >= '$') |
---|
1716 | figure_width = font->per_char['$' - font->min_char_or_byte2].width; |
---|
1717 | else |
---|
1718 | figure_width = font->max_bounds.width; |
---|
1719 | |
---|
1720 | return(figure_width); |
---|
1721 | } |
---|