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

Revision 22837, 35.5 KB checked in by tabbott, 17 years ago (diff)
In xdsc: * Merged quilt patches into mainline Athena tree
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#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
46static char rcsid[] = "$Id: xdsc.c,v 1.35 1999-12-16 01:58:24 danw Exp $";
47
48/*
49** Globals
50*/
51
52char            *RunCommand();
53TextWidget      toptextW, bottextW;
54Boolean         debug = False;
55char            filebase[50];
56int             topscreen = MAIN;
57Widget          topW, paneW;
58void            RemoveLetterC();
59int             char_width;
60char            axis[10];
61void            TopSelect(), BotSelect();
62void            Update(), Stub();
63void            PrintEvent();
64int             simplemode = 0;
65int             edscversion;
66Boolean         nocache;
67
68/*
69** External functions
70*/
71
72extern void     PutUpHelp();
73extern void     SubmitTransaction();
74extern void     WriteTransaction();
75extern char     *tempnam();
76extern int      PopdownCB();
77extern char     *getenv();
78extern void     TriggerAdd(), TriggerNum(), TriggerDelete();
79extern void     TriggerWrite(), TriggerPopdown(), TriggerSend();
80extern void     TriggerFocusMove();
81extern void     DispatchClick();
82extern void     FetchIfNecessary();
83extern int      HighlightedTransaction();
84
85/*
86** Private functions
87*/
88
89static void     MenuCallback();
90static void     KeyCallback();
91static void     QuitCB(), HelpCB();
92static void     BuildUserInterface();
93static void     DoTheRightThing();
94static void     DoTheRightThingInReverse();
95static void     CheckEdscVersion();
96static void     BuildSkeleton();
97static unsigned long GetFontWidth();
98
99/*
100** Private globals
101*/
102
103static int      filedesparent[2], filedeschild[2];
104static FILE     *inputfile, *outputfile;
105static char     *meetinglist;
106
107static Widget   topboxW, botboxW;
108static Widget   label1W;
109static int      prevfirst = 0;
110static XawTextPosition  startOfCurrentMeeting = -1;
111Display         *dpy;
112Window          root_window;
113static XawTextPosition  oldarrow = -1;
114
115/*
116** Data for top row of buttons
117*/
118
119static char * menu_labels0[MAX_BUTTONS] = {
120        "Down", "Up", "update", "configure", "mode",
121        "show", "HELP", "QUIT"};
122
123static char * menu_names0[MAX_BUTTONS] = {
124        "downbutton", "upbutton", "updatebutton", "configurebutton",
125        "modebutton", "showbutton", "helpbutton", "quitbutton"};
126
127static 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
137static 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
151static char * menu_labels1[MAX_BUTTONS] = {
152        "next", "prev", "Next in chain", "Prev in chain",
153        "goto", "enter", "write", NULL };
154
155static char * menu_names1[MAX_BUTTONS] = {
156        "nextbutton", "prevbutton", "nchainbutton", "pchainbutton",
157        "gotobutton", "enterbutton", "writebutton", NULL };
158
159static 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
168static 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
178EntryRec        toplevelbuttons[2][MAX_BUTTONS];
179
180void
181main(argc, argv)
182int argc;
183char *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
213original code
214        char_width = (((TextSinkObject) (toptextW->text.sink))->
215                                text_sink.font->max_bounds.width);
216
217removed because font parameter is either private or nonexistent (private in
218mit Xaw include files, nonexistent in others).
219
220borrowed code from Xaw/TextSink.c to write a generic GetFontWidth routine.
221rearranged some to use font resource, rather than accessing internals.
222
223mdb 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
283SetUpEdsc()
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
312static void
313BuildSkeleton()
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
406static void
407BuildUserInterface()
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
528static void
529MenuCallback(w, event, params, num_params)
530Widget  w;
531XEvent  *event;
532String  *params;
533int     *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
588ABORT:
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
601void
602TopSelect(w, client_data, call_data)
603Widget  w;                              /*IGNORED*/
604XtPointer       client_data;
605XtPointer       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
732void
733BotSelect(w, client_data, call_data)
734Widget  w;                              /*IGNORED*/
735XtPointer       client_data;
736XtPointer       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
811RestoreTopTextWidget()
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
826static void
827QuitCB(w, client_data, call_data)
828Widget  w;
829XtPointer       client_data;
830XtPointer       call_data;
831{
832        (void) SaveMeetingNames("", "");
833
834        fputs("(quit)\n", outputfile);
835        fflush (outputfile);
836        exit (0);
837}
838
839static void
840HelpCB(w, client_data, call_data)
841Widget  w;
842XtPointer       client_data;
843XtPointer       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
854HighlightNewItem(textW, mode, flag)
855Widget  textW;          /* list of meetings */
856int     mode;           /* one of { NEXTNEWS, PREVNEWS, UPDATE, INITIALIZE} */
857Boolean 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
1000char    *
1001RunCommand (command, textW, filename, returnvalue)
1002char    *command;
1003Widget  textW;
1004char    *filename;
1005Boolean 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
1030READLINE:
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
1073FileIntoWidget(filename, textW)
1074char            *filename;
1075TextWidget      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
1135static void
1136CheckEdscVersion()
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
1157ParseMeetingsFile()
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
1220myfree(ptr)
1221char    *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
1236void
1237Update()
1238{
1239        if (topscreen == MAIN) {
1240                (void) MoveToMeeting(UPDATE);
1241        }
1242        else if (topscreen == LISTTRNS) {
1243                GoToTransaction(HighlightedTransaction(), True);
1244        }
1245}
1246
1247
1248void
1249Stub()
1250{
1251}
1252
1253void
1254PrintEvent(w, event, params, num_params)
1255Widget  w;
1256XEvent  *event;
1257String  *params;
1258int     *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
1272static void
1273DoTheRightThing()
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
1301static void
1302DoTheRightThingInReverse()
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
1330TryToScrollAPage(ctx, direction)
1331TextWidget      ctx;
1332int             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
1363static char             oldline[80];
1364
1365PutUpTempMessage(string)
1366char    *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
1380TakeDownTempMessage()
1381{
1382        Arg             args[1];
1383
1384        XtSetArg(args[0], XtNstring, oldline);
1385        XtSetValues (label1W, args, 1);
1386}
1387
1388PutUpStatusMessage(string)
1389char    *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
1404PutUpArrow(textW, start, moveinsert)
1405TextWidget      textW;
1406XawTextPosition start;
1407Boolean         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
1466void
1467RemoveLetterC()
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
1489AddChildren (parent, whichone)
1490Widget  parent;
1491int     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
1599static void     
1600KeyCallback(w, event, params, num_params)
1601Widget  w;
1602XEvent  *event;
1603String  *params;
1604int     *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
1665void
1666DispatchClick(w, event, params, num_params)
1667Widget w;
1668XEvent *event;
1669String *params;         /* unused */
1670Cardinal *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
1693static unsigned long
1694GetFontWidth(w)
1695Widget 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}
Note: See TracBrowser for help on using the repository browser.