Window Manager Flames, by Don Hopkins

The ICCCM Sucks

The ICCCM, abbreviated I39L, sucks. I39L is a hash for the acronymic expansion of ICCCM for "Inter-Client Communication Conventions Manual". Please read it if you don't believe me that it sucks! It really does. However, we must live with it. But how???

Some notes about TkWM

To: comp-lang-tcl@berkeley.edu
Subject: Re: Extensible Tk Window Manager?
"David Herron" <DAVID@twg.com> writes:
Somebody else writes:
Who's interested in a extensible Tk ICCCM window manager?
Me me me me ...

In fact I've been tempted more than once to type ^X^Ftkwm.c and see what happened ;-) (just like Tom LaStrange suggested once somewhere..)
But remember, he also warned that you'll regret it for the rest of your life. ICCCM is not the prettiest of protocols. (Your adaptable natural language driven multi media email interface should now play the user definable sound effect you have elected to hear whenever someone makes a gross understatement.)
Actually what sounds more interesting is a Tk extension to X11. You'd embed a TCL/TK interpretor into the X server and use that to build the UI. Some little applications (calculator programs) would be able to run completely within the server, while others would communicate with a back end using higher level commands of some sort.
Hey, that sounds familiar. Might as well put in multitasking, a high level event handling mechanism, networking support, assorted Byzantine interfaces to X server internals, a device independent stencil paint imaging model, a structured graphics editor, an object oriented programming system, persistent objects, an extensible user interface toolkit that runs in the server, that is editable by the user at run-time, and whose image can be captured as a PostScript drawing, with warehouses full of useful graphical component prototypes with you can cut and paste into editable interfaces like HyperCard stacks, with a scripting language with C-like syntax (like PdB), and customizable property sheets for configuring each user interface component.

Once you have all that stuff, _then_ it's time to write a window manager. We were just to that point with NeWS, and even had a really fancy prototype ICCCM X11 window manager implement completely in the server, using The NeWS Toolkit window frames (subclassed to support a virtual scrolling desktop, rooms, pie menus, and movable title tabs), and an optimizing object oriented ANSI-C to PostScript compiler (PdB) that allows human beings to write scripts to customize the user interface, when Sun cut our throats for the final time.

Well fortunately, PdB binaries are now available for the sun4 and rs6000 via anonymous ftp from ftp.uu.net (in "graphics/NeWS/pdb2.1.1.*") and bongo.garnet.cs.cmu.edu (in "pub/PdB").
So users can construct custom environments by composing X applications and programmable window management widgets like close buttons, menus of keyboard or mouse macros, drag and drop targets, post-it notes, shared white boards, graphics editors, etc...
I think he's got the fever!!!
Bill Buxton put it well: it is an unworthy design objective to aim for anything less than trying to do to the Macintosh what the Macintosh did to the previous state of the art.

-Don

PS: If you're really interested in this kind of stuff, and actually running OpenWindows 3.0, you should check out the free HyperLook demo, "HyperLook1.5-runtime.tar.Z", available via anonymous ftp from ftp.uu.net in "graphics/NeWS", or bongo.garnet.cs.cmu.edu in "pub/HyperLook". The runtime system is free, but the user interface editor isn't included in the demo. It does include a fully functional structured PostScript graphics editor that imports and exports EPS (which is a user interface component you can use in your own HyperLook applications and property sheets). There are also some PostScript files describing the system, and several demos showing what it can do. One of the demos (HyperLook-Clocks.tar.Z, the NeatClocks stack) is a warehouse of customizable clock components, whose property sheet has three structured graphics editors, for the face and the hands. The clock scales and rotates the graphics (like a clipped image of Alan Turing's head for the clock face, or a Zapf Dingbat pointing hand) to display the time. You can press the "Props" key over a clock face to edit its graphical properties, or "Help" to see the specialized help text that also tells the current time and date. This kind of stuff really is down to earth and practical (I haven't yet described the far out blue sky stuff), and incredibly fun to build and use!

Who Should Manage the Windows, X11 or NeWS?

This is a discussion of ICCCM Window Management for X11/NeWS. One of the horrible problems of X11/NeWS was window management. The X people wanted to wrap NeWS windows up in X frames (that is, OLWM). The NeWS people wanted to do it the other way around, and prototyped an ICCCM window manager in NeWS (mostly object oriented PostScript, and a tiny bit of C), that wrapped X windows up in NeWS window frames.

Why wrap X windows in NeWS frames? Because NeWS is much better at window management than X. On the surface, it was easy to implement lots of cool features. But deeper, NeWS is capable of synchronizing input events much more reliably than X11, so it can manage the input focus perfectly, where asynchronous X11 window managers fall flat on their face by definition.

Our next step (if you'll pardon the allusion) was to use HyperNeWS (renamed HyperLook, a graphical user interface system like HyperCard with PostScript) to implemented a totally customizable X window manager!

Some notes about OWM

OWM is the "Open Window Manager" we prototyped in NeWS. We enhanced the NeWS window frames so they sported indexing tabs, pie menus, rooms, and a scrolling virtual desktop. Many of our enhancements were separately developed, and plugged together orthogonally like Legos. All NeWS applications could use these fancy frames, and the Open Window Manager wrapped X clients in the same frames that NeWS windows got!

This way, factoring the window frames out as a part of the toolkit, and implementing the X window manager separately, NeWS applications don't have to know a thing about X window management, and X clients can go on doing the same nasty things they've always done, and everybody get the benefits of dynamic extensibility, and a consistent user interface, by using the default window class!

I39L window management complicates pinned menus enormously. TNT menus pin correctly, so that when you push the pin in, the menu window simply stays up on the screen, just like you'd expect. This is not the case with XView or even OLWM. Under an I39L window manager, the Open Look pinned menu metaphor completely breaks down. When you pin an X menu, it disappears from the screen for an instant, then comes back at a different place, at a different size, with a different look and feel. If you're not running just the right window manager, pinned menus don't even have pins! There is no need for such "ICCCM compliant" behavior with TNT menus. When they're pinned, they can just stay there and manage themselves. But were TNT windows managed by an external I39L window manager, they would have to degenerate to the level of X menus.

Under the OWM solution, pinned TNT menus work correctly, and they inherit their pinned window behavior from ClassPopupWindow, the same class managing pinned X menus. The look and feel is high quality, consistent, maintainable, and intentionally extensible.

If I39L window management has such a negative impact on pinned menus, how else will it impact other parts of the toolkit and applications?

Will it effect popup notices? Since they need keyboard input for the buttons, will they have to play the I39L window management game? How do we get the notice tail (a separate canvas) to line up, if the window manager decides to wrap a frame around the notice window?

It is impossible to know how it will effect TNT applications, because the toolkit was specifically designed to be subclassed and extended in areas that overlap with I39L window management. NeWSRoom and the TNT virtual window manager are examples of simple, interesting extensions to the window class that are in direct conflict with I39L window management. We would be giving up a lot of actual and potential functionality, that we designed the toolkit to support in the first place. We need to redesign the window class for greater flexibility and easier subclassability, but those goals are at odds with I39L window management. The result of a cross of these two opposing goals would be massively complex and would sacrifice most of the important advantages of the TNT approach. However, the OWM approach to window management, wrapping X windows in instances of the TNT window class, synergizes with extensions to the window classes. As an extreme example, you can make OWM wrap window frames with title tabs that pop up pie menus full of handy window management functions around all your X windows.

There are several other technological advantages of managing X windows internally with NeWS, over managing them externally with X. By an external window manager, I mean one that is in a separate address space as the windows. Relative to the server, all windows are internal, all X "Xlib" and NeWS "wire service" clients are external, and NeWS canvas objects and light weight processes are internal. But an external X window manager is in a different address space must try to manage many shared resources at a distance, an intrinsically difficult task, imposing limitations on the whole system and unavoidably restricting the user interface possibilities.

The management of arbitrarily shaped windows becomes very complicated under an I39L window manager. In contrast, PizzaTool has a popup pizza preview window, whose shape is a rectangular frame around a round (or semi-circular, depending on your appetite) pizza window, with the space between the inside of the frame and the pizza cut out. It was very easy to implement, by subclassing ClassPopupWindow and overriding the /path method to cut out the inside of the frame and ask the center pizza client to add its shape to the path. When you move or stretch the window, you see a rubber-band preview of the actual shape the window will take when you release the button. The pizza path procedure knows to maintain a 1:1 aspect ratio (no oval pizzas), that centers the round pizza in the frame as you drag the resize corner around. The shape of a TNT window is not simply defined by curves or bitmaps -- it is defined by a method of the window object, which can apply constraints and may depend on the state of other objects in the system, like the size or number of slices of the pizza inside the frame. All this nice interactive feedback is totally trivial to implement with TNT, and is completely impossible with an I39L window manager. And even if an I39L window manager could be programmed to perform such custom feedback, it would still have to grab the server and lock out all other animation in the process, instead of using nondestructive overlays like TNT.

X11 window managers must grab the server in order to animate rubber-band feedback over the screen when resizing and moving windows. This grabbing causes many problems with NeWS synchronous interests, that can be demonstrated by pressing the "Help" key while dragging out a rectangle on the root background. NeWS can do a much better job at managing global resources in the server because it is in the same address space and it has facilities like the overlay plane specifically designed to implement such window management functions, without even grabbing the server. This antisocial server grabbing behavior is just one symptom of a general class of problems with external X window management, including other important issues such as keyboard and colormap focus.

If NeWS alone manages the input focus, it can manage it perfectly. An X window manager alone cannot, because it runs in a foreign address space, and is not in a position to synchronously block the input queue and directly effect the distribution of events the way NeWS is. But even worse is when an X window manager *and* NeWS both try to manage the input focus at once, which is the situation we are in today. The input focus problem could be solved in several ways: OWM solves the problem elegantly, as PSWM did in the past; OLWM could be made NeWS aware, so that when our own customers run our own external X window manager on our own server that we ship preinstalled on the disks of our own computers, OLWM could download some PostScript and let NeWS handle the focus management the way it was designed.

It's criminally negligent to ship a product that is incapable of keeping the input focus up to date with the cursor position, when you have the technology to do so. Your xtrek has paged the window manager out of core, and the console beeps and you suddenly need to move the cursor into the terminal emulator and type the command to keep the reactor from melting down, but the input focus stays in the xtrek for three seconds while the window manager pages in, but you keep on typing, and the keys slip right through to xtrek, and you accidentally fire off your last photon torpedo and beam twelve red shirt engineers into deep space!

Some Questions About xinit

Date: Tue,  4 Jun 1991 04:12:49 -0400 (EDT)
From: Pat_Barron@transarc.com
To: Don.Hopkins@Eng (Don Hopkins)
Subject: Re: xinit
Excerpts from mail: 4-Jun-91 xinit Don Hopkins@Eng.Sun.COM (81)
Could somebody please explain why xinit exists? Does anybody use it? Why?
I'm not really sure what you're asking. If you're asking why people don't just use xdm or something, I can tell you that (at least in my environment) I don't always want the window system running, at all. Also, I have at least one user here who alternates back and forth between X11 and Suntools, so he needs to log in on the console and manually start whatever window system he needs to use that day.

--Pat.
I'm interested to know if there's something special about they way xinit sets things up and takes things down that makes people want to use it, or if it's that they simply want to be able to log in on the console and run whatever window system they choose.

It's trying to solve several problems, and it imposes a certain model, so I'd like to know what problems people need xinit to solve, and what non-problems people don't need xinit to solve but it tries to solve anyway.

In particular, one problem it tries to solve is the "start up the window system from the command line" problem. Another is the "shut down the window system from the user interface" problem. Along the way, it makes a stab at the "initialize the window system" problem, which generally includes the "start up the managers" and "start up the clients" problems. Depending on the way you have things set up, xinit might fire off any number of managers and clients, or just hand the responsibility off to one manager or shell script who starts off the whole show. What happens at this point is private matter between you and your site administrator.

The thing I want to question is xinit's solution to the "shut down the window system from the user interface" problem. Its policy is to hang around until the "last long lived program started (usually a window manager or terminal emulator)" has exited. Or is that a mechanism? I'm sorry, these days it's hard to tell, what with all the patriotism that's going around. Anyway, what I wanna know, is why is xinit trying to solve a *user interface* problem? What is the documented "user interface" for indicating to xinit that you are done, and that it should solve the "shut down the window system" problem? Simple: you cause a shell script to exit. That's certainly intuitive and easy!

[Well, it's intuitive if your site administrator has everything nicely set up so that one *special* xterm automatically comes up in AutoIconify mode with blinking text and a huge banner in bright bright red 48 point RockyHorror-BoldItalic saying "!!!DEATH TERM!!!". Well, it's easy if your window manager is so tough that it laughs maniacally whenever it gets hit by a SEGV, and has a popup confirmation dialog hard wired to the exit button, saying "You mess with me, and I'll blow your whole god damned window system out of the water, sucker!!! (make my day) (cancel)".]

In other words, what are the *problems* people use xinit to solve, that make them need to use xinit instead of some other solution? I don't care so much about the particular solutions themselves. [Of course I'm not interested in anybody else's solution, because in my spare time, I'm developing ExitTool, a fully customizable point and click graphical user interface to exiting the window system, which has a special private interclient communication protocol to rendezvous with other applications subscribing to compatible desktop metaphors, actually empowering the user to drag'n'drop from YesTool (a full featured graphical adaptation of the classic unix utility), and cut'n'paste from NoTool (actually implemented using trendy and powerful object oriented programming techniques as a *subclass* of YesTool!)]

-Don c(^;

Some Notes on piewm

An X window manager is a special X program that lets you interact with windows of many other X programs at once. A workstation has resources like the mouse, the keyboard, and space on the screen, that X programs must share.

The window manager usually puts frames around the windows, with controls on them for moving, resizing, and iconifying the window. It provides menus for selecting commands and running programs. It also lets you invoke programs and function from the keyboard or various combinations of mouse clicks and shift keys.

Because they have so many different tasks to perform, and everyone wants them to behave differently, window managers usually have some sort of customization language. With the "twm" window manager (and its descendants), you can define its behavior by binding events like mouse clicks and keys to build-in functions and external programs. You can create menus and buttons and attach them to window frames and backgrounds. There are zillions of options you can configure, like fonts, colors, patterns, icons, styles, measurements, modes, and all sorts of idiosyncratic behaviors.

The "twm" window manager reads the file called ".twmrc" in your home directory when it starts up. The twm manual explains the exact syntax and all the options in detail. I will briefly demonstrate the syntax by giving a few simple examples.
# Comments start with hash marks.

# Set modes by writing the name of the mode:
NoGrabServer

# Set variables by writing the name of the variable, 
# one or more spaces or tabs, then the value.
TitleFont "lucidasans-bold-14"
BorderWidth 1
There are all kinds of modes and variables you can set, but many of them are unimportant or simply too bizarre to mention. Look at the commented example .twmrc file to find out about the interesting ones. For some reason, you have to set the fonts and colors before you set the other variables. That's just the way it is, unfortunately.

The color variables should take on different values depending on whether the screen is color or monochrome. You can set color and monochrome values appropriately for the screen you're using like this:
# If we're on a color screen, use these color settings.
Color {
  BorderColor "slategray"
  DefaultBackground "pukegreen"
  # ...etc
}

# If we're on a monochrome screen, use these color settings.
Monochrome {
  BorderColor "black"
  DefaultBackground "white"
  # ...etc
}
There are several other options that require lists as arguments (like lists of cursors, icons, or window names), and they all use braces in the same manner as the "Color" and "Monochrome" commands. Look in the example and the manual to find out more, since most of those options are pretty advanced or esoteric.

The kind of customization you're going to want to do most is defining menus. Each menu has a name and a list of items. Each item has a label and an action. The action is a built-in function that performs some window management task, or pops up another sub-menu, or runs a shell command.
# This is a simple top level menu, with entries that invoke submenus.
menu "Windows" {
  "Programs"            f.menu "Programs"
  "Quit"                f.menu "Quit"
}

# This is a menu with entries that invoke shell commands. 
menu "Programs" {
  "Terminal"            !"xterm -sb -sl 500 &"
  "Editor"              !"gnu-emacs &"
  "Adventure"           !"xterm -sb -sl 2000 -e /usr/games/adventure &"
  "Who's On"            !"xterm -sb -e /bin/csh -c 'finger | more ; cat' &"
}

# This is a menu with entries that invoke built-in functions. 
menu "Quit" {
  "Oops, never mind."   f.beep
  "Yes, I'm sure!"      f.quit
}
Once you've defined some menus, you still have to tell the window manager what you do to invoke them. Any menu can be invoked as a submenu of any of the other menus, but initially there must be a way to call up the top level menu. To make that possible, you bind it to some input event like a mouse click or function key, in some particular context, like a window frame, button, or background.

Menus aren't the only way to invoke functions -- you can bind input events directly to functions. In fact popping up a menu is just another function. You create a binding by specifying an input event, a set of modifier keys, a context, and a function. The event is the name of a mouse button or function key (Button1, Button2, Button3, "F1", "Home"). The modifier key set specifies which of the modifier keys (shift, meta, control) must be held down to invoke this binding. The context defines where on the screen this binding is in effect (window, title, icon, root, all). The function of a binding is just like a menu action.
#Button = KEYS : CONTEXT : FUNCTION
#-----------------------------------------------
Button1 =      : root    : f.menu "Windows"
Button1 =      : title   : f.raiselower
Button2 =      : title   : f.move
Button3 =      : title   : f.menu "Frame"
Button1 =      : icon    : f.iconify
Button2 =      : icon    : f.move
Button3 =      : icon    : f.menu "Frame"
"F1" =         : all     : f.raiselower
"F2" =         : all     : f.iconify
Another way you can invoke functions is by clicking on buttons in the title bars of your windows. You can define your own title buttons and bind them to any function. Your buttons are added to the left or right side of the title bar, in the order you specify. To define a button you must give the name of a bitmap file or one of the built-in bitmaps, which is used to draw the button.
LeftTitleButton ":dot" = f.iconify
RightTitleButton ":resize" = f.resize
The "tvtwm" window manager runs your ".twmrc" file through the "m4" macro preprocessor, defining certain useful constants that describe the environment. This allows you to include other files, define macros and symbolic names, and conditionalize parts of your ".twmrc" file depending on the environment. It's very powerful, and it lets you write one .tvtwm file that works across many different systems, but it can get pretty hairy. Read the "m4" and "tvtwm" manuals for more information.

My modified version of "tvtwm" has pie menus. The labels of a pie menu are arranged in a circle around the cursor, and the menu selection is based on the direction you move between clicking the button. They are fast and easy to use because each of the target areas is a large wedge shaped area adjacent to the cursor. You can also display pixmaps as pie menu labels, by using a label beginning with an underscore followed by a bitmap or pixmap file name. You define pie menus the same way as regular linear menus, except using the word "piemenu" instead of "menu". There is an extra optional argument following the menu name and an "@" sign, that specifies the direction of the first menu item, defaulting to 0 (to the right, increasing counter-clockwise). To pop up a pie menu (in a binding or as a submenu), use the "f.piemenu" function instead of the "f.menu" function. Pie menus can be submenus of linear menus, and the other way around, too.
# The first item goes at 0 degrees (to the right) and the rest are
# laid out counter-clockwise evenly spaced around the circle.
# (In directions appropriate for their function.)  
piemenu "Pan" {
  "Right"       f.scrollright
  "Goto"        f.menu "TwmWindows"
  "Up"          f.scrollup
  "Home"        f.scrollhome
  "Left"        f.scrollleft
  "Back"        f.scrollback
  "Down"        f.scrolldown
  "Quad"        f.piemenu "Quad"
}

# The first item of this menu will be to the north-east, as the 
# label suggests.  You can select between four quadrants, and the
# virtual screen pans there. 
piemenu "Quad" @ 45 {
  "NE"          f.scroll "+1+0"
  "NW"          f.scroll "+0+0"
  "SW"          f.scroll "+0+1"
  "SE"          f.scroll "+1+1"
}

# The first item of this menu will be at the top, so it's like an
# on/off switch (in the US at least, they're the other way around
# in other countries, so you can change the number after the @ to 
# 270 if it'll make you feel more at home). 
piemenu "Key Click" @ 90 {
  "On"          !"xset c on"
  "Off"         !"xset c off"
}