source: trunk/athena/bin/xdsc/xdsc.c @ 12263

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