[comp.windows.x] "twm" doesn't handle IconWindowHint sanely

guy@auspex.auspex.com (Guy Harris) (02/03/90)

Yes, I know, the manual page says "twm" doesn't support it.  This is,
however:

	1) rude of it, since it apparently *can* support it (it
	   apparently attempts to handle the IconPixmapHint as well,
	   which the manual page claims it doesn't; methinks the manual
	   page needs cleaning up)

and

	2) incorrect, since it doesn't ignore the IconWindowHint, it
	   just half-heartedly recognizes it - sometimes it works, and
	   sometimes it doesn't.

			  X Window System Bug Report
			    xbugs@expo.lcs.mit.edu


VERSION:
    R4

CLIENT MACHINE and OPERATING SYSTEM:
    all

DISPLAY TYPE:
    all

WINDOW MANAGER:
    twm

AREA:
    twm

SYNOPSIS:
    If an application changes the XA_WM_HINTS property and provides an
    IconWindowHint, "twm" doesn't properly grab (partial) control of the
    icon window, nor does it position it properly.

DESCRIPTION:
    If you run an application that changes the icon window as above -
    for instance, an XView "shelltool", which accepts an escape
    sequences to specify a file from which the icon should be taken
    (note: the current XView has a bug that keeps this from working; a
    fix exists, which I can provide if necessary) - the new icon window
    will *not* be properly treated as an icon window by "twm".  For
    example, if your ".twmrc" is set up to bring up a menu on a button
    press when the cursor is in an icon window, the menu won't appear.

    Furthermore, if you try to change the icon title for an icon whose
    window was supplied by the application, "twm" completely screws up,
    changing the size of the window as would be appropriate were it to
    contain *only* the icon title, but not painting anything in it.

REPEAT BY:
    Run such an application, with such a ".twmrc", and note that the
    menu doesn't pop up.  For the second problem, run an application
    that provides its own icon window and allows you to set the icon
    title - again, the XView "shelltool" has an escape sequence to let
    you set the icon title.

SAMPLE FIX:
    Basically, you change it so that:

	1) if the property changes and an icon window *hasn't* yet been
	   created, it just remembers the property change, and doesn't
	   do anything with the new window (CreateIconWindow will do
	   what's appropriate the first time the window is iconified);

	2) if the property changes and an icon window *has* been
	   created, move the new window atop the old one, unmap or
	   destroy the old one, and set up the new one so that input
	   events will be handled by "twm";

	3) flag windows whose icon window was supplied by the
	   application, and don't do anything if the icon title changes
	   for windows like that.

*** twm.h.dist	Thu Dec 14 11:51:29 1989
--- twm.h	Wed Jan 31 15:30:34 1990
***************
*** 251,256 ****
--- 251,257 ----
      short mapped;		/* is the window mapped ? */
      short auto_raise;		/* should we auto-raise this window ? */
      short forced;		/* has had an icon forced upon it */
+     short icon_not_ours;	/* icon pixmap or window supplied to us */
      short highlight;		/* should highlight this window */
      short iconify_by_unmapping;	/* unmap window to iconify it */
      short iconmgr;		/* this is an icon manager window */

*** events.c.dist	Thu Dec 14 11:52:19 1989
--- events.c	Fri Feb  2 11:41:00 1990
***************
*** 737,745 ****
  	  Tmp_win->group = Tmp_win->wmhints->window_group;
  
  	if (!Tmp_win->forced && Tmp_win->wmhints &&
! 	    Tmp_win->wmhints->flags & IconWindowHint)
! 	  Tmp_win->icon_w = Tmp_win->wmhints->icon_window;
  
  	if (Tmp_win->icon_w && !Tmp_win->forced && Tmp_win->wmhints &&
  	    (Tmp_win->wmhints->flags & IconPixmapHint)) {
  	    if (!XGetGeometry (dpy, Tmp_win->wmhints->icon_pixmap, &JunkRoot,
--- 737,796 ----
  	  Tmp_win->group = Tmp_win->wmhints->window_group;
  
  	if (!Tmp_win->forced && Tmp_win->wmhints &&
! 	    Tmp_win->wmhints->flags & IconWindowHint) {
! 	    if (Tmp_win->icon_w) {
! 	    	int icon_x, icon_y;
  
+ 		/*
+ 		 * There's already an icon window.
+ 		 * Try to find out where it is; if we succeed, move the new
+ 		 * window to where the old one is.
+ 		 */
+ 		if (XGetGeometry (dpy, Tmp_win->icon_w, &JunkRoot, &icon_x,
+ 		  &icon_y, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth)) {
+ 		    /*
+ 		     * Move the new icon window to where the old one was.
+ 		     */
+ 		    XMoveWindow(dpy, Tmp_win->wmhints->icon_window, icon_x,
+ 		      icon_y);
+ 		}
+ 
+ 		/*
+ 		 * If the window is iconic, map the new icon window.
+ 		 */
+ 		if (Tmp_win->icon)
+ 		    XMapWindow(dpy, Tmp_win->wmhints->icon_window);
+ 
+ 		/*
+ 		 * Now, if the old window isn't ours, unmap it, otherwise
+ 		 * just get rid of it completely.
+ 		 */
+ 		if (Tmp_win->icon_not_ours)
+ 		    XUnmapWindow(dpy, Tmp_win->icon_w);
+ 		else
+ 		    XDestroyWindow(dpy, Tmp_win->icon_w);
+ 
+ 		/*
+ 		 * The new icon window isn't our window, so note that fact
+ 		 * so that we don't treat it as ours.
+ 		 */
+ 		Tmp_win->icon_not_ours = TRUE;
+ 
+ 		/*
+ 		 * Now make the new window the icon window for this window,
+ 		 * and set it up to work as such (select for key presses
+ 		 * and button presses/releases, set up the contexts for it,
+ 		 * and define the cursor for it).
+ 		 */
+ 		Tmp_win->icon_w = Tmp_win->wmhints->icon_window;
+ 		XSelectInput (dpy, Tmp_win->icon_w,
+ 		  KeyPressMask | ButtonPressMask | ButtonReleaseMask);
+ 		XSaveContext(dpy, Tmp_win->icon_w, TwmContext, (caddr_t)Tmp_win);
+ 		XSaveContext(dpy, Tmp_win->icon_w, ScreenContext, (caddr_t)Scr);
+ 		XDefineCursor(dpy, Tmp_win->icon_w, Scr->IconCursor);
+ 	    }
+ 	}
+ 
  	if (Tmp_win->icon_w && !Tmp_win->forced && Tmp_win->wmhints &&
  	    (Tmp_win->wmhints->flags & IconPixmapHint)) {
  	    if (!XGetGeometry (dpy, Tmp_win->wmhints->icon_pixmap, &JunkRoot,
***************
*** 812,817 ****
--- 863,871 ----
      }
  
      if (Tmp_win->icon_w == NULL)
+ 	return;
+ 
+     if (Tmp_win->icon_not_ours)
  	return;
  
      Tmp_win->icon_w_width = XTextWidth(Scr->IconFont.font,

*** icons.c.dist	Sun Dec 10 16:20:06 1989
--- icons.c	Thu Feb  1 14:41:33 1990
***************
*** 321,326 ****
--- 321,327 ----
      FB(tmp_win->iconc.fore, tmp_win->iconc.back);
  
      tmp_win->forced = FALSE;
+     tmp_win->icon_not_ours = FALSE;
  
      /* now go through the steps to get an icon window,  if ForceIcon is 
       * set, then no matter what else is defined, the bitmap from the
***************
*** 476,481 ****
--- 477,486 ----
  	{
  	    tmp_win->icon_w = NULL;
  	    tmp_win->wmhints->flags &= ~IconWindowHint;
+ 	}
+ 	else
+ 	{
+ 	    tmp_win->icon_not_ours = TRUE;
  	}
      }
      else