home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume9 / xterm / part07 / scrollbar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-04-21  |  17.4 KB  |  693 lines

  1. /*
  2.  *    $Source: /u1/X/xterm/RCS/scrollbar.c,v $
  3.  *    $Header: scrollbar.c,v 10.100 86/12/01 14:45:27 jg Rel $
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include <sys/time.h>
  8. #include <X/Xlib.h>
  9. #include <setjmp.h>
  10. #include "scrollbar.h"
  11. #include "ptyx.h"
  12. #include "data.h"
  13. #include "error.h"
  14. #ifdef MODEMENU
  15. #include "menu.h"
  16. #endif MODEMENU
  17.  
  18. #include "button.ic"
  19. #include "dark.ic"
  20. #include "light.ic"
  21. #include "upline.ic"
  22. #include "downline.ic"
  23. #include "uppage.ic"
  24. #include "downpage.ic"
  25. #include "top.ic"
  26. #include "bottom.ic"
  27. #include "saveoff.ic"
  28. #include "saveon.ic"
  29. #ifndef lint
  30. static char sccs_id[] = "@(#)scrollbar.c\tX10/6.6B\t12/26/86";
  31. #endif    lint
  32.  
  33. static struct timeval stepspeed;
  34.  
  35. ScrollBar *
  36. CreateScrollBar(w, x, y, height, fg, bg, bordertile, val, valregion,
  37.  topval, botval, arrow)
  38.     Window w;
  39.     int x, y, height, fg, bg, val, valregion, topval, botval;
  40.     Pixmap bordertile;
  41.     Cursor arrow;
  42. {
  43.     register ScrollBar *sb;
  44.     register int i;
  45.     Pixmap btile, bgnd;
  46.     extern char *calloc();
  47.     static Window Make_tiled_window();
  48.     extern Pixmap Make_tile();
  49.  
  50.     if(!w || height < MINSCROLLBARHEIGHT ||
  51.      (sb = (ScrollBar *)calloc(1, sizeof(ScrollBar))) == NULL)
  52.         return(NULL);
  53.     btile = bordertile;
  54.     if(bg == BlackPixel && fg == WhitePixel) {
  55.         bg = WhitePixel;
  56.         fg = BlackPixel;
  57.         if(btile == WhitePixmap)
  58.             btile = BlackPixmap;
  59.     }
  60.     sb->fg = fg;
  61.     sb->bg = bg;
  62.     sb->cursor = arrow;
  63.     if((sb->bar = Make_tiled_window(light_width, light_height, light_bits,
  64.      fg, bg, &bgnd, w, x, y, (SCROLLBARWIDTH - 1), height, 1, bordertile))
  65.      == NULL)
  66.         goto failed_bar;
  67.     if((sb->button = XCreateWindow(sb->bar, -1, -1, (SCROLLBARWIDTH - 1),
  68.      BUTTONHEIGHT - 1, 1, btile, bgnd)) == NULL)
  69.         goto failed_button;
  70.     if((sb->save = XCreateWindow(sb->bar, -1, BUTTONHEIGHT - 1,
  71.      (SCROLLBARWIDTH - 1), BUTTONHEIGHT - 1, 1, btile, bgnd)) == NULL)
  72.         goto failed_save;
  73.     if((sb->region = Make_tiled_window(dark_width, dark_height, dark_bits,
  74.      fg, bg, &bgnd, sb->bar, 0, 0, (SCROLLBARWIDTH - 1), 10, 0,
  75.      (Pixmap)NULL)) == NULL) {
  76.         XDestroyWindow(sb->save);
  77. failed_save:
  78.         XDestroyWindow(sb->button);
  79. failed_button:
  80.         XDestroyWindow(sb->bar);
  81. failed_bar:
  82.         free((char *)sb);
  83.         return(NULL);
  84.     }
  85.     sb->savebits[SAVE_OFF] = saveoff_bits;
  86.     sb->savebits[SAVE_ON] = saveon_bits;
  87.     sb->buttonbits[BUTTON_UPLINE / 2] = upline_bits;
  88.     sb->buttonbits[BUTTON_DOWNLINE / 2] = downline_bits;
  89.     sb->buttonbits[BUTTON_UPPAGE / 2] = uppage_bits;
  90.     sb->buttonbits[BUTTON_DOWNPAGE / 2] = downpage_bits;
  91.     sb->buttonbits[BUTTON_TOP / 2] = top_bits;
  92.     sb->buttonbits[BUTTON_BOTTOM / 2] = bottom_bits;
  93.     sb->buttonbits[BUTTON_NORMAL / 2] = button_bits;
  94.     XDefineCursor(sb->bar, sb->cursor);
  95.     XSelectInput(sb->bar, ButtonPressed | ButtonReleased | ExposeWindow |
  96.      EnterWindow | LeaveWindow | UnmapWindow);
  97.     XSelectInput(sb->button, EnterWindow | LeaveWindow);
  98.     XMapWindow(sb->button);    /* will really map when bar is mapped */
  99.     XMapWindow(sb->save);    /* will really map when bar is mapped */
  100.     sb->buttonstate = sb->buttonset = BUTTON_NORMAL;
  101.     sb->savestate = sb->saveset = SAVE_ON;
  102.     sb->set.value = val;
  103.     sb->set.regionheight = valregion;
  104.     sb->set.topvalue = topval;
  105.     sb->set.bottomvalue = botval;
  106.     sb->set.height = height - BARSTART;
  107.     return(sb);
  108. }
  109.  
  110. ShowScrollBar(sb)
  111.     register ScrollBar *sb;
  112. {
  113.     if(sb->visible)
  114.         return;
  115.     sb->visible = 1;
  116.     if(sb->regionvisible) {
  117.         XUnmapWindow(sb->region);
  118.         sb->regionvisible = 0;
  119.     }
  120.     XMapWindow(sb->bar);
  121.     DrawScrollRegion(sb);
  122.     sb->action = SHOW;
  123. }
  124.  
  125. HideScrollBar(sb)
  126.     register ScrollBar *sb;
  127. {
  128.     if(!sb->visible)
  129.         return;
  130.     sb->visible = 0;
  131.     XUnmapWindow(sb->bar);
  132. }
  133.  
  134. DrawScrollRegion(sb)
  135.     register ScrollBar *sb;
  136. {
  137.     register int region, temp;
  138.  
  139.     if(sb->set.regionheight <= 0)
  140.         sb->set.regionheight = 0;
  141.     if((region = sb->set.topvalue - sb->set.bottomvalue) >= 0) {
  142.         if(sb->set.value > sb->set.topvalue)
  143.             sb->set.value = sb->set.topvalue;
  144.         else if(sb->set.value < sb->set.bottomvalue)
  145.             sb->set.value = sb->set.bottomvalue;
  146.     } else {
  147.         region = -region;
  148.         if(sb->set.value < sb->set.topvalue)
  149.             sb->set.value = sb->set.topvalue;
  150.         else if(sb->set.value > sb->set.bottomvalue)
  151.             sb->set.value = sb->set.bottomvalue;
  152.     }
  153.     if(sb->set.value == sb->set.topvalue) {
  154.         sb->set.pixelheight = (region == 0) ? sb->set.height :
  155.          (sb->set.height - 1) * sb->set.regionheight /
  156.          (sb->set.regionheight + region);
  157.         sb->set.y = BARSTART;
  158.     } else if(sb->set.value == sb->set.bottomvalue) {
  159.         sb->set.pixelheight = (sb->set.height - 1) *
  160.          sb->set.regionheight / (sb->set.regionheight + region);
  161.         sb->set.y = BARSTART + sb->set.height - sb->set.pixelheight;
  162.     } else {
  163.         if(sb->set.topvalue >= sb->set.bottomvalue) {
  164.             temp = sb->set.topvalue - 1;
  165.             region = temp - (sb->set.bottomvalue + 1);
  166.             sb->set.y = temp - sb->set.value;
  167.         } else {
  168.             temp = sb->set.topvalue + 1;
  169.             region = (sb->set.bottomvalue - 1) - temp;
  170.             sb->set.y = sb->set.value - temp;
  171.         }
  172.         sb->set.y = (BARSTART + 1) + sb->set.y * (sb->set.height - 2) /
  173.          (temp = sb->set.regionheight + region);
  174.         sb->set.pixelheight = (sb->set.height - 2) *
  175.          sb->set.regionheight / temp;
  176.     }
  177.     if(sb->set.pixelheight <= 0)
  178.         sb->set.pixelheight = 1;
  179.     if(sb->set.regionheight == 0) {
  180.         sb->state = sb->set;
  181.         if(sb->regionvisible) {
  182.             XUnmapWindow(sb->region);
  183.             sb->regionvisible = 0;
  184.         }
  185.         return;
  186.     }
  187.     if(!sb->visible || sb->regionvisible
  188.      && sb->state.y == sb->set.y
  189.      && sb->state.pixelheight == sb->set.pixelheight) {
  190.         sb->state = sb->set;
  191.         return;
  192.     }
  193.     sb->state = sb->set;
  194.     XConfigureWindow(sb->region, 0, sb->state.y, (SCROLLBARWIDTH - 1),
  195.      sb->state.pixelheight);
  196.     if(!sb->regionvisible) {
  197.         XMapWindow(sb->region);
  198.         sb->regionvisible = 1;
  199.     }
  200. }
  201.  
  202. DrawButton(sb)
  203.     register ScrollBar *sb;
  204. {
  205.     register int fg, bg;
  206.  
  207.     if(sb->visible && sb->buttonstate != sb->buttonset) {
  208.         if((sb->buttonstate = sb->buttonset) & HILITED) {
  209.             fg = sb->bg;
  210.             bg = sb->fg;
  211.         } else {
  212.             fg = sb->fg;
  213.             bg = sb->bg;
  214.         }
  215.         XBitmapBitsPut(sb->button, 0, 0, SCROLLBARWIDTH - 1,
  216.          BUTTONHEIGHT - 1, sb->buttonbits[sb->buttonstate / 2],
  217.          fg, bg, (Bitmap)0, GXcopy, AllPlanes);
  218.     }
  219. }
  220.  
  221. DrawSave(sb)
  222.     register ScrollBar *sb;
  223. {
  224.     if(sb->visible && sb->savestate != sb->saveset)
  225.         XBitmapBitsPut(sb->save, 0, 0, SCROLLBARWIDTH - 1,
  226.          BUTTONHEIGHT - 1, sb->savebits[sb->savestate = sb->saveset],
  227.          sb->fg, sb->bg, (Bitmap)0, GXcopy, AllPlanes);
  228. }
  229.  
  230. ResizeScrollBar(sb, x, y, height, region)
  231.     register ScrollBar *sb;
  232.     int x, y, height, region;
  233. {
  234.     register int act;
  235.  
  236.     act = sb->action;
  237.     sb->action = NONE;
  238.     switch(act) {
  239.      case SHOW:
  240.         return;
  241.      case HIDE:
  242.         HideScrollBar(sb);
  243.         return;
  244.     }
  245.     if(!sb->visible)
  246.         return;
  247.     if(sb->regionvisible) {
  248.         XUnmapWindow(sb->region);
  249.         sb->regionvisible = 0;
  250.     }
  251.     XConfigureWindow(sb->bar, x, y, (SCROLLBARWIDTH - 1), height);
  252.     sb->set.height = height - BARSTART;
  253.     sb->set.regionheight = region;
  254.     DrawScrollRegion(sb);
  255. }
  256.  
  257. PositionRegion(sb, y)
  258.     register ScrollBar *sb;
  259.     register int y;
  260. {
  261.     if(y <= BARSTART)
  262.         sb->set.value = sb->set.topvalue;
  263.     else if(y >= BARSTART + sb->set.height *
  264.      (sb->set.bottomvalue - sb->set.topvalue) /
  265.      (sb->set.bottomvalue + sb->set.regionheight - sb->set.topvalue))
  266.         sb->set.value = sb->set.bottomvalue;
  267.     else
  268.         sb->set.value = sb->set.topvalue + (y - BARSTART) *
  269.          (sb->set.bottomvalue + sb->set.regionheight - sb->set.topvalue)
  270.          / sb->set.height;
  271.     DrawScrollRegion(sb);
  272.     return(sb->state.value);
  273. }
  274.  
  275. ButtonRegion(sb)
  276.     register ScrollBar *sb;
  277. {
  278.     register int reverse, pagesize;
  279.  
  280.     if(!(sb->buttonset & HILITED))
  281.         return(sb->set.value);
  282.     reverse = (sb->set.bottomvalue > sb->set.topvalue);
  283.     pagesize = sb->set.regionheight - 1;
  284.     switch(sb->buttonset) {
  285.      case BUTTON_UPLINEHI:
  286.         if(reverse)
  287.             sb->set.value--;
  288.         else
  289.             sb->set.value++;
  290.         break;
  291.      case BUTTON_DOWNLINEHI:
  292.         if(reverse)
  293.             sb->set.value++;
  294.         else
  295.             sb->set.value--;
  296.         break;
  297.      case BUTTON_UPPAGEHI:
  298.         if(reverse)
  299.             sb->set.value -= pagesize;
  300.         else
  301.             sb->set.value += pagesize;
  302.         break;
  303.      case BUTTON_DOWNPAGEHI:
  304.         if(reverse)
  305.             sb->set.value += pagesize;
  306.         else
  307.             sb->set.value -= pagesize;
  308.         break;
  309.      case BUTTON_TOPHI:
  310.         sb->set.value = sb->set.topvalue;
  311.         break;
  312.      case BUTTON_BOTTOMHI:
  313.         sb->set.value = sb->set.bottomvalue;
  314.     }
  315.     DrawScrollRegion(sb);
  316.     return(sb->set.value);
  317. }
  318.  
  319. DownButtonDown(term, reply, pty)
  320.     Terminal *term;
  321.     register XKeyOrButtonEvent *reply;
  322.     int pty;            /* file descriptor of pty */
  323. {
  324.     register Screen *screen = &term->screen;
  325.     register ScrollBar *sb = screen->sb;
  326.     register Window window = reply->subwindow;
  327.  
  328.     if(!window || window == sb->region) {
  329.         WindowScroll(screen, PositionRegion(sb, reply->y));
  330.         return;
  331.     }
  332.     if(window == sb->save) {
  333.         SetSaveState(sb, !GetSaveState(sb));
  334.         return;
  335.     }
  336.     if(window != sb->button || !XGrabMouse(sb->button, sb->cursor,
  337.      ButtonReleased | EnterWindow | LeaveWindow)) {
  338.         Bell();
  339.         return;
  340.     }
  341.     if(reply->detail & ControlMask)
  342.         sb->buttonset = BUTTON_BOTTOMHI;
  343.     else if(reply->detail & ShiftMask)
  344.         sb->buttonset = BUTTON_DOWNPAGEHI;
  345.     else {
  346.         sb->buttonset = BUTTON_DOWNLINEHI;
  347.         stepspeed.tv_usec = PAUSETIME;
  348.         screen->timeout = &stepspeed;
  349.         WindowScroll(screen, ButtonRegion(screen->sb));
  350.     }
  351.     DrawButton(sb);
  352. }
  353.  
  354. UpButtonDown(term, reply, pty)
  355.     Terminal *term;
  356.     register XKeyOrButtonEvent *reply;
  357.     int pty;            /* file descriptor of pty */
  358. {
  359.     register Screen *screen = &term->screen;
  360.     register ScrollBar *sb = screen->sb;
  361.     register Window window = reply->subwindow;
  362.  
  363.     if(!window || window == sb->region) {
  364.         WindowScroll(screen, PositionRegion(sb, reply->y));
  365.         return;
  366.     }
  367.     if(window == sb->save) {
  368.         SetSaveState(sb, !GetSaveState(sb));
  369.         return;
  370.     }
  371.     if(window != sb->button || !XGrabMouse(sb->button, sb->cursor,
  372.      ButtonReleased | EnterWindow | LeaveWindow)) {
  373.         Bell();
  374.         return;
  375.     }
  376.     if(reply->detail & ControlMask)
  377.         sb->buttonset = BUTTON_TOPHI;
  378.     else if(reply->detail & ShiftMask)
  379.         sb->buttonset = BUTTON_UPPAGEHI;
  380.     else {
  381.         sb->buttonset = BUTTON_UPLINEHI;
  382.         stepspeed.tv_usec = PAUSETIME;
  383.         screen->timeout = &stepspeed;
  384.         WindowScroll(screen, ButtonRegion(screen->sb));
  385.     }
  386.     DrawButton(sb);
  387. }
  388.  
  389. ButtonUp(term, reply, pty)
  390.     Terminal *term;
  391.     XKeyOrButtonEvent *reply;
  392.     int pty;            /* file descriptor of pty */
  393. {
  394.     register Screen *screen = &term->screen;
  395.     register ScrollBar *sb = screen->sb;
  396.     register int state;
  397.  
  398.     if((state = GetButtonState(sb)) == BUTTON_NORMAL)
  399.         return;
  400.     /* don't scroll further on line mode */
  401.     if(state > BUTTON_DOWNLINEHI)
  402.         WindowScroll(screen, ButtonRegion(sb));
  403.     sb->buttonset = BUTTON_NORMAL;
  404.     DrawButton(sb);
  405.     screen->timeout = NULL;
  406.     XUngrabMouse();
  407. }
  408.  
  409. WindowScroll(screen, top)
  410.     register Screen *screen;
  411.     int top;
  412. {
  413.     register int i, lines;
  414.     register int scrolltop, scrollheight, refreshtop;
  415.  
  416.     if((i = screen->topline - top) == 0)
  417.         return;
  418.     if(screen->cursor_state)
  419.         HideCursor();
  420.     lines = i > 0 ? i : -i;
  421.     if(lines > screen->max_row + 1)
  422.         lines = screen->max_row + 1;
  423.     scrollheight = screen->max_row - lines + 1;
  424.     if(i > 0)
  425.         refreshtop = scrolltop = 0;
  426.     else {
  427.         scrolltop = lines;
  428.         refreshtop = scrollheight;
  429.     }
  430.     if(scrollheight > 0) {
  431.         if (screen->multiscroll && scrollheight == 1 &&
  432.          screen->topline == 0 && screen->top_marg == 0 &&
  433.          screen->bot_marg == screen->max_row) {
  434.             if (screen->incopy < 0 && screen->scrolls == 0)
  435.                 CopyWait (screen);
  436.             screen->scrolls++;
  437.         } else {
  438.             if (screen->incopy)
  439.                 CopyWait (screen);
  440.             screen->incopy = -1;
  441.         }
  442.         XMoveArea(VWindow(screen), screen->border, scrolltop *
  443.          FontHeight(screen) + screen->border + Titlebar(screen),
  444.          screen->border, (scrolltop + i) * FontHeight(screen) +
  445.          screen->border + Titlebar(screen), Width(screen),
  446.          scrollheight * FontHeight(screen));
  447.     }
  448.     screen->topline = top;
  449.     XTileSet(VWindow(screen), screen->border, refreshtop * FontHeight(screen) +
  450.      screen->border + Titlebar(screen), Width(screen), lines *
  451.      FontHeight(screen), screen->bgndtile);
  452.     ScrnRefresh(screen, refreshtop, 0, lines, screen->max_col + 1);
  453. }
  454.  
  455. ScrollBarOn(screen, show, init)
  456.     register Screen *screen;
  457.     int show, init;
  458. {
  459.     register int border = 2 * screen->border;
  460.     register int i;
  461.     char *realloc(), *calloc();
  462.  
  463.     if(screen->scrollbar)
  464.         return;
  465.     if(!screen->sb) {
  466.         if((screen->sb = CreateScrollBar(VWindow(screen),
  467.          Width(screen) + border, Titlebar(screen) - 1,
  468.          Height(screen) + border, screen->foreground,
  469.          screen->background, screen->bordertile, 0,
  470.          screen->max_row + 1, 0, 0, screen->arrow)) == NULL) {
  471.             Bell();
  472.             return;
  473.         }
  474.         if((screen->allbuf = (ScrnBuf) realloc(screen->buf,
  475.          2*(screen->max_row + 2 + screen->savelines) * sizeof(char *)))
  476.          == NULL)
  477.             Error (ERROR_SBRALLOC);
  478.         screen->buf = &screen->allbuf[2 * screen->savelines];
  479.         bcopy ((char *)screen->allbuf, (char *)screen->buf,
  480.          2 * (screen->max_row + 2) * sizeof (char *));
  481.         for(i = 2 * screen->savelines - 1 ; i >= 0 ; i--)
  482.             if((screen->allbuf[i] =
  483.              calloc(screen->max_col + 1, sizeof(char))) == NULL)
  484.                 Error (ERROR_SBRALLOC2);
  485.         screen->sb->saveset = !screen->alternate;
  486.     } else {
  487.         XConfigureWindow(screen->sb->bar, FullWidth(screen),
  488.          Titlebar(screen) - 1, (SCROLLBARWIDTH - 1),
  489.          i = FullHeight(screen) - Titlebar(screen));
  490.         screen->sb->set.height = i - BARSTART;
  491.         screen->sb->set.regionheight = screen->max_row + 1;
  492.     }
  493.     if(show) {
  494.         screen->scrollbar = SCROLLBARWIDTH;
  495.         ShowScrollBar(screen->sb);
  496.         if(!init) {
  497.             XSetResizeHint(VWindow(screen), border + SCROLLBARWIDTH,
  498.              border + Titlebar(screen) + screen->statusheight,
  499.              FontWidth(screen), FontHeight(screen));
  500.             XChangeWindow(VWindow(screen), (screen->max_col + 1) *
  501.              FontWidth(screen) + border + SCROLLBARWIDTH,
  502.              FontHeight(screen) * (screen->max_row + 1) +
  503.              screen->statusheight + border + Titlebar(screen));
  504.         }
  505.     }
  506. }
  507.  
  508. ScrollBarOff(screen)
  509.     register Screen *screen;
  510. {
  511.     register int border = 2 * screen->border;
  512.  
  513.     if(!screen->scrollbar)
  514.         return;
  515.     screen->sb->action = HIDE;
  516.     screen->scrollbar = 0;
  517.     XSetResizeHint(VWindow(screen), border, border + Titlebar(screen) +
  518.      screen->statusheight, FontWidth(screen), FontHeight(screen));
  519.     XChangeWindow(VWindow(screen), (screen->max_col + 1) * FontWidth(screen) +
  520.      border, FontHeight(screen) * (screen->max_row + 1) + screen->statusheight
  521.      + border + Titlebar(screen));
  522. }
  523.  
  524. ClearLinesOffTop(screen)
  525.     register Screen *screen;
  526. {
  527.     if(!screen->sb)
  528.         return;
  529.     if(screen->topline)
  530.         WindowScroll(screen, 0);
  531.     SetScrollBarTop(screen->sb, 0);
  532.     DrawScrollRegion(screen->sb);
  533. }
  534.  
  535. SetSaveState(sb, state)
  536.     register ScrollBar *sb;
  537.     int state;
  538. {
  539.     extern Terminal term;
  540.     register Screen *screen = &term.screen;
  541.  
  542.     if(screen->alternate)
  543.         return;
  544.     if(screen->scroll_amt)
  545.         FlushScroll(screen);
  546.     sb->saveset = state;
  547.     DrawSave(sb);
  548. }
  549.  
  550. SetButtonState(sb, state)
  551.     register ScrollBar *sb;
  552.     int state;
  553. {
  554.     sb->buttonset = state;
  555.     DrawButton(sb);
  556. }
  557.  
  558. static Window
  559. Make_tiled_window(bitmap_width, bitmap_height, bitmap_bits, foreground,
  560.  background, bgnd, parent, x, y, width, height, borderwidth, bordertile)
  561.     int bitmap_width, bitmap_height, foreground, background, x, y, width,
  562.      height, borderwidth;
  563.     short *bitmap_bits;
  564.     Window parent;
  565.     Pixmap *bgnd, bordertile;
  566. {
  567.     register Pixmap pix;
  568.     register Window w;
  569.     extern Pixmap Make_tile();
  570.  
  571.     if((pix = Make_tile(bitmap_width, bitmap_height, bitmap_bits,
  572.      foreground, background)) == NULL)
  573.         return(NULL);
  574.     w = XCreateWindow(parent, x, y, width, height, borderwidth, bordertile,
  575.      pix);
  576.     *bgnd = pix;
  577.     return(w);
  578. }
  579.  
  580. Pixmap
  581. Make_tile(bitmap_width, bitmap_height, bitmap_bits, foreground, background)
  582.     int bitmap_width, bitmap_height, foreground, background;
  583.     short *bitmap_bits;
  584. {
  585.     register Bitmap bm;
  586.     register Pixmap pix;
  587.  
  588.     if((bm = XStoreBitmap(bitmap_width, bitmap_height, bitmap_bits))
  589.      == NULL)
  590.         return(NULL);
  591.     pix = XMakePixmap(bm, foreground, background);
  592.     XFreeBitmap(bm);
  593.     return(pix);
  594. }
  595.  
  596. ScrollToBottom(sb)
  597. register ScrollBar *sb;
  598. {
  599.     SetScrollBarValue(sb, GetScrollBarBottom(sb));
  600.     DrawScrollRegion(sb);
  601.     WindowScroll(&term.screen, GetScrollBarValue(sb));
  602. }
  603.  
  604. #ifdef MODEMENU
  605. #define    SMENU_SCROLLKEY    0
  606. #define    SMENU_SCROLLINPUT (SMENU_SCROLLKEY+1)
  607. #define    SMENU_LINESTOP    (SMENU_SCROLLINPUT+1)
  608. #define    SMENU_LINE    (SMENU_LINESTOP+1)
  609. #define    SMENU_CLEARTOP    (SMENU_LINE+1)
  610. #define    SMENU_HIDE    (SMENU_CLEARTOP+1)
  611.  
  612. static char *stext[] = {
  613.     "Scroll to Bottom on Key",
  614.     "Scroll to Bottom on Input",
  615.     "Lines Off Top Saved",
  616.     "-",
  617.     "Clear Lines Off Top",
  618.     "Hide Scrollbar",
  619.     0,
  620. };
  621.  
  622.  
  623. static int salternate;
  624. static int slinestop;
  625. static int sscrollinput;
  626. static int sscrollkey;
  627.  
  628. Menu *ssetupmenu(menu)
  629. register Menu **menu;
  630. {
  631.     register Screen *screen = &term.screen;
  632.     register char **cp;
  633.  
  634.     if (*menu == NULL) {
  635.         if ((*menu = NewMenu("Scrollbar", re_verse)) == NULL)
  636.             return(NULL);
  637.         for(cp = stext ; *cp ; cp++)
  638.             AddMenuItem(*menu, *cp);
  639.         if(sscrollkey = screen->scrollkey)
  640.             CheckItem(*menu, SMENU_SCROLLKEY);
  641.         if(sscrollinput = screen->scrollinput)
  642.             CheckItem(*menu, SMENU_SCROLLINPUT);
  643.         if(slinestop = (screen->sb && GetSaveState(screen->sb)))
  644.             CheckItem(*menu, SMENU_LINESTOP);
  645.         if(salternate = screen->alternate)
  646.             DisableItem(*menu, SMENU_LINESTOP);
  647.         DisableItem(*menu, SMENU_LINE);
  648.         return(*menu);
  649.     }
  650.     if(sscrollkey != screen->scrollkey)
  651.         SetItemCheck(*menu, SMENU_SCROLLKEY, (sscrollkey =
  652.          screen->scrollkey));
  653.     if(sscrollinput != screen->scrollinput)
  654.         SetItemCheck(*menu, SMENU_SCROLLINPUT, (sscrollinput =
  655.          screen->scrollinput));
  656.     if(screen->sb && slinestop != GetSaveState(screen->sb))
  657.         SetItemCheck(*menu, SMENU_LINESTOP, (slinestop =
  658.          GetSaveState(screen->sb)));
  659.     if(salternate != screen->alternate)
  660.         SetItemDisable(*menu, SMENU_LINESTOP, (salternate =
  661.          screen->alternate));
  662.     return(*menu);
  663. }
  664.  
  665. sdomenufunc(item)
  666. int item;
  667. {
  668.     register Screen *screen = &term.screen;
  669.  
  670.     switch (item) {
  671.      case SMENU_SCROLLKEY:
  672.         screen->scrollkey = !screen->scrollkey;
  673.         break;
  674.  
  675.      case SMENU_SCROLLINPUT:
  676.         screen->scrollinput = !screen->scrollinput;
  677.         break;
  678.  
  679.      case SMENU_LINESTOP:
  680.         SetSaveState(screen->sb, !GetSaveState(screen->sb));
  681.         break;
  682.  
  683.      case SMENU_CLEARTOP:
  684.         ClearLinesOffTop(screen);
  685.         break;
  686.  
  687.      case SMENU_HIDE:
  688.         ScrollBarOff(screen);
  689.         break;
  690.     }
  691. }
  692. #endif MODEMENU
  693.