Archive-name: motif-faq/part4 Last-modified: 1 FEB 2002 Posting-Frequency: irregular Organization: Kenton Lee, X/Motif Consultant, http://www.rahul.net/kenton/ URL: http://www.rahul.net/kenton/mfaq.html Version: 8.1 ---------------------------------------------------------------------------- Subject: 67) Is there an mwm virtual desktop manager? [Last modified: Sep 97] Answer: David Kaelbling (drk@x.org) reports: In OSF/Motif 2.0, mwm supports both workspaces (see the f.cci function and the wsm demo for a sample interface) and a virtual root window. To manipulate the virtual screen f.goto, f.pan, and f.track_pan were added, as were iconPinned and clientPinned client resources. Peter E. Wagner (pwagner@panix.com): Imagine that your "desktop" extends beyond the view provided by your monitor. A virtual window manager gives you access to the space beyond your viewport (i.e. your screen) by allowing you to move the viewport to other areas of the extended desktop. The first one is Solbourne's swm, which spawned vtwm/tvtwm/olvwm. David B. Lewis created one. suresh@unipalm.co.uk has further developed it into the UniPalm product DOORS, which is only available as a source code extension to the MOTIF window manager. The price of the source and unlimited right to distribute binaries is 10,000 pounds Sterling. Alternately, source and right to use within one company is 2,000 pounds Sterling. Contact Peter Dawe Unipalm Limited Voice: +44 (0) 223 420002 216 The Science Park Fax: +44 (0) 223 426868 CAMBRIDGE CB4 4WA An enhancement request for such an object has been filed with OSF. Tim Failes (tim@aus.oz.au) of Advanced User Systems Pty Ltd writes: IXI (now SCO) has a fully supported product called Panorama which provides this facility. Panorama allows the user to pan around the virtual work space, dynamically change the size of the virtual workspace, and also access windows via an icon box. Panorama also includes a point-and-click tool for setting resources such as colours, focus policy, etc. [SCO contact information appears in the "Where can I get Motif?" subject. -ed] ----------------------------------------------------------------------------- Subject: 68) Why does mwm 1.2 crash on startup? [Last modified: March 93] Answer: David Brooks wrote: The commonest cause of early mwm demise is as follows: - You, or someone, built Xlib in the default way using the Xsi internationalization functions. - Your Xlib wasn't installed completely (or at all). - Early on, mwm calls the function XmbTextListToTextProperty, which calls _XConvertMBToCT, which looks for the Xsi locale database, finds it missing, ignores this fact and tries to dereference zero. The workaround is to find the database *somewhere*, and point the environment variable XNLSPATH at it. For example, in my personal X source tree: setenv XNLSPATH /home/X11r5src/mit/lib/nls/Xsi ----------------------------------------------------------------------------- Subject: 69) How do I obtain the size of a unmanaged shell widget? Answer: In the code below, use getsize() for widgets which have been managed, and getsize2() for newly created shell widgets which have not yet been managed. getsize2() takes two widget parameters because popup dialogs etc. _consist_ of two separate widgets - the parent shell and the child bulletin board, form, whatever. This important distinction (somewhat glossed over in the Motif manuals) is the cause of a large number of queries in comp.windows.x.motif. XmCreate...Dialog() functions return the (bulletin board, form, whatever) _child_ of the pair, not the parent shell. getsize2() takes the _shell_ widget as it's first parameter, and the shell's _child_ (the bulletin board, form, whatever) as it's second. Thus, if you are using code like widget = XmCreate...Dialog() to create your popup dialogs, use code like getsize2(XtParent(widget),widget,&width,&height) to get the width and height. If you use e.g. XmCreateDialogShell() or XtCreatePopupShell(), then you are creating the the shell widget and it's child explicitly, and can just pass them into getsize2() with no problem. Note: getsize2() calls getsize(). /* getsize(widget,width,height); * Widget widget; * int *width,*height; * * returns the width and height of a managed widget */ void getsize(l,w,h) Widget l; int *w,*h; { Dimension w_,h_,b_; static Arg size_args[] = { { XmNwidth,0 }, { XmNheight,0 }, { XmNborderWidth,0 }, }; size_args[0].value = (XtArgVal)&w_; size_args[1].value = (XtArgVal)&h_; size_args[2].value = (XtArgVal)&b_; XtGetValues(l,size_args,3); if (w) *w = w_ + b_; if (h) *h = h_ + b_; } /* getsize2(shell,child,width,height); * Widget shell,child; * int *width,*height; * * returns the width, height of an unmanaged shell widget */ void getsize2(p,c,w,h) Widget p,c; int *w,*h; { XtSetMappedWhenManaged(p,0); XtManageChild(c); getsize(p,w,h); XtUnmanageChild(c); XtSetMappedWhenManaged(p,-1); } submitted by: [ Huw Rogers Communications Software Engineer, NEC Corporation, Tokyo, Japan ] [ Email: rogersh@ccs.mt.nec.co.jp Fax: +81-3-5476-1005 Tel: +81-3-5476-1096 ] ----------------------------------------------------------------------------- Subject: 70) How can I create a shell widget with a non-default visual type? [Last modified: Feb 00] Answer: You must specify the colormap, visual type, and depth for the shell before it is realized. If you don't specify all three resources (or specify them incorrectly), you will probably get BadMatch protocol errors from your X server. Ken Lee, http://www.rahul.net/kenton/ Mike Stroyan, mike_stroyan@fc.hp.com, adds: It is convenient to use XrmPutResource to cause all widgets to pick up a consistent set of visual, depth, and colormap. It is just very difficult to get at each and every shell including menushells created by functions like XmVaCreateSimpleMenuBar and XmVaCreateSimpleOptionMenu. This example uses the default visual for menus, but a non-default for the top level shell: if (!non_default_dialogs) { /* Set default depth and colormap of shell widgets, especially menus */ Screen *default_screen; int default_depth; Colormap default_colormap; XrmDatabase db = XtDatabase(display); XrmValue v; default_screen = DefaultScreenOfDisplay(display); default_depth = DefaultDepthOfScreen(default_screen); default_colormap = DefaultColormapOfScreen(default_screen); v.size = sizeof(default_depth); v.addr = (XtPointer) &default_depth; XrmPutResource(&db,"*XmMenuShell.depth", XmRInt, &v); XrmPutResource(&db,"*XmDialogShell.depth", XmRInt, &v); v.size = sizeof(default_colormap); v.addr = (XtPointer) &default_colormap; XrmPutResource(&db,"*XmMenuShell.colormap", XmRColormap, &v); XrmPutResource(&db,"*XmDialogShell.colormap", XmRColormap, &v); } /* Get visual information. */ template.screen = DefaultScreen(display); template.class = TrueColor; template.depth = 24; mask = VisualScreenMask | VisualDepthMask | VisualClassMask; vilist = XGetVisualInfo(display, mask, &template, &nvisual); if (nvisual == 0) { fprintf(stderr, "Cannot find an acceptable visual!0); exit(1); } visual = vilist[0].visual; depth = vilist[0].depth; XFree((char *) vilist); private_colormap = XCreateColormap(display, DefaultRootWindow(display), visual, AllocNone); { XColor real, exact; XAllocNamedColor(display, private_colormap, "Green", &real, &exact); green = real.pixel; } XtVaSetValues(toplevel, XmNdepth, depth, XmNvisual, visual, XmNcolormap, private_colormap, NULL); if (non_default_dialogs) { /* Set non-default visual for all widgets. */ XrmDatabase db = XtDatabase(display); XrmValue v; v.size = sizeof(visual); v.addr = (XtPointer) &visual; XrmPutResource(&db,"*visual", XmRVisual, &v); } ----------------------------------------------------------------------------- Subject: 71) Can a non-shell Motif widget have a different visual type from its parent? [Last modified: May 97] Answer: None of the standard Motif widgets support this. You can, however, write your own subclasses that have different visual types. You'll have to override the Realize method in your subclass. Becareful to set the colormap and depth properly to match your visual type. Ken Lee ----------------------------------------------------------------------------- Subject: 72) Why do I get BadMatch errors from my menus when I use a non- default visual type for my application shell? [Last modified: Sept 95] Answer: Unfortunately, the visual type and depth attributes are copied differently from parent to child. To be safe you use non-default visuals on any of your widgets and use these as parents for shell widgets (including menus), you should set the visual type, depth, and colormap on the child shells. Ken Lee ----------------------------------------------------------------------------- Subject: 73) How do I popup a scrolled list on top of other widgets? [Last modified: Sept 95 ] Put it in an override redirect shell and do a XMapRaise on the shell's window. That will do it. If you're using Motif then just use a VendorShell with XmNoverrideRedirect set to true. Thanks to Doug Rand (drand@sgi.com) ----------------------------------------------------------------------------- Subject: 74) How can I keep my application's window always on top of all other applications' windows? [Last modified: Sep 97] Answer: Some window managers have features supporting this. Mwm does not. The ICCCM does not specify a standard protocol for using the feature. Note: some applications attempt to implement this by periodically popping themselves to the top of the stack (perhaps in response to visibility change events). This is very poor practice and should be avoided. If more than one of a user's applications try this hack, the user will not be pleased. Ken Lee ----------------------------------------------------------------------------- Subject: 75) How can I maximize my top level shell? [Last modified: Apr 98] Answer: There is no explicit support for this. Maximizing makes sense in single tasking operating systems where the user must choose one application to be active. Motif usually runs in multi-tasking operating systems where several applications may be active and having one take over the screen is undesirable. If you must make your application full screen, use the Xlib macros to compute the root window size and set the width and height of your shell to this size. You may want to leave a little space around the edges for the window manager frame. Ken Lee ----------------------------------------------------------------------------- Subject: 76) TOPIC: MOTIF DEVELOPMENT TOOLS (GUI BUILDERS and UIMS's) ----------------------------------------------------------------------------- Subject: 77)* What GUI tools exist to assist in developing Motif applications? [Last modified: Feb 02 ] Answer: This subject was very out-of-date and has been deleted. Some popular tools are listed at: http://www.rahul.net/kenton/xsites.framed.html ----------------------------------------------------------------------------- Subject: 78) TOPIC: GEOMETRY MANAGEMENT ----------------------------------------------------------------------------- Subject: 79) Why is geometry management so important? [Last modified: Sept 94] Answer: Geometry management is a key element of Motif applications for reasons which include, but are not limited to, the following: The user should be able to re-size the shell and get some reasonable geometry response (other than clipping). The user should be able to tailor fonts and have the widgets adjust accordingly. (Many people over 40 simply can't read small fonts without serious eye strain.) When the designers decide to change a label, the widgets should re-adjust accordingly. Some labels must be set dynamically and the widgets should re-layout accordingly. An internationalized application must work with several resource files, one for each supported natural language. The labels in each file have different lengths and the application should adjust accordingly. ----------------------------------------------------------------------------- Subject: 80) Why don't my labels resize in a RowColumn widget? I have a RowColumn widget in my application, with several rows and columns of XmLabels. When I update the text in the labels, the label's width does not get updated. [Last modified: Oct 94] Answer: Make sure all the ancestor widget resize mechanisms are enabled: - on shells, set XmNallowShellResize - on row column, set XmNresizeWidth and XmNresizeHeight - on bulletin board and form, set XmNresizePolicy Also, set XmNrecomputeSize on the label itself. The shell resource is off by default; the others should be on by default. Ken Lee ----------------------------------------------------------------------------- Subject: 81) Does XmRowColumn support multiple columns with different column widths? [Last modified: Apr 98] Answer: XmRowColumn was designed for simple layouts like menu panes and tool bars. For more sophisticated layouts, you should use an XmForm widget instead. Ken Lee ----------------------------------------------------------------------------- Subject: 82) Why do composite widgets (including dialogs) that were created after their parents were realized appear smaller under 1.2.3 and later? [Last modified: Dec 97] A. Thanks to David Brooks (dbrooks@ics.com) for pointing me to Daniel Dardailler (daniel@x.org) who wrote this scholarly treatise: Application's Geometry Management Advanced Guidelines: ===================================================== (or "How to properly manage children of already realized parent") Xt Background: ------------- XtCreateWidget: call Initialize ; XtManageChild: if (parent realized) call ChangeManaged ; call Realize ; XtRealizeWidget: postorder ChangeManaged loop ; preorder Window-creation loop ; Creating a widget only invokes its Initialize method (its parent's InsertPosition method too, but that has nothing to do with GM). Composite widgets, by opposition to Primitive, does not usually get a correct size at initialization time, since their correct size is based on their children sizes, which do not exist yet at this time. Applications usually create an entire tree of managed but unrealized widgets and then realize their top level widget, which recursively realize every widgets in the tree. During the creation process, the managing of the unrealized widgets is a no-op (only mark them managed). When XtRealizeWidget(toplevel) happens, the change_managed methods of all the composite widgets in the tree are called in bottom-to-top order, thus giving each of them a chance to determine their own size based on their children *current* sizes (composite or not). Using the current size of the children in this situation is fine, since they should also be the children's preferred size, not yet constrained by the parents layout (post-order traversal). When one create a widget inside an already realized parent, this is a different story and the order of management vs realization is important. Consider a MessageBox created in a realized Frame. The MessageBox itself creates a bunch of managed children inside its Initialize method. If you manage the MessageBox right after its creation, the Frame ChangeManaged will be called (since it is realized), and its will use the MessageBox current size as its base for its own size. Unfortunately, the MessageBox ChangeManaged proc has never been called! so its current size is whatever the default is, usually a non-settable value (needed for tracking real initial size setting). The MessageBox ChangeManaged has not been called because its children were created and managed at a time where it wasn't realized. What to do ? The first solution would be to have all the ChangeManaged methods in Motif call XtQueryGeometry instead of using the current size if it's not the first time (i.e. if they're already realized). But this is a lot of code to change and a kind of expensive run-time process as it results in non-linear traversal order of the realized tree (looks like an O(n!) but I'm not sure). It's not even guaranteed that it will always work fine, since it relies on the assumption that the geometry queried is the same that the geometry asked for any manager (I mean, it might be the case, but if it's not, it's just more code to fix in a very "bc-sensitive" part of Xm). This other solution lies into the application, and is to realize a manager first and then to manage it. By realizing it, you are forcing its ChangeManaged proc to be called (XtRealizeWidget does that), it will get a correct size and this size will be used by its parent ChangeManaged when you'll manage the manager. By explicitly realizing the branch before managing its root, you are reproducing the ordering that is typical of most applications at startup. So the trick is: XtCreateWidget(realize_parent, MessageBox); XtRealizeWidget(MessageBox); /* needed */ XtManageChild(MessageBox); and the model is: "Always explicitly realize a composite widget child of an already realized parent before managing it if all its children have been already managed" One can always realize every widget children of realized parents, that won't hurt, but it's useless for Primitives and Composites that get more children added later in the program. Why? because Primitives get their correct size at initialization time anyway and adding a child to a Composite will generate a geometry request and a layout that will have the same effect as if the ChangeManaged method had been called (well, nearly the same effect, that a complication I will address later). If we consider Motif, this trick is only useful for MessageBox, SelectionBox and subclasses, and Scale, since those are the only Composites that create managed children in their Initialize method and don't usually get additional kids from the application. However, any application that re-creates this order of actions will need to apply the "realize<manage" method too. For instance: XtCreateWidget(realize_parent, DrawingArea); XtRealizeWidget(DrawingArea); /* not needed */ XtManageChild(DrawingArea); XtCreateWidget(DrawingArea, any_child) ; XtManageChild(any_child); but XtCreateWidget(realize_parent, DrawingArea); XtCreateWidget(DrawingArea, any_child) ; XtManageChild(any_child); XtRealizeWidget(DrawingArea); /* needed */ XtManageChild(DrawingArea); Now this is becoming interesting: there are exceptions to the model :-) The first one is the Xt Shell widget, which has what I consider to be a bug, but what MIT has, until recently, always considered to be a specific behavior overridable by a subclass (like our VendorShell): the ChangeManaged method always resizes the child to its own size when the Shell is realized. A side effect of this behavior is that even the realized<managed trick won't work for direct descendant of Shell widget: XtCreateWidget(realize_shell, MessageBox); XtRealizeWidget(MessageBox); /* needless */ XtManageChild(MessageBox); /* will get resized anyway */ To get rid of this problem, one needs to add a regular manager between the Shell and the MessageBox in this case, for the sake of having this manager doing a request to the Shell from its ChangeManaged proc. This request will then be handled by the Shell geometry manager, not its ChangeManaged proc, and it will take into account the child size. Note that we could also change our VendorShell ChangeManaged code to not systematically envelop the Xt Shell ChangeManaged class method, and check for the already realized case, but I would rather wait for an Xt fix instead (I'm working on it). If you broader the scope of the Xt Shell situation, you find that there are also some resources in Xm that come into effect upon geometry request reception but are not used in the ChangeManaged method. Take the PanedWindow constraint resource XmNallowResize for instance, which controls the validity of a geometry request made by a PW child. If you do: XtCreateWidget(realize_shell, PanedWindow); XtManageChild(PanedWindow); XtCreateWidget(PanedWindow, button); XtManageChild(button); that works fine since the ChangeManaged of the PanedWindow will handle the insertion of the button and allowResize won't be used. But if you add a manager in this hierarchy: XtCreateWidget(realize_parent, PanedWindow); XtManageChild(PanedWindow); XtCreateWidget(PanedWindow, manager); XtManageChild(manager); XtCreateWidget(manager, button); XtManageChild(button); That doesn't work anymore since the button management results in its parent manager's ChangeManaged being called, which in turn makes a *request* to the PanedWindow, resulting in a No reply because of allowResize (set to False by default). The PanedWindow parent wouldn't have been realized that everything would have worked fine, since no request would have been made. It really depends on the early realization scheme. I think XmNresizable in Form is the only other resource to present this problem. There is not much to do in those cases except than setting the corresponding resource to True, which makes sense. - Daniel Dardailler (daniel@x.org) In addition, John Michael Davison <davisonj@panix.com> sends this suggestion. I think it's overkill for most people, but you may want to consider it if you have problems in this area: /* Workaround for motif 1.2.3-style geometry management */ void smart_manage_child(Widget widget) { assert(widget != 0); #if XmVersion >= 1002 && XmUPDATE_LEVEL >= 3 /* In Motif 1.2.3 and later: /* "Always explicitly realize a composite widget child of an already /* realized parent before managing it..." /* Note that this is unnecessary for simple UI objects (i.e. wrappers for /* Motif "Primitive" widgets.) */ if (XtIsManaged(widget)) return; if (!XtIsRealized(widget) && XtIsComposite(widget)) { Widget parent_widget = XtParent(widget); if (parent_widget && XtIsRealized(parent_widget)) XtRealizeWidget(widget); } #endif /* XmVersion >= 1002 && XmUPDATE_LEVEL >= 3 */ XtManageChild(widget); } - John Michael Davison <davisonj@panix.com> FYI - Asente & Swick (p. 207) says: If the child's parent is realized, XtManageChild and XtManageChildren automatically realize any widgets passed to them that are not currently realized, causing the creation of their windows. However, you should explicitly realize a composite child of a realized widget before managing the child to ensure that the child appears with its correct size. - Ken Lee, http://www.rahul.net/kenton/ ----------------------------------------------------------------------------- Subject: 83) How does the ScrolledWindow manage resizing? [Last modified: June 95] Answer: The scrolled window should resize its immediate child when it is resized. The child is XmNworkWindow in the default application-defined scrolling mode or XmNclipWindow in the automatic scrolling mode. In either case, you can then resize your row column. If you set XmNadjustLast, the children of a one column row column will be automatically resized. Ken Lee ----------------------------------------------------------------------------- Subject: 84) Does the XmPanedWindow widget support horizontal paning? [Last modified: May 97] Answer: In Motif 2.x it does, but not in Motif 1.x. There are, however, some 3rd party horizontal paned widgets listed in the Widget FAQ: http://reality.sgi.com/widgetFAQ/ Ken Lee ----------------------------------------------------------------------------- Subject: 85) TOPIC: TEXT WIDGET ----------------------------------------------------------------------------- Subject: 86) How do XmTextField and a single line XmText widget differ? [Last modified: Oct 94] Answer: XmTextField is designed to be a lightweight, single line text editor. It does not provide as much functionality as does XmText in order to achieve better performance. Thanks to Kevin Till, kev@osf.org ----------------------------------------------------------------------------- Subject: 87) Why does pressing RETURN in a text widget do nothing? This happens using Motif 1.0 when I have a text widget inside a bulletin board (or form) inside a dialog shell. (In Motif 1.1 it is fixed for both text and list widgets.) Answer: In single line mode, pressing the <return> key usually invokes the activate() action, and in multi-line mode, the newline() action. However, whenever a widget is the child of a bulletin board widget which is the child of a dialog shell, the bulletin board forces all of its children to translate <return> to the bulletin board action Return() which is usually associated with the default button of the dialog. To restore the text actions of activate() or newline(), you need to overide the Return() action of the bulletin board. /* declarations */ /* for a single line widget */ char newTrans[] = "<Key>Return : activate()"; /* for a multi line widget */ char newTrans[] = "<Key>Return : newline()"; XtTranslations transTable; /* in executable section */ transTable = XtParseTranslationTable(newTrans); /* after creating but before managing text widget */ XtOverrideTranslations(textWidget, transTable); ----------------------------------------------------------------------------- Subject: 88) Can you reuse the return value from XtParseTranslationTable? [Last modified: Nov 96] Answer: The following is a conversation circa 30 Sep 1996 between Kaleb Keithley (kaleb@x.org) and Tim Behrendsen (tim@a-sis.com, tim@airshields.com>. The latter suggested this appear in the Motif FAQ. B> Can the return value from XtParseTranslationTable be saved TB> off and reused for the lifetime of the application? KK> Yes. TB> Ah! The answer. Thank you. KK> KK> XtVaSetValues(widget, KK> XmNtranslations, XtParseTranslationTable(table), NULL); TB> which implies it's a one-shot deal (otherwise, this would cause TB> a memory leak). KK> No, you can always retrieve them with Xt(Va)GetValues. TB> You can, but if you don't and use the technique to wantonly TB> create and destroy dialogs, it seems you will get a memory TB> leak. KK> That's correct. TB> In fact, what's scary is this technique is used in the Motif TB> FAQ list; I knew I saw it somewhere reasonably authoritative TB> ([approx.] Question 133; code by Dan Heller, O'Reilly and Associates). TB> He does the following: TB> XtOverrideTranslations(bboard, TB> XtParseTranslationTable("<Configure>: resize()")); TB> This has to be unquestionably broken code, if the translation TB> tables are never freed or never reused. Obviously, I can't TB> extract out the table from overridden translations. KK> You can't extract the original translations, that's correct. TB> Come to think of it; how is this handled when translations are TB> parsed in resource files? If I have lots of translation TB> overrides, do they simply burn up space that can't be reused? TB> Does it get burned up over and over as I create widgets that TB> use those translation resources? KK> Yup and yup. ----------------------------------------------------------------------------- Subject: 89) When I add text to a scrolling text widget, how can I get the new text to show? [Last modified: Sept 94] Answer: Use the (fully supported) function XmTextShowPosition: void XmTextShowPosition(w, position) Widget w; XmTextPosition position; where the position is the number of characters from the beginning of the buffer of the text to be displayed. If you don't know how many characters are in the buffer, use XmTextGetLastPosition. position = XmTextGetLastPosition(w) ----------------------------------------------------------------------------- Subject: 90) How do I scroll text to display the most recently added information? [Last modified: Aug 95] Answer: If you're using the XmScrolledText widget, use XmTextSetTopCharacter() or XmTextScroll(). Ken Lee ----------------------------------------------------------------------------- Subject: 91) Does the text widget support 16 bit character fonts? [Last modified: November 92] Answer: R5 has support for 16 bit character sets, and Motif 1.2 uses that. Neither Motif 1.0 nor 1.1 support 16 bit sets. ----------------------------------------------------------------------------- Subject: 92) How can I stop the text widget from echoing characters typed? I need to turn off echo for password input. Answer: Use the XmNmodifyVerifyCallback to tell when input is received. Set the `doit' field in the XmTextVerifyCallbackStruct to False to stop the echo. (In Motif 1.0 this will cause a beep per character: Live with it, because at 1.1 you can turn it off.) Note that password hiding is inherently insecure in X - someone may have an X grab on the keyboard and be reading all characters typed in anyway. Another solution often proposed is to set the foreground and background colours to be the same, effectively hiding the text. This has a major flaw: someone may select the text (triple click the mouse to get the line), and then paste the password into say an xterm with *different* foreground and background colours. This immediately shows the password. ----------------------------------------------------------------------------- Subject: 93) How can I replace characters typed with say a `*'? I want to replace input for password entry. [Last modified: Nov 96] Answer: The solution involves the use of XmNmodifyVerifyCallback and then examining the XmTextVerifyCallbackStruct. The following program from Dan Heller and Paula Ferguson illustrates this: /* Written by Dan Heller and Paula Ferguson. * Copyright 1994, O'Reilly & Associates, Inc. * Permission to use, copy, and modify this program without * restriction is hereby granted, as long as this copyright * notice appears in each copy of the program source code. * This program is freely distributable without licensing fees and * is provided without guarantee or warrantee expressed or implied. * This program is -not- in the public domain. * * 9Sept1996 RAF -- this is a working version, at least under Sol2.4, * using gcc. I only modified check_passwd(). * */ /* password.c -- prompt for a password. All input looks like * a series of *'s. Store the actual data typed by the user in * an internal variable. Don't allow paste operations. Handle * backspacing by deleting all text from insertion point to the * end of text. */ #include <Xm/Text.h> #include <Xm/LabelG.h> #include <Xm/RowColumn.h> #include <ctype.h> void check_passwd(); char *passwd; /* store user-typed passwd here. */ main(argc, argv) int argc; char *argv[]; { Widget toplevel, text_w, rowcol; XtAppContext app; XtSetLanguageProc (NULL, NULL, NULL); toplevel = XtVaAppInitialize (&app, "Demos", NULL, 0, &argc, argv, NULL, NULL); rowcol = XtVaCreateWidget ("rowcol", xmRowColumnWidgetClass, toplevel, XmNorientation, XmHORIZONTAL, NULL); XtVaCreateManagedWidget ("Password:", xmLabelGadgetClass, rowcol, NULL); text_w = XtVaCreateManagedWidget ("text_w", xmTextWidgetClass, rowcol, NULL); XtAddCallback(text_w, XmNmodifyVerifyCallback, check_passwd, NULL); XtAddCallback(text_w, XmNactivateCallback, check_passwd, NULL); XtManageChild (rowcol); XtRealizeWidget (toplevel); XtAppMainLoop (app); } /* check_passwd() -- handle the input of a password. */ void check_passwd(text_w, client_data, call_data) Widget text_w; XtPointer client_data; XtPointer call_data; { char *new; char *oldpasswd; int len; XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *) call_data; if (cbs->reason == XmCR_ACTIVATE) { printf ("4assword: %s0, passwd); return; } if( cbs->text->length > 1 ) { cbs->doit = False; /* don't allow paste operations; make the */ return; /* user type the password! */ } if( cbs->startPos < cbs->endPos ) { /* shrink the password by moving endPos... characters forward to /* the point of deletion */ memmove( &(passwd[cbs->startPos]), &(passwd[cbs->endPos]), strlen(passwd) - cbs->endPos + 1 ); if( cbs->text->length == 0 ) /* then just a delete, not a replace */ return; } new = XtMalloc( cbs->text->length + 1 ); strncpy( new, cbs->text->ptr, cbs->text->length ); /* just the new chars */ new[cbs->text->length]=' '; if( passwd ) { /* open a hole for the new characters, and insert them /* in the proper place */ passwd = XtRealloc( passwd, strlen(passwd) + cbs->text->length + 1 ); memmove( &(passwd[cbs->startPos + cbs->text->length]), &(passwd[cbs->startPos]), strlen(passwd) - cbs->startPos + 1 ); memcpy( &(passwd[cbs->startPos]), new, cbs->text->length ); } else { passwd = new; } memset( cbs->text->ptr, '*', cbs->text->length ); /* makes it all stars */ } Thanks to OM1_JDA@pki-nbg.philips.de (Joerg Danne) for alerting me to updating this code sample. Thanks also to Russell Fink (rfink@polaris.umuc.edu) for providing the Nov. 1996 code update. ----------------------------------------------------------------------------- Subject: 94) How can I make a text widget insensitive without graying out the text? [Last modified: Dec 98] This is mostly a problem in Motif 1.2 and later, since grayed-out text is sometimes difficult to read. Instead of making the widget insensitive, set XmNeditable to false. Ken Lee ----------------------------------------------------------------------------- Subject: 95) How can I best add a large piece of text to a scrolled text widget? [Last modified: Sept 94] [NOTE: This problem is probably only relevant for Motif 1.0 which probably no one is using anymore. If you know this to still be a problem, send mail to kenton@nojunk.rahul.net. I'll probably remove this question otherwise.] In some versions of Motif 1.0 even using XmTextSetString, it insists on adding the text one line at a time, adjusting the scroll bar each time. It looks awful and is slow. Answer: If you don't have this problem, use XmTextSetString to set all of the text in the widget. If you do have this slowdown problem even using XmTextSetString, unmanage the widget, add the text and then manage it again. This may cause the window to blink, but you have to put up with that or switch to a different version of Motif. ----------------------------------------------------------------------------- Subject: 96) How can I get the correct colors for scrolled text widget scrollbars (Sun only)? [Last modified: Nov 97] Answer: Michael Hall <mhall@semy.com> writes: I have found a fix to a bug which is common on SUN platforms. The problem is that the scroll bars on scrolled text widgets are not colored or shaded correctly. scrolledWindowText2 = XtVaCreateManagedWidget("scrolledWindowText2", xmScrolledWindowWidgetClass, form1, XmNscrollBarDisplayPolicy, XmSTATIC, NULL ); runValuesText = XtVaCreateManagedWidget("runValuesText", xmTextWidgetClass, scrolledWindowText2, XmNeditMode, XmMULTI_LINE_EDIT , XmNeditable, FALSE, NULL ); /* workaround a Motif bug - text widget scroll bars are wrong color, and not shaded. */ /* by Michael Hall */ /* just to get background */ junkScroll = XmCreateScrollBar(form1, "junkScroll", NULL, 0); XtVaGetValues(junkScroll, XmNbackground, &junkPixel, NULL); XtVaGetValues(XtParent(runValuesText), XmNchildren, &kids, XmNnumChildren, &numkids, NULL); for (n=0;n<numkids;n++) { if (XmIsScrollBar(kids[n])) { XtVaSetValues(kids[n], XmNbackground, junkPixel, XmNshadowThickness, 30, XmNwidth, 200, XmNheight, 200, NULL); XmChangeColor(kids[n], junkPixel); } } ----------------------------------------------------------------------------- Subject: 97) How can I highlight text in the Text widget? Answer: argv@zipcode.com (Dan Heller) wrote: If you don't need font or color changes, you can do all this using a Text widget very easily [in Motif 1.1, anyway]. loop() { pos = offset_of_pattern_in_text_widget(pattern, text_w); search_len = strlen(pattern); XmTextSetHighlight(text_w, pos, pos+search_len, XmHIGHLIGHT_SELECTED); } There are two choices for highlighting: reverse video (HIGHLIGHT_SELECTED) and underlined (HIGHLIGHT_SECONDARY_SELECTED). Be careful that your users won't confuse your highlights with actual selections! ----------------------------------------------------------------------------- Subject: 98) How can I select all of the text in a widget programmatically? So that some initial text is displayed, but anything typed replaces it. [Last modified: July 95] Answer: XmTextSetSelection(Text1, 0, XmTextGetLastPosition(Text1), event- >xbutton.time); where Text1 is the widget in question (obviously) and event is some event that triggered this call. You can use XtLastTimestampProcessed( display) instead of xbutton.time if you don't happen to have an event pointer handy. Jon A. Christopher (jac8792@tam2000.tamu.edu) writes: I have had difficulty getting this to work as described (even though it agrees with the documentation). I believe that it may be because I usually change the TextField to some value and then try to select it. I haven't looked at the internals of the TextField widget, but it must only select the text if the text hasn't changed since the time specified. Ususally the "LastTimestampProcessed" will be be *before* you modify the text, and the selection is therefore ignored. I'd suggest using the CurrentTime variable. This is an X variable which, if used will make sure that your text is always selected. ----------------------------------------------------------------------------- Subject: 99) Can I customize the pointer cursor or insert position indicator used by the text widget? [Last modified: May 97] Answer: No. These are hard coded. Ken Lee ----------------------------------------------------------------------------- Subject: 100) How can I change colours of text in the Text widget? I want some of the text in one colour, some in another. [Last modified: Feb 98] Answer: In Motif 1.x, you can't. Text stores an ordinary string, and points where `highlights' of various types begin and end. These highlights are all the control you have over components of the text. In the Motif 2.0 CSText widget, XmStrings may be different colors in the same widget. Note, however, that the CSText widget was dropped from Motif 2.1. Ken Lee ----------------------------------------------------------------------------- Subject: 101) How can I change the font of text in the Text widget? I want some of the text in one font, some in another. [Last modified: Feb 98] Answer: You can't in Text (see the previous question). If you wanted readonly text, you could do it by using a label instead. Label uses XmStrings, which can contain multiple character sets in the one string. If you are using Motif 2.0, however, XmStrings are now permitted in CSText widgets, which solves this particular problem. Note, however, that the CSText widget was dropped from Motif 2.1. Ken Lee ----------------------------------------------------------------------------- Subject: 102) Is there an emacs binding for the text widget? Answer: This set is due to Kee Hinckley: *XmText.translations: #override\n\ Ctrl <Key>b: backward-character()\n\ Alt <Key>b: backward-word()\n\ Meta <Key>b: backward-word()\n\ Shift Alt <Key>b: backward-word(extend)\n\ Shift Meta <Key>b: backward-word(extend)\n\ Alt <Key>[: backward-paragraph()\n\ Meta <Key>[: backward-paragraph()\n\ Shift Alt <Key>[: backward-paragraph(extend)\n\ Shift Meta <Key>[: backward-paragraph(extend)\n\ Alt <Key><: beginning-of-file()\n\ Meta <Key><: beginning-of-file()\n\ Ctrl <Key>a: beginning-of-line()\n\ Shift Ctrl <Key>a: beginning-of-line(extend)\n\ Ctrl <Key>osfInsert: copy-clipboard()\n\ Shift <Key>osfDelete: cut-clipboard()\n\ Shift <Key>osfInsert: paste-clipboard()\n\ Alt <Key>>: end-of-file()\n\ Meta <Key>>: end-of-file()\n\ Ctrl <Key>e: end-of-line()\n\ Shift Ctrl <Key>e: end-of-line(extend)\n\ Ctrl <Key>f: forward-character()\n\ Alt <Key>]: forward-paragraph()\n\ Meta <Key>]: forward-paragraph()\n\ Shift Alt <Key>]: forward-paragraph(extend)\n\ Shift Meta <Key>]: forward-paragraph(extend)\n\ Ctrl Alt <Key>f: forward-word()\n\ Ctrl Meta <Key>f: forward-word()\n\ Ctrl <Key>d: kill-next-character()\n\ Alt <Key>BackSpace: kill-previous-word()\n\ Meta <Key>BackSpace: kill-previous-word()\n\ Ctrl <Key>w: key-select() kill-selection()\n\ Ctrl <Key>y: unkill()\n\ Ctrl <Key>k: kill-to-end-of-line()\n\ Alt <Key>Delete: kill-to-start-of-line()\n\ Meta <Key>Delete: kill-to-start-of-line()\n\ Ctrl <Key>o: newline-and-backup()\n\ Ctrl <Key>j: newline-and-indent()\n\ Ctrl <Key>n: next-line()\n\ Ctrl <Key>osfLeft: page-left()\n\ Ctrl <Key>osfRight: page-right()\n\ Ctrl <Key>p: previous-line()\n\ Ctrl <Key>g: process-cancel()\n\ Ctrl <Key>l: redraw-display()\n\ Ctrl <Key>osfDown: next-page()\n\ Ctrl <Key>osfUp: previous-page()\n\ Ctrl <Key>space: set-anchor() ! If you'd like the Delete key to work like backspace instead of deleting ! backwards, add the following definition to the lines above. ! <Key>osfDelete: delete-previous-character()\n\ ! These aren't included because they could intefere with | menu accelerators (or vice versa) ! Alt <Key>p: backward-paragraph()\n\ ! Meta <Key>p: backward-paragraph()\n\ ! Shift Alt<Key>p: backward-paragraph(extend)\n\ ! Shift Meta<Key>p: backward-paragraph(extend)\n\ ! Alt <Key>w: copy-clipboard()\n\ ! Meta <Key>w: copy-clipboard()\n\ ! Ctrl Alt <Key>w: cut-clipboard()\n\ ! Ctrl Meta <Key>w: cut-clipboard()\n\ ! Alt <Key>y: paste-clipboard()\n\ ! Meta <Key>y: paste-clipboard()\n\ ! Alt <Key>f: forward-word()\n\ ! Meta <Key>f: forward-word()\n\ ! Alt <Key>n: forward-paragraph()\n\ ! Meta <Key>n: forward-paragraph()\n\ ! Shift Alt <Key>n: forward-paragraph(extend)\n\ ! Shift Meta <Key>n: forward-paragraph(extend)\n\ ! Shift Alt <Key>f: forward-word(extend)\n\ ! Shift Meta <Key>f: forward-word(extend)\n\ ! Alt <Key>d: kill-next-word()\n\ ! Meta <Key>d: kill-next-word()\n\ ! Alt <Key>h: select-all()\n\ ! Meta <Key>h: select-all()\n\ Similar sets of translations have been suggested by others. ----------------------------------------------------------------------------- Subject: 103) What if I have problems with the backspace/delete keys? [Last modified: Dec 94] Answer: mclarnon@maths.ox.ac.uk (Gerald.McLarnon) writes: I am running a precompiled program based on motif and am having some problems with the backspace/delete keys. Following the instructions of the faq I put th e following lines in my .Xdefaults file *XmText.translations: #override <Key>osfDelete: delete-previous-character() *XmTextField.translations: #override <Key>osfDelete: delete-previous-character() This meant that in dialogue boxes (such as 'Open File') the delete key deleted to the left, but not in the main application window. Any hints for someone who isn't much of an X-pert? David Kaelbling <drk@x.org> replied: There are a couple possibilities. In addition to the precedence of loading resource files (explained in section 2.3 of the X11R5 X Toolkit Intrinsics manual), resource values in the database are chosen based on a "most explicit match" algorithm (i.e. those with the most qualifiers on the left hand side win -- see section 15.2 of the X11R5 Xlib - C Library manual). So if this application's app-defaults file or fallback resources says *Foo*XmText.translations:... that value will be used instead of yours. Find the app-defaults file for your application and look to see if it specifies translations for text widgets in the main application; if it does you'll need to make yours at least as explicit. If the app-defaults file isn't the problem then the application may be hard- wiring the translations. If that's the case you'll probably have to change your virtual key bindings so that the key you think of as osfDelete is really osfBackSpace. You can do that for an individual application by setting its defaultVirtualBindings resource, or for all Motif applications with a $HOME/.motifbind file ("man xmbind" and "man VirtualBindings" give more detail and alternatives). In either case you'll need to specify a complete list of virtual key bindings; there is no equivalent to #override. To find out your current virtual key bindings run "xprop -root | fgrep BINDINGS" and clean up the result. ----------------------------------------------------------------------------- Subject: 104) How can I use a file as the text source for a Text widget? Answer: You can't do it directly like you can with the Athena Text widget. Instead, read the text from the file into a string (all of it!) and then use XmTextSetString. Alternatively, read blocks of characters and add them at the end of the text using XmTextInsertString. The following is an excerpt from Dan Heller's "file_browser.c": /* file_browser.c -- use a ScrolledText object to view the * contents of arbitrary files chosen by the user from a * FileSelectionDialog or from a single-line text widget. */ struct stat statb; /* make sure the file is a regular text file and open it */ if (stat(filename, &statb) == -1 || (statb.st_mode & S_IFMT) != S_IFREG || !(fp = fopen(filename, "r"))) { if ((statb.st_mode & S_IFMT) == S_IFREG) perror(filename); /* send to stderr why we can't read it */ else fprintf(stderr, "%s: not a regular file\n", filename); XtFree(filename); return; } /* put the contents of the file in the Text widget by allocating * enough space for the entire file, reading the file into the * allocated space, and using XmTextFieldSetString() to show the file. */ if (!(text = XtMalloc((unsigned)(statb.st_size+1)))) { fprintf(stderr, "Can't alloc enough space for %s", filename); XtFree(filename); fclose(fp); return; } if (!fread(text, sizeof(char), statb.st_size+1, fp)) fprintf(stderr, "Warning: may not have read entire file!\n"); text[statb.st_size] = 0; /* be sure to NULL-terminate */ /* insert file contents in Text widget */ XmTextSetString(text_w, text); ----------------------------------------------------------------------------- Subject: 105) How can put Text in overstrike mode instead of insert? [Last modified: Mar 95] Answer: (Be sure to read the update after the first answer. This is also a second update which cautions against the approach.) There is no direct way. This was posted by Edmond Pitt (ejp@bohra.cpg.oz) The correct answer to the question is to put the following in a modifyVerify callback, where 'mvcb' is the XmTextVerifyCallbackStruct, and 'overstriking' is defined by you: if (overstriking && mvcb->text->length == 1) { _XmTextDisableRedisplay(w,FALSE); XtCallActionProc(w,"delete-next-character",mvcb->event,0); _XmTextEnableRedisplay(w); } _XmText{Dis,En}ableRedisplay() are XmText{Dis,En}ableRedisplay() in 1.0, but X11R3 has no XtCallActionProc() anyway. For this environment you need my 1.0.3 Text widget patches posted last year & available on request. An update was provided by Ingeborg (inca@osf.org): In 1.2 and later releases, there is an action function toggle-overstrike() which will toggle between overstrike and insert mode. Before 1.2.3, there is no visual difference, and at most one character will get overstruck. In 1.2.3, a block cursor was added as a visual cue to that the widget is in overstrike mode, and the code was fixed to overstrike the actual number of characters input (this makes a difference if you have preediting - for example in japanese). There is no default binding in 1.2, but the recommended key is osfInsert without modifiers. No resource exists. Ed Kaltenbach (kaltenba@ataway.aptec.com) wrote: I was simulating overstrike mode in the Text Field widget by using the delete_next_character solution listed in subject 71. When the software is compiled with Motif 1.2.2, the modifyVerify callback does not get called for the last character when XmNmaxLength is specified. It seems that the check if maxLength has been reached is done before the modifyVerify gets called and it keeps the modifyVerify from being called. Is this a Motif bug? Does anybody have a solution that will work with Versions 1.1 and 1.2 of Motif? Phil Day <phil@cfmu.eurocontrol.be> responded to Ed (and apologized for only sending pseudocode!): I've had the same problem, and for my money it's a bug. My workaround is to make all text widgets (I don't use textfield because of some other problems in the past) have XmNmaxLength > XmNcolumns, so that the modifyVerify callback gets a chance to do its stuff. If you only want to support overstrike for typing, 1 extra charater is enough, but if you want to support cut-and-paste for any length string you need maxLength = 2*columns. In the modifyVerify you have to check the result is < columns. I've tried using the Motif 1.2 support for overstrike, but this just seems to work on a kind of pending-delete and only works for the single charater replacement caes (that's my main argument for calling it a bug). I don't use delete-next-character (I can't remember why just now, but I know I had some problem with it). Instead I have something like the following: modifyVerify() { if (acceptable) XmReplaceText(...) cd->doit = False; // we've just done it, we don't wnat Motif to ! XtVaSetValues (w, XmNverifyBell, False, NULL); // Otherwise we'll get a beep. } valueChanged() { XtVaSetValues (w, XmNverifyBell, True, NULL); // turned off in modifyVerify } Glenn Mandelkern <gmandel@Corp.Megatest.Com> writes about a problem with the above solution. We have been running our software on Sparc 20's, under Motif 1.1 and Motif 1.2, X11R5, Solaris 2.4. Unfortunately, some colleagues and I have found a disturbing side effect when following this suggestion. Calling XtVaSetValues() in the modifyVerifyCallback causes the Text widget to flash. The O'Reilly guides say not to call XtVaSetValues() during text modification callbacks. Motif Volume 6 has this on page 511 and Motif Volume 6A has it on page 496. I myself thought it would be fairly trivial to just switch the bell on and off. But since XtVaSetValues() calls XmText's set_values() method, my guess is that its set_values() does something that causes this. So when you enter characters, the Text widget flashes. It also slows down the performance of the Text widget. You'll see this on a multi-line Text widget, especially with it occupying a full screen with text. If you want to see this, take the editor.c program in Volume 6 or 6A, then add a modifyVerifyCallback to the text_output widget. Then inside that callback, call XtVaSetValues with the XmNverifyBell like above. This is a common "mistake", one which I've done more than once. I remember also that when I did not have the XtVaSetValues() in place, I got the beeps. So now we've reworked the application as follows: 1. The Text widget is initially created with XmNverifyBell set to False. 2. We ring the bell using XBell() when we detect a condition for which we want to veto text modifications. For our application, this provides the wanted feedback and gets rid of the flashes. ----------------------------------------------------------------------------- Subject: 106) How can I make the Delete key do a Backspace? Related question: How can I swap Delete and Backspace? [Last modified: Oct 94] Answer: Put this in your .Xdefaults *XmText.translations: #override <Key>osfDelete: delete-previous-character() Additional information from David Kaelbling <drk@x.org>: You can also supply an arbitrary file name to xmbind (so you can conditionally run xmbind from your .xinitrc file based on the hostname, architecture, xdpyinfo output, or whatever). Some people prefer to use xmodmap to swap the keysyms for all applications, but what you're doing will work fine if you specify all of the virtual key bindings. The current bindings are stored on the root window -- use "xprop -root" and look for a _MOTIF_BINDINGS or _MOTIF_DEFAULT_BINDINGS property. OSF/Motif is also distributed with a "bindings" directory containing all the fallback virtkey binding files. There are several ways to do display-specific customization: make ----------------------------------------------------------------------------- Subject: 107) Can I change the tab stops in the XmText widget? [Last modified: May 95] Answer: No. Ken Lee ----------------------------------------------------------------------------- END OF PART FOUR
Закладки на сайте Проследить за страницей |
Created 1996-2024 by Maxim Chirkov Добавить, Поддержать, Вебмастеру |