From: snail@lsl.co.uk
Newsgroups: comp.windows.x
Subject: Re: Using XtCreatePopupShell with transient and topLevel shell class
Date: 7 Jan 93 12:26:07 GMT
Organization: Laser-Scan Ltd., Cambridge

In article <1993Jan5.224918.23614@walter.bellcore.com>, cindy@kolob.NoSubdomain.NoDomain (Cindy Lee) writes:
> Hi folks,
> I'm trying to create an application with 2 shells that will enable
> the following 2 window manager functions:
> 1) bringing either window forward in front of the other one
> 2) iconifying BOTH windows
> 
> I'm fiddling with XtCreatePopupShell with class types of
> transientShellWidgetClass and topLevelShellWidgetClass.
> The transient satisfies requirement #2 but not #1.
> The topLevel satisfies requirement #1 but not #2.

We've done this here, except for any amount of shells. First thing is you
should use toplevel or application shells. This satisfies requirement #1.

To satisfy requirement #2 is more complex and requires you to write some code.
Our system is set up such that any shell can iconify/deiconify/withdraw itself
without affecting any other shell, EXCEPT that the very first shell created 
behaves differently. If it is iconised, it then tells all other shells to
iconise themselves, it if is deiconised, it tells all shells to restore
themselves to the state they were in before the first shell was iconised.

This code took a while to write and I'm not going to give it away, quite apart
form the fact it uses some of our collection objects etc. However I'm gonna
give you the basic outline of what you need to do...(to get a system like ours,
then it's simple to change to the way you need)

#1	attach an event handler to every toplevel shell that gets called when
        the shell is iconised/withdrawn/de-iconised.

      XtAddEventHandler(shell_w,                        /* shell        */
                        PropertyChangeMask,             /* iconise      */
                        False,
                        _mmi_iconise_event,             /* callback func*/
                        shell_data);                    /* callback data*/
  
#2
	The callback function should be along these lines:-

static XtCallbackProc _mmi_iconise_event(Widget         w,
                                         XtPointer      client_data,
                                         XPropertyEvent *event)
{
   if (event->type != PropertyNotify)
      return NULL;

   /* We check for a new Property Value and that the property that has  */
   /* changed is Window Manager State 'WM_STATE'. Then we know the      */
   /* iconised state has changed, and we queue the function. This       */
   /* ensures that when the postponed function is called the state info */
   /* about the shell is known.                                         */

   if (event->state == PropertyNewValue)
   {
      string = XGetAtomName(XtDisplay(w), event->atom);
      if (strcmp(string, "WM_STATE") == 0)
	{
		/* check the shell state.. see the FAQ or one of my
		   posting on this. My posting is derived from the FAQ
		   but is I feel a bit easier to follow, last posted about
                   a month ago.

	 	   if the shell is in a state you're interested in then
                   you can make the decision to iconise/deiconise/withdraw
                   or restore the other shells states. If you want to
                   restore the other shells states, then you must track 
                   their states.

                   Also if you want it so that any shell can invoke this
                   then you'll have to check for looping caused by events
                   caused by your iconise/deiconise/withdraw strategy.

		   Note that the shell_data structure I have passed as
                   client_data tells me the shell widget id, what I believe
                   it's state is and what it's previous state is etc,
                   you could add flags to this to prevent the looping
                   I describe. If you need globals, you've done it wrong. 
                */
	}
      XFree(string);
   }
   return NULL;
}

You also need:-

#3 To iconify a window:-	XIconifyWindow()
#4 To deiconify:-          XMapRaised()
#5 To withdraw:-           XWithdrawWindow()
#6 To iconify a withdrawn window:- XMapRaised() followed by XIconifyWindow()
                                doesn't look nice, but if you know better let 
                                me know.

#7 It often helps to remove the event handlers whilst doing the above (to
   prevent loops) and then re-install the event handler afterwards.

#8 When doing a XMapRaised() also call
      XtCallCallbacks(shell_w, XtNpopupCallback, NULL);
   so that the callbacks get called. In X11R4 there was a bug so they didn't
   get called. We still call them in X11R5 - no problem.

#9 You will also notice that dialog shells etc don't get re-mapped to the
   screen when you de-iconify their parent, so you must keep track of all
   dialog shells etc and after the XMapRaised of their parents do the
   following:-

   XtMapWidget(XtParent(dialog_shell_w));
 
That should help you on your way....

Now don't say I don't give you any help :-)
-- 
snail@lsl.co.uk      

"Washing one's hands of the conflict between the powerful and the powerless
 means to side with the powerful, not to be Neutral."
                                                     Quote by Freire.
                                                     Poster by OXFAM.