diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/macmenu.c | 153 |
1 files changed, 121 insertions, 32 deletions
diff --git a/src/macmenu.c b/src/macmenu.c index e97a968d92d..77c66470c09 100644 --- a/src/macmenu.c +++ b/src/macmenu.c | |||
| @@ -1356,6 +1356,68 @@ update_submenu_strings (first_wv) | |||
| 1356 | } | 1356 | } |
| 1357 | 1357 | ||
| 1358 | 1358 | ||
| 1359 | /* Event handler function that pops down a menu on C-g. We can only pop | ||
| 1360 | down menus if CancelMenuTracking is present (OSX 10.3 or later). */ | ||
| 1361 | |||
| 1362 | #ifdef HAVE_CANCELMENUTRACKING | ||
| 1363 | static pascal OSStatus | ||
| 1364 | menu_quit_handler (nextHandler, theEvent, userData) | ||
| 1365 | EventHandlerCallRef nextHandler; | ||
| 1366 | EventRef theEvent; | ||
| 1367 | void* userData; | ||
| 1368 | { | ||
| 1369 | UInt32 keyCode; | ||
| 1370 | UInt32 keyModifiers; | ||
| 1371 | extern int mac_quit_char_modifiers; | ||
| 1372 | extern int mac_quit_char_keycode; | ||
| 1373 | |||
| 1374 | GetEventParameter (theEvent, kEventParamKeyCode, | ||
| 1375 | typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode); | ||
| 1376 | |||
| 1377 | GetEventParameter (theEvent, kEventParamKeyModifiers, | ||
| 1378 | typeUInt32, NULL, sizeof(UInt32), | ||
| 1379 | NULL, &keyModifiers); | ||
| 1380 | |||
| 1381 | if (keyCode == mac_quit_char_keycode | ||
| 1382 | && keyModifiers == mac_quit_char_modifiers) | ||
| 1383 | { | ||
| 1384 | MenuRef menu = userData != 0 | ||
| 1385 | ? (MenuRef)userData : AcquireRootMenu (); | ||
| 1386 | |||
| 1387 | CancelMenuTracking (menu, true, 0); | ||
| 1388 | if (!userData) ReleaseMenu (menu); | ||
| 1389 | return noErr; | ||
| 1390 | } | ||
| 1391 | |||
| 1392 | return CallNextEventHandler (nextHandler, theEvent); | ||
| 1393 | } | ||
| 1394 | #endif /* HAVE_CANCELMENUTRACKING */ | ||
| 1395 | |||
| 1396 | /* Add event handler for MENU_HANDLE so we can detect C-g. | ||
| 1397 | If MENU_HANDLE is NULL, install handler for all menus in the menu bar. | ||
| 1398 | If CancelMenuTracking isn't available, do nothing. */ | ||
| 1399 | |||
| 1400 | static void | ||
| 1401 | install_menu_quit_handler (MenuHandle menu_handle) | ||
| 1402 | { | ||
| 1403 | #ifdef HAVE_CANCELMENUTRACKING | ||
| 1404 | EventHandlerUPP handler = NewEventHandlerUPP(menu_quit_handler); | ||
| 1405 | UInt32 numTypes = 1; | ||
| 1406 | EventTypeSpec typesList[] = { { kEventClassKeyboard, kEventRawKeyDown } }; | ||
| 1407 | int i = MIN_MENU_ID; | ||
| 1408 | MenuHandle menu = menu_handle ? menu_handle : GetMenuHandle (i); | ||
| 1409 | |||
| 1410 | while (menu != NULL) | ||
| 1411 | { | ||
| 1412 | InstallMenuEventHandler (menu, handler, GetEventTypeCount (typesList), | ||
| 1413 | typesList, menu_handle, NULL); | ||
| 1414 | if (menu_handle) break; | ||
| 1415 | menu = GetMenuHandle (++i); | ||
| 1416 | } | ||
| 1417 | DisposeEventHandlerUPP (handler); | ||
| 1418 | #endif /* HAVE_CANCELMENUTRACKING */ | ||
| 1419 | } | ||
| 1420 | |||
| 1359 | /* Set the contents of the menubar widgets of frame F. | 1421 | /* Set the contents of the menubar widgets of frame F. |
| 1360 | The argument FIRST_TIME is currently ignored; | 1422 | The argument FIRST_TIME is currently ignored; |
| 1361 | it is set the first time this is called, from initialize_frame_menubar. */ | 1423 | it is set the first time this is called, from initialize_frame_menubar. */ |
| @@ -1575,6 +1637,8 @@ set_frame_menubar (f, first_time, deep_p) | |||
| 1575 | 1637 | ||
| 1576 | DrawMenuBar (); | 1638 | DrawMenuBar (); |
| 1577 | 1639 | ||
| 1640 | /* Add event handler so we can detect C-g. */ | ||
| 1641 | install_menu_quit_handler (NULL); | ||
| 1578 | free_menubar_widget_value_tree (first_wv); | 1642 | free_menubar_widget_value_tree (first_wv); |
| 1579 | 1643 | ||
| 1580 | UNBLOCK_INPUT; | 1644 | UNBLOCK_INPUT; |
| @@ -1606,7 +1670,43 @@ free_frame_menubar (f) | |||
| 1606 | } | 1670 | } |
| 1607 | 1671 | ||
| 1608 | 1672 | ||
| 1609 | /* mac_menu_show actually displays a menu using the panes and items in | 1673 | static Lisp_Object |
| 1674 | pop_down_menu (arg) | ||
| 1675 | Lisp_Object arg; | ||
| 1676 | { | ||
| 1677 | struct Lisp_Save_Value *p1 = XSAVE_VALUE (Fcar (arg)); | ||
| 1678 | struct Lisp_Save_Value *p2 = XSAVE_VALUE (Fcdr (arg)); | ||
| 1679 | |||
| 1680 | FRAME_PTR f = p1->pointer; | ||
| 1681 | MenuHandle *menu = p2->pointer; | ||
| 1682 | |||
| 1683 | BLOCK_INPUT; | ||
| 1684 | |||
| 1685 | /* Must reset this manually because the button release event is not | ||
| 1686 | passed to Emacs event loop. */ | ||
| 1687 | FRAME_MAC_DISPLAY_INFO (f)->grabbed = 0; | ||
| 1688 | |||
| 1689 | /* delete all menus */ | ||
| 1690 | { | ||
| 1691 | int i = MIN_POPUP_SUBMENU_ID; | ||
| 1692 | MenuHandle submenu = GetMenuHandle (i); | ||
| 1693 | while (submenu != NULL) | ||
| 1694 | { | ||
| 1695 | DeleteMenu (i); | ||
| 1696 | DisposeMenu (submenu); | ||
| 1697 | submenu = GetMenuHandle (++i); | ||
| 1698 | } | ||
| 1699 | } | ||
| 1700 | |||
| 1701 | DeleteMenu (POPUP_SUBMENU_ID); | ||
| 1702 | DisposeMenu (*menu); | ||
| 1703 | |||
| 1704 | UNBLOCK_INPUT; | ||
| 1705 | |||
| 1706 | return Qnil; | ||
| 1707 | } | ||
| 1708 | |||
| 1709 | /* Mac_menu_show actually displays a menu using the panes and items in | ||
| 1610 | menu_items and returns the value selected from it; we assume input | 1710 | menu_items and returns the value selected from it; we assume input |
| 1611 | is blocked by the caller. */ | 1711 | is blocked by the caller. */ |
| 1612 | 1712 | ||
| @@ -1644,6 +1744,7 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error) | |||
| 1644 | = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object)); | 1744 | = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object)); |
| 1645 | int submenu_depth = 0; | 1745 | int submenu_depth = 0; |
| 1646 | int first_pane; | 1746 | int first_pane; |
| 1747 | int specpdl_count = SPECPDL_INDEX (); | ||
| 1647 | 1748 | ||
| 1648 | *error = NULL; | 1749 | *error = NULL; |
| 1649 | 1750 | ||
| @@ -1817,7 +1918,7 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error) | |||
| 1817 | title = ENCODE_MENU_STRING (title); | 1918 | title = ENCODE_MENU_STRING (title); |
| 1818 | #endif | 1919 | #endif |
| 1819 | wv_title->name = (char *) SDATA (title); | 1920 | wv_title->name = (char *) SDATA (title); |
| 1820 | wv_title->enabled = TRUE; | 1921 | wv_title->enabled = FALSE; |
| 1821 | wv_title->title = TRUE; | 1922 | wv_title->title = TRUE; |
| 1822 | wv_title->button_type = BUTTON_TYPE_NONE; | 1923 | wv_title->button_type = BUTTON_TYPE_NONE; |
| 1823 | wv_title->help = Qnil; | 1924 | wv_title->help = Qnil; |
| @@ -1830,6 +1931,10 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error) | |||
| 1830 | submenu_id = MIN_POPUP_SUBMENU_ID; | 1931 | submenu_id = MIN_POPUP_SUBMENU_ID; |
| 1831 | fill_submenu (menu, first_wv->contents); | 1932 | fill_submenu (menu, first_wv->contents); |
| 1832 | 1933 | ||
| 1934 | /* Free the widget_value objects we used to specify the | ||
| 1935 | contents. */ | ||
| 1936 | free_menubar_widget_value_tree (first_wv); | ||
| 1937 | |||
| 1833 | /* Adjust coordinates to be root-window-relative. */ | 1938 | /* Adjust coordinates to be root-window-relative. */ |
| 1834 | pos.h = x; | 1939 | pos.h = x; |
| 1835 | pos.v = y; | 1940 | pos.v = y; |
| @@ -1844,11 +1949,18 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error) | |||
| 1844 | 1949 | ||
| 1845 | InsertMenu (menu, -1); | 1950 | InsertMenu (menu, -1); |
| 1846 | 1951 | ||
| 1952 | record_unwind_protect (pop_down_menu, | ||
| 1953 | Fcons (make_save_value (f, 0), | ||
| 1954 | make_save_value (&menu, 0))); | ||
| 1955 | |||
| 1956 | /* Add event handler so we can detect C-g. */ | ||
| 1957 | install_menu_quit_handler (menu); | ||
| 1958 | |||
| 1847 | /* Display the menu. */ | 1959 | /* Display the menu. */ |
| 1848 | menu_item_choice = PopUpMenuSelect (menu, pos.v, pos.h, 0); | 1960 | menu_item_choice = PopUpMenuSelect (menu, pos.v, pos.h, 0); |
| 1849 | menu_item_selection = LoWord (menu_item_choice); | 1961 | menu_item_selection = LoWord (menu_item_choice); |
| 1850 | 1962 | ||
| 1851 | /* Get the refcon to find the correct item*/ | 1963 | /* Get the refcon to find the correct item */ |
| 1852 | if (menu_item_selection) | 1964 | if (menu_item_selection) |
| 1853 | { | 1965 | { |
| 1854 | MenuHandle sel_menu = GetMenuHandle (HiWord (menu_item_choice)); | 1966 | MenuHandle sel_menu = GetMenuHandle (HiWord (menu_item_choice)); |
| @@ -1856,35 +1968,10 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error) | |||
| 1856 | GetMenuItemRefCon (sel_menu, menu_item_selection, &refcon); | 1968 | GetMenuItemRefCon (sel_menu, menu_item_selection, &refcon); |
| 1857 | } | 1969 | } |
| 1858 | } | 1970 | } |
| 1859 | 1971 | else if (! for_click) | |
| 1860 | #if 0 | 1972 | /* Make "Cancel" equivalent to C-g unless this menu was popped up by |
| 1861 | /* Clean up extraneous mouse events which might have been generated | 1973 | a mouse press. */ |
| 1862 | during the call. */ | 1974 | Fsignal (Qquit, Qnil); |
| 1863 | discard_mouse_events (); | ||
| 1864 | #endif | ||
| 1865 | |||
| 1866 | /* Must reset this manually because the button release event is not | ||
| 1867 | passed to Emacs event loop. */ | ||
| 1868 | FRAME_MAC_DISPLAY_INFO (f)->grabbed = 0; | ||
| 1869 | |||
| 1870 | /* Free the widget_value objects we used to specify the | ||
| 1871 | contents. */ | ||
| 1872 | free_menubar_widget_value_tree (first_wv); | ||
| 1873 | |||
| 1874 | /* delete all menus */ | ||
| 1875 | { | ||
| 1876 | int i = MIN_POPUP_SUBMENU_ID; | ||
| 1877 | MenuHandle submenu = GetMenuHandle (i); | ||
| 1878 | while (submenu != NULL) | ||
| 1879 | { | ||
| 1880 | DeleteMenu (i); | ||
| 1881 | DisposeMenu (submenu); | ||
| 1882 | submenu = GetMenuHandle (++i); | ||
| 1883 | } | ||
| 1884 | } | ||
| 1885 | |||
| 1886 | DeleteMenu (POPUP_SUBMENU_ID); | ||
| 1887 | DisposeMenu (menu); | ||
| 1888 | 1975 | ||
| 1889 | /* Find the selected item, and its pane, to return | 1976 | /* Find the selected item, and its pane, to return |
| 1890 | the proper value. */ | 1977 | the proper value. */ |
| @@ -1944,6 +2031,8 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error) | |||
| 1944 | /* Make "Cancel" equivalent to C-g. */ | 2031 | /* Make "Cancel" equivalent to C-g. */ |
| 1945 | Fsignal (Qquit, Qnil); | 2032 | Fsignal (Qquit, Qnil); |
| 1946 | 2033 | ||
| 2034 | unbind_to (specpdl_count, Qnil); | ||
| 2035 | |||
| 1947 | return Qnil; | 2036 | return Qnil; |
| 1948 | } | 2037 | } |
| 1949 | 2038 | ||