home *** CD-ROM | disk | FTP | other *** search
/ ftp.freefriends.org / ftp.freefriends.org.tar / ftp.freefriends.org / arnold / Source / mush.rstevens.tar.gz / mush.tar / hdr_sw.c < prev    next >
C/C++ Source or Header  |  1992-10-30  |  14KB  |  467 lines

  1. /* @(#)hdr_sw.c    (c) copyright    2/17/90 (Dan Heller) */
  2.  
  3. /* This file handles all the header subwindow code.  It would be much
  4.  * better if this subwindow, which displays the headers for the current
  5.  * folder, were a textsw.  That way, this file would go away completely.
  6.  * Until then, we have to create the window (canvas), define an event
  7.  * handler for when events happen in this window, create our own scrollbar,
  8.  * figure out when the user scrolls with it, attach our own popup menu to
  9.  * the canvas, handle events for that, let's see... kitchen sink?  Oh,
  10.  * that's over there in the corner.
  11.  */
  12. #include "mush.h"
  13. #ifdef SUN_4_0 /* SunOS 4.0+ */
  14. #include <sunwindow/win_keymap.h>
  15. #endif /* SUN_4_0 */
  16.  
  17. extern Panel hdr_panel;
  18. extern void hdr_io(), fkey_interposer();
  19.  
  20. static Notify_value scroll_hdr();
  21. static void msg_menu_func(), do_menu(), msg_menu_notify();
  22. Menu msg_menu;
  23.  
  24. void
  25. make_hdr_sw(parent)
  26. Frame parent;
  27. {
  28.     Textsw tmpsw;
  29.  
  30.     if (!(hdr_sw = window_create(parent, CANVAS,
  31.     WIN_HEIGHT,        10 + screen*l_height(),
  32.     WIN_WIDTH,        WIN_EXTEND_TO_EDGE,
  33.     WIN_BELOW,        hdr_panel,
  34.     WIN_EVENT_PROC,        hdr_io,
  35.     CANVAS_AUTO_CLEAR,    TRUE,
  36.     CANVAS_RETAINED,    TRUE,
  37.     WIN_CONSUME_KBD_EVENTS,
  38.         WIN_ASCII_EVENTS, WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS, NULL,
  39.     WIN_IGNORE_KBD_EVENTS,
  40.         WIN_UP_ASCII_EVENTS, NULL,
  41.     WIN_CONSUME_PICK_EVENTS,
  42.         LOC_WINENTER, WIN_MOUSE_BUTTONS, LOC_MOVE, NULL,
  43.     WIN_VERTICAL_SCROLLBAR, scrollbar_create(0),
  44.     NULL)))
  45.     perror("hdr_sw"), cleanup(0);
  46.     hdr_win = canvas_pixwin(hdr_sw);
  47.     (void) notify_interpose_event_func(hdr_sw, fkey_interposer, NOTIFY_SAFE);
  48.     (void) notify_interpose_event_func(hdr_sw, scroll_hdr, NOTIFY_SAFE);
  49.     scrollbar_set((Scrollbar)window_get(hdr_sw, WIN_VERTICAL_SCROLLBAR),
  50.     SCROLL_NORMALIZE,    FALSE,
  51.     SCROLL_ADVANCED_MODE,    TRUE,
  52.     SCROLL_LINE_HEIGHT,    l_height(),
  53.     SCROLL_VIEW_LENGTH,    screen,
  54.     NULL);
  55. #ifdef SUN_4_0 /* SunOS 4.0+ */
  56.     /* This is a particularly ugly hack.  If Sun only documented the correct
  57.      * way to set up the key mapping for a window the way that textsw's do
  58.      * then we wouldn't have to do anything this awful.  Maybe in 4.2.....
  59.      *
  60.      * The object here is to get the same translation table for our header
  61.      * canvas as for a textsw (more or less anyway).  This way the arrow
  62.      * keys and such work right.
  63.      */
  64.     tmpsw = window_create(parent, TEXTSW, NULL);
  65. #ifdef SUN_4_1
  66.     keymap_from_fd[(int)window_get(hdr_sw, WIN_FD)].keymap =
  67.     keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].keymap;
  68.     keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].keymap = (Keymap *) 0;
  69. #else /* !SUN_4_1 */
  70.     keymap_from_fd[(int)window_get(hdr_sw, WIN_FD)].kf_keymap =
  71.     keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].kf_keymap;
  72.     keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].kf_keymap = (Keymap *) 0;
  73. #endif /* SUN_4_1 */
  74.     (void) window_destroy(tmpsw);
  75. #endif /* SUN_4_0 */
  76. }
  77.  
  78. static Notify_value
  79. scroll_hdr(canvas, event, arg, type)
  80. Canvas    canvas;
  81. Event    *event;
  82. Notify_arg    arg;
  83. Notify_event_type    type;
  84. {
  85.     int amount, count, i;
  86.     int show_deleted = !!do_set(set_options, "show_deleted");
  87.     char *argv[3], msgnum[8];
  88.     Scrollbar sb;
  89.     argv[0] = "headers";
  90.     argv[1] = msgnum;
  91.     argv[2] = NULL;
  92.  
  93.     switch (decode_scroll((Notify_client) canvas, event, screen, &amount)) {
  94.     case MUSH_SCROLL_PASS_EVENT:
  95.         switch(ID) {
  96.         case SCROLL_ENTER:
  97.         case SCROLL_EXIT:
  98.             return NOTIFY_IGNORED;
  99.         case SCROLL_REQUEST:
  100.             sb = (Scrollbar)arg;
  101.             switch( (Scroll_motion)
  102.              scrollbar_get(sb, SCROLL_REQUEST_MOTION)) {
  103.             case SCROLL_LINE_FORWARD:
  104.                 amount = 1;
  105.                 break;
  106.             case SCROLL_LINE_BACKWARD:
  107.                 amount = -1;
  108.                 break;
  109.             case SCROLL_ABSOLUTE:
  110.                 i = (int)scrollbar_get(sb, SCROLL_VIEW_START);
  111.                 if (!show_deleted) {
  112.                 count = i;
  113.                 for (i = 0; i < msg_cnt-1; i++)
  114.                         if (!ison(msg[i].m_flags, DELETE) &&
  115.                         count-- == 0)
  116.                     break;
  117.                 }
  118.                 (void) sprintf(msgnum, "%d", i+1);
  119.                 argv[1] = msgnum;
  120.                 (void) do_hdrs(2, argv, NULL);
  121.                 return(NOTIFY_DONE);
  122.             default:
  123.                 amount =
  124.                 (int)scrollbar_get(sb, SCROLL_VIEW_START) -
  125.                 (int)scrollbar_get(sb, SCROLL_LAST_VIEW_START);
  126.                 break;
  127.             }
  128.             break;
  129.         default:
  130.             return notify_next_event_func(canvas, event, arg, type);
  131.         }
  132.         break;
  133.     case MUSH_SCROLL_IGNORE:
  134.         return NOTIFY_IGNORED;
  135.     case MUSH_SCROLL_TO:
  136.         if (amount == 1) {
  137.         argv[1] = "1";
  138.         (void) do_hdrs(2, argv, NULL);
  139.         return NOTIFY_DONE;
  140.         } else {
  141.         (void) sprintf(msgnum, "%d", msg_cnt - screen + 1);
  142.         argv[1] = msgnum;
  143.         (void) do_hdrs(2, argv, NULL);
  144.         return NOTIFY_DONE;
  145.         }
  146.     }
  147.     if (amount == screen)
  148.     argv[1] = "+";
  149.     else if (amount == -screen)
  150.     argv[1] = "-";
  151.     else if (amount >= 0) {
  152.     if (amount < screen)
  153.         (void) sprintf(msgnum, "%d", min(n_array[amount]+1, msg_cnt-1));
  154.     else {
  155.         /* so much for layering */
  156.         for (i = n_array[0]+1; i < msg_cnt-1 && amount > 0; i++)
  157.         if (show_deleted || !ison(msg[i].m_flags, DELETE))
  158.             amount--;
  159.         (void) sprintf(msgnum, "%d", i);
  160.     }
  161.     } else {
  162.     /* so much for layering */
  163.     for (i = n_array[0]; i > 0 && amount < 0; i--)
  164.         if (show_deleted || !ison(msg[i-1].m_flags, DELETE))
  165.         amount++;
  166.     (void) sprintf(msgnum, "%d", i + 1);
  167.     }
  168.     (void) do_hdrs(2, argv, NULL);
  169.     return NOTIFY_DONE;
  170. }
  171.  
  172. /*
  173.  * Routines to handle io on the hdr_sw (canvas).
  174.  */
  175.  
  176. /* if MENU button goes down on a hdr, drawbox around hdr and popup menu */
  177. #define draw(x1,y1,x2,y2) (void) pw_vector(hdr_win, x1,y1,x2,y2,PIX_XOR,1)
  178. #define box(x1,y1,x2,y2)  \
  179.     draw(x1,y1, x1,y2), draw(x1,y2, x2,y2), \
  180.     draw(x2,y2, x2,y1), draw(x2,y1, x1,y1)
  181.  
  182. #define READ_MSG    (char *)'r'
  183. #define DEL_MSG        (char *)'d'
  184. #define UNDEL_MSG    (char *)'u'
  185. #define REPL_MSG    (char *)'R'
  186. #define SAVE_MSG    (char *)'s'
  187. #define PRNT_MSG    (char *)'p'
  188. #define PRE_MSG        (char *)'P'
  189. #define MARK_MSG    (char *)'m'
  190. #define HELP_MSG    (char *)'H'
  191.  
  192. #define MARK_TOGGLE    (char *)'T'
  193. #define MARK_A        (char *)'A'
  194. #define MARK_B        (char *)'B'
  195. #define MARK_C        (char *)'C'
  196. #define MARK_D        (char *)'D'
  197. #define MARK_E        (char *)'E'
  198. #define MARK_CLEAR    (char *)'c'
  199. #define MARK_HELP    (char *)'h'
  200.  
  201. /*ARGSUSED*/
  202. void
  203. hdr_io(canvas, event, arg)
  204. Canvas canvas;
  205. Event *event;
  206. caddr_t arg;
  207. {
  208.     static int    which_cursor;
  209.     int     line;
  210.  
  211.     if (ID == WIN_REPAINT) {
  212.     if (is_iconic != (int) window_get(tool, FRAME_CLOSED)) {
  213.         check_new_mail();
  214.  
  215.         /*  Reload time with value of timeout upon timer expiration. */
  216.         mail_timer.it_interval.tv_sec = time_out;
  217.  
  218.         mail_timer.it_value.tv_sec = time_out;
  219.         (void) notify_set_itimer_func(tool, do_check,
  220.         ITIMER_REAL, &mail_timer, (struct itimerval *) 0);
  221.         is_iconic = 0;
  222.     }
  223.     }
  224.  
  225.     /* make cursor change which button is lit */
  226.     switch (which_cursor) {
  227.     case 0 : (void) window_set(canvas, WIN_CURSOR, l_cursor, NULL);
  228.     when 1 : (void) window_set(canvas, WIN_CURSOR, m_cursor, NULL);
  229.     when 2 : (void) window_set(canvas, WIN_CURSOR, r_cursor, NULL);
  230.     }
  231.  
  232.     which_cursor = (which_cursor+1) % 3;
  233.  
  234.     /* just return -- we just wanted to make the cursor flicker */
  235.     if (ID == LOC_STILL || ID == LOC_MOVE || ID == LOC_WINENTER ||
  236.     ID == LOC_RGNENTER || ID == KBD_USE || ID == KBD_DONE)
  237.     return;
  238.  
  239.     if (event_is_button(event) && event_is_down(event)) {
  240.     line = (event_y(event) - 5) / l_height();
  241.     if (line < 0)
  242.         line = 0;
  243.     else if (line >= screen)
  244.         line = screen - 1;
  245.     if (!msg_cnt || n_array[line] > msg_cnt)
  246.         return;
  247.     if (ID == MS_RIGHT)
  248.         do_menu(hdr_sw, event, window_get(hdr_sw, WIN_FD), n_array[line]);
  249.     else if (ID == MS_MIDDLE) {
  250.         set_isread(n_array[line]);
  251.         msg_menu_func((int)DEL_MSG, n_array[line]);
  252.     } else {
  253.         int do_do_hdrs = 0;
  254.         if (current_msg != n_array[line]) {
  255.         current_msg = n_array[line];
  256.         do_do_hdrs++;
  257.         }
  258.         if (ison(msg[current_msg].m_flags, UNREAD))
  259.         do_do_hdrs++;
  260.         (void) display_msg(n_array[line], (u_long)0);
  261.         if (do_do_hdrs)
  262.         (void) do_hdrs(0, DUBL_NULL, NULL);
  263.     }
  264.     } else
  265.     window_default_event_proc(canvas, event, NULL);
  266. }
  267.  
  268. static struct menu_rec {
  269.     char *str;    /* Menu item label. */
  270.     char *data;    /* Menu item client data. */
  271. };
  272.  
  273. void
  274. get_msg_menu()
  275. {
  276.     int i;
  277.     Menu_item mi = NULL, sub_mi;
  278.  
  279.     static struct menu_rec msg_items[] = {
  280.     { "Read",            READ_MSG  },
  281.     { "Delete",          DEL_MSG   },
  282.     { "Undelete",        UNDEL_MSG },
  283.     { "Reply",           REPL_MSG  },
  284.     { "Save",            SAVE_MSG  },
  285.     { "Preserve",        PRE_MSG   },
  286.     { "Mark",         MARK_MSG  },
  287.     { "Print",           PRNT_MSG  },
  288.     { "Help",            HELP_MSG  },
  289.     };
  290.     static struct menu_rec mark_msg_items[] = {
  291.     { "Toggle Mark",    MARK_TOGGLE},
  292.     { "Priority A",     MARK_A     },
  293.     { "Priority B",     MARK_B     },
  294.     { "Priority C",     MARK_C     },
  295.     { "Priority D",     MARK_D     },
  296.     { "Priority E",     MARK_E     },
  297.     { "Clear Priority", MARK_CLEAR },
  298.     { "Help",           MARK_HELP  },
  299.     };
  300.  
  301.     msg_menu = menu_create(MENU_NOTIFY_PROC, menu_return_item, NULL);
  302.     for (i = 0; i < ArraySize(msg_items); i++) {
  303.     mi = menu_create_item(MENU_STRING,    msg_items[i].str,
  304.                   MENU_CLIENT_DATA,    msg_items[i].data,
  305.                   NULL);
  306.     if (msg_items[i].data == MARK_MSG) {
  307.         int j;
  308.         /* get the menu from <Mark> and set as this item's pullright */
  309.         Menu the_menu = menu_create(
  310.         MENU_NOTIFY_PROC, menu_return_item, NULL);
  311.         for (j = 0; j < ArraySize(mark_msg_items); j++) {
  312.         sub_mi = menu_create_item(
  313.             MENU_STRING,    mark_msg_items[j].str,
  314.             MENU_CLIENT_DATA,    mark_msg_items[j].data,
  315.             NULL);
  316.         (void) menu_set(the_menu, MENU_APPEND_ITEM, sub_mi, NULL);
  317.         }
  318.         menu_set(mi, MENU_PULLRIGHT, the_menu, NULL);
  319.     }
  320.     (void) menu_set(msg_menu, MENU_APPEND_ITEM, mi, NULL);
  321.     }
  322. }
  323.  
  324. static void
  325. do_menu(can_sw, event, fd, message)
  326. Canvas can_sw;
  327. Event *event;
  328. int fd, message;
  329. {
  330.     char *action;
  331.     char *save_place;
  332.     Menu_item cur_msg_item;
  333.     static char buf[16];
  334.  
  335.     if (!msg_cnt) {
  336.     wprint("No Messages.\n");
  337.     return;
  338.     }
  339.     if (fd) {
  340.     int line;
  341.     Rect *hdr_rect;
  342.     extern Menu hdr_save_menu;
  343.  
  344.     if (!msg_menu)
  345.         get_msg_menu();
  346.     (void) sprintf(buf, "Message #%d", message+1);
  347.     /* provide feedback about what message the menu references */
  348.     for (line = 0; line <= n_array[screen-1]; line++)
  349.         if (n_array[line] == message)
  350.         break;
  351.     hdr_rect = (Rect *)window_get(hdr_sw, WIN_RECT);
  352.     box(0, 5 + line * l_height(),
  353.         hdr_rect->r_width, 5 + (line+1) * l_height());
  354.     /* show menu */
  355.     cur_msg_item = menu_show(msg_menu, can_sw, event, NULL);
  356.     /* remove feedback */
  357.     box(0, 5 + line * l_height(),
  358.         hdr_rect->r_width, 5 + (line+1) * l_height());
  359.     /* if user selected something, figure out what was selected. */
  360.     if (!cur_msg_item)
  361.         return;
  362.     else {
  363. #ifndef NO_WALK_MENUS
  364.         Menu item = (Menu)cur_msg_item;
  365.         while (item = (Menu)menu_get(item, MENU_PARENT))
  366.         if ((Menu)item == hdr_save_menu)
  367.             break;
  368.         /* May also need to test the type of item and
  369.          * break if it is not a Menu_item -- but how??
  370.          * My sunview isn't that good ... I got the
  371.          * fragment above from Dan's XView book.
  372.          */
  373.         if ((Menu)item == hdr_save_menu) {
  374.         save_place = (char *)menu_get(cur_msg_item, MENU_CLIENT_DATA);
  375.         action = SAVE_MSG;
  376.         } else
  377. #endif /* NO_WALK_MENUS */
  378.         action = (char *) menu_get(cur_msg_item, MENU_CLIENT_DATA);
  379.     }
  380.     } else
  381.     action = (char *) event;
  382.  
  383.     set_isread(message);
  384.     switch ((int) action) {
  385.     case SAVE_MSG : {
  386.         extern Panel_item msg_num_item, save_item;
  387.         (void) panel_set(msg_num_item, PANEL_VALUE,
  388.                     sprintf(buf, "%d", message+1), NULL);
  389. #ifndef NO_WALK_MENUS
  390.         if (*save_place == '\0') /* magic to mean "use Filename:" */
  391.             do_file_dir(save_item, event);
  392.         else
  393.             xx_file_dir(save_item, save_place);
  394. #else /* NO_WALK_MENUS */
  395.         event_id(event) = MS_LEFT;
  396.         do_file_dir(save_item, 0, event);
  397. #endif /* NO_WALK_MENUS */
  398.         (void) panel_set(msg_num_item, PANEL_VALUE, NO_STRING, NULL);
  399.     }
  400.     when HELP_MSG :
  401.         help(0, "headers", tool_help);
  402.     when REPL_MSG : {
  403.         extern Panel_item reply_item;
  404.         open_compose();
  405.         if (!compose_frame)
  406.         break;    /* open failed */
  407.         /* reply_item shouldn't be here */
  408.         respond_mail(reply_item, message, NO_EVENT);
  409.     }
  410.     when READ_MSG :
  411.         if (current_msg != message) {
  412.         current_msg = message;
  413.         (void) do_hdrs(0, DUBL_NULL, NULL);
  414.         }
  415. #ifdef SUN_3_5
  416.         /* Test for a shortage of file descriptors */
  417.         if (nopenfiles(0) > 3)
  418. #endif /* SUN_3_5 */
  419.         turnon(glob_flags, NEW_FRAME);
  420.         more_prompt = compose_hdr(message);
  421.         display_msg(message, (u_long)0);
  422.  
  423.     otherwise :
  424.         msg_menu_func((int)action, message);
  425.     }
  426. }
  427.  
  428. /* msg_menu_func() is a function called to perform message menu actions
  429.  * that are either selected from the popup menu in the header window or
  430.  * from mouse actions that function as accelerators.
  431.  */
  432. static void
  433. msg_menu_func(action, message)
  434. int action;
  435. {
  436.     int argc;
  437.     register char **argv;
  438.     char buf[32];
  439.  
  440.     switch (action) {
  441.         case PRNT_MSG :
  442.         wprint("Message #%d sent to printer.\n", message+1);
  443.         (void) strcpy(buf, "lpr");
  444.     when UNDEL_MSG : case DEL_MSG :
  445.         (void) sprintf(buf, "%selete", (action == (int)DEL_MSG)?"d":"und");
  446.         when PRE_MSG :
  447.         (void) strcpy(buf, "preserve");
  448.         when MARK_MSG : case MARK_TOGGLE :
  449.         (void) sprintf(buf, "%smark",
  450.         ison(msg[message].m_flags, M_PRIORITY(0))? "un" : "");
  451.     when MARK_A : case MARK_B : case MARK_C : case MARK_D : case MARK_E :
  452.         (void) sprintf(buf, "mark -%c", action);
  453.     when MARK_CLEAR    :
  454.         (void) strcpy(buf, "mark -");
  455.     when MARK_HELP :
  456.         (void) help(0, "mark", tool_help);
  457.         return;
  458.     otherwise :
  459.         print("unknown switch: %c\n", action);
  460.         return;
  461.     }
  462.     (void) sprintf(&buf[strlen(buf)], " %d", message+1);
  463.  
  464.     if (argv = make_command(buf, (char ***) DUBL_NULL, &argc))
  465.     (void) do_command(argc, argv, msg_list);
  466. }
  467.