[the question of how an application can force some part of itself as the top level window is a FAQ]
How can this be done in ptk?
Win32
The API function needed is (see also [1]):
SetWindowPos(HWND hWnd, // handle to window HWND hWndAfter, // placement order handle int x, int y, // position (horizontal, vertical) int cx, int cy, // size (width, height) UINT uFlags) // positioning flags
The placement order handle can be either another HWND or once of the following constants:
The Flags can be one of a number but for this page probably SWP_NOMOVE (2) and SWP_NOSIZE (1) are likely the most useful. So:
SetWindowPos([winfo id .], HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE)
which turns out to be the code used by XRaiseWindow in win/tkWinWindow.c
[Melissa Schrumpf] recommends the GPLed WinCtl [2] utility, which makes it possible to write
exec WinCtlW.exe -id [wm frame .] topmost &
(or might there be more punctuation in the vicinity of the id?).
Martin Lemburg - 25th February 2002, 13:16 GMT
I found the original topmost package made by John Rosauer in 12.1997. It works only with tcl/tk v.8.0.
The URL is: ftp://ftp.dcade.de/pub/ml/tcl/packages/topmost10.zip [3]
I created a stubs enabled topmost package, usable with tcl/tk 8.1.1 and higher.
The URL is:
ftp://ftp.dcade.de/pub/ml/tcl/packages/topmost20.zip [4]
Usage:
package require topmost 2.0; topmost widget ?boolean?
Much fun!
MPJ - March 9th 2002
Using the topmost source as a guideline I wrote this tcl proc using Ffidl. Its usage is similar to the topmost package except that it does not want a widget name but the window title.
load ffidl05.dll ffidl::callout dll_SetWindowPos {int int int int int int int} int [ffidl::symbol user32.dll SetWindowPos] ffidl::callout dll_GetWindowLong {int int} int [ffidl::symbol user32.dll GetWindowLongA] ffidl::callout dll_FindWindowTitle {int pointer-utf8} int [ffidl::symbol user32.dll FindWindowA] # windowname is based on wm title # state is 1 to set or anything else to reset, empty returns the current state proc topmost {windowname {state ""}} { set hwnd [dll_FindWindowTitle 0 $windowname] if {$hwnd == 0 } { return "Not a valid top window" } set WS_EX_TOPMOST 0x8 set GWL_EXSTYLE -20 set TOPMOST -1 set NOTOPMOST -2 set SWP_NOACTIVATE 0x10 set SWP_NOMOVE 0x2 set SWP_NOSIZE 0x1 set screenwidth [lindex [split [wm geometry .] x+] 0] set screenheight [lindex [split [wm geometry .] x+] 1] set result [expr ([dll_GetWindowLong $hwnd $GWL_EXSTYLE] & $WS_EX_TOPMOST )>>3] if {$state == "" } { return $result } if {$state == 1} { dll_SetWindowPos $hwnd $TOPMOST 0 0 \ $screenwidth $screenheight \ [expr $SWP_NOACTIVATE | $SWP_NOMOVE | $SWP_NOSIZE] } else { dll_SetWindowPos $hwnd $NOTOPMOST 0 0 \ $screenwidth $screenheight \ [expr $SWP_NOACTIVATE | $SWP_NOMOVE | $SWP_NOSIZE] } return [expr ([dll_GetWindowLong $hwnd $GWL_EXSTYLE] & $WS_EX_TOPMOST )>>3] }
Usage:
topmost [wm title .] ?boolean?
MPJ - June 21, 2002
Now that topmost is supported in the Tcl core (8.4b1) for the MsWindows platform you can just use:
wm attributes (window) -topmost 1
The example below will cause the topmost setting to be toggled when the F3 key is pressed.
bind . <F3> "setontop" proc setontop {} {wm attributes . -topmost [expr [wm attributes . -topmost] ^ 1]}
MGS 2003/03/26 - For non-Windows systems, you could something like this:
proc ontop {W boolean} { set bindtags [bindtags $W] set index [lsearch $bindtags bind$W] if { $boolean } { if { $index == -1 } { bindtags $W [linsert $bindtags 0 bind$W] bind bind$W <Visibility> [list ontop:state %W %s] } } else { if { $index != -1 } { bindtags $W [lreplace $bindtags $index $index] bind bind$W <Visibility> {} } } } proc ontop:state {W state} { puts "ontop \[$W\] \[$state\]" if { ![string equal [winfo toplevel $W] $W] } { puts " window \[$W\] is not a toplevel" return } if { ![string equal $state VisibilityUnobscured] } { raise $W } } # demo code toplevel .t ontop .t 1 checkbutton .top \ -text "On Top" \ -variable ontop(.) \ -command "ontop . \$ontop(.)" button .exit -text exit -default active -command exit pack .exit -side bottom -anchor se pack .top -side top -padx 50 -pady 50
which will raise a window whenever it is obscured. But beware, if you have more than one window, you can have multiple windows fighting over who gets to be on top (if they overlap).
TFW - Jan 9, 2003
I find it convienent to add a checkbox to the system menu to toggle always on top on/off.
Related topic:
wm transient $higher_widget $lower_widget
keeps $higher_widget on top of $lower_widget. Sometimes. As DKF explains, "This doesn't actually enforce it, it just gives a strong hint to the window manager (or OS, depending on platform) that the child is an agent acting on behalf of the parent. Most WMs interpret this as meaning keep it on top of its parent and decorate it like a dialog, but not all. However, that's usually good enough anyway."
For more on the subject, see "Modal dialogs".