After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 96772 - Startup notification patch
Startup notification patch
Status: RESOLVED FIXED
Product: gtk+
Classification: Platform
Component: .General
2.1.x
Other other
: Normal normal
: ---
Assigned To: gtk-bugs
gtk-bugs
Depends on:
Blocks:
 
 
Reported: 2002-10-25 05:05 UTC by Havoc Pennington
Modified: 2011-02-04 16:11 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
initial patch (12.70 KB, patch)
2002-10-25 05:05 UTC, Havoc Pennington
none Details | Review
New version of patch (11.87 KB, patch)
2002-11-02 05:30 UTC, Owen Taylor
none Details | Review

Description Havoc Pennington 2002-10-25 05:05:02 UTC
Patch to implement startup notification. 
This uses the currently-proposed spec, but 
the API is appropriate for any of the specs 
that have been proposed so far.

I've searched for the win32 API for this to check portability,
but haven't had any luck. Probably I'm not searching for the right 
thing as I don't know what they call the feature.
Comment 1 Havoc Pennington 2002-10-25 05:05:58 UTC
Created attachment 11821 [details] [review]
initial patch
Comment 2 Havoc Pennington 2002-10-25 15:48:59 UTC
From: Francois Gouget <fgouget@codeweavers.com>
Subject: Re: startup notification
To: Havoc Pennington <hp@redhat.com>
CC: xdg-list@freedesktop.org
Date: Fri, 25 Oct 2002 02:44:34 -0700

Havoc Pennington wrote:
[...]
> cvs.freedesktop.org has this document under
> startup-notification/doc/startup-notification.txt; the module also
> contains "libsn" which is a reference implementation.

You asked how Windows does this in another email. I don't really know,
however there is the following API:

DWORD WINAPI WaitForInputIdle(HANDLE hProcess, DWORD dwTimeOut);

 From the MSDN:
(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/waitforinputidle.asp)
 > The WaitForInputIdle function waits until the specified process is
 > waiting for user input with no input pending, or until the time-out
 > interval has elapsed.

Here 'no input pending' is when the message queue of the process's
main thread is empty. It does not take into account data that may be
pending on file descriptor or other stuff like that.

So here is how I think 'startup notification' is implemented: when you
start an application using Explorer, it calls CreateProcess to start
it. Then it setups up a busy cursor and calls the above API with a
timeout of 30 seconds or so. Finally it restores the normal cursor as
soon as the API returns.

Comment 3 Owen Taylor 2002-11-01 19:28:58 UTC
The interaction of this with --screen is really a mess.
Sending the notification to the screen given by --screen
would require the launching application to understand the
--screen option, but sending it to the default screen
from $DISPLAY would require parsing $DISPLAY to figure
out what screen that was.

(Yes, --screen isn't meant for interactive use, but it actually
is quite useful for interactive use ... imagine creating
a launcher to launch your 8-bit only app on the right screen,
so I suspect that people will use it occasionally.)
Comment 4 Havoc Pennington 2002-11-01 21:52:21 UTC
Brain dump on interaction with multihead:

Each startup notification sequence needs to be screen-specific. That
is, I launch it on a given screen, the tasklist on a given screen
notices the launch (tasklists are per-screen), the window manager sets
the root window cursor for 
a given screen, the app then comes up on a given screen. I think it's
broken if the "given screen" in any of those cases is different, 
a sequence is for a specific screen, that's how all our code (and I
think KDE's) has been written, and is the only real way to write the 
code without breaking the EWMH in major ways and confusing the hell
out of ourselves. Also, it's what people want; e.g. workspaces are
per-screen because people use multihead for things like keeping a
trading graph on one head and their office apps on the other, 
or keeping a video display on one head and their apps on the other.

Now the concrete problem is, how do we be sure the "given screen" is
known to all the processes involved. To keep it simple let's say the
panel (doing the launching), the application, and the task list.

From a protocol standpoint, the "initiate startup notification
sequence" message can (must?) contain a SCREEN attribute giving the
number of the screen 
the notification is on. This is because we don't know which root 
window the message was sent to. However the protocol also requires
the messages for a sequence to be sent to the root window
corresponding to SCREEN.

SCREEN is thus provided by the application doing the launching (say
the panel) and is not known to the application being launched, as 
the application-being-launched didn't see the initial message for
obvious reasons. Right now we assume the screen in DISPLAY (default
screen) is the "screen we were launched on."

As currently written the panel is attempting to pass in the screen 
when it does a launch. cf. Mark McLoughlin's exec_on_screen() set of 
functions posted a while back. i.e. the panel knows which screen 
it intends to launch something on. The app picks this up from DISPLAY.

If the user adds --screen to a .desktop file, this is going to mean
one of two things:
 1) the panel sets DISPLAY but --screen overrides it, so the panel 
    has the wrong idea about which screen the app is launching on
 2) the panel understands --screen somehow and knows which screen 
    the app is launching on
(s/--screen/--display/ and the same things are true)

According to the current protocol, 2) will work and 1) will break.

Imagine a solution to 1) such as sending all messages to screen 0. The
problem is, the panel still needs to know which root window 
the app is starting on. There's at least two features we have already 
planned that require this: a) the panel sends the DESKTOP property 
for the startup sequence, to start the app on the current DESKTOP; 
but DESKTOP is per-screen, so the panel needs to know which screen the
app is on and b) the panel sends the geometry of the launcher in root 
window coordinates, so an "opening" animation that expands the icon 
to the new window can be drawn. So sending everything to root 0 
keeps us from totally hosing the startup notification, but 
still we screw up details of it, because fundamentally everything 
has to know "which screen the app is being launched on."

I'm not sure we can get out of having to know that. However this patch
makes one assumption beyond "we know which screen we're launched on"
which is "at least one window will open on the screen we're launched
on", that is it sends the "finished" message only when opening a
window on that particular screen. Arguably we should instead send
"finished" as soon as we open a window on *any* screen. Or we could
say that's a case where the app is supposed to do its own startup
notification handling.

At least in principle, we should be able to display three independent
startup notification sequences for opening three windows from 
the same app on three different screens.

A per-screen GDK API can be mapped to a per-display startup
notification protocol by simply ignoring the passed-in screen,
the reverse is less true.

As a bad hack, we could require setting DESKTOP_STARTUP_SCREEN 
in addition to DESKTOP_STARTUP_ID when launching an app, 
so that GDK could detect and handle the case where --screen is 
out of sync with what the launcher application thought.
Comment 5 Owen Taylor 2002-11-01 22:24:29 UTC
There are basically three things here:

 A) The screen where the user triggered the launch
 B) The screen on whose root window the client message
    is exchanged
 C) The screen(s) where the application opens its
    windows.

Right now, the protocol links A, B, and C together.
An application showing application feedback can only
determine A) via B). The launchee can only determine
B) as a function of C).

What you seem to be arguing here is that A) needs 
to be exposed in the protocol. Which doesn't imply
to me that B) and C) need to be tied to it in this
way. 

Practically speaking, multihead is such a fringe case 
that we probably can get away with getting it sort 
of wrong, but don't see any particular reason why it
buys us much to tie these different screens together.
Comment 6 Havoc Pennington 2002-11-01 22:49:23 UTC
What I'm saying is:

 - there's a single screen which is the "screen where the launch
occurs"    
   typically identical to A), the screen where the 
   user triggered the launch.

 - unless everyone knows this "screen where launch occurs" stuff just   
   breaks

 - thus there's no advantage to using screen 0 for B), 
   vs. the screen where the launch occurs. the argument for 
   screen 0 is that screen 0 is more reliably known than 
   the screen where the launch occured. Well, we have to 
   reliably know the screen where the launch occurred *anyway*

 - there are disadvantages to using screen 0 for B), namely
   it makes the window manager and pager code more 
   annoying and less modular, because I have to write extra 
   code to always XSelectInput() on screen 0, and to filter out 
   non-startup-notification events on screen 0.

You are hardcoding B) instead of making it track A), but this adds no
useful flexibility whatsoever, unless we didn't know A), but we *have*
to know A). C) is totally orthogonal to this whole issue on the
protocol level. The proposed GTK auto-startup-notification-handling
currently only stops notification when opening a window on A), 
but that could trivially be changed if we want.

As we *have* to know A), we may as well avoid hardcoding B) and make
B) conveniently sync up to the screen the pager and window manager are
already dealing with.
Comment 7 Owen Taylor 2002-11-01 23:19:14 UTC
Why I'm proposing hardcoding B) is to keep things simple 
for the launchee. Currently, there is no way for the launchee
to know A), so it can't reliably use it for B).

Since I dont' see any reason why the launchee needs to know
A), hardcoding it seems simpler than passing it, but you
could in fact pass it in an environment variable as well;
it doesn't make much of a difference for me within GTK+;
what I'd like to avoid is having to make guesses at A)
to derive B).

I think it's more important to keep things simple for 
launchees than for launchers; ISV's may have to write
their own launchee handling, they are unlikely to write
launchers.
Comment 8 David Lazaro 2002-11-02 00:06:36 UTC
I have some knowledge about how Windows handles this.  I can't find
the reference now, it has passed a lot of time since I did heavy
duty Windows development, but I understood it as this:

* Explorer launches the app through the Shell API.
  Reference:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_programming/launch.asp?frame=true&hidetoc=true

* A compound busy pointer is shown on the window and only on the
  window that launched the app.  This means that the cursor is shown
  either on the folder window, desktop, quick launch bar or other.

  I am not so sure about this one; some testing on a Windows machine
  would help.

* Last, Explorer peeks at the message queue of the new thread.  When
  the first event (or input event, can't remember well) is processed
  by the thread the pointer is restored to normal.

  The pointer is also restored if a timeout is exceeded.

The main points for the Windows implementation are the 
ShellExecuteEx() part and its associated SHELLEXECUTEINFO struct,
and the peeking of the message queue associated with the "launchee"
application by the "launcher".

The SHELLEXECUTEINFO struct has a member hMonitor to indicate the
screen on which to show the window on multi-head configurations.
Comment 9 Havoc Pennington 2002-11-02 00:46:37 UTC
>  Currently, there is no way for the launchee
> to know A), so it can't reliably use it for B).

The launchee *has* to know A). That's the point. Perhaps a better way
to phrase it, A) really must be the DefaultScreen() for the launchee,
so that DESKTOP property, animations, etc. work.

If you want to improve the reliability of the launchee knowing A) then 
OK, but we can't get out of the launchee needing to know A) if we 
want stuff to work right. All the panel/tasklist/WM interactions are 
done per-screen right now.

I think DefaultScreen() is the most obvious/intuitive thing for 
launchees to implement, anyhow.
Comment 10 Havoc Pennington 2002-11-02 00:55:11 UTC
All that said, the GDK API may as well take no arguments:

 gdk_notify_startup_complete()

because it's known that it has to go to default screen on default
display in any case. To make it useful for any situation other 
than initial app startup (say opening a new window), it needs to take
a "startup ID" arg in addition to the screen.

So we could just do the no-args thing for now.

Comment 11 Owen Taylor 2002-11-02 03:19:20 UTC
I think it's perfectly fine in the unusual case of cross-screen
launching (A != C) if the user sees a watch cursor and/or
task list item on screen A until the app pops up on C.

The window manager should have no problem realizing that 
a cross-screen launch occurred and not doing the animation
from the launch location.

I also came to the idea that the GDK function probably should
be a global function ... startup notification is "per application"
and there is no reason to assume a one-to-one correspondence
between applications and screens, or even displays. Just 
making a per-screen function doesn't give you any ability to do 
multiple apps. 

The only advantage of making it per-screen or (probably better)
per-display would be to handle the weird case where the app
wants the startup notification to end when it opens something
on the default display, but first opens a window on some other
display that the user can't see.

I don't see that as worth adding extra complexity that we'd
need to deal with public per-screen fnuctions if we decide to later
add some real facility for multiple startup notifications.
Comment 12 Havoc Pennington 2002-11-02 04:40:27 UTC
> I think it's perfectly fine in the unusual case of cross-screen
> launching (A != C) if the user sees a watch cursor and/or
> task list item on screen A until the app pops up on C.

It's not a disaster, but it is broken. The tasklist icon should be 
on screen C, and the desktop the app is placed on should be the
current desktop for C, not the current desktop for screen A.

Anyhow, let's just do the global function, that's the right thing.
We can sort this out later. I'll do a new patch on Monday.
Comment 13 Owen Taylor 2002-11-02 04:56:59 UTC
I'm almost done reworking your patch for global function; 
I want the functionality in for 1.1.2, which is imminent. 
Comment 14 Owen Taylor 2002-11-02 05:30:06 UTC
Created attachment 11980 [details] [review]
New version of patch
Comment 15 Owen Taylor 2002-11-02 05:33:28 UTC
OK, new version of patch attached. Differences is mostly
making the notification global not per-screen, and concentrating
the code in gdkdisplay-x11.c. 

I haven't tried to handle add any magic handling of --screen; 
doing so would require some grotty but straightforward 
display name parsing code and a couple of gdk <=> gdk/x11
hooks.

I'm going to go ahead and commit it, but I don't really have
any means of testing (I checked that a client message is
sent to the root window, and it doesn't crash.)


   
Comment 16 Owen Taylor 2002-11-02 05:55:20 UTC
Sat Nov  2 00:22:33 2002  Owen Taylor  <otaylor@redhat.com>

        Add startup notification hooks - mostly based on patch
        by Havoc Pennington in #96772.

        * gdk/gdk.h gdk/x11/gdkdisplay-x11.c
        gdk/{win32,linux-fb}/gdkmain-*.c: (gdk_notify_startup_complete):
        new function that indicates an application has finished starting
        up.

        * gdk/x11/gdkmain-x11.c gdk/x11/gdkdisplay-x11.c
        (_gdk_windowing_set_default_display): store value of
        DESKTOP_STARTUP_ID on the default screen, and clear it from the
        environment.

        * gdk/x11/gdkdisplay-x11.c:
        Set _NET_STARTUP_ID hint on display's group leader window.

        * gtk/gtkwindow.c (gtk_window_set_auto_startup_notification):
        function to toggle whether we automatically broadcast that we've
        started up, after mapping the first toplevel window.
        (gtk_window_map): call gdk_screen_notify_startup_complete() by
        default, unless enabled by above.
Comment 17 Owen Taylor 2002-12-09 23:50:16 UTC
OK, Havoc promises to put language in the spec that either:

 - Makes it clear that GTK+'s current handling of --screen
   and startup notification is correct

Or:

 - Forbids passing --screen when using startup notification

Given that, I think this can be closed now.