diff --git a/doc/fixes36.2 b/doc/fixes36.2 index e02e5b717..d470094ba 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -222,6 +222,9 @@ Qt: entering extended commands, hide non-matching ones Qt: remember tile and font size X11: implement menucolors and allow menus to obey inverse attribute X11: make key translations work with menus on Linux +X11: allow mouse wheel scrolling to work in menus by default +X11: handle paged menu control keys +X11: remember perm_invent window geometry General New Features diff --git a/include/winX.h b/include/winX.h index 3e6b67197..6939353c9 100644 --- a/include/winX.h +++ b/include/winX.h @@ -168,6 +168,9 @@ struct menu_info_t { boolean cancelled; /* Menu has been explicitly cancelled. */ boolean counting; /* true when menu_count has a valid value */ boolean permi; + + int permi_x, permi_y; /* perm_invent window x,y */ + int permi_w, permi_h; /* perm_invent window wid, hei */ }; /* @@ -293,6 +296,7 @@ E void FDECL(positionpopup, (Widget, BOOLEAN_P)); /* ### winX.c ### */ E struct xwindow *FDECL(find_widget, (Widget)); E Boolean FDECL(nhApproxColor, (Screen *, Colormap, char *, XColor *)); +E void FDECL(get_widget_window_geometry, (Widget, int *, int *, int *, int *)); E Dimension FDECL(nhFontHeight, (Widget)); E char FDECL(key_event_to_char, (XKeyEvent *)); E void FDECL(msgkey, (Widget, XtPointer, XEvent *)); diff --git a/win/X11/winX.c b/win/X11/winX.c index 5da69a6ec..fa94043cd 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -432,6 +432,58 @@ XtPointer *closure_ret; } } +/* Ask the WM for window frame size */ +void +get_window_frame_extents(w, top, bottom, left, right) +Widget w; +long *top, *bottom, *left, *right; +{ + XEvent event; + Display *dpy = XtDisplay(w); + Window win = XtWindow(w); + Atom prop, retprop; + int retfmt; + unsigned long nitems; + unsigned long nbytes; + unsigned char *data = 0; + long *extents; + + prop = XInternAtom(dpy, "_NET_FRAME_EXTENTS", True); + + while (XGetWindowProperty(dpy, win, prop, + 0, 4, False, AnyPropertyType, + &retprop, &retfmt, + &nitems, &nbytes, &data) != Success + || nitems != 4 || nbytes != 0) + { + XNextEvent(dpy, &event); + } + + extents = (long *) data; + + *left = extents[0]; + *right = extents[1]; + *top = extents[2]; + *bottom = extents[3]; +} + +void +get_widget_window_geometry(w, x,y, width, height) +Widget w; +int *x, *y, *width, *height; +{ + long top, bottom, left, right; + Arg args[5]; + XtSetArg(args[0], nhStr(XtNx), x); + XtSetArg(args[1], nhStr(XtNy), y); + XtSetArg(args[2], nhStr(XtNwidth), width); + XtSetArg(args[3], nhStr(XtNheight), height); + XtGetValues(w, args, 4); + get_window_frame_extents(w, &top, &bottom, &left, &right); + *x -= left; + *y -= top; +} + #ifdef TEXTCOLOR /* ARGSUSED */ static void @@ -2472,19 +2524,12 @@ Cardinal *num_params; direction = atoi(params[0]); - horiz_sb = XtNameToWidget(viewport, "*horizontal"); - vert_sb = XtNameToWidget(viewport, "*vertical"); - - if (!horiz_sb && !vert_sb) { - /* Perhaps the widget enclosing this has scrollbars (could use while) - */ - Widget parent = XtParent(viewport); - - if (parent) { - horiz_sb = XtNameToWidget(parent, "horizontal"); - vert_sb = XtNameToWidget(parent, "vertical"); - } - } + Widget scrollw = viewport; + do { + horiz_sb = XtNameToWidget(scrollw, "*horizontal"); + vert_sb = XtNameToWidget(scrollw, "*vertical"); + scrollw = XtParent(scrollw); + } while (!horiz_sb && !vert_sb && scrollw); #define H_DELTA 0.25 /* distance of horiz shift */ /* vert shift is half of curr distance */ diff --git a/win/X11/winmenu.c b/win/X11/winmenu.c index 81e892f6b..77009b8d7 100644 --- a/win/X11/winmenu.c +++ b/win/X11/winmenu.c @@ -67,8 +67,14 @@ static const char menu_translations[] = "#override\n\ Right: scroll(6)\n\ Up: scroll(8)\n\ Down: scroll(2)\n\ + : scroll(8)\n\ + : scroll(2)\n\ : menu_key()"; +static const char menu_entry_translations[] = "#override\n\ + : scroll(8)\n\ + : scroll(2)"; + /* * Menu callback. */ @@ -251,19 +257,19 @@ Cardinal *num_params; X11_nhbell(); return; } - } else if (ch == MENU_SELECT_ALL) { /* select all */ + } else if (ch == MENU_SELECT_ALL || ch == MENU_SELECT_PAGE) { if (menu_info->how == PICK_ANY) select_all(wp); else X11_nhbell(); return; - } else if (ch == MENU_UNSELECT_ALL) { /* unselect all */ + } else if (ch == MENU_UNSELECT_ALL || ch == MENU_UNSELECT_PAGE) { if (menu_info->how == PICK_ANY) select_none(wp); else X11_nhbell(); return; - } else if (ch == MENU_INVERT_ALL) { /* invert all */ + } else if (ch == MENU_INVERT_ALL || ch == MENU_INVERT_PAGE) { if (menu_info->how == PICK_ANY) invert_all(wp); else @@ -515,6 +521,15 @@ static void menu_popdown(wp) struct xwindow *wp; { + if (iflags.perm_invent && wp == &window_list[WIN_INVEN] + && wp->menu_information->how == PICK_NONE) { + get_widget_window_geometry(wp->popup, + &wp->menu_information->permi_x, + &wp->menu_information->permi_y, + &wp->menu_information->permi_w, + &wp->menu_information->permi_h); + } + nh_XtPopdown(wp->popup); /* remove the event grab */ XtDestroyWidget(wp->popup); wp->w = wp->popup = (Widget) 0; @@ -817,6 +832,9 @@ struct menu *curr_menu; XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; } + XtSetArg(args[num_args], XtNtranslations, + XtParseTranslationTable(menu_entry_translations)); num_args++; + menulineidx++; Sprintf(tmpbuf, "menuline_%s", (canpick) ? "command" : "label"); curr->w = linewidget @@ -913,6 +931,12 @@ menu_item **menu_list; num_args = 0; XtSetArg(args[num_args], XtNallowShellResize, True); num_args++; + if (permi && menu_info->permi_x != -1) { + XtSetArg(args[num_args], nhStr(XtNwidth), menu_info->permi_w); + num_args++; + XtSetArg(args[num_args], nhStr(XtNheight), menu_info->permi_h); + num_args++; + } wp->popup = XtCreatePopupShell((window == WIN_INVEN) ? "inventory" : "menu", (how == PICK_NONE) @@ -1013,8 +1037,22 @@ menu_item **menu_list; menu_info->is_up = TRUE; if (permi) { + if (permi && menu_info->permi_x != -1) { + /* Cannot set window x,y at creation time, + we must move the window now instead */ + XMoveWindow(XtDisplay(wp->popup), XtWindow(wp->popup), + menu_info->permi_x, menu_info->permi_y); + } /* cant use nh_XtPopup() because it may try to grab the focus */ XtPopup(wp->popup, (int) XtGrabNone); + if (permi && menu_info->permi_x == -1) { + /* remember perm_invent window geometry the first time */ + get_widget_window_geometry(wp->popup, + &menu_info->permi_x, + &menu_info->permi_y, + &menu_info->permi_w, + &menu_info->permi_h); + } if (!updated_inventory) { XMapRaised(XtDisplay(wp->popup), XtWindow(wp->popup)); } @@ -1236,6 +1274,10 @@ struct xwindow *wp; reset_menu_count(wp->menu_information); wp->w = wp->popup = (Widget) 0; wp->menu_information->nh_colors_inited = FALSE; + wp->menu_information->permi_x = -1; + wp->menu_information->permi_y = -1; + wp->menu_information->permi_w = -1; + wp->menu_information->permi_h = -1; } void