source: trunk/third/startup-notification/doc/startup-notification.txt @ 20837

Revision 20837, 13.6 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20836, which included commits to RCS files with non-trunk default branches.
Line 
1Startup notification protocol
2===
3
4This document specifies a mechanism allowing a desktop environment to
5track application startup, to provide user feedback and other
6features.
7
8Version: 0.1
9Revised: October 20, 2002
10Authors: Lubos Lunak, Havoc Pennington
11
12Terms
13===
14
15Launch:   a "startup event" such as opening a new window, opening a new
16          application, or adding a panel applet. Note that the
17          launch may or may not involve creating a new UNIX process.
18Launcher: code which starts up a launch
19Launchee: code which is started up by the launcher
20
21X Messages
22===
23
24"X messages" are a mechanism for sending text strings between X
25clients.
26
27To send a string as an X message, a client does the following:
28
29 - Creates an X window to be used to identify the message
30   uniquely. This window need not be mapped, and may be
31   a child of any window.
32
33 - Interns atoms type_atom and type_atom_begin indicating
34   the type of message.
35
36 - Decides on a target_xwindow; this is the root window
37   for "broadcast" messages, or a specific client's window.
38
39 - Send a series of client messages to the target X window, where each
40   client message contains a portion of the string. The client
41   messages should have the window field set to the X window
42   identifying the message, the format field set to 8, and
43   the message_type field set to the type of message, type_atom_begin
44   for the first client message and type_atom for any following client
45   messages.
46
47   The last byte used in the last client message must be nul, and no
48   intermediate bytes may be nul. The nul byte identifies
49   the end of the message.
50
51   Client messages must be sent to the chosen target_xwindow, with the
52   event mask PropertyChangeMask.
53
54   (FIXME this is a bad choice of mask, as we get a bunch of annoying
55   PropertyNotify events; but which mask would be better?)
56
57   Attachment "A" contains example code.
58
59 - Destroys the unique X window used to identify the message.
60   The window can be destroyed immediately, it is only used
61   for its window ID.
62
63Implementations may impose a maximum length of message they are
64willing to accept. Typically this length will be reasonably low,
65perhaps 4K of data.
66
67Key-value strings
68===
69
70The specific strings sent during startup notification encode a message
71type, followed by a list of key-value pairs. Here is an example:
72
73  new: NAME="Hello World" PID=252
74
75A string listing key-value pairs works as follows:
76
77 - the entire string must be valid UTF-8. Invalid strings should be
78   discarded as corrupt, as accepting bad data leads to
79   interoperability problems. (Learn from web browsers.)
80
81   Although the string is UTF-8, parsing is specified in terms of
82   bytes not characters in the below specification.
83
84 - all bytes up to the first ':' byte indicate the type of the
85   message. If the message contains no ':' byte it should be discarded
86   as corrupt.
87
88 - To find the start of a key, the ':' byte delimiting the message
89   type must be skipped. Any space (' ') bytes following it must also
90   be skipped. (Other kinds of whitespace must not be skipped.)  The
91   first non-' ' byte after the ':' byte is the start of the first
92   key.
93
94 - All bytes until the next '=' byte form the name of the
95   key. The '=' byte should be discarded, as it delimits the
96   key from the value.
97
98 - Parsing of the value begins with the byte immediately following the
99   '=' byte.  The value is parsed
100   as follows.
101
102   There are two dimensions, "escaped" and "quoted", creating 4
103   states:
104
105     - escaped = TRUE quoted = TRUE
106         . the current byte is appended literally, and the escaped
107           flag is set to FALSE
108
109     - escaped = TRUE quoted = FALSE
110         . the current byte is appended literally, and the escaped
111           flag is set to FALSE
112
113     - escaped = FALSE quoted = FALSE
114         . if the current byte is a double quote '"' it is
115           discarded, and the quoted flag is set to TRUE
116         . if the current byte is a backslash '\', it is
117           discarded, and the escaped flag is set to TRUE
118         . if the current byte is a space ' ' byte or nul byte,
119           the end of the value has been reached
120         . any other byte, INCLUDING tabs, newlines, etc., must be
121           appended literally.
122
123     - escaped = FALSE quoted = TRUE:
124         . if the current byte is a double quote '"'
125           it is discarded, and the quoted flag is
126           set to FALSE
127         . if the current byte is a backslash '\'
128           it is discarded, and the escaped flag
129           is set to TRUE
130         . otherwise the current byte is appended literally
131
132   If a nul byte is seen in a state other than escaped = FALSE
133   quoted = FALSE, it is an error, and the message should be discarded
134   as corrupt.
135
136   Note that the escaping here is simpler than either C string literal
137   escaping, or shell quoting. Unlike C string literals, "\n" means
138   "the letter n," not "newline"; unlike quoted shell strings, "\e"
139   means "the letter e," not "backslash followed by the letter e."
140
141   Note that an empty string can be represented by simply not
142   including a value before the first whitespace, as in FOO:
143      FOO= NAME=Hello
144   or by empty quotes as in BAR:
145      BAR="" NAME=Hello
146
147 - Once the end of the value has been reached, any space (' ') bytes
148   should be skipped. The first non-' ' byte is the first byte of the
149   next key.
150
151Note that keys are case-sensitive, Foo and FOO are different keys.
152
153
154Startup notification
155===
156
157The startup notification protocol involves sending X messages with the
158message_type atom _NET_STARTUP_INFO_BEGIN/_NET_STARTUP_INFO to the
159root window.  In multihead setups, the messages should go to the root
160window of the X screen where the launchee application is being
161launched.
162
163As a general convention, any key-value pairs in startup notification
164messages that aren't understood by a given client should be ignored by
165that client. Also, any keys or message types not documented here must
166be prefixed by the two bytes "X-" as in "X-myproperty" or
167"X-mymessage".
168
169All messages in the startup notification protocol refer to a "startup
170sequence"; a "startup sequence" reflects a single launch event.
171
172Here are the message types ("message types" here means the type at the
173beginning of the message string, not the type of the X message):
174 
175  new:    message indicating that a new startup sequence has been
176          initiated. The key-value pairs in this message indicate the
177          properties of the startup sequence. If this startup sequence
178          already exists, "new:" message is equivalent to "change:"
179          (i.e. the values are updated instead of creating a new
180          startup sequence).
181         
182
183  change: message updating an existing startup sequence. If a client
184          has not seen a "new:" message for the same sequence, then
185          all "change:" messages should be ignored. i.e. a "change:"
186          message should not be taken as a "new:" message.
187
188          "change" messages contain a subset of the keys allowed
189          in a "new" message. Not all attributes of the startup
190          sequence are allowed to change over time.
191
192  remove: message ending a startup sequence. Once this message
193          has been seen for a given sequence, any further
194          messages referring to the sequence should be ignored.
195         
196All messages must include these keys:
197
198  ID
199 
200          uniquely identifies a startup sequence; should be some globally
201          unique string (for example, hostname+pid+current time).
202
203The following keys are required in a "new" message and may be included
204in either a "new" or a "changed" message:
205
206  NAME   
207
208          some human-readable name of the item being started;
209          for example, "Control Center" or "Untitled Document";
210          this name should be localized.
211
212  SCREEN
213
214          the X screen number the startup sequence is on
215
216The following keys may be provided optionally in either a "new" or a
217"changed" message:
218
219  BIN     
220         
221          name of the executable being started, argv[0]
222         
223  ICON   
224 
225          a string to be interpreted exactly as the "Icon" field
226          in desktop entries is interpreted.
227
228  DESKTOP
229
230          the desktop on which the application should appear,
231          counting from 0, as in _NET_WM_DESKTOP. However,
232          this value should never override a _NET_WM_DESKTOP
233          property set on window that's being mapped.
234          This desktop is relative to the screen provided by
235          the SCREEN key.
236
237  TIMESTAMP
238
239          X server timestamp of the user action that caused this
240          launch. For example window manager that doesn't allow
241          stealing of focus by newly mapped windows while the user
242          works in an application can use this timestamp for windows
243          that have matching _NET_STARTUP_ID property if they don't
244          have any _NET_WM_USER_TIME property set or if it's older.
245          See the description of _NET_WM_USER_TIME in the WM spec
246          for details.
247
248  DESCRIPTION   
249
250          a short description suitable for display in a dialog that
251          indicates what's happening. For example "Opening document
252          Foo" or "Launching KWord" - the description should be in
253          "foo-ing whatever" format, describing the current status.
254
255  WMCLASS
256
257          a string to match against the "resource name" or "resource
258          class" hints. If this key is present, the launchee will most
259          likely not send a "remove" message on its own. If the
260          desktop environment detects a toplevel window mapped with
261          this name or class, it should send a "remove" message for
262          the startup sequence. Note that the class hint is in
263          Latin-1, so the value of this key must be converted to
264          Latin-1 before strcmp'ing it with the window class/name.
265          (Though in all known cases only ASCII is involved so it
266          doesn't matter.)
267         
268  SILENT
269         
270          a boolean (1/0) value. When set to 1, there should be
271          no visual feedback. This can be used to suspend
272          the visual feedback temporarily, e.g. when
273          application shows a dialog during its startup before
274          mapping the main window. Another use is for launch
275          sequences for applications that are neither compliant
276          nor their WMClass is known, but which should preferably
277          have their window mapped on the desktop specified by
278          the value of DESKTOP.
279
280Some details of the startup sequence:
281
282 - "new" and "change" messages are sent by the launcher code
283
284 - the launchee code is responsible for sending a "remove"
285   message to end the launch sequence, unless the WMCLASS
286   key was set.
287
288 - the "new" message must be the first message. Other message
289   types should be ignored by all clients unless those clients
290   have seen a "new" message with the same ID.
291
292 - "change" messages can be sent at any time between "new" and
293   "remove"
294
295 
296Communicating from a launcher process to a launchee process
297===
298
299To communicate the startup sequence information from a launcher
300process to a launchee process, when possible an environment variable
301should be used:
302
303 DESKTOP_STARTUP_ID
304   value of the "ID" field in the "new" message
305
306It is suggested to unset this environment variable in the launchee
307as soon as it's read, to avoid possible reuse by some process started
308later by launchee.
309Mechanisms other than the environment variable may be used as well, as
310long as they are reliable. The environment variable is only used when
311the launchee code is in a process started by the launcher code; if
312they are in the same process the environment variable may not be
313relevant.
314
315Desktop entry spec extensions
316===
317
318StartupNotify=BOOLEAN
319
320  If true, it is KNOWN that the application will send a "remove"
321  message when started with the DESKTOP_LAUNCH_ID environment variable
322  set.
323
324StartupWMClass=STRING
325
326  If true, it is KNOWN that the application will map at least one
327  window with the given string as its WM class or WM name hint.
328
329EWMH spec extensions
330===
331
332_NET_STARTUP_ID, UTF8_STRING
333
334  The ID used for the startup sequence for the window. If set
335  on a group leader window, applies to all application windows
336  in that group that do not set their own _NET_STARTUP_ID.
337
338
339Launchee failures
340===
341
342The launcher process is responsible for detecting launchee failures
343such as a crash and should end the launch sequence in such case.
344In case launchee fails to end the launch sequence, clients should
345treat the launch sequence as ended withing a reasonable time.
346
347
348A. Sample code to send X message
349===
350
351This code omits creation/destruction of "xwindow" which is the unique
352identifier window for the message. It should be created just before
353this code and destroyed just after.
354   
355       XEvent xevent;
356       const char *src;
357       const char *src_end;
358       char *dest;
359       char *dest_end;
360
361       xevent.xclient.type = ClientMessage;
362       xevent.xclient.message_type = type_atom_begin;
363       xevent.xclient.display = xdisplay;
364       xevent.xclient.window = xwindow;
365       xevent.xclient.format = 8;
366
367       src = message;
368       src_end = message + strlen (message) + 1; /* +1 to include nul byte */
369
370       while (src != src_end)
371         {
372           dest = &xevent.xclient.data.b[0];
373           dest_end = dest + 20;
374
375           if (src == message)
376             {
377               *dest = '\0';
378               ++dest;
379             }
380
381           while (dest != dest_end &&
382                  src != src_end)
383             {
384               *dest = *src;
385               ++dest;
386               ++src;
387             }
388
389           XSendEvent (xdisplay,
390                       target_xwindow,
391                       False,
392                       PropertyChangeMask,
393                       xevent);
394
395           xevent.xclient.message_type = type_atom_begin;
396         }
Note: See TracBrowser for help on using the repository browser.