Search Parameter Sharing Protocol for the X Window System

--------

Introduction

Many programs allow the user to search through text, be it a text file, a collection of email messages, or a web page. Sometimes one has the text for which to search in one program (e.g. in a mail message) while the text in which to search is in a different program (e.g. a text editor or a web browser). While one can usually copy the search string from the source program and paste it into the destination program, it is even more convenient if the programs can share this text directly. The Search Parameter Sharing Protocol (XSearch) provides an elegant, efficient way to share both the search string and the replace string, thereby replacing the sequence
  1. go to program #1
  2. copy text
  3. go to program #3
  4. open search dialog
  5. paste text into search string input field
  6. go to program #2
  7. copy text
  8. go to program #3
  9. open search dialog
  10. paste text into replace string input field
  11. search
with the must shorter sequence
  1. go to program #1
  2. use selection as search string
  3. go to program #2
  4. use selection as replace string
  5. go to program #3
  6. search
Many text editors already provide this convenience between windows within the application. The XSearch protocol can be viewed as an extension of this ability to work with all windows on the desktop.

Current version: 1
Last updated on May 1, 2000

Supporters of the XSearch protocol

Other related protocols


Definitions

The search string is the text for which to search.

The replace string is the text to be substituted in place of the search string, once it is found.

An entire word match is one where the match starts and ends at a word boundary. As an example, searching for "and" would not match "band."

An entire partial word match uses a more restrictive definition of a word boundary which is particularly useful for source code. In addition to the ends of a word, a partial word boundary also occurs within a word when one encounters a change in case or a non-alphabetic character. As an example, "call_me_ishmael" contains three partial words, and so does "GetDNDAction."

The version window is the X window on which the XsearchVersion property is set.

The data window is the X window on which the XsearchDataV* properties are set.


Procedures

Initialization

When a program starts, it must initialize itself so that it can use the XSearch protocol. Define D1 to be the display that is already open.

  1. Call XOpenDisplay(DisplayString(D1)) to create a new connection (D2) to the same X server.

  2. Create two X windows via D2 with the "override redirect" property so they will be invisible to the user. These will be the version and data windows if nobody else has already initialized XSearch. Creating the windows via a separate Display allows the program to be lazy about releasing the rest of its resources when terminating.

  3. Call XSetCloseDownMode(D2, RetainPermanent) to guarantee that the version and data windows will persist even after the program exits.

  4. Call XCloseDisplay(D2).

  5. Call XGrabServer(D1) to avoid race conditions.

  6. If the XSearchWindows property does not exist on the root window:

    1. Store the version and data window ID's in the XSearchWindows property on the root window.
    2. Set the search parameters, as explained below.

  7. If the XSearchWindows property exists on the root window:

    1. Call XKillClient() on the version window created in Step 2. It is not sufficient to merely destroy the windows because then the X server will still eventually run out of client slots.
    2. Retrieve the version and data window ID's stored in the XSearchWindows property.
    3. Retrieve the search parameters, as explained below.

  8. Call XSelectInput() on the version window with PropertyChangeMask.

  9. Call XUngrabServer(D1).

Setting the search parameters

The search parameters must be updated when:

To update the search parameters:
  1. Call XGrabServer() to avoid race conditions.

  2. Request ownership of the X Selection named XsearchSelection. If this fails, call XUngrabServer() and give up.

  3. Update the window properties XsearchDataV1 to XsearchDataVN on the data window, where N is the maximum version that the program can write.

  4. Update the window property XsearchVersion on the version window to contain the value of N from Step 3.

  5. Call XUngrabServer().

Retrieving the search parameters

The search parameters must be retrieved when the program receives a PropertyNotify event from the version window for the XsearchVersion property and the program does not currently own XsearchSelection.

  1. Retrieve the XsearchVersion property from the version window.

  2. Retrieve the XsearchDataVN property from the data window, where N is the minimum of the value from the XsearchVersion property and the highest version that the program supports.
Unfortunately, one cannot optimize this by waiting to retrieve the data until the search dialog is activated or a search is performed. One must enable or disable menu items such as "Search forward" based on whether or not the current search string is empty. Waiting for the user to open the menu or press a shortcut key is pointless because the menu items may be on the toolbar, in which case they have to be enabled or disabled as soon as a change occurs.


Proof of Efficiency

The XSearch protocol provides the most efficient method for the current owner of the search parameters to broadcast changes in these parameters to all other programs that support the protocol.

All properties are stored on two persistent windows: the version window and the data window. The ID's of these windows are stored in the XSearchWindows property on the root window so all programs can find the windows once they have been created. Storing XsearchVersion on its own window minimizes the number of PropertyNotify events received because each program only needs to listen to the version window. Storing XsearchDataV* on a separate window avoids sending unnecessary PropertyNotify events to programs that are forced to listen to other properties on the root window.

Storing XsearchVersion separately from the data also allows each receiver to retrieve only two window properties: XsearchVersion and then a single XsearchDataVN, as explained in the Procedures section.

XsearchSelection is used to reduce the network traffic and improve performance. Since the server is grabbed when the search parameters are updated, each program is guaranteed to receive a SelectionClear message for XsearchSelection before it receives any PropertyNotify events that were generated by other programs. Thus, if a program thinks that it currently owns the selection, then that program can ignore PropertyNotify events because they must result either from the program's own changes or from changes made by other programs before this program last took ownership of the selection (i.e. events still in transit from the server or in the Xlib queue when the server was grabbed). The latter reason obviously reduces network traffic. The former reason eliminates the four packets required to retrieve XsearchVersion and XsearchDataVN, at a cost of three packets to obtain ownership of XsearchSelection and one packet to notify the previous owner. Even though there is no net change in traffic in this case, it does reduce the delay required to set the data because retrieving the two window properties requires two blocking round trips to the X server and redrawing of the screen to display the new values, while obtaining ownership of XsearchSelection only requires one blocking round trip (the mandatory check of XGetSelectionOwner()).

Since the version property is modified separately, programs may not manage to retrieve the data before somebody else modifies the data in preparation for sending a new PropertyNotify event. This is not dangerous, however, because XChangeProperty() is atomic, so the receivers will simply get data that is closer to being current. If the new owner doesn't support the previous owner's version, the receiver will get the "correct," outdated data. Either way, another PropertyNotify event will already be in the queue, and this will force the receiver to update to the correct data. Note that such rapid changes are very unlikely since they are triggered by user actions which are orders of magnitude slower than the typical network. Repeated, redundant updating will therefore happen very rarely, if at all.

An alternate protocol would be to modify only a version property and have each receiver request the contents of the XsearchSelection. In an environment with many programs that support the XSearch protocol, this puts an unnecessarily large load on the network. Define NV to be the number of XSearch protocol versions and NR to be the number of receivers. Retrieving a selection requires seven packets per receiver, while the current method requires only NV packets to set XsearchDataV*, and two packets per receiver. (This ignores the packet to set XsearchVersion, the packet to each receiver containing the PropertyNotify event, and the two packets per receiver to retrieve XsearchVersion. These packets are required by both protocols.) As long as NV+2*NR<7*NR, the protocol that is used by XSearch requires significantly less network traffic. It also puts far less load on the source program since the source does not have to respond to SelectionRequest events.


Notes

Regular expression searching is provided by many programs. Unfortunately, since there are so many dialects, it is not possible to make this part of the official protocol. Instead, specification of the dialect is covered by the provision for extended data, as described in the Technical Details section. This allows programs that use the same dialect to share the parameters. For other programs that do not understand the dialect, the user must translate the regular expression manually. (The regular expression should always be treated as any other search string, because this saves the user the trouble of copying it from one program to another.)


Technical details

Current version: 1

All constants mentioned below are the string names of X atoms, capitalized as shown. This avoids the need for hard-coded values, which would require a global registry.


Atoms and Properties

XsearchSelection

This is the name of the X Selection that is used to avoid retrieving ones own data.

XSearchWindows

This window property must be set on the root window and must be of type XA_WINDOW. It contains the ID's of the version and data windows, in that order.

XsearchVersion

This window property is set on the version window and must be of type XA_ATOM. It contains the maximum XSearch protocol version supported by the program that last set the contents of XsearchDataV*.

XsearchDataV*

These window properties are set on the data window and must be of type text/plain, including the charset attribute, if it is not ISO-8859-1. This allows the search and replace strings to be in any language. Programs that cannot handle the character set can ignore the data.

The version number is encoded in the property name so programs that do not support the latest version can still easily retrieve data that they can interpret.

XsearchDataV1

Version 1 of the XSearch protocol contains the following data:

  1. Search string (charset is obtained from property type)
  2. 0x00
  3. Replace string (charset is obtained from property type)
  4. 0x00

  5. 0x54 (T) if the search should wrap when it reaches the end of the text.
    0x46 (F) if the search should stop when it reaches the end of the text.

  6. 0x54 (T) if the search should only report "entire word" matches.
    0x46 (F) if the search should report all matches.

  7. 0x54 (T) if the search should only report "entire partial word" matches.
    0x46 (F) if the search should report all matches.

  8. 0x54 (T) if the search should ignore upper vs. lower case when reporting matches.
    0x46 (F) if the search should only report matches where the case also matches.
For all four flags, the value can also be 0x58 (X) if the provider does not support the feature. In this case, if the receiver does support the feature, the receiver should not change its current setting.

Providing additional search parameters

Most programs provide many features beyond simply searching for a literal string. Regular expression searching is the most common (see Notes section). In order to allow programs to share such additional information, one can append additional data to the XsearchDataV* properties after appending 0x00, followed by a unique tag to identify the data format, followed by 0x00. To allow for new formats of this data in later releases, the data itself should have the format: first version id, data, second version id, data, etc. This allows each program to retrieve the newest version that it can handle by skipping over the older versions. As an example, the JX Application Framework appends the following data

  1. 0x00
  2. JX_Application_Framework
  3. 0x00
  4. 0x31 (1)

  5. 0x54 (T) if the search string is a Spencer regular expression with certain Perl extensions.
    0x46 (F) if the search string is a literal string.

  6. 0x54 (T) if the search string is a regular expression and newlines should not automatically terminate the match.
    0x46 (F) otherwise.

  7. 0x54 (T) if the replace string is a Perl replacement expression that uses $N as a placeholder for the Nth subexpression matched by the search expression.
    0x46 (F) if the replace string is a literal string.

  8. 0x54 (T) if the case of the replace string should be matched to that of the text matched by the search expression.
    0x46 (F) if the replace string should be used without adjusting the case.
For all four flags, the value can also be 0x58 (X) if the provider does not support the feature. In this case, if the receiver does support the feature, the receiver should not change its current setting.


Sample implementation

If you are interested in supporting this protocol, but daunted by having to start from scratch, you can obtain sample C++ code via anonymous ftp. This code may be used under any license.

If you use a different language, please consider donating your code for others to look at.

We also have a binary that you can use to test interoperability between a correct implementation and your implementation.

While implementing this protocol, you may find it very useful to use the programs xlsatoms to list all the atoms that the server knows about, xprop to list all the properties on a particular window, and xscope to study the timing of events.

Even if you implement XSearch from scratch, we would appreciate it if your distribution included some sort of documentation that states clearly that you are supporting this protocol and provides a reference to this web page. This will help get the snowball rolling. The more programs that support the same protocol, the more useful XSearch will be for the users. If you tell us that you support the protocol, we will also add you to the list of supporters.


Changes from previous versions

May 1, 2000:

Initial publication.


Acknowledgements

This protocol was developed by John Lindal at New Planet Software. The original inspiration for XSearch came from NeXT which provided the capability as part of the operating system.