Menu

#1794 TkAqua: CompleteIdlers() is never called for menubar menus

obsolete: 8.5.6
open-accepted
6
2009-08-06
2004-11-17
No

It appears that a menu's -postcommand on Aqua is not
called until after the menu is posted, or else if it
makes changes to the menu they are not reflected until
the next time the menu is posted. A short example:

menu .m
.m add cascade -label Foo -menu .m.f
menu .m.f -postcommand Foo
.m.f add command -label "(Empty)"

set i 1

proc Foo {} {
.m.f delete 0 end
.m.f add command -label "$::i - Foo1"
.m.f add command -label "$::i - Foo2"
.m.f add command -label "$::i - Foo3"
.m.f add command -label "$::i - Foo4"
incr ::i
}

. config -menu .m

Each time the menu is posted, its contents will change
to some so the number indicates how many times it's
been posted. It's expected that the -first- time it's
posted it will show "1 - Foo1" etc. Instead it shows
"(Empty)". It's expected that the second time it's
posted it will show "2 - Foo1" etc. Instead it shows
"1 - Foo1" etc.

Discussion

  • Michael Kirkham

    Michael Kirkham - 2004-11-17

    Logged In: YES
    user_id=498198

    Possibly related or partly responsible: in trying to track
    down the source of the problem, I tried the following script
    that periodically switches the state of a menu entry:

    menu .m
    .m add cascade -label Foo -menu .m.f
    menu .m.f
    .m.f add command -label Bar

    set i 0
    proc toggle {} {
    if {($::i % 2) == 0} {
    set state normal
    } else {
    set state disabled
    }

    .m.f entryconfig Bar -state $state
    puts $state
    after 1000 toggle
    }

    . config -menu .m.f
    after 1000 toggle

    I run this and click on the Foo menu. On Unix (X/Windows)
    and Windows, the Bar entry periodically switches back and
    forth between states and "normal" and "disabled" are written
    to the console. Under Aqua, "normal" and "disabled" are
    periodically written to the console only while the menu is
    unposted. As soon as I click on the menu the output stops
    and the entry does not toggle. It resumes once the menu is
    unposted.

    I'm almost led to believe that the post command is getting
    triggered when the menu is posted but actually gets blocked
    until the menu is unposted, but as far as I can tell so far
    in reading the source code it's not called as a n idle task
    or anything, so I don't see why that would be the case.

     
  • Michael Kirkham

    Michael Kirkham - 2004-11-18

    Logged In: YES
    user_id=498198

    Okay, it turns out the post command actually *is* getting
    called, but the changes to the menus aren't getting applied
    until the next post. Adding to the top of the post command:

    puts "POSTED - $::i"

    Shows that the command is indeed called, but the number
    printed is one less than what's displayed in the actual menu
    entries. So maybe an issue with CompleteIdlers()?

     
  • Michael Kirkham

    Michael Kirkham - 2004-11-18

    Logged In: YES
    user_id=498198

    After noticing that the problem doesn't appear for tk_popup
    posted menus and sprinkling printf()s here and there to see
    what's going on, I've isolated the problem and have a
    workaround, but I'm not sure about a proper fix.

    It turns out that CompleteIdlers() is never called for menu
    bar menus. The reconfiguration is done in the postcommand
    and a couple idle callbacks are set up to reconfigure the
    menus via Tcl_DoWhenIdle(ReconfigureMacintoshMenu, ..), in
    this case in TkpDestroyMenuEntry(), but are not called until
    the menu unposted.

    Adding an "update idletasks" to the end of the postcommand
    proc that reconfigures the menu works around the problem.
    It would seem that a call to CompleteIdlers() needs to be
    made some time after TkPreprocessMenu() is called; I tried
    doing it there before returning and it only catches the
    first of the two ReconfigureMacintoshMenu() callbacks; the
    other seems to get added some time after TkPreprocessMenu()
    returns.

     
  • Daniel A. Steffen

    • priority: 5 --> 7
     
  • Daniel A. Steffen

    • assigned_to: gbjsmith --> wolfsuit
     
  • Daniel A. Steffen

    • summary: menu postcommand not processed before post --> TkAqua: CompleteIdlers() is never called for menu
      bar menus
     
  • Russell Owen

    Russell Owen - 2005-09-22

    Logged In: YES
    user_id=431773

    A presumably-related issue:
    If a pull-down menu contains submenus and if postcommand is used to
    update the submenus (at least if it's used to delete all entries from the
    submenu and add new ones) then the submenus stop working. The
    submenu entries exist and are not grayed out, but they do nothing.

    The only way I've found to make the pull-down menu work again is to
    bring a different toplevel to the top or bring a different application to the
    top. Then all is well. But it's a bizarre hackaround and not something one
    wants to ask users to do.

    A variant of this hack that sort of works in code is:
    Whenever a submenu is changed, do the following:
    - create a toplevel
    - update idletasks
    - destroy the toplevel
    the submenus will fail the first time the pull-down menu is used, but the
    pull-down menu will work after that.

     
  • Daniel A. Steffen

    Logged In: YES
    user_id=90580

    Russell,

    I am looking into the events during menutracking issue ATM, it would be
    useful if you could post a small sample script that exhibits the problem
    you see.

    Thanks

     
  • Daniel A. Steffen

    • assigned_to: wolfsuit --> das
    • summary: TkAqua: CompleteIdlers() is never called for menu
      bar menus --> TkAqua: CompleteIdlers() is never called for menubar menus
    • status: open --> open-accepted
     
  • Daniel A. Steffen

    • priority: 7 --> 6
     
  • Miguel Pasenau

    Miguel Pasenau - 2009-08-04

    Hi, how is the status of this issue?

    i've the problem that submenus, from a menubar, created using the -postcommand do not appear, as Michale Kirkham explained.

    Here is a variant of the script by Michael Kirkham, where the problem mentioned by 'reowen' which i also have: (only the Foo proc is changed):

    menu .m
    .m add cascade -label Foo -menu .m.f
    menu .m.f -postcommand Foo
    .m.f add command -label "(Empty)"

    set i 1

    proc Foo {} {
    .m.f delete 0 end
    .m.f add command -label "$::i - Foo1"
    .m.f add command -label "$::i - Foo2"
    .m.f add command -label "$::i - Foo3"
    .m.f add cascade -label "C $::i" -menu .m.f.c
    if { [ winfo exists .m.f.c]} {
    .m.f.c delete 0 end
    } else {
    menu .m.f.c
    }
    .m.f.c add command -label "C $::i Foo 1"
    .m.f.c add command -label "C $::i Foo 2"
    incr ::i
    }

    . config -menu .m

    The submenus are not created.
    At the moment i disable the post command ( .m.f configure -postcommand "") the submenu options appear. i tried also inserting 'update idletasks' in the Foo procedure but does not work.
    ¿Any suggestions?

    Miguel Pasenau

     
  • Daniel A. Steffen

    Hi Miguel,

    this issue is fixed in the new Cocoa-based TkAqua 8.6 (which has a completely new menu implementation written from scratch) and your script works correctly there.
    Note that a backport of TkAqua Cocoa to Tk 8.5 is also available from http://github.com/das/tcltk/tree/de-carbon-8-5\).

    I am not aware of any solution to this for the obsolete TkAqua Carbon sourcebase, its menu code is exceedingly baroque and very different to other platforms (in particular w.r.t the idle time processing that is at the root of this issue), at this point I have no plans nor time to work on the numerous issues in the old codebase.

     
  • Daniel A. Steffen

    • milestone: 420075 --> obsolete: 8.5.6
     
  • Miguel Pasenau

    Miguel Pasenau - 2009-08-06

    Hi Daniel,

    thanks for the quick reply.
    As the original application i'm working on, has several menus which have this problem, a temporary solution i adopted is to

    - register the widget menu identifier together with the postcomand to be issued;

    - then delete the postcommand of the menus (this step is necessary, otherwise the submenus are not visualized/created when i change them later)

    - update explicitly the menus whenever i need to change them and then create a temporary toplevel window (with geometry 0x0+0+0), update tk, and destroy it.

    With the temporary creation and destruction of this window, the menus are correctly refreshed, although they disappear momentarily. A couple of users which used the application doesn't find it that annoying.

    I'll check the back-port if it can be easily applicable, or wait until 8.6 is released.

    Thanks

    Miguel

     
MongoDB Logo MongoDB