Changeset 1661
- Timestamp:
- 02/17/98 01:45:16 (11 years ago)
- Files:
-
- branches/GNU/src/w32menu.c (modified) (73 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/GNU/src/w32menu.c
r1635 r1661 1 1 /* Menu support for GNU Emacs on the Microsoft W32 API. 2 Copyright (C) 1986, 88, 93, 94, 96, 98, 1999Free Software Foundation, Inc.2 Copyright (C) 1986, 1988, 1993, 1994, 1996, 1998 Free Software Foundation, Inc. 3 3 4 4 This file is part of GNU Emacs. … … 19 19 Boston, MA 02111-1307, USA. */ 20 20 21 #include <signal.h> 21 22 #include <config.h> 22 #include <signal.h>23 23 24 24 #include <stdio.h> 25 25 #include "lisp.h" 26 26 #include "termhooks.h" 27 #include "keyboard.h"28 27 #include "frame.h" 29 28 #include "window.h" 29 #include "keyboard.h" 30 30 #include "blockinput.h" 31 31 #include "buffer.h" … … 46 46 47 47 #undef HAVE_MULTILINGUAL_MENU 48 #undef HAVE_DIALOGS /* TODO: Implement native dialogs. */49 48 50 49 /******************************************************************/ … … 54 53 typedef char Boolean; 55 54 56 enum button_type 57 { 58 BUTTON_TYPE_NONE, 59 BUTTON_TYPE_TOGGLE, 60 BUTTON_TYPE_RADIO 61 }; 55 #define True 1 56 #define False 0 57 58 typedef enum _change_type 59 { 60 NO_CHANGE = 0, 61 INVISIBLE_CHANGE = 1, 62 VISIBLE_CHANGE = 2, 63 STRUCTURAL_CHANGE = 3 64 } change_type; 62 65 63 66 typedef struct _widget_value … … 69 72 /* keyboard equivalent. no implications for XtTranslations */ 70 73 char* key; 71 /* Help string or null if none. */72 char *help;73 74 /* true if enabled */ 74 75 Boolean enabled; 75 76 /* true if selected */ 76 77 Boolean selected; 77 /* The type of a button. */78 enum button_type button_type;79 78 /* true if menu title */ 80 79 Boolean title; … … 140 139 void set_frame_menubar (); 141 140 142 static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object, 143 Lisp_Object, Lisp_Object, Lisp_Object, 144 Lisp_Object, Lisp_Object)); 141 static Lisp_Object w32_menu_show (); 145 142 static Lisp_Object w32_dialog_show (); 146 static Lisp_Object w32_menu_show ();147 143 148 144 static void keymap_panes (); … … 178 174 #define MENU_ITEMS_PANE_LENGTH 3 179 175 180 enum menu_item_idx 181 { 182 MENU_ITEMS_ITEM_NAME = 0, 183 MENU_ITEMS_ITEM_ENABLE, 184 MENU_ITEMS_ITEM_VALUE, 185 MENU_ITEMS_ITEM_EQUIV_KEY, 186 MENU_ITEMS_ITEM_DEFINITION, 187 MENU_ITEMS_ITEM_TYPE, 188 MENU_ITEMS_ITEM_SELECTED, 189 MENU_ITEMS_ITEM_HELP, 190 MENU_ITEMS_ITEM_LENGTH 191 }; 176 #define MENU_ITEMS_ITEM_NAME 0 177 #define MENU_ITEMS_ITEM_ENABLE 1 178 #define MENU_ITEMS_ITEM_VALUE 2 179 #define MENU_ITEMS_ITEM_EQUIV_KEY 3 180 #define MENU_ITEMS_ITEM_DEFINITION 4 181 #define MENU_ITEMS_ITEM_LENGTH 5 192 182 193 183 static Lisp_Object menu_items; … … 210 200 static int popup_activated_flag; 211 201 212 static int next_menubar_widget_id;213 214 202 /* This is set nonzero after the user activates the menu bar, and set 215 203 to zero again after the menu bars are redisplayed by prepare_menu_bar. … … 223 211 224 212 /* Return the frame whose ->output_data.w32->menubar_widget equals 225 ID, or 0 if none. */213 MENU, or 0 if none. */ 226 214 227 215 static struct frame * 228 menubar_id_to_frame (id) 229 HMENU id; 216 menubar_id_to_frame (HMENU menu) 230 217 { 231 218 Lisp_Object tail, frame; 232 219 FRAME_PTR f; 233 220 234 for (tail = Vframe_list; GC_CONSP (tail); tail = XC DR (tail))235 { 236 frame = XC AR (tail);221 for (tail = Vframe_list; GC_CONSP (tail); tail = XCONS (tail)->cdr) 222 { 223 frame = XCONS (tail)->car; 237 224 if (!GC_FRAMEP (frame)) 238 225 continue; 239 226 f = XFRAME (frame); 240 if ( !FRAME_WINDOW_P (f))227 if (f->output_data.nothing == 1) 241 228 continue; 242 if (f->output_data.w32->menubar_widget == id)229 if (f->output_data.w32->menubar_widget == menu) 243 230 return f; 244 231 } … … 353 340 } 354 341 355 /* Push one menu item into the current pane. NAME is the string to356 display. ENABLE if non-nil means this item can be selected. KEY357 is the key generated by choosing this item, or nil if this item358 doesn't really have a definition. DEF is the definition of this359 item. EQUIV is the textual description of the keyboard equivalent360 for this item (or nil if none). TYPE is the type of this menu361 item, one of nil, `toggle' or `radio'.*/342 /* Push one menu item into the current pane. 343 NAME is the string to display. ENABLE if non-nil means 344 this item can be selected. KEY is the key generated by 345 choosing this item, or nil if this item doesn't really have a definition. 346 DEF is the definition of this item. 347 EQUIV is the textual description of the keyboard equivalent for 348 this item (or nil if none). */ 362 349 363 350 static void 364 push_menu_item (name, enable, key, def, equiv , type, selected, help)365 Lisp_Object name, enable, key, def, equiv , type, selected, help;351 push_menu_item (name, enable, key, def, equiv) 352 Lisp_Object name, enable, key, def, equiv; 366 353 { 367 354 if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated) … … 373 360 XVECTOR (menu_items)->contents[menu_items_used++] = equiv; 374 361 XVECTOR (menu_items)->contents[menu_items_used++] = def; 375 XVECTOR (menu_items)->contents[menu_items_used++] = type;376 XVECTOR (menu_items)->contents[menu_items_used++] = selected;377 XVECTOR (menu_items)->contents[menu_items_used++] = help;378 362 } 379 363 … … 397 381 P is the number of panes we have made so far. */ 398 382 for (mapno = 0; mapno < nmaps; mapno++) 399 single_keymap_panes (keymaps[mapno], 400 map_prompt (keymaps[mapno]), Qnil, notreal, 10); 383 single_keymap_panes (keymaps[mapno], Qnil, Qnil, notreal, 10); 401 384 402 385 finish_menu_items (); … … 423 406 Lisp_Object tail, item; 424 407 struct gcpro gcpro1, gcpro2; 408 int notbuttons = 0; 425 409 426 410 if (maxdepth <= 0) … … 429 413 push_menu_pane (pane_name, prefix); 430 414 431 for (tail = keymap; CONSP (tail); tail = XCDR (tail)) 415 #ifndef HAVE_BOXES 416 /* Remember index for first item in this pane so we can go back and 417 add a prefix when (if) we see the first button. After that, notbuttons 418 is set to 0, to mark that we have seen a button and all non button 419 items need a prefix. */ 420 notbuttons = menu_items_used; 421 #endif 422 423 for (tail = keymap; CONSP (tail); tail = XCONS (tail)->cdr) 432 424 { 433 425 GCPRO2 (keymap, pending_maps); 434 426 /* Look at each key binding, and if it is a menu item add it 435 427 to this menu. */ 436 item = XC AR (tail);428 item = XCONS (tail)->car; 437 429 if (CONSP (item)) 438 single_menu_item (XC AR (item), XCDR (item),439 &pending_maps, notreal, maxdepth );430 single_menu_item (XCONS (item)->car, XCONS (item)->cdr, 431 &pending_maps, notreal, maxdepth, ¬buttons); 440 432 else if (VECTORP (item)) 441 433 { … … 448 440 XSETFASTINT (character, c); 449 441 single_menu_item (character, XVECTOR (item)->contents[c], 450 &pending_maps, notreal, maxdepth );442 &pending_maps, notreal, maxdepth, ¬buttons); 451 443 } 452 444 } … … 459 451 Lisp_Object elt, eltcdr, string; 460 452 elt = Fcar (pending_maps); 461 eltcdr = XC DR (elt);462 string = XC AR (eltcdr);453 eltcdr = XCONS (elt)->cdr; 454 string = XCONS (eltcdr)->car; 463 455 /* We no longer discard the @ from the beginning of the string here. 464 456 Instead, we do this in w32_menu_show. */ 465 457 single_keymap_panes (Fcar (elt), string, 466 XC DR (eltcdr), notreal, maxdepth - 1);458 XCONS (eltcdr)->cdr, notreal, maxdepth - 1); 467 459 pending_maps = Fcdr (pending_maps); 468 460 } … … 476 468 If NOTREAL is nonzero, only check for equivalent key bindings, don't 477 469 evaluate expressions in menu items and don't make any menu. 478 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */ 470 If we encounter submenus deeper than MAXDEPTH levels, ignore them. 471 NOTBUTTONS_PTR is only used when simulating toggle boxes and radio 472 buttons. It points to variable notbuttons in single_keymap_panes, 473 which keeps track of if we have seen a button in this menu or not. */ 479 474 480 475 static void 481 single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth) 476 single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth, 477 notbuttons_ptr) 482 478 Lisp_Object key, item; 483 479 Lisp_Object *pending_maps_ptr; 484 480 int maxdepth, notreal; 485 { 486 Lisp_Object map, item_string, enabled; 481 int *notbuttons_ptr; 482 { 483 Lisp_Object def, map, item_string, enabled; 487 484 struct gcpro gcpro1, gcpro2; 488 485 int res; … … 518 515 } 519 516 517 #ifndef HAVE_BOXES 518 /* Simulate radio buttons and toggle boxes by putting a prefix in 519 front of them. */ 520 { 521 Lisp_Object prefix = Qnil; 522 Lisp_Object type = XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE]; 523 if (!NILP (type)) 524 { 525 Lisp_Object selected 526 = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED]; 527 528 if (*notbuttons_ptr) 529 /* The first button. Line up previous items in this menu. */ 530 { 531 int index = *notbuttons_ptr; /* Index for first item this menu. */ 532 int submenu = 0; 533 Lisp_Object tem; 534 while (index < menu_items_used) 535 { 536 tem 537 = XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME]; 538 if (NILP (tem)) 539 { 540 index++; 541 submenu++; /* Skip sub menu. */ 542 } 543 else if (EQ (tem, Qlambda)) 544 { 545 index++; 546 submenu--; /* End sub menu. */ 547 } 548 else if (EQ (tem, Qt)) 549 index += 3; /* Skip new pane marker. */ 550 else if (EQ (tem, Qquote)) 551 index++; /* Skip a left, right divider. */ 552 else 553 { 554 if (!submenu && XSTRING (tem)->data[0] != '\0' 555 && XSTRING (tem)->data[0] != '-') 556 XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME] 557 = concat2 (build_string (" "), tem); 558 index += MENU_ITEMS_ITEM_LENGTH; 559 } 560 } 561 *notbuttons_ptr = 0; 562 } 563 564 /* Calculate prefix, if any, for this item. */ 565 if (EQ (type, QCtoggle)) 566 prefix = build_string (NILP (selected) ? "[ ] " : "[X] "); 567 else if (EQ (type, QCradio)) 568 prefix = build_string (NILP (selected) ? "( ) " : "(*) "); 569 } 570 /* Not a button. If we have earlier buttons, then we need a prefix. */ 571 else if (!*notbuttons_ptr && XSTRING (item_string)->data[0] != '\0' 572 && XSTRING (item_string)->data[0] != '-') 573 prefix = build_string (" "); 574 575 if (!NILP (prefix)) 576 item_string = concat2 (prefix, item_string); 577 } 578 #endif /* not HAVE_BOXES */ 579 580 #if 0 581 if (!NILP(map)) 582 /* Indicate visually that this is a submenu. */ 583 item_string = concat2 (item_string, build_string (" >")); 584 #endif 585 520 586 push_menu_item (item_string, enabled, key, 521 587 XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF], 522 XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ], 523 XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE], 524 XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED], 525 XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]); 526 588 XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ]); 589 590 #if 1 527 591 /* Display a submenu using the toolkit. */ 528 592 if (! (NILP (map) || NILP (enabled))) … … 532 596 push_submenu_end (); 533 597 } 598 #endif 534 599 } 535 600 … … 573 638 item = Fcar (tail); 574 639 if (STRINGP (item)) 575 push_menu_item (item, Qnil, Qnil, Qt, Qnil , Qnil, Qnil, Qnil);640 push_menu_item (item, Qnil, Qnil, Qt, Qnil); 576 641 else if (NILP (item)) 577 642 push_left_right_boundary (); … … 581 646 item1 = Fcar (item); 582 647 CHECK_STRING (item1, 1); 583 push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil , Qnil, Qnil, Qnil);648 push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil); 584 649 } 585 650 } … … 622 687 Lisp_Object position, menu; 623 688 { 689 int number_of_panes, panes; 624 690 Lisp_Object keymap, tem; 625 691 int xpos, ypos; … … 627 693 char *error_name; 628 694 Lisp_Object selection; 695 int i, j; 629 696 FRAME_PTR f; 630 697 Lisp_Object x, y, window; … … 640 707 /* Decode the first argument: find the window and the coordinates. */ 641 708 if (EQ (position, Qt) 642 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar) 643 || EQ (XCAR (position), Qtool_bar)))) 709 || (CONSP (position) && EQ (XCONS (position)->car, Qmenu_bar))) 644 710 { 645 711 /* Use the mouse's current position. */ 646 FRAME_PTR new_f = SELECTED_FRAME ();712 FRAME_PTR new_f = selected_frame; 647 713 Lisp_Object bar_window; 648 enum scroll_bar_part part;714 int part; 649 715 unsigned long time; 650 716 … … 697 763 f = XFRAME (WINDOW_FRAME (XWINDOW (window))); 698 764 699 xpos = (FONT_WIDTH ( FRAME_FONT (f))765 xpos = (FONT_WIDTH (f->output_data.w32->font) 700 766 * XFASTINT (XWINDOW (window)->left)); 701 ypos = ( FRAME_LINE_HEIGHT (f)767 ypos = (f->output_data.w32->line_height 702 768 * XFASTINT (XWINDOW (window)->top)); 703 769 } … … 720 786 /* Decode the menu items from what was specified. */ 721 787 722 keymap = get_keymap (menu, 0, 0); 723 if (CONSP (keymap)) 788 keymap = Fkeymapp (menu); 789 tem = Qnil; 790 if (CONSP (menu)) 791 tem = Fkeymapp (Fcar (menu)); 792 if (!NILP (keymap)) 724 793 { 725 794 /* We were given a keymap. Extract menu info from the keymap. */ 726 795 Lisp_Object prompt; 796 keymap = get_keymap (menu); 727 797 728 798 /* Extract the detailed info to make one pane. */ … … 741 811 keymaps = 1; 742 812 } 743 else if ( CONSP (menu) && KEYMAPP (XCAR (menu)))813 else if (!NILP (tem)) 744 814 { 745 815 /* We were given a list of keymaps. */ … … 757 827 Lisp_Object prompt; 758 828 759 maps[i++] = keymap = get_keymap (Fcar (tem) , 1, 0);829 maps[i++] = keymap = get_keymap (Fcar (tem)); 760 830 761 831 prompt = map_prompt (keymap); … … 835 905 /* Decode the first argument: find the window or frame to use. */ 836 906 if (EQ (position, Qt) 837 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar) 838 || EQ (XCAR (position), Qtool_bar)))) 907 || (CONSP (position) && EQ (XCONS (position)->car, Qmenu_bar))) 839 908 { 840 909 #if 0 /* Using the frame the mouse is on may not be right. */ 841 910 /* Use the mouse's current position. */ 842 FRAME_PTR new_f = SELECTED_FRAME ();911 FRAME_PTR new_f = selected_frame; 843 912 Lisp_Object bar_window; 844 enum scroll_bar_part part;913 int part; 845 914 unsigned long time; 846 915 Lisp_Object x, y; … … 886 955 CHECK_WINDOW (window, 0); 887 956 888 #if ndef HAVE_DIALOGS957 #if 1 889 958 /* Display a menu with these alternatives 890 959 in the middle of frame F. */ … … 899 968 Fcons (Fcar (contents), Fcons (contents, Qnil))); 900 969 } 901 #else /* HAVE_DIALOGS */970 #else 902 971 { 903 972 Lisp_Object title; … … 921 990 return selection; 922 991 } 923 #endif /* HAVE_DIALOGS */992 #endif 924 993 } 925 994 … … 936 1005 This way we can safely execute Lisp code. */ 937 1006 938 void939 1007 x_activate_menubar (f) 940 1008 FRAME_PTR f; … … 965 1033 if (!f) 966 1034 return; 967 entry = Qnil;968 1035 subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object)); 969 1036 vector = f->menu_bar_vector; … … 1000 1067 1001 1068 XSETFRAME (frame, f); 1002 buf.kind = MENU_BAR_EVENT; 1003 buf.frame_or_window = frame; 1004 buf.arg = frame; 1069 buf.kind = menu_bar_event; 1070 buf.frame_or_window = Fcons (frame, Fcons (Qmenu_bar, Qnil)); 1005 1071 kbd_buffer_store_event (&buf); 1006 1072 … … 1008 1074 if (!NILP (subprefix_stack[j])) 1009 1075 { 1010 buf.kind = MENU_BAR_EVENT; 1011 buf.frame_or_window = frame; 1012 buf.arg = subprefix_stack[j]; 1076 buf.kind = menu_bar_event; 1077 buf.frame_or_window = Fcons (frame, subprefix_stack[j]); 1013 1078 kbd_buffer_store_event (&buf); 1014 1079 } … … 1016 1081 if (!NILP (prefix)) 1017 1082 { 1018 buf.kind = MENU_BAR_EVENT; 1019 buf.frame_or_window = frame; 1020 buf.arg = prefix; 1083 buf.kind = menu_bar_event; 1084 buf.frame_or_window = Fcons (frame, prefix); 1021 1085 kbd_buffer_store_event (&buf); 1022 1086 } 1023 1087 1024 buf.kind = MENU_BAR_EVENT; 1025 buf.frame_or_window = frame; 1026 buf.arg = entry; 1088 buf.kind = menu_bar_event; 1089 buf.frame_or_window = Fcons (frame, entry); 1027 1090 kbd_buffer_store_event (&buf); 1028 1091 … … 1091 1154 Lisp_Object *mapvec; 1092 1155 widget_value **submenu_stack; 1156 int mapno; 1093 1157 int previous_items = menu_items_used; 1094 1158 int top_level_items = 0; … … 1112 1176 { 1113 1177 if (SYMBOLP (mapvec[i]) 1114 || (CONSP (mapvec[i]) && !KEYMAPP (mapvec[i]))) 1178 || (CONSP (mapvec[i]) 1179 && NILP (Fkeymapp (mapvec[i])))) 1115 1180 { 1116 1181 /* Here we have a command at top level in the menu bar … … 1118 1183 top_level_items = 1; 1119 1184 push_menu_pane (Qnil, Qnil); 1120 push_menu_item (item_name, Qt, item_key, mapvec[i], 1121 Qnil, Qnil, Qnil, Qnil); 1185 push_menu_item (item_name, Qt, item_key, mapvec[i], Qnil); 1122 1186 } 1123 1187 else … … 1134 1198 wv->value = 0; 1135 1199 wv->enabled = 1; 1136 wv->button_type = BUTTON_TYPE_NONE;1137 1200 first_wv = wv; 1138 1201 save_wv = 0; … … 1201 1264 wv->value = 0; 1202 1265 wv->enabled = 1; 1203 wv->button_type = BUTTON_TYPE_NONE;1204 1266 } 1205 1267 save_wv = wv; … … 1210 1272 { 1211 1273 /* Create a new item within current pane. */ 1212 Lisp_Object item_name, enable, descrip, def, type, selected; 1213 Lisp_Object help; 1214 1274 Lisp_Object item_name, enable, descrip, def; 1215 1275 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME]; 1216 1276 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE]; … … 1218 1278 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY]; 1219 1279 def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION]; 1220 type = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_TYPE];1221 selected = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_SELECTED];1222 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];1223 1224 1280 #ifndef HAVE_MULTILINGUAL_MENU 1225 1281 if (STRING_MULTIBYTE (item_name)) … … 1228 1284 descrip = ENCODE_SYSTEM (descrip); 1229 1285 #endif 1230 1231 1286 wv = xmalloc_widget_value (); 1232 1287 if (prev_wv) … … 1243 1298 wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0); 1244 1299 wv->enabled = !NILP (enable); 1245 1246 if (NILP (type))1247 wv->button_type = BUTTON_TYPE_NONE;1248 else if (EQ (type, QCradio))1249 wv->button_type = BUTTON_TYPE_RADIO;1250 else if (EQ (type, QCtoggle))1251 wv->button_type = BUTTON_TYPE_TOGGLE;1252 else1253 abort ();1254 1255 wv->selected = !NILP (selected);1256 if (STRINGP (help))1257 wv->help = (char *) XSTRING (help)->data;1258 else1259 wv->help = NULL;1260 1261 1300 prev_wv = wv; 1262 1301 … … 1288 1327 { 1289 1328 HMENU menubar_widget = f->output_data.w32->menubar_widget; 1290 Lisp_Object items;1329 Lisp_Object tail, items, frame; 1291 1330 widget_value *wv, *first_wv, *prev_wv = 0; 1292 1331 int i; … … 1307 1346 wv->value = 0; 1308 1347 wv->enabled = 1; 1309 wv->button_type = BUTTON_TYPE_NONE;1310 1348 first_wv = wv; 1311 1349 … … 1343 1381 1344 1382 /* Run the Lucid hook. */ 1345 safe_run_hooks (Qactivate_menubar_hook);1383 call1 (Vrun_hooks, Qactivate_menubar_hook); 1346 1384 /* If it has changed current-menubar from previous value, 1347 1385 really recompute the menubar from the value. */ … … 1380 1418 /* Don't set wv->name here; GC during the loop might relocate it. */ 1381 1419 wv->enabled = 1; 1382 wv->button_type = BUTTON_TYPE_NONE;1383 1420 prev_wv = wv; 1384 1421 } … … 1424 1461 { 1425 1462 /* Make a widget-value tree containing 1426 just the top level menu bar strings. */ 1463 just the top level menu bar strings. 1464 1465 It turns out to be worth comparing the new contents with the 1466 previous contents to avoid unnecessary rebuilding even of just 1467 the top-level menu bar, which turns out to be fairly slow. We 1468 co-opt f->menu_bar_vector for this purpose, since its contents 1469 are effectively discarded at this point anyway. 1470 1471 Note that the lisp-level hooks have already been run by 1472 update_menu_bar - it's kinda a shame the code is duplicated 1473 above as well for deep_p, but there we are. */ 1427 1474 1428 1475 items = FRAME_MENU_BAR_ITEMS (f); 1476 1477 /* If there has been no change in the Lisp-level contents of just 1478 the menu bar itself, skip redisplaying it. Just exit. */ 1479 for (i = 0; i < f->menu_bar_items_used; i += 4) 1480 if (i == XVECTOR (items)->size 1481 || (XVECTOR (f->menu_bar_vector)->contents[i] 1482 != XVECTOR (items)->contents[i])) 1483 break; 1484 if (i == XVECTOR (items)->size && i == f->menu_bar_items_used && i != 0) 1485 return; 1486 1429 1487 for (i = 0; i < XVECTOR (items)->size; i += 4) 1430 1488 { … … 1439 1497 wv->value = 0; 1440 1498 wv->enabled = 1; 1441 wv->button_type = BUTTON_TYPE_NONE;1442 1499 /* This prevents lwlib from assuming this 1443 1500 menu item is really supposed to be empty. */ … … 1453 1510 } 1454 1511 1455 /* Forget what we thought we knew about what is in the 1456 detailed contents of the menu bar menus. 1457 Changing the top level always destroys the contents. */ 1458 f->menu_bar_items_used = 0; 1512 /* Remember the contents of FRAME_MENU_BAR_ITEMS (f) in 1513 f->menu_bar_vector, so we can check whether the top-level 1514 menubar contents have changed next time. */ 1515 if (XVECTOR (f->menu_bar_vector)->size < XVECTOR (items)->size) 1516 f->menu_bar_vector 1517 = Fmake_vector (make_number (XVECTOR (items)->size), Qnil); 1518 bcopy (XVECTOR (items)->contents, 1519 XVECTOR (f->menu_bar_vector)->contents, 1520 XVECTOR (items)->size * sizeof (Lisp_Object)); 1521 f->menu_bar_items_used = XVECTOR (items)->size; 1459 1522 } 1460 1523 … … 1564 1627 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object)); 1565 1628 int submenu_depth = 0; 1629 1566 1630 int first_pane; 1631 int next_release_must_exit = 0; 1567 1632 1568 1633 *error = NULL; … … 1580 1645 wv->value = 0; 1581 1646 wv->enabled = 1; 1582 wv->button_type = BUTTON_TYPE_NONE;1583 1647 first_wv = wv; 1584 1648 first_pane = 1; … … 1643 1707 wv->value = 0; 1644 1708 wv->enabled = 1; 1645 wv->button_type = BUTTON_TYPE_NONE;1646 1709 save_wv = wv; 1647 1710 prev_wv = 0; … … 1658 1721 { 1659 1722 /* Create a new item within current pane. */ 1660 Lisp_Object item_name, enable, descrip, def, type, selected, help; 1661 1723 Lisp_Object item_name, enable, descrip, def; 1662 1724 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME]; 1663 1725 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE]; … … 1665 1727 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY]; 1666 1728 def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION]; 1667 type = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_TYPE];1668 selected = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_SELECTED];1669 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];1670 1729 1671 1730 #ifndef HAVE_MULTILINGUAL_MENU 1672 if (STRINGP (item_name) &&STRING_MULTIBYTE (item_name))1673 item_name = ENCODE_SYSTEM (item_name);1674 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))1675 descrip = ENCODE_SYSTEM (descrip);1731 if (STRING_MULTIBYTE (item_name)) 1732 item_name = ENCODE_SYSTEM (item_name); 1733 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) 1734 descrip = ENCODE_SYSTEM (descrip); 1676 1735 #endif 1677 1736 … … 1689 1748 wv->call_data = !NILP (def) ? (void *) (EMACS_INT) i : 0; 1690 1749 wv->enabled = !NILP (enable); 1691 1692 if (NILP (type))1693 wv->button_type = BUTTON_TYPE_NONE;1694 else if (EQ (type, QCtoggle))1695 wv->button_type = BUTTON_TYPE_TOGGLE;1696 else if (EQ (type, QCradio))1697 wv->button_type = BUTTON_TYPE_RADIO;1698 else1699 abort ();1700 1701 wv->selected = !NILP (selected);1702 1703 if (STRINGP (help))1704 wv->help = (char *) XSTRING (help)->data;1705 else1706 wv->help = NULL;1707 1708 1750 prev_wv = wv; 1709 1751 … … 1728 1770 #endif 1729 1771 wv_title->name = (char *) XSTRING (title)->data; 1730 wv_title->enabled = TRUE; 1731 wv_title->title = TRUE; 1732 wv_title->button_type = BUTTON_TYPE_NONE; 1772 /* Handle title specially, so it looks better. */ 1773 wv_title->title = True; 1733 1774 wv_title->next = wv_sep; 1734 1775 first_wv->contents = wv_title; … … 1738 1779 menu = CreatePopupMenu (); 1739 1780 fill_in_menu (menu, first_wv->contents); 1740 1781 1741 1782 /* Adjust coordinates to be root-window-relative. */ 1742 1783 pos.x = x; … … 1744 1785 ClientToScreen (FRAME_W32_WINDOW (f), &pos); 1745 1786 1787 /* Free the widget_value objects we used to specify the contents. */ 1788 free_menubar_widget_value_tree (first_wv); 1789 1746 1790 /* No selection has been chosen yet. */ 1747 1791 menu_item_selection = 0; … … 1756 1800 discard_mouse_events (); 1757 1801 1758 /* Free the widget_value objects we used to specify the contents. */1759 free_menubar_widget_value_tree (first_wv);1760 1761 1802 DestroyMenu (menu); 1762 1803 … … 1767 1808 Lisp_Object prefix, entry; 1768 1809 1769 prefix = entry =Qnil;1810 prefix = Qnil; 1770 1811 i = 0; 1771 1812 while (i < menu_items_used) … … 1835 1876 int menu_item_selection; 1836 1877 1837 widget_value *wv, * first_wv = 0, *prev_wv = 0;1878 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; 1838 1879 1839 1880 /* Number of elements seen so far, before boundary. */ … … 1873 1914 1874 1915 /* Create a new item within current pane. */ 1875 Lisp_Object item_name, enable, descrip, help; 1876 1916 Lisp_Object item_name, enable, descrip; 1877 1917 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME]; 1878 1918 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE]; 1879 1919 descrip 1880 1920 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY]; 1881 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];1882 1921 1883 1922 if (NILP (item_name)) … … 1943 1982 1944 1983 /* Actually create the dialog. */ 1945 #if def HAVE_DIALOGS1984 #if 0 1946 1985 dialog_id = widget_id_tick++; 1947 1986 menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv, 1948 1987 f->output_data.w32->widget, 1, 0, 1949 1988 dialog_selection_callback, 0); 1950 lw_modify_all_widgets (dialog_id, first_wv->contents, T RUE);1989 lw_modify_all_widgets (dialog_id, first_wv->contents, True); 1951 1990 #endif 1952 1991 … … 1958 1997 1959 1998 /* Display the menu. */ 1960 #if def HAVE_DIALOGS1999 #if 0 1961 2000 lw_pop_up_all_widgets (dialog_id); 1962 2001 popup_activated_flag = 1; … … 2014 2053 char *name; 2015 2054 { 2016 char *start = name; 2017 2018 /* Check if name string consists of only dashes ('-'). */ 2055 /* Check if name string consists of only dashes ('-') */ 2019 2056 while (*name == '-') name++; 2020 /* Separators can also be of the form "--:TripleSuperMegaEtched" 2021 or "--deep-shadow". We don't implement them yet, se we just treat 2022 them like normal separators. */ 2023 return (*name == '\0' || start + 2 == name); 2057 return (*name == '\0'); 2024 2058 } 2025 2059 … … 2037 2071 UINT fuFlags; 2038 2072 char *out_string; 2039 int return_value;2040 2073 2041 2074 if (name_is_separator (wv->name)) 2042 { 2043 fuFlags = MF_SEPARATOR; 2044 out_string = NULL; 2045 } 2075 fuFlags = MF_SEPARATOR; 2046 2076 else 2047 2077 { … … 2069 2099 fuFlags = MF_OWNERDRAW | MF_DISABLED; 2070 2100 } 2071 /* Draw radio buttons and tickboxes. */2072 else if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||2073 wv->button_type == BUTTON_TYPE_RADIO))2074 fuFlags |= MF_CHECKED;2075 else2076 fuFlags |= MF_UNCHECKED;2077 2101 } 2078 2102 … … 2080 2104 fuFlags = MF_POPUP; 2081 2105 2082 return_value = 2083 AppendMenu (menu, 2084 fuFlags, 2085 item != NULL ? (UINT) item : (UINT) wv->call_data, 2086 out_string ); 2087 2088 /* This must be done after the menu item is created. */ 2089 if ((fuFlags & MF_STRING) != 0) 2090 { 2091 HMODULE user32 = GetModuleHandle ("user32.dll"); 2092 FARPROC set_menu_item_info = GetProcAddress (user32, "SetMenuItemInfoA"); 2093 2094 if (set_menu_item_info) 2095 { 2096 MENUITEMINFO info; 2097 bzero (&info, sizeof (info)); 2098 info.cbSize = sizeof (info); 2099 info.fMask = MIIM_DATA; 2100 2101 /* Set help string for menu item. */ 2102 info.dwItemData = (DWORD)wv->help; 2103 2104 if (wv->button_type == BUTTON_TYPE_RADIO) 2105 { 2106 /* CheckMenuRadioItem allows us to differentiate TOGGLE and 2107 RADIO items, but is not available on NT 3.51 and earlier. */ 2108 info.fMask |= MIIM_TYPE | MIIM_STATE; 2109 info.fType = MFT_RADIOCHECK | MFT_STRING; 2110 info.dwTypeData = out_string; 2111 info.fState = wv->selected ? MFS_CHECKED : MFS_UNCHECKED; 2112 } 2113 2114 set_menu_item_info (menu, 2115 item != NULL ? (UINT) item : (UINT) wv->call_data, 2116 FALSE, &info); 2117 } 2118 } 2119 return return_value; 2106 return AppendMenu (menu, 2107 fuFlags, 2108 item != NULL ? (UINT) item : (UINT) wv->call_data, 2109 (fuFlags == MF_SEPARATOR) ? NULL: out_string ); 2120 2110 } 2121 2111 2122 2112 /* Construct native Windows menu(bar) based on widget_value tree. */ 2123 int2113 static int 2124 2114 fill_in_menu (HMENU menu, widget_value *wv) 2125 2115 { … … 2151 2141 } 2152 2142 2153 int2154 popup_activated ()2155 {2156 /* popup_activated_flag not actually used on W32 */2157 return 0;2158 }2159 2160 /* Display help string for currently pointed to menu item. Not2161 supported on NT 3.51 and earlier, as GetMenuItemInfo is not2162 available. */2163 void2164 w32_menu_display_help (HMENU menu, UINT item, UINT flags)2165 {2166 int pane = 0; /* TODO: Set this to pane number. */2167 2168 HMODULE user32 = GetModuleHandle ("user32.dll");2169 FARPROC get_menu_item_info = GetProcAddress (user32, "GetMenuItemInfoA");2170 2171 if (get_menu_item_info)2172 {2173 extern Lisp_Object Qmenu_item;2174 Lisp_Object *first_item;2175 Lisp_Object pane_name;2176 Lisp_Object menu_object;2177 MENUITEMINFO info;2178 2179 bzero (&info, sizeof (info));2180 info.cbSize = sizeof (info);2181 info.fMask = MIIM_DATA;2182 get_menu_item_info (menu, item, FALSE, &info);2183 2184 first_item = XVECTOR (menu_items)->contents;2185 if (EQ (first_item[0], Qt))2186 pane_name = first_item[MENU_ITEMS_PANE_NAME];2187 else if (EQ (first_item[0], Qquote))2188 /* This shouldn't happen, see w32_menu_show. */2189 pane_name = build_string ("");2190 else2191 pane_name = first_item[MENU_ITEMS_ITEM_NAME];2192 2193 /* (menu-item MENU-NAME PANE-NUMBER) */2194 menu_object = Fcons (Qmenu_item,2195 Fcons (pane_name,2196 Fcons (make_number (pane), Qnil)));2197 2198 show_help_echo (info.dwItemData ?2199 build_string ((char *) info.dwItemData) : Qnil,2200 Qnil, menu_object, make_number (item), 1);2201 }2202 }2203 2204 2205 2206 2143 #endif /* HAVE_MENUS */ 2207 2144
