home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #27 / NN_1992_27.iso / spool / alt / sources / 2528 / workman_stubs.c
Encoding:
C/C++ Source or Header  |  1992-11-15  |  50.6 KB  |  2,204 lines

  1. /*
  2.  * @(#)workman_stubs.c    1.111 11/15/92
  3.  *
  4.  * workman_stubs.c - Notify and event callback function stubs.
  5.  */
  6.  
  7. static char *ident = "@(#)workman_stubs.c    1.111 11/15/92";
  8.  
  9. #include <stdio.h>
  10. #include <sys/param.h>
  11. #include <sys/types.h>
  12. #include <signal.h>
  13. #include <xview/xview.h>
  14. #include <xview/panel.h>
  15. #include <xview/textsw.h>
  16. #include <xview/xv_xrect.h>
  17. #include <xview/screen.h>
  18. #include <xview/notice.h>
  19. #include "workman_ui.h"
  20. #include "struct.h"
  21.  
  22. void    quit();
  23. void    continued();
  24. void    setup_itimer();
  25. void    init_stats();
  26. void    avoid_track();
  27. void    keep_settings();
  28. void    cd_volume();
  29. void    keep_cd_open();
  30. void    figure_volume();
  31. void    set_default_volume();
  32. void    text_event_p();
  33. void    next_stopmode();
  34. char *    listentry();
  35. char *    trackname();
  36. int *    get_playlist();
  37. void    make_initial_playlist();
  38. void    kill_stats();
  39. void    start_repeating();
  40. void    add_playlist();
  41. int    switch_playlists();
  42. void    stop_repeating();
  43. Notify_value check_open(), byebye(), sigusr1(), sigusr2();
  44. void    window1_button2_notify_callback(),
  45.     popup1_buttonpl_notify_callback(),
  46.     window1_button4_notify_callback(),
  47.     window1_button3_notify_callback();
  48. Panel_item    quitbutton;
  49.  
  50. char    *pidfile = "/tmp/.wm_pid";
  51. char *    empty = "";
  52. extern char *cd_device;
  53. #ifndef SYSV
  54. extern char *optarg;
  55. #endif
  56.  
  57. Rect    *track_rect = NULL;
  58. Xv_Notice wannasave, mountedfs;
  59. int    confirmsave;
  60. int    add_height, small_height;
  61. int    min_lines = -1;
  62. int    dont_retry = 0;
  63. void    (*text_event_handler)();
  64.  
  65. window1_objects    *Workman_window1;
  66. popup1_objects    *Workman_popup1;
  67. about_objects    *Workman_about;
  68. goodies_objects    *Workman_goodies;
  69. plpopup_objects    *Workman_plpopup;
  70.  
  71. extern int cur_track, cur_pos_abs, cur_pos_rel, cur_tracklen, cur_cdlen,
  72.     cur_cdmode, cur_ntracks, cur_lasttrack, cur_firsttrack, cur_listno;
  73. extern int cur_frame;
  74. extern int cd_fd;
  75. extern int exit_on_eject, suppress_locking;
  76. extern int found_in_db, found_in_rc;
  77. extern char *cur_cdname, *cur_artist, cur_contd, cur_avoid;
  78. int cur_playnew = -1;
  79. int displayed_track = -1;        /* Track whose info is onscreen */
  80. int pop_track = 0;            /* Track being edited in popup */
  81. int *pop_list = NULL;            /* Our notion of the playlist */
  82. int pop_listsize = 0;            /* List size, including 0 */
  83. int pl_item = -1;            /* Playlist item selected */
  84. int pl_listnum = -1;            /* Number of current playlist */
  85. int my_artist = 0, my_cdname = 0;
  86. int num_names = 0, num_nalloc = 0;
  87. int cur_balance = 10;
  88. int manual_volume = 0;        /* Has the user changed the volume by hand? */
  89. int cur_stopmode = -1;
  90. int mark_a = 0, mark_b = 0;
  91. int window_is_open;
  92. int was_repeating = 0;
  93. int info_modified = 0;
  94. int dismiss_button = 0;
  95.  
  96. Attr_attribute    INSTANCE;
  97.  
  98. main(argc, argv)
  99.     int    argc;
  100.     char    **argv;
  101. {
  102.     int        c, keep_open = 1;
  103.     Panel_item    item;
  104.     FILE        *fp;
  105.  
  106.     /*
  107.      * Initialize XView.
  108.      */
  109.     xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, NULL);
  110.     INSTANCE = xv_unique_key();
  111.     
  112.     /*
  113.      * Initialize user interface components.
  114.      * Do NOT edit the object initializations by hand.
  115.      */
  116.     Workman_window1 = window1_objects_init(NULL, NULL);
  117.     Workman_popup1 = popup1_objects_init(NULL, Workman_window1->window1);
  118.     Workman_about = about_objects_init(NULL, Workman_window1->window1);
  119.     Workman_goodies = goodies_objects_init(NULL, Workman_window1->window1);
  120.     Workman_plpopup = plpopup_objects_init(NULL, Workman_window1->window1);
  121.     
  122.     while ((c = getopt(argc, argv, "p:dc:ol:eXnb")) != EOF)
  123.         switch (c) {
  124.         case 'p':
  125.             pidfile = optarg;
  126.             break;
  127.         case 'b':
  128.             dismiss_button = 1;
  129.             break;
  130.         case 'd':
  131.             xv_set(Workman_window1->artist_display, XV_SHOW,
  132.                 FALSE, NULL);
  133.             xv_set(Workman_window1->cdname_display, XV_SHOW,
  134.                 FALSE, PANEL_LABEL_STRING, "X", NULL);
  135.             track_rect = (Rect *) xv_get(
  136.                 Workman_window1->cdname_display,
  137.                 PANEL_ITEM_RECT);
  138.             xv_set(Workman_window1->cdname_display, XV_SHOW,
  139.                 FALSE, NULL);
  140.             PANEL_EACH_ITEM(Workman_window1->controls1, item)
  141.                 if (xv_get(item, XV_SHOW) == TRUE)
  142.                     xv_set(item, PANEL_ITEM_Y,
  143.                         xv_get(item, PANEL_ITEM_Y) -
  144.                         track_rect->r_top -
  145.                         track_rect->r_height, NULL);
  146.             PANEL_END_EACH
  147.             xv_set(Workman_window1->window1, XV_HEIGHT,
  148.                 xv_get(Workman_window1->window1, XV_HEIGHT) -
  149.                 track_rect->r_top - track_rect->r_height, NULL);
  150.             break;
  151.         case 'e':
  152.             if (dont_retry == 0)
  153.                 dont_retry = 2;
  154.             else
  155.                 dont_retry = 1;
  156.             break;
  157.         case 'c':
  158.             cd_device = optarg;
  159.             break;
  160.         case 'o':
  161.             keep_open = 0;
  162.             break;
  163.         case 'l':
  164.             min_lines = atoi(optarg);
  165.             break;
  166.         case 'X':
  167.             exit_on_eject = 1;
  168.             break;
  169.         case 'n':
  170.             suppress_locking = 1;
  171.             break;
  172.         default:
  173.             fprintf(stderr,
  174. "usage: %s [-p file] [-d] [-c device] [-o] [-l N] [-e] [-X] [-n] [-b]\n\
  175. \t-c\tuse alternate device (default = %s)\n\
  176. \t-d\tdon't display title information\n\
  177. \t-e\tdon't check for CD insertion when no CD is present\n\
  178. \t-l\tleave room for at least N lines of track title\n\
  179. \t-X\texit when CD is ejected\n\
  180. \t-n\tdon't use file locking when updating database (dangerous)\n\
  181. \t-o\tdon't run background job to keep device open (SVr4 only)\n\
  182. \t-p\twrite process ID to another file (default = %s)\n\
  183. \t-b\tput dismiss buttons on windows\n",
  184. argv[0], cd_device, pidfile);
  185.             exit(1);
  186.         }
  187.  
  188. #ifdef SYSV
  189.     if (keep_open)
  190.         if (fork() == 0)
  191.             keep_cd_open();
  192.         else
  193.             wait(NULL);
  194. #endif
  195.  
  196.     /*
  197.      * Fill up the PID-file.
  198.      */
  199.     fp = fopen(pidfile, "w");
  200.     if (fp != NULL)
  201.     {
  202.         fprintf(fp, "%d\n", getpid());
  203.         fflush(fp);
  204.         fchmod(fileno(fp), 0666);
  205.         fclose(fp);
  206.     }
  207.     else
  208.     {
  209.         fprintf(stderr, "Warning: ");
  210.         perror(pidfile);
  211.     }
  212.  
  213.     if (dismiss_button)
  214.     {
  215.         Panel_item    button;
  216.         int        spacing;
  217.  
  218.         xv_create(Workman_plpopup->controls5, PANEL_BUTTON,
  219.             XV_X, 10, XV_Y, (int) xv_get(Workman_plpopup->delete,
  220.             XV_Y), PANEL_LABEL_STRING, "Dismiss", PANEL_NOTIFY_PROC,
  221.             popup1_buttonpl_notify_callback, NULL);
  222.         xv_create(Workman_popup1->controls2, PANEL_BUTTON,
  223.             XV_X, 10, XV_Y, (int) xv_get(Workman_popup1->buttonpl,
  224.             XV_Y), PANEL_LABEL_STRING, "Dismiss", PANEL_NOTIFY_PROC,
  225.             window1_button2_notify_callback, NULL);
  226. #define ip Workman_window1
  227.         /* Squish the main window buttons down some. */
  228.         quitbutton = xv_create(ip->controls1, PANEL_BUTTON,
  229.             PANEL_LABEL_STRING, "Quit", PANEL_NOTIFY_PROC,
  230.             quit, NULL);
  231.         xv_set(ip->button3, PANEL_LABEL_STRING, "About", NULL);
  232.         xv_set(ip->button2, PANEL_LABEL_STRING, "CD Info", NULL);
  233.         xv_set(ip->button4, PANEL_LABEL_STRING, "Goodies", NULL);
  234.         spacing = ((int) xv_get(ip->controls1, XV_WIDTH) - (
  235.             (int) xv_get(ip->button2, XV_WIDTH) +
  236.             (int) xv_get(ip->button3, XV_WIDTH) +
  237.             (int) xv_get(ip->button4, XV_WIDTH) +
  238.             (int) xv_get(quitbutton, XV_WIDTH))) / 5;
  239.         xv_set(ip->button3, XV_X, spacing, NULL);
  240.         xv_set(ip->button2, XV_X, (int) xv_get(ip->button3, XV_WIDTH) +
  241.             (int) xv_get(ip->button3, XV_X) + spacing, NULL);
  242.         xv_set(ip->button4, XV_X, (int) xv_get(ip->button2, XV_WIDTH) +
  243.             (int) xv_get(ip->button2, XV_X) + spacing, NULL);
  244.         xv_set(quitbutton, XV_Y, (int) xv_get(Workman_window1->button2,
  245.             XV_Y), XV_X, (int) xv_get(ip->controls1, XV_WIDTH) -
  246.             (int) xv_get(quitbutton, XV_WIDTH) - spacing, NULL);
  247. #undef ip
  248.         button = xv_create(Workman_about->controls3, PANEL_BUTTON,
  249.             PANEL_LABEL_STRING, "Dismiss", PANEL_NOTIFY_PROC,
  250.             window1_button3_notify_callback, NULL);
  251.         xv_set(Workman_about->about, XV_HEIGHT,
  252.             (int) xv_get(button, XV_HEIGHT) + 5 +
  253.             (int) xv_get(Workman_about->about, XV_HEIGHT),
  254.             NULL);
  255.         xv_set(button, XV_X, ((int) xv_get(Workman_about->about,
  256.             XV_WIDTH) - (int) xv_get(button, XV_WIDTH)) / 2,
  257.             XV_Y, (int) xv_get(Workman_about->message6, XV_Y) +
  258.             (int) xv_get(Workman_about->message6, XV_HEIGHT) + 5,
  259.             NULL);
  260.         button = xv_create(Workman_goodies->controls4, PANEL_BUTTON,
  261.             PANEL_LABEL_STRING, "Dismiss", PANEL_NOTIFY_PROC,
  262.             window1_button4_notify_callback, NULL);
  263.         xv_set(Workman_goodies->goodies, XV_HEIGHT,
  264.             (int) xv_get(button, XV_HEIGHT) +
  265.             (int) xv_get(Workman_goodies->goodies, XV_HEIGHT),
  266.             NULL);
  267.         xv_set(button, XV_X, ((int) xv_get(Workman_goodies->goodies,
  268.             XV_WIDTH) - (int) xv_get(button, XV_WIDTH)) / 2,
  269.             XV_Y, (int) xv_get(Workman_goodies->indexscan, XV_Y) +
  270.             (int) xv_get(Workman_goodies->indexscan, XV_HEIGHT) + 5,
  271.             NULL);
  272.     }
  273.  
  274.     srand(getpid());
  275.     kill_stats(Workman_window1);
  276.     track_rect = (Rect *)xv_get(Workman_window1->tracks, PANEL_ITEM_RECT);
  277.  
  278.     xv_set(Workman_goodies->abrepeat, PANEL_INACTIVE, TRUE, NULL);
  279.  
  280.     /* Initialize some stuff Guide won't do. */
  281.     xv_set(Workman_window1->volume, PANEL_VALUE, xv_get(Workman_window1->
  282.         volume, PANEL_MAX_VALUE), PANEL_NOTIFY_LEVEL, PANEL_ALL, NULL);
  283.     xv_set(Workman_goodies->balance, PANEL_NOTIFY_LEVEL, PANEL_ALL, NULL);
  284.     xv_set(Workman_popup1->defaultvolume, PANEL_NOTIFY_LEVEL, PANEL_ALL,
  285.         NULL);
  286.     xv_set(Workman_window1->songpos, PANEL_NOTIFY_LEVEL, PANEL_ALL,
  287.         PANEL_JUMP_DELTA, 5, NULL);
  288.     cd_volume(254);
  289.     xv_set(Workman_about->about, FRAME_CMD_PUSHPIN_IN, FALSE, NULL);
  290.     xv_set(Workman_popup1->popup1, FRAME_CMD_PUSHPIN_IN, FALSE, NULL);
  291.     xv_set(Workman_goodies->goodies, FRAME_CMD_PUSHPIN_IN, FALSE, NULL);
  292.     xv_set(Workman_plpopup->plpopup, FRAME_CMD_PUSHPIN_IN, FALSE,
  293.         XV_KEY_DATA, FRAME_CMD_PUSHPIN_IN, FALSE, NULL);
  294.     xv_set(Workman_popup1->whichvolume, PANEL_DEFAULT_VALUE, 1, NULL);
  295.     text_event_handler = (void (*)())xv_get(Workman_popup1->artist,
  296.         PANEL_EVENT_PROC);
  297.     xv_set(Workman_popup1->cdname, PANEL_EVENT_PROC, text_event_p, NULL);
  298.     xv_set(Workman_popup1->artist, PANEL_EVENT_PROC, text_event_p, NULL);
  299.     xv_set(Workman_popup1->trackname, PANEL_EVENT_PROC, text_event_p, NULL);
  300.     small_height = track_rect->r_height;
  301.     next_stopmode(Workman_window1->repeat, cur_stopmode, NULL);
  302.     setup_itimer(Workman_window1, 5);
  303.  
  304.     /*
  305.      * Attempt to lay out the popups somewhat decently.  About goes at
  306.      * the upper left, goodies to its right.
  307.      * CD Info is positioned the first time it appears.
  308.      */
  309.     xv_set(Workman_goodies->goodies, XV_X,
  310.         c = ((int) xv_get(Workman_about->about, XV_WIDTH) + 15), NULL);
  311.     xv_set(Workman_plpopup->plpopup, XV_X,
  312.         (int) xv_get(Workman_goodies->goodies, XV_WIDTH) + c + 15,
  313.         NULL);
  314.  
  315.     window_is_open = ! xv_get(Workman_window1->window1, FRAME_CLOSED);
  316.     notify_interpose_event_func(Workman_window1->window1, check_open,
  317.         NOTIFY_SAFE);
  318.     notify_interpose_destroy_func(Workman_window1->window1, byebye);
  319.     notify_set_signal_func(Workman_window1->window1, sigusr1, SIGUSR1,
  320.         NOTIFY_SYNC);
  321.     notify_set_signal_func(Workman_window1->window1, sigusr2, SIGUSR2,
  322.         NOTIFY_SYNC);
  323.  
  324.     wannasave = xv_create(Workman_window1->window1, NOTICE,
  325.         NOTICE_MESSAGE_STRINGS, "WorkMan alert!", "",
  326.         "You have changed this CD's information,",
  327.         "but you didn't save your changes.", NULL, NOTICE_BUTTON_YES,
  328.         "Save changes", NOTICE_BUTTON_NO, "Discard changes",
  329.         NOTICE_STATUS, &confirmsave, NULL);
  330.     mountedfs = xv_create(Workman_window1->window1, NOTICE,
  331.         NOTICE_MESSAGE_STRINGS, "WorkMan alert!", "",
  332.         "This CD contains a mounted filesystem.",
  333.         "Please run 'umount' before ejecting",
  334.         "or nasty things may happen.", NULL, NOTICE_BUTTON,
  335.         "Okay", 0, NULL);
  336.  
  337.     /*
  338.      * Turn control over to XView.
  339.      */
  340.     xv_main_loop(Workman_window1->window1);
  341.  
  342.     unlink(pidfile);
  343.     exit(0);
  344. }
  345.  
  346. /*
  347.  * Callback function for Apply button.
  348.  */
  349. void
  350. save_config(item, event)
  351.     Panel_item    item;
  352.     Event        *event;
  353. {
  354.     keep_settings(Workman_window1);
  355.     save();
  356.     info_modified = 0;
  357. }
  358.  
  359. static int time_wanted = -1;
  360.  
  361. static unsigned short sink_bits[8][64 * 16] = { {
  362. #include "bitmaps/sink0"
  363. }, {
  364. #include "bitmaps/sink1"
  365. }, {
  366. #include "bitmaps/sink2"
  367. }, {
  368. #include "bitmaps/sink3"
  369. }, {
  370. #include "bitmaps/sink4"
  371. }, {
  372. #include "bitmaps/sink5"
  373. }, {
  374. #include "bitmaps/sink6"
  375. }, {
  376. #include "bitmaps/sink7"
  377. } };
  378.  
  379. /*
  380.  * Timer handler.  This is called twice a second and updates the clocks and
  381.  * gauges and such.
  382.  */
  383. Notify_value
  384. handle_timer(c, w)
  385. Notify_client    c;
  386. int        w;
  387. {
  388.     window1_objects *ip = Workman_window1;
  389.     static int old_cdmode, new_image = 0;
  390.     Xv_opaque old_image;
  391.  
  392.     if (xv_get(ip->mode, PANEL_VALUE) != 5 || ! dont_retry)
  393.         switch (cd_status()) {
  394.         case 0:        /* No CD in drive */
  395.             cur_cdmode = 5;
  396.             if (old_cdmode != 5)
  397.             {
  398.                 if (!xv_get(ip->cdname_display, PANEL_INACTIVE))
  399.                 {
  400.                     keep_settings(ip);
  401.                     kill_stats(ip);
  402.                 }
  403.                 xv_set(ip->mode, PANEL_VALUE, 5, NULL);
  404.             }
  405.             break;
  406.         case 1:        /* CD in drive, what state is it in? */
  407.             if (cur_cdmode == 0)        /* Done with track... */
  408.             {
  409. donewithcd:
  410.                 if (xv_get(Workman_goodies->abrepeat,
  411.                                 PANEL_VALUE))
  412.                 {
  413.                     play_chunk(mark_a, mark_b);
  414.                     return (handle_timer(c, w));
  415.                 }
  416.                 if (was_repeating)
  417.                 {
  418.                     was_repeating = 0;
  419.                     play_chunk(mark_b, cur_lasttrack >=
  420.                         cur_ntracks ?
  421.                         (cd->length - 1) * 75 :
  422.                         cd->trk[cur_lasttrack].start-1);
  423.                     return (handle_timer(c, w));
  424.                 }
  425.  
  426.                 play_next_entry();
  427.                 if (cd_status() != 1)
  428.                     return (handle_timer(c, w));
  429.                 if (cur_cdmode == 4)    /* Done with CD */
  430.                 {
  431.                     xv_set(Workman_goodies->abrepeat,
  432.                         PANEL_VALUE, FALSE, NULL);
  433.                     switch (xv_get(ip->repeat, PANEL_VALUE))
  434.                     {
  435.                     case 1:
  436.                         make_playlist(xv_get(
  437.                             ip->shuffle,
  438.                             PANEL_VALUE), 0);
  439.                         play_next_entry();
  440.                         break;
  441.                     case 2:
  442.                         keep_settings(ip);
  443.                         if (info_modified)
  444.                         {
  445.                         /*one more tab and we're dead*/
  446.                             xv_set(wannasave,
  447.                                 XV_SHOW, TRUE,
  448.                                 NULL);
  449.                             if (confirmsave)
  450.                                 save_config(
  451.                                     NULL,
  452.                                     NULL);
  453.                             info_modified = 0;
  454.                         }
  455.                         if (eject_cd() == 0)
  456.                         {
  457.                             setup_itimer(ip, 5);
  458.                             kill_stats(ip);
  459.                         }
  460.                         break;
  461.                     default:
  462.                         icon_label("Stop");
  463.                         xv_set(ip->tracks, PANEL_VALUE,
  464.                             -1, NULL);
  465.                         xv_set(ip->tracklen,
  466.                             PANEL_LABEL_STRING,
  467.                             "0:00", NULL);
  468.                         cur_pos_abs = cur_pos_rel = 0;
  469.                         cur_tracklen = 0;
  470.                         new_trackname_display("", 0);
  471.                         xv_set(Workman_goodies->delete,
  472.                             PANEL_INACTIVE, TRUE,
  473.                             NULL);
  474.                         xv_set(Workman_goodies->split,
  475.                             PANEL_INACTIVE, TRUE,
  476.                             NULL);
  477.                         reset_cdlen(ip);
  478.                         displayed_track = -1;
  479.                         cur_track = -1;
  480.                     }
  481.                 }
  482.             }
  483.  
  484.             /* We're at the end of the previous track. */
  485.             if (cur_firsttrack != -1 && cur_track < cur_firsttrack)
  486.                 cur_track = cur_firsttrack;
  487.  
  488.             /* The slider has been moved... */
  489.             if (time_wanted > -1 && cur_cdmode == 1)
  490.             {
  491.                 play_from_pos(time_wanted);
  492.                 time_wanted = -2;
  493.                 return (handle_timer(c, w));
  494.             }
  495.             if (time_wanted == -2)
  496.             {
  497.                 time_wanted = -1;
  498.                 xv_set(ip->cdgauge, PANEL_VALUE, cur_pos_abs,
  499.                     NULL);
  500.             }
  501.  
  502.             /* We've hit the start of a track we don't want. */
  503.             if (cur_lasttrack != -1 && cur_track > cur_lasttrack)
  504.                 goto donewithcd;
  505.  
  506.             if (cur_cdmode != 4 && cur_cdmode != 3 || old_cdmode !=
  507.                                 cur_cdmode)
  508.                 show_stats(ip);
  509.             break;
  510.  
  511.         case 2:        /* CD has just been inserted. */
  512.             info_modified = 0;
  513.             if (dont_retry > 1)
  514.                 dont_retry = 0;
  515.             setup_itimer(ip, 0);
  516.             init_stats(ip);
  517.             xv_set(ip->repeat, PANEL_VALUE, cur_stopmode, NULL);
  518.             xv_set(Workman_goodies->playnewcds, PANEL_VALUE,
  519.                 cur_playnew, NULL);
  520.             show_stats(ip);
  521.             cd_status();
  522.             if ((cur_playnew && !found_in_rc) || get_autoplay() ||
  523.                                 cur_cdmode == 1)
  524.                 make_initial_playlist(get_playmode());
  525.             break;
  526.         }
  527.  
  528.     old_cdmode = cur_cdmode;
  529.  
  530.     if (window_is_open && xv_get(Workman_about->about, XV_SHOW))
  531.     {
  532.         old_image = xv_get(Workman_about->sink, PANEL_LABEL_IMAGE);
  533.         xv_set(Workman_about->sink, PANEL_LABEL_IMAGE,
  534.             xv_create(XV_NULL, SERVER_IMAGE, SERVER_IMAGE_DEPTH, 1,
  535.                 XV_WIDTH, 64, XV_HEIGHT, 64, SERVER_IMAGE_BITS,
  536.                 sink_bits[new_image], NULL), NULL);
  537.         xv_destroy(old_image);
  538.         new_image = (new_image + 1) & 7;
  539.     }
  540.  
  541.     return (NOTIFY_DONE);
  542. }
  543.  
  544. /*
  545.  * Make an initial playlist.  If the CD was already playing, skip forward in
  546.  * the list to an entry where the current track would be playing (except in
  547.  * Shuffle mode; in that case, start a new random list beginning with
  548.  * the current track.)
  549.  */
  550. void
  551. make_initial_playlist(playmode)
  552.     int    playmode;
  553. {
  554.     if (cur_cdmode == 1)
  555.     {
  556.         if (playmode == 1)
  557.         {
  558.             make_playlist(1, cur_track);
  559.             cur_listno = 1;
  560.         }
  561.         else
  562.         {
  563.             make_playlist(playmode, 0);
  564.             pl_find_track(cur_track);
  565.         }
  566.     }
  567.     else
  568.     {
  569.         make_playlist(get_playmode(), 0);
  570.         play_next_entry();
  571.     }
  572. }
  573.  
  574. /*
  575.  * Set up the interval timers.
  576.  */
  577. void
  578. setup_itimer(ip, interval)
  579.     window1_objects *ip;
  580.     int        interval;
  581. {
  582.     static struct itimerval it;
  583.  
  584.     it.it_value.tv_sec = 0;
  585.     it.it_value.tv_usec = 500000;
  586.     it.it_interval.tv_sec = interval;
  587.     it.it_interval.tv_usec = interval ? 0 : 500000;
  588.     notify_set_itimer_func(ip->window1, handle_timer, ITIMER_REAL,
  589.         &it, NULL);
  590. }
  591.  
  592. /*
  593.  * Stash the current settings away in memory (in preparation for changing
  594.  * tracks, for instance, or before a save.)
  595.  */
  596. void
  597. keep_settings(ip)
  598.     window1_objects    *ip;
  599. {
  600.     popup1_objects    *pu = Workman_popup1;
  601.  
  602.     stash_cdinfo(xv_get(pu->artist, PANEL_VALUE),
  603.         xv_get(pu->cdname, PANEL_VALUE),
  604.         xv_get(pu->autoplay, PANEL_VALUE),
  605.         xv_get(pu->playmode, PANEL_VALUE), NULL);
  606.     if (pop_track > 0)
  607.         stash_trkinfo(pop_track, xv_get(pu->trackname, PANEL_VALUE),
  608.             xv_get(pu->trackoptions, PANEL_VALUE) & 1,
  609.             xv_get(pu->trackoptions, PANEL_VALUE) & 2);
  610. }
  611.  
  612. /*
  613.  * Notify callback function for `mode'.
  614.  */
  615. void
  616. change_mode(item, value, event)
  617.     Panel_item    item;
  618.     int        value;
  619.     Event        *event;
  620. {
  621.     window1_objects *ip = Workman_window1;
  622.     int    track, playmode;
  623.  
  624.     if (cur_cdmode == 5)
  625.         return;
  626.  
  627.     switch (value) {
  628.     case 0:        /* back a track */
  629.         if (cur_cdmode == 4)
  630.             if (cur_track > 0)
  631.                 cur_track = cur_track == 1 ? cur_ntracks :
  632.                     cur_track - 1;
  633.             else
  634.                 cur_track = cur_ntracks;
  635.         if (cur_cdmode == 1)
  636.         {
  637.             play_prev_track();
  638.             cd_status();
  639.         }
  640.         if (cur_cdmode == 1 || cur_cdmode == 4)
  641.             xv_set(ip->mode, PANEL_VALUE, cur_cdmode, NULL);
  642.  
  643.         if (xv_get(Workman_goodies->abrepeat, PANEL_VALUE))
  644.             xv_set(Workman_goodies->abrepeat, PANEL_VALUE, FALSE,
  645.                 NULL);
  646.         displayed_track = -1;
  647.         if (cur_track < cur_firsttrack)
  648.             cur_track = cur_firsttrack;
  649.         show_stats(ip);
  650.         break;
  651.  
  652.     case 1:        /* play */
  653.         if (cur_cdmode == 3)
  654.         {
  655.             pause_cd();
  656.             show_stats(ip);
  657.             break;
  658.         }
  659.         if (cur_cdmode == 4)
  660.         {
  661.             /* XXX should call make_initial_playlist() */
  662.             track = xv_get(ip->tracks, PANEL_VALUE) + 1;
  663.             playmode = xv_get(ip->shuffle, PANEL_VALUE);
  664.             if (playmode == 1)
  665.                 make_playlist(1, track);
  666.             else
  667.             {
  668.                 make_playlist(playmode, 0);
  669.                 if (track)
  670.                 {
  671.                     pl_find_track(track);
  672.                     cur_track = track;
  673.                     cur_cdmode = 1;
  674.                     play_from_pos(0);
  675.                     displayed_track = -1;
  676.                 }
  677.             }
  678.         }
  679.         if (cur_cdmode != 1)
  680.             play_next_entry();
  681.         cd_status();
  682.  
  683.         /* We're at the end of the previous track. */
  684.         if (cur_track < cur_firsttrack)
  685.             cur_track = cur_firsttrack;
  686.  
  687.         if (displayed_track == -1)
  688.             new_track(ip);
  689.         break;
  690.  
  691.     case 2:        /* forward a track */
  692.         if (cur_cdmode == 4)
  693.             if (cur_track > 0)
  694.                 cur_track = cur_track == cur_ntracks ? 1 :
  695.                     cur_track + 1;
  696.             else
  697.                 cur_track = 1;
  698.         if (cur_cdmode == 1)
  699.         {
  700.             play_next_track();
  701.             if (cur_cdmode == 4)
  702.                 goto stopped;
  703.             cd_status();
  704.         }
  705.         if (cur_cdmode == 1 || cur_cdmode == 4)
  706.             xv_set(ip->mode, PANEL_VALUE, cur_cdmode, NULL);
  707.  
  708.         if (xv_get(Workman_goodies->abrepeat, PANEL_VALUE))
  709.             xv_set(Workman_goodies->abrepeat, PANEL_VALUE, FALSE,
  710.                 NULL);
  711.         if (cur_track < cur_firsttrack)
  712.             cur_track = cur_firsttrack;
  713.         show_stats(ip);
  714.         break;
  715.  
  716.     case 3:        /* pause */
  717.         pause_cd();
  718.         show_stats(ip);
  719.         break;
  720.     case 4:        /* stop */
  721.         stop_cd();
  722.         cd_status();
  723. stopped:
  724.         new_trackname_display("", 0);
  725.         reset_cdlen(ip);
  726.         icon_label("Stop");
  727.         xv_set(ip->tracks, PANEL_VALUE, -1, NULL);
  728.         xv_set(Workman_goodies->abrepeat, PANEL_VALUE, FALSE, NULL);
  729.         xv_set(Workman_goodies->split, PANEL_INACTIVE, TRUE, NULL);
  730.         xv_set(Workman_goodies->delete, PANEL_INACTIVE, TRUE, NULL);
  731.         displayed_track = -1;
  732.         cur_track = -1;
  733.         break;
  734.     case 5:        /* eject */
  735.         keep_settings(ip);
  736.  
  737.         if (info_modified)
  738.         {
  739.             xv_set(wannasave, XV_SHOW, TRUE, NULL);
  740.             if (confirmsave)
  741.                 save_config(NULL, NULL);
  742.             info_modified = 0;
  743.         }
  744.  
  745.         switch (eject_cd()) {
  746.         case 0:
  747.             setup_itimer(ip, 5);
  748.             kill_stats(ip);
  749.             break;
  750.         case 1:
  751.             xv_set(ip->mode, PANEL_VALUE, 4, NULL);
  752.             break;    /* XXX - should display an error popup */
  753.         case 2:
  754.             xv_set(ip->mode, PANEL_VALUE, 4, NULL);
  755.             xv_set(mountedfs, XV_SHOW, TRUE, NULL);
  756.             break;
  757.         }
  758.  
  759.         break;
  760.     }
  761. }
  762.  
  763. /*
  764.  * Notify callback function for `button2'.  Show the CD Info popup.
  765.  */
  766. void
  767. window1_button2_notify_callback(item, event)
  768.     Panel_item    item;
  769.     Event        *event;
  770. {
  771.     window1_objects *ip = Workman_window1;
  772.     int        cdi_width, cdi_height, wm_width, wm_x, c;
  773.     static int    positioned = 0;
  774.     Xv_Screen    screen;
  775.     Display        *dpy;
  776.  
  777.     /*
  778.      * CD Info is positioned (badly) at this point.  It goes to the right
  779.      * of the main window if it'll fit, to the left if not, aligned with
  780.      * the top of the main window as closely as possible.  This is not
  781.      * as nice as it could be, but is probably as nice as it's gonna get.
  782.      *
  783.      * XXX We make (BAD BAD BAD) assumptions about the size of the window
  784.      *    decorations so things line up right under olwm.
  785.      */
  786.     if (! positioned)
  787.     {
  788.         positioned = 1;
  789.         dpy = (Display *) xv_get(ip->window1, XV_DISPLAY);
  790.         screen = (Xv_Screen) xv_get(ip->window1, XV_SCREEN);
  791.         c = (int) xv_get(screen, SCREEN_NUMBER);
  792.         cdi_width = (int) xv_get(Workman_popup1->popup1, XV_WIDTH);
  793.         cdi_height = (int) xv_get(Workman_popup1->popup1, XV_HEIGHT);
  794.         wm_width = (int) xv_get(ip->window1, XV_WIDTH);
  795.         wm_x = (int) xv_get(ip->window1, XV_X);
  796.         if (wm_width + cdi_width + 10 + (int) xv_get(ip->window1,
  797.                 XV_X) > DisplayWidth(dpy, c))
  798.             xv_set(Workman_popup1->popup1, XV_X, wm_x - cdi_width -
  799.                 20 < 0 ? 0 : wm_x - cdi_width - 20, NULL);
  800.         else
  801.             xv_set(Workman_popup1->popup1, XV_X, wm_x + wm_width +
  802.                 10, NULL);
  803.         if ((int) xv_get(ip->window1, XV_Y) + cdi_height >
  804.                             DisplayHeight(dpy, c))
  805.             xv_set(Workman_popup1->popup1, XV_Y,
  806.                 DisplayHeight(dpy, c) - cdi_height - 28, NULL);
  807.         else
  808.             xv_set(Workman_popup1->popup1, XV_Y, xv_get(ip->
  809.                 window1, XV_Y) - 25, NULL);
  810.     }
  811.     
  812.     if (dismiss_button && item == ip->button2 ||
  813.         xv_get(Workman_popup1->popup1, FRAME_CMD_PUSHPIN_IN) == FALSE)
  814.     {
  815.         xv_set(Workman_popup1->popup1, FRAME_CMD_PUSHPIN_IN, TRUE,
  816.             NULL);
  817.         xv_set(Workman_popup1->popup1, XV_SHOW, TRUE, NULL);
  818.         if (xv_get(Workman_plpopup->plpopup, XV_KEY_DATA,
  819.                             FRAME_CMD_PUSHPIN_IN))
  820.             xv_set(Workman_plpopup->plpopup, XV_SHOW, TRUE,
  821.                 FRAME_CMD_PUSHPIN_IN, TRUE, XV_KEY_DATA,
  822.                 FRAME_CMD_PUSHPIN_IN, FALSE, NULL);
  823.     }
  824.     else
  825.     {
  826.         xv_set(Workman_popup1->popup1, FRAME_CMD_PUSHPIN_IN, FALSE,
  827.             XV_SHOW, FALSE, NULL);
  828.         xv_set(Workman_plpopup->plpopup, FRAME_CMD_PUSHPIN_IN, FALSE,
  829.             XV_KEY_DATA, FRAME_CMD_PUSHPIN_IN,
  830.             xv_get(Workman_plpopup->plpopup, FRAME_CMD_PUSHPIN_IN),
  831.             XV_SHOW, FALSE, NULL);
  832.     }
  833. }
  834.  
  835. /*
  836.  * Notify callback function for `delete'.
  837.  */
  838. void
  839. delete_from_playlist(item, event)
  840.     Panel_item    item;
  841.     Event        *event;
  842. {
  843.     plpopup_objects *ip = Workman_plpopup;
  844.     int i;
  845.     
  846.     info_modified = 1;
  847.  
  848.     if (pl_item >= 0)
  849.     {
  850.         xv_set(ip->playlist, PANEL_LIST_SELECT, pl_item, FALSE,
  851.             PANEL_LIST_DELETE, pl_item, NULL);
  852.         for (i = pl_item; i < pop_listsize; i++)
  853.             pop_list[i] = pop_list[i + 1];
  854.         if (--pop_listsize)
  855.         {
  856.             if (pl_item == pop_listsize)
  857.                 pl_item--;
  858.             xv_set(ip->playlist, PANEL_LIST_SELECT, pl_item,
  859.                 TRUE, NULL);
  860.             cd->lists[pl_listnum].list = pop_list;
  861.         }
  862.         else
  863.         {
  864.             pl_item = -1;
  865.             xv_set(ip->delete, PANEL_INACTIVE, TRUE, NULL);
  866.             free(pop_list);
  867.             pop_list = NULL;
  868.             cd->lists[pl_listnum].list = pop_list;
  869.         }
  870.     }
  871. }
  872.  
  873. /*
  874.  * Notify callback function for `tracks'.
  875.  */
  876. void
  877. change_track(item, value, event)
  878.     Panel_item    item;
  879.     int        value;
  880.     Event        *event;
  881. {
  882.     window1_objects *ip = Workman_window1;
  883.     
  884.     if (cur_cdlen > 0 && cur_cdmode != 5)
  885.     {
  886.         if (value == -1)
  887.         {
  888.             if (cur_cdmode == 1 || cur_cdmode == 3)
  889.                 xv_set(item, PANEL_VALUE, cur_track - 1, NULL);
  890.             else
  891.             {
  892.                 xv_set(Workman_goodies->split, PANEL_INACTIVE,
  893.                     TRUE, NULL);
  894.                 xv_set(Workman_goodies->delete, PANEL_INACTIVE,
  895.                     TRUE, NULL);
  896.                 cur_track = -1;
  897.             }
  898.         }
  899.         else
  900.             cur_track = value + 1;
  901.  
  902.         if (cur_cdmode == 1)
  903.         {
  904.             pl_find_track(cur_track);
  905.             play_from_pos(0);
  906.             cd_status();
  907.             if (cur_track < cur_firsttrack)
  908.                 cur_track = cur_firsttrack;
  909.         }
  910.         new_track(ip);
  911.     }
  912. }
  913.  
  914. /*
  915.  * Notify callback function for `songpos'.
  916.  */
  917. void
  918. change_pos(item, value, event)
  919.     Panel_item    item;
  920.     int        value;
  921.     Event        *event;
  922. {
  923.     window1_objects *ip = Workman_window1;
  924.     char    time[6];
  925.     int    value_left;
  926.     
  927.     time_wanted = value;
  928.  
  929.     if (cur_cdmode == 4 && cur_track > 0)
  930.     {
  931.         if (! xv_get(Workman_goodies->timemode, PANEL_VALUE))
  932.             sprintf(time, "%02d:%02d", value / 60, value % 60);
  933.         else
  934.         {
  935.             value_left = tracklen(cur_track - 1) - value;
  936.             if (value < 0)
  937.                 value = 0;
  938.             sprintf(time, "%02d:%02d", value_left / 60,
  939.                             value_left % 60);
  940.         }
  941.  
  942.         xv_set(Workman_window1->tracktimer, PANEL_LABEL_STRING, time,
  943.             NULL);
  944.         cur_pos_rel = time_wanted;
  945.         cur_frame = cd->trk[cur_track - 1].start + time_wanted * 75;
  946.         cur_pos_abs = cur_frame / 75;
  947.     }
  948.  
  949.     if (xv_get(Workman_goodies->abrepeat, PANEL_VALUE))
  950.         xv_set(Workman_goodies->abrepeat, PANEL_VALUE, FALSE, NULL);
  951. }
  952.  
  953. /*
  954.  * Notify callback function for `artist'.
  955.  */
  956. Panel_setting
  957. update_title(item, event)
  958.     Panel_item    item;
  959.     Event        *event;
  960. {
  961.     popup1_objects *ip = Workman_popup1;
  962.     char *title;
  963.  
  964.     if (! my_cdname)
  965.     {
  966.         title = (char *) xv_get(ip->cdname, PANEL_VALUE);
  967.         if (title == NULL || title[0] == '\0')
  968.             title = "Unknown CD name";
  969.         xv_set(Workman_window1->cdname_display, PANEL_LABEL_STRING,
  970.             title, NULL);
  971.  
  972.         center_titles();
  973.     }
  974.  
  975.     if (! my_artist)
  976.     {
  977.         title = (char *) xv_get(ip->artist, PANEL_VALUE);
  978.         if (title == NULL || title[0] == '\0')
  979.             title = "Unknown artist";
  980.         xv_set(Workman_window1->artist_display, PANEL_LABEL_STRING,
  981.             title, NULL);
  982.  
  983.         center_titles();
  984.     }
  985.  
  986.     if (event == NULL)
  987.         return (NULL);
  988.     return panel_text_notify(item, event);
  989. }
  990.  
  991. /*
  992.  * Notify callback function for `tracklist'.
  993.  */
  994. int
  995. update_trackname(item, string, client_data, op, event, row)
  996.     Panel_item    item;
  997.     char        *string;
  998.     Xv_opaque    client_data;
  999.     Panel_list_op    op;
  1000.     Event        *event;
  1001.     int        row;
  1002. {
  1003.     popup1_objects *ip = Workman_popup1;
  1004.     int    options;
  1005.     char    *name;
  1006.  
  1007.     switch(op) {
  1008.     case PANEL_LIST_OP_DESELECT:
  1009.     case PANEL_LIST_OP_VALIDATE:
  1010.         if (! pop_track)    /* workaround for bug 1090204 */
  1011.             break;
  1012.         options = xv_get(ip->trackoptions, PANEL_VALUE);
  1013.         name = (char *) xv_get(ip->trackname, PANEL_VALUE);
  1014.         stash_trkinfo(row + 1, name, options & 1, (options & 2) >> 1);
  1015.         xv_set(ip->tracklist, PANEL_LIST_STRING, row, listentry(row),
  1016.             NULL);
  1017.         if (cur_track - 1 == row)
  1018.             new_trackname_display(name, cur_track);
  1019.         if (op == PANEL_LIST_OP_DESELECT)
  1020.         {
  1021.             xv_set(ip->trackname, PANEL_VALUE, empty, NULL);
  1022.             pop_track = 0;
  1023.         }
  1024.         break;
  1025.  
  1026.     case PANEL_LIST_OP_SELECT:
  1027.         xv_set(ip->trackname, PANEL_VALUE, trackname(row), NULL);
  1028.         xv_set(ip->trackoptions, PANEL_VALUE, (get_avoid(row) ? 2 : 0) |
  1029.             (get_contd(row) ? 1 : 0), NULL);
  1030.         pop_track = row + 1;
  1031.         if (xv_get(ip->whichvolume, PANEL_VALUE))
  1032.         {
  1033.             xv_set(ip->defaultvolume, PANEL_VALUE,
  1034.                 get_default_volume(row + 1), NULL);
  1035.             set_default_volume(ip->defaultvolume,
  1036.                 get_default_volume(row + 1), NULL);
  1037.         }
  1038.         break;
  1039.  
  1040.     case PANEL_LIST_OP_DELETE:
  1041.         break;
  1042.     }
  1043.  
  1044.     return XV_OK;
  1045. }
  1046.  
  1047. /*
  1048.  * Notify callback function for `trackname'.
  1049.  */
  1050. Panel_setting
  1051. name_entered(item, event)
  1052.     Panel_item    item;
  1053.     Event        *event;
  1054. {
  1055.     popup1_objects *ip = Workman_popup1;
  1056.     char *    value = (char *) xv_get(item, PANEL_VALUE);
  1057.     int    next_track = 0;
  1058.     Panel_setting    retval;
  1059.     
  1060.     switch (event_action(event))
  1061.     {
  1062.         case '\n':
  1063.         case '\r':
  1064.         case '\033':
  1065.             retval = PANEL_NONE;
  1066.             next_track = 1;
  1067.             break;
  1068.         case '\t':
  1069.             retval = PANEL_NEXT;
  1070.             break;
  1071.         default:
  1072.             retval = panel_text_notify(item, event);
  1073.     }
  1074.  
  1075. /* If a track was selected, save the current settings and go to the next. */
  1076.     if (pop_track)
  1077.     {
  1078.         if (next_track)
  1079.         {
  1080.             next_track = pop_track;
  1081.             if (next_track == cur_ntracks)
  1082.                 next_track = 0;
  1083.             xv_set(ip->tracklist, PANEL_LIST_SELECT, pop_track - 1,
  1084.                 FALSE, NULL);
  1085.             update_trackname(ip->tracklist, listentry(pop_track -
  1086.                 1), NULL, PANEL_LIST_OP_DESELECT, event,
  1087.                 pop_track - 1);
  1088.             xv_set(ip->tracklist, PANEL_LIST_SELECT, next_track,
  1089.                 TRUE, NULL);
  1090.             update_trackname(ip->tracklist, listentry(next_track),
  1091.                 NULL, PANEL_LIST_OP_SELECT, event, next_track);
  1092.         }
  1093.         else
  1094.             update_trackname(ip->tracklist, listentry(pop_track -
  1095.                 1), NULL, PANEL_LIST_OP_VALIDATE, event,
  1096.                 pop_track - 1);
  1097.     }
  1098.  
  1099.     return (retval);
  1100. }
  1101.  
  1102. /*
  1103.  * Notify callback function for `shuffle'.
  1104.  */
  1105. void
  1106. next_playmode_default(item, value, event)
  1107.     Panel_item    item;
  1108.     int        value;
  1109.     Event        *event;
  1110. {
  1111.     window1_objects *ip = Workman_window1;
  1112.     int    newdefault;
  1113.     
  1114.     if (value == 0)
  1115.         newdefault = 1;
  1116.     else
  1117.         if (cd->lists == NULL || cd->lists[value - 1].name == NULL)
  1118.             newdefault = 0;
  1119.         else
  1120.             newdefault = value + 1;
  1121.  
  1122.     xv_set(item, PANEL_DEFAULT_VALUE, newdefault, NULL);
  1123. }
  1124.  
  1125. /*
  1126.  * Notify callback function for `playlist'.
  1127.  */
  1128. int
  1129. playlist_notify(item, string, client_data, op, event, row)
  1130.     Panel_item    item;
  1131.     char        *string;
  1132.     Xv_opaque    client_data;
  1133.     Panel_list_op    op;
  1134.     Event        *event;
  1135.     int        row;
  1136. {
  1137.     plpopup_objects *ip = Workman_plpopup;
  1138.     
  1139.     switch(op) {
  1140.     case PANEL_LIST_OP_DESELECT:
  1141.         pl_item = -1;
  1142.         xv_set(ip->delete, PANEL_INACTIVE, TRUE, NULL);
  1143.         break;
  1144.  
  1145.     case PANEL_LIST_OP_SELECT:
  1146.         pl_item = row;
  1147.         xv_set(ip->delete, PANEL_INACTIVE, FALSE, NULL);
  1148.         break;
  1149.  
  1150.     case PANEL_LIST_OP_VALIDATE:
  1151.     case PANEL_LIST_OP_DELETE:
  1152.         break;
  1153.     }
  1154.     return XV_OK;
  1155. }
  1156.  
  1157. static unsigned short speaker_bits[8][15] = { {
  1158. #include "bitmaps/loud0.icon"
  1159. }, {
  1160. #include "bitmaps/loud1.icon"
  1161. }, {
  1162. #include "bitmaps/loud2.icon"
  1163. }, {
  1164. #include "bitmaps/loud3.icon"
  1165. }, {
  1166. #include "bitmaps/loud4.icon"
  1167. }, {
  1168. #include "bitmaps/loud5.icon"
  1169. }, {
  1170. #include "bitmaps/loud6.icon"
  1171. }, {
  1172. #include "bitmaps/loud.icon"
  1173. } };
  1174.  
  1175. /*
  1176.  * Notify callback function for `volume'.
  1177.  */
  1178. void
  1179. set_volume(item, value, event)
  1180.     Panel_item    item;
  1181.     int        value;
  1182.     Event        *event;
  1183. {
  1184.     window1_objects *ip = Workman_window1;
  1185.     static int    old_image = 7;
  1186.     Xv_opaque    old_serverimage;
  1187.     int        max = xv_get(item, PANEL_MAX_VALUE);
  1188.     int        new_image;
  1189.     int        leftval, rightval;
  1190.  
  1191.     manual_volume = 1;
  1192.  
  1193.     /* we want this to look sort of logarithmic */
  1194.     new_image = value / (max / 8);
  1195.  
  1196.     if (cur_balance < 9)
  1197.         rightval = value - (9 - cur_balance) * 2;
  1198.     else
  1199.         rightval = value;
  1200.  
  1201.     if (cur_balance > 11)
  1202.         leftval = value - (cur_balance - 11) * 2;
  1203.     else
  1204.         leftval = value;
  1205.  
  1206.     leftval = ((max * max) - ((max - leftval) * (max - leftval))) * 127 /
  1207.         (max * max) + 128;
  1208.     rightval = ((max * max) - ((max - rightval) * (max - rightval))) * 127 /
  1209.         (max * max) + 128;
  1210.  
  1211.     /* volumes 128 or lower seem useless */
  1212.     cd_volume(leftval, rightval);
  1213.  
  1214.     /* maybe show a new icon... */
  1215.     if (new_image > 7)
  1216.         new_image = 7;
  1217.     if (new_image != old_image)
  1218.     {
  1219.         old_serverimage = xv_get(ip->speaker, PANEL_LABEL_IMAGE);
  1220.         xv_set(ip->speaker, PANEL_LABEL_IMAGE, xv_create(XV_NULL,
  1221.             SERVER_IMAGE, SERVER_IMAGE_DEPTH, 1, XV_WIDTH, 16,
  1222.             XV_HEIGHT, 15, SERVER_IMAGE_BITS,
  1223.             speaker_bits[new_image], NULL), NULL);
  1224.         xv_destroy(old_serverimage);
  1225.         old_image = new_image;
  1226.     }
  1227. }
  1228.  
  1229. /*
  1230.  * Figure out the proper volume for this track and set it.  If the user has
  1231.  * touched the manual volume knob, use that setting instead of any default.
  1232.  *
  1233.  * XXX defaults should still affect the volume depending on how much the
  1234.  * user changed it manually.
  1235.  */
  1236. void
  1237. figure_volume(ip)
  1238.     window1_objects *ip;
  1239. {
  1240.     int volume = 0, old_manual = manual_volume;
  1241.  
  1242.     if (! manual_volume)
  1243.     {
  1244.         if (cur_track)
  1245.             volume = get_default_volume(cur_track);
  1246.         if (! volume)
  1247.             volume = get_default_volume(0);
  1248.     }
  1249.     if (! volume)
  1250.         volume = xv_get(ip->volume, PANEL_VALUE);
  1251.     xv_set(ip->volume, PANEL_VALUE, volume, NULL);
  1252.     set_volume(ip->volume, volume, NULL);
  1253.     manual_volume = old_manual;
  1254. }
  1255.  
  1256. /*
  1257.  * Notify callback function for `button3'.
  1258.  */
  1259. void
  1260. window1_button3_notify_callback(item, event)
  1261.     Panel_item    item;
  1262.     Event        *event;
  1263. {
  1264.     window1_objects *ip = Workman_window1;
  1265.     
  1266.     if (dismiss_button && item == ip->button3 ||
  1267.         xv_get(Workman_about->about, FRAME_CMD_PUSHPIN_IN) == FALSE)
  1268.     {
  1269.         xv_set(Workman_about->about, FRAME_CMD_PUSHPIN_IN, TRUE, NULL);
  1270.         xv_set(Workman_about->about, XV_SHOW, TRUE, NULL);
  1271.     }
  1272.     else
  1273.         xv_set(Workman_about->about, FRAME_CMD_PUSHPIN_IN, FALSE,
  1274.             XV_SHOW, FALSE, NULL);
  1275. }
  1276.  
  1277. /*
  1278.  * Notify callback function for `defaultvolume'.
  1279.  */
  1280. void
  1281. set_default_volume(item, value, event)
  1282.     Panel_item    item;
  1283.     int        value;
  1284.     Event        *event;
  1285. {
  1286.     popup1_objects *ip = Workman_popup1;
  1287.     static int    old_image = -1;
  1288.     Xv_opaque    old_serverimage;
  1289.     int        max = xv_get(item, PANEL_MAX_VALUE);
  1290.     int        new_image;
  1291.     static int    old_manual, old_volume = -1;
  1292.  
  1293.     /*
  1294.      * Make the real volume track the default volume while the user is
  1295.      * sliding the default slider.
  1296.      */
  1297.     if (event != NULL)
  1298.     {
  1299.         info_modified = 1;
  1300.  
  1301.         if (event_is_up(event))
  1302.         {
  1303.             if (old_volume != -1)
  1304.                 xv_set(Workman_window1->volume, PANEL_VALUE,
  1305.                     old_volume, NULL);
  1306.             old_volume = -1;
  1307.         }
  1308.         else
  1309.         {
  1310.             if (old_volume == -1)
  1311.                 old_volume = xv_get(Workman_window1->volume,
  1312.                     PANEL_VALUE);
  1313.             if (value)
  1314.                 xv_set(Workman_window1->volume, PANEL_VALUE,
  1315.                     value - 1, NULL);
  1316.         }
  1317.         figure_volume(Workman_window1);
  1318.     }
  1319.  
  1320.     /* we want this to look sort of logarithmic */
  1321.     if (value)
  1322.     {
  1323.         default_volume(xv_get(ip->whichvolume, PANEL_VALUE) * pop_track,
  1324.             value);
  1325.         new_image = value / (max / 8);
  1326.         value = (max * max) - ((max - value) * (max - value));
  1327.     }
  1328.     else
  1329.     {
  1330.         new_image = -1;
  1331.         default_volume(xv_get(ip->whichvolume, PANEL_VALUE) * pop_track,
  1332.             0);
  1333.     }
  1334.  
  1335.     /* maybe show a new icon... */
  1336.     if (new_image > 7)
  1337.         new_image = 7;
  1338.     if (old_image > -1)
  1339.         old_serverimage = xv_get(ip->defaultspeaker, PANEL_LABEL_IMAGE);
  1340.     if (new_image != old_image && new_image > -1)
  1341.     {
  1342.         xv_set(ip->defaultspeaker, PANEL_LABEL_IMAGE,
  1343.             xv_create(XV_NULL, SERVER_IMAGE, SERVER_IMAGE_DEPTH, 1,
  1344.             XV_WIDTH, 16, XV_HEIGHT, 15, SERVER_IMAGE_BITS,
  1345.             speaker_bits[new_image], NULL), NULL);
  1346.         if (old_image > 0)
  1347.             xv_destroy(old_serverimage);
  1348.         old_image = new_image;
  1349.     }
  1350.     if (new_image != old_image && new_image == -1)
  1351.     {
  1352.         xv_destroy(old_serverimage);
  1353.         xv_set(ip->defaultspeaker, PANEL_LABEL_STRING, "None", NULL);
  1354.         old_image = -1;
  1355.     }
  1356. }
  1357.  
  1358. /*
  1359.  * Notify callback function for `whichvolume'.
  1360.  */
  1361. void
  1362. set_which_volume(item, value, event)
  1363.     Panel_item    item;
  1364.     int        value;
  1365.     Event        *event;
  1366. {
  1367.     popup1_objects *ip = Workman_popup1;
  1368.     int    vol;
  1369.  
  1370.     if (value == 1 && ! pop_track)
  1371.     {
  1372.         xv_set(item, PANEL_VALUE, 0, NULL);
  1373.         value = 0;
  1374.     }
  1375.  
  1376.     xv_set(item, PANEL_DEFAULT_VALUE, (value + 1) % 2, NULL);
  1377.     xv_set(ip->defaultvolume, PANEL_VALUE, vol = get_default_volume(value ?
  1378.         pop_track : 0), NULL);
  1379.     set_default_volume(ip->defaultvolume, vol, NULL);
  1380. }
  1381.  
  1382. /*
  1383.  * Notify callback function for `button4'.
  1384.  */
  1385. void
  1386. window1_button4_notify_callback(item, event)
  1387.     Panel_item    item;
  1388.     Event        *event;
  1389. {
  1390.     window1_objects *ip = Workman_window1;
  1391.     
  1392.     if (dismiss_button && item == ip->button4 ||
  1393.         xv_get(Workman_goodies->goodies, FRAME_CMD_PUSHPIN_IN) == FALSE)
  1394.     {
  1395.         xv_set(Workman_goodies->goodies, FRAME_CMD_PUSHPIN_IN, TRUE,
  1396.             NULL);
  1397.         xv_set(Workman_goodies->goodies, XV_SHOW, TRUE, NULL);
  1398.     }
  1399.     else
  1400.         xv_set(Workman_goodies->goodies, FRAME_CMD_PUSHPIN_IN, FALSE,
  1401.             XV_SHOW, FALSE, NULL);
  1402. }
  1403.  
  1404. static unsigned short phone_bits[7][22] = { {
  1405. #include "bitmaps/phonesl3"
  1406. }, {
  1407. #include "bitmaps/phonesl2"
  1408. }, {
  1409. #include "bitmaps/phonesl1"
  1410. }, {
  1411. #include "bitmaps/phones0"
  1412. }, {
  1413. #include "bitmaps/phonesr1"
  1414. }, {
  1415. #include "bitmaps/phonesr2"
  1416. }, {
  1417. #include "bitmaps/phonesr3"
  1418. } };
  1419.  
  1420. /*
  1421.  * Notify callback function for `balance'.
  1422.  */
  1423. void
  1424. slide_balance(item, value, event)
  1425.     Panel_item    item;
  1426.     int        value;
  1427.     Event        *event;
  1428. {
  1429.     goodies_objects *ip = Workman_goodies;
  1430.     static int    old_image = 3;
  1431.     Xv_opaque    old_serverimage;
  1432.     int        max = xv_get(item, PANEL_MAX_VALUE);
  1433.     int        new_image;
  1434.  
  1435.     new_image = value / (max / 6);
  1436.  
  1437.     /* maybe show a new icon... */
  1438.     if (new_image > 6)
  1439.         new_image = 6;
  1440.     if (new_image != old_image)
  1441.     {
  1442.         old_serverimage = xv_get(ip->phones, PANEL_LABEL_IMAGE);
  1443.         xv_set(ip->phones, PANEL_LABEL_IMAGE, xv_create(XV_NULL,
  1444.             SERVER_IMAGE, SERVER_IMAGE_DEPTH, 1, XV_WIDTH, 16,
  1445.             XV_HEIGHT, 22, SERVER_IMAGE_BITS,
  1446.             phone_bits[new_image], NULL), NULL);
  1447.         xv_destroy(old_serverimage);
  1448.         old_image = new_image;
  1449.     }
  1450.  
  1451.     cur_balance = value;
  1452.     figure_volume(Workman_window1);
  1453. }
  1454.  
  1455. /*
  1456.  * Notify callback function for `repeat'.
  1457.  * Change the current stopmode; then select a new default value for the
  1458.  * choice item.  Wrap around when we hit the end of the playlists.
  1459.  */
  1460. void
  1461. next_stopmode(item, value, event)
  1462.     Panel_item    item;
  1463.     int        value;
  1464.     Event        *event;
  1465. {
  1466.     window1_objects *ip = Workman_window1;
  1467.  
  1468.     cur_stopmode = value;
  1469.     xv_set(item, PANEL_DEFAULT_VALUE, (value + 1) % 3, NULL);
  1470. }
  1471.  
  1472. /*
  1473.  * Event notify procedure for text fields, so the PANEL_NOTIFY_PROC gets
  1474.  * called when the user clicks on another field.
  1475.  */
  1476. void
  1477. text_event_p(item, event)
  1478.     Panel_item    item;
  1479.     Event        *event;
  1480. {
  1481.     Panel_setting   (*fp)();
  1482.     int               e;
  1483.     char             *pns;
  1484.     Panel_setting     level;
  1485.     static Panel_item last_item = NULL;
  1486.     Xv_opaque         parent;
  1487.     Xv_pkg           *pack;
  1488.  
  1489.     e = event_id(event);
  1490.  
  1491. /* call last_item's PANEL_NOTIFY_PROC if user mouse clicks off it
  1492.    but don't do this if PANEL_NOTIFY_PROC already gets triggered via kbd */
  1493.     if ( (item != last_item) && (event_action(event) == ACTION_SELECT) &&
  1494.         (last_item != NULL) )
  1495.     {
  1496.         level = (Panel_setting) xv_get(last_item, PANEL_NOTIFY_LEVEL);
  1497.         switch (level)
  1498.         {
  1499.         case PANEL_NONE:
  1500.             break;
  1501.         case PANEL_NON_PRINTABLE:
  1502.             break;
  1503.         case PANEL_SPECIFIED:
  1504.             pns = (char *)xv_get(last_item, PANEL_NOTIFY_STRING);
  1505.             if ( strchr( pns, (char)e ) != NULL)
  1506.                 break;
  1507.         case PANEL_ALL:
  1508.         default:
  1509.             fp = (Panel_setting (*)())
  1510.                 xv_get(last_item, PANEL_NOTIFY_PROC);
  1511.             (*fp)(last_item, event);
  1512.             break;
  1513.         }
  1514.     }
  1515.  
  1516.     /* save last item in static var */
  1517.     last_item = item;
  1518.  
  1519.     (text_event_handler)(item, event);
  1520. }
  1521.  
  1522. /*
  1523.  * Notify callback function for `abrepeat'.
  1524.  */
  1525. void
  1526. goodies_abrepeat_notify_callback(item, value, event)
  1527.     Panel_item    item;
  1528.     int        value;
  1529.     Event        *event;
  1530. {
  1531.     goodies_objects *ip = Workman_goodies;
  1532.     short    i;
  1533.     
  1534.     for (i = 0; i < 1; i++) {
  1535.         if (i == 0 && (value & 01))
  1536.         {
  1537.             start_repeating(item, value, event);
  1538.         }
  1539.         
  1540.         if (i == 0 && !(value & 01))
  1541.         {
  1542.             stop_repeating(item, value, event);
  1543.         }
  1544.         value >>= 1;
  1545.     }
  1546. }
  1547.  
  1548. /*
  1549.  * User-defined action for `abrepeat'.
  1550.  */
  1551. void
  1552. start_repeating(item, value, event)
  1553.     Panel_item    item;
  1554.     int        value;
  1555.     Event        *event;
  1556. {
  1557.     cur_firsttrack = cur_lasttrack = -1;
  1558.     play_chunk(mark_a, mark_b);
  1559. }
  1560.  
  1561. /*
  1562.  * Set one of the A-B repeat time messages.  "which" should be 0 for the A
  1563.  * timer and 1 for the B timer.
  1564.  */
  1565. void
  1566. set_abtimer(which, frame)
  1567.     int        which;
  1568.     int        frame;
  1569. {
  1570.     char    buf[30];
  1571.     int    tnum, relpos;
  1572.  
  1573.     if (frame < cd->trk[0].start || frame > cd->length * 75)
  1574.         return;
  1575.  
  1576.     for (tnum = 1; tnum < cur_ntracks; tnum++)
  1577.         if (frame < cd->trk[tnum].start)
  1578.             break;
  1579.     tnum--;
  1580.     relpos = (frame - cd->trk[tnum].start) / 75;
  1581.  
  1582.     sprintf(buf, "Track: %02d Time: %02d:%02d", cd->trk[tnum].track,
  1583.         relpos / 60, relpos % 60);
  1584.  
  1585.     if (which)
  1586.     {
  1587.         if (mark_a && frame <= mark_a)
  1588.             return;
  1589.  
  1590.         mark_b = frame;
  1591.         xv_set(Workman_goodies->blabel, PANEL_LABEL_STRING, buf, NULL);
  1592.     }
  1593.     else
  1594.     {
  1595.         if (mark_b && frame >= mark_b)
  1596.         {
  1597.             mark_b = 0;
  1598.             return;
  1599.         }
  1600.  
  1601.         mark_a = frame;
  1602.         xv_set(Workman_goodies->alabel, PANEL_INACTIVE, FALSE,
  1603.             PANEL_LABEL_STRING, buf, NULL);
  1604.     }
  1605.  
  1606.     if (mark_a && mark_b && mark_a < mark_b)
  1607.     {
  1608.         xv_set(Workman_goodies->abrepeat, PANEL_INACTIVE, FALSE, NULL);
  1609.         xv_set(Workman_goodies->blabel, PANEL_INACTIVE, FALSE, NULL);
  1610.     }
  1611. }
  1612.  
  1613. /*
  1614.  * Notify callback function for `a'.
  1615.  */
  1616. void
  1617. section_start(item, event)
  1618.     Panel_item    item;
  1619.     Event        *event;
  1620. {
  1621.     goodies_objects *ip = Workman_goodies;
  1622.     
  1623.     set_abtimer(0, cur_frame);
  1624.     xv_set(ip->blabel, PANEL_INACTIVE, TRUE, NULL);
  1625.     mark_b = 0;
  1626.     xv_set(ip->abrepeat, PANEL_VALUE, FALSE, PANEL_INACTIVE, TRUE, NULL);
  1627. }
  1628.  
  1629. /*
  1630.  * Notify callback function for `b'.
  1631.  */
  1632. void
  1633. section_end(item, event)
  1634.     Panel_item    item;
  1635.     Event        *event;
  1636. {
  1637.     goodies_objects *ip = Workman_goodies;
  1638.     char buf[30];
  1639.     
  1640.     set_abtimer(1, cur_frame);
  1641. }
  1642.  
  1643. /*
  1644.  * Notify callback function for `button6'.
  1645.  */
  1646. void
  1647. rename_playlist(item, event)
  1648.     Panel_item    item;
  1649.     Event        *event;
  1650. {
  1651.     plpopup_objects *ip = Workman_plpopup;
  1652.     char    *name = (char *) xv_get(ip->listname, PANEL_VALUE);
  1653.     int    i;
  1654.  
  1655.     info_modified = 1;
  1656.  
  1657.     if (name[0] == '\0' || pl_listnum == -1)
  1658.         return;
  1659.  
  1660.     for (i = 0; cd->lists[i].name != NULL; i++)
  1661.         if (i != pl_listnum && ! strcmp(name, cd->lists[i].name))
  1662.             break;
  1663.  
  1664.     if (cd->lists[i].name != NULL)
  1665.     {
  1666.         notice_prompt(ip->plpopup, event, NOTICE_FOCUS_XY,
  1667.             event_x(event), event_y(event), NOTICE_MESSAGE_STRINGS,
  1668.             "The name", name, "is already being used",
  1669.             NULL, NOTICE_BUTTON, "Comprendo", 101, NULL);
  1670.         return;
  1671.     }
  1672.  
  1673.     strmcpy(&cd->lists[pl_listnum].name, name);
  1674.     xv_set(ip->playlists, PANEL_LIST_STRING, pl_listnum, name, NULL);
  1675.     xv_set(Workman_window1->shuffle, PANEL_CHOICE_STRING, pl_listnum + 2,
  1676.         name, NULL);
  1677. }
  1678.  
  1679. /*
  1680.  * User-defined action for `button7'.
  1681.  * Add a new playlist to the system.  If the user has specified a name, use
  1682.  * it; otherwise make up a lettered name ("List X") based on the list's
  1683.  * position in the list of lists.
  1684.  */
  1685. void
  1686. add_playlist(item, event)
  1687.     Panel_item    item;
  1688.     Event        *event;
  1689. {
  1690.     plpopup_objects *ip = Workman_plpopup;
  1691.     char    *name = (char *) xv_get(ip->listname, PANEL_VALUE), *tmp = NULL;
  1692.     char    fakename[sizeof("List XXX")];
  1693.     int    i;
  1694.     char    c;
  1695.  
  1696.     info_modified = 1;
  1697.  
  1698.     if (name[0] == '\0')
  1699.     {
  1700.         name = fakename;
  1701.         strcpy(name, "List A");
  1702.         if (cd->lists != NULL && cd->lists[0].name != NULL)
  1703.             for (c = 'A'; c < 'z'; c++)
  1704.             {
  1705.                 name[sizeof("List")] = c;
  1706.                 for (i = 0; cd->lists[i].name != NULL; i++)
  1707.                     if (! strcmp(name, cd->lists[i].name))
  1708.                         break;
  1709.                 if (! cd->lists[i].name)
  1710.                     break;
  1711.                 if (c == 'Z')
  1712.                     c = 'a' - 1;
  1713.             }
  1714.     }
  1715.     else if (cd->lists != NULL)
  1716.         for (i = 0; cd->lists[i].name != NULL; i++)
  1717.             if (! strcmp(name, cd->lists[i].name))
  1718.                 break;
  1719.  
  1720.     if (cd->lists != NULL && cd->lists[i].name != NULL)
  1721.     {
  1722.         notice_prompt(ip->plpopup, event, NOTICE_FOCUS_XY,
  1723.             event_x(event), event_y(event), NOTICE_MESSAGE_STRINGS,
  1724.             "The name", name, "is already being used",
  1725.             NULL, NOTICE_BUTTON, "Comprendo", 101, NULL);
  1726.         return;
  1727.     }
  1728.  
  1729.     /* Make the list itself internally. */
  1730.     if (new_list(cd, name) == NULL)
  1731.     {
  1732.         perror("new_list");
  1733.         exit(1);
  1734.     }
  1735.  
  1736.     /* Add the list to the scrolling list of playlists. */
  1737.     i = (int) xv_get(ip->playlists, PANEL_LIST_NROWS);
  1738.     xv_set(ip->playlists, PANEL_LIST_INSERT, i, PANEL_LIST_STRING,
  1739.         i, name, PANEL_LIST_SELECT, i, TRUE, NULL);
  1740.     switch_playlists(ip->playlists, NULL, NULL, PANEL_LIST_OP_SELECT,
  1741.         NULL, i);
  1742.  
  1743.     /* ...And to the play mode choice item on the main window. */
  1744.     xv_set(Workman_window1->shuffle, PANEL_CHOICE_STRING, i + 2, name,
  1745.         NULL);
  1746.     if (xv_get(Workman_window1->shuffle, PANEL_DEFAULT_VALUE) == 0)
  1747.         xv_set(Workman_window1->shuffle, PANEL_DEFAULT_VALUE, i + 2,
  1748.             NULL);
  1749. }
  1750.  
  1751. /*
  1752.  * Notify callback function for `button5'.
  1753.  */
  1754. void
  1755. delete_playlist(item, event)
  1756.     Panel_item    item;
  1757.     Event        *event;
  1758. {
  1759.     plpopup_objects *ip = Workman_plpopup;
  1760.     int    nlists = xv_get(ip->playlists, PANEL_LIST_NROWS);
  1761.     int    shuf, i;
  1762.     
  1763.     info_modified = 1;
  1764.  
  1765.     if (pl_listnum >= 0)
  1766.     {
  1767.         xv_set(ip->playlists, PANEL_LIST_DELETE, pl_listnum, NULL);
  1768.         free(cd->lists[pl_listnum].name);
  1769.         if (cd->lists[pl_listnum].list != NULL)
  1770.             free(cd->lists[pl_listnum].list);
  1771.  
  1772.         for (i = pl_listnum; i < nlists; i++)
  1773.             cd->lists[i] = cd->lists[i + 1];
  1774.  
  1775.         shuf = xv_get(Workman_window1->shuffle, PANEL_VALUE);
  1776.         if (--nlists)
  1777.         {
  1778.             if (pl_listnum == nlists)
  1779.                 pl_listnum--;
  1780.             xv_set(ip->playlists, PANEL_LIST_SELECT, pl_listnum,
  1781.                 TRUE, NULL);
  1782.             switch_playlists(ip->playlists, NULL, NULL,
  1783.                 PANEL_LIST_OP_SELECT, NULL, pl_listnum);
  1784.         }
  1785.         else
  1786.         {
  1787.             pl_listnum = -1;
  1788.             free(cd->lists);
  1789.             cd->lists = NULL;
  1790.             switch_playlists(ip->playlists, NULL, NULL,
  1791.                 PANEL_LIST_OP_DESELECT, NULL, 0);
  1792.         }
  1793.         xv_set(Workman_window1->shuffle, XV_SHOW, FALSE,
  1794.             PANEL_CHOICE_STRINGS, "Normal", "Shuffle", NULL, NULL);
  1795.         for (i = 0; i < nlists; i++)
  1796.             xv_set(Workman_window1->shuffle, PANEL_CHOICE_STRING,
  1797.                 i + 2, cd->lists[i].name, NULL);
  1798.  
  1799.         if (shuf > pl_listnum + 1)
  1800.             shuf--;
  1801.         xv_set(Workman_window1->shuffle, PANEL_VALUE, shuf, XV_SHOW,
  1802.             TRUE, NULL);
  1803.         next_playmode_default(Workman_window1->shuffle, shuf, NULL);
  1804.     }
  1805. }
  1806.  
  1807. /*
  1808.  * Notify callback function for `buttonpl'.
  1809.  */
  1810. void
  1811. popup1_buttonpl_notify_callback(item, event)
  1812.     Panel_item    item;
  1813.     Event        *event;
  1814. {
  1815.     popup1_objects *ip = Workman_popup1;
  1816.     
  1817.     if (dismiss_button && item == ip->buttonpl ||
  1818.         xv_get(Workman_plpopup->plpopup, FRAME_CMD_PUSHPIN_IN) == FALSE)
  1819.     {
  1820.         xv_set(Workman_plpopup->plpopup, FRAME_CMD_PUSHPIN_IN, TRUE,
  1821.             NULL);
  1822.         xv_set(Workman_plpopup->plpopup, XV_SHOW, TRUE, NULL);
  1823.     }
  1824.     else
  1825.         xv_set(Workman_plpopup->plpopup, FRAME_CMD_PUSHPIN_IN, FALSE,
  1826.             XV_SHOW, FALSE, NULL);
  1827.     xv_set(Workman_plpopup->plpopup, XV_KEY_DATA, FRAME_CMD_PUSHPIN_IN,
  1828.         FALSE, NULL);
  1829. }
  1830.  
  1831. /*
  1832.  * Notify callback function for `button7'.
  1833.  */
  1834. void
  1835. plpopup_button7_notify_callback(item, event)
  1836.     Panel_item    item;
  1837.     Event        *event;
  1838. {
  1839.     add_playlist(item, event);
  1840. }
  1841.  
  1842. /*
  1843.  * Insert a track into the playlist.  This is the notify procedure for the
  1844.  * dynamically-built track number menu's items.
  1845.  */
  1846. void
  1847. insert_into_playlist(menu, item)
  1848.     Menu        menu;
  1849.     Menu_item    item;
  1850. {
  1851.     plpopup_objects *ip = Workman_plpopup;
  1852.     int    trackno;
  1853.  
  1854.     if (pl_listnum == -1)
  1855.         return;
  1856.  
  1857.     info_modified = 1;
  1858.  
  1859.     trackno = (int) xv_get(item, XV_KEY_DATA, 1234);
  1860.     if (pop_list == NULL)
  1861.         pop_list = (int *)malloc(sizeof (int) * 2);
  1862.     else
  1863.         pop_list = (int *)realloc(pop_list, sizeof (int) *
  1864.             (pop_listsize + 2));
  1865.     if (pop_list == NULL)
  1866.     {
  1867.         perror("malloc");
  1868.         exit(1);
  1869.     }
  1870.  
  1871.     xv_set(ip->playlist, PANEL_LIST_INSERT, pop_listsize,
  1872.         PANEL_LIST_STRING, pop_listsize,
  1873.         listentry(trackno - 1), PANEL_LIST_SELECT,
  1874.         pop_listsize, TRUE, NULL);
  1875.     xv_set(ip->delete, PANEL_INACTIVE, FALSE, NULL);
  1876.  
  1877.     pl_item = pop_listsize;
  1878.     pop_list[pop_listsize++] = trackno;
  1879.     pop_list[pop_listsize] = 0;
  1880.     cd->lists[pl_listnum].list = pop_list;
  1881. }
  1882.  
  1883. /*
  1884.  * Notify callback function for `button8'.
  1885.  */
  1886. void
  1887. cdinfo_reset(item, event)
  1888.     Panel_item    item;
  1889.     Event        *event;
  1890. {
  1891.     popup1_objects *ip = Workman_popup1;
  1892.     int    old_cdmode = cur_cdmode;
  1893.     
  1894.     kill_stats(Workman_window1);
  1895.     wipe_cdinfo();
  1896.     load();
  1897.     init_stats(Workman_window1);
  1898.     show_stats(Workman_window1);
  1899.     if (old_cdmode == 3)
  1900.     {
  1901.         cur_cdmode = 3;
  1902.         xv_set(Workman_window1->mode, PANEL_VALUE, 3, NULL);
  1903.     }
  1904.     info_modified = 0;
  1905. }
  1906.  
  1907. /*
  1908.  * Notify callback function for `playlists'.
  1909.  */
  1910. int
  1911. switch_playlists(item, string, client_data, op, event, row)
  1912.     Panel_item    item;
  1913.     char        *string;
  1914.     Xv_opaque    client_data;
  1915.     Panel_list_op    op;
  1916.     Event        *event;
  1917.     int        row;
  1918. {
  1919.     plpopup_objects *ip = Workman_plpopup;
  1920.     int    i, *thislist;
  1921.     
  1922.     switch(op) {
  1923.     case PANEL_LIST_OP_DESELECT:
  1924.         xv_set(ip->playlist, PANEL_LIST_DELETE_ROWS, 0,
  1925.             xv_get(ip->playlist, PANEL_LIST_NROWS), NULL);
  1926.         xv_set(ip->delete, PANEL_INACTIVE, TRUE, NULL);
  1927.         xv_set(ip->button5, PANEL_INACTIVE, TRUE, NULL);
  1928.         xv_set(ip->button6, PANEL_INACTIVE, TRUE, NULL);
  1929.         pop_list = NULL;
  1930.         pop_listsize = 0;
  1931.         pl_listnum = -1;
  1932.         pl_item = -1;
  1933.         break;
  1934.  
  1935.     case PANEL_LIST_OP_SELECT:
  1936.         xv_set(ip->button5, PANEL_INACTIVE, FALSE, NULL);
  1937.         xv_set(ip->button6, PANEL_INACTIVE, FALSE, NULL);
  1938.         /* If there's stuff in the list already (how?), delete it. */
  1939.         if (xv_get(ip->playlist, PANEL_LIST_NROWS) != 0)
  1940.             xv_set(ip->playlist, PANEL_LIST_DELETE_ROWS, 0,
  1941.                 xv_get(ip->playlist, PANEL_LIST_NROWS), NULL);
  1942.         thislist = cd->lists[row].list;
  1943.         if (thislist != NULL && thislist[0])
  1944.         {
  1945.             xv_set(ip->playlist, XV_SHOW, FALSE, NULL);
  1946.             for (i = 0; thislist[i]; i++)
  1947.                 xv_set(ip->playlist, PANEL_LIST_INSERT, i,
  1948.                     PANEL_LIST_STRING, i,
  1949.                     listentry(thislist[i] - 1), NULL);
  1950.             xv_set(ip->playlist, XV_SHOW, TRUE, PANEL_LIST_SELECT,
  1951.                 i - 1, TRUE, NULL);
  1952.             xv_set(ip->delete, PANEL_INACTIVE, FALSE, NULL);
  1953.             pop_list = thislist;
  1954.             pop_listsize = i;
  1955.             pl_item = 0;
  1956.         }
  1957.         else
  1958.         {
  1959.             pl_item = -1;
  1960.             pop_list = NULL;
  1961.             pop_listsize = 0;
  1962.             xv_set(ip->delete, PANEL_INACTIVE, TRUE, NULL);
  1963.         }
  1964.         pl_listnum = row;
  1965.         break;
  1966.  
  1967.     case PANEL_LIST_OP_VALIDATE:
  1968.     case PANEL_LIST_OP_DELETE:
  1969.         break;
  1970.     }
  1971.     return XV_OK;
  1972. }
  1973.  
  1974. /*
  1975.  * User-defined action for `abrepeat'.
  1976.  */
  1977. void
  1978. stop_repeating(item, value, event)
  1979.     Panel_item    item;
  1980.     int        value;
  1981.     Event        *event;
  1982. {
  1983.     goodies_objects *ip = Workman_goodies;
  1984.  
  1985.     was_repeating = 1;
  1986.     cur_lasttrack = cur_ntracks;
  1987. }
  1988.  
  1989. /*
  1990.  * Split the current track at the current position.
  1991.  */
  1992. void
  1993. split_track(item, event)
  1994.     Panel_item    item;
  1995.     Event        *event;
  1996. {
  1997.     int    listno;
  1998.  
  1999.     if (cur_frame < 1)
  2000.         return;
  2001.     
  2002.     if (! split_trackinfo(cur_frame))
  2003.         return;
  2004.  
  2005.     info_modified = 1;
  2006.  
  2007.     if (cur_track != -1 && pop_track > cur_track)
  2008.         pop_track++;
  2009.  
  2010.     fill_buttons();
  2011.     cleanout_lists();
  2012.     fill_lists();
  2013.     if (pl_listnum >= 0)
  2014.     {
  2015.         listno = pl_listnum;
  2016.         switch_playlists(Workman_plpopup->playlists, NULL, NULL,
  2017.             PANEL_LIST_OP_DESELECT, NULL, pl_listnum);
  2018.         switch_playlists(Workman_plpopup->playlists, NULL, NULL,
  2019.             PANEL_LIST_OP_SELECT, NULL, listno);
  2020.     }
  2021.  
  2022.     if (pop_track)
  2023.         xv_set(Workman_popup1->tracklist, PANEL_LIST_SELECT,
  2024.             pop_track - 1, TRUE, NULL);
  2025.  
  2026.     if (cur_track != -1)
  2027.         new_track(Workman_window1);
  2028. }
  2029.  
  2030. void
  2031. delete_track(item, event)
  2032.     Panel_item    item;
  2033.     Event        *event;
  2034. {
  2035.     int    listno;
  2036.  
  2037.     if (cur_track < 1)
  2038.         return;
  2039.     
  2040.     if (! remove_trackinfo(cur_track - 1))
  2041.         return;
  2042.     
  2043.     info_modified = 1;
  2044.  
  2045.     if (pop_track > cur_track)
  2046.         pop_track--;
  2047.     
  2048.     fill_buttons();
  2049.     cleanout_lists();
  2050.     fill_lists();
  2051.     if (pl_listnum >= 0)
  2052.     {
  2053.         listno = pl_listnum;
  2054.         switch_playlists(Workman_plpopup->playlists, NULL, NULL,
  2055.             PANEL_LIST_OP_DESELECT, NULL, pl_listnum);
  2056.         switch_playlists(Workman_plpopup->playlists, NULL, NULL,
  2057.             PANEL_LIST_OP_SELECT, NULL, listno);
  2058.     }
  2059.  
  2060.     if (pop_track)
  2061.     {
  2062.         if (pop_track == cur_track)
  2063.         {
  2064.             xv_set(Workman_popup1->trackname, PANEL_VALUE, "",
  2065.                 NULL);
  2066.             pop_track = 0;
  2067.         }
  2068.         xv_set(Workman_popup1->tracklist, PANEL_LIST_SELECT,
  2069.             pop_track - 1, TRUE, NULL);
  2070.     }
  2071.  
  2072.     new_track(Workman_window1);
  2073. }
  2074.  
  2075. void
  2076. index_scan(item, event)
  2077.     Panel_item    item;
  2078.     Event        *event;
  2079. {
  2080.     int    track, index;
  2081.  
  2082.     if (cur_cdmode != 4)
  2083.     {
  2084.         change_mode(NULL, 4, NULL);
  2085.         cur_cdmode = 4;
  2086.         xv_set(Workman_window1->mode, PANEL_VALUE, 4, NULL);
  2087.     }
  2088.  
  2089.     for (track = 1; track <= cd->ntracks; track++)
  2090.     {
  2091.         cur_frame = 0;
  2092.         index = 2;
  2093.         while (cur_frame = find_trkind(track, index, cur_frame))
  2094.         {
  2095.             cur_track = -1;
  2096.             split_track(item, event);
  2097.             index++;
  2098.         }
  2099.     }
  2100.  
  2101.     stop_cd();
  2102. }
  2103.  
  2104. /*
  2105.  * Called when the user quits.
  2106.  */
  2107. Notify_value
  2108. byebye(c, s)
  2109.     Notify_client    c;
  2110.     Destroy_status    s;
  2111. {
  2112.     if (s == DESTROY_CHECKING && cur_cdmode != 5)
  2113.     {
  2114.         keep_settings(Workman_window1);
  2115.         if (info_modified)
  2116.         {
  2117.             xv_set(wannasave, XV_SHOW, TRUE, NULL);
  2118.             if (confirmsave)
  2119.                 save_config(NULL, NULL);
  2120.             info_modified = 0;
  2121.         }
  2122.     }
  2123.     else if (s == DESTROY_CLEANUP)
  2124.         return (notify_next_destroy_func(c, s));
  2125.  
  2126.     return (NOTIFY_DONE);
  2127. }
  2128.  
  2129. /*
  2130.  * Quit programmatically.  This will cause byebye() to be called, and
  2131.  * the main loop to exit.
  2132.  */
  2133. void
  2134. quit()
  2135. {
  2136.     xv_destroy_safe(Workman_window1->window1);
  2137. }
  2138.  
  2139. /*
  2140.  * Notify callback function for `playnewcds'.
  2141.  */
  2142. void
  2143. goodies_playnewcds_notify_callback(item, value, event)
  2144.     Panel_item    item;
  2145.     int        value;
  2146.     Event        *event;
  2147. {
  2148.     goodies_objects *ip = Workman_goodies;
  2149.     short    i;
  2150.     
  2151.     for (i = 0; i < 1; i++) {
  2152.         if (i == 0 && (value & 01))
  2153.             cur_playnew = 1;
  2154.         
  2155.         if (i == 0 && !(value & 01))
  2156.             cur_playnew = 0;
  2157.  
  2158.         value >>= 1;
  2159.     }
  2160. }
  2161.  
  2162. /*
  2163.  * Handle SIGUSR1 (to pause the CD) and SIGUSR2 (to play the CD if paused.)
  2164.  */
  2165. Notify_value
  2166. sigusr1(client, sig, when)
  2167.     Notify_client        client;
  2168.     int            sig;
  2169.     Notify_signal_mode    when;
  2170. {
  2171.     if (cur_cdmode == 1)
  2172.     {
  2173.         xv_set(Workman_window1->mode, PANEL_VALUE, 3, NULL);
  2174.         pause_cd();
  2175.         show_stats(Workman_window1);
  2176.     }
  2177.  
  2178.     return (NOTIFY_DONE);
  2179. }
  2180.  
  2181. Notify_value
  2182. sigusr2(client, sig, when)
  2183.     Notify_client        client;
  2184.     int            sig;
  2185.     Notify_signal_mode    when;
  2186. {
  2187.     if (cur_cdmode == 3)
  2188.     {
  2189.         xv_set(Workman_window1->mode, PANEL_VALUE, 1, NULL);
  2190.         pause_cd();
  2191.         show_stats(Workman_window1);
  2192.     }
  2193.  
  2194.     return (NOTIFY_DONE);
  2195. }
  2196.  
  2197. /*
  2198.  * Return the value of the "Play new CDs" button.
  2199.  */
  2200. get_playnew()
  2201. {
  2202.     return (xv_get(Workman_goodies->playnewcds, PANEL_VALUE));
  2203. }
  2204.