Bring to front multiple windows

Hi!
I'm trying to bring up multiple windows when clicking on one of them (e.g. bring to front Graph1, Graph2 and Graph3 -- with Graph2 being the topmost -- when clicking on Graph2). The only solution I came up so far is to define a window hook for all windows I want to show up together like this:

Function myHook(s)
    STRUCT WMWinHookStruct &s
   
    NVAR clicked = root:clicked
    Variable i
    String WindowList = "Graph1;Graph2;Graph3;"
    String clickedWin = s.winName, currWin
   
   
    if ( s.eventCode == 0 )
        if ( abs(clicked - s.ticks) < 1 )
            return 0
        else
            clicked = s.ticks
        endif
       
        for (i=0; i<ItemsInList(WindowList); i+=1)
            currWin = StringFromList(i, WindowList)
            DoWindow /F $currWin
        endfor
        DoWindow /F $clickedWin
    endif
End

Function DemoWindows()
    Display /N=Graph1; SetWindow Graph1, hook(myHook) = myHook
    Display /N=Graph2; SetWindow Graph2, hook(myHook) = myHook
    Display /N=Graph3; SetWindow Graph3, hook(myHook) = myHook
End


The reason I have to use the global variable ("clicked") is to avoid recursion, that is when clicking on Graph2, Graph1 is going to front, which in turn results in a call of "myHook".

Is there a more elegant way of doing this?

Cheers
A slightly less inelegant solution would be to disable the window hook functions at the start of your event handler and reenable them just before exiting the event handler. But this presupposes that you know which windows to act on.
Window user data is useful for stuff like this. Try this code. Before running DoWindow /F on the another window, it flags it with a named userdata called "UserClicked", then unflags it after. It still looks disappointingly "flickery" on my screen but is definitely less kludgey than using the computer timer to distinguish automated events. If you uncomment the print statements, you can see that each window is only brought to the front once except the originally clicked window. I cannot think of a way around needing that last DoWindow /F call.

Function myHook(s)
    STRUCT WMWinHookStruct &s
    Variable i
    String WindowList = "Graph1;Graph2;Graph3;"
    String clickedWin = s.winName, currWin
    string flaglist = RemoveFromList(s.winName,WindowList)
   
    if ( s.eventCode == 0 )
        if (!stringmatch(GetUserData(S.winName,"","UserClicked"),"N"))  // This should only be true for the first window the user clicked
           
//          print S.winName + " was clicked"
            for (i=0; i<ItemsInList(flaglist); i+=1)                            // run bring to front loop over all other windows
                currWin = StringFromList(i, flaglist)
                SetWindow $currWin, userdata(UserClicked)="N"           // set flag to indicate automatic bring to front already called
                DoWindow /F $currWin                                // bring the rest to the front
            endfor
            for (i=0; i<ItemsInList(flaglist); i+=1)                            // Reset the "UserClicked flag" for the other windows
                currWin = StringFromList(i, flaglist)
                SetWindow $currWin, userdata(UserClicked)="Y"                                  
            endfor
            SetWindow $S.winName, userdata(UserClicked)="N"         // Now suppress current window
//          print S.winName + " final bring to front"
            DoWindow /F $S.winName                                  // Bring to the front again
            SetWindow $S.winName, userdata(UserClicked)="Y"         // Ready for next call

//      else
//          print "Automated call, bringing " + S.winName + " to front"
        endif
    endif
End
 
Function DemoWindows()
    Display /N=Graph1; SetWindow Graph1, hook(myHook) = myHook
    Display /N=Graph2; SetWindow Graph2, hook(myHook) = myHook
    Display /N=Graph3; SetWindow Graph3, hook(myHook) = myHook
End
<\igor>
Recently I had a similar challenge when I needed to bring up projections when selecting a broadband transient absorption spectrum. It seemed doable, because the window names of the projections were just as the parent spectrum, just a suffix was added. So the hook could be general.

However, Dowindow/F is a bit too powerful, it not only brings a window to the front, but also activates it.

The simple solution is put everything else behind it! Just use Dowindow/B inside a for-loop over the items of WinList. Import is the beginning, end and direction of the loop. And exclude the one you need to keep on top. Here's an example (I didn't run it, but it gets the point across):

Function Familyontop(s)
    STRUCT WMWinHookStruct &s
    if(s.eventCode==0)  // eventcode 0 = activate
        String Swin=s.winName//get name of window
        String Swindowstack=winlist("*",";","WIN:7,VISIBLE:1"),Snu // Which windows are on top?
        Variable Vgver=WhichListItem(Swin+"_ver",Swindowstack) // Where is the cousin with suffix "_ver"?
       
        String Sdeep=StringFromList(Vgver,Swindowstack,";")  // What is this cousin called?  
       
        For(n=Vgver-1;n>=0;n-=1)    // Loop over all graphs, tables and layouts above the graph
            Snow=StringFromList(n,Swindowstack,";") // Current graph to slide under the cousin
            dowindow /B=$Vgver $Snow  // slide below graph of interest
        endfor

        return 1
    endif
    return 0    // Zorgt dat Igor ook nog hotkeys verwerkt.
End
Thanks for the fast replies!

Just to close this thread and if anybody has a similar problem, I ended up with this solution:

Function myHook(s)
    STRUCT WMWinHookStruct &s
   
    Variable i
    String WindowList = "Graph1;Graph2;Graph3;"
   
    if ( s.eventCode == 0 )
        WindowList = RemoveFromList(s.winName, WindowList)
        for (i=0; i<ItemsInList(WindowList); i+=1)
            String currWin = StringFromList(i, WindowList)
            DoWindow /B=$s.winName $currWin
        endfor
    endif
End
 
Function DemoWindows()
    Display /N=Graph1; SetWindow Graph1, hook(myHook) = myHook
    Display /N=Graph2; SetWindow Graph2, hook(myHook) = myHook
    Display /N=Graph3; SetWindow Graph3, hook(myHook) = myHook
End


The window that is clicked on is brought to front automatically (which can't be prevented anyway) and all other windows that should go to front are brought to the background just behind the topmost window.

Cheers