Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!ucbvax!hplabs!hplabsz!mayer From: mayer@hplabsz.HPL.HP.COM (Niels Mayer) Newsgroups: comp.windows.x,hp.windows.motif Subject: Need help in interactive selection of a motif widget/gadget Summary: primitive allows application to interactively modify it's widgets Keywords: widget gadget motif X11 help-me-please Message-ID: <4219@hplabsz.HPL.HP.COM> Date: 26 Oct 89 02:41:28 GMT Reply-To: mayer@hplabs.hp.com (Niels Mayer) Organization: Hewlett-Packard Labs, Software Technology Lab, Palo Alto, CA. Lines: 121 Expires: Sender: Followup-To: I have added a primitive to my WINTERP application (a Motif application prototyping/develpment/delivery environment) which will allow users click on a widget to get back the WIDGET-OBJECT corresponding to the widget. I am using this to allow users to interactively modify the interfaces they build by pointing and clicking on widgets. (It's the sort of primitive that'll enable WINTERP to take on some of the features of hypercard (hope I don't get sued for saying that...). For example, to interactively change a callback on a button, you can send the following instruction to winterp's xlisp server: (send (get_moused_widget) :set_callback :xmn_arm_callback '() '((format T "this is a test\n"))) Then after the cursor changes to a crossbar (just like in xwd or xwininfo) you can the boink the mouse on the appropriate widget to set or change its callback. It's also lots of fun to use this to interactively change colors inside your winterp-based applications. My GET_MOUSED_WIDGET primitive currently works by using a combination of XGrabPointer() and XTranslateCoordinates() to find the window that got a buttonpress, the uses XtWindowToWidget() to get back the widgetID. If the desired widget is infact a gadget (a windowless widget), the designated window will infact be the gadget's manager. To check for that case, I see whether the widget is a composite (i.e. a gadget-manager), and if so, I call _XmInputInGadget() with the composite widget's ID, and the (x,y) location of the buttonpress. For the most part, GET_MOUSED_WIDGET works fine. However, if the designated gadget is inside a rowcolumn manager which is inside a scrolledwindow manager, i sometimes get problems. If the scrolledwin's origin == the rowcol windows's origin, get_moused_widget will work fine on a gadget. However, if the rowcol window is scrolled by , boinking a gadget at (x+offset,y+offset) will return the WIDGETOBJ at (x,y). Am I doing something wrong? Is this a Motif or Xtoolkit bug? Do I have to add yet another special kludge for a gadget-inside-a-manager- -inside-a-scrolled-window? Inquiring minds want to know. Here's the C code that gets called when winterp's xlisp interpreter evaluates the expression (get_moused_widget): /****************************************************************************** * (GET_MOUSED_WIDGET) * evaluating this function will change the cursor to a crossbar, indicating * that the user is to 'click' the mouse to designate an object on the screen. * If the user clicks on a visual item within WINTERP, this fucntion will * return the WIDGETOBJ associated with the visual item. * * KNOWN-BUG: Given gadget inside a rowcol manager which is inside a * scrolled manager. If the scrolled window's top == rowcol windows's top, * get_moused_widgetwill work fine on a gadget. However, if the rowcol * window is scrolled by , boinking a gadget at (x+offset,y+offset) * will return the WIDGETOBJ at (x,y). ******************************************************************************/ LVAL Wut_UserClick_To_WidgetObj() { extern Display* display; /* global in winterp.c */ extern LVAL Wcls_WidgetID_To_WidgetObj(); /* from w_classes.c */ Cursor cursor = XCreateFontCursor(display, XC_crosshair); Window root = DefaultRootWindow(display); Window parent_win, child_win, win; int parent_win_x, parent_win_y, child_win_x, child_win_y; Widget widget_id; XEvent event; xllastarg(); if (GrabSuccess != XGrabPointer(display, root, 0, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime)) xlfail("Wut_UserClick_To_WidgetObject() -- couldn't grab pointer (XGrabPointer() failed)."); XWindowEvent(display, root, ButtonPressMask, &event); XUngrabPointer(display, CurrentTime); XFlush(display); if (event.type != ButtonPress) /* sanity check: ensure valid access to event.xbutton variant */ xlfail("Wut_UserClick_To_WidgetObject() -- expected a button event."); if (!event.xbutton.subwindow) xlfail("Wut_UserClick_To_WidgetObject() -- User clicked on root window."); parent_win = root; child_win = event.xbutton.subwindow; parent_win_x = event.xbutton.x_root; parent_win_y = event.xbutton.y_root; child_win_x = event.xbutton.x; child_win_y = event.xbutton.y; while (XTranslateCoordinates(display, parent_win, child_win, parent_win_x, parent_win_y, /* give the x,y coords of event in parent_w */ &parent_win_x, &parent_win_y, /* return the x,y coords relative to child_w */ &win) /* returns child of parent_win if coords are in this win, else NIL */ && win) { #ifdef DEBUG_WINTERP_1 fprintf(stderr, "parent_win=%lx, child_win=%lx, win=%lx\n", parent_win, child_win, win); #endif parent_win = child_win; child_win = win; child_win_x = parent_win_x; child_win_y = parent_win_y; } #ifdef DEBUG_WINTERP_1 fprintf(stderr, " Smallest window containing userclick is %lx\n", child_win); #endif if (!(widget_id = XtWindowToWidget(display, child_win))) xlfail("Wut_UserClick_To_WidgetObject() -- Couldn't find widget associated with window (Is the selected widget/window inside a different application?).\n"); else if (XtIsComposite(widget_id)) { /* if it's a composite, smallest window may be a gadget's manager */ extern XmGadget _XmInputInGadget(); /* in Xm/GadetUtils.c extern'd in XmP.h */ Widget gadget_id = (Widget) _XmInputInGadget(widget_id, child_win_x, child_win_y); if (gadget_id) /* if gadget could be retrieved from looking up x,y coords in manager */ return (Wcls_WidgetID_To_WidgetObj(gadget_id)); /* then return the WIDGETOBJ assoc'd with gadget */ } return (Wcls_WidgetID_To_WidgetObj(widget_id)); /* otherwise, we return the WIDGETOBJ assoc'd with smallest window */ } ------------------------------------------------------------------------------- Niels Mayer -- hplabs!mayer -- mayer@hplabs.hp.com Human-Computer Interaction Department Hewlett-Packard Laboratories Palo Alto, CA. *