Updated 2012-12-09 10:40:57 by RLE

Vince wrote: What is the right (x-platform) way to find the size/position of a toplevel window, including all window-manager decorations (so that I can position two windows without their wm borders overlapping)?

Testing on Windows shows that

wm geometry . returns contentswidthxcontentsheight+decorationTop+decorationLeftEdge.

and

winfo rooty . returns contentsTop

winfo rootx . returns contentsLeftEdge

So, we have the (x,y) of the wm decoration from wm geometry, and we can get the titlebar/border height with contentsTop - decorationTop, and the left decoration thickness with contentsLeftEdge - decorationLeftEdge. But how do I get the thickness of the right-edge and bottom-edge decoration? I can assume it's the same as the left edge decoration, I suppose.

Is the above true cross-platform? Is there a better way of doing this? Does it work if the toplevel now has . configure -menu applied?

Peter Newman 22 April 2004: In Centering a window, Martin Lemburg asked a similar question (and got no answer). winfo provides lots of useful information. But it doesn't provide that. But whether that's because

  1. it's impossible to provide that info. in a cross-platform way,
  2. it's un-necessary, because your assumption that it's alway left = right = bottom is always correct, or
  3. winfos authors never though of it, who knows?

On my Windows 95, I've never seen an app that doesn't do this. Nor on any Windows or Linux screen dump I've seen on the Net. Maybe there's some Linux and Mac users out there can tell us if that's true for them. I think you have to assume that it is. And I've never experienced . configure -menu changing this.

Vince adds then, that this proc works for windows:
    proc totalGeometry {{w .}} {
        set geom [wm geometry $w]
        regexp -- {([0-9]+)x([0-9]+)\+([0-9]+)\+([0-9]+)} $geom -> \
          width height decorationLeft decorationTop
        set contentsTop [winfo rooty $w]
        set contentsLeft [winfo rootx $w]
        # Measure left edge, and assume all edges except top are the
        # same thickness
        set decorationThickness [expr {$contentsLeft - $decorationLeft}]

        # Find titlebar and menubar thickness
        set menubarThickness [expr {$contentsTop - $decorationTop}]
        incr width [expr {2 * $decorationThickness}]
        incr height $decorationThickness
        incr height $menubarThickness
        return [list $width $height $decorationLeft $decorationTop]
    }

But can anyone test it on other platforms, please?

MHo 2007-09-21: Some lines in the code above seems to be doubled...?

Lars H: Indeed, it seems to have happened in revision 17 of this page -- cf. http://wiki.tcl.tk/_diff/11291?V=17&D=16#diff0. Most likely not deliberate.

22 apr 2004 dk -- it appears to work under OS X (mac)

Sadly it appears not to work at all under X11. I can't find any way to get the titlebar height under X.

Peter Newman 23 April 2004: Just had a look on MSDN. And it appears to me that, though the Windows API, right from Windows 95, would allow an app. to create a window where 'left border' = 'right border' = 'bottom border' is no longer true, Tk doesn't take advantage of this. Tk appears to restrict itself to rectangular, grey, unskinned/unthemed windows, where 'left border' = 'right border' = 'bottom border'.

So if Tk is a cross-platform app., and it applies that restriction to Windows, then surely it must apply it to other platforms as well.

However, if you're a Linux or Mac user, don't let that stop you from checking out Vince's proc on your machine as well (see above).

Peter Newman 23 April 2004: Another related issue that I remember some Tcl'er pointing out, was that Tk, on Windows (not sure the others), didn't know anything about the taskbar (at the bottom of the screen). So while an app. can find the screen height and width from winfo, it can't find out how high the taskbar is (from winfo).

And from personal experience (on Windows 95), I know that apps that are too big for the screen - and/or that overwrite the taskbar - can cause problems (including crashing either themselves, and/or Windows).

Just assuming a fixed height wasn't a total solution, because the taskbar can be resized by the user (dragging it up and down the screen).

Vince there's a related issue on MacOS/MacOS X -- how to find the size of the system menubar and (on OS X) the size and position of the dock. The menubar is critical, since one never wants to put a window on top of that, and the dock is similar to the Windows taskbar (resizable, etc, also can change to left/right side of window). Note that I've never had a problem with a window on top of the windows task bar causing crashes as suggested above, but I've never used Win95, just WinNT/2000/XP.

MG April 25th 2004 - You can figure out the height of the taskbar in MS Windows (XP home, anyway) by doing something like this...
  proc taskbar {{w .taskBarSize}} {
    catch {destroy $w}
    toplevel $w
    wm state $w zoomed
    update
    set val [expr {[winfo screenheight $w]-[winfo height $w]}]
    destroy $w
    return $val;
  }

  (%) taskbar
  47

mjk: Note, that the above code doesn't check, if the taskbar is on the side of the desktop. It would be wise to check the [expr {[winfo screenwidth $w]-[winfo width $w]}] also.

HE This doesn't give you the height of the taskbar (at least under w2000). It gives you 'height of the taskbar' + 'height of the top decoration of the testwindow'.

EF No it does not but is very close, if you do the following you will get the height of the taskbar, supposing it is at the bottom of the screen:
  proc taskbar {{w .taskBarSize}} {
    catch {destroy $w}
    toplevel $w
    catch {wm attributes -alpha 0.0}
    wm state $w zoomed
    update
    set val [expr {[winfo screenheight $w]-[winfo height $w]-[winfo rooty $w]}]
    destroy $w
    return $val;
  }

Francois Vogel August 31 2005 - Slight improvement for proc totalGeometry from Vince:

I accidentally found out that the regexp from the code above fails to set width height decorationLeft decorationTop if wm geometry returns negative values, which can happen when the widget is partially off-screen.

I replaced this regexp by
  scan $geom "%dx%d+%d+%d" width height decorationLeft decorationTop

and this works well.

APN Alternatively, you can also use TWAPI to retrieve the "usable" desktop area on Windows NT platforms. The function twapi::get_desktop_workarea will return screen area excluding any taskbars and application desktop toolbars.