• Tcl/Tk detecting maximize & restore

    From Mark Summerfield@m.n.summerfield@gmail.com to comp.lang.tcl on Thu Oct 30 09:03:19 2025
    From Newsgroup: comp.lang.tcl

    I'm developing a Tcl/Tk 9 app on Linux with menus and toolbars.
    The toolbars use a grid layout and I have a refresh_toolbars
    method for redoing the layout when the user resizes the
    window:

    bind . <Configure> [callback on_window_state_change]

    oo::define App method on_window_state_change {} {
    if {$WindowWidth > 1} {
    set height [winfo height .]
    set width [winfo width .]
    if {abs($WindowWidth - $width) > $::ICON_SIZE ||
    abs($WindowHeight - $height) > $::ICON_SIZE} {
    set WindowWidth $width
    set WindowHeight $height
    after idle [callback refresh_toolbars]
    }
    }
    }

    This works fine (if a bit flickery), but the binding is
    _not_ called when the maximize/restore button is clicked.

    Can this button be detected?
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Ralf Fassel@ralfixx@gmx.de to comp.lang.tcl on Thu Oct 30 10:19:19 2025
    From Newsgroup: comp.lang.tcl

    * Mark Summerfield <m.n.summerfield@gmail.com>
    | I'm developing a Tcl/Tk 9 app on Linux with menus and toolbars.
    | The toolbars use a grid layout and I have a refresh_toolbars
    | method for redoing the layout when the user resizes the
    | window:

    | bind . <Configure> [callback on_window_state_change]

    --<snip-snip>--
    | This works fine (if a bit flickery), but the binding is
    | _not_ called when the maximize/restore button is clicked.

    | Can this button be detected?

    My guess would be to check the <Map> and <Unmap> events...

    HTH
    R'
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Ralf Fassel@ralfixx@gmx.de to comp.lang.tcl on Thu Oct 30 10:26:07 2025
    From Newsgroup: comp.lang.tcl

    * Mark Summerfield <m.n.summerfield@gmail.com>
    | I'm developing a Tcl/Tk 9 app on Linux with menus and toolbars.
    | The toolbars use a grid layout and I have a refresh_toolbars
    | method for redoing the layout when the user resizes the
    | window:

    | bind . <Configure> [callback on_window_state_change]

    Are you aware that this bindings triggers for all children of "."?
    (The bindtags for each widget includes ".")

    You'll see this if you add the %W field:

    bind . <Configure> {resize %W %w %h}
    pack [label .l -text label] -fill both -expand yes
    pack [button .b -text Button] -fill both -expand yes
    proc resize {window width height} {
    puts "resize window $window width $width height $height"
    }

    - now resize the toplevel
    resize window . width 170 height 123
    resize window .l width 170 height 56
    resize window .b width 170 height 67

    Since I would guess that in your case one invocation is enough, I would
    add %W (and probably also %w %h) and check in the callback that the
    widget is ".", and only react in this case.

    R'
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Mark Summerfield@m.n.summerfield@gmail.com to comp.lang.tcl on Thu Oct 30 10:37:00 2025
    From Newsgroup: comp.lang.tcl

    On Thu, 30 Oct 2025 10:19:19 +0100, Ralf Fassel wrote:

    * Mark Summerfield <m.n.summerfield@gmail.com>
    | I'm developing a Tcl/Tk 9 app on Linux with menus and toolbars.
    | The toolbars use a grid layout and I have a refresh_toolbars
    | method for redoing the layout when the user resizes the
    | window:

    | bind . <Configure> [callback on_window_state_change]

    --<snip-snip>--
    | This works fine (if a bit flickery), but the binding is
    | _not_ called when the maximize/restore button is clicked.

    | Can this button be detected?

    My guess would be to check the <Map> and <Unmap> events...

    HTH
    R'

    Thanks for the advice about %W which I now use.

    I tried binding to Map and Unmap but they are not triggered
    by maximize or restore.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Harald Oehlmann@wortkarg3@yahoo.com to comp.lang.tcl on Thu Oct 30 11:54:06 2025
    From Newsgroup: comp.lang.tcl

    Am 30.10.2025 um 10:03 schrieb Mark Summerfield:
    I'm developing a Tcl/Tk 9 app on Linux with menus and toolbars.
    The toolbars use a grid layout and I have a refresh_toolbars
    method for redoing the layout when the user resizes the
    window:

    bind . <Configure> [callback on_window_state_change]

    oo::define App method on_window_state_change {} {
    if {$WindowWidth > 1} {
    set height [winfo height .]
    set width [winfo width .]
    if {abs($WindowWidth - $width) > $::ICON_SIZE ||
    abs($WindowHeight - $height) > $::ICON_SIZE} {
    set WindowWidth $width
    set WindowHeight $height
    after idle [callback refresh_toolbars]
    }
    }
    }

    This works fine (if a bit flickery), but the binding is
    _not_ called when the maximize/restore button is clicked.

    Can this button be detected?

    I am quite wondering, as normally a resize is implied and the configure
    should be called.

    To find out, I would do a diagnostic bind on all wm related events with
    a puts command.
    AFAIK, on Linux this depends even on the Windows manager.

    Harald


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Mark Summerfield@m.n.summerfield@gmail.com to comp.lang.tcl on Thu Oct 30 11:21:39 2025
    From Newsgroup: comp.lang.tcl

    The problem was in my code. I _am_ getting the resize events
    on maximize/restore.

    And so I've simplified to:

    oo::define App method on_window_state_change window {
    if {$window eq "."} { after 100 [callback refresh_toolbars] }
    }

    But unfortunately this is also triggered by window _move_.

    Is it possible to distinguish between a move event and a resize
    event?

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Ralf Fassel@ralfixx@gmx.de to comp.lang.tcl on Thu Oct 30 13:53:50 2025
    From Newsgroup: comp.lang.tcl

    * Mark Summerfield <m.n.summerfield@gmail.com>
    | On Thu, 30 Oct 2025 10:19:19 +0100, Ralf Fassel wrote:

    | > * Mark Summerfield <m.n.summerfield@gmail.com>
    | > | I'm developing a Tcl/Tk 9 app on Linux with menus and toolbars.
    | > | The toolbars use a grid layout and I have a refresh_toolbars
    | > | method for redoing the layout when the user resizes the
    | > | window:
    | >>
    | > | bind . <Configure> [callback on_window_state_change]
    | >>
    | > --<snip-snip>--
    | > | This works fine (if a bit flickery), but the binding is
    | > | _not_ called when the maximize/restore button is clicked.
    | >>
    | > | Can this button be detected?
    | >
    | > My guess would be to check the <Map> and <Unmap> events...

    | Thanks for the advice about %W which I now use.

    | I tried binding to Map and Unmap but they are not triggered
    | by maximize or restore.

    Ah, sorry, I was on the wrong path, I meant deiconify/iconify for
    Map/Unmap.

    Using fvwm on Opensuse, the Configure event triggers here with maximize/restore:

    # startup
    resize window . width 80 height 60
    # maximize
    resize window . width 1904 height 1120
    # restore
    resize window . width 80 height 60


    Which OS/Window manager are you using?

    R'
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Harald Oehlmann@wortkarg3@yahoo.com to comp.lang.tcl on Thu Oct 30 13:54:58 2025
    From Newsgroup: comp.lang.tcl

    Am 30.10.2025 um 12:21 schrieb Mark Summerfield:
    The problem was in my code. I _am_ getting the resize events
    on maximize/restore.

    And so I've simplified to:

    oo::define App method on_window_state_change window {
    if {$window eq "."} { after 100 [callback refresh_toolbars] }
    }

    But unfortunately this is also triggered by window _move_.

    Is it possible to distinguish between a move event and a resize
    event?

    I don't think so. The configure is called in many other cases, see bind
    manual page. It just says "something changed".

    If you need to distinguish a size change, I would buffer the size and
    compare. Take care, that there are requested sizes and size
    winfo height/reqheight

    Harald

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Ralf Fassel@ralfixx@gmx.de to comp.lang.tcl on Thu Oct 30 13:58:14 2025
    From Newsgroup: comp.lang.tcl

    * Mark Summerfield <m.n.summerfield@gmail.com>
    --<snip-snip>--
    | <Configure> binding
    | But unfortunately this is also triggered by window _move_.

    | Is it possible to distinguish between a move event and a resize
    | event?

    man bind:
    Configure
    A Configure event is sent to a window whenever its size, position,
    or border width changes, and sometimes when it has changed posi-
    tion in the stacking order.

    So I guess you would need to remember the width/height of your toplevel,
    add %w %h to the binding, and detect changes in width/height in the
    binding callback.

    R'
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Mark Summerfield@m.n.summerfield@gmail.com to comp.lang.tcl on Thu Oct 30 19:07:12 2025
    From Newsgroup: comp.lang.tcl

    On Thu, 30 Oct 2025 13:58:14 +0100, Ralf Fassel wrote:

    * Mark Summerfield <m.n.summerfield@gmail.com>
    --<snip-snip>--
    | <Configure> binding
    | But unfortunately this is also triggered by window _move_.

    | Is it possible to distinguish between a move event and a resize
    | event?

    man bind:
    Configure
    A Configure event is sent to a window whenever its size, position,
    or border width changes, and sometimes when it has changed posi-
    tion in the stacking order.

    So I guess you would need to remember the width/height of your toplevel,
    add %w %h to the binding, and detect changes in width/height in the
    binding callback.

    R'

    I finally got it to ignore moves & not to flicker.
    I have to keep track of 3 variables:

    # at startup
    set RefreshingToolbars false
    set MainX [winfo x .]
    set MainWidth [winfo width .]

    oo::define App method refresh_toolbars {} {
    if {$RefreshingToolbars} { return }
    set RefreshingToolbars true
    try {
    update
    set main_x [winfo x .]
    set main_width [winfo width .]
    if {$MainX != $main_x && $MainWidth == $main_width} { return }
    set MainX $main_x
    set MainWidth $main_width
    # grid toolbars user wants to see
    # ...
    } finally {
    set RefreshingToolbars false
    }
    }
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Christian Gollwitzer@auriocus@gmx.de to comp.lang.tcl on Fri Oct 31 08:43:56 2025
    From Newsgroup: comp.lang.tcl

    Am 30.10.25 um 20:07 schrieb Mark Summerfield:
    On Thu, 30 Oct 2025 13:58:14 +0100, Ralf Fassel wrote:

    * Mark Summerfield <m.n.summerfield@gmail.com>
    --<snip-snip>--
    | <Configure> binding
    | But unfortunately this is also triggered by window _move_.

    | Is it possible to distinguish between a move event and a resize
    | event?

    man bind:
    Configure
    A Configure event is sent to a window whenever its size, position,
    or border width changes, and sometimes when it has changed posi-
    tion in the stacking order.

    So I guess you would need to remember the width/height of your toplevel,
    add %w %h to the binding, and detect changes in width/height in the
    binding callback.

    R'

    I finally got it to ignore moves & not to flicker.
    I have to keep track of 3 variables:

    # at startup
    set RefreshingToolbars false
    set MainX [winfo x .]
    set MainWidth [winfo width .]

    oo::define App method refresh_toolbars {} {
    if {$RefreshingToolbars} { return }
    set RefreshingToolbars true
    try {
    update
    set main_x [winfo x .]
    set main_width [winfo width .]
    if {$MainX != $main_x && $MainWidth == $main_width} { return }
    set MainX $main_x
    set MainWidth $main_width
    # grid toolbars user wants to see
    # ...
    } finally {
    set RefreshingToolbars false
    }
    }

    I think you're doing it wrong. Why do you check the configuration state
    of the main window? I would expect that the toolbar is a frame packed
    into the main window like this:


    Main console display active (Tcl8.6.12 / Tk8.6.12)
    (chris) 49 % package req Tk
    8.6.12
    (chris) 50 % frame .toolbar
    .toolbar
    (chris) 51 % pack .toolbar -expand yes -fill x
    (chris) 52 % bind .toolbar <Configure> { puts "It changed %W %w %h" }
    (chris) 53 %

    When I try it, resizing the main window triggers the configuration event
    on the toolbar, moving the main window doesn't (because the tool bar
    itself does not move inside the main window)

    Christian
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Mark Summerfield@m.n.summerfield@gmail.com to comp.lang.tcl on Fri Oct 31 08:01:32 2025
    From Newsgroup: comp.lang.tcl

    On Fri, 31 Oct 2025 08:43:56 +0100, Christian Gollwitzer wrote:

    [snip]
    When I try it, resizing the main window triggers the configuration event
    on the toolbar, moving the main window doesn't (because the tool bar
    itself does not move inside the main window)

    Christian

    Thank you!

    I've now made the code specific to my toolbar & the only flicker
    is when I change width because then of course the toolbar re-grids.

    # at startup
    set ToolbarWidth [winfo width .mf.tb]

    bind .mf.tb <Configure> [callback on_configure %x %y %w %h]
    bind .mf.tb <<ToolbarResizedWidth>> [callback on_toolbar_resized_width]

    oo::define App method on_configure {x y width height} {
    if {$ToolbarWidth != $width} {
    event generate .mf.tb <<ToolbarResizedWidth>>
    set ToolbarWidth $width
    }
    }

    oo::define App method on_toolbar_resized_width {} {
    after 100 [callback refresh_toolbars]
    }

    oo::define App method refresh_toolbars {} {
    if {$RefreshingToolbars} { return }
    set RefreshingToolbars true
    try {
    # re-grid those toolbars the user has chosen to see (if any)
    ...
    # show_toolbars is true if at least one toolbar is chosen
    if {$show_toolbars} {
    grid .mf.tb
    } else {
    grid remove .mf.tb
    }
    } finally {
    set RefreshingToolbars false
    }
    }
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Ralf Fassel@ralfixx@gmx.de to comp.lang.tcl on Sat Nov 1 17:34:40 2025
    From Newsgroup: comp.lang.tcl

    * Mark Summerfield <m.n.summerfield@gmail.com>
    | I've now made the code specific to my toolbar & the only flicker
    | is when I change width because then of course the toolbar re-grids.

    This could probably be improved by only calling the actual callback only
    once. I think you are trying to do that via 'RefreshingToolbars', but
    this does not work as expected (put a 'puts' in the callback to see that
    it triggers *and* works repeatedly).

    I'd cancel any still pending invocation instead:

    - set up a class var after_id to remember the ticket for the 'after' event

    | oo::define App method on_toolbar_resized_width {} {

    after cancel $after_id
    set after_id [after 100 [callback refresh_toolbars]]

    | }

    This way only the final callback is done when you're done resizing the
    window.


    R'

    --- Synchronet 3.21a-Linux NewsLink 1.2