home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume21 / notes / part01 / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-20  |  12.8 KB  |  637 lines

  1. /*
  2.  * main.c
  3.  *
  4.  * notes - by Bob Smith <bob@snuffy.dracut.ma.us>
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <strings.h>
  9. #include <malloc.h>
  10. #include <sys/param.h>        /* for MAXPATHLEN */
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13.  
  14. #include <X11/Intrinsic.h>
  15. #include <X11/StringDefs.h>
  16. #include <X11/Shell.h>
  17.  
  18. #include <X11/Xaw/Box.h>
  19. #include <X11/Xaw/Cardinals.h>
  20. #include <X11/Xaw/Command.h>
  21. #include <X11/Xaw/Label.h>
  22. #include <X11/Xaw/Form.h>
  23. #include <X11/Xaw/List.h>
  24.  
  25. #include "notes.h"
  26.  
  27.  
  28. /*
  29.  * Global Variables
  30.  */
  31. XtAppContext app_con;
  32. Widget toplevel;
  33. Widget start_button;
  34.  
  35. Widget **Notes;
  36. char **Titles;
  37.  
  38. char notefile[MAXPATHLEN];
  39.  
  40.  
  41. /*
  42.  * forward declarations
  43.  */
  44. void die(), write_notefile(), sensitize_start_button();
  45. static void dismiss_all(), dismiss_note(), save_dismiss_all();
  46. static void version(), ask_quit(), desensitize_start_button();
  47.  
  48.  
  49. /*
  50.  * external functions
  51.  */
  52. /* in callbacks.c */
  53. extern void null(), show_list(), quit(), destroy_widget(), destroy_list();
  54. extern Widget *make_note_widget();
  55.  
  56.  
  57. /*
  58.  * XtActionsRec actionTable
  59.  */
  60. static XtActionsRec actionTable[] = {
  61.     { "null",                null },
  62.     { "quit",                quit },
  63.     { "ask_quit",            ask_quit },
  64.     { "version",            version },
  65.     { "dismiss_all",        dismiss_all },
  66.     { "dismiss_note",        dismiss_note },
  67.     { "save_dismiss_all",    save_dismiss_all },
  68. };
  69.  
  70.  
  71. /*
  72.  * fallback_resources
  73.  */
  74. static char *fallback_resources[] = {
  75.     "notes.start_button.bitmap: notes.xbm",
  76.     "*List.Columns: 1",
  77.     "*input*translations: #override \\n\
  78.         <Key>Return:            null() \\n\
  79.         <Key>Tab:                null() \\n\
  80.         Ctrl<Key>J:                null()",
  81.     "*start_button*translations: #override \\n\
  82.         <Key>q:                    quit() \\n\
  83.         <Key>Q:                    quit() \\n\
  84.         <Key>v:                    version() \\n\
  85.         <Key>V:                    version() \\n\
  86.         <Btn2Down>:                set() \\n\
  87.         <Btn2Down>,<Btn2Up>:    version() reset() \\n\
  88.         <Btn3Down>:                set() \\n\
  89.         <Btn3Down>,<Btn3Up>:    ask_quit() reset()",
  90.     "*Notes*dismiss_button*translations: #override \\n\
  91.         <Btn2Down>:                set() \\n\
  92.         <Btn2Down>,<Btn2Up>:    dismiss_all() reset()",
  93.     "*Notes*save_button*translations: #override \\n\
  94.         <Btn2Down>:                set() \\n\
  95.         <Btn2Down>,<Btn2Up>:    save_dismiss_all() reset()",
  96.     "*Notes*list*translations: #override \\n\
  97.         <Btn2Down>:                Set() \\n\
  98.         <Btn2Down>,<Btn2Up>:    dismiss_note() Unset()",
  99.         NULL
  100. };
  101.  
  102.  
  103. #ifdef NEED_STRDUP
  104. /*
  105.  * strdup ()
  106.  */
  107. char *
  108. strdup(s)
  109.     char *s;
  110. {
  111.     char *t;
  112.  
  113.     if ((t = malloc(strlen(s)+1)) == NULL)
  114.         die("Malloc in strdup failed.");
  115.     strcpy(t, s);
  116.     return t;
  117. }
  118. #endif
  119.  
  120.  
  121. /*
  122.  * die ()
  123.  */
  124. void
  125. die(s)
  126.     char *s;
  127. {
  128.     fprintf(stderr, "%s\n", s);
  129.     fflush(stderr);
  130.     quit();
  131. }
  132.  
  133.  
  134. /*
  135.  * dismiss_all ()
  136.  * dismiss all notes and the list widget
  137.  */
  138. static void
  139. dismiss_all(widget, client_data, call_data)
  140.     Widget widget;
  141.     XtPointer client_data, call_data;
  142. {
  143.     int i;
  144.     XWindowAttributes atribs;
  145.  
  146.     i = 0;
  147.     while (Notes[i]) {
  148.         XGetWindowAttributes(XtDisplay(*Notes[i]),
  149.             XtWindow(*Notes[i]), &atribs);
  150.         if (atribs.map_state != IsUnmapped) {
  151.             XtPopdown(*Notes[i]);
  152.             XtUnmapWidget(*Notes[i]);
  153.         }
  154.         i++;
  155.     }
  156.     destroy_list();
  157.     sensitize_start_button();
  158. }
  159.  
  160.  
  161. /*
  162.  * save_dismiss_all ()
  163.  * save the notefile and dismiss all notes and the list
  164.  */
  165. static void
  166. save_dismiss_all(widget, client_data, call_data)
  167.     Widget widget;
  168.     XtPointer client_data, call_data;
  169. {
  170.     write_notefile();
  171.     dismiss_all();
  172. }
  173.  
  174.  
  175. /*
  176.  * dismiss_note ()
  177.  * dismiss a note
  178.  */
  179. static void
  180. dismiss_note(widget, client_data, call_data)
  181.     Widget widget;
  182.     XtPointer client_data, call_data;
  183. {
  184.     XawListReturnStruct *item;
  185.     Widget w;
  186.     XWindowAttributes atribs;
  187.  
  188.     item = XawListShowCurrent(widget);
  189.     if (item->list_index == -1)
  190.         return;
  191.  
  192.     w = *Notes[item->list_index];
  193.     XGetWindowAttributes(XtDisplay(w), XtWindow(w), &atribs);
  194.  
  195.     if (atribs.map_state != IsUnmapped) {
  196.         XtPopdown(w);
  197.         XtUnmapWidget(w);
  198.     }
  199. }
  200.  
  201.  
  202. /*
  203.  * ask_quit()
  204.  */
  205. static void
  206. ask_quit(widget, client_data, call_data)
  207.     Widget widget;
  208.     XtPointer client_data, call_data;
  209. {
  210.     Widget popup, form, prompt;
  211.     Widget confirm_button, filler_box, cancel_button;
  212.     Dimension top_w, pop_w;
  213.     Position x, y;
  214.  
  215.     desensitize_start_button();
  216.  
  217.     popup = XtCreatePopupShell("Quit",
  218.         transientShellWidgetClass, toplevel,
  219.         NULL, ZERO);
  220.  
  221.     form = XtCreateManagedWidget("form",
  222.         formWidgetClass, popup,
  223.         NULL, ZERO);
  224.  
  225.     prompt = XtVaCreateManagedWidget("prompt",
  226.         labelWidgetClass, form,
  227.         XtNlabel, "Quit, Are you sure?",
  228.         XtNborderWidth, 0,
  229.         XtNtop, XawChainTop,
  230.         XtNbottom, XawChainTop,
  231.         XtNleft, XawChainLeft,
  232.         XtNright, XawChainLeft,
  233.         NULL);
  234.  
  235.     confirm_button = XtVaCreateManagedWidget("confirm_button",
  236.         commandWidgetClass, form,
  237.         XtNlabel, "Yes",
  238.         XtNwidth, 64,
  239.         XtNfromVert, prompt,
  240.         XtNtop, XawChainBottom,
  241.         XtNbottom, XawChainBottom,
  242.         XtNleft, XawChainLeft,
  243.         XtNright, XawChainLeft,
  244.         NULL);
  245.         AddCallback(confirm_button, quit, NULL);
  246.  
  247.     filler_box = XtVaCreateManagedWidget("filler_box",
  248.         boxWidgetClass, form,
  249.         XtNwidth, 64,
  250.         XtNborderWidth, 0,
  251.         XtNfromHoriz, confirm_button,
  252.         XtNfromVert, prompt,
  253.         XtNtop, XawChainBottom,
  254.         XtNbottom, XawChainBottom,
  255.         XtNleft, XawChainLeft,
  256.         XtNright, XawChainRight,
  257.         NULL);
  258.  
  259.     cancel_button = XtVaCreateManagedWidget("cancel_button",
  260.         commandWidgetClass, form,
  261.         XtNlabel, "No",
  262.         XtNwidth, 64,
  263.         XtNfromHoriz, filler_box,
  264.         XtNfromVert, prompt,
  265.         XtNtop, XawChainBottom,
  266.         XtNbottom, XawChainBottom,
  267.         XtNleft, XawChainRight,
  268.         XtNright, XawChainRight,
  269.         NULL);
  270.         AddCallback(cancel_button, destroy_widget, NULL);
  271.         AddCallback(cancel_button, sensitize_start_button, NULL);
  272.  
  273.     XtRealizeWidget(popup);
  274.  
  275.     XtVaGetValues(toplevel, XtNwidth, &top_w, NULL);
  276.     XtVaGetValues(popup, XtNwidth, &pop_w, NULL);
  277.     XtTranslateCoords(toplevel, (top_w-pop_w)/2, 0, &x, &y);
  278.     XtVaSetValues(popup, XtNx, x, XtNy, y, NULL);
  279.  
  280.     XtPopup(popup, XtGrabNone);
  281. }
  282.  
  283. /*
  284.  * sort_titles ()
  285.  * sort the titles and return the new index of where widget
  286.  * `j' ended up
  287.  */
  288. int
  289. sort_titles(j)
  290.     int j;
  291. {
  292.     int i;
  293.     char *s;
  294.  
  295.     i = 0;
  296.     while (Titles[i] && Titles[i+1]) {
  297.         if (strcmp(Titles[i], Titles[i+1]) > 0) {
  298.             if (j == i)
  299.                 j++;
  300.             else
  301.                 if (j == i+1)
  302.                     j--;
  303.             s = Titles[i];
  304.             Titles[i] = Titles[i+1];
  305.             Titles[i+1] = s;
  306.             s = (char *) Notes[i];
  307.             Notes[i] = Notes[i+1];
  308.             Notes[i+1] = (Widget *) s;
  309.             i = 0;
  310.         } else
  311.             i++;
  312.     }
  313.     return j;
  314. }
  315.  
  316.  
  317. /*
  318.  * read_notefile ()
  319.  * read the notefile and make a note widget for each note
  320.  */
  321. void
  322. read_notefile()
  323. {
  324.     FILE *fp;
  325.     char title[80];
  326.     char *buffer, *s, *t;
  327.     int i, x, y, w, h;
  328.     char *getenv();
  329.     struct stat sbuf;
  330.  
  331.     Notes = (Widget **) malloc(sizeof(char *));
  332.     Titles = (char **) malloc(sizeof(char *));
  333.     if (!Notes || !Titles)
  334.         die("Malloc in read_notefile failed.");
  335.     *Notes = NULL;
  336.     *Titles = NULL;
  337.  
  338.     /*
  339.      * check the current directory, and then the HOME
  340.      * directory...  if there is no .notes file, free the
  341.      * temp buffer and get out of here leaving notefile
  342.      * pointing to the HOME directory
  343.      */
  344.     strcpy(notefile, NOTEFILE);
  345.     if ((fp = fopen(notefile, "r")) == NULL) {
  346.         if ((s = getenv("HOME")) == NULL)
  347.             return;
  348.         strcpy(notefile, s);
  349.         strcat(notefile, "/");
  350.         strcat(notefile, NOTEFILE);
  351.         if ((fp = fopen(notefile, "r")) == NULL)
  352.             return;
  353.     }
  354.  
  355.     /*
  356.      * check the size of the notes file and allocate a buffer
  357.      * of appropriate size
  358.      */
  359.     if (fstat(fileno(fp), &sbuf) == 0) {
  360.         if ((buffer = malloc(sbuf.st_size+1)) == NULL) {
  361.             fclose(fp);
  362.             die("Malloc of buffer in read_notefile failed.");
  363.         }
  364.     } else {
  365.         fclose(fp);
  366.         die("Can't stat notes file.");
  367.     }
  368.  
  369.     /*
  370.      * read the notes file into the temp buffer
  371.      */
  372.     if ((i = fread(buffer, sbuf.st_size, 1, fp)) != 1) {
  373.         fclose(fp);
  374.         die("Read error on notes file.");
  375.     }
  376.     buffer[sbuf.st_size] = '\0';
  377.     fclose(fp);
  378.  
  379.     /*
  380.      * spin through the temp buffer and setup the initial
  381.      * state of the NoteStruct pointers...
  382.      */
  383.     s = buffer;
  384.     i = 0;
  385.     while (*s) {
  386.         if (*s == '\f') {
  387.             *s = '\0';
  388. speed_hack:;
  389.             i++;
  390.             Notes = (Widget **) realloc(Notes, (i+1)*sizeof(char *));
  391.             Titles = (char **) realloc(Titles, (i+1)*sizeof(char *));
  392.             if (!Notes || !Titles)
  393.                 die("Realloc in read_notefile failed.");
  394.             s++;
  395.             if ((t = index(s, '\n')) == NULL)
  396.                 die("Oop! No newline at end of title?");
  397.             else {
  398.                 sscanf(s, "%d %d %d %d %[^\n]", &x, &y, &w, &h, title);
  399.                 s = ++t;
  400.                 if ((t = index(s, '\f')) != NULL) *t = '\0';
  401.                 Notes[i-1] = make_note_widget(title, x, y, w, h, s);
  402.                 Notes[i] = NULL;
  403.                 Titles[i-1] = strdup(title);
  404.                 Titles[i] = NULL;
  405.                 if (t) {
  406.                     s = t;
  407.                     /* this is ugly, but it works...  */
  408.                     goto speed_hack;
  409.                 }
  410.             }
  411.         } else
  412.             s++;
  413.     }
  414.     free(buffer);
  415.     (void) sort_titles(0);
  416. }
  417.  
  418.  
  419. /*
  420.  * alloc_new_note ()
  421.  * make a new note
  422.  */
  423. int
  424. alloc_new_note(title)
  425.     char *title;
  426. {
  427.     int i;
  428.     Position top_w, x, y;
  429.  
  430.     XtVaGetValues(toplevel, XtNwidth, &top_w, NULL);
  431.     XtTranslateCoords(toplevel, (top_w - 512)/2, 0, &x, &y);
  432.  
  433.     i = 0;
  434.     while (Notes[i]) i++;
  435.     i++;
  436.     Notes = (Widget **) realloc(Notes, (i+1)*sizeof(char *));
  437.     Titles = (char **) realloc(Titles, (i+1)*sizeof(char *));
  438.     if (!Notes || !Titles)
  439.         die("Realloc in alloc_new_note failed.");
  440.     Notes[i-1] = make_note_widget(title, x, y, 500, 300, "");
  441.     Notes[i] = NULL;
  442.     Titles[i-1] = strdup(title);
  443.     Titles[i] = NULL;
  444.     return sort_titles(i-1);
  445. }
  446.  
  447.  
  448. /*
  449.  * unalloc_note ()
  450.  */
  451. void
  452. unalloc_note(widget)
  453.     Widget widget;
  454. {
  455.     int i;
  456.  
  457.     i = 0;
  458.     while (Notes[i]) {
  459.         if (*Notes[i] == widget) {
  460.             while (Notes[i+1]) {
  461.                 Notes[i] = Notes[i+1];
  462.                 Titles[i] = Titles[i+1];
  463.                 i++;
  464.             }
  465.             Notes[i] = NULL;
  466.             Titles[i] = NULL;
  467.             Notes = (Widget **) realloc(Notes, (i+1)*sizeof(char *));
  468.             Titles = (char **) realloc(Titles, (i+1)*sizeof(char *));
  469.             if (!Notes || !Titles)
  470.                 die("Realloc in unalloc_note failed.");
  471.             return;
  472.         }
  473.         i++;
  474.     }
  475. }
  476.  
  477.  
  478. /*
  479.  * write_notefile ()
  480.  */
  481. void
  482. write_notefile()
  483. {
  484.     FILE *fp;
  485.     int i;
  486.     Dimension w, h;
  487.     Position x, y;
  488.     String title, text;
  489.     XWindowAttributes atribs;
  490.  
  491.     if ((fp = fopen(notefile, "w")) == NULL)
  492.         return;
  493.  
  494.     i = 0;
  495.     while (Notes[i]) {
  496.         XtVaGetValues(*Notes[i], XtNtitle, &title,
  497.             XtNx, &x, XtNy, &y, NULL);
  498.         XGetWindowAttributes(XtDisplay(*Notes[i]),
  499.             XtWindow(*Notes[i]), &atribs);
  500.         /*
  501.          * this hack is the only way I know for now of eliminating
  502.          * 'creeping' windows caused by the offset injected into
  503.          * the x and y values of a window when they're mapped by
  504.          * a window manager such as twm...  there's undoubtedly
  505.          * a more elegant approach, but I don't know how to
  506.          * do it yet! :-)
  507.          */
  508.         if (atribs.map_state != IsUnmapped) {
  509.             x -= H_OFFSET;
  510.             y -= V_OFFSET;
  511.         }
  512.         XtVaGetValues(XtNameToWidget(*Notes[i], "*note"),
  513.             XtNstring, &text, XtNwidth, &w, XtNheight, &h, NULL);
  514.         fprintf(fp, "\f%d %d %d %d %s\n%s", x, y, w, h, title, text);
  515.         i++;
  516.     }
  517.     fclose(fp);
  518. }
  519.  
  520.  
  521. /*
  522.  * desensitize_start_button ()
  523.  */
  524. static void
  525. desensitize_start_button(widget, client_data, call_data)
  526.     Widget widget;
  527.     XtPointer client_data, call_data;
  528. {
  529.     Widget w;
  530.  
  531.     w = XtNameToWidget(toplevel, "*start_button");
  532.     if (w)
  533.         XtVaSetValues(w, XtNsensitive, False, NULL);
  534. }
  535.  
  536.  
  537. /*
  538.  * sensitize_start_button ()
  539.  */
  540. void
  541. sensitize_start_button(widget, client_data, call_data)
  542.     Widget widget;
  543.     XtPointer client_data, call_data;
  544. {
  545.     Widget w;
  546.  
  547.     w = XtNameToWidget(toplevel, "*start_button");
  548.     if (w)
  549.         XtVaSetValues(w, XtNsensitive, True, NULL);
  550. }
  551.  
  552. /*
  553.  * version ()
  554.  */
  555. static void
  556. version(widget, client_data, call_data)
  557.     Widget widget;
  558.     XtPointer client_data, call_data;
  559. {
  560.     Widget w, popup, form, prompt, dismiss_button;
  561.     static char tmp[BUFSIZ];
  562.     Position top_w, pop_w, x, y;
  563.  
  564.     desensitize_start_button();
  565.  
  566.     popup = XtCreatePopupShell("Version",
  567.         transientShellWidgetClass, toplevel,
  568.         NULL, ZERO);
  569.  
  570.     form = XtCreateManagedWidget("form",
  571.         formWidgetClass, popup,
  572.         NULL, ZERO);
  573.  
  574.     sprintf(tmp, "Notes v%d.%d.%d\nby %s",
  575.         VERSION, SUBVERSION, PATCHLEVEL, AUTHOR);
  576.     prompt = XtVaCreateManagedWidget("prompt",
  577.         labelWidgetClass, form,
  578.         XtNlabel, tmp,
  579.         XtNborderWidth, 0,
  580.         XtNtop, XawChainTop,
  581.         XtNbottom, XawChainTop,
  582.         XtNleft, XawChainLeft,
  583.         XtNright, XawChainLeft,
  584.         NULL);
  585.  
  586.     dismiss_button = XtVaCreateManagedWidget("dismiss_button",
  587.         commandWidgetClass, form,
  588.         XtNlabel, "Dismiss",
  589.         XtNwidth, 64,
  590.         XtNfromVert, prompt,
  591.         XtNtop, XawChainBottom,
  592.         XtNbottom, XawChainBottom,
  593.         XtNleft, XawChainLeft,
  594.         XtNright, XawChainLeft,
  595.         NULL);
  596.         AddCallback(dismiss_button, destroy_widget, NULL);
  597.         AddCallback(dismiss_button, sensitize_start_button, NULL);
  598.  
  599.     XtRealizeWidget(popup);
  600.  
  601.     XtVaGetValues(toplevel, XtNwidth, &top_w, NULL);
  602.     XtVaGetValues(popup, XtNwidth, &pop_w, NULL);
  603.     XtTranslateCoords(toplevel, (top_w-pop_w)/2, 0, &x, &y);
  604.     XtVaSetValues(popup, XtNx, x, XtNy, y, NULL);
  605.  
  606.     XtPopup(popup, XtGrabNone);
  607. }
  608.  
  609.  
  610. /*
  611.  * main ()
  612.  */
  613. main(argc, argv)
  614.     int argc;
  615.     char *argv[];
  616. {
  617.     Widget start_button;
  618.  
  619.     toplevel = XtAppInitialize(&app_con, "notes",
  620.         NULL, ZERO,                /* options, option count */
  621.         &argc, argv,            /* command line options */
  622.         fallback_resources,        /* fallback resources */
  623.         NULL, ZERO);            /* other args */
  624.  
  625.     XtAppAddActions(app_con, actionTable, XtNumber(actionTable));
  626.  
  627.     start_button = XtCreateManagedWidget("start_button",
  628.         commandWidgetClass, toplevel,
  629.         NULL, ZERO);
  630.         AddCallback(start_button, desensitize_start_button, NULL);
  631.         AddCallback(start_button, show_list, NULL);
  632.  
  633.     XtRealizeWidget(toplevel);
  634.     read_notefile();
  635.     XtAppMainLoop(app_con);
  636. }
  637.