%
% Grab.tex -- All about vendor shell extension objects and grabs
%
% (c) 1996 The Hungry Programmers
% (c) 1996 Harald Albrecht (albrecht@igpm.rwth-aachen.de)
% See the file PUBLIC for details.
%
\chapter[Diverting User Input with Grabs]
{Diverting User Input with Grabs}
\by{Harald Albrecht}


\section{Introduction}

\index{Xt grabs}\index{Xlib grabs}%
\index{grabs!exclusive and non-exclusive}%
\index{grabs!Xlib and Xt}%
\codeindex{XtDispatchEvent}%
A ``grab'' is a mechanism that changes the way in which user input
events -- from the mouse or the keyboard -- are reported. In addition
to the Xlib grabs, which change the handling of user input within the
X server (and which I'm not going to discuss here), the Xt Intrinsics
add a second grab layer: the ``Xt grabs''. They are similar to the
Xlib grabs in that they change the way user input events are
reported. But the Xt grabs work entirely within an application and
therefore do not affect other applications using the same X server:
the central event dispatch function \code{XtDispatchEvent()} is mainly
responsible for the Xt grab mechanism.

Without going too much into the dirty details, it is important to know
that the Xt Intrinsics maintain a grab list. If this list is not
empty, only the widgets on the list, as well as their child widgets,
will receive input events. Widgets can be added to the end of the grab
list either as exclusive or non-exclusive. Only the widgets on the
list from the most recently added exclusive widget to the end will
receive input events.  This way, adding a widget to the grab list
exclusively will keep any user input events away from the widgets (and
their children) that were already on the list. In the end, the grab
list treats the widgets as a cascade. When you remove a widget from the
list, all widgets that were added after it are removed, too.

\Motif{} uses a different approach to the grab mechanism. Whereas the
Intrinsics' concept of a grab cascade is sensible for a set of
cascading menus, it isn't for modal dialogs. If there are two modal
dialogs visible, popping down the older one should not remove the
younger one from the grab list. Unfortunately, to achieve the desired
grab behaviour \Motif{} uses a completely undocumented grab layer, so
the usual omnipotent disclaimer applies: continue reading at your own
risk. All knowledge about \Motif{}'s grab layer results from
investigations done on the ``living subject'' with the help of a nice
test program that can pretty-print various data trees to the
console. The test program lives in
\code{\textdollar(LESSTIF\_ROOT)/testXm/extobj/test2.c}.


\section{The Grab Layer and the Grab List}

\codeindex{XtRemoveGrab}%
To be compatible with \Motif{}'s grab concept, \LessTif{} maintains
its own grab list somewhat paralleling that inside the Xt
Intrinsics. Whenever \LessTif{} removes a grab from a widget by
calling \code{XtRemoveGrab()} it puts back on all the widgets that are
on its own list after the widget just removed.

\LessTif{} manages the grabs on a per-display basis, thus you can find
each grab list in the instance variable \code{modals} within the
instance record of a \code{XmScreen} widget. The number of entries
allocated for the list is stored in the \code{maxModals} instance
member, whereas the \code{numModals} member -- as usual -- indicates
how many entries currently are in use.

\codeindex{LTAddGrab}\codeindex{LTRemoveGrab}%
Two pure internal functions work on the private grab lists:
\begin{itemlist}
\item \code{LTAddGrab()} adds a new widget to the grab list as either
exclusive or non-exclusive.
\item \code{LTRemoveGrab()} removes a widget from the grab list and puts
back on all the widgets that were after it on the list.
\end{itemlist}

Because the grab lists are mainly used to achieve dialog modality, and
dialogs are eventually special shells, you can find the implementation
of \code{LTAddGrab()} and \code{LTRemoveGrab()} in
\code{\textdollar(LESSTIF\_ROOT)/libXm/Vendor.c}.

\index{internal grab layer}%
\index{grabs!internal layer}%
\index{grabs!adding or removing}%
Two additional functions -- although not mentioned in the official
documentation -- are visible outside the \code{Vendor.c} module and
provide access to \Motif{}'s grab layer (the interface functions are
needed by the drag \& drop mechanism and the menu system):
\begin{verbatim}
void _XmAddGrab(Widget wid, Boolean exclusive, Boolean spring_loaded);
void _XmRemoveGrab(Widget wid);
\end{verbatim}

\codeindex{XtAddGrab}\codeindex{XtRemoveGrab}%
\codeindex{\_XmAddGrab}\codeindex{\_XmRemoveGrab}%
They both can be used just the same way as their counterparts from the
Xt Intrinsics. It is very important \textbf{never to use}
\code{XtAddGrab()} or \code{XtRemoveGrab()} as this will put
\LessTif{}'s grab list out of sync with the Xt grab list.

Each entry of \LessTif{}'s grab list stores detailed information about
a single grab:
\begin{verbatim}
typedef struct _XmModalDataRec {
    Widget                 wid;
    XmVendorShellExtObject ve;
    XmVendorShellExtObject grabber;
    Boolean                exclusive;
    Boolean                springLoaded;
} XmModalDataRec, *XmModalData;
\end{verbatim}

The members \code{wid}, \code{exclusive}, and \code{springLoaded} of
the \code{XmModalDataRec} structure re\-cord the values of
the function parameters from the call to \code{LTAddGrab()} or
\code{\_XmAddGrab()}. This way, whenever removing a grab, \LessTif{}
can restore the grabs that were on the list after that grab.

When working with primary application modal dialogs, \LessTif{} needs
to remember such dialogs in \code{grabber} so it can remove, later on,
any additional grabs it had to add in order to achieve the primary
application modality. The \code{grabber} member, as well as \code{ve},
is not an ordinary widget ID but rather links to a so-called extension
object of a vendor shell. I'll discuss this below in more detail.


\subsection{Full Application Modal Dialogs}

With a full application modal dialog on the display, the user must
respond to it before she or he can do anything else in the
application. To achieve this effect, \LessTif{} must block out any
user input events which are not meant for the full application modal
dialog. \LessTif{} therefore issues an exclusive grab on the shell
widget of the dialog -- see figure \ref{Fam_Dialog}. In this figure,
as well as in the next few ones, I'll leave out those child widgets of
shell widgets that aren't shells themselves -- otherwise the figures
would be overcrowded.

In addition, in the following figures you'll see some entries on the
grab list that are framed by thick edges. These entries form the
``active Xt modal cascade'': user input events are dispatched only to
those widgets (as well as to their children) that are part of the
active Xt modal cascade. The active Xt modal cascade always starts
with the most recent exclusive grab.

\begin{figure}[ht]
\centerline{\includegraphics[scale=1.09]{Fam_Dialog}}
\caption{\label{Fam_Dialog}Entries on the grab list after a full
application modal dialog popped up.}
\end{figure}

You may already be wondering why there is another (non-exclusive) grab in
slot \#1 of the list, just before our exclusive grab for the
application modal dialog. This non-exclusive grab belongs to the top
level shell of the application. \LessTif{} installs such grabs on
every VendorShell (or any subclass of) which does not serve as a popup
shell (that is, as a dialog). Otherwise the top level shell of an
application and any of its children won't receive input anymore as
soon as a modeless dialog shows up, because modeless dialogs use
grabs, too.


\subsection{Modeless Dialogs}

Although somewhat weird at a first glance, \LessTif{} even installs a
(non-exclusive) grab on the shells of modeless dialogs -- see grab entry
\#3 in figure \ref{Ml_Dialog}.

\begin{figure}[h]
\centerline{\includegraphics[scale=1.09]{Ml_Dialog}}
\caption{\label{Ml_Dialog}Entries on the grab list after a modeless
dialog popped up.}
\end{figure}

The reason for this is that from \LessTif{}'s point of view the
dialogs and their grabs don't form a cascade. Thus, if you pop up a
modeless dialog whenever a full application modal dialog is already
active, the new dialog should receive user input too -- even if the
modeless dialog is created as a child of the other dialog's parent and
not as a child of the full application modal dialog.


\subsection{System Modal Dialogs}

System modal dialogs are much the same as full application modal
dialogs. But with system modal dialogs, the user must respond to the
dialog before doing anything else in \emph{any} application. Because
an exclusive Xt grab is only effective within the application, any
\LessTif{} application needs additional help from the window manager
to make a dialog system modal. Currently, only \code{mwm} (and thus
\code{lmwm}) provides the help needed. If there is no suitable
window manager present, the system modal dialog behaves like any full
application modal dialog.

In the case of a system modal dialog the grab list looks like the one
presented in figure \ref{Ml_Dialog}.


\subsection{Primary Application Modal Dialogs}

A primary application modal dialog (what a name!) is the fourth -- and
last -- kind of \LessTif{}'s dialog types. Whenever such a dialog is
visible, the user can interact with any dialog that is \emph{not} a
parent of the primary application modal dialog, just as with any other
top level shell. Unfortunately, the behaviour just described isn't
suited to the Xt grab mechanism at all. \LessTif{} therefore has to do
some work behind the scenes to get the desired grab behaviour: it must
reissue all grabs that do not belong to any of the parental shells of
our primary application modal dialog. A more elaborate example, figure
\ref{Pam_Dialog}, shows the grab list after a primary application
modal dialog popped up.

\begin{figure}[h]
\centerline{\includegraphics[scale=1.09]{Pam_Dialog}}
\caption{\label{Pam_Dialog}Entries on the grab list after a full
primary application modal dialog popped up.}
\end{figure}

For some reason -- yet not fully understood -- \Motif reissues the
grabs for the shells, which aren't parents of the primary application
modal dialog, only if \code{mwm} is present. Users of other window
managers -- like the famous \code{fvwm} -- look (literally spoken)
into the tube.

When popping down a primary application modal dialog, \LessTif{} must
get rid off all those grabs that once were necessary to get the
desired grab behavior. In figure \ref{Pam_Dialog} the two grabs in
the slots \#2 and \#4 are belonging to the \emph{modeless} dialog
\circled{3}. But only the grab from slot \#4 must be
removed together with the grab \#3 that belongs to the primary
application modal dialog.

This is where the \code{grabber} member mentioned above comes in. In
the case of a primary application modal dialog the \code{grabber}
links to an object (of class \code{XmVendorShellExtObject}) that
belongs to the shell widget of the primary application modal
dialog. All we then have to do inside \code{LTRemoveGrab()} is to
remove all grabs from the list whose \code{grabber} belongs to the
primary application modal dialog just popped down. In other cases of
dialog grabs the member \code{grabber} links to the extension object
of the same shell as referenced in \code{wid}.


\section{Creating Dialog Shells the Right Way}

\codeindex{XtCreatePopupShell}%
\codeindex{XtCreateWidget}%
\index{creating!dialog shells}%
There are two major ways of creating dialog shells:
\begin{itemlist}
\item Either using \code{XtCreatePopupShell()} or one of the
\code{XmCreate*Dialog()} functions. The latter ones just stand on
the shoulders of \code{XtCreatePopupShell()} but hide this to some
extend from the programmer. \code{XtCreatePopupShell()} also adds the
shell widget just created to the parent's list of popup shells. All
widgets (but neither gadgets nor objects) maintain such lists.

\item Using \code{XtCreateWidget()} -- and thus the same way as ``ordinary''
widgets are commonly created. If the parent of a shell is of class
Composite (or any subclass of) then the (shell) widget is added to the
parent's list of child widgets -- which must be distinguished from the
list of popup shells.
\end{itemlist}

Although not recommended, \code{XtCreateWidget()} is widely used for
creating dialog shells or shells in general (shame on me, too. Where's
the sack and the ash?). Maybe the most prominent reason for this is
that it makes widget creation more uniform. At the first look there
seems to be no reason why to use \code{XtCreatePopupShell()}
anyway. But \Motif{} needs to know for its grab layer whether a shell
widget serves as an ordinary top level shell (and thus has no
modality) or as a dialog shell. In the latter case the
\code{XmNdialogStyle} resource of a BulletinBoard-derived child of a
dialog shell controls the dialog modality and eventually the grabs
used.

The only way currently known to distinguish ordinary shells from
shells working as popup dialogs is to check whether the shell is
registered with the parent's list of popup shells. But this will
fail miserably if the dialog shell was created using
\code{XtCreateWidget()} instead of \code{XtCreate\-PopupShell()}. In that
case the dialog shell first sets an unnecessary non-modal grab as soon
as the shell is realized. Finally, when popping up the dialog, the
\code{LTShellPopupCallback} callback sets the real (modal or non-modal)
grab. Fortunately the first and unnecessary non-modal grab doesn't
hurt very much -- it just pollutes \Motif{}'s grab list. But the user
won't notice that anyway.


\section{Extending the VendorShell}

\index{shadow shell tree}%
The objects of the \code{XmVendorShellExtObject} class serve for two
purposes. First, they provide storage for resources that are new with
\Motif{}'s particular VendorShell. Second, they form a tree (or hierarchy)
which shadows the instance hierarchy of all the shell widgets an
application has. From now on I'll refer to this hierarchy as the
``shadow shell tree''. But first some more information about the
rather less-spotted vendor shell extension objects.

By definition a VendorShell is a subclass of a WMShell and allows
software vendors to provide new resources, class methods, etc. to
support their custom window managers. So much for theory. In practice
the spirit (idea) was willing but the flesh (the implementation)
\emph{is} still weak. If you would have to write your own VendorShell
widget class that has additional instance variables (``resources'')
you would be in trouble -- or rather those programmers writing their X
applications using your new VendorShell.  As several widget classes
are derived from the VendorShell class (for example the
TransientShell, the TopLevelShell and the ApplicationShell, see figure
\ref{Class_Family} on page \pageref{Class_Family}) these classes then
would have to be recompiled. Otherwise the VendorShell part of an
already compiled and older ApplicationShell would differ from that
part of a new VendorShell. At this point the object-orientated
approach simply can't handle the case where you need to replace a
class \emph{within} the class tree.

Historically, the \CSF{} \emph{needed} to add new resources to the
VendorShell to support resolution independance, specific MWM
functions and other ``features''. But extending the existing
VendorShell was not desirable at all, as mentioned above, so the
programmers at the \CSF{} took another approach.

\begin{figure}[ht]
\centerline{\includegraphics[scale=1.09]{ExtObjClasses}}
\caption{\label{ExtObject_Classes}Class hierarchy for extension objects.}
\end{figure}

\index{extension!object}%
With \Motif{}, every VendorShell widget (as well as every widget
created from a subclass of VendorShell) is accompanied by a so-called
VendorShell extension object. This VendorShell extension object (or
``VSE object'' for short) is a descendant of XmDesktopObject,
XmExtObject, and thus finally of the Intrinsics' Object class (see
figure \ref{ExtObject_Classes}).

The Object class was made public in X11R4 to enable programmers to use
the Intrinsics' classing and resource handling mechanisms for things
besides widgets. Within \Motif{}, the VSE objects serve to hold all the
instance variables (resources) that had to be added to the VendorShell
class after the Xt Intrinsics had already been written down.

\codeindex{XmExtObject}%
\codeindex{XmNlogicalParent}%
The starting point for all kind of extension object classes within
\LessTif{} is the XmExtObject class. This class provides for synthetic
resources as well as external resources. In addition, every instance
of a XmExtObject contains a pointer to its ``logical parent''
(resource \code{XmNlogical\-Parent}) that is the widget that owns the
extension object (or that the extension object extends). You'll never
find a XmExtObject in its logical parent's child list. One reason is
that \Motif{} seems to use some kind of self-crafted
\code{XtCreateWidget()} when creating extension objects. A second
reason is that \LessTif{} currently uses a call to
\code{XtCreateWidget()} when creating VSE objects. To cite Mitch, the
affected logical parents keep ``those pesky [extension] objects'' out
of the child list using special \code{insert\_child()} and
\code{delete\_child()} methods.


\section{The Shadow Shell Tree}

\codeindex{XmVendorShellExtObject}%
\codeindex{XmDesktopObject}%
The VSE object (XmVendorShellExtObject) is subclassed from the
XmDesktopObject class which in turn is subclassed from
XmExtObject. Whereas the XmExtObject only knows of an associated
``logical parent'', the XmDesktopObject class introduces the concept
of children to the extension objects (see figure \ref{Desktop_Class}).

\begin{figure}[ht]
\centerline{\includegraphics[scale=1.09]{DesktopClass}}
\caption{\label{Desktop_Class}The XmDesktopObjects form a tree of
XmDesktopObjects with a XmScreen widget at the top.}
\end{figure}

The children of a XmDesktopObject (which must be either
XmDesktopObjects again or a subclass of) are managed in a list much
the same way Composite does.  But as extension objects have no real
parent (only a logical parent which is merely an associated widget)
the XmDesktopObject class adds a new resource called
\code{XmNdesktopParent}.  It links to the parental object this
particular XmDesktopObject is a child of. All the XmDesktopObjects
form a ``shadow tree'' of the shell instance hierarchy.  This tree is
much like the well-known widget instance tree any application has --
but this time any widgets that are not shells are left out.

\codeindex{XmScreen}%
At the top of the tree of XmDesktopObjects there is always a
XmScreen widget. But as the XmScreen class is a \emph{direct} subclass
of Core and not of Composite it can't manage a list of children -- at
least from the Xt Intrinsics' point of view. This is there the Desktop
class part comes in a second time as ``Nobody expects the Spanish
Inquisition...''. Oops -- wrong movie.

In figure \ref{ExtObject_Classes} you can see the XmDesktopObject
(surrounded by dashed edges) reappearing at the branch between the
Core class and the XmScreen class. At this point the principle of
inheritance is somewhat broken as the XmScreen class is a
\emph{direct} subclass of Core. But XmScreen extends the instance record
of the Core class not only by its own XmScreen-specific part but also
by the XmDesktop-specific part.

This makes creating and inserting XmDesktopObjects ponderous because
every such object must push its (desktop) parent to be inserted into
the parent's list of children. But remember that the parent can be not
only another XmDesktopObject but also a XmScreen widget. Thus, both
XmDesktopObject as well as XmScreen provide methods through their
desktop part within the class record for inserting
(\code{insert\_child()}) and deleting (\code{delete\_child()}) a
single child.

Whenever a XmDesktopObject is created, and its \code{XmNdesktopParent}
resource is not \code{NULL}, it calls the \code{insert\_child} method
that is appropiate for the respective parent. As an example how this
is done here is the \code{initialize()} method of the XmDesktopObject
class (ripped of from
\code{\textdollar(LESSTIF\_ROOT)/libXm/Desktop.c}):

\begin{verbatim}
static void initialize(Widget request, Widget new_w,
                       ArgList args, Cardinal *num_args)
{
    Widget       desktopParent;
    XtWidgetProc insertChild;

    Desktop_Children(new_w)    = NULL;
    Desktop_NumChildren(new_w) = 0;
    Desktop_NumSlots(new_w)    = 0;
    desktopParent = Desktop_Parent(new_w);
    if ( desktopParent ) {
        if ( _XmIsFastSubclass(XtClass(desktopParent), XmSCREEN_BIT) ) {
            insertChild = ((XmScreenClassRec *) XtClass(desktopParent))->
                              desktop_class.insert_child;
        } else {
            insertChild = ((XmDesktopClassRec *) XtClass(desktopParent))->
                              desktop_class.insert_child;
        }
        if ( insertChild == NULL ) {
            _XmError(new_w,
                     "insert_child method of my desktop parent is NULL");
        }
        insertChild(new_w);
    }
} /* initialize */
\end{verbatim}

\codeindex{XmDisplay}
The XmScreen widget at the top of the tree of XmDesktopObjects isn't
yet the end of the road. Instead there's still another level
represented by a XmDisplay widget (see figure
\ref{Shadow_Shell}). \Motif{} creates such XmDisplay widgets for
every display connection an application opens. The XmDisplay widget
then gathers the various shadow shell trees via XmScreen widgets
under its hood.

\begin{figure}[h]
\centerline{\includegraphics[scale=1.09]{ShadowShell}}
\caption{\label{Shadow_Shell}The shadow shell tree is organized by
XmScreen widgets which are in turn gathered under the hood of a
XmDisplay widget.}
\end{figure}

From time to time you need to look up the VSE object for a given
VendorShell widget. For this you'll need the help of
\code{\_XmGetWidgetExtData()} from the BaseClass stuff. During
initializing, every VendorShell widget creates a widget extension data
record of type \code{XmWidgetExtDataRec} and pushes it on an extension
data stack that \LessTif{} maintains for some widget (and gadget)
classes. The member \code{widget} of such a widget extension data
structure finally points to the VSE object for the VendorShell. The
following code excerpt shows how to find a VSE object using
\code{\_XmGetWidgetExtData()}.

\begin{verbatim}
    Widget                 vendorShell;
    XmVendorShellExtObject ve;
    XmWidgetExtData        extData;

    °/* vendorShell references a VendorShell widget */°
    extData = _XmGetWidgetExtData(vendorShell, XmSHELL_EXTENSION);
    ve      = extData->widget;
    °/* ve now references the VSE object */°
\end{verbatim}

% End of Grab.tex
