nazgul@alfalfa.com (Kee Hinckley) (03/18/91)
> What I actually want to do is set the position of the dialog > (from XmCreatePromptDialog()), but I can't set the position > (Xt ignores my request) > until after the Dialog has been managed, which means > it appears and then moves. > I have XmNdefaultPosition set to False. > So I was trying to map it after positioning it. > So how do you set the position of a dialog before it appears, > or if you can't, how can you do what the original poster wanted? > (R3/1.x) Here's what I do at R4/1.1. It should work in older versions, but you never know. I've posted this code before, but it was buggy as all get out then. This does a bit more than you asked for - it also places stuff at a specified location or relative to the parent window (I usually try for top-right of parent and top-left of child). This is in C++, but it should be easily convertable to C. If you find any bugs or have any questions about it let me know. typedef long OmLocation; #define OmChildCenter 0x0000 #define OmChildRight 0x0001 #define OmChildLeft 0x0002 #define OmChildTop 0x0004 #define OmChildBottom 0x0008 #define OmParentCenter 0x0000 #define OmParentRight 0x0100 #define OmParentLeft 0x0200 #define OmParentTop 0x0400 #define OmParentBottom 0x0800 #define OmCenter 0x0000 #define OmScreenCenter 0x1000 #define OmDontMove 0x2000 // // Structure to pass placement information to the callback if we need to wait // until we are mapped. // typedef struct { Position x, y; Dimension width, height; OmLocation loc; } PlaceInfo; // // Internal placement call. // static void placeWindow(Widget widget, OmLocation loc=OmScreenCenter, Position px=0, Position py=0, Dimension pwidth=0, Dimension pheight=0); // // Callback called on map // static void placeWindowCB(Widget widget, XtPointer p, XtPointer) { PlaceInfo *pi = (PlaceInfo *) p; placeWindow(widget, pi->loc, pi->x, pi->y, pi->width, pi->height); XtRemoveCallback(widget, XmNmapCallback, placeWindowCB, pi); delete pi; } // // A couple handy macros // #define PLRCentered(loc) (! ((loc & OmParentLeft) || (nloc & OmParentRight)) ) #define PTBCentered(loc) (! ((loc & OmParentTop) || (nloc & OmParentBottom)) ) // // Place the window at a particular location relative to its parent's location. // // Note that the position values here are for the parent, not the widget. // static void placeWindow(Widget widget, OmLocation loc, Position px, Position py, Dimension pwidth, Dimension pheight) { Dimension cwidth, cheight, swidth, sheight; Position x, y, origx, origy; Arg args[10]; int i; OmLocation nloc; Boolean moveIt = False; if (loc == OmDontMove) return; // If we aren't realized then we can't place ourselves quite yet, so we set // up a callback for when we are. if (!XtIsRealized(widget)) { PlaceInfo *pi = new PlaceInfo; //printf("No realized, setting a mapCallback\n"); pi->x = px; pi->y = py; pi->width = pwidth; pi->height = pheight; pi->loc = loc; XtAddCallback(widget, XmNmapCallback, placeWindowCB, pi); return; } //printf("PlaceWindow %X: %d x %d +%d +%d\n", loc, px, py, pwidth, pheight); swidth = WidthOfScreen(XtScreen(widget)); sheight = HeightOfScreen(XtScreen(widget)); //printf("Screen = +%d +%d\n", swidth, sheight); //!! We've got to get the kids managed so we can get the right width/height //!! Unfortunately, both of these die in _XmBulletinBoardFOcusMoved - line 2350 /* if (!XtIsRealized(widget)) { XtSetArg(args[0], XmNmappedWhenManaged, False); XtSetValues(widget, args, 1); XtManageChild(widget); //XtRealizeWidget(widget); } */ i = 0; XtSetArg(args[i], XmNwidth, &cwidth); ++i; XtSetArg(args[i], XmNheight, &cheight); ++i; XtGetValues(widget, args, i); //!! Hack to deal with case where dialog hasn't been sized yet (see commented out //!! stuff above) if (cwidth < 50) cwidth = 100; if (cheight < 50) cheight = 100; //printf("Child = +%d +%d\n", cwidth, cheight); // // We try and be smart here. We want to stay on the screen, but the placement // might put us somewhere else. So if we are centered in the axis that doesn't // fit we'll just slide over. But if we were supposed to be on one side, and we // don't fit there, we'll try the other side on the assumption that that's better // than obscuring the application. Note that none of this stuff has been tested // yet, so who knows if it works. But that's the concept. Anyway, if we don't // fit on the other side *either* then we just give up and put ourselves on the // original side, but slide over until we are on screen. // nloc = loc; tryagain: x = px; y = py; if (nloc & OmScreenCenter) { x = swidth / 2; y = sheight / 2; } else { if (nloc & OmParentLeft); else if (nloc & OmParentRight) x = px + pwidth; else x = px + pwidth/2; if (nloc & OmParentTop); else if (nloc & OmParentBottom) y = py + pheight; else y = py + pheight/2; } if (nloc & OmChildLeft); else if (nloc & OmChildRight) x -= cwidth; else x -= cwidth/2; if (nloc & OmChildTop); else if (nloc & OmChildBottom) y -= cheight; else y -= cheight/2; //printf("nloc = %X, x = %d, y = %d\n", nloc, x, y); if (!moveIt) { // Remember these the first time origx = x; origy = y; //printf("origx = %d, origy = %d\n", origx, origy); } // Sanity checks (we try once as is, once modified, and then we go back do the // normal settings and just shift things onto the screen.) if (x < 0 || x+cwidth >= swidth || y < 0 || y+cheight >= sheight) { //printf("Sanity failed: x < 0 || x+cwidth >= swidth || y < 0 || y+cheight >= sheight\n"); giveup: //printf("giveup: "); if (moveIt) { //printf("moveit (reset x(%d) to origx and y(%d) to origy): ", x, y); x = origx; // Tried to change, but it didn't help y = origy; if (x+cwidth >= swidth) x = swidth - cwidth; if (x < 0) x = 0; if (y+cheight >= sheight) y = sheight - cheight; if (y < 0) y = 0; //printf("final x=%d, y=%d\n", x, y); } else { //printf("setting moveIt: "); moveIt = True; // Note that we don't try to move around based on child pos if (x < 0) { // Too far to left //printf("x < 0\n"); if (nloc & OmParentLeft) { // If on parent left nloc &= ~OmParentLeft; // Try righthand side nloc |= OmParentRight; if (nloc & OmChildRight) { nloc &= ~OmChildRight; nloc |= OmChildLeft; } else if (nloc & OmChildLeft) { nloc &= ~OmChildLeft; nloc |= OmChildRight; } //printf("try the right hand siee\n"); } } else if (x+cwidth >= swidth) { // Too far to right //printf("x+cwidth >= swidth\n"); if (nloc & OmParentRight) { // If on parent right nloc &= ~OmParentRight; // Try lefthand side nloc |= OmParentLeft; //printf("try the left hand side\n"); if (nloc & OmChildRight) { nloc &= ~OmChildRight; nloc |= OmChildLeft; } else if (nloc & OmChildLeft) { nloc &= ~OmChildLeft; nloc |= OmChildRight; } } } if (y < 0) { // Too far to top //printf("y < 0\n"); if (nloc & OmParentTop) { // If on parent top nloc &= ~OmParentTop; // Try bottom side nloc |= OmParentBottom; //printf("Try the bottom\n"); if (nloc & OmChildTop) { nloc &= ~OmChildTop; nloc |= OmChildBottom; } else if (nloc & OmChildBottom) { nloc &= ~OmChildBottom; nloc |= OmChildTop; } } } else if (y+cheight >= sheight) { // Too far to bottom //printf("y+cheight >= sheight\n"); if (nloc & OmParentBottom) { // If on parent bottom nloc &= ~OmParentBottom; // Try top side nloc |= OmParentTop; if (nloc & OmChildTop) { nloc &= ~OmChildTop; nloc |= OmChildBottom; } else if (nloc & OmChildBottom) { nloc &= ~OmChildBottom; nloc |= OmChildTop; } //printf("try the top\n"); } } //printf("nloc = %X, loc = %X (!= tryagain, else giveup)\n", nloc, loc); if (nloc != loc) goto tryagain; // Try something different else goto giveup; // Nothing we can do } } //printf("Settled on x = %d and y = %d\n", x, y); XtSetArg(args[0], XmNx, x); XtSetArg(args[1], XmNy, y); XtSetValues(widget, args, 2); } void OmXWindow::placeManage(OmLocation loc, Widget parent) { Widget shell; Position x, y; Dimension width, height; for (shell = widget; shell && !XtIsShell(shell); shell = XtParent(shell)); if (shell && XtIsRealized(parent)) { arglist.add(XmNdefaultPosition, (XtArgVal)False, NULL); XtSetValues(widget, arglist.args, arglist.clear()); arglist.add(XmNwidth, &width, XmNheight, &height, NULL); XtGetValues(parent, arglist.args, arglist.clear()); XtTranslateCoords(parent, 0, 0, &x, &y); placeWindow(widget, loc, x, y, width, height); } manage(); } void OmXWindow::placeManage(OmLocation loc, Position x, Position y) { /*Widget shell; for (shell = widget; shell && !XtIsShell(shell); shell = XtParent(shell)); if (shell) */placeWindow(widget, loc, x, y, 0, 0); manage(); } Alfalfa Software, Inc. | Poste: The EMail for Unix nazgul@alfalfa.com | Send Anything... Anywhere 617/646-7703 (voice/fax) | info@alfalfa.com I'm not sure which upsets me more: that people are so unwilling to accept responsibility for their own actions, or that they are so eager to regulate everyone else's.