The Motif Protocol

The protocol revealed here was essentially reversed engineered from what Motif was observed to do, with some assistance from its source code, and also the source code of the Intrinsics.

In general, when using the secondary-selection, there are two windows involved (if they happen to be the same, then the implementation will likely use some shortcut)

Note that the two windows may belong to different clients, quite possibly using different toolkits, so the protocol has to be defined at the X-Window level. Note also that it is the Donor which initiates the protocol (because, until you start clicking in the Donor -  with Ctrl down, or whatever - nobody knows that a secondary-selection operation is happening.

Firstly, we have to invent a brand-new selection, with AtomName "_MOTIF_DESTINATION" (yes, X-Windows allows you to invent new selections, in fact the clipboard is just a selection in disguise). We shall refer to this as the motif-selection; it contains no data to be copied around, but it does have an associated target with AtomName "INSERT_SELECTION".

Every selection has an owner, and it is arranged, by means to be discussed later, that the Recipient is the owner of the motif-selection.

So here we go:

  1. The Donor sets a property of type "ATOM_PAIR" on itself
    typedef struct {
    	Atom selection;
    	Atom target;
    } _XmTextInsertPair;
    _XmTextInsertPair atomPair = {XA_SECONDARY, None};
    XChangeProperty(the_display, the_donor, a_property, "ATOM_PAIR", 32, PropModeReplace, &atomPair, 2);
  2. The Donor goes through the motions of pasting the motif-selection to its own insertion-point (of course, nothing actually gets pasted there.
    So it sends a SelectionRequest to the motif-selection owner (which is, of course, the Recipient).
    {
      type       xselectionrequest;
      ...
    owner the_recipient; requestor the_donor; selection "_MOTIF_DESTINATION"; target "INSERT_SELECTION"; property a_property; ...
    }
  3. The Recipient has been requested to supply a motif-selection, but it does not send it yet. Instead, it obtains the "a_property" from the Donor (i.e. the ATOM_PAIR), so it knows that a secondary-selection is on offer and proceeds to request the Donor to send it.
  4. The Recipient sends a SelectionRequest to the Donor
    {
      type       xselectionrequest;
      ...
    owner the_donor; requestor the_recipient; selection XA_SECONDARY; target some-target; property a_property; ...
    }
  5. The Donor endeavours to convert its secondary-selection to match the "some-target" requested.
  6. If the Recipient perceives that the property in the notification was "None", and it has other targets it can accept, then it may return to Step 5; Rinse and Repeat until either some target succeeds (in which case the received data gets pasted at the Recipient's insertion-point), or there are no further acceptable targets. Either way, there is nothing more that the Recipient can do; but it is still nominally engaged in processing a request to deliver a motif-selection with target "INSERT_SELECTION". Well, actually there is no data associated with that target, so it just has to notify that it is done.
  7. The Recipient sends a SelectionNotify to the Donor (and the property field within it should be "None" if no pasting had taken place).
  8. The Donor now clears the secondary-selection.

BUT we are still left with the question of how the Recipient, which initiated the whole transaction, came to be the owner of the motif-selection. "Well" you may say "surely the Recipient is just the window with the focus?"; and indeed we were in the focus window when it all started. But since then we have moved the cursor to some other window (the Donor) and started clicking things in there, and current Window Managers will take the view that you intended to move the focus, happily ignoring the fact that you had some modifier such as Ctrl down to indicate that a secondary-selection was being made.

However, the means whereby Motif bestows ownership of the motif-selection are somewhat weird. If a window has the focus, it is a candidate for the honour. But there may be many windows (even sub-windows of one top-level window) which are potentially focusable, each with its own insertion-point. So the rule is that if, while a window is focussed, you do something therein (type, paste, delete, make a selection, etc.) if becomes the owner, but if you focus a window momentarily the ownership remains where it was. Seemingly, even creating a new empty focussed window with insertion-point all ready for typing does not give it the ownership.

Usually in Motif this does the Right Thing, but occasionally it causes surprises. So for my experimental GTK+ implementation I have done it differently. Initially you are in the Recipient window when you decide to summon a secondary-selection; so you press some modifier such as Ctrl which gives your window the ownership of the motif-selection (and releasing that modifier/Ctrl releases that ownership). But if you leave the Recipient window whilst in possession of the motif-selection, that possession becomes permanent, certainly so long as that modifier/Ctrl is held down, and hopefully until you get back to the Recipient or some other window grabs it.

Note that gaining and releasing the motif-selection each time Ctrl is pressed/released will use up lots of compute cycles, so in a production system there would be a flag to record motif-selection-intended until such time as the system really needed to know. Also, current Window Managers will do their best to thwart your intentions by moving the focus to the Donor window when you least want it. I have a hacked version of compiz which avoids this, and makes using secondary-selections much more pleasant.

All this is fine until the window you are working in pops up some dialog with a GtkEntry inside it, and causes same to acquire the focus (e.g in gedit you use such a dialog to Open a new file or to Find some text). So although the cursor is probably still in the original window outside of that dialog, anything you type will appear in the focussed entry. Now, if you want that entry to become the Recipient for some filename or search-text you first have to move the cursor inside that entry before pressing Ctrl and moving out of it again so as to make it become the motif-selection owner. This is a nuisance, and error-prone, so I have made a special provision that if you leave the original now-unfocussed window with Ctrl down, and there exists another focussed window which has demonstrably been popped up by the original window, then that focussed window becomes the Recipient and acquires the motif-selection.

There is one final snag you should be aware of. The text-editor nedit is probably the best known Motif application, and it duly provides secondary-selection facilities. However, it does not use the standard Motif library for the purpose; rather it Rolls-its- Own secondary-selection implementation and, Horror of Horrors! it uses the AtomName "MOTIF_DESTINATION" (no leading underscore) for its motif-selection, thus rendering it non-interoperable with other Motif applications, let alone with my experimental GTK+.

CONTINUE