[comp.windows.x] Active icons for X11R4 xterm

karl_kleinpaste@cis.ohio-state.edu (09/28/90)

X11R4 xterm lost X10R4 xterm 6.6B's capability to use active icons,
that is, an "icon" which is actually a smallified xterm window that
occupies the icon position on the screen, but which allows I/O and is
very useful to some of us who keep a herd of xterms around for a
variety of reasons.  We have made the following changes to
X/mit/clients/xterm to recreate this capability in X11R4.

Please note: These changes are not what we'd call complete.  There are
bugs and glitches which we haven't addressed.  See the BUGS section of
the modified xterm.man for details.

The short version of using the modified xterm is
	1 new action
		active-icon()	Toggles normal/active-icon state.
	3 new options
		-I	start initially active-iconic.
		-A	autowarp to window center on active-deiconify.
		-FN fn	font name for use in active icon, default "nil2."
	3 new resources
		Name			Default
		startActiveIcon		false
		warpActiveIcon		false
		fontActiveIcon		nil2

We now use the following in .X11defaults:

XTerm*fontActiveIcon:           nil2
XTerm*warpActiveIcon:           true
XTerm*startActiveIcon:          true
XTerm*VT100.Translations:       #override \n\
        <Key>F1:                set-vt-font(1) set-scrollbar(off) \n\
        <Key>F2:                set-vt-font(2) set-scrollbar(on) \n\
        <Key>F3:                set-vt-font(3) set-scrollbar(on) \n\
        <Key>F4:                set-vt-font(4) set-scrollbar(on) \n\
        <Key>F5:                set-scrollbar(toggle) \n\
        <Key>F6:                set-vt-font(d) set-scrollbar(on) \n\
        <Key>F7:                active-icon() \n\
        Shift<Btn1Down>:        select-start() \n\
        Shift<Btn1Motion>:      select-extend() \n\
        Shift<Btn2Down>:        ignore() \n\
        Shift<Btn2Up>:          insert-selection(PRIMARY,CUT_BUFFER0) \n\
        Shift<Btn3Down>:        start-extend() \n\
        Ctrl<Btn1Down>:         popup-menu(mainMenu) \n\
        Ctrl<Btn2Down>:         popup-menu(vtMenu) \n\
        Ctrl<Btn3Down>:         popup-menu(fontMenu) \n\
        <BtnDown>:              active-icon()

This allows any normal unmodified button hit to active-(de)iconify,
while the cut/paste functions have been pushed onto Shifted hits.

These changes were mailed to xbugs@expo.lcs.mit.edu a short while ago.
The changes are to X11R4 with fixes through #14 applied.

Enjoy,
--Terri
--Karl

diff -c xterm.old/charproc.c xterm.new/charproc.c
*** xterm.old/charproc.c	Thu Sep 27 14:39:53 1990
--- xterm.new/charproc.c	Fri Sep 21 09:12:14 1990
***************
*** 114,119 ****
--- 114,123 ----
  #define XtNtiteInhibit		"titeInhibit"
  #define	XtNvisualBell		"visualBell"
  #define XtNallowSendEvents	"allowSendEvents"
+ /* active icon hack */
+ #define XtNstartActiveIcon	"startActiveIcon"
+ #define XtNwarpActiveIcon	"warpActiveIcon"
+ #define XtNfontActiveIcon	"fontActiveIcon"
  
  #define XtCAlwaysHighlight	"AlwaysHighlight"
  #define	XtCC132			"C132"
***************
*** 145,150 ****
--- 149,158 ----
  #define XtCTiteInhibit		"TiteInhibit"
  #define	XtCVisualBell		"VisualBell"
  #define XtCAllowSendEvents	"AllowSendEvents"
+ /* active icon hack */
+ #define XtCStartActiveIcon	"StartActiveIcon"
+ #define XtCWarpActiveIcon	"WarpActiveIcon"
+ #define XtCFontActiveIcon	"FontActiveIcon"
  
  #define	doinput()		(bcnt-- > 0 ? *bptr++ : in_put())
  
***************
*** 170,175 ****
--- 178,193 ----
  extern int scrtable[];
  extern int scstable[];
  
+ /*
+  * Active Icon save variables.
+  */
+ extern int xterm_savex, xterm_savey;     /* (x,y) coords for window/icon     */
+ int xterm_pcount = 0;                    /* param count for saved font state */
+ char nil2name[]         = "nil2";        /* name of the default icon font    */
+ char *xterm_fontsave[3]                  /* more font state information      */
+     = { " ", (char *) NULL, (char *) NULL };
+ char *t_fontsave[3]                      /* temp for call to HandleSetFont   */
+     = { " ", (char *) NULL, (char *) NULL };
  
  /* event handlers */
  extern void HandleKeyPressed(), HandleEightBitKeyPressed();
***************
*** 190,195 ****
--- 208,214 ----
  extern void HandleScrollBack();
  extern void HandleCreateMenu(), HandlePopupMenu();
  extern void HandleSetFont();
+ extern void HandleActiveIcon();
  extern void SetVTFont();
  
  /*
***************
*** 288,293 ****
--- 307,313 ----
      { "tek-page",		HandleTekPage },
      { "tek-reset",		HandleTekReset },
      { "tek-copy",		HandleTekCopy },
+     { "active-icon",		HandleActiveIcon },
  };
  
  static XtResource resources[] = {
***************
*** 414,419 ****
--- 434,450 ----
  {XtNallowSendEvents, XtCAllowSendEvents, XtRBoolean, sizeof(Boolean),
  	XtOffset(XtermWidget, screen.allowSendEvents),
  	XtRBoolean, (caddr_t) &defaultFALSE},
+ /* active icon hack */
+ {XtNstartActiveIcon, XtCStartActiveIcon, XtRBoolean, sizeof(Boolean),
+         XtOffset(XtermWidget, screen.startActiveIcon),
+         XtRBoolean, (caddr_t) &defaultFALSE},
+ {XtNwarpActiveIcon, XtCWarpActiveIcon, XtRBoolean, sizeof(Boolean),
+         XtOffset(XtermWidget, screen.warpActiveIcon),
+         XtRBoolean, (caddr_t) &defaultFALSE},
+ {XtNfontActiveIcon, XtCFontActiveIcon, XtRString, sizeof(char *),
+         XtOffset(XtermWidget, screen.fontActiveIcon),
+         XtRString, (caddr_t) "nil2"},
+ 
  {"font1", "Font1", XtRString, sizeof(String),
  	XtOffset(XtermWidget, screen.menu_font_names[fontMenu_font1]),
  	XtRString, (caddr_t) NULL},
***************
*** 480,486 ****
--- 511,531 ----
  	register unsigned char *cp;
  	register int row, col, top, bot, scstype;
  	extern int bitset(), bitclr(), finput(), TrackMouse();
+ /* active icon hack (temp variables) */
+ 	Window root;
+ 	int temp_savex, temp_savey, junk;
  
+ /* active icon hack (code to start active iconic if requested) */
+ 	screen->now_iconic = FALSE;
+ 	if (screen->startActiveIcon) {
+ 	    XGetGeometry(XtDisplay(term), XtWindow(XtParent(term)), &root, 
+ 			 &temp_savex, &temp_savey, &junk, &junk, &junk, &junk);
+ 	    HandleActiveIcon(XtParent(term), (XEvent *) NULL,
+ 			     (char **) NULL, 0);
+ 	    xterm_savex = temp_savex;
+ 	    xterm_savey = temp_savey;
+ 	}
+ 
  	if(setjmp(vtjmpbuf))
  		parsestate = groundtable;
  	for( ; ; ) {
***************
*** 1876,1882 ****
  {
  	register TScreen *screen = &term->screen;
  	register int i;
! 	
  	if (!screen->Vshow) {
  	    XtRealizeWidget (term->core.parent);
  	    set_vt_visibility (TRUE);
--- 1921,1927 ----
  {
  	register TScreen *screen = &term->screen;
  	register int i;
! 
  	if (!screen->Vshow) {
  	    XtRealizeWidget (term->core.parent);
  	    set_vt_visibility (TRUE);
***************
*** 1901,1906 ****
--- 1946,1952 ----
  	for( ; i > 0 ; i--)
  		*bptr++ = *Tbptr++;
  	bptr = buffer;
+ 
  	if(!setjmp(VTend))
  		VTparse();
  	HideCursor();
***************
*** 2037,2042 ****
--- 2083,2093 ----
     new->screen.pointer_cursor = request->screen.pointer_cursor;
     new->screen.eight_bits = request->screen.eight_bits;
     new->screen.allowSendEvents = request->screen.allowSendEvents;
+ /* active icon hack */
+    new->screen.startActiveIcon = request->screen.startActiveIcon;
+    new->screen.warpActiveIcon = request->screen.warpActiveIcon;
+    new->screen.fontActiveIcon = request->screen.fontActiveIcon;
+ 
     new->misc.titeInhibit = request->misc.titeInhibit;
     for (i = 0; i < NMENUFONTS; i++) {
         new->screen.menu_font_names[i] = request->screen.menu_font_names[i];
***************
*** 2663,2669 ****
--- 2714,2786 ----
      return;
  }
  
+ /*
+  * Active Icon Hack...
+  * Implemented as a window move function
+  * which swaps the position of the "icon"
+  * position with the "open" position.
+  *
+  * This is grotesque code.
+  *
+  * Guilty parties: Terri Watson & Karl Kleinpaste,
+  * who clearly have no shame whatever.  X10 lives!  X sucks!
+  */
  
+ 
+ void HandleActiveIcon(w, event, params, param_count)
+     Widget w;
+     XEvent *event;		/* unused */
+     String *params;		/* unused */
+     Cardinal *param_count;	/* unused */
+ {
+     TScreen *screen = &term->screen;
+     int i;
+     short savex, savey;
+     int tx, ty;
+     static int ScrollBar = 0;
+     Window root, root2;
+     unsigned int junk;
+ 
+     XtTranslateCoords(XtParent(term), 0, 0, &savex, &savey);
+     XGetGeometry(XtDisplay(term), XtWindow(XtParent(term)), &root, &tx, &ty,
+ 		 &junk, &junk, &junk, &junk);
+     if (! screen->now_iconic) {
+ 	if (!LoadNewFont(screen, screen->fontActiveIcon, (char *) NULL, True, 0)) {
+ 	    Bell();
+ 	    return;
+ 	}
+ 	ScrollBar = screen->scrollbar;
+ 	ScrollBarOff(screen);
+     }
+     XtMoveWidget(XtParent(term), xterm_savex, xterm_savey);
+     xterm_savex = savex-tx;
+     xterm_savey = savey-ty;
+     if (screen->now_iconic) {
+ 	/* We have to pass a copy of xterm_fontsave to HandleSetFont. */
+ 	t_fontsave[0][0] = xterm_fontsave[0][0];
+ 	for (i = 1; i < 3; i++) {
+ 	    if (t_fontsave[i]) {
+ 		free(t_fontsave[i]);
+ 	    }
+ 	    if (xterm_fontsave[i]) {
+ 		if (t_fontsave[i] = malloc(strlen(xterm_fontsave[i])+1)) {
+ 		    strcpy(t_fontsave[i], xterm_fontsave[i]);
+ 		}
+ 	    }
+ 	}
+ 	if (ScrollBar)
+ 	    ScrollBarOn(term, FALSE, FALSE);
+ 	HandleSetFont(w, event, t_fontsave, &xterm_pcount);
+ 	if (screen->warpActiveIcon)
+ 	    XWarpPointer(XtDisplay(term), None, XtWindow(XtParent(term)),
+ 			 0,0,0,0,
+ 			 (int)(XtParent(term)->core.width/2 - 1),
+ 			 (int)(XtParent(term)->core.height/2 - 1));
+     }
+     screen->now_iconic = (! screen->now_iconic);
+ }
+ 
+ 
  /* ARGSUSED */
  void HandleSetFont(w, event, params, param_count)
      Widget w;
***************
*** 2702,2716 ****
--- 2819,2846 ----
  	    Bell();
  	    return;
  	}
+ 
+ 	xterm_fontsave[0][0] = params[0][0];
+ 	  
  	switch (*param_count) {		/* assign 'em */
  	  case 3:
  	    name2 = params[2];
+ 	    if (xterm_fontsave[2])
+ 		free(xterm_fontsave[2]);
+ 	    if (xterm_fontsave[2]=malloc(strlen(name2)+1))
+ 	        strcpy(xterm_fontsave[2], name2);
  	    /* fall through */
  	  case 2:
  	    name1 = params[1];
+ 	    if (xterm_fontsave[1])
+ 		free(xterm_fontsave[1]);
+ 	    if (xterm_fontsave[1]=malloc(strlen(name1)+1))
+ 	        strcpy(xterm_fontsave[1], name1);
  	    break;
  	}
      }
+ 
+     xterm_pcount = *param_count;
  
      SetVTFont (fontnum, True, name1, name2);
  }
diff -c xterm.old/main.c xterm.new/main.c
*** xterm.old/main.c	Thu Sep 27 14:41:35 1990
--- xterm.new/main.c	Thu Sep 27 14:59:12 1990
***************
*** 308,313 ****
--- 308,318 ----
  char *ProgramName;
  Boolean sunFunctionKeys;
  
+ /*
+  * Active icon hack - (x,y) coords & are we iconic flag
+  */
+ int xterm_savex = 0, xterm_savey = 0;
+ 
  static struct _resource {
      char *xterm_name;
      char *icon_geometry;
***************
*** 424,429 ****
--- 429,438 ----
  {"-rv",		"*reverseVideo",XrmoptionNoArg,		(caddr_t) "on"},
  {"+rv",		"*reverseVideo",XrmoptionNoArg,		(caddr_t) "off"},
  {"-w",		".borderWidth", XrmoptionSepArg,	(caddr_t) NULL},
+ /* active icon hack */
+ {"-I",		"*startActiveIcon", XrmoptionNoArg,	(caddr_t) "on"},
+ {"-A",		"*warpActiveIcon",  XrmoptionNoArg,	(caddr_t) "on"},
+ {"-FN",		"*fontActiveIcon",  XrmoptionSepArg,	(caddr_t) NULL},
  };
  
  static struct _options {
***************
*** 440,445 ****
--- 449,457 ----
  { "-bw number",            "border width in pixels" },
  { "-fn fontname",          "normal text font" },
  { "-iconic",               "start iconic" },
+ { "-Iconic",		   "start active-iconic" },
+ { "-Autowarp",		   "autowarp to window center on active-deiconify" },
+ { "-FN icon-fontname",	   "active icon text font"},
  { "-name string",          "client instance, icon, and title strings" },
  { "-title string",         "title string" },
  { "-xrm resourcestring",   "additional resource specifications" },
***************
*** 699,704 ****
--- 711,722 ----
  	    args[1].name = XtNiconY;
  	    XGeometry(XtDisplay(toplevel), scr, resource.icon_geometry, "",
  		      0, 0, 0, 0, 0, &ix, &iy, &junk, &junk);
+ 	    /*
+ 	     * Get initial active icon locations.
+ 	     */
+ 	    xterm_savex = ix;
+ 	    xterm_savey = iy;
+ 
  	    args[0].value = (XtArgVal) ix;
  	    args[1].value = (XtArgVal) iy;
  	    XtSetValues( toplevel, args, 2);
diff -c xterm.old/ptyx.h xterm.new/ptyx.h
*** xterm.old/ptyx.h	Thu Sep 27 14:42:45 1990
--- xterm.new/ptyx.h	Fri Sep 21 08:55:46 1990
***************
*** 264,269 ****
--- 264,274 ----
  	int		scrolllines;	/* number of lines to button scroll */
  	Boolean		scrollttyoutput; /* scroll to bottom on tty output */
  	Boolean		scrollkey;	/* scroll to bottom on key	*/
+ /* active icon hack */
+ 	Boolean		startActiveIcon; /* start in active icon mode */
+ 	Boolean		warpActiveIcon;	/* warp cursor when de-iconifying */
+ 	Boolean		now_iconic;     /* are we currently active iconic? */
+ 	char 		*fontActiveIcon; /* active icon fontname */
  	
  	ScrnBuf		buf;		/* screen buffer (main)		*/
  	ScrnBuf		allbuf;		/* screen buffer (may include
diff -c xterm.old/xterm.man xterm.new/xterm.man
*** xterm.old/xterm.man	Thu Sep 27 14:48:36 1990
--- xterm.new/xterm.man	Thu Sep 27 14:43:33 1990
***************
*** 364,369 ****
--- 364,380 ----
  .B \-iconic
  This option indicates that \fIxterm\fP should ask the window manager to 
  start it as an icon rather than as the normal window.
+ .TP 8
+ .B \-Iconic
+ This option indicates that \fIxterm\fP should start up in active-icon mode.
+ .TP 8
+ .B \-Autowarp
+ This option indicates that \fIxterm\fP should autowarp the cursor to
+ the window's center when performing the active-icon() function.
+ .TP 8
+ .B \-FN \fIfont\fP
+ This option specifies the font to be used for displaying text in the
+ active icon.  The default is \fInil2\fP.
  .SH RESOURCES
  The program understands all of the core X Toolkit resource names and
  classes as well as:
***************
*** 396,401 ****
--- 407,423 ----
  .B "sunFunctionKeys (\fPclass\fB SunFunctionKeys)"
  Specifies whether or not Sun Function Key escape codes should be generated for
  function keys instead of standard escape sequences.
+ .TP 8
+ .B "startActiveIcon (\fPclass\fB StartActiveIcon)"
+ Specifies whether or not \fIxterm\fP should start up in active-icon mode.
+ .TP 8
+ .B "warpActiveIcon (\fPclass\fB WarpActiveIcon)"
+ Specifies whether or not \fIxterm\fP should autowarp the cursor to the
+ window's center when performing the active-icon() function.
+ .TP 8
+ .B "fontActiveIcon (\fPclass\fB FontActiveIcon)"
+ Specifies the name of the font to be used for displaying text in the
+ active icon.  The default is \fInil2\fP.
  .\".in -1in
  .sp
  .PP
***************
*** 1336,1341 ****
--- 1358,1368 ----
  in \fIvtMenu\fP and the \fBvtshow\fP and \fBtekhide\fP entries in 
  \fItekMenu\fP.
  .TP 8
+ .B "active-icon()"
+ This action causes \fIxterm\fP to toggle its state between normal and
+ active-icon.  If the -Autowarp option was provided, the mouse cursor
+ will autowarp to window center.
+ .TP 8
  .B "set-tek-text(\fIlarge/2/3/small\fP)"
  This action sets font used in the Tektronix window to the value of the 
  resources \fBtektextlarge\fP, \fBtektext2\fP, \fBtektext3\fP, and
***************
*** 1502,1507 ****
--- 1529,1560 ----
  starts.
  .PP
  The Tek widget does not support key/button re-binding.
+ .PP
+ Initial placement of an active icon has a braindamaged
+ timing-dependent interaction with the window manager.  When invoked
+ with -I and a geometry spec, it sometimes takes too long to perform
+ initialization (particularly if you have a slow swap device and/or too
+ little memory), and the result is that the window manager doesn't
+ learn of the geometry request soon enough.  Typically, this means that
+ the window manager offers rubberband placement, but even so,
+ eventually the requested geometry spec takes over.  For, e.g., twm(1)
+ users, this can be worked around by putting RandomPlacement in .twmrc.
+ .PP
+ The active-icon() action takes several steps internally, and
+ unfortunately the window is in mid-display at each step.  So executing
+ active-icon() makes your display sort of explode oddly as, e.g., the
+ window shrinks, then loses its scrollbar, then moves to its new
+ location.  There ought to be a way of completely unmapping the window
+ while the changes are executed; but the intuitive way makes things
+ fail due to a lack of proper information regarding parents for the
+ sake of compensating for such things as title bars.
+ .PP
+ For some reason which manages to escape those responsible, specifying
+ a -geometry option which includes a negative Y offset (e.g., XxY+x\fI-y\fP)
+ causes both the normal and active-icon versions of the window to creep
+ upward by the title bar height every time active-icon() is called.
+ This is a serious bug that ought to be fixed, but we can't even guess
+ what we should be looking for.
  .SH COPYRIGHT
  Copyright 1989, Massachusetts Institute of Technology.
  .br

karl_kleinpaste@cis.ohio-state.edu (09/30/90)

I posted changes to X11R4 xterm Friday, providing active icons.  Since
I've had three people write me mail asking what we were doing (in
various terms :-), I thought I should explain a bit.

X10R4 xterm 6.6B had active icons.  You hit the title bar of the xterm
and it would "iconify" by shifting to the nil2 font and parking itself
in the icon location on the screen.

X11 has made the issues of font selection and go-to-icon-location
orthogonal.  In fact, you _can't_ get them together.  You can _either_
load a different font (e.g., nil2) and watch the xterm shrink in
place, _or_ you can iconify it and have it disappear to the right
place, but no longer be able to interact with it.  But you can't have
both.  We think this is an error -- we find the ability to interact
with a sometimes-small xterm _incredibly_ useful, and are unwilling to
live without it.  Hence, our active icon hack to X11R4 xterm -- it
recreates the X10 behavior that we know and love.

If you keep a pile of xterms on your screen most of the time (I
normally have 13 xterms alive), the capability is very sorely missed
when it's not present.  We only converted X10->X11 a month ago, a
matter forced on us due to conversion Sun3/50->SunSLC and no X10
support on Sparcs or under SunOS4.x.  The primary hold-up factor in
not having converted sooner was this particular behavior, not to
mention the abysmal performance of X11 in discless 4Mb 3/50s.

--karl (and terri)

PS- Of course, now someone will show us X11 neophytes how we could
have gotten what we wanted without all this pain...somehow it would
figure.  But the local X11 experts (both of 'em :-) had no clue how to
get what we wanted without this hack.