wm maxsize . 1000 1000

frame .f -relief raised -borderwidth 2

button .f.b -text {Quit} -command {exit 0}

button .f.r -text {Rescan} -command {InfoWidgetTreeRead [xaccess xwinroot -widget .] 10 10}

button .f.p -text {Reparent} -command {
  if {"[.f.i get]" != ""} {
    xaccess eventreparent -window [.f.i get] -parentwidget .r
  }}

button .f.c -text {Configure} -command {
  if {"[.f.i get]" != ""} {
    xaccess eventconfigure -window [.f.i get] -width [winfo width .r] -height [winfo height .r] -x 0 -y 0 -borderwidth 0
  }}

button .f.m -text {Map} -command {
  if {"[.f.i get]" != ""} {
    xaccess eventmap -window [.f.i get]
  }}

button .f.u -text {Unmap} -command {
  if {"[.f.i get]" != ""} {
    xaccess eventunmap -window [.f.i get]
  }}

label .f.l -text {Window id:}

entry .f.i

label .m -text "Reparented windows go here:" -relief raised

frame .g -relief raised -borderwidth 2

canvas .g.c -xscrollcommand {.g.h set} -yscrollcommand {.g.v set} -confine 1

scrollbar .g.h -command {.g.c xview} -orient horizontal

scrollbar .g.v -command {.g.c yview}

frame .r -relief raised -borderwidth 2 -width 10 -height 100

pack append .f \
            .f.b {left} \
            .f.r {left} \
            .f.p {left} \
            .f.c {left} \
            .f.m {left} \
            .f.u {left} \
            .f.l {left} \
            .f.i {left fill expand}

pack append .g \
            .g.h {bottom fill} \
            .g.v {right fill} \
            .g.c {top fill expand}

pack append . \
            .f {top fill} \
            .g {top fill expand} \
            .m {top fill} \
            .r {top fill expand}

update
set xfMisc(windowTreeRoot) [xaccess xwinroot -widget .]
set xfMisc(windowTreeY) 10

##########
# Procedure: InfoWidgetTreeRead
# Description: update the widget tree in a canvas
# Arguments: xfWindow - the current window
#            xfX - current X offset
#            xfY - current Y offset
# Returns: none
# Sideeffects: none
##########
proc InfoWidgetTreeRead {xfWindow xfX xfY} {
  global xfMisc
 
  if {"$xfWindow" == "$xfMisc(windowTreeRoot)"} {
    set xfMisc(windowTreeY) 10
    foreach xfCounter [.g.c find all] {
      .g.c delete $xfCounter
    }
  }
  
  set item [.g.c create rectangle $xfX $xfMisc(windowTreeY) [expr $xfX+40] [expr $xfMisc(windowTreeY)+40] -fill black -tag $xfWindow]
  .g.c bind $item <Button-1> ".f.i delete 0 end; .f.i insert 0 $xfWindow"

  set itemText [.g.c create text [expr $xfX+50] [expr $xfMisc(windowTreeY)+30] -text "$xfWindow (0x[format %lx $xfWindow]) = [xaccess xwinname -windowid $xfWindow]" -anchor sw -tag $xfWindow]

  if {"$xfWindow" != "$xfMisc(windowTreeRoot)"} {
    set itemLine [.g.c create line $xfX [expr $xfMisc(windowTreeY)+20] [expr $xfX-30] [expr $xfMisc(windowTreeY)+20] [expr $xfX-30] [expr $xfY-10]]
  }

  incr xfMisc(windowTreeY) 50
  set xfY $xfMisc(windowTreeY)
  foreach xfCounter [xaccess xwinchilds -window $xfWindow] {
    InfoWidgetTreeRead $xfCounter [expr $xfX+50] $xfY
  }

  if {"$xfWindow" == "$xfMisc(windowTreeRoot)"} {
    set xfBBox [.g.c bbox all]
    .g.c config -scrollregion "0c 0c [expr [lindex $xfBBox 2]+20] [expr [lindex $xfBBox 3]+20]"
  }
}

InfoWidgetTreeRead [xaccess xwinroot -widget .] 10 10

# eof
