home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume27 / ytalk-3.0 / part01 / curses.c < prev    next >
C/C++ Source or Header  |  1993-08-20  |  7KB  |  396 lines

  1. /* curses.c -- curses interface */
  2.  
  3. /*               NOTICE
  4.  *
  5.  * Copyright (c) 1990,1992,1993 Britt Yenne.  All rights reserved.
  6.  * 
  7.  * This software is provided AS-IS.  The author gives no warranty,
  8.  * real or assumed, and takes no responsibility whatsoever for any 
  9.  * use or misuse of this software, or any damage created by its use
  10.  * or misuse.
  11.  * 
  12.  * This software may be freely copied and distributed provided that
  13.  * no part of this NOTICE is deleted or edited in any manner.
  14.  * 
  15.  */
  16.  
  17. /* Mail comments or questions to ytalk@austin.eds.com */
  18.  
  19. #include "header.h"
  20. #include <curses.h>
  21. #include <sys/signal.h>
  22. #include "curses.h"
  23.  
  24. typedef struct _ywin {
  25.     struct _ywin *next;        /* next ywin in linked list */
  26.     yuser *user;        /* user pointer */
  27.     WINDOW *win;        /* window pointer */
  28.     int height, width;        /* height and width in characters */
  29.     int row, col;        /* row and column position on screen */
  30.     char *title;        /* window title string */
  31. } ywin;
  32.  
  33. static ywin *head;        /* head of linked list */
  34.  
  35. /* ---- local functions ---- */
  36.  
  37. /* Take input from the user.
  38.  */
  39. static void
  40. curses_input(fd)
  41.   int fd;
  42. {
  43.     register int rc;
  44.     static ychar buf[MAXBUF];
  45.  
  46.     if((rc = read(fd, buf, MAXBUF)) <= 0)
  47.     {
  48.     if(rc == 0)
  49.         bail(YTE_SUCCESS);
  50.     bail(YTE_ERROR);
  51.     }
  52.     my_input(buf, rc);
  53. }
  54.  
  55. static ywin *
  56. new_ywin(user, title)
  57.   yuser *user;
  58.   char *title;
  59. {
  60.     register ywin *out;
  61.     register int len;
  62.  
  63.     len = strlen(title);
  64.     out = (ywin *)get_mem(sizeof(ywin) + len + 1);
  65.     (void)memset(out, 0, sizeof(ywin));
  66.     out->user = user;
  67.     out->title = ((char *)out) + sizeof(ywin);
  68.     strcpy(out->title, title);
  69.     return out;
  70. }
  71.  
  72. static void
  73. make_win(w, height, width, row, col)
  74.   ywin *w;
  75.   int height, width, row, col;
  76. {
  77.     if((w->win = newwin(height, width, row, col)) == NULL)
  78.     {
  79.     register ywin *w;
  80.     w = (ywin *)(me->term);
  81.     if(w->win != NULL)
  82.         show_error("make_win: newwin() failed");
  83.     bail(YTE_ERROR);
  84.     }
  85.     w->height = height;
  86.     w->width = width;
  87.     w->row = row;
  88.     w->col = col;
  89.     scrollok(w->win, FALSE);
  90.     wmove(w->win, 0, 0);
  91. }
  92.  
  93. static void
  94. draw_title(w)
  95.   ywin *w;
  96. {
  97.     register int pad, x;
  98.     register char *t;
  99.  
  100.     pad = (w->width - strlen(w->title)) / 2;
  101.     move(w->row - 1, w->col);
  102.     x = 0;
  103.     for(; x < pad - 2; x++)
  104.     addch('-');
  105.     if(pad >= 2)
  106.     {
  107.     addch('=');
  108.     addch(' ');
  109.     x += 2;
  110.     }
  111.     for(t = w->title; *t && x < w->width; x++, t++)
  112.     addch(*t);
  113.     if(pad >= 2)
  114.     {
  115.     addch(' ');
  116.     addch('=');
  117.     x += 2;
  118.     }
  119.     for(; x < w->width; x++)
  120.     addch('-');
  121. }
  122.  
  123. /* Return number of lines per window, given "wins" windows.
  124.  */
  125. static int
  126. win_size(wins)
  127.   int wins;
  128. {
  129.     return (LINES - 1) / wins;
  130. }
  131.  
  132. /* Break down and redraw all user windows.
  133.  */
  134. static void
  135. curses_redraw()
  136. {
  137.     register ywin *w;
  138.     register int row, wins, wsize;
  139.  
  140.     /* kill old windows */
  141.  
  142.     wins = 0;
  143.     for(w = head; w; w = w->next)
  144.     {
  145.     if(w->win)
  146.     {
  147.         delwin(w->win);
  148.         w->win = NULL;
  149.     }
  150.     wins++;
  151.     }
  152.     if((wsize = win_size(wins)) < 3)
  153.     {
  154.     end_term();
  155.     errno = 0;
  156.     show_error("curses_redraw: window size too small");
  157.     bail(YTE_ERROR);
  158.     }
  159.  
  160.     /* make new windows */
  161.  
  162.     clear();
  163.     refresh();
  164.     row = 0;
  165.     for(w = head; w; w = w->next)
  166.     {
  167.     if(w->next)
  168.     {
  169.         make_win(w, wsize-1, COLS, row+1, 0);
  170.         resize_win(w->user, wsize-1, COLS);
  171.     }
  172.     else
  173.     {
  174.         make_win(w, LINES-row-2, COLS, row+1, 0);
  175.         resize_win(w->user, LINES-row-2, COLS);
  176.     }
  177.     draw_title(w);
  178.     row += wsize;
  179.     refresh();
  180.     wrefresh(w->win);
  181.     }
  182. }
  183.  
  184. /* Start curses and set all options.
  185.  */
  186. static void
  187. curses_start()
  188. {
  189.     LINES = COLS = 0;    /* so resizes will work */
  190.     initscr();
  191.     raw();
  192.     crmode();
  193.     noecho();
  194.     clear();
  195. }
  196.  
  197. /* Restart curses... window size has changed.
  198.  */
  199. static void
  200. curses_restart()
  201. {
  202.     register ywin *w;
  203.  
  204.     /* kill old windows */
  205.  
  206.     for(w = head; w; w = w->next)
  207.     if(w->win)
  208.     {
  209.         delwin(w->win);
  210.         w->win = NULL;
  211.     }
  212.  
  213.     /* restart curses */
  214.  
  215.     endwin();
  216.     curses_start();
  217.     curses_redraw();
  218.     refresh();
  219.  
  220.     /* some systems require we do this again */
  221.  
  222. #ifdef SIGWINCH
  223.     signal(SIGWINCH, curses_restart);
  224. #endif
  225. }
  226.  
  227. /* ---- global functions ---- */
  228.  
  229. void
  230. init_curses()
  231. {
  232.     curses_start();
  233.     refresh();
  234.     head = NULL;
  235.     add_fd(0, curses_input);    /* set up user's input function */
  236.  
  237.     /* set up SIGWINCH signal handler */
  238.  
  239. #ifdef SIGWINCH
  240.     signal(SIGWINCH, curses_restart);
  241. #endif
  242. }
  243.  
  244. void
  245. end_curses()
  246. {
  247.     move(LINES-1, 0);
  248.     clrtoeol();
  249.     refresh();
  250.     endwin();
  251. }
  252.  
  253. /* Open a new window.
  254.  */
  255. int
  256. open_curses(user, title)
  257.   yuser *user;
  258.   char *title;
  259. {
  260.     register ywin *w;
  261.     register int wins;
  262.  
  263.     /* count the open windows.  We want to ensure at least
  264.      * three lines per window.
  265.      */
  266.     wins = 0;
  267.     for(w = head; w; w = w->next)
  268.     wins++;
  269.     if(win_size(wins+1) < 3)
  270.     return -1;
  271.     
  272.     /* add the new user */
  273.  
  274.     if(head == NULL)
  275.     w = head = new_ywin(user, title);
  276.     else
  277.     for(w = head; w; w = w->next)
  278.         if(w->next == NULL)
  279.         {
  280.         w->next = new_ywin(user, title);
  281.         w = w->next;
  282.         break;
  283.         }
  284.     user->term = w;
  285.  
  286.     /* redraw */
  287.  
  288.     curses_redraw();
  289.     return 0;
  290. }
  291.  
  292. /* Close a window.
  293.  */
  294. void
  295. close_curses(user)
  296.   yuser *user;
  297. {
  298.     register ywin *w, *p;
  299.  
  300.     /* zap the old user */
  301.  
  302.     w = (ywin *)(user->term);
  303.     if(w == head)
  304.     head = w->next;
  305.     else
  306.     {
  307.     for(p = head; p; p = p->next)
  308.         if(w == p->next)
  309.         {
  310.         p->next = w->next;
  311.         break;
  312.         }
  313.     if(p == NULL)
  314.     {
  315.         show_error("close_curses: user not found");
  316.         return;
  317.     }
  318.     }
  319.     delwin(w->win);
  320.     free(w);
  321.     curses_redraw();
  322. }
  323.  
  324. void
  325. addch_curses(user, c)
  326.   yuser *user;
  327.   register ychar c;
  328. {
  329.     register ywin *w;
  330.     register int x, y;
  331.  
  332.     w = (ywin *)(user->term);
  333.     getyx(w->win, y, x);
  334.     waddch(w->win, c);
  335.     if(x >= COLS-1)
  336.     wmove(w->win, y, x);
  337. }
  338.  
  339. void
  340. move_curses(user, y, x)
  341.   yuser *user;
  342.   register int y, x;
  343. {
  344.     register ywin *w;
  345.  
  346.     w = (ywin *)(user->term);
  347.     wmove(w->win, y, x);
  348. }
  349.  
  350. void
  351. clreol_curses(user)
  352.   register yuser *user;
  353. {
  354.     register ywin *w;
  355.  
  356.     w = (ywin *)(user->term);
  357.     wclrtoeol(w->win);
  358. }
  359.  
  360. void
  361. clreos_curses(user)
  362.   register yuser *user;
  363. {
  364.     register ywin *w;
  365.  
  366.     w = (ywin *)(user->term);
  367.     wclrtobot(w->win);
  368. }
  369.  
  370. void
  371. scroll_curses(user)
  372.   register yuser *user;
  373. {
  374.     register ywin *w;
  375.  
  376.     /* Curses has uses busted scrolling.  In order to call scroll()
  377.      * effectively, scrollok() must be TRUE.  However, if scrollok()
  378.      * is TRUE, then placing a character in the lower right corner
  379.      * will cause an auto-scroll.  *sigh*
  380.      */
  381.     w = (ywin *)(user->term);
  382.     scrollok(w->win, TRUE);
  383.     scroll(w->win);
  384.     scrollok(w->win, FALSE);
  385. }
  386.  
  387. void
  388. flush_curses(user)
  389.   register yuser *user;
  390. {
  391.     register ywin *w;
  392.  
  393.     w = (ywin *)(user->term);
  394.     wrefresh(w->win);
  395. }
  396.