w3m

Unnamed repository; edit this file to name it for gitweb.
git clone https://logand.com/git/w3m.git/
Log | Files | Refs | README

menu.c (52124B)


      1 /* $Id$ */
      2 /* 
      3  * w3m menu.c
      4  */
      5 #include <stdio.h>
      6 
      7 #include "fm.h"
      8 #include "menu.h"
      9 #include "func.h"
     10 #include "myctype.h"
     11 #include "regex.h"
     12 
     13 #ifdef USE_MOUSE
     14 #ifdef USE_GPM
     15 #include <gpm.h>
     16 static int gpm_process_menu_mouse(Gpm_Event * event, void *data);
     17 extern int gpm_process_mouse(Gpm_Event *, void *);
     18 #endif				/* USE_GPM */
     19 #ifdef USE_SYSMOUSE
     20 extern int (*sysm_handler) (int x, int y, int nbs, int obs);
     21 static int sysm_process_menu_mouse(int, int, int, int);
     22 extern int sysm_process_mouse(int, int, int, int);
     23 #endif				/* USE_SYSMOUSE */
     24 #if defined(USE_GPM) || defined(USE_SYSMOUSE)
     25 #define X_MOUSE_SELECTED (char)0xff
     26 static int X_Mouse_Selection;
     27 extern int do_getch();
     28 #define getch()	do_getch()
     29 #endif				/* defined(USE_GPM) || defined(USE_SYSMOUSE) */
     30 #endif				/* USE_MOUSE */
     31 
     32 #ifdef USE_MENU
     33 
     34 static char **FRAME;
     35 static int FRAME_WIDTH;
     36 static int graph_mode = FALSE;
     37 #define G_start  {if (graph_mode) graphstart();}
     38 #define G_end    {if (graph_mode) graphend();}
     39 
     40 static int mEsc(char c);
     41 static int mEscB(char c);
     42 static int mEscD(char c);
     43 static int mNull(char c);
     44 static int mSelect(char c);
     45 static int mDown(char c);
     46 static int mUp(char c);
     47 static int mLast(char c);
     48 static int mTop(char c);
     49 static int mNext(char c);
     50 static int mPrev(char c);
     51 static int mFore(char c);
     52 static int mBack(char c);
     53 static int mLineU(char c);
     54 static int mLineD(char c);
     55 static int mOk(char c);
     56 static int mCancel(char c);
     57 static int mClose(char c);
     58 static int mSusp(char c);
     59 static int mMouse(char c);
     60 static int mSrchF(char c);
     61 static int mSrchB(char c);
     62 static int mSrchN(char c);
     63 static int mSrchP(char c);
     64 #ifdef __EMX__
     65 static int mPc(char c);
     66 #endif
     67 
     68 /* *INDENT-OFF* */
     69 static int (*MenuKeymap[128]) (char c) = {
     70 /*  C-@     C-a     C-b     C-c     C-d     C-e     C-f     C-g      */
     71 #ifdef __EMX__
     72     mPc,    mTop,   mPrev,  mClose, mNull,  mLast,  mNext,  mNull,
     73 #else
     74     mNull,  mTop,   mPrev,  mClose, mNull,  mLast,  mNext,  mNull,
     75 #endif
     76 /*  C-h     C-i     C-j     C-k     C-l     C-m     C-n     C-o      */
     77     mCancel,mNull,  mOk,    mNull,  mNull,  mOk,    mDown,  mNull,
     78 /*  C-p     C-q     C-r     C-s     C-t     C-u     C-v     C-w      */
     79     mUp,    mNull,  mSrchB, mSrchF, mNull,  mNull,  mNext,  mNull,
     80 /*  C-x     C-y     C-z     C-[     C-\     C-]     C-^     C-_      */
     81     mNull,  mNull,  mSusp,  mEsc,   mNull,  mNull,  mNull,  mNull,
     82 /*  SPC     !       "       #       $       %       &       '        */
     83     mOk,    mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
     84 /*  (       )       *       +       ,       -       .       /        */
     85     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mSrchF,
     86 /*  0       1       2       3       4       5       6       7        */
     87     mNull,  mNull,  mNull,  mNull,  mNull,  mNull , mNull,  mNull,
     88 /*  8       9       :       ;       <       =       >       ?        */
     89     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mSrchB,
     90 /*  @       A       B       C       D       E       F       G        */
     91     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
     92 /*  H       I       J       K       L       M       N       O        */
     93     mNull,  mNull,  mLineU, mLineD, mNull,  mNull,  mSrchP, mNull,
     94 /*  P       Q       R       S       T       U       V       W        */
     95     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
     96 /*  X       Y       Z       [       \       ]       ^       _        */
     97     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
     98 /*  `       a       b       c       d       e       f       g        */
     99     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    100 /*  h       i       j       k       l       m       n       o        */
    101     mCancel,mNull,  mDown,  mUp,    mOk,    mNull,  mSrchN, mNull,
    102 /*  p       q       r       s       t       u       v       w        */
    103     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    104 /*  x       y       z       {       |       }       ~       DEL      */
    105     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mCancel,
    106 };
    107 static int (*MenuEscKeymap[128]) (char c) = {
    108     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    109     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    110     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    111     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    112 
    113     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    114     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    115     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    116     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    117 
    118     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    119 /*  O     */
    120     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mEscB,
    121     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    122 /*  [                                     */
    123     mNull,  mNull,  mNull,  mEscB,  mNull,  mNull,  mNull,  mNull,
    124 
    125     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    126     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    127 /*  v             */
    128     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mPrev,  mNull,
    129     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    130 };
    131 static int (*MenuEscBKeymap[128]) (char c) = {
    132     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    133     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    134     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    135     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    136 
    137     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    138     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    139     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    140     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    141 /*  A       B       C       D       E                     */
    142     mNull,  mUp,    mDown,  mOk,    mCancel,mClose, mNull, mNull,
    143 /*  L       M                     */
    144     mNull,  mNull,  mNull,  mNull,  mClose, mMouse, mNull,  mNull,
    145     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    146     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    147 
    148     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    149     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    150     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    151     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    152 };
    153 static int (*MenuEscDKeymap[128]) (char c) = {
    154 /*  0       1       INS     3       4       PgUp,   PgDn    7     */
    155     mNull,  mNull,  mClose, mNull,  mNull,  mBack,  mFore,  mNull,
    156 /*  8       9       10      F1      F2      F3      F4      F5       */
    157     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    158 /*  16      F6      F7      F8      F9      F10     22      23       */
    159     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    160 /*  24      25      26      27      HELP    29      30      31       */
    161     mNull,  mNull,  mNull,  mNull,  mClose, mNull,  mNull,  mNull,
    162 
    163     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    164     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    165     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    166     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    167 
    168     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    169     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    170     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    171     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    172 
    173     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    174     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    175     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    176     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    177 };
    178 
    179 #ifdef __EMX__
    180 static int (*MenuPcKeymap[256])(char c)={
    181 //			  Null
    182   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    183 //							  S-Tab
    184   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    185 // A-q	  A-w	  A-E	  A-r	  A-t	  A-y	  A-u	  A-i
    186   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    187 // A-o	  A-p	  A-[	  A-]			  A-a	  A-s
    188   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    189 // A-d	  A-f	  A-g	  A-h	  A-j	  A-k	  A-l	  A-;
    190   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    191 // A-'    A-'		  A-\		  A-x	  A-c	  A-v
    192   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mPrev,
    193 // A-b	  A-n	  A-m	  A-,	  A-.	  A-/		  A-+
    194   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    195 //			  F1	  F2	  F3	  F4	  F5
    196   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    197 // F6	  F7	  F8	  F9	  F10			  Home
    198   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mTop,
    199 // Up	  PgUp	  A-/	  Left	  5	  Right	  C-*	  End
    200   mUp,	  mUp,	  mNull,  mCancel,mNull,  mOk,	  mNull,  mLast,
    201 // Down	  PgDn	  Ins	  Del	  S-F1	  S-F2	  S-F3	  S-F4
    202   mDown,  mDown,  mClose, mCancel,mNull,  mNull,  mNull,  mNull,
    203 // S-F5	  S-F6	  S-F7	  S-F8	  S-F9	  S-F10	  C-F1	  C-F2
    204   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    205 // C-F3	  C-F4	  C-F5	  C-F6	  C-F7	  C-F8	  C-F9	  C-F10
    206   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    207 // A-F1	  A-F2	  A-F3	  A-F4	  A-F5	  A-F6	  A-F7	  A-F8
    208   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    209 // A-F9	  A-F10	  PrtSc	  C-Left  C-Right C-End	  C-PgDn  C-Home
    210   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    211 // A-1	  A-2	  A-3	  A-4	  A-5	  A-6	  A-7/8	  A-9
    212   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    213 // A-0	  A -	  A-=		  C-PgUp  F11	  F12	  S-F11
    214   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    215 // S-F12  C-F11	  C-F12	  A-F11	  A-F12	  C-Up	  C-/	  C-5
    216   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    217 // S-*	  C-Down  C-Ins	  C-Del	  C-Tab	  C -	  C-+
    218   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    219   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
    220 //				  A -	  A-Tab	  A-Enter
    221   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 160
    222   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 168
    223   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 176
    224   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 184
    225   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 192
    226   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 200
    227   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 208
    228   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 216
    229   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 224
    230   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 232
    231   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 240
    232   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull	   // 248
    233 };
    234 #endif
    235 /* *INDENT-ON* */
    236 /* --- SelectMenu --- */
    237 
    238 static Menu SelectMenu;
    239 static int SelectV = 0;
    240 static void initSelectMenu(void);
    241 static void smChBuf(void);
    242 static int smDelBuf(char c);
    243 
    244 /* --- SelectMenu (END) --- */
    245 
    246 /* --- SelTabMenu --- */
    247 
    248 static Menu SelTabMenu;
    249 static int SelTabV = 0;
    250 static void initSelTabMenu(void);
    251 static void smChTab(void);
    252 static int smDelTab(char c);
    253 
    254 /* --- SelTabMenu (END) --- */
    255 
    256 /* --- MainMenu --- */
    257 
    258 static Menu MainMenu;
    259 #ifdef USE_M17N
    260 /* FIXME: gettextize here */
    261 static wc_ces MainMenuCharset = WC_CES_US_ASCII;	/* FIXME: charset of source code */
    262 static int MainMenuEncode = FALSE;
    263 #endif
    264 
    265 static MenuItem MainMenuItem[] = {
    266     /* type        label           variable value func     popup keys data  */
    267     {MENU_FUNC, N_(" Back         (b) "), NULL, 0, backBf, NULL, "b", NULL},
    268     {MENU_POPUP, N_(" Select Buffer(s) "), NULL, 0, NULL, &SelectMenu, "s",
    269      NULL},
    270     {MENU_POPUP, N_(" Select Tab   (t) "), NULL, 0, NULL, &SelTabMenu, "tT",
    271      NULL},
    272     {MENU_FUNC, N_(" View Source  (v) "), NULL, 0, vwSrc, NULL, "vV", NULL},
    273     {MENU_FUNC, N_(" Edit Source  (e) "), NULL, 0, editBf, NULL, "eE", NULL},
    274     {MENU_FUNC, N_(" Save Source  (S) "), NULL, 0, svSrc, NULL, "S", NULL},
    275     {MENU_FUNC, N_(" Reload       (r) "), NULL, 0, reload, NULL, "rR", NULL},
    276     {MENU_NOP, N_(" ---------------- "), NULL, 0, nulcmd, NULL, "", NULL},
    277     {MENU_FUNC, N_(" Go Link      (a) "), NULL, 0, followA, NULL, "a", NULL},
    278     {MENU_FUNC, N_("   on New Tab (n) "), NULL, 0, tabA, NULL, "nN", NULL},
    279     {MENU_FUNC, N_(" Save Link    (A) "), NULL, 0, svA, NULL, "A", NULL},
    280     {MENU_FUNC, N_(" View Image   (i) "), NULL, 0, followI, NULL, "i", NULL},
    281     {MENU_FUNC, N_(" Save Image   (I) "), NULL, 0, svI, NULL, "I", NULL},
    282     {MENU_FUNC, N_(" View Frame   (f) "), NULL, 0, rFrame, NULL, "fF", NULL},
    283     {MENU_NOP, N_(" ---------------- "), NULL, 0, nulcmd, NULL, "", NULL},
    284     {MENU_FUNC, N_(" Bookmark     (B) "), NULL, 0, ldBmark, NULL, "B", NULL},
    285     {MENU_FUNC, N_(" Help         (h) "), NULL, 0, ldhelp, NULL, "hH", NULL},
    286     {MENU_FUNC, N_(" Option       (o) "), NULL, 0, ldOpt, NULL, "oO", NULL},
    287     {MENU_NOP, N_(" ---------------- "), NULL, 0, nulcmd, NULL, "", NULL},
    288     {MENU_FUNC, N_(" Quit         (q) "), NULL, 0, qquitfm, NULL, "qQ", NULL},
    289     {MENU_END, "", NULL, 0, nulcmd, NULL, "", NULL},
    290 };
    291 
    292 /* --- MainMenu (END) --- */
    293 
    294 static MenuList *w3mMenuList;
    295 
    296 static Menu *CurrentMenu = NULL;
    297 
    298 #define mvaddch(y, x, c)        (move(y, x), addch(c))
    299 #define mvaddstr(y, x, str)     (move(y, x), addstr(str))
    300 #define mvaddnstr(y, x, str, n) (move(y, x), addnstr_sup(str, n))
    301 
    302 void
    303 new_menu(Menu *menu, MenuItem *item)
    304 {
    305     int i, l;
    306     char *p;
    307 
    308     menu->cursorX = 0;
    309     menu->cursorY = 0;
    310     menu->x = 0;
    311     menu->y = 0;
    312     menu->nitem = 0;
    313     menu->item = item;
    314     menu->initial = 0;
    315     menu->select = 0;
    316     menu->offset = 0;
    317     menu->active = 0;
    318 
    319     if (item == NULL)
    320 	return;
    321 
    322     for (i = 0; item[i].type != MENU_END; i++) ;
    323     menu->nitem = i;
    324     menu->height = menu->nitem;
    325     for (i = 0; i < 128; i++)
    326 	menu->keymap[i] = MenuKeymap[i];
    327     menu->width = 0;
    328     for (i = 0; i < menu->nitem; i++) {
    329 	if ((p = item[i].keys) != NULL) {
    330 	    while (*p) {
    331 		if (IS_ASCII(*p)) {
    332 		    menu->keymap[(int)*p] = mSelect;
    333 		    menu->keyselect[(int)*p] = i;
    334 		}
    335 		p++;
    336 	    }
    337 	}
    338 	l = get_strwidth(item[i].label);
    339 	if (l > menu->width)
    340 	    menu->width = l;
    341     }
    342 }
    343 
    344 void
    345 geom_menu(Menu *menu, int x, int y, int mselect)
    346 {
    347     int win_x, win_y, win_w, win_h;
    348 
    349     menu->select = mselect;
    350 
    351     if (menu->width % FRAME_WIDTH)
    352 	menu->width = (menu->width / FRAME_WIDTH + 1) * FRAME_WIDTH;
    353     win_x = menu->x - FRAME_WIDTH;
    354     win_w = menu->width + 2 * FRAME_WIDTH;
    355     if (win_x + win_w > COLS)
    356 	win_x = COLS - win_w;
    357     if (win_x < 0) {
    358 	win_x = 0;
    359 	if (win_w > COLS) {
    360 	    menu->width = COLS - 2 * FRAME_WIDTH;
    361 	    menu->width -= menu->width % FRAME_WIDTH;
    362 	    win_w = menu->width + 2 * FRAME_WIDTH;
    363 	}
    364     }
    365     menu->x = win_x + FRAME_WIDTH;
    366 
    367     win_y = menu->y - mselect - 1;
    368     win_h = menu->height + 2;
    369     if (win_y + win_h > LASTLINE)
    370 	win_y = LASTLINE - win_h;
    371     if (win_y < 0) {
    372 	win_y = 0;
    373 	if (win_y + win_h > LASTLINE) {
    374 	    win_h = LASTLINE - win_y;
    375 	    menu->height = win_h - 2;
    376 	    if (menu->height <= mselect)
    377 		menu->offset = mselect - menu->height + 1;
    378 	}
    379     }
    380     menu->y = win_y + 1;
    381 }
    382 
    383 void
    384 draw_all_menu(Menu *menu)
    385 {
    386     if (menu->parent != NULL)
    387 	draw_all_menu(menu->parent);
    388     draw_menu(menu);
    389 }
    390 
    391 void
    392 draw_menu(Menu *menu)
    393 {
    394     int x, y, w;
    395     int i, j;
    396 
    397     x = menu->x - FRAME_WIDTH;
    398     w = menu->width + 2 * FRAME_WIDTH;
    399     y = menu->y - 1;
    400 
    401     if (menu->offset == 0) {
    402 	G_start;
    403 	mvaddstr(y, x, FRAME[3]);
    404 	for (i = FRAME_WIDTH; i < w - FRAME_WIDTH; i += FRAME_WIDTH)
    405 	    mvaddstr(y, x + i, FRAME[10]);
    406 	mvaddstr(y, x + i, FRAME[6]);
    407 	G_end;
    408     }
    409     else {
    410 	G_start;
    411 	mvaddstr(y, x, FRAME[5]);
    412 	G_end;
    413 	for (i = FRAME_WIDTH; i < w - FRAME_WIDTH; i++)
    414 	    mvaddstr(y, x + i, " ");
    415 	G_start;
    416 	mvaddstr(y, x + i, FRAME[5]);
    417 	G_end;
    418 	i = (w / 2 - 1) / FRAME_WIDTH * FRAME_WIDTH;
    419 	mvaddstr(y, x + i, ":");
    420     }
    421 
    422     for (j = 0; j < menu->height; j++) {
    423 	y++;
    424 	G_start;
    425 	mvaddstr(y, x, FRAME[5]);
    426 	G_end;
    427 	draw_menu_item(menu, menu->offset + j);
    428 	G_start;
    429 	mvaddstr(y, x + w - FRAME_WIDTH, FRAME[5]);
    430 	G_end;
    431     }
    432     y++;
    433     if (menu->offset + menu->height == menu->nitem) {
    434 	G_start;
    435 	mvaddstr(y, x, FRAME[9]);
    436 	for (i = FRAME_WIDTH; i < w - FRAME_WIDTH; i += FRAME_WIDTH)
    437 	    mvaddstr(y, x + i, FRAME[10]);
    438 	mvaddstr(y, x + i, FRAME[12]);
    439 	G_end;
    440     }
    441     else {
    442 	G_start;
    443 	mvaddstr(y, x, FRAME[5]);
    444 	G_end;
    445 	for (i = FRAME_WIDTH; i < w - FRAME_WIDTH; i++)
    446 	    mvaddstr(y, x + i, " ");
    447 	G_start;
    448 	mvaddstr(y, x + i, FRAME[5]);
    449 	G_end;
    450 	i = (w / 2 - 1) / FRAME_WIDTH * FRAME_WIDTH;
    451 	mvaddstr(y, x + i, ":");
    452     }
    453 }
    454 
    455 void
    456 draw_menu_item(Menu *menu, int mselect)
    457 {
    458     mvaddnstr(menu->y + mselect - menu->offset, menu->x,
    459 	      menu->item[mselect].label, menu->width);
    460 }
    461 
    462 int
    463 select_menu(Menu *menu, int mselect)
    464 {
    465     if (mselect < 0 || mselect >= menu->nitem)
    466 	return (MENU_NOTHING);
    467     if (mselect < menu->offset)
    468 	up_menu(menu, menu->offset - mselect);
    469     else if (mselect >= menu->offset + menu->height)
    470 	down_menu(menu, mselect - menu->offset - menu->height + 1);
    471 
    472     if (menu->select >= menu->offset &&
    473 	menu->select < menu->offset + menu->height)
    474 	draw_menu_item(menu, menu->select);
    475     menu->select = mselect;
    476     standout();
    477     draw_menu_item(menu, menu->select);
    478     standend();
    479     /* 
    480      * move(menu->cursorY, menu->cursorX); */
    481     move(menu->y + mselect - menu->offset, menu->x);
    482     toggle_stand();
    483     refresh();
    484 
    485     return (menu->select);
    486 }
    487 
    488 void
    489 goto_menu(Menu *menu, int mselect, int down)
    490 {
    491     int select_in;
    492     if (mselect >= menu->nitem)
    493 	mselect = menu->nitem - 1;
    494     else if (mselect < 0)
    495 	mselect = 0;
    496     select_in = mselect;
    497     while (menu->item[mselect].type == MENU_NOP) {
    498 	if (down > 0) {
    499 	    if (++mselect >= menu->nitem) {
    500 		down_menu(menu, select_in - menu->select);
    501 		mselect = menu->select;
    502 		break;
    503 	    }
    504 	}
    505 	else if (down < 0) {
    506 	    if (--mselect < 0) {
    507 		up_menu(menu, menu->select - select_in);
    508 		mselect = menu->select;
    509 		break;
    510 	    }
    511 	}
    512 	else {
    513 	    return;
    514 	}
    515     }
    516     select_menu(menu, mselect);
    517 }
    518 
    519 void
    520 up_menu(Menu *menu, int n)
    521 {
    522     if (n < 0 || menu->offset == 0)
    523 	return;
    524     menu->offset -= n;
    525     if (menu->offset < 0)
    526 	menu->offset = 0;
    527 
    528     draw_menu(menu);
    529 }
    530 
    531 void
    532 down_menu(Menu *menu, int n)
    533 {
    534     if (n < 0 || menu->offset + menu->height == menu->nitem)
    535 	return;
    536     menu->offset += n;
    537     if (menu->offset + menu->height > menu->nitem)
    538 	menu->offset = menu->nitem - menu->height;
    539 
    540     draw_menu(menu);
    541 }
    542 
    543 int
    544 action_menu(Menu *menu)
    545 {
    546     char c;
    547     int mselect;
    548     MenuItem item;
    549 
    550     if (menu->active == 0) {
    551 	if (menu->parent != NULL)
    552 	    menu->parent->active = 0;
    553 	return (0);
    554     }
    555     draw_all_menu(menu);
    556     select_menu(menu, menu->select);
    557 
    558     while (1) {
    559 #ifdef USE_MOUSE
    560 	if (use_mouse)
    561 	    mouse_active();
    562 #endif				/* USE_MOUSE */
    563 	c = getch();
    564 #ifdef USE_MOUSE
    565 	if (use_mouse)
    566 	    mouse_inactive();
    567 #if defined(USE_GPM) || defined(USE_SYSMOUSE)
    568 	if (c == X_MOUSE_SELECTED) {
    569 	    mselect = X_Mouse_Selection;
    570 	    if (mselect != MENU_NOTHING)
    571 		break;
    572 	}
    573 #endif				/* defined(USE_GPM) || defined(USE_SYSMOUSE) */
    574 #endif				/* USE_MOUSE */
    575 	if (IS_ASCII(c)) {	/* Ascii */
    576 	    mselect = (*menu->keymap[(int)c]) (c);
    577 	    if (mselect != MENU_NOTHING)
    578 		break;
    579 	}
    580     }
    581     if (mselect >= 0 && mselect < menu->nitem) {
    582 	item = menu->item[mselect];
    583 	if (item.type & MENU_POPUP) {
    584 	    popup_menu(menu, item.popup);
    585 	    return (1);
    586 	}
    587 	if (menu->parent != NULL)
    588 	    menu->parent->active = 0;
    589 	if (item.type & MENU_VALUE)
    590 	    *item.variable = item.value;
    591 	if (item.type & MENU_FUNC) {
    592 	    CurrentKey = -1;
    593 	    CurrentKeyData = NULL;
    594 	    CurrentCmdData = item.data;
    595 	    (*item.func) ();
    596 	    CurrentCmdData = NULL;
    597 	}
    598     }
    599     else if (mselect == MENU_CLOSE) {
    600 	if (menu->parent != NULL)
    601 	    menu->parent->active = 0;
    602     }
    603     return (0);
    604 }
    605 
    606 void
    607 popup_menu(Menu *parent, Menu *menu)
    608 {
    609     int active = 1;
    610 
    611     if (menu->item == NULL || menu->nitem == 0)
    612 	return;
    613     if (menu->active)
    614 	return;
    615 
    616 #ifdef USE_MOUSE
    617 #ifdef USE_GPM
    618     gpm_handler = gpm_process_menu_mouse;
    619 #endif				/* USE_GPM */
    620 #ifdef USE_SYSMOUSE
    621     sysm_handler = sysm_process_menu_mouse;
    622 #endif				/* USE_SYSMOUSE */
    623 #endif				/* USE_MOUSE */
    624     menu->parent = parent;
    625     menu->select = menu->initial;
    626     menu->offset = 0;
    627     menu->active = 1;
    628     if (parent != NULL) {
    629 	menu->cursorX = parent->cursorX;
    630 	menu->cursorY = parent->cursorY;
    631 	guess_menu_xy(parent, menu->width, &menu->x, &menu->y);
    632     }
    633     geom_menu(menu, menu->x, menu->y, menu->select);
    634 
    635     CurrentMenu = menu;
    636     while (active) {
    637 	active = action_menu(CurrentMenu);
    638 	displayBuffer(Currentbuf, B_FORCE_REDRAW);
    639     }
    640     menu->active = 0;
    641     CurrentMenu = parent;
    642 #ifdef USE_MOUSE
    643 #ifdef USE_GPM
    644     if (CurrentMenu == NULL)
    645 	gpm_handler = gpm_process_mouse;
    646 #endif				/* USE_GPM */
    647 #ifdef USE_SYSMOUSE
    648     if (CurrentMenu == NULL)
    649 	sysm_handler = sysm_process_mouse;
    650 #endif				/* USE_SYSMOUSE */
    651 #endif				/* USE_MOUSE */
    652 }
    653 
    654 void
    655 guess_menu_xy(Menu *parent, int width, int *x, int *y)
    656 {
    657     *x = parent->x + parent->width + FRAME_WIDTH - 1;
    658     if (*x + width + FRAME_WIDTH > COLS) {
    659 	*x = COLS - width - FRAME_WIDTH;
    660 	if ((parent->x + parent->width / 2 > *x) &&
    661 	    (parent->x + parent->width / 2 > COLS / 2))
    662 	    *x = parent->x - width - FRAME_WIDTH + 1;
    663     }
    664     *y = parent->y + parent->select - parent->offset;
    665 }
    666 
    667 void
    668 new_option_menu(Menu *menu, char **label, int *variable, void (*func) ())
    669 {
    670     int i, nitem;
    671     char **p;
    672     MenuItem *item;
    673 
    674     if (label == NULL || *label == NULL)
    675 	return;
    676 
    677     for (i = 0, p = label; *p != NULL; i++, p++) ;
    678     nitem = i;
    679 
    680     item = New_N(MenuItem, nitem + 1);
    681 
    682     for (i = 0, p = label; i < nitem; i++, p++) {
    683 	if (func != NULL)
    684 	    item[i].type = MENU_VALUE | MENU_FUNC;
    685 	else
    686 	    item[i].type = MENU_VALUE;
    687 	item[i].label = *p;
    688 	item[i].variable = variable;
    689 	item[i].value = i;
    690 	item[i].func = func;
    691 	item[i].popup = NULL;
    692 	item[i].keys = "";
    693     }
    694     item[nitem].type = MENU_END;
    695 
    696     new_menu(menu, item);
    697 }
    698 
    699 static void
    700 set_menu_frame(void)
    701 {
    702     if (graph_ok()) {
    703 	graph_mode = TRUE;
    704 	FRAME_WIDTH = 1;
    705 	FRAME = graph_symbol;
    706     }
    707     else {
    708 	graph_mode = FALSE;
    709 #ifdef USE_M17N
    710 	FRAME_WIDTH = 0;
    711 	FRAME = get_symbol(DisplayCharset, &FRAME_WIDTH);
    712 	if (!WcOption.use_wide)
    713 	    FRAME_WIDTH = 1;
    714 #else
    715 	FRAME_WIDTH = 1;
    716 	FRAME = get_symbol();
    717 #endif
    718     }
    719 }
    720 
    721 /* --- MenuFunctions --- */
    722 
    723 #ifdef __EMX__
    724 static int
    725 mPc(char c)
    726 {
    727     c = getch();
    728     return (MenuPcKeymap[(int)c] (c));
    729 }
    730 #endif
    731 
    732 static int
    733 mEsc(char c)
    734 {
    735     c = getch();
    736     return (MenuEscKeymap[(int)c] (c));
    737 }
    738 
    739 static int
    740 mEscB(char c)
    741 {
    742     c = getch();
    743     if (IS_DIGIT(c))
    744 	return (mEscD(c));
    745     else
    746 	return (MenuEscBKeymap[(int)c] (c));
    747 }
    748 
    749 static int
    750 mEscD(char c)
    751 {
    752     int d;
    753 
    754     d = (int)c - (int)'0';
    755     c = getch();
    756     if (IS_DIGIT(c)) {
    757 	d = d * 10 + (int)c - (int)'0';
    758 	c = getch();
    759     }
    760     if (c == '~')
    761 	return (MenuEscDKeymap[d] (c));
    762     else
    763 	return (MENU_NOTHING);
    764 }
    765 
    766 static int
    767 mNull(char c)
    768 {
    769     return (MENU_NOTHING);
    770 }
    771 
    772 static int
    773 mSelect(char c)
    774 {
    775     if (IS_ASCII(c))
    776 	return (select_menu(CurrentMenu, CurrentMenu->keyselect[(int)c]));
    777     else
    778 	return (MENU_NOTHING);
    779 }
    780 
    781 static int
    782 mDown(char c)
    783 {
    784     if (CurrentMenu->select >= CurrentMenu->nitem - 1)
    785 	return (MENU_NOTHING);
    786     goto_menu(CurrentMenu, CurrentMenu->select + 1, 1);
    787     return (MENU_NOTHING);
    788 }
    789 
    790 static int
    791 mUp(char c)
    792 {
    793     if (CurrentMenu->select <= 0)
    794 	return (MENU_NOTHING);
    795     goto_menu(CurrentMenu, CurrentMenu->select - 1, -1);
    796     return (MENU_NOTHING);
    797 }
    798 
    799 static int
    800 mLast(char c)
    801 {
    802     goto_menu(CurrentMenu, CurrentMenu->nitem - 1, -1);
    803     return (MENU_NOTHING);
    804 }
    805 
    806 static int
    807 mTop(char c)
    808 {
    809     goto_menu(CurrentMenu, 0, 1);
    810     return (MENU_NOTHING);
    811 }
    812 
    813 static int
    814 mNext(char c)
    815 {
    816     int mselect = CurrentMenu->select + CurrentMenu->height;
    817 
    818     if (mselect >= CurrentMenu->nitem)
    819 	return mLast(c);
    820     down_menu(CurrentMenu, CurrentMenu->height);
    821     goto_menu(CurrentMenu, mselect, -1);
    822     return (MENU_NOTHING);
    823 }
    824 
    825 static int
    826 mPrev(char c)
    827 {
    828     int mselect = CurrentMenu->select - CurrentMenu->height;
    829 
    830     if (mselect < 0)
    831 	return mTop(c);
    832     up_menu(CurrentMenu, CurrentMenu->height);
    833     goto_menu(CurrentMenu, mselect, 1);
    834     return (MENU_NOTHING);
    835 }
    836 
    837 static int
    838 mFore(char c)
    839 {
    840     if (CurrentMenu->select >= CurrentMenu->nitem - 1)
    841 	return (MENU_NOTHING);
    842     goto_menu(CurrentMenu, (CurrentMenu->select + CurrentMenu->height - 1),
    843 	      (CurrentMenu->height + 1));
    844     return (MENU_NOTHING);
    845 }
    846 
    847 static int
    848 mBack(char c)
    849 {
    850     if (CurrentMenu->select <= 0)
    851 	return (MENU_NOTHING);
    852     goto_menu(CurrentMenu, (CurrentMenu->select - CurrentMenu->height + 1),
    853 	      (-1 - CurrentMenu->height));
    854     return (MENU_NOTHING);
    855 }
    856 
    857 static int
    858 mLineU(char c)
    859 {
    860     int mselect = CurrentMenu->select;
    861 
    862     if (mselect >= CurrentMenu->nitem)
    863 	return mLast(c);
    864     if (CurrentMenu->offset + CurrentMenu->height >= CurrentMenu->nitem)
    865 	mselect++;
    866     else {
    867 	down_menu(CurrentMenu, 1);
    868 	if (mselect < CurrentMenu->offset)
    869 	    mselect++;
    870     }
    871     goto_menu(CurrentMenu, mselect, 1);
    872     return (MENU_NOTHING);
    873 }
    874 
    875 static int
    876 mLineD(char c)
    877 {
    878     int mselect = CurrentMenu->select;
    879 
    880     if (mselect <= 0)
    881 	return mTop(c);
    882     if (CurrentMenu->offset <= 0)
    883 	mselect--;
    884     else {
    885 	up_menu(CurrentMenu, 1);
    886 	if (mselect >= CurrentMenu->offset + CurrentMenu->height)
    887 	    mselect--;
    888     }
    889     goto_menu(CurrentMenu, mselect, -1);
    890     return (MENU_NOTHING);
    891 }
    892 
    893 static int
    894 mOk(char c)
    895 {
    896     int mselect = CurrentMenu->select;
    897 
    898     if (CurrentMenu->item[mselect].type == MENU_NOP)
    899 	return (MENU_NOTHING);
    900     return (mselect);
    901 }
    902 
    903 static int
    904 mCancel(char c)
    905 {
    906     return (MENU_CANCEL);
    907 }
    908 
    909 static int
    910 mClose(char c)
    911 {
    912     return (MENU_CLOSE);
    913 }
    914 
    915 static int
    916 mSusp(char c)
    917 {
    918     susp();
    919     draw_all_menu(CurrentMenu);
    920     select_menu(CurrentMenu, CurrentMenu->select);
    921     return (MENU_NOTHING);
    922 }
    923 
    924 static char *SearchString = NULL;
    925 
    926 int (*menuSearchRoutine) (Menu *, char *, int);
    927 
    928 static int
    929 menuForwardSearch(Menu *menu, char *str, int from)
    930 {
    931     int i;
    932     char *p;
    933     if ((p = regexCompile(str, IgnoreCase)) != NULL) {
    934 	message(p, 0, 0);
    935 	return -1;
    936     }
    937     if (from < 0)
    938 	from = 0;
    939     for (i = from; i < menu->nitem; i++)
    940 	if (menu->item[i].type != MENU_NOP &&
    941 	    regexMatch(menu->item[i].label, -1, 1) == 1)
    942 	    return i;
    943     return -1;
    944 }
    945 
    946 static int
    947 menu_search_forward(Menu *menu, int from)
    948 {
    949     char *str;
    950     int found;
    951     str = inputStrHist("Forward: ", NULL, TextHist);
    952     if (str != NULL && *str == '\0')
    953 	str = SearchString;
    954     if (str == NULL || *str == '\0')
    955 	return -1;
    956     SearchString = str;
    957     str = conv_search_string(str, DisplayCharset);
    958     menuSearchRoutine = menuForwardSearch;
    959     found = menuForwardSearch(menu, str, from + 1);
    960     if (WrapSearch && found == -1)
    961 	found = menuForwardSearch(menu, str, 0);
    962     if (found >= 0)
    963 	return found;
    964     disp_message("Not found", TRUE);
    965     return -1;
    966 }
    967 
    968 static int
    969 mSrchF(char c)
    970 {
    971     int mselect;
    972     mselect = menu_search_forward(CurrentMenu, CurrentMenu->select);
    973     if (mselect >= 0)
    974 	goto_menu(CurrentMenu, mselect, 1);
    975     return (MENU_NOTHING);
    976 }
    977 
    978 static int
    979 menuBackwardSearch(Menu *menu, char *str, int from)
    980 {
    981     int i;
    982     char *p;
    983     if ((p = regexCompile(str, IgnoreCase)) != NULL) {
    984 	message(p, 0, 0);
    985 	return -1;
    986     }
    987     if (from >= menu->nitem)
    988 	from = menu->nitem - 1;
    989     for (i = from; i >= 0; i--)
    990 	if (menu->item[i].type != MENU_NOP &&
    991 	    regexMatch(menu->item[i].label, -1, 1) == 1)
    992 	    return i;
    993     return -1;
    994 }
    995 
    996 static int
    997 menu_search_backward(Menu *menu, int from)
    998 {
    999     char *str;
   1000     int found;
   1001     str = inputStrHist("Backward: ", NULL, TextHist);
   1002     if (str != NULL && *str == '\0')
   1003 	str = SearchString;
   1004     if (str == NULL || *str == '\0')
   1005 	return -1;
   1006     SearchString = str;
   1007     str = conv_search_string(str, DisplayCharset);
   1008     menuSearchRoutine = menuBackwardSearch;
   1009     found = menuBackwardSearch(menu, str, from - 1);
   1010     if (WrapSearch && found == -1)
   1011 	found = menuBackwardSearch(menu, str, menu->nitem);
   1012     if (found >= 0)
   1013 	return found;
   1014     disp_message("Not found", TRUE);
   1015     return -1;
   1016 }
   1017 
   1018 static int
   1019 mSrchB(char c)
   1020 {
   1021     int mselect;
   1022     mselect = menu_search_backward(CurrentMenu, CurrentMenu->select);
   1023     if (mselect >= 0)
   1024 	goto_menu(CurrentMenu, mselect, -1);
   1025     return (MENU_NOTHING);
   1026 }
   1027 
   1028 static int
   1029 menu_search_next_previous(Menu *menu, int from, int reverse)
   1030 {
   1031     int found;
   1032     static int (*routine[2]) (Menu *, char *, int) = {
   1033     menuForwardSearch, menuBackwardSearch};
   1034     char *str;
   1035 
   1036     if (menuSearchRoutine == NULL) {
   1037 	disp_message("No previous regular expression", TRUE);
   1038 	return -1;
   1039     }
   1040     str = conv_search_string(SearchString, DisplayCharset);
   1041     if (reverse != 0)
   1042 	reverse = 1;
   1043     if (menuSearchRoutine == menuBackwardSearch)
   1044 	reverse ^= 1;
   1045     from += reverse ? -1 : 1;
   1046     found = (*routine[reverse]) (menu, str, from);
   1047     if (WrapSearch && found == -1)
   1048 	found = (*routine[reverse]) (menu, str, reverse * menu->nitem);
   1049     if (found >= 0)
   1050 	return found;
   1051     disp_message("Not found", TRUE);
   1052     return -1;
   1053 }
   1054 
   1055 static int
   1056 mSrchN(char c)
   1057 {
   1058     int mselect;
   1059     mselect = menu_search_next_previous(CurrentMenu, CurrentMenu->select, 0);
   1060     if (mselect >= 0)
   1061 	goto_menu(CurrentMenu, mselect, 1);
   1062     return (MENU_NOTHING);
   1063 }
   1064 
   1065 static int
   1066 mSrchP(char c)
   1067 {
   1068     int mselect;
   1069     mselect = menu_search_next_previous(CurrentMenu, CurrentMenu->select, 1);
   1070     if (mselect >= 0)
   1071 	goto_menu(CurrentMenu, mselect, -1);
   1072     return (MENU_NOTHING);
   1073 }
   1074 
   1075 #ifdef USE_MOUSE
   1076 #define MOUSE_BTN1_DOWN 0
   1077 #define MOUSE_BTN2_DOWN 1
   1078 #define MOUSE_BTN3_DOWN 2
   1079 #define MOUSE_BTN4_DOWN_RXVT 3
   1080 #define MOUSE_BTN5_DOWN_RXVT 4
   1081 #define MOUSE_BTN4_DOWN_XTERM 64
   1082 #define MOUSE_BTN5_DOWN_XTERM 65
   1083 #define MOUSE_BTN_UP 3
   1084 #define MOUSE_BTN_RESET -1
   1085 
   1086 static int
   1087 mMouse_scroll_line(void)
   1088 {
   1089     int i = 0;
   1090     if (relative_wheel_scroll)
   1091 	i = (relative_wheel_scroll_ratio * CurrentMenu->height + 99) / 100;
   1092     else
   1093 	i = fixed_wheel_scroll_count;
   1094     return i ? i : 1;
   1095 }
   1096 
   1097 static int
   1098 process_mMouse(int btn, int x, int y)
   1099 {
   1100     Menu *menu;
   1101     int mselect, i;
   1102     static int press_btn = MOUSE_BTN_RESET, press_x, press_y;
   1103     char c = ' ';
   1104 
   1105     menu = CurrentMenu;
   1106 
   1107     if (x < 0 || x >= COLS || y < 0 || y > LASTLINE)
   1108 	return (MENU_NOTHING);
   1109 
   1110     if (btn == MOUSE_BTN_UP) {
   1111 	switch (press_btn) {
   1112 	case MOUSE_BTN1_DOWN:
   1113 	case MOUSE_BTN3_DOWN:
   1114 	    if (x < menu->x - FRAME_WIDTH ||
   1115 		x >= menu->x + menu->width + FRAME_WIDTH ||
   1116 		y < menu->y - 1 || y >= menu->y + menu->height + 1) {
   1117 		return (MENU_CANCEL);
   1118 	    }
   1119 	    else if ((x >= menu->x - FRAME_WIDTH &&
   1120 		      x < menu->x) ||
   1121 		     (x >= menu->x + menu->width &&
   1122 		      x < menu->x + menu->width + FRAME_WIDTH)) {
   1123 		return (MENU_NOTHING);
   1124 	    }
   1125 	    else if (press_y > y) {
   1126 		for (i = 0; i < press_y - y; i++)
   1127 		    mLineU(c);
   1128 		return (MENU_NOTHING);
   1129 	    }
   1130 	    else if (press_y < y) {
   1131 		for (i = 0; i < y - press_y; i++)
   1132 		    mLineD(c);
   1133 		return (MENU_NOTHING);
   1134 	    }
   1135 	    else if (y == menu->y - 1) {
   1136 		mPrev(c);
   1137 		return (MENU_NOTHING);
   1138 	    }
   1139 	    else if (y == menu->y + menu->height) {
   1140 		mNext(c);
   1141 		return (MENU_NOTHING);
   1142 	    }
   1143 	    else {
   1144 		mselect = y - menu->y + menu->offset;
   1145 		if (menu->item[mselect].type == MENU_NOP)
   1146 		    return (MENU_NOTHING);
   1147 		return (select_menu(menu, mselect));
   1148 	    }
   1149 	    break;
   1150 	case MOUSE_BTN4_DOWN_RXVT:
   1151 	    for (i = 0; i < mMouse_scroll_line(); i++)
   1152 		mLineD(c);
   1153 	    break;
   1154 	case MOUSE_BTN5_DOWN_RXVT:
   1155 	    for (i = 0; i < mMouse_scroll_line(); i++)
   1156 		mLineU(c);
   1157 	    break;
   1158 	}
   1159     }
   1160     else if (btn == MOUSE_BTN4_DOWN_XTERM) {
   1161 	for (i = 0; i < mMouse_scroll_line(); i++)
   1162 	    mLineD(c);
   1163     }
   1164     else if (btn == MOUSE_BTN5_DOWN_XTERM) {
   1165 	for (i = 0; i < mMouse_scroll_line(); i++)
   1166 	    mLineU(c);
   1167     }
   1168 
   1169     if (btn != MOUSE_BTN4_DOWN_RXVT || press_btn == MOUSE_BTN_RESET) {
   1170 	press_btn = btn;
   1171 	press_x = x;
   1172 	press_y = y;
   1173     }
   1174     else {
   1175 	press_btn = MOUSE_BTN_RESET;
   1176     }
   1177     return (MENU_NOTHING);
   1178 }
   1179 
   1180 static int
   1181 mMouse(char c)
   1182 {
   1183     int btn, x, y;
   1184 
   1185     btn = (unsigned char)getch() - 32;
   1186 #if defined(__CYGWIN__) && CYGWIN_VERSION_DLL_MAJOR < 1005
   1187     if (cygwin_mouse_btn_swapped) {
   1188 	if (btn == MOUSE_BTN2_DOWN)
   1189 	    btn = MOUSE_BTN3_DOWN;
   1190 	else if (btn == MOUSE_BTN3_DOWN)
   1191 	    btn = MOUSE_BTN2_DOWN;
   1192     }
   1193 #endif
   1194     x = (unsigned char)getch() - 33;
   1195     if (x < 0)
   1196 	x += 0x100;
   1197     y = (unsigned char)getch() - 33;
   1198     if (y < 0)
   1199 	y += 0x100;
   1200 
   1201     /* 
   1202      * if (x < 0 || x >= COLS || y < 0 || y > LASTLINE) return; */
   1203     return process_mMouse(btn, x, y);
   1204 }
   1205 
   1206 #ifdef USE_GPM
   1207 static int
   1208 gpm_process_menu_mouse(Gpm_Event * event, void *data)
   1209 {
   1210     int btn = MOUSE_BTN_RESET, x, y;
   1211     if (event->type & GPM_UP)
   1212 	btn = MOUSE_BTN_UP;
   1213     else if (event->type & GPM_DOWN) {
   1214 	switch (event->buttons) {
   1215 	case GPM_B_LEFT:
   1216 	    btn = MOUSE_BTN1_DOWN;
   1217 	    break;
   1218 	case GPM_B_MIDDLE:
   1219 	    btn = MOUSE_BTN2_DOWN;
   1220 	    break;
   1221 	case GPM_B_RIGHT:
   1222 	    btn = MOUSE_BTN3_DOWN;
   1223 	    break;
   1224 	}
   1225     }
   1226     else {
   1227 	GPM_DRAWPOINTER(event);
   1228 	return 0;
   1229     }
   1230     x = event->x;
   1231     y = event->y;
   1232     X_Mouse_Selection = process_mMouse(btn, x - 1, y - 1);
   1233     return X_MOUSE_SELECTED;
   1234 }
   1235 #endif				/* USE_GPM */
   1236 
   1237 #ifdef USE_SYSMOUSE
   1238 static int
   1239 sysm_process_menu_mouse(int x, int y, int nbs, int obs)
   1240 {
   1241     int btn;
   1242     int bits;
   1243 
   1244     if (obs & ~nbs)
   1245 	btn = MOUSE_BTN_UP;
   1246     else if (nbs & ~obs) {
   1247 	bits = nbs & ~obs;
   1248 	btn = bits & 0x1 ? MOUSE_BTN1_DOWN :
   1249 	    (bits & 0x2 ? MOUSE_BTN2_DOWN :
   1250 	     (bits & 0x4 ? MOUSE_BTN3_DOWN : 0));
   1251     }
   1252     else			/* nbs == obs */
   1253 	return 0;
   1254     X_Mouse_Selection = process_mMouse(btn, x, y);
   1255     return X_MOUSE_SELECTED;
   1256 }
   1257 #endif				/* USE_SYSMOUSE */
   1258 #else				/* not USE_MOUSE */
   1259 static int
   1260 mMouse(char c)
   1261 {
   1262     return (MENU_NOTHING);
   1263 }
   1264 #endif				/* not USE_MOUSE */
   1265 
   1266 /* --- MenuFunctions (END) --- */
   1267 
   1268 /* --- MainMenu --- */
   1269 
   1270 void
   1271 popupMenu(int x, int y, Menu *menu)
   1272 {
   1273     set_menu_frame();
   1274 
   1275     initSelectMenu();
   1276     initSelTabMenu();
   1277 
   1278     menu->cursorX = Currentbuf->cursorX + Currentbuf->rootX;
   1279     menu->cursorY = Currentbuf->cursorY + Currentbuf->rootY;
   1280     menu->x = x + FRAME_WIDTH + 1;
   1281     menu->y = y + 2;
   1282 
   1283     popup_menu(NULL, menu);
   1284 }
   1285 
   1286 void
   1287 mainMenu(int x, int y)
   1288 {
   1289     popupMenu(x, y, &MainMenu);
   1290 }
   1291 
   1292 DEFUN(mainMn, MAIN_MENU MENU, "Popup menu")
   1293 {
   1294     Menu *menu = &MainMenu;
   1295     char *data;
   1296     int n;
   1297     int x = Currentbuf->cursorX + Currentbuf->rootX,
   1298 	y = Currentbuf->cursorY + Currentbuf->rootY;
   1299 
   1300     data = searchKeyData();
   1301     if (data != NULL) {
   1302 	n = getMenuN(w3mMenuList, data);
   1303 	if (n < 0)
   1304 	    return;
   1305 	menu = w3mMenuList[n].menu;
   1306     }
   1307 #ifdef USE_MOUSE
   1308     if (mouse_action.in_action) {
   1309 	x = mouse_action.cursorX;
   1310 	y = mouse_action.cursorY;
   1311     }
   1312 #endif
   1313     popupMenu(x, y, menu);
   1314 }
   1315 
   1316 /* --- MainMenu (END) --- */
   1317 
   1318 /* --- SelectMenu --- */
   1319 
   1320 DEFUN(selMn, SELECT_MENU, "Popup buffer selection menu")
   1321 {
   1322     int x = Currentbuf->cursorX + Currentbuf->rootX,
   1323 	y = Currentbuf->cursorY + Currentbuf->rootY;
   1324 
   1325 #ifdef USE_MOUSE
   1326     if (mouse_action.in_action) {
   1327 	x = mouse_action.cursorX;
   1328 	y = mouse_action.cursorY;
   1329     }
   1330 #endif
   1331     popupMenu(x, y, &SelectMenu);
   1332 }
   1333 
   1334 static void
   1335 initSelectMenu(void)
   1336 {
   1337     int i, nitem, len = 0, l;
   1338     Buffer *buf;
   1339     Str str;
   1340     char **label;
   1341     char *p;
   1342     static char *comment = " SPC for select / D for delete buffer ";
   1343 
   1344     SelectV = -1;
   1345     for (i = 0, buf = Firstbuf; buf != NULL; i++, buf = buf->nextBuffer) {
   1346 	if (buf == Currentbuf)
   1347 	    SelectV = i;
   1348     }
   1349     nitem = i;
   1350 
   1351     label = New_N(char *, nitem + 2);
   1352     for (i = 0, buf = Firstbuf; i < nitem; i++, buf = buf->nextBuffer) {
   1353 	str = Sprintf("<%s>", buf->buffername);
   1354 	if (buf->filename != NULL) {
   1355 	    switch (buf->currentURL.scheme) {
   1356 	    case SCM_LOCAL:
   1357 		if (strcmp(buf->currentURL.file, "-")) {
   1358 		    Strcat_char(str, ' ');
   1359 		    Strcat_charp(str,
   1360 				 conv_from_system(buf->currentURL.real_file));
   1361 		}
   1362 		break;
   1363 		/* case SCM_UNKNOWN: */
   1364 	    case SCM_MISSING:
   1365 		break;
   1366 	    default:
   1367 		Strcat_char(str, ' ');
   1368 		p = parsedURL2Str(&buf->currentURL)->ptr;
   1369 		if (DecodeURL)
   1370 		    p = url_unquote_conv(p, 0);
   1371 		Strcat_charp(str, p);
   1372 		break;
   1373 	    }
   1374 	}
   1375 	label[i] = str->ptr;
   1376 	if (len < str->length)
   1377 	    len = str->length;
   1378     }
   1379     l = get_strwidth(comment);
   1380     if (len < l + 4)
   1381 	len = l + 4;
   1382     if (len > COLS - 2 * FRAME_WIDTH)
   1383 	len = COLS - 2 * FRAME_WIDTH;
   1384     len = (len > 1) ? ((len - l + 1) / 2) : 0;
   1385     str = Strnew();
   1386     for (i = 0; i < len; i++)
   1387 	Strcat_char(str, '-');
   1388     Strcat_charp(str, comment);
   1389     for (i = 0; i < len; i++)
   1390 	Strcat_char(str, '-');
   1391     label[nitem] = str->ptr;
   1392     label[nitem + 1] = NULL;
   1393 
   1394     new_option_menu(&SelectMenu, label, &SelectV, smChBuf);
   1395     SelectMenu.initial = SelectV;
   1396     SelectMenu.cursorX = Currentbuf->cursorX + Currentbuf->rootX;
   1397     SelectMenu.cursorY = Currentbuf->cursorY + Currentbuf->rootY;
   1398     SelectMenu.keymap['D'] = smDelBuf;
   1399     SelectMenu.item[nitem].type = MENU_NOP;
   1400 }
   1401 
   1402 static void
   1403 smChBuf(void)
   1404 {
   1405     int i;
   1406     Buffer *buf;
   1407 
   1408     if (SelectV < 0 || SelectV >= SelectMenu.nitem)
   1409 	return;
   1410     for (i = 0, buf = Firstbuf; i < SelectV; i++, buf = buf->nextBuffer) ;
   1411     Currentbuf = buf;
   1412     for (buf = Firstbuf; buf != NULL; buf = buf->nextBuffer) {
   1413 	if (buf == Currentbuf)
   1414 	    continue;
   1415 #ifdef USE_IMAGE
   1416 	deleteImage(buf);
   1417 #endif
   1418 	if (clear_buffer)
   1419 	    tmpClearBuffer(buf);
   1420     }
   1421 }
   1422 
   1423 static int
   1424 smDelBuf(char c)
   1425 {
   1426     int i, x, y, mselect;
   1427     Buffer *buf;
   1428 
   1429     if (CurrentMenu->select < 0 || CurrentMenu->select >= SelectMenu.nitem)
   1430 	return (MENU_NOTHING);
   1431     for (i = 0, buf = Firstbuf; i < CurrentMenu->select;
   1432 	 i++, buf = buf->nextBuffer) ;
   1433     if (Currentbuf == buf)
   1434 	Currentbuf = buf->nextBuffer;
   1435     Firstbuf = deleteBuffer(Firstbuf, buf);
   1436     if (!Currentbuf)
   1437 	Currentbuf = nthBuffer(Firstbuf, i - 1);;
   1438     if (Firstbuf == NULL) {
   1439 	Firstbuf = nullBuffer();
   1440 	Currentbuf = Firstbuf;
   1441     }
   1442 
   1443     x = CurrentMenu->x;
   1444     y = CurrentMenu->y;
   1445     mselect = CurrentMenu->select;
   1446 
   1447     initSelectMenu();
   1448 
   1449     CurrentMenu->x = x;
   1450     CurrentMenu->y = y;
   1451 
   1452     geom_menu(CurrentMenu, x, y, 0);
   1453 
   1454     CurrentMenu->select = (mselect <= CurrentMenu->nitem - 2) ? mselect
   1455 	: (CurrentMenu->nitem - 2);
   1456 
   1457     displayBuffer(Currentbuf, B_FORCE_REDRAW);
   1458     draw_all_menu(CurrentMenu);
   1459     select_menu(CurrentMenu, CurrentMenu->select);
   1460     return (MENU_NOTHING);
   1461 }
   1462 
   1463 /* --- SelectMenu (END) --- */
   1464 
   1465 /* --- SelTabMenu --- */
   1466 
   1467 DEFUN(tabMn, TAB_MENU, "Popup tab selection menu")
   1468 {
   1469     int x = Currentbuf->cursorX + Currentbuf->rootX,
   1470 	y = Currentbuf->cursorY + Currentbuf->rootY;
   1471 
   1472 #ifdef USE_MOUSE
   1473     if (mouse_action.in_action) {
   1474 	x = mouse_action.cursorX;
   1475 	y = mouse_action.cursorY;
   1476     }
   1477 #endif
   1478     popupMenu(x, y, &SelTabMenu);
   1479 }
   1480 
   1481 static void
   1482 initSelTabMenu(void)
   1483 {
   1484     int i, nitem, len = 0, l;
   1485     TabBuffer *tab;
   1486     Buffer *buf;
   1487     Str str;
   1488     char **label;
   1489     char *p;
   1490     static char *comment = " SPC for select / D for delete tab ";
   1491 
   1492     SelTabV = -1;
   1493     for (i = 0, tab = LastTab; tab != NULL; i++, tab = tab->prevTab) {
   1494 	if (tab == CurrentTab)
   1495 	    SelTabV = i;
   1496     }
   1497     nitem = i;
   1498 
   1499     label = New_N(char *, nitem + 2);
   1500     for (i = 0, tab = LastTab; i < nitem; i++, tab = tab->prevTab) {
   1501 	buf = tab->currentBuffer;
   1502 	str = Sprintf("<%s>", buf->buffername);
   1503 	if (buf->filename != NULL) {
   1504 	    switch (buf->currentURL.scheme) {
   1505 	    case SCM_LOCAL:
   1506 		if (strcmp(buf->currentURL.file, "-")) {
   1507 		    Strcat_char(str, ' ');
   1508 		    Strcat_charp(str,
   1509 				 conv_from_system(buf->currentURL.real_file));
   1510 		}
   1511 		break;
   1512 		/* case SCM_UNKNOWN: */
   1513 	    case SCM_MISSING:
   1514 		break;
   1515 	    default:
   1516 		p = parsedURL2Str(&buf->currentURL)->ptr;
   1517 		if (DecodeURL)
   1518 		    p = url_unquote_conv(p, 0);
   1519 		Strcat_charp(str, p);
   1520 		break;
   1521 	    }
   1522 	}
   1523 	label[i] = str->ptr;
   1524 	if (len < str->length)
   1525 	    len = str->length;
   1526     }
   1527     l = strlen(comment);
   1528     if (len < l + 4)
   1529 	len = l + 4;
   1530     if (len > COLS - 2 * FRAME_WIDTH)
   1531 	len = COLS - 2 * FRAME_WIDTH;
   1532     len = (len > 1) ? ((len - l + 1) / 2) : 0;
   1533     str = Strnew();
   1534     for (i = 0; i < len; i++)
   1535 	Strcat_char(str, '-');
   1536     Strcat_charp(str, comment);
   1537     for (i = 0; i < len; i++)
   1538 	Strcat_char(str, '-');
   1539     label[nitem] = str->ptr;
   1540     label[nitem + 1] = NULL;
   1541 
   1542     new_option_menu(&SelTabMenu, label, &SelTabV, smChTab);
   1543     SelTabMenu.initial = SelTabV;
   1544     SelTabMenu.cursorX = Currentbuf->cursorX + Currentbuf->rootX;
   1545     SelTabMenu.cursorY = Currentbuf->cursorY + Currentbuf->rootY;
   1546     SelTabMenu.keymap['D'] = smDelTab;
   1547     SelTabMenu.item[nitem].type = MENU_NOP;
   1548 }
   1549 
   1550 static void
   1551 smChTab(void)
   1552 {
   1553     int i;
   1554     TabBuffer *tab;
   1555     Buffer *buf;
   1556 
   1557     if (SelTabV < 0 || SelTabV >= SelTabMenu.nitem)
   1558 	return;
   1559     for (i = 0, tab = LastTab; i < SelTabV && tab != NULL;
   1560 	 i++, tab = tab->prevTab) ;
   1561     CurrentTab = tab;
   1562     for (tab = LastTab; tab != NULL; tab = tab->prevTab) {
   1563 	if (tab == CurrentTab)
   1564 	    continue;
   1565 	buf = tab->currentBuffer;
   1566 #ifdef USE_IMAGE
   1567 	deleteImage(buf);
   1568 #endif
   1569 	if (clear_buffer)
   1570 	    tmpClearBuffer(buf);
   1571     }
   1572 }
   1573 
   1574 static int
   1575 smDelTab(char c)
   1576 {
   1577     int i, x, y, mselect;
   1578     TabBuffer *tab;
   1579 
   1580     if (CurrentMenu->select < 0 || CurrentMenu->select >= SelTabMenu.nitem)
   1581 	return (MENU_NOTHING);
   1582     for (i = 0, tab = LastTab; i < CurrentMenu->select && tab != NULL;
   1583 	 i++, tab = tab->prevTab) ;
   1584     deleteTab(tab);
   1585 
   1586     x = CurrentMenu->x;
   1587     y = CurrentMenu->y;
   1588     mselect = CurrentMenu->select;
   1589 
   1590     initSelTabMenu();
   1591 
   1592     CurrentMenu->x = x;
   1593     CurrentMenu->y = y;
   1594 
   1595     geom_menu(CurrentMenu, x, y, 0);
   1596 
   1597     CurrentMenu->select = (mselect <= CurrentMenu->nitem - 2) ? mselect
   1598 	: (CurrentMenu->nitem - 2);
   1599 
   1600     displayBuffer(Currentbuf, B_FORCE_REDRAW);
   1601     draw_all_menu(CurrentMenu);
   1602     select_menu(CurrentMenu, CurrentMenu->select);
   1603     return (MENU_NOTHING);
   1604 }
   1605 
   1606 /* --- SelectMenu (END) --- */
   1607 
   1608 /* --- OptionMenu --- */
   1609 
   1610 void
   1611 optionMenu(int x, int y, char **label, int *variable, int initial,
   1612 	   void (*func) ())
   1613 {
   1614     Menu menu;
   1615 
   1616     set_menu_frame();
   1617 
   1618     new_option_menu(&menu, label, variable, func);
   1619     menu.cursorX = COLS - 1;
   1620     menu.cursorY = LASTLINE;
   1621     menu.x = x;
   1622     menu.y = y;
   1623     menu.initial = initial;
   1624 
   1625     popup_menu(NULL, &menu);
   1626 }
   1627 
   1628 /* --- OptionMenu (END) --- */
   1629 
   1630 /* --- InitMenu --- */
   1631 
   1632 static void
   1633 interpret_menu(FILE * mf)
   1634 {
   1635     Str line;
   1636     char *p, *s;
   1637     int in_menu = 0, nmenu = 0, nitem = 0, type;
   1638     MenuItem *item = NULL;
   1639 #ifdef USE_M17N
   1640     wc_ces charset = SystemCharset;
   1641 #endif
   1642 
   1643     while (!feof(mf)) {
   1644 	line = Strfgets(mf);
   1645 	Strchop(line);
   1646 	Strremovefirstspaces(line);
   1647 	if (line->length == 0)
   1648 	    continue;
   1649 #ifdef USE_M17N
   1650 	line = wc_Str_conv(line, charset, InnerCharset);
   1651 #endif
   1652 	p = line->ptr;
   1653 	s = getWord(&p);
   1654 	if (*s == '#')		/* comment */
   1655 	    continue;
   1656 	if (in_menu) {
   1657 	    type = setMenuItem(&item[nitem], s, p);
   1658 	    if (type == -1)
   1659 		continue;	/* error */
   1660 	    if (type == MENU_END)
   1661 		in_menu = 0;
   1662 	    else {
   1663 		nitem++;
   1664 		item = New_Reuse(MenuItem, item, (nitem + 1));
   1665 		w3mMenuList[nmenu].item = item;
   1666 		item[nitem].type = MENU_END;
   1667 	    }
   1668 	}
   1669 	else if (!strcmp(s, "menu")) {
   1670 	    s = getQWord(&p);
   1671 	    if (*s == '\0')	/* error */
   1672 		continue;
   1673 	    in_menu = 1;
   1674 	    if ((nmenu = getMenuN(w3mMenuList, s)) != -1)
   1675 		w3mMenuList[nmenu].item = New(MenuItem);
   1676 	    else
   1677 		nmenu = addMenuList(&w3mMenuList, s);
   1678 	    item = w3mMenuList[nmenu].item;
   1679 	    nitem = 0;
   1680 	    item[nitem].type = MENU_END;
   1681 	}
   1682 #ifdef USE_M17N
   1683 	else if (!strcmp(s, "charset") || !strcmp(s, "encoding")) {
   1684 	    s = getQWord(&p);
   1685 	    if (*s == '\0')	/* error */
   1686 		continue;
   1687 	    charset = wc_guess_charset(s, charset);
   1688 	}
   1689 #endif
   1690     }
   1691 }
   1692 
   1693 void
   1694 initMenu(void)
   1695 {
   1696     FILE *mf;
   1697     MenuList *list;
   1698 
   1699     w3mMenuList = New_N(MenuList, 3);
   1700     w3mMenuList[0].id = "Main";
   1701     w3mMenuList[0].menu = &MainMenu;
   1702     w3mMenuList[0].item = MainMenuItem;
   1703     w3mMenuList[1].id = "Select";
   1704     w3mMenuList[1].menu = &SelectMenu;
   1705     w3mMenuList[1].item = NULL;
   1706     w3mMenuList[2].id = "SelectTab";
   1707     w3mMenuList[2].menu = &SelTabMenu;
   1708     w3mMenuList[2].item = NULL;
   1709     w3mMenuList[3].id = NULL;
   1710 
   1711 #ifdef USE_M17N
   1712     if (!MainMenuEncode) {
   1713 	MenuItem *item;
   1714 #ifdef ENABLE_NLS
   1715 	/* FIXME: charset that gettext(3) returns */
   1716 	MainMenuCharset = SystemCharset;
   1717 #endif
   1718 	for (item = MainMenuItem; item->type != MENU_END; item++)
   1719 	    item->label =
   1720 		wc_conv(_(item->label), MainMenuCharset,
   1721 			InnerCharset)->ptr;
   1722 	MainMenuEncode = TRUE;
   1723     }
   1724 #endif
   1725     if ((mf = fopen(confFile(MENU_FILE), "rt")) != NULL) {
   1726 	interpret_menu(mf);
   1727 	fclose(mf);
   1728     }
   1729     if ((mf = fopen(rcFile(MENU_FILE), "rt")) != NULL) {
   1730 	interpret_menu(mf);
   1731 	fclose(mf);
   1732     }
   1733 
   1734     for (list = w3mMenuList; list->id != NULL; list++) {
   1735 	if (list->item == NULL)
   1736 	    continue;
   1737 	new_menu(list->menu, list->item);
   1738     }
   1739 }
   1740 
   1741 int
   1742 setMenuItem(MenuItem *item, char *type, char *line)
   1743 {
   1744     char *label, *func, *popup, *keys, *data;
   1745     int f;
   1746     int n;
   1747 
   1748     if (type == NULL || *type == '\0')	/* error */
   1749 	return -1;
   1750     if (strcmp(type, "end") == 0) {
   1751 	item->type = MENU_END;
   1752 	return MENU_END;
   1753     }
   1754     else if (strcmp(type, "nop") == 0) {
   1755 	item->type = MENU_NOP;
   1756 	item->label = getQWord(&line);
   1757 	return MENU_NOP;
   1758     }
   1759     else if (strcmp(type, "func") == 0) {
   1760 	label = getQWord(&line);
   1761 	func = getWord(&line);
   1762 	keys = getQWord(&line);
   1763 	data = getQWord(&line);
   1764 	if (*func == '\0')	/* error */
   1765 	    return -1;
   1766 	item->type = MENU_FUNC;
   1767 	item->label = label;
   1768 	f = getFuncList(func);
   1769 	item->func = w3mFuncList[(f >= 0) ? f : FUNCNAME_nulcmd].func;
   1770 	item->keys = keys;
   1771 	item->data = data;
   1772 	return MENU_FUNC;
   1773     }
   1774     else if (strcmp(type, "popup") == 0) {
   1775 	label = getQWord(&line);
   1776 	popup = getQWord(&line);
   1777 	keys = getQWord(&line);
   1778 	if (*popup == '\0')	/* error */
   1779 	    return -1;
   1780 	item->type = MENU_POPUP;
   1781 	item->label = label;
   1782 	if ((n = getMenuN(w3mMenuList, popup)) == -1)
   1783 	    n = addMenuList(&w3mMenuList, popup);
   1784 	item->popup = w3mMenuList[n].menu;
   1785 	item->keys = keys;
   1786 	return MENU_POPUP;
   1787     }
   1788     return -1;			/* error */
   1789 }
   1790 
   1791 int
   1792 addMenuList(MenuList **mlist, char *id)
   1793 {
   1794     int n;
   1795     MenuList *list = *mlist;
   1796 
   1797     for (n = 0; list->id != NULL; list++, n++) ;
   1798     *mlist = New_Reuse(MenuList, *mlist, (n + 2));
   1799     list = *mlist + n;
   1800     list->id = id;
   1801     list->menu = New(Menu);
   1802     list->item = New(MenuItem);
   1803     (list + 1)->id = NULL;
   1804     return n;
   1805 }
   1806 
   1807 int
   1808 getMenuN(MenuList *list, char *id)
   1809 {
   1810     int n;
   1811 
   1812     for (n = 0; list->id != NULL; list++, n++) {
   1813 	if (strcmp(id, list->id) == 0)
   1814 	    return n;
   1815     }
   1816     return -1;
   1817 }
   1818 
   1819 /* --- InitMenu (END) --- */
   1820 
   1821 LinkList *
   1822 link_menu(Buffer *buf)
   1823 {
   1824     Menu menu;
   1825     LinkList *l;
   1826     int i, nitem, len = 0, linkV = -1;
   1827     char **label;
   1828     Str str;
   1829     char *p;
   1830 
   1831     if (!buf->linklist)
   1832 	return NULL;
   1833 
   1834     for (i = 0, l = buf->linklist; l; i++, l = l->next) ;
   1835     nitem = i;
   1836 
   1837     label = New_N(char *, nitem + 1);
   1838     for (i = 0, l = buf->linklist; l; i++, l = l->next) {
   1839 	str = Strnew_charp(l->title ? l->title : "(empty)");
   1840 	if (l->type == LINK_TYPE_REL)
   1841 	    Strcat_charp(str, " [Rel] ");
   1842 	else if (l->type == LINK_TYPE_REV)
   1843 	    Strcat_charp(str, " [Rev] ");
   1844 	else
   1845 	    Strcat_charp(str, " ");
   1846 	if (!l->url)
   1847 	    p = "";
   1848 	else if (DecodeURL)
   1849 	    p = url_unquote_conv(l->url, buf->document_charset);
   1850 	else
   1851 	    p = l->url;
   1852 	Strcat_charp(str, p);
   1853 	label[i] = str->ptr;
   1854 	if (len < str->length)
   1855 	    len = str->length;
   1856     }
   1857     label[nitem] = NULL;
   1858 
   1859     set_menu_frame();
   1860     new_option_menu(&menu, label, &linkV, NULL);
   1861 
   1862     menu.initial = 0;
   1863     menu.cursorX = buf->cursorX + buf->rootX;
   1864     menu.cursorY = buf->cursorY + buf->rootY;
   1865     menu.x = menu.cursorX + FRAME_WIDTH + 1;
   1866     menu.y = menu.cursorY + 2;
   1867 
   1868     popup_menu(NULL, &menu);
   1869 
   1870     if (linkV < 0)
   1871 	return NULL;
   1872     for (i = 0, l = buf->linklist; l; i++, l = l->next) {
   1873 	if (i == linkV)
   1874 	    return l;
   1875     }
   1876     return NULL;
   1877 }
   1878 
   1879 /* --- LinkMenu (END) --- */
   1880 
   1881 Anchor *
   1882 accesskey_menu(Buffer *buf)
   1883 {
   1884     Menu menu;
   1885     AnchorList *al = buf->href;
   1886     Anchor *a;
   1887     Anchor **ap;
   1888     int i, n, nitem = 0, key = -1;
   1889     char **label;
   1890     char *t;
   1891     unsigned char c;
   1892 
   1893     if (!al)
   1894 	return NULL;
   1895     for (i = 0; i < al->nanchor; i++) {
   1896 	a = &al->anchors[i];
   1897 	if (!a->slave && a->accesskey && IS_ASCII(a->accesskey))
   1898 	    nitem++;
   1899     }
   1900     if (!nitem)
   1901 	return NULL;
   1902 
   1903     label = New_N(char *, nitem + 1);
   1904     ap = New_N(Anchor *, nitem);
   1905     for (i = 0, n = 0; i < al->nanchor; i++) {
   1906 	a = &al->anchors[i];
   1907 	if (!a->slave && a->accesskey && IS_ASCII(a->accesskey)) {
   1908 	    t = getAnchorText(buf, al, a);
   1909 	    label[n] = Sprintf("%c: %s", a->accesskey, t ? t : "")->ptr;
   1910 	    ap[n] = a;
   1911 	    n++;
   1912 	}
   1913     }
   1914     label[nitem] = NULL;
   1915 
   1916     new_option_menu(&menu, label, &key, NULL);
   1917 
   1918     menu.initial = 0;
   1919     menu.cursorX = buf->cursorX + buf->rootX;
   1920     menu.cursorY = buf->cursorY + buf->rootY;
   1921     menu.x = menu.cursorX + FRAME_WIDTH + 1;
   1922     menu.y = menu.cursorY + 2;
   1923     for (i = 0; i < 128; i++)
   1924 	menu.keyselect[i] = -1;
   1925     for (i = 0; i < nitem; i++) {
   1926 	c = ap[i]->accesskey;
   1927 	menu.keymap[(int)c] = mSelect;
   1928 	menu.keyselect[(int)c] = i;
   1929     }
   1930     for (i = 0; i < nitem; i++) {
   1931 	c = ap[i]->accesskey;
   1932 	if (!IS_ALPHA(c) || menu.keyselect[n] >= 0)
   1933 	    continue;
   1934 	c = TOLOWER(c);
   1935 	menu.keymap[(int)c] = mSelect;
   1936 	menu.keyselect[(int)c] = i;
   1937 	c = TOUPPER(c);
   1938 	menu.keymap[(int)c] = mSelect;
   1939 	menu.keyselect[(int)c] = i;
   1940     }
   1941 
   1942     a = retrieveCurrentAnchor(buf);
   1943     if (a && a->accesskey && IS_ASCII(a->accesskey)) {
   1944 	for (i = 0; i < nitem; i++) {
   1945 	    if (a->hseq == ap[i]->hseq) {
   1946 		menu.initial = i;
   1947 		break;
   1948 	    }
   1949 	}
   1950     }
   1951 
   1952     popup_menu(NULL, &menu);
   1953 
   1954     return (key >= 0) ? ap[key] : NULL;
   1955 }
   1956 
   1957 static char lmKeys[] = "abcdefgimopqrstuvwxyz";
   1958 static char lmKeys2[] = "1234567890ABCDEFGHILMOPQRSTUVWXYZ";
   1959 #define nlmKeys (sizeof(lmKeys) - 1)
   1960 #define nlmKeys2 (sizeof(lmKeys2) - 1)
   1961 
   1962 static int
   1963 lmGoto(char c)
   1964 {
   1965     if (IS_ASCII(c) && CurrentMenu->keyselect[(int)c] >= 0) {
   1966 	goto_menu(CurrentMenu, CurrentMenu->nitem - 1, -1);
   1967 	goto_menu(CurrentMenu, CurrentMenu->keyselect[(int)c] * nlmKeys, 1);
   1968     }
   1969     return (MENU_NOTHING);
   1970 }
   1971 
   1972 static int
   1973 lmSelect(char c)
   1974 {
   1975     if (IS_ASCII(c))
   1976 	return select_menu(CurrentMenu, (CurrentMenu->select / nlmKeys) *
   1977 			   nlmKeys + CurrentMenu->keyselect[(int)c]);
   1978     else
   1979 	return (MENU_NOTHING);
   1980 }
   1981 
   1982 Anchor *
   1983 list_menu(Buffer *buf)
   1984 {
   1985     Menu menu;
   1986     AnchorList *al = buf->href;
   1987     Anchor *a;
   1988     Anchor **ap;
   1989     int i, n, nitem = 0, key = -1, two = FALSE;
   1990     char **label;
   1991     char *t;
   1992     unsigned char c;
   1993 
   1994     if (!al)
   1995 	return NULL;
   1996     for (i = 0; i < al->nanchor; i++) {
   1997 	a = &al->anchors[i];
   1998 	if (!a->slave)
   1999 	    nitem++;
   2000     }
   2001     if (!nitem)
   2002 	return NULL;
   2003 
   2004     if (nitem >= nlmKeys)
   2005 	two = TRUE;
   2006     label = New_N(char *, nitem + 1);
   2007     ap = New_N(Anchor *, nitem);
   2008     for (i = 0, n = 0; i < al->nanchor; i++) {
   2009 	a = &al->anchors[i];
   2010 	if (!a->slave) {
   2011 	    t = getAnchorText(buf, al, a);
   2012 	    if (!t)
   2013 		t = "";
   2014 	    if (two && n >= nlmKeys2 * nlmKeys)
   2015 		label[n] = Sprintf("  : %s", t)->ptr;
   2016 	    else if (two)
   2017 		label[n] = Sprintf("%c%c: %s", lmKeys2[n / nlmKeys],
   2018 				   lmKeys[n % nlmKeys], t)->ptr;
   2019 	    else
   2020 		label[n] = Sprintf("%c: %s", lmKeys[n], t)->ptr;
   2021 	    ap[n] = a;
   2022 	    n++;
   2023 	}
   2024     }
   2025     label[nitem] = NULL;
   2026 
   2027     set_menu_frame();
   2028     set_menu_frame();
   2029     new_option_menu(&menu, label, &key, NULL);
   2030 
   2031     menu.initial = 0;
   2032     menu.cursorX = buf->cursorX + buf->rootX;
   2033     menu.cursorY = buf->cursorY + buf->rootY;
   2034     menu.x = menu.cursorX + FRAME_WIDTH + 1;
   2035     menu.y = menu.cursorY + 2;
   2036     for (i = 0; i < 128; i++)
   2037 	menu.keyselect[i] = -1;
   2038     if (two) {
   2039 	for (i = 0; i < nlmKeys2; i++) {
   2040 	    c = lmKeys2[i];
   2041 	    menu.keymap[(int)c] = lmGoto;
   2042 	    menu.keyselect[(int)c] = i;
   2043 	}
   2044 	for (i = 0; i < nlmKeys; i++) {
   2045 	    c = lmKeys[i];
   2046 	    menu.keymap[(int)c] = lmSelect;
   2047 	    menu.keyselect[(int)c] = i;
   2048 	}
   2049     }
   2050     else {
   2051 	for (i = 0; i < nitem; i++) {
   2052 	    c = lmKeys[i];
   2053 	    menu.keymap[(int)c] = mSelect;
   2054 	    menu.keyselect[(int)c] = i;
   2055 	}
   2056     }
   2057 
   2058     a = retrieveCurrentAnchor(buf);
   2059     if (a) {
   2060 	for (i = 0; i < nitem; i++) {
   2061 	    if (a->hseq == ap[i]->hseq) {
   2062 		menu.initial = i;
   2063 		break;
   2064 	    }
   2065 	}
   2066     }
   2067 
   2068     popup_menu(NULL, &menu);
   2069 
   2070     return (key >= 0) ? ap[key] : NULL;
   2071 }
   2072 
   2073 #endif				/* USE_MENU */