launch feedback status update



Hi,

Here is what's happening in the wide world of launch feedback.

I have a library "liblf" on freedesktop.org that implements both the
proposed spec that I wrote up, and the current KStartupInfo protocol
used in KDE.  You can download a snapshot at
http://pobox.com/~hp/launchfeedback-0.1.tar.gz
I'm talking to Lubos from KDE about sorting out the two protocols.
The KDE protocol doesn't have a "launch ended" step, instead all
launch-feedback-providing apps learn about new windows from DCOP
messages sent from KWin, and stop feedback when one of those matches
the launch. So that needs sorting out.

With either protocol, I think we'll want GTK 2.2 to end launch
feedback when the first GtkWindow is mapped.

We probably want more GTK API eventually, to be able to start new
launch sequences, manually end launch feedback, etc., but for 2.2 just
ending feedback on first map seems sane. We might also add:

 gtk_launch_set_automatic (gboolean setting);

to disable the automatic end on first map, just in case someone wants
to write their own code or use liblf.

Appending docs on the two protocols.

After sorting out the protocol/toolkit level, we need to implement in
a few places in GNOME:

 - panel menus and launchers
 - when opening application help
 - in window manager, start apps on same workspace where the launch 
   started
 - nautilus
 - task list should show tasks as they launch

It's pretty trivial to add the "start feedback" code anywhere we
fork/exec a program, probably it can go in the desktop_file_launch
function. The task list and window manager changes are mildly more
involved but not really hard.

Before anyone asks, I'm postponing GEP on this until the protocol is
more sorted out.

Havoc

Informal draft writeup of how to handle application launching in the X
environment. Needs conversion into an actual spec.

Should potentially dump this and use the KDE client message thing.

Executive summary of end-user benefits
===

 - allow busy cursor launch feedback mode
 - allow launch feedback mode where you put an animation 
   over the icon they clicked to cause the launch
 - allow cancellation of a launch-in-progress
 - allow WindowMaker-style (single-instance) launch buttons to work nicely
 - allow task lists to display the currently-in-progress launches
 - allow choice of which program displays the launch feedback
 - avoid ending up with two conflicting launch feedbacks at once (e.g.
   two different animations on the launcher icon)
 - allow launch feedback for launches inside a single process
   (for example opening a file manager window by clicking
   on a directory icon)
 - generic spec works across desktops

Design Goals
===

 - as close to 100% reliable operation as possible. 
   "If everything implements the spec properly, then everything 
    will work properly."

 - have a single program provide launch indication for the whole
   desktop, regardless of who is launching it; this provides
   consistency

 - easy to support correctly in applications, so we can 
   add native support to all toolkits and legacy apps
   (complexity burden placed on desktop components rather
   than individual apps)

 - ensure we have a path away from LD_PRELOAD hacks and such - i.e., a
   way to avoid such hacks for apps that support the protocol
   natively, so that once most apps support it natively, we can drop
   the hacks
 
 - allow apps to control the indicator; for example, an app may want 
   to map a window of some kind without removing the indicator, 
   or remove the indicator before mapping a window.

 - allow the window manager to keep track of when apps are launched
   and which windows belong to a given launch attempt - this allows
   the WM to for example put an app on the workspace which was active 
   at launch time

 - allow the WM to be notified when an app has reached its final
   start-up state. For example, if a word processor launches a splash
   screen, then the main window, then both the splash screen and the
   main window could be placed on the workspace which was active at
   launch-time. However, this needs to happen without forcing all
   windows from that app to always be on the launch workspace. So the WM
   needs to know when an app's windows should no longer be treated in
   a special way.
 
 - allow a similar feedback mechanism and WM special-casing for 
   opening new windows within an application. For example, when
   opening a new word processor window, it might be nice to 
   keep it on the workspace where "New" was selected from the menu.
   (Of course it would be nicer if opening a new window were fast, 
   but for some apps that may not always be true. Consider 
   opening a large document, for example.)

 - allow indication that is sensitive to where and how the 
   launching occurred; for example a sparkle at the launch point.
   This should work even if the launch point is inside a 
   user-reconfigurable window.

 - allow apps to open new windows, or just plain start up, without
   progress indication. This would normally be done for programs that
   users may not think of as apps; say a panel applet. The main point
   here is that toolkits should be able to provide API to control the
   launch feedback, and the spec has to allow toolkits to implement
   that

 - allow the user to cancel a launch-in-progress, for example if the
   progress indicator is a dialog, they could press the Stop button; 
   if it's a busy cursor, the window manager might provide a keybinding.

Proposed solution overview
===

There is a concept of a "launch sequence."  A launch sequence
typically begins when the user asks to launch an application or open a
new document, and ends when the app or document finishes loading.

Each launch sequence is identified by a unique ID. The launching
program initially notifies the launch manager that a launch ID exists
and gives the launch manager pertinent information about how to
display progress. Subsequent information about the status of the
launch is provided to the launch manager as appropriate, by the
launching program and also the launched application.

Launch Sequence
===

A launch sequence is an instance of launching something. For example,
running a program or opening a new window. Each launch sequence
involves a launcher (the program doing the launching) and a launchee
(whatever is being launched). 

Launch sequences are identified by a launch sequence ID. The launch
sequence ID is a string, generated as follows:

  LAUNCHER/LAUNCHEE/XTIMESTAMP/UNIQUENESS

The elements are:

 - name of launcher; no rigorous semantics
 - name of launchee; no rigorous semantics; can be same as launcher
 - X timestamp from event causing the launch, or most recent 
   timestamp received; not CurrentTime, for obvious reasons
 - a uniqueness string; launchers should use this to ensure the
   launch sequence ID is unique if they launch two or more copies
   of the same application at the same time

The launcher/launchee names "namespace" the subsequent fields, and are
intended to be helpful when debugging. The X timestamp makes it very
likely that the launch ID is unique across the X display. The
uniqueness string ensures uniqueness for sequences from a given
launcher process.

It is remotely possible that two launcher process have the same name,
launch the same program, at the same time, and with the same
uniqueness string. Launchers are encouraged to use something other
than a monotonically increasing serial number for the uniqueness
string, as an extra safety net. For example, they might include their
process ID or some random digits. Including the hostname of the 
launcher may make sense as well.

The launch sequence ID should be a valid UTF-8 string.

The four elements of the sequence ID may not contain the '/' separator
character, since that would render the ID unparseable. That said, no
application should rely on parsing the sequence ID; its format is only
specified as a debugging aid, and to ensure that IDs are unique.

An example sequence ID is:
 gnome-panel/kword/5419456/xw45c2z-342

Launch Sequence Window
===

Each launch sequence has a number of attributes that need to be
communicated between the launcher program, any programs displaying
launch feedback, and the program being launched. The easiest way to
share key-value pairs between X clients is to use an X window.

Each launch sequence thus has a corresponding X window, created by the
launcher program, where launch sequence properties can be set
and launch-related messages can be sent.

The launch sequence window must be an immediate child of a root
window. It should have the override_redirect attribute set to True,
and should never be mapped.

Launch sequence windows must be created specifically for a given
launch; they may not be recycled. Recycling them makes things harder
to implement correctly.

The following property MUST be set on this window before initiating
a launch:

 - _NET_LAUNCH_ID  STRING

   The launch sequence ID


The following properties are optional, but if set must be set
before initiating the launch, and unless otherwise noted should be
left unchanged throughout the launch sequence:

 - _NET_LAUNCH_TYPE ATOM[]/32

   A list of atoms indicating the context of the launch, with the most
   appropriate atoms first in the list. The property is an array to
   support adding new types in the future; clients can specify both an
   older type and an extended type.

      _NET_LAUNCH_TYPE_OTHER
      _NET_LAUNCH_TYPE_DOCK_ICON 
      _NET_LAUNCH_TYPE_DESKTOP_ICON
      _NET_LAUNCH_TYPE_MENU
      _NET_LAUNCH_TYPE_KEY_SHORTCUT

   If the property is unset or contains only unrecognized atoms, OTHER
   should be assumed.

   Rationale: the launch feedback display may choose to special-case
   some of these. For example, you can't display an animation over the
   top of a menu or key shortcut, but you can over a desktop or dock
   icon.

 - _NET_LAUNCH_GEOMETRY CARDINAL[4]/32

   x, y, width, height geometry of the icon the user 
   clicked to begin the launch. The coordinates 
   are relative to _NET_LAUNCH_GEOMETRY_WINDOW if 
   that property is set, otherwise to the root window
   the launch sequence window is a child of.

   This property may be updated during the launch sequence, 
   to reflect e.g. moving the launch icon.

   If a launcher wants to draw its own feedback on top of an icon, it
   should not set this property.  However drawing one's own feedback
   is discouraged since it's nicer if all apps have the same feedback
   animation.

 - _NET_LAUNCH_GEOMETRY_WINDOW WINDOW/32

   Window that _NET_LAUNCH_GEOMETRY is relative to. Must be either 
   a root window, or a window-managed toplevel application window
   (i.e. a window that the window manager will set WM_STATE on).

   If this window is not a root window, the program displaying
   feedback should track movement of the window around the screen.
   That is, if displaying an animation on the launch icon, if the user
   moves the window containing the launch icon, the animation should
   also move.

 - _NET_LAUNCH_SUPPORTS_CANCEL CARDINAL/32

   Contains 1 if the launcher supports cancelling this launch
   sequence, 0 if not. If the property is unset, 0 should be
   assumed. Cancelling a launch sequence means ending the operation
   that is in progress, for example killing the application being
   launched.

 - _NET_LAUNCH_NAME UTF8_STRING

   The user-visible name of the launch sequence; normally the name of
   the application being launched, or the name of the document being
   loaded.

 - _NET_LAUNCH_DESCRIPTION UTF8_STRING

   A short description suitable for display in a dialog that indicates
   what's happening. For example "Opening document Foo" or
   "Launching KWord" - the description should be in "foo-ing whatever" 
   format, describing the current status.

 - _NET_LAUNCH_DESKTOP CARDINAL/32

   The active workspace from the _NET_CURRENT_DESKTOP property (see
   extended window manager hints specification).  

   Window managers may use this property to put application windows on
   the same desktop they were launched from.  If an application sets
   _NET_WM_DESKTOP, window managers should use the value of that hint
   instead of the value of _NET_LAUNCH_DESKTOP.

   FIXME: is there a race condition because the WM can't tell if a
   MapRequest from a launchee window came before or after a launch
   started/ended? Or is the sequence of receiving those events
   guaranteed?

 - _NET_LAUNCH_BINARY_NAME  STRING

   The name of the binary being launched (argv[0] passed to exec()).
   Note that a launch sequence doesn't necessarily imply a separate
   process, but it can.

 - _NET_LAUNCH_PID  CARDINAL/32
  
   The pid of the process being launched (note that a launch sequence
   doesn't necessarily imply a separate process, but it can).  This
   property must be set after the launch sequence is initiated, since
   the sequence would generally be initiated before forking the child
   process, and the PID isn't known until after forking. However once 
   set this property should not be modified.

 - _NET_LAUNCH_ICON_NAME  STRING

   The name of an icon as used in the "Icon" field of desktop entry 
   files. This name is generally looked up in an icon theme 
   as specified by http://www.freedesktop.org/standards/icon-theme-spec.html

 - _NET_LAUNCH_HOSTNAME  STRING

   The name of the host on which the child process is being launched.
   Should be set to the same value normally used for WM_CLIENT_MACHINE
   on an application window.

 - _NET_LAUNCH_LEGACY_RESOURCE_CLASS STRING

        A class (as for the first part of the WM_CLASS hint).

   _NET_LAUNCH_LEGACY_RESOURCE_NAME STRING

        A name (as for the second part of the WM_CLASS hint).

   _NET_LAUNCH_LEGACY_NAME  STRING

        A window title (as for WM_NAME)    

   If one or more of these three properties are set, then the launchee
   is a legacy X client. If they are set, the following must be known
   to the launcher via some reliable mechanism:

    - the legacy X client will create at least one new toplevel
      managed window
    - the toplevel managed window it creates will have the 
      given class/name/title
    - the legacy X client does not support this specification

   If one of these properties is set, then [FIXME, who] is responsible
   for completing the launch sequence by setting _NET_LAUNCH_COMPLETE
   when the legacy launchee maps a toplevel X window that matches the
   given resource class, name, and title. If multiple properties are
   set, they must all be matched; that is, if both a legacy class and
   a legacy title are given, then the launch sequence ends only after
   mapping a window matching both the class and the title.

The following property may be set at any time by any client:

 - _NET_LAUNCH_CANCELED CARDINAL/32

   The value of this property is irrelevant; if the property exists,
   the user has asked to cancel the launch. This property may be
   set by any X client in response to user input.

   If the launcher program set _NET_LAUNCH_SUPPORTS_CANCEL, then 
   it should listen for PropertyNotify on this property, and cancel
   the launch if a PropertyNotify is received.

   If the launcher program did not set _NET_LAUNCH_SUPPORTS_CANCEL,
   it may ignore _NET_LAUNCH_CANCELED.

   Programs displaying feedback should not end launch feedback when
   _NET_LAUNCH_CANCELED is set; instead, they should wait for the
   cancellation to take effect.

The following property should be set by the launchee once it considers
itself fully started up, or by the launcher after cancellation:

 - _NET_LAUNCH_COMPLETE CARDINAL/32

   The launchee program should set this property on the launch 
   window when the launch sequence is complete. The launchee should 
   map all windows that are part of an application's initial 
   state BEFORE it sets this property. After launching is complete, 
   window managers will not place newly-mapped windows on the 
   launch workspace.

   The launcher program should set this property on the launch 
   window after cancelling the launch.

   Launch feedback should be ended if _NET_LAUNCH_COMPLETE has been
   set.

   The launcher program must destroy the launch sequence window 
   after this property is set.

The following message may be sent to the launch window by the launchee
to indicate that it's working on starting up:

 _NET_LAUNCH_PULSE

   window = launch sequence window
   message_type = _NET_LAUNCH_PULSE 
   format = 32
   data.l[0] = 0;         /* reserved, always set to 0 */
   data.l[1] = 0;         /* reserved, always set to 0 */

   Launchees are encouraged to re-send _NET_LAUNCH_PULSE at regular
   intervals, indicating that progress continues. This property should
   be set before and during showing a splash screen, for example. See
   implementation notes for more details.

   The purpose of this property is to allow the displayer of feedback
   to feel confident that the application is moving forward, and avoid
   e.g. putting up a "the launchee appears to be stopped" dialog on
   top of the launchee's splash screen.

Launch initiation
===

Before initiating a launch, the launcher program should create a 
launch sequence window and set its initial properties.
Then, it should send a client message to all root windows
on the current display as follows:

 _NET_LAUNCH_INITIATE
   window = launch sequence window
   message_type = _NET_LAUNCH_INITIATE 
   format = 32
   data.l[0] = timestamp; /* X timestamp of event (mouse click, etc.) causing
                           * launch, or CurrentTime if unavailable
                           */
   data.l[1] = 0;         /* reserved, always set to 0 */
   data.l[2] = 0;         /* reserved, always set to 0 */
   data.l[3] = 0;         /* reserved, always set to 0 */

The event mask passed to XSendEvent() should be "PropertyChangeMask."

Note that an XFlush() is required after creating the launch sequence
window but before sending the client message, to be sure the launch
sequence window is available to all clients. (FIXME probably untrue 
as we are passing the window via a client message, not some
out-of-band method.)

The _NET_LAUNCH_INITIATE message should be sent _before_ launching the
launchee. Also, an XFlush() is needed before launching the launchee.
This ensures the feedback program or window manager knows about the
launch prior to the launch actually happening.

Launch termination, launch sequence window destruction
===
   
If a PropertyNotify for _NET_LAUNCH_COMPLETE is received on the launch
sequence window, then launching is complete. Launching is considered
to have ended at the time of the PropertyNotify event.

The launch sequence window may be destroyed at any time, either on
purpose by the launcher application, or because the launcher
application crashes. Clients monitoring a launch sequence should take
this into account.

 - When reading the initial values from the launch sequence window, 
   a BadWindow error indicates that the window was already destroyed.
   In this case, the launch sequence should be ignored. Launch 
   feedback should only be initiated if all the initial properties
   of the launch sequence window are read successfully.

 - Once launch feedback has been initiated, a DestroyNotify on the
   launch sequence window indicates that the launch sequence is
   complete. However, normally a PropertyNotify from
   _NET_LAUNCH_COMPLETE will have been received before the window was
   destroyed. Because DestroyNotify events have no timestamp, the time
   of completion should be taken from the PropertyNotify on
   _NET_LAUNCH_COMPLETE. If _NET_LAUNCH_COMPLETE was never set, the 
   time of completion is unknown.

Launch cancellation
===

If _NET_LAUNCH_CANCELED is set, then the launcher program should
stop launching whatever was being launched, then set
_NET_LAUNCH_COMPLETE, then destroy the launch sequence window.

Property on Launched Application Windows
===

All group leader windows of a launched application should have
the following property:
 
 - _NET_LAUNCH_ID  STRING

   The launch sequence ID, as on the launch sequence window

If windows inside an application are launched using an independent
launch sequence, then those windows may have their own _NET_LAUNCH_ID
which overrides the launch ID on the group leader.  The group leader
launch ID identifies the launch sequence of an entire application.  A
_NET_LAUNCH_ID set on a window itself should be used in preference to
the one on the group leader, if both exist.

The purpose of the _NET_LAUNCH_ID property is to allow window managers
and other applications to associate an application or window with 
the launch sequence that created it. This can be used to transform the
launcher button into a persistent "activate the launched application"
button, for example.

Communicating from a launcher process to a launchee process
===

To communicate the launch sequence information from a launcher process
to a launchee process, when possible two environment variables should 
be used:

 DESKTOP_LAUNCH_ID
   Launch sequence ID
 DESKTOP_LAUNCH_WINDOW
   Launch sequence window ID in hex format, e.g. "0x1a0000d"

Mechanisms other than the environment variable may be used in some
cases.  Keep in mind that launcher and launchee are allowed to be in
the same process, for example when opening a document from the File
menu in an application.

Summary of Responsibilities
===

What each participant in the launch process does.

Launch feedback program(s):
 - establishes policy about timing out clients
 - draws launch feedback animations, sets root window
   busy cursor

Launchee:
 - sets _NET_LAUNCH_COMPLETE
 - optionally sends _NET_LAUNCH_PULSE
 - sets _NET_LAUNCH_ID on group leader and optionally other windows

Launcher:
 - generates launch sequence
 - creates launch sequence window
 - sends _NET_LAUNCH_INITIATE
 - sets DESKTOP_LAUNCH_ID or DESKTOP_LAUNCH_WINDOW environment 
   variables
 - handles _NET_LAUNCH_CANCELED
 - sets _NET_LAUNCH_ID
 - sets _NET_LAUNCH_TYPE
 - sets _NET_LAUNCH_GEOMETRY
 - sets _NET_LAUNCH_GEOMETRY_WINDOW
 - sets _NET_LAUNCH_SUPPORTS_CANCEL
 - sets _NET_LAUNCH_TYPE
 - sets _NET_LAUNCH_NAME
 - sets _NET_LAUNCH_DESCRIPTION
 - sets _NET_LAUNCH_DESKTOP
 - sets _NET_LAUNCH_LEGACY_RESOURCE_CLASS
 - sets _NET_LAUNCH_LEGACY_RESOURCE_NAME
 - sets _NET_LAUNCH_LEGACY_NAME
 - sets _NET_LAUNCH_BINARY_NAME
 - sets _NET_LAUNCH_PID
 - sets _NET_LAUNCH_ICON_NAME
 - sets _NET_LAUNCH_HOSTNAME
 
Anyone:
 - sets _NET_LAUNCH_CANCELED

Desktop entry extensions
===

[These should be included in the desktop entry spec, not in the
 launcher spec]

To share information about launchee applications between desktops, the 
following fields are supported in .desktop files:
 
  LaunchFeedbackSupported=VERSION

    If this field is absent, the app does not support the "launchee"
    part of this specification. If present, the to-be-launched app
    supports this specification and can be expected to set
    _NET_LAUNCH_COMPLETE on the window specified in the
    DESKTOP_LAUNCH_WINDOW environment variable. VERSION should 
    be the newest supported version of the spec.

  LaunchLegacyClass=STRING

    If present, specifies a class for
    _NET_LAUNCH_LEGACY_RESOURCE_CLASS and that property should be 
    set by the launcher. This field will be in Latin-1 for
    "legacy-mixed" desktop files and UTF-8 for regular desktop files, 
    but should be converted to Latin-1 when compared with the 
    WM_CLASS property on client windows.

  LaunchLegacyName   string

    If present, specifies a resource name for
    _NET_LAUNCH_LEGACY_RESOURCE_NAME and that property should be set
    by the launcher. This field will be in Latin-1 for "legacy-mixed"
    desktop files and UTF-8 for regular desktop files, but should be
    converted to Latin-1 when compared with the WM_CLASS property on
    client windows.

  LaunchLegacyTitle  string

    If present, specifies a title for _NET_LAUNCH_LEGACY_NAME and that
    property should be set by the launcher. This field will be in
    Latin-1 for "legacy-mixed" desktop files and UTF-8 for regular
    desktop files. It should be converted to Latin-1 when compared
    with the WM_NAME property on client windows.

The LaunchLegacy properties are mutually exclusive with
LaunchFeedbackSupported. If a .desktop file claims that launch
feedback is supported, and also gives the legacy fields, then the
legacy fields should be used and the launcher should assume that
launch feedback is not supported.

Implementation Notes
===

Multihead is handled by sending the _NET_LAUNCH_INITIATE message to 
ALL root windows on a given display; be sure to do this.

The launch feedback provided should be something relatively
unobtrusive; examples are changing the cursor, or a small animation at
the launcher icon.

Progress dialogs or splash screens should be provided by the launchee
application, rather than by an external program.

The launchee application should complete the launch sequence after it
has its first user-interaction-allowing window onscreen. (That is,
a splash screen should not end the launch sequence, but a dialog or
main window should.)

One possible solution to the "stuck cursor" problem seen with
current launch feedback solutions:

 After a timeout, the launch feedback program might replace the
 unobtrusive feedback (cursor, etc.) with a dialog that has a Stop
 button; when clicked, the Stop button sets _NET_LAUNCH_CANCELED if
 _NET_LAUNCH_SUPPORTS_CANCEL, and otherwise simply sets
 _NET_LAUNCH_COMPLETE to give up on the whole launch feedback thing.

 If a launch feedback app did something like this, the dialog should
 be avoided if _NET_LAUNCH_PULSE has been sent
 recently. _NET_LAUNCH_PULSE indicates that the launchee is moving
 forward and perhaps displaying a splash screen already.

A less-complicated and quite possibly better solution would be to 
just time out the launch after some interval.

Launchers should attempt to detect launchee failures and end the
launch sequence if appropriate; for example, if a launched application
exits with a nonzero exit code, it would be a good idea to set
_NET_LAUNCH_COMPLETE and end launch feedback. The launcher is
responsible for displaying an error dialog to the user in this case.

Launchers should not however end feedback if a launched process exits
normally, because the process may have been a wrapper script, may have
asked an already-open application to create a new window, etc.

Only an external "launch manager" program should "time out" a launchee
and decide to end launch feedback; the launcher application should
never do this, it should only end the launch sequence if it has a good
reason to believe the launchee exited abnormally.

Task lists are encouraged to provide a button for each launch
sequence, and support launch cancellation from this button. This
allows users to get rid of the busy cursor if it's stuck.
Alternatively, a task list integrated with launch feedback could for
example pop up the aforementioned dialog-with-stop-button if you
clicked on the button for the launch sequence.

If displaying an animated busy cursor, the feedback should "spin" the
cursor when _NET_LAUNCH_PULSE is received. Launchees are encouraged to
send _NET_LAUNCH_PULSE messages in tune with their own splash screen
progress bar or the like.

Child processes can inherit a DESKTOP_LAUNCH_ID or
DESKTOP_LAUNCH_WINDOW that doesn't apply to them.  This should not
normally be an issue if the launch sequence for the DESKTOP_LAUNCH_ID
is already completed. If an application starts a child application
prior to completing its own launch sequence, it should clear the
DESKTOP_LAUNCH_ID and DESKTOP_LAUNCH_WINDOW environment variables.
$Id: README.kstartupinfo,v 1.7 2002/02/28 17:02:24 lunakl Exp $


Application startup notification
Lubos Lunak <l lunak kde org>
--------------------------------
--------------------------------


 When a new application is started in KDE, together with it a startup
notification is sent, which is used to show a startup entry in taskbar,
the busy icon next to the cursor and put the window of the started app
on correct desktop.
 This application startup notification ( ASN for short in the following
text ) usually works fine without problems, but some applications and
some special cases may need special handling.
 Right now, this is only an internal KDE standard, but since a toolkit
support would improve the results a bit, I'll try to discuss this
on http://www.freedesktop.org .


Starting apps with ASN :
-------------------------

 When an application is started from the K-Menu or the minicli, and from other
places, ASN is sent automatically for it, assuming a matching .desktop file
is found for the starting application. Application without a .desktop file
don't get ASN ( this may change, but it's unlikely as it creates too many
ASNs which will stay too long until a timeout ). For improving the quality
of ASN and reducing the number of ASNs that don't detect when the application
has started, some .desktop file entries may be helpful ( see below ).
 If you want to start an application in your code, prefer using KRun or
KApplication::startServiceByXXX() calls. Classes like KProcess don't create
ASN, so if you need to use it, you have to send it manually ( only in case
ASN is useful in this case, it shouldn't be sent e.g. for system processes ).
 

.desktop files :
-----------------

These following .desktop file entries affect ASN :

X-KDE-StartupNotify=<bool>
    - if true, this app/service will get app startup notify
    - if false, this app/service will _not_ get app startup notify
    - if not set
        - if it's service, it will _not_ get app startup notify
        - if it's app, it will get app startup notify, but
            X-KDE-WMClass will be assumed to be "0" ( non-compliant )
X-KDE-WMClass=<string>
    - if set, and it's different from "0" ( without quotes ), this
        is the WMClass value for startup notification
    - if it's "0" ( without quotes ), such app is considered non-compliant,
        and the startup notification will stop
            - either if its windows is correctly detected using the default
                WMClass value ( the name of the binary )
            - or if a window is mapped that is not recognized ( doesn't have
                neither _KDE_STARTUP_ID nor _NET_WM_PID property /*CHECKME*/),
                it's assumed this window belongs to the started app;
                the start-on-desktop feature won't work then too
    - if not set, it defaults to the binary name of the app ( ok for most apps,
        including KDE ones )
    - to get the WMCLASS value for any app, run 'xprop' and click on the app's
        window, WMCLASS value for this app should be any of the strings listed
        in the WM_CLASS property ( it's usually the same as the name of the
        app's binary file, in such case it doesn't need to be explicitly set )
MapNotify=<bool>
    - this key is obsolete
    - true is equivalent to X-KDE-StartupNotify=true and no X-KDE-WMClass set
    - false is equivalent to X-KDE-StartupNotify=true and X-KDE-WMClass=0
        - many .desktop files in KDE ( especially in kdebase/kappfinder )
            seem to have MapNotify=false even though it's not needed, this
            needs to be checked and replaced by the needed X-KDE-* values,
            often just X-KDE-StartupNotify=true should be enough
        
 The best way to check if the entries are set correctly is to start
the application and switch to other desktop. If the startup notification
disappears and the application appears on the desktop on which it was
started, it's correct ( with X-KDE-WMClass=0, the start-on-desktop
feature may not work ).

 Ideally, every .desktop file should have X-KDE-StartupNotify set to the correct
value, and for apps which need it also X-KDE-WMClass should be set. This
sometimes gives slightly better behaviour than when these entries are not set.


The KStartupInfo classes : 
--------------------------

 In some cases, or if you are interested in getting the ASN information, you
have to use the KStartupInfo classes in kdelibs/kdecore.

Receiving the application startup notification information :
------------------------------------------------------------

 Create an instance of class KStartupInfo and connect to its slots, they
will be emitted whenever a ASN info is received.
 The clean_on_cantdetect argument to the constructor means whether all
ASN info for non-compliant apps should be removed when a window is mapped
which cannot be identified ( it's not possible to say if it belong to one
of the starting applications or not ). If the argument is true, it is
assumed that the window does belong to one of the starting applications,
and all ASN info for non-compliant apps must be removed, otherwise the ASN
info would timeout ( e.g. kdesktop sets it to true, otherwise the busy
icon would sometimes stay for too long, which is oftern annoying ).
On the other hand, KWin, which maps the first window of the starting apps
to the given virtual desktop, sets it to false, because there's no visual
representation and if a window for a starting non-compliant application is
detected later, it still will be sucessfully places on the correct virtual
desktop.
 Note that the ASN info is often send in several messages, and the slots
will be therefore emitted several times, with the updated info ( e.g. the
binary name or PID is not know from the beginning ).

Sending the application startup notification information :
----------------------------------------------------------

 Before an application is started, ASN info for it must be sent ( unless
it's done by classes like KRun ). See e.g. KRun sources for details.
 During the starting of the application, the info may need some updating
( e.g. right after starting the app, the PID with hostname may be sent,
or a PID change when KUniqueApplication forks into background ).
 When it's detected that the started process exited, it an ASN info
about the finished process should be sent. Since the application may
have forked into background, the finish info should include the PID
and hostname, and the notification will be stopped only if there's
no other PID for it. On the other hand, if you simply really need
to stop ASN, send only the identification ( KStartupInfo::sendFinish()
with only KStartupInfoId argument ).



Implementation details :
------------------------

 The ASN info data is sent using X ClientMessages as text ( see below ),
this is mainly in hope also non-KDE people will start using it, and
they wouldn't be very happy with DCOP.
 Before starting an application, and environment variable called
KDE_STARTUP_ENV is added to it's environment, and it's set to unique
identifier of its startup notification, or "0" for disabled ASN.
Ideally, the application should read it, and set a window property
called _KDE_STARTUP_ID ( type XA_STRING ) at least on its first mapped
toplevel window to this value. It should also unset it, so it doesn't get
propagated to other applications started from it. It should also
update the ASN info when necessary, e.g. when KUniqueApplication
forks into background, it sends the PID change. That's how compliant
applications should work, and this support for ASN should be provided
by toolkits. All KDE application should be compliant by now, since
kdelibs do all the necessary things. The KDE_STARTUP_ENV variable
is read and unset in KApplication constructor, and _KDE_STARTUP_ID
is set on every toplevel window in KApplication::setTopWidget().
 However, majority of applications aren't compliant now, and even
if I succeed making this thing a standard ( part of NETWM_SPEC
or whatever ), there still will be old applications that won't behave
this way. Not unsetting KDE_STARTUP_ENV is not a big problem, since
the ASN for its value will usually timeout, and when the app starts
a new application, this ASN identification value will get reused without
problems. The other problem is detecting, which newly mapped windows
belong to which starting application. If a newly mapped window doesn't
have _KDE_STARTUP_ID property, the code tries to read its _NET_WM_PID
property, and if it's set, it tries to match it ( together with
WM_CLIENT_MACHINE ) with PIDs of all ASN infos. And if the window
doesn't have even the _NET_WM_PID property, WM_CLASS property is used
then. It's usually set to two strings, and at least one of them is
usually the binary name of the application, so it's converted
to lowercase and compared. For applications, where such comparison
would fail, the X-KDE-WMClass .desktop file entry should be set
to the correct WMClass value ( e.g. for XEmacs, the binary name
is 'xemacs', but WM_CLASS is 'emacs', 'Emacs', so its X-KDE-WMClass
in its .desktop file should be set to 'emacs' - the case doesn't
matter ).
 The ASN identification string must be a unique string for every ASN.
In KStartupInfo class, it's created as 'hostname;tm.sec;tm.usec;pid',
tm being the current time. If the identification string is set to "0",
it means no ASN should be done ( e.g. for things like kio_uiserver,
which shouldn't get ASN ). Empty identification string means the same
like "0", except for the call to KStartupInfoId::initId(), where it means
to create a new one.


Format of the text messages :
-----------------------------

There are 3 types of messages :
 - new: message
    - this message announces that a new application is being started,
      if there is not ASN info for this ASN identification, it should be
      updated, otherwise it will be created
    - the text of the message starts with 4 characters 'new:', followed
      by the text entries ( see below )
 - change: message
    - this message is like new: message, but it's only for updating existing
      ASN info, if there's no ASN info for the given identification, it won't
      be created. This is used e.g. in KUniqueApplication when it forks
      into background and sends info about the PID change - it should update
      any existing ASN info, but mustn't create a new one, otherwise there
      could appear ASN even for applications which shouldn't have ASN
    - the text of the message starts with 4 characters 'change:', followed
      by the text entries ( see below )
 - remove: message
    - this message is sent for stopping ASN with the given identification.
      If the only item in the message is the identification string, the ASN
      info should be removed. If there are also the PID and HOSTNAME entries
      ( see below ), the matching ASN info should be only removed if this
      given PID is the only PID for it ( in this case, the identification
      string may be omitted ).
    - the text of the message starts with 4 characters 'remove:', followed
      by
          - only ID entry
	  - only ID, PID and HOSTNAME entries
	  - only PID and HOSTNAME entries


Text entries in the mesasges :
------------------------------

Every entry is of the form <name>=<value>. Value may be either a number
or a string. If the string contains spaces, it must be quoted ("), all
backslashes and quotes (") must be escaped by backslashes. If this ever
becomes more than an internal KDE standard, non-standard entry names should
start with an underscore.

Entries :

- ID        - string
            - the identification string of the startup notification
            - it must be present in all messages except for the remove:
              message with only PID and HOSTNAME
- BIN       - string
            - the binary name of the starting application
            - usually used as a fallback value if WMCLASS is not present
            - e.g. 'kcontrol'
- NAME      - string
            - the name of the starting application
            - usually used only for displaying it when indicating that
              the application is starting
            - e.g. 'Control Center'
- ICON      - string
            - the icon for this startup notification
            - it should be handled like the Icon= entry in .desktop files
            - e.g. 'kcontrol'
- DESKTOP   - number
            - the virtual desktop on which the application should appear
            - if the application's first window has _NET_WM_DESKTOP already
              set when the window is mapped, it shouldn't be changed
- WMCLASS   - string
            - the WMCLASS value used for matching newly mapped windows
              of non-compliant applications
            - useful only if it's different from the binary
              name of the application
- PID       - number
            - the PID of a process that belongs to this startup notification
            - there may be several PIDs for one notification
            - value 0 is also valid, meaning that there's a process
              with unknown PID for this notification ( is used e.g.
              by kfmclient when it sends a DCOP message to already running
              konqueror instance to create a new window and exits immediately,
              without adding the zero PID to the notification, process
              that started kfmclient could detect it exited and would send
              a remove: message for the notification with kfmclient's PID,
              which would cause the notification to stop if there wasn't also
              PID=0 for it
- HOSTNAME  - string
            - the hostname of the machine on which the application is being
              started
            - this is used together with the PID entry

--------------------

 Well, I guess that's all. The KDE2.2 release will show if the users like it
or not ( it's quite good IMHO, even though there are probably some minor
details to fix or improve ). The only big thing remaining is to make also
non-KDE people agree on using something like this. My first attempt
https://listman.redhat.com/pipermail/xdg-list/2001-May/000083.html
didn't get much attention, but now that there's a working implementation,
I hope it will get better, when I try again sometime in the future.



 Lubos Lunak <l lunak kde org>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]