From: mgc@cray.com (M. G. Christenson)
Newsgroups: comp.lang.tcl
Subject: Re: Re: How to raise window to become top-layer? (and positioning dialogs)
Date: 19 Aug 92 14:37:34 GMT
Reply-To: mgc@cray.com
Organization: Cray Research, Inc.

>> How do I raise a top level window that is covered by other windows
>> to become top-layer? 
>
>There should be a "wm raise" command, and a few others.  I have a list of
>others at home if anybody's interested.
>
>In C you do:  XRaiseWindow(display, window).  Not sure what happens if the
>window is a child of some enclosing window, but this is what I do in
>Xt based programs (on `shell' widgets) & it works fine.
>
>Why does tk not have things like `wm raise' and `wm lower'??  Raise, at
>least, is a very useful thing to have around.  Motif uses it when parenting
>an error/message dialog off a particular window.  It places the dialog
>in the center of the window and raises the whole shebang to front.  It sure
>gets the attention of the user, which was probably the intention of the
>designers.
>
>I have written most of what's necessary for Motif-compliant message and
>error dialogs for TK.  I've even drawn my own copies of the pictures!
>All that's waiting now is to upgrade it to tk2.2 since that has enough
>stuff to make real modal dialogs.  Two are easy (key grabs, and not 
>returning until its ready to), but two problems are not.  This (lack
>of `wm raise') is one problem.  The other is that my first attempt at
>locating the dialog above the center of its parent did not work.  (I called
>`wm rootx', `wm rooty' and whatever gets width/height, and calculated what
>should have been the x/y coords, then did `toplevel ... -geometry ${x}x${y}'
>but this did not help.)
>
>
><- David Herron <david@twg.com> (work) <david@davids.mmdf.com> (home)
><-
><- "Just because I recreate the middle ages on weekends doesn't mean I have to
><- at work." -- me

I have added the following to raise and lower windows (sorry, it's not a patch):

In tkWindow.c:

void
Tk_RaiseWindow(tkwin)
    Tk_Window tkwin;		/* Window to move. */
{
    register TkWindow *winPtr = (TkWindow *) tkwin;

    if (winPtr->window != NULL) {
	XRaiseWindow(winPtr->display, winPtr->window);
	if (!(winPtr->flags & TK_TOP_LEVEL)) {
	    DoConfigureNotify(winPtr);
	}
    }
}

void
Tk_LowerWindow(tkwin)
    Tk_Window tkwin;		/* Window to move. */
{
    register TkWindow *winPtr = (TkWindow *) tkwin;

    if (winPtr->window != NULL) {
	XLowerWindow(winPtr->display, winPtr->window);
	if (!(winPtr->flags & TK_TOP_LEVEL)) {
	    DoConfigureNotify(winPtr);
	}
    }
}

and to main.c:

	/* ARGSUSED */
int
RaiseCmd(tkwin, interp, argc, argv)
    Tk_Window tkwin;			/* Application window. */
    Tcl_Interp *interp;			/* Current interpreter. */
    int argc;				/* Number of arguments. */
    char **argv;			/* Argument strings. */
{
    Tk_Window window;

    if (argc != 2) {
	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
		" window\"", (char *) NULL);
	return TCL_ERROR;
    }
    window = Tk_NameToWindow(interp, argv[1], tkwin);
    if (window == NULL) {
	return TCL_ERROR;
    }
    Tk_RaiseWindow(window, x, y);
    return TCL_OK;
}

	/* ARGSUSED */
int
LowerCmd(tkwin, interp, argc, argv)
    Tk_Window tkwin;			/* Application window. */
    Tcl_Interp *interp;			/* Current interpreter. */
    int argc;				/* Number of arguments. */
    char **argv;			/* Argument strings. */
{
    Tk_Window window;

    if (argc != 2) {
	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
		" window\"", (char *) NULL);
	return TCL_ERROR;
    }
    window = Tk_NameToWindow(interp, argv[1], tkwin);
    if (window == NULL) {
	return TCL_ERROR;
    }
    Tk_LowerWindow(window, x, y);
    return TCL_OK;?
}

in main():

    Tcl_CreateCommand(interp, "lower", LowerCmd, (ClientData) w,
	    (void (*)()) NULL);
    Tcl_CreateCommand(interp, "raise", RaiseCmd, (ClientData) w,
	    (void (*)()) NULL);


The following is the hack I use to position dialogs.  It works with tvtwm,
but I don't know if it will with other window managers.  It should
be called right after creating the dialog box.  Don't do an 'update' before
calling it.

proc position_dialog {name} {
    wm withdraw $name

    update

    set w [winfo width $name]
    set h [winfo height $name]
    set sw [winfo screenwidth $name]
    set sh [winfo screenheight $name]

    wm geometry $name +[expr "($sw - $w)/2"]+[expr "($sh - $h)/2"]

    update

    map $name
}

Note that this requires the map command, which isn't in wish anymore.  To add
it, add to main.c:

    if (argc != 2) {
	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
		" window\"", (char *) NULL);
	return TCL_ERROR;
    }
    window = Tk_NameToWindow(interp, argv[1], tkwin);
    if (window == NULL) {
	return TCL_ERROR;
    }
    Tk_MapWindow(window);
    return TCL_OK;
}

and in main():

    Tcl_CreateCommand(interp, "map", MapCmd, (ClientData) w,
	    (void (*)()) NULL);


Mark