diff options
Diffstat (limited to 'Build/source/texk/xdvik/gui/xm_menu.c')
-rw-r--r-- | Build/source/texk/xdvik/gui/xm_menu.c | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/Build/source/texk/xdvik/gui/xm_menu.c b/Build/source/texk/xdvik/gui/xm_menu.c new file mode 100644 index 00000000000..51a2bedbd53 --- /dev/null +++ b/Build/source/texk/xdvik/gui/xm_menu.c @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2001 Marcin Dalecki and others + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "xdvi-config.h" +#include "xdvi.h" + +#include "xm_menu.h" +#include "xm_toolbar.h" +#include "my-snprintf.h" +#include "util.h" +#include "x_util.h" +#include "version.h" +#include "statusline.h" +#include "pagehist.h" +#include "dvi-init.h" +#include "filehist.h" +#include "c-openmx.h" +#include "message-window.h" + +#ifdef MOTIF /* needed for `make depend' */ + +#include <Xm/RowColumn.h> +#include <Xm/Frame.h> +#include <Xm/PushB.h> +#include <Xm/PushBG.h> +#include <Xm/CascadeBG.h> +#include <Xm/SeparatoG.h> +#include <Xm/ToggleB.h> +#include <Xm/ToggleBG.h> +#include <Xm/Separator.h> + + +/* + * There's an apparent bug in Motif related to the interaction between + * the menubar menus and the magnifier. + * + * If you click on a menu on the menubar and then click on the drawing + * widget to pop up a magnifier, the keyboard and pointer are still + * grabbed, leading to a weird situation in which the magnifier stays + * around even after you release the pointer. The ungrab_serial + * counter works around this bug by ignoring such pointer events. + * + * This bug occurs in Motif 1.2 and OpenMotif 2.2.2 (at least). It + * does not occur in Lesstif. + */ +static unsigned long ungrab_event_num = 0; + +void +popdown_callback(Widget w, XtPointer client_data, XtPointer call_data) +{ + UNUSED(w); + UNUSED(client_data); + /* Lesstif gives call_data == NULL */ + if (call_data != NULL && *((XtGrabKind *) call_data) != XtGrabNone) { + ungrab_event_num = LastKnownRequestProcessed(DISP); + } +} + +Boolean +pulldown_menu_active(unsigned long event_num) +{ + return event_num < ungrab_event_num; +} + + +void +toggle_menubar(void) +{ + if ((resource.expert_mode & XPRT_SHOW_MENUBAR) == 0) + XtUnmanageChild(globals.widgets.menu_bar); + else + XtManageChild(globals.widgets.menu_bar); +} + +static void +update_menu_labels(Widget menu) +{ + WidgetList children; + int num_children; + int i; + + static char *buf = NULL; + static size_t buf_len = 0; + + XtVaGetValues(menu, + XmNnumChildren, &num_children, + XmNchildren, &children, + NULL); + +/* for (i = 0; i < num_children; i++) { */ + for (i = 0; i < (int)file_history_size(); i++) { + int dummy_page; + char *filename; + size_t new_len; + XmString str; + + if ((filename = file_history_get_elem(i, &dummy_page)) == NULL) { + XDVI_ERROR((stderr, "Error accessing element %d of file history", i)); + continue; + } + + new_len = LENGTH_OF_INT + strlen(filename) + 1; + if (new_len > buf_len) { + buf = xrealloc(buf, new_len); + buf_len = new_len; + } + + sprintf(buf, "%d %s", i + 1, filename); + str = XmStringCreateLocalized(buf); + XtVaSetValues(children[i], + XmNlabelString, str, + NULL); + if (i + 1 < 10) { + XtVaSetValues(children[i], XmNmnemonic, buf[0], NULL); + } + XmStringFree(str); + } + + /* if history size < number of menu entries, destroy excess menu entries */ + for (; i < num_children; i++) { + XtDestroyWidget(children[i]); + } +} + +static void +filehist_select_cb(Widget w, XtPointer client_data, XtPointer call_data) +{ + Widget menu; + XmString label; + char *label_ptr; + int pageno; + char *fname; + int idx; + +/* UNUSED(w); */ + UNUSED(call_data); + UNUSED(client_data); + + XtVaGetValues(w, + XmNuserData, &menu, + XmNlabelString, &label, + NULL); + + XmStringGetLtoR(label, G_charset, &label_ptr); + idx = strtol(label_ptr, (char **)NULL, 10) - 1; + XtFree(label_ptr); + + ASSERT(menu != NULL, "XmNuserData in filehist_select_cb musn't be NULL!"); + + if (idx == 0) { /* user re-selected current file: reload */ + globals.ev.flags |= EV_RELOAD; + return; + } + if ((fname = file_history_get_elem(idx, &pageno)) == NULL) { + statusline_print(STATUS_MEDIUM, "Error accessing file %d of history", idx); + return; + } + + file_history_open(fname); +} + +void +filehist_menu_refresh(void) +{ + Widget menu; + if (get_widget_by_name(&menu, globals.widgets.menu_bar, Xdvi_FILEHIST_MENU, True)) { + update_menu_labels(menu); + } +} + +void +filehist_menu_add_entry(const char *filename) +{ + Widget menu; + + static char *buf = NULL; + static size_t buf_len = 0; + size_t new_len = LENGTH_OF_INT + strlen(filename) + 1; + + if (get_widget_by_name(&menu, globals.widgets.menu_bar, Xdvi_FILEHIST_MENU, True)) { + int num_children; + Widget w; + + if (new_len > buf_len) { + buf = xrealloc(buf, new_len); + buf_len = new_len; + } + + XtVaGetValues(menu, XmNnumChildren, &num_children, NULL); + + sprintf(buf, "%d %s", num_children + 1, filename); + + w = XtVaCreateManagedWidget(buf, xmPushButtonGadgetClass, menu, + XmNuserData, menu, + NULL); + if (num_children + 1 < 10) { + XtVaSetValues(w, XmNmnemonic, buf[0], NULL); + } + XtAddCallback(w, XmNactivateCallback, filehist_select_cb, (XtPointer)(num_children + 1)); + + update_menu_labels(menu); + + } +} + +static void +filehist_submenu(int idx, const char *filename, int pageno, void *data) +{ + Widget menu = (Widget)data; + Widget w; + static char *buf = NULL; + static size_t buf_len = 0; + size_t new_len = LENGTH_OF_INT + strlen(filename) + 1; + + if (new_len > buf_len) { + buf = xrealloc(buf, new_len); + buf_len = new_len; + } + + UNUSED(pageno); + + sprintf(buf, "%d %s", idx + 1, filename); + TRACE_GUI((stderr, "Creating menu `%s'", buf)); + w = XtVaCreateManagedWidget(buf, xmPushButtonGadgetClass, menu, +/* XmNmnemonic, buf[0], */ + XmNuserData, menu, + NULL); + if (idx + 1 < 10) { + XtVaSetValues(w, XmNmnemonic, buf[0], NULL); + } + XtAddCallback(w, XmNactivateCallback, filehist_select_cb, (XtPointer)idx); +} + + + +static Widget +recent_files_submenu(Widget parent, char *title, char mnemonic) +{ + Widget menu = 0, cascade = 0; + XmString str; + + menu = XmCreatePulldownMenu(parent, Xdvi_FILEHIST_MENU, NULL, 0); + str = XmStringCreateLocalized(title); + cascade = XtVaCreateManagedWidget(title, xmCascadeButtonGadgetClass, parent, + XmNsubMenuId, menu, + XmNlabelString, str, + XmNmnemonic, mnemonic, + NULL); + XmStringFree(str); + + file_history_enumerate(filehist_submenu, menu); + return cascade; +} + +Widget +xm_create_menu(Widget parent, char *title, char mnemonic, struct button_info *item) +{ + Widget menu = 0, cascade = 0, w = 0; + size_t i; + XmString str; + + menu = XmCreatePulldownMenu(parent, "_pulldown", NULL, 0); + str = XmStringCreateLocalized(title); + cascade = XtVaCreateManagedWidget(title, xmCascadeButtonGadgetClass, parent, + XmNsubMenuId, menu, + XmNlabelString, str, + XmNmnemonic, mnemonic, + NULL); + XmStringFree(str); + + /* add the menu items */ + for (i = 0; item != NULL && i < item->size; i++) { + item->elems[i].widget = 0; + /* if there's a subitem, call this function recursively */ + if (item->elems[i].submenu != NULL) { + w = xm_create_menu(menu, item->elems[i].title, + item->elems[i].mnemonic, item->elems[i].submenu); + /* + workaround for pointer grabbing bug; add additional callback to all menus + (they have the same parent) + */ + XtAddCallback(XtParent(menu), XtNpopdownCallback, + popdown_callback, (XtPointer) 0); + } + else if (item->elems[i].action != NULL && item->elems[i].action->proc == Act_recent_files) { + /* special case: submenu with recent files */ + w = recent_files_submenu(menu, item->elems[i].title, item->elems[i].mnemonic); + XtAddCallback(XtParent(menu), XtNpopdownCallback, + popdown_callback, (XtPointer) 0); + } + else { + switch(item->elems[i].type) { + case BT_PUSH: + w = XtVaCreateManagedWidget(item->elems[i].title, xmPushButtonGadgetClass, menu, + NULL); + break; + case BT_RADIO: + w = XtVaCreateManagedWidget(item->elems[i].title, xmToggleButtonGadgetClass, menu, + XmNindicatorType, XmONE_OF_MANY, + NULL); + break; + case BT_CHECK: + w = XtVaCreateManagedWidget(item->elems[i].title, xmToggleButtonGadgetClass, menu, + XmNindicatorType, XmN_OF_MANY, + NULL); + break; + case BT_SEP: + w = XtVaCreateManagedWidget(item->elems[i].title, xmSeparatorGadgetClass, menu, + NULL); + break; + default: + XDVI_WARNING((stderr, "unrecognized button type %d in menu %s (skipping this item).\n", + item->elems[i].type, item->elems[i].title)); + break; + } + item->elems[i].widget = w; + } + + if (item->elems[i].mnemonic != 0) + XtVaSetValues(w, XmNmnemonic, item->elems[i].mnemonic, NULL); + + if (item->elems[i].accelerator != NULL) { + str = XmStringCreateLocalized(item->elems[i].accelerator); + XtVaSetValues(w, XmNacceleratorText, str, NULL); + XmStringFree(str); + } + + if (item->elems[i].action != NULL) { + String cb_type; + if (XmIsToggleButton(w) || XmIsToggleButtonGadget(w)) + cb_type = XmNvalueChangedCallback; + else + cb_type = XmNactivateCallback; + XtAddCallback(w, cb_type, handle_command, item->elems[i].action); + } + } + return cascade; +} + +#else +/* silence `empty compilation unit' warnings */ +static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); } +#endif /* MOTIF */ + |