diff options
| author | Fred Pierresteguy | 1994-03-11 18:01:00 +0000 |
|---|---|---|
| committer | Fred Pierresteguy | 1994-03-11 18:01:00 +0000 |
| commit | 165e1749b20e7caf149c725db3737a275c3d3170 (patch) | |
| tree | 429132b965c00217df074176a4b5aefe3860ee69 /src | |
| parent | ce5a08a1b46e9d059ed7271f9cdbeaf337b30ff9 (diff) | |
| download | emacs-165e1749b20e7caf149c725db3737a275c3d3170.tar.gz emacs-165e1749b20e7caf149c725db3737a275c3d3170.zip | |
(xdialog_show): New function to handle the display of dialog boxes.
(Fx_popup_dialog): New function.
(dialog_selection_callback): New function.
(xmenu_show) [USE_X_TOOLKIT]: Don't call lw_destroy_all_widgets at the end.
Do the work of construct_mouse_click in the ButtonRelease case.
Diffstat (limited to 'src')
| -rw-r--r-- | src/xmenu.c | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/src/xmenu.c b/src/xmenu.c index eb9122b2d06..43811e751b7 100644 --- a/src/xmenu.c +++ b/src/xmenu.c | |||
| @@ -94,6 +94,7 @@ extern void process_expose_from_menu (); | |||
| 94 | extern XtAppContext Xt_app_con; | 94 | extern XtAppContext Xt_app_con; |
| 95 | 95 | ||
| 96 | static int string_width (); | 96 | static int string_width (); |
| 97 | static Lisp_Object xdialog_show (); | ||
| 97 | #endif | 98 | #endif |
| 98 | 99 | ||
| 99 | static Lisp_Object xmenu_show (); | 100 | static Lisp_Object xmenu_show (); |
| @@ -826,6 +827,133 @@ cached information about equivalent key sequences.") | |||
| 826 | if (error_name) error (error_name); | 827 | if (error_name) error (error_name); |
| 827 | return selection; | 828 | return selection; |
| 828 | } | 829 | } |
| 830 | |||
| 831 | DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 1, 2, 0, | ||
| 832 | "Pop up a dialog box and return user's selection.\n\ | ||
| 833 | POSITION is a position specification. This is either a mouse button event\n\ | ||
| 834 | or a list ((XOFFSET YOFFSET) WINDOW)\n\ | ||
| 835 | where XOFFSET and YOFFSET are positions in characters from the top left\n\ | ||
| 836 | corner of WINDOW's frame. (WINDOW may be a frame object instead of a window.)\n\ | ||
| 837 | This controls the position of the center of the first line\n\ | ||
| 838 | in the first pane of the menu, not the top left of the menu as a whole.\n\ | ||
| 839 | If POSITION is t, it means to use the current mouse position.\n\ | ||
| 840 | \n\ | ||
| 841 | MENU is a specifier for a menu. For the simplest case, MENU is a keymap.\n\ | ||
| 842 | The menu items come from key bindings that have a menu string as well as\n\ | ||
| 843 | a definition; actually, the \"definition\" in such a key binding looks like\n\ | ||
| 844 | \(STRING . REAL-DEFINITION). To give the menu a title, put a string into\n\ | ||
| 845 | the keymap as a top-level element.\n\n\ | ||
| 846 | You can also use a list of keymaps as MENU.\n\ | ||
| 847 | Then each keymap makes a separate pane.\n\ | ||
| 848 | When MENU is a keymap or a list of keymaps, the return value\n\ | ||
| 849 | is a list of events.\n\n\ | ||
| 850 | Alternatively, you can specify a menu of multiple panes\n\ | ||
| 851 | with a list of the form (TITLE PANE1 PANE2...),\n\ | ||
| 852 | where each pane is a list of form (TITLE ITEM1 ITEM2...).\n\ | ||
| 853 | Each ITEM is normally a cons cell (STRING . VALUE);\n\ | ||
| 854 | but a string can appear as an item--that makes a nonselectable line\n\ | ||
| 855 | in the menu.\n\ | ||
| 856 | With this form of menu, the return value is VALUE from the chosen item.\n\ | ||
| 857 | \n\ | ||
| 858 | If POSITION is nil, don't display the menu at all, just precalculate the\n\ | ||
| 859 | cached information about equivalent key sequences.") | ||
| 860 | (position, menu) | ||
| 861 | Lisp_Object position, menu; | ||
| 862 | { | ||
| 863 | int number_of_panes, panes; | ||
| 864 | Lisp_Object keymap, tem; | ||
| 865 | int xpos, ypos; | ||
| 866 | Lisp_Object title; | ||
| 867 | char *error_name; | ||
| 868 | Lisp_Object selection; | ||
| 869 | int i, j; | ||
| 870 | FRAME_PTR f; | ||
| 871 | Lisp_Object x, y, window; | ||
| 872 | int keymaps = 0; | ||
| 873 | int menubarp = 0; | ||
| 874 | struct gcpro gcpro1; | ||
| 875 | |||
| 876 | check_x (); | ||
| 877 | |||
| 878 | if (! NILP (position)) | ||
| 879 | { | ||
| 880 | /* Decode the first argument: find the window and the coordinates. */ | ||
| 881 | if (EQ (position, Qt)) | ||
| 882 | { | ||
| 883 | /* Use the mouse's current position. */ | ||
| 884 | FRAME_PTR new_f; | ||
| 885 | Lisp_Object bar_window; | ||
| 886 | int part; | ||
| 887 | unsigned long time; | ||
| 888 | |||
| 889 | (*mouse_position_hook) (&new_f, &bar_window, &part, &x, &y, &time); | ||
| 890 | XSET (window, Lisp_Frame, new_f); | ||
| 891 | } | ||
| 892 | |||
| 893 | CHECK_NUMBER (x, 0); | ||
| 894 | CHECK_NUMBER (y, 0); | ||
| 895 | |||
| 896 | /* Decode where to put the menu. */ | ||
| 897 | |||
| 898 | if (XTYPE (window) == Lisp_Frame) | ||
| 899 | { | ||
| 900 | f = XFRAME (window); | ||
| 901 | |||
| 902 | xpos = 0; | ||
| 903 | ypos = 0; | ||
| 904 | } | ||
| 905 | else if (XTYPE (window) == Lisp_Window) | ||
| 906 | { | ||
| 907 | CHECK_LIVE_WINDOW (window, 0); | ||
| 908 | f = XFRAME (WINDOW_FRAME (XWINDOW (window))); | ||
| 909 | |||
| 910 | xpos = (FONT_WIDTH (f->display.x->font) * XWINDOW (window)->left); | ||
| 911 | ypos = (FONT_HEIGHT (f->display.x->font) * XWINDOW (window)->top); | ||
| 912 | } | ||
| 913 | else | ||
| 914 | /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME, | ||
| 915 | but I don't want to make one now. */ | ||
| 916 | CHECK_WINDOW (window, 0); | ||
| 917 | |||
| 918 | xpos += XINT (x); | ||
| 919 | ypos += XINT (y); | ||
| 920 | } | ||
| 921 | |||
| 922 | title = Qnil; | ||
| 923 | GCPRO1 (title); | ||
| 924 | |||
| 925 | /* Decode the dialog items from what was specified. */ | ||
| 926 | { | ||
| 927 | /* We were given an old-fashioned menu. */ | ||
| 928 | title = Fcar (menu); | ||
| 929 | CHECK_STRING (title, 1); | ||
| 930 | |||
| 931 | list_of_panes (Fcdr (menu)); | ||
| 932 | |||
| 933 | keymaps = 0; | ||
| 934 | } | ||
| 935 | |||
| 936 | if (NILP (position)) | ||
| 937 | { | ||
| 938 | discard_menu_items (); | ||
| 939 | UNGCPRO; | ||
| 940 | return Qnil; | ||
| 941 | } | ||
| 942 | |||
| 943 | /* Display them in a dialog box. */ | ||
| 944 | BLOCK_INPUT; | ||
| 945 | |||
| 946 | selection = xdialog_show (f, xpos, ypos, menubarp, | ||
| 947 | keymaps, title, &error_name); | ||
| 948 | UNBLOCK_INPUT; | ||
| 949 | |||
| 950 | discard_menu_items (); | ||
| 951 | |||
| 952 | UNGCPRO; | ||
| 953 | |||
| 954 | if (error_name) error (error_name); | ||
| 955 | return selection; | ||
| 956 | } | ||
| 829 | 957 | ||
| 830 | #ifdef USE_X_TOOLKIT | 958 | #ifdef USE_X_TOOLKIT |
| 831 | 959 | ||
| @@ -939,6 +1067,19 @@ popup_down_callback (widget, id, client_data) | |||
| 939 | UNBLOCK_INPUT; | 1067 | UNBLOCK_INPUT; |
| 940 | } | 1068 | } |
| 941 | 1069 | ||
| 1070 | static void | ||
| 1071 | dialog_selection_callback (widget, id, client_data) | ||
| 1072 | Widget widget; | ||
| 1073 | LWLIB_ID id; | ||
| 1074 | XtPointer client_data; | ||
| 1075 | { | ||
| 1076 | if ((int)client_data != -1) | ||
| 1077 | menu_item_selection = (Lisp_Object *) client_data; | ||
| 1078 | BLOCK_INPUT; | ||
| 1079 | lw_destroy_all_widgets (id); | ||
| 1080 | UNBLOCK_INPUT; | ||
| 1081 | } | ||
| 1082 | |||
| 942 | /* This recursively calls free_widget_value() on the tree of widgets. | 1083 | /* This recursively calls free_widget_value() on the tree of widgets. |
| 943 | It must free all data that was malloc'ed for these widget_values. | 1084 | It must free all data that was malloc'ed for these widget_values. |
| 944 | In Emacs, many slots are pointers into the data of Lisp_Strings, and | 1085 | In Emacs, many slots are pointers into the data of Lisp_Strings, and |
| @@ -1186,6 +1327,9 @@ check_mouse_other_menu_bar (f) | |||
| 1186 | 1327 | ||
| 1187 | #ifdef USE_X_TOOLKIT | 1328 | #ifdef USE_X_TOOLKIT |
| 1188 | 1329 | ||
| 1330 | extern unsigned int x_mouse_grabbed; | ||
| 1331 | extern Lisp_Object Vmouse_depressed; | ||
| 1332 | |||
| 1189 | static Lisp_Object | 1333 | static Lisp_Object |
| 1190 | xmenu_show (f, x, y, menubarp, keymaps, title, error) | 1334 | xmenu_show (f, x, y, menubarp, keymaps, title, error) |
| 1191 | FRAME_PTR f; | 1335 | FRAME_PTR f; |
| @@ -1426,6 +1570,16 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error) | |||
| 1426 | if (event.type == ButtonRelease) | 1570 | if (event.type == ButtonRelease) |
| 1427 | { | 1571 | { |
| 1428 | XtDispatchEvent (&event); | 1572 | XtDispatchEvent (&event); |
| 1573 | if (! menubarp) | ||
| 1574 | { | ||
| 1575 | /* Do the work of construct_mouse_click since it can't | ||
| 1576 | be called. Initially, the popup menu has been called | ||
| 1577 | from a ButtonPress in the edit_widget. Then the mouse | ||
| 1578 | has been set to grabbed. Reset it now. */ | ||
| 1579 | x_mouse_grabbed &= ~(1 << event.xbutton.button); | ||
| 1580 | if (!x_mouse_grabbed) | ||
| 1581 | Vmouse_depressed = Qnil; | ||
| 1582 | } | ||
| 1429 | break; | 1583 | break; |
| 1430 | } | 1584 | } |
| 1431 | else if (event.type == Expose) | 1585 | else if (event.type == Expose) |
| @@ -1481,8 +1635,10 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error) | |||
| 1481 | dispatch_dummy_expose (f->display.x->menubar_widget, x, y); | 1635 | dispatch_dummy_expose (f->display.x->menubar_widget, x, y); |
| 1482 | } | 1636 | } |
| 1483 | 1637 | ||
| 1638 | #if 0 /* No need to do that. The menu has disappeared. */ | ||
| 1484 | /* Make sure the menu disappears. */ | 1639 | /* Make sure the menu disappears. */ |
| 1485 | lw_destroy_all_widgets (menu_id); | 1640 | lw_destroy_all_widgets (menu_id); |
| 1641 | #endif | ||
| 1486 | 1642 | ||
| 1487 | /* Unread any events that we got but did not handle. */ | 1643 | /* Unread any events that we got but did not handle. */ |
| 1488 | while (queue != NULL) | 1644 | while (queue != NULL) |
| @@ -1548,6 +1704,186 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error) | |||
| 1548 | return Qnil; | 1704 | return Qnil; |
| 1549 | } | 1705 | } |
| 1550 | 1706 | ||
| 1707 | static char * button_names [] = { | ||
| 1708 | "button1", "button2", "button3", "button4", "button5", | ||
| 1709 | "button6", "button7", "button8", "button9", "button10" }; | ||
| 1710 | |||
| 1711 | static Lisp_Object | ||
| 1712 | xdialog_show (f, x, y, menubarp, keymaps, title, error) | ||
| 1713 | FRAME_PTR f; | ||
| 1714 | int x; | ||
| 1715 | int y; | ||
| 1716 | int menubarp; | ||
| 1717 | int keymaps; | ||
| 1718 | Lisp_Object title; | ||
| 1719 | char **error; | ||
| 1720 | { | ||
| 1721 | int i, nb_buttons=0; | ||
| 1722 | int dialog_id; | ||
| 1723 | Widget menu; | ||
| 1724 | XlwMenuWidget menubar = (XlwMenuWidget) f->display.x->menubar_widget; | ||
| 1725 | |||
| 1726 | /* This is the menu bar item (if any) that led to this menu. */ | ||
| 1727 | widget_value *menubar_item = 0; | ||
| 1728 | |||
| 1729 | widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; | ||
| 1730 | |||
| 1731 | /* Define a queue to save up for later unreading | ||
| 1732 | all X events that don't pertain to the menu. */ | ||
| 1733 | struct event_queue | ||
| 1734 | { | ||
| 1735 | XEvent event; | ||
| 1736 | struct event_queue *next; | ||
| 1737 | }; | ||
| 1738 | |||
| 1739 | struct event_queue *queue = NULL; | ||
| 1740 | struct event_queue *queue_tmp; | ||
| 1741 | |||
| 1742 | *error = NULL; | ||
| 1743 | |||
| 1744 | /* Create a tree of widget_value objects | ||
| 1745 | representing the text label and buttons. */ | ||
| 1746 | { | ||
| 1747 | Lisp_Object pane_name, prefix; | ||
| 1748 | char *pane_string; | ||
| 1749 | pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME]; | ||
| 1750 | prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX]; | ||
| 1751 | pane_string = (NILP (pane_name) | ||
| 1752 | ? "" : (char *) XSTRING (pane_name)->data); | ||
| 1753 | prev_wv = malloc_widget_value (); | ||
| 1754 | prev_wv->value = pane_string; | ||
| 1755 | if (keymaps && !NILP (prefix)) | ||
| 1756 | prev_wv->name++; | ||
| 1757 | prev_wv->enabled = 1; | ||
| 1758 | prev_wv->name = "message"; | ||
| 1759 | first_wv = prev_wv; | ||
| 1760 | |||
| 1761 | /* Loop over all panes and items, filling in the tree. */ | ||
| 1762 | i = MENU_ITEMS_PANE_LENGTH; | ||
| 1763 | while (i < menu_items_used) | ||
| 1764 | { | ||
| 1765 | |||
| 1766 | /* Create a new item within current pane. */ | ||
| 1767 | Lisp_Object item_name, enable, descrip; | ||
| 1768 | item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME]; | ||
| 1769 | enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE]; | ||
| 1770 | descrip | ||
| 1771 | = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY]; | ||
| 1772 | |||
| 1773 | wv = malloc_widget_value (); | ||
| 1774 | prev_wv->next = wv; | ||
| 1775 | wv->name = (char *) button_names [nb_buttons]; | ||
| 1776 | if (!NILP (descrip)) | ||
| 1777 | wv->key = XSTRING (descrip)->data; | ||
| 1778 | wv->value = XSTRING (item_name)->data; | ||
| 1779 | wv->call_data = (void *) &XVECTOR (menu_items)->contents[i]; | ||
| 1780 | wv->enabled = !NILP (enable); | ||
| 1781 | prev_wv = wv; | ||
| 1782 | |||
| 1783 | nb_buttons++; | ||
| 1784 | i += MENU_ITEMS_ITEM_LENGTH; | ||
| 1785 | } | ||
| 1786 | |||
| 1787 | wv = malloc_widget_value (); | ||
| 1788 | wv->name = "Q2BR1"; | ||
| 1789 | wv->contents = first_wv; | ||
| 1790 | first_wv = wv; | ||
| 1791 | |||
| 1792 | } | ||
| 1793 | |||
| 1794 | /* Actually create the dialog. */ | ||
| 1795 | dialog_id = ++popup_id_tick; | ||
| 1796 | menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv, | ||
| 1797 | f->display.x->widget, 1, 0, | ||
| 1798 | dialog_selection_callback, 0); | ||
| 1799 | lw_modify_all_widgets (dialog_id, first_wv, True); | ||
| 1800 | lw_modify_all_widgets (dialog_id, first_wv->contents, True); | ||
| 1801 | /* Free the widget_value objects we used to specify the contents. */ | ||
| 1802 | free_menubar_widget_value_tree (first_wv); | ||
| 1803 | |||
| 1804 | /* No selection has been chosen yet. */ | ||
| 1805 | menu_item_selection = 0; | ||
| 1806 | |||
| 1807 | |||
| 1808 | /* Display the menu. */ | ||
| 1809 | lw_pop_up_all_widgets (dialog_id); | ||
| 1810 | |||
| 1811 | /* Process events that apply to the menu. */ | ||
| 1812 | while (1) | ||
| 1813 | { | ||
| 1814 | XEvent event; | ||
| 1815 | |||
| 1816 | XtAppNextEvent (Xt_app_con, &event); | ||
| 1817 | if (event.type == ButtonRelease) | ||
| 1818 | { | ||
| 1819 | XtDispatchEvent (&event); | ||
| 1820 | break; | ||
| 1821 | } | ||
| 1822 | else if (event.type == Expose) | ||
| 1823 | process_expose_from_menu (event); | ||
| 1824 | XtDispatchEvent (&event); | ||
| 1825 | if (XtWindowToWidget(XDISPLAY event.xany.window) != menu) | ||
| 1826 | { | ||
| 1827 | queue_tmp = (struct event_queue *) malloc (sizeof (struct event_queue)); | ||
| 1828 | |||
| 1829 | if (queue_tmp != NULL) | ||
| 1830 | { | ||
| 1831 | queue_tmp->event = event; | ||
| 1832 | queue_tmp->next = queue; | ||
| 1833 | queue = queue_tmp; | ||
| 1834 | } | ||
| 1835 | } | ||
| 1836 | } | ||
| 1837 | pop_down: | ||
| 1838 | |||
| 1839 | /* Unread any events that we got but did not handle. */ | ||
| 1840 | while (queue != NULL) | ||
| 1841 | { | ||
| 1842 | queue_tmp = queue; | ||
| 1843 | XPutBackEvent (XDISPLAY &queue_tmp->event); | ||
| 1844 | queue = queue_tmp->next; | ||
| 1845 | free ((char *)queue_tmp); | ||
| 1846 | } | ||
| 1847 | |||
| 1848 | /* Find the selected item, and its pane, to return | ||
| 1849 | the proper value. */ | ||
| 1850 | if (menu_item_selection != 0) | ||
| 1851 | { | ||
| 1852 | Lisp_Object prefix; | ||
| 1853 | |||
| 1854 | prefix = Qnil; | ||
| 1855 | i = 0; | ||
| 1856 | while (i < menu_items_used) | ||
| 1857 | { | ||
| 1858 | Lisp_Object entry; | ||
| 1859 | |||
| 1860 | if (EQ (XVECTOR (menu_items)->contents[i], Qt)) | ||
| 1861 | { | ||
| 1862 | prefix | ||
| 1863 | = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; | ||
| 1864 | i += MENU_ITEMS_PANE_LENGTH; | ||
| 1865 | } | ||
| 1866 | else | ||
| 1867 | { | ||
| 1868 | entry | ||
| 1869 | = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE]; | ||
| 1870 | if (menu_item_selection == &XVECTOR (menu_items)->contents[i]) | ||
| 1871 | { | ||
| 1872 | if (keymaps != 0) | ||
| 1873 | { | ||
| 1874 | entry = Fcons (entry, Qnil); | ||
| 1875 | if (!NILP (prefix)) | ||
| 1876 | entry = Fcons (prefix, entry); | ||
| 1877 | } | ||
| 1878 | return entry; | ||
| 1879 | } | ||
| 1880 | i += MENU_ITEMS_ITEM_LENGTH; | ||
| 1881 | } | ||
| 1882 | } | ||
| 1883 | } | ||
| 1884 | |||
| 1885 | return Qnil; | ||
| 1886 | } | ||
| 1551 | #else /* not USE_X_TOOLKIT */ | 1887 | #else /* not USE_X_TOOLKIT */ |
| 1552 | 1888 | ||
| 1553 | static Lisp_Object | 1889 | static Lisp_Object |
| @@ -1761,4 +2097,5 @@ syms_of_xmenu () | |||
| 1761 | 2097 | ||
| 1762 | popup_id_tick = (1<<16); | 2098 | popup_id_tick = (1<<16); |
| 1763 | defsubr (&Sx_popup_menu); | 2099 | defsubr (&Sx_popup_menu); |
| 2100 | defsubr (&Sx_popup_dialog); | ||
| 1764 | } | 2101 | } |