Mercurial > hg > xemacs-beta
diff src/menubar-msw.c @ 251:677f6a0ee643 r20-5b24
Import from CVS: tag r20-5b24
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:19:59 +0200 |
parents | 83b3d10dcba9 |
children | 157b30c96d03 |
line wrap: on
line diff
--- a/src/menubar-msw.c Mon Aug 13 10:19:12 2007 +0200 +++ b/src/menubar-msw.c Mon Aug 13 10:19:59 2007 +0200 @@ -101,303 +101,44 @@ /* Current menubar or popup hashtable. gcpro'ed */ static Lisp_Object current_hashtable; -/* Bound by menubar.el */ -static Lisp_Object Qfind_menu_item; - /* This is used to allocate unique ids to menu items. Items ids are in MENU_ITEM_ID_MIN to MENU_ITEM_ID_MAX. Allocation checks that the item is not already in the TOP_LEVEL_MENU */ -/* #### defines go to gui-msw.h */ + +/* #### defines go to gui-msw.h, as the range is shared with toolbars + (If only toolbars will be implemented as common controls) */ #define MENU_ITEM_ID_MIN 0x8000 #define MENU_ITEM_ID_MAX 0xFFFF #define MENU_ITEM_ID_BITS(x) ((x) & 0x7FFF | 0x8000) static HMENU top_level_menu; -/* ============= THIS STUFF MIGHT GO SOMEWHERE ELSE ================= */ - -/* All these functions are windows sys independent, and are candidates - to go to lisp code instead */ - -/* - * DESCRIPTOR is a list in the form ({:keyword value}+ rest...). - * This function extracts all the key-value pairs into the newly - * created plist, and returns pointer to REST. Original list is not - * modified (heaven save!) - */ -Lisp_Object -gui_parse_menu_keywords (Lisp_Object descriptor, Lisp_Object *plist) -{ - Lisp_Object pair, key, val; - *plist = Qnil; - LIST_LOOP (pair, descriptor) - { - if (!CONSP(pair)) - signal_simple_error ("Mailformed gui entity descriptor", descriptor); - key = XCAR(pair); - if (!KEYWORDP (key)) - return pair; - pair = XCDR (pair); - if (!CONSP(pair)) - signal_simple_error ("Mailformed gui entity descriptor", descriptor); - val = XCAR (pair); - internal_plist_put (plist, key, val); - } - return pair; -} - -/* - * DESC is a vector describing a menu item. The function returns menu - * item name in NAME, callback form in CALLBACK, and all key-values - * pairs in PLIST. For old-style vectors, the plist is faked. - */ -void -gui_parse_button_descriptor (Lisp_Object desc, Lisp_Object *name, - Lisp_Object *callback, Lisp_Object *plist) -{ - int length = XVECTOR_LENGTH (desc); - Lisp_Object *contents = XVECTOR_DATA (desc); - int plist_p; - - *name = Qnil; - *callback = Qnil; - *plist = Qnil; - - if (length < 3) - signal_simple_error ("Button descriptors must be at least 3 long", desc); - - /* length 3: [ "name" callback active-p ] - length 4: [ "name" callback active-p suffix ] - or [ "name" callback keyword value ] - length 5+: [ "name" callback [ keyword value ]+ ] - */ - plist_p = (length >= 5 || KEYWORDP (contents [2])); - - *name = contents [0]; - *callback = contents [1]; - - if (!plist_p) - /* the old way */ - { - internal_plist_put (plist, Q_active, contents [2]); - if (length == 4) - internal_plist_put (plist, Q_suffix, contents [3]); - } - else - /* the new way */ - { - int i; - if (length & 1) - signal_simple_error ( - "Button descriptor has an odd number of keywords and values", - desc); - - for (i = 2; i < length;) - { - Lisp_Object key = contents [i++]; - Lisp_Object val = contents [i++]; - if (!KEYWORDP (key)) - signal_simple_error_2 ("Not a keyword", key, desc); - internal_plist_put (plist, key, val); - } - } -} - -/* - * Given PLIST of key-value pairs for a menu item or button, consult - * :included and :config properties (the latter against - * CONFLIST). Return value is non-zero when item should *not* appear. - */ -int -gui_plist_says_item_excluded (Lisp_Object plist, Lisp_Object conflist) -{ - Lisp_Object tem; - /* This function can call lisp */ +#define MAX_MENUITEM_LENGTH 128 - /* Evaluate :included first */ - tem = internal_plist_get (plist, Q_included); - if (!UNBOUNDP (tem)) - { - tem = Feval (tem); - if (NILP (tem)) - return 1; - } - - /* Do :config if conflist is given */ - if (!NILP (conflist)) - { - tem = internal_plist_get (plist, Q_config); - if (!UNBOUNDP (tem)) - { - tem = Fmemq (tem, conflist); - if (NILP (tem)) - return 1; - } - } - - return 0; -} - -/* - * Given PLIST of key-value pairs for a menu item or button, consult - * :active property. Return non-zero if the item is *inactive* - */ -int -gui_plist_says_item_inactive (Lisp_Object plist) -{ - Lisp_Object tem; - /* This function can call lisp */ - - tem = internal_plist_get (plist, Q_active); - if (!UNBOUNDP (tem)) - { - tem = Feval (tem); - if (NILP (tem)) - return 1; - } - - return 0; -} - -/* - * Given PLIST of key-value pairs for a menu item or button, evaluate - * the form which is the value of :filter property. Filter function - * given DESC as argument. If there's no :filter property, DESC is - * returned, otherwise the value returned by the filter function is - * returned. - */ -Lisp_Object -gui_plist_apply_filter (Lisp_Object plist, Lisp_Object desc) -{ - Lisp_Object tem; - /* This function can call lisp */ - - tem = internal_plist_get (plist, Q_filter); - if (UNBOUNDP (tem)) - return desc; - else - return call1 (tem, desc); -} - -/* - * This is tricky because there's no menu item styles in Windows, only - * states: Each item may be given no checkmark, radio or check - * mark. This function returns required mark style as determined by - * PLIST. Return value is the value of :style property if the item is - * :seleted, or nil otherwise - */ -Lisp_Object -gui_plist_get_current_style (Lisp_Object plist) -{ - Lisp_Object style, selected; - style = internal_plist_get (plist, Q_style); - if (UNBOUNDP (style) || NILP(style)) - return Qnil; - - selected = internal_plist_get (plist, Q_selected); - if (UNBOUNDP (selected) || NILP(Feval(selected))) - return Qnil; - - return style; -} - -Lisp_Object -current_frame_menubar (CONST struct frame* f) -{ - struct window *w = XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f)); - return symbol_value_in_buffer (Qcurrent_menubar, w->buffer); -} - -/* ============ END IF STUFF THAT MIGHT GO SOMEWHERE ELSE =============== */ - -/* Change these together */ -#define MAX_MENUITEM_LENGTH 128 -#define DISPLAYABLE_MAX_MENUITEM_LENGTH "128" - -static void -signal_item_too_long (Lisp_Object name) -{ - signal_simple_error ("Menu item is longer than " - DISPLAYABLE_MAX_MENUITEM_LENGTH - " characters", name); -} - -/* #### If this function returned (FLUSHLEFT . FLUSHRIGHT) it also - could be moved above that line - it becomes window system - independant */ /* * This returns Windows-style menu item string: * "Left Flush\tRight Flush" */ -static CONST char* -plist_get_menu_item_name (Lisp_Object name, Lisp_Object callback, Lisp_Object plist) +static char* +displayable_menu_item (struct gui_item* pgui_item) { /* We construct the name in a static buffer. That's fine, beause menu items longer than 128 chars are probably programming errors, and better be caught than displayed! */ - static char buf[MAX_MENUITEM_LENGTH]; - char* p = buf; - int buf_left = MAX_MENUITEM_LENGTH - 1; - Lisp_Object tem; - - /* Get name first */ - buf_left -= XSTRING_LENGTH (name); - if (buf_left < 0) - signal_item_too_long (name); - strcpy (p, XSTRING_DATA (name)); - p += XSTRING_LENGTH (name); + static char buf[MAX_MENUITEM_LENGTH+2]; + unsigned int ll, lr; - /* Have suffix? */ - tem = internal_plist_get (plist, Q_suffix); - if (!UNBOUNDP (tem)) - { - if (!STRINGP (tem)) - signal_simple_error (":suffix must be a string", tem); - buf_left -= XSTRING_LENGTH (tem) + 1; - if (buf_left < 0) - signal_item_too_long (name); - *p++ = ' '; - strcpy (p, XSTRING_DATA (tem)); - p += XSTRING_LENGTH (tem); - } + /* Left flush part of the string */ + ll = gui_item_display_flush_left (pgui_item, buf, MAX_MENUITEM_LENGTH); - /* Have keys? */ - if (menubar_show_keybindings) - { - static char buf2 [1024]; - buf2[0] = 0; + /* Right flush part */ + assert (MAX_MENUITEM_LENGTH > ll + 1); + lr = gui_item_display_flush_right (pgui_item, buf + ll + 1, + MAX_MENUITEM_LENGTH - ll - 1); + if (lr) + buf [ll] = '\t'; - tem = internal_plist_get (plist, Q_keys); - if (!UNBOUNDP (tem)) - { - if (!STRINGP (tem)) - signal_simple_error (":keys must be a string", tem); - if (XSTRING_LENGTH (tem) > sizeof (buf2) - 1) - signal_item_too_long (name); - strcpy (buf2, XSTRING_DATA (tem)); - } - else if (SYMBOLP (callback)) - { - /* #### Warning, dependency here on current_buffer and point */ - /* #### I've borrowed this warning along with this code from - menubar-x.c. What does that mean? -- kkm */ - where_is_to_char (callback, buf2); - } - - if (buf2 [0]) - { - int n = strlen (buf2) + 1; - buf_left -= n; - if (buf_left < 0) - signal_item_too_long (name); - *p++ = '\t'; - strcpy (p, buf2); - p += n-1; - } - } - - *p = 0; return buf; } @@ -416,10 +157,11 @@ * the hashtable rather than abandon it. */ static Lisp_Object -allocate_menu_item_id (Lisp_Object path, Lisp_Object name) +allocate_menu_item_id (Lisp_Object path, Lisp_Object name, Lisp_Object suffix) { - UINT id = MENU_ITEM_ID_BITS (HASH2 (internal_hash (path, 0), - internal_hash (name, 0))); + UINT id = MENU_ITEM_ID_BITS (HASH3 (internal_hash (path, 0), + internal_hash (name, 0), + internal_hash (suffix, 0))); do { id = MENU_ITEM_ID_BITS (id + 1); } while (GetMenuState (top_level_menu, id, MF_BYCOMMAND) != 0xFFFFFFFF); @@ -429,12 +171,7 @@ static HMENU create_empty_popup_menu (void) { - HMENU submenu = CreatePopupMenu (); - /* #### It seems that really we do not need "(empty)" at this stage */ -#if 0 - AppendMenu (submenu, MF_STRING | MF_GRAYED, EMPTY_ITEM_ID, EMPTY_ITEM_NAME); -#endif - return submenu; + return CreatePopupMenu (); } static void @@ -473,10 +210,8 @@ else if (VECTORP (item)) { /* An ordinary item - hash its name and callback form. */ - Lisp_Object plist, name, callback; - gui_parse_button_descriptor (item, &name, &callback, &plist); - return HASH2 (internal_hash (name, 0), - internal_hash (callback, 0)); + return HASH2 (internal_hash (XVECTOR_DATA(item)[0], 0), + internal_hash (XVECTOR_DATA(item)[1], 0)); } /* An error - will be caught later */ @@ -488,7 +223,6 @@ Lisp_Object hash_tab, Lisp_Object item, int flush_right) { MENUITEMINFO item_info; - struct gcpro gcpro1, gcpro2; item_info.cbSize = sizeof (item_info); item_info.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID; @@ -511,20 +245,23 @@ else if (CONSP (item)) { /* Submenu */ - Lisp_Object subname = XCAR (item); - Lisp_Object plist; HMENU submenu; - - if (!STRINGP (subname)) + struct gui_item gui_item; + struct gcpro gcpro1; + + gui_item_init (&gui_item); + GCPRO1 (gui_item); + gcpro1.nvars = GUI_ITEM_GCPRO_COUNT; + + menu_parse_submenu_keywords (item, &gui_item); + + if (!STRINGP (gui_item.name)) signal_simple_error ("Menu name (first element) must be a string", item); - item = gui_parse_menu_keywords (XCDR (item), &plist); - GCPRO1 (plist); - - if (gui_plist_says_item_excluded (plist, Vmenubar_configuration)) + if (!gui_item_included_p (&gui_item, Vmenubar_configuration)) return; - if (gui_plist_says_item_inactive (plist)) + if (!gui_item_active_p (&gui_item)) item_info.fState = MFS_GRAYED; /* Temptation is to put 'else' right here. Although, the displayed item won't have an arrow indicating that it is a @@ -532,46 +269,50 @@ submenu = create_empty_popup_menu(); item_info.fMask |= MIIM_SUBMENU; - item_info.dwTypeData = plist_get_menu_item_name (subname, Qnil, plist); + item_info.dwTypeData = displayable_menu_item (&gui_item); item_info.hSubMenu = submenu; - UNGCPRO; /* plist */ - if (!(item_info.fState & MFS_GRAYED)) { /* Now add the full submenu path as a value to the hash table, keyed by menu handle */ if (NILP(path)) - path = list1 (subname); - else { - Lisp_Object arg[2]; - arg[0] = path; - arg[1] = list1 (subname); - GCPRO1 (arg[1]); - path = Fappend (2, arg); - UNGCPRO; /* arg[1] */ - } + /* list1 cannot GC */ + path = list1 (gui_item.name); + else + { + Lisp_Object arg[2] = { path, list1 (gui_item.name) }; + /* Fappend gcpro'es its arg */ + path = Fappend (2, arg); + } - GCPRO1 (path); + /* Fputhash GCPRO'es PATH */ Fputhash (hmenu_to_lisp_object (submenu), path, hash_tab); - UNGCPRO; /* path */ } + UNGCPRO; /* gui_item */ } else if (VECTORP (item)) { /* An ordinary item */ - Lisp_Object plist, name, callback, style, id; - - gui_parse_button_descriptor (item, &name, &callback, &plist); - GCPRO2 (plist, callback); + Lisp_Object style, id; + struct gui_item gui_item; + struct gcpro gcpro1; - if (gui_plist_says_item_excluded (plist, Vmenubar_configuration)) + gui_item_init (&gui_item); + GCPRO1 (gui_item); + gcpro1.nvars = GUI_ITEM_GCPRO_COUNT; + + gui_parse_item_keywords (item, &gui_item); + + if (!gui_item_included_p (&gui_item, Vmenubar_configuration)) return; - if (gui_plist_says_item_inactive (plist)) - item_info.fState |= MFS_GRAYED; + if (!gui_item_active_p (&gui_item)) + item_info.fState = MFS_GRAYED; - style = gui_plist_get_current_style (plist); + style = (NILP (gui_item.selected) || NILP (Feval (gui_item.selected)) + ? Qnil : gui_item.style); + if (EQ (style, Qradio)) { item_info.fType |= MFT_RADIOCHECK; @@ -582,18 +323,19 @@ item_info.fState |= MFS_CHECKED; } - id = allocate_menu_item_id (path, name); - Fputhash (id, callback, hash_tab); - - UNGCPRO; /* plist, callback */ + id = allocate_menu_item_id (path, gui_item.name, + gui_item.suffix); + Fputhash (id, gui_item.callback, hash_tab); item_info.wID = (UINT) XINT(id); item_info.fType |= MFT_STRING; - item_info.dwTypeData = plist_get_menu_item_name (name, callback, plist); + item_info.dwTypeData = displayable_menu_item (&gui_item); + + UNGCPRO; /* gui_item */ } else { - signal_simple_error ("Ill-constructed menu descriptor", item); + signal_simple_error ("Mailformed menu item descriptor", item); } if (flush_right) @@ -614,13 +356,18 @@ * Return value is the menu checksum. */ static unsigned long -populate_or_checksum_helper (HMENU menu, Lisp_Object path, Lisp_Object descriptor, +populate_or_checksum_helper (HMENU menu, Lisp_Object path, Lisp_Object desc, Lisp_Object hash_tab, int bar_p, int populate_p) { - Lisp_Object menu_name, plist, item_desc; + Lisp_Object item_desc; int deep_p, flush_right; struct gcpro gcpro1; unsigned long checksum = 0; + struct gui_item gui_item; + + gui_item_init (&gui_item); + GCPRO1 (gui_item); + gcpro1.nvars = GUI_ITEM_GCPRO_COUNT; /* Will initially contain only "(empty)" */ if (populate_p) @@ -629,33 +376,20 @@ /* PATH set to nil indicates top-level popup or menubar */ deep_p = !NILP (path); - if (!deep_p) - top_level_menu = menu; + /* Fetch keywords prepending the item list */ + desc = menu_parse_submenu_keywords (desc, &gui_item); - if (!CONSP(descriptor)) - signal_simple_error ("Menu descriptor must be a list", descriptor); + /* Check that menu name is specified when expected */ + if (NILP (gui_item.name) && deep_p) + signal_simple_error ("Menu must have a name", desc); - if (STRINGP (XCAR (descriptor))) - { - menu_name = XCAR (descriptor); - descriptor = XCDR (descriptor); - } - else - { - menu_name = Qnil; - if (deep_p) /* Not a popup or bar */ - signal_simple_error ("Menu must have a name", descriptor); - } + /* Apply filter if specified */ + if (!NILP (gui_item.filter)) + desc = call1 (gui_item.filter, desc); - /* Fetch keywords prepending the item list */ - descriptor = gui_parse_menu_keywords (descriptor, &plist); - GCPRO1 (plist); - descriptor = gui_plist_apply_filter (plist, descriptor); - UNGCPRO; /* plist */ - - /* Loop thru the descriptor's CDR and add items for each entry */ + /* Loop thru the desc's CDR and add items for each entry */ flush_right = 0; - EXTERNAL_LIST_LOOP (item_desc, descriptor) + EXTERNAL_LIST_LOOP (item_desc, desc) { if (NILP (XCAR (item_desc))) { @@ -681,47 +415,30 @@ /* Add the header to the popup, if told so. The same as in X - an insensitive item, and a separator (Seems to me, there were two separators in X... In Windows this looks ugly, anywats. */ - if (!bar_p && !deep_p && popup_menu_titles && !NILP(menu_name)) + if (!bar_p && !deep_p && popup_menu_titles && !NILP(gui_item.name)) { + CHECK_STRING (gui_item.name); InsertMenu (menu, 0, MF_BYPOSITION | MF_STRING | MF_DISABLED, - 0, XSTRING_DATA(menu_name)); + 0, XSTRING_DATA(gui_item.name)); InsertMenu (menu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); SetMenuDefaultItem (menu, 0, MF_BYPOSITION); } } + UNGCPRO; /* gui_item */ return checksum; } static void -populate_menu (HMENU menu, Lisp_Object path, Lisp_Object descriptor, +populate_menu (HMENU menu, Lisp_Object path, Lisp_Object desc, Lisp_Object hash_tab, int bar_p) { - populate_or_checksum_helper (menu, path, descriptor, hash_tab, bar_p, 1); + populate_or_checksum_helper (menu, path, desc, hash_tab, bar_p, 1); } static unsigned long -checksum_menu (Lisp_Object descriptor) -{ - return populate_or_checksum_helper (NULL, Qnil, descriptor, Qunbound, 0, 0); -} - -static Lisp_Object -find_menu (Lisp_Object desc, Lisp_Object path) +checksum_menu (Lisp_Object desc) { - /* #### find-menu-item is not what's required here. - Need to write this in C, or improve lisp */ - if (!NILP (path)) - { - desc = call2 (Qfind_menu_item, desc, path); - /* desc is (supposed to be) (ITEM . PARENT). Supposed - to signal but sometimes manages to return nil */ - if (!NILP(desc)) - { - CHECK_CONS (desc); - desc = XCAR (desc); - } - } - return desc; + return populate_or_checksum_helper (NULL, Qnil, desc, Qunbound, 0, 0); } static void @@ -733,6 +450,8 @@ ? symbol_value_in_buffer (Qcurrent_menubar, w->buffer) : Qnil); + top_level_menu = menubar; + if (NILP (desc) && menubar != NULL) { /* Menubar has gone */ @@ -842,13 +561,9 @@ /* Now find a desc chunk for it. If none, then probably menu open hook has played too much games around stuff */ - desc = current_menudesc; - if (!NILP (path)) - { - desc = find_menu (desc, path); - if (NILP (desc)) - signal_simple_error ("This menu does not exist any more", path); - } + desc = Fmenu_find_real_submenu (current_menudesc, path); + if (NILP (desc)) + signal_simple_error ("This menu does not exist any more", path); /* Now, stuff it */ /* DESC may be generated by filter, so we have to gcpro it */ @@ -862,6 +577,10 @@ unsafe_handle_wm_initmenu_1 (struct frame* f) { /* This function can call lisp */ + + /* NOTE: This is called for the bar only, WM_INITMENU + for popups is filtered out */ + /* #### - this menubar update mechanism is expensively anti-social and the activate-menubar-hook is now mostly obsolete. */ @@ -878,20 +597,6 @@ return Qt; } -#ifdef KKM_DOES_NOT_LIKE_UNDOCS_SOMETIMES - -/* #### This may become wrong in future Windows */ - -static Lisp_Object -unsafe_handle_wm_exitmenuloop_1 (struct frame* f) -{ - if (!NILP (current_tracking_popup)) - prune_menubar (f); - return Qt; -} - -#endif - /* * Return value is Qt if we have dispatched the command, * or Qnil if id has not been mapped to a callback. @@ -924,7 +629,8 @@ else if (CONSP (command)) funcsym = Qeval; else - signal_simple_error ("Illegal callback", command); + signal_simple_error ("Callback must be either evallable form or a symbol", + command); XSETFRAME (frame, f); enqueue_misc_user_event (frame, funcsym, command); @@ -959,14 +665,6 @@ return unsafe_handle_wm_initmenu_1 (wm_initmenu_frame); } -#ifdef KKM_DOES_NOT_LIKE_UNDOCS_SOMETIMES -static Lisp_Object -unsafe_handle_wm_exitmenuloop (Lisp_Object u_n_u_s_e_d) -{ - return unsafe_handle_wm_exitmenuloop_1 (wm_initmenu_frame); -} -#endif - Lisp_Object mswindows_handle_wm_initmenupopup (HMENU hmenu, struct frame* frm) { @@ -988,15 +686,12 @@ return Qt; } +/* #### This function goes away. Removing it now may + interfere with pending patch 980128-jhar */ Lisp_Object mswindows_handle_wm_exitmenuloop (struct frame* f) { -#ifdef KKM_DOES_NOT_LIKE_UNDOCS_SOMETIMES - wm_initmenu_frame = f; - return mswindows_protect_modal_loop (unsafe_handle_wm_exitmenuloop, Qnil); -#else return Qt; -#endif } @@ -1007,7 +702,13 @@ static void mswindows_update_frame_menubars (struct frame* f) { - update_frame_menubar_maybe (f); + /* #### KLUDGE. menubar.c calls us when the following + condition is true: + (f->menubar_changed || f->windows_changed) + Is that much really necessary? + */ + if (f->menubar_changed) + update_frame_menubar_maybe (f); } static void @@ -1060,6 +761,7 @@ current_hashtable = Fmake_hashtable (make_int(10), Qequal); menu = create_empty_popup_menu(); Fputhash (hmenu_to_lisp_object (menu), Qnil, current_hashtable); + top_level_menu = menu; ok = TrackPopupMenu (menu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, @@ -1086,7 +788,6 @@ void syms_of_menubar_mswindows (void) { - defsymbol (&Qfind_menu_item, "find-menu-item"); } void @@ -1106,5 +807,3 @@ staticpro (¤t_menudesc); staticpro (¤t_hashtable); - Fprovide (intern ("mswindows-menubars")); -}