GNOME Bugzilla – Bug 326008
Need a lib providing common functionality for "singleton" apps
Last modified: 2007-03-17 17:51:12 UTC
Please describe the problem: I have an app that uses bonobo to only run one instance. If I run my app, close it (which just hides the window), and then run the app again it does not come to the front, it is just strobed in the bar. I am calling gtk_widget_grab_focus() and then gtk_window_present_with_time() on the window. I am under the impression that this should bring the window to the front. The attached file demonstrates the issue. NOTE – It will come to the front if you do not do anything with this window on initial launch, ie just cover it with another window. As soon as you click the button or close it though, from then on it will not come to the front on relaunch. Steps to reproduce: Actual results: Expected results: Does this happen every time? Yes Other information:
Created attachment 56871 [details] File that demonstrates the issue
Short version: You've been misled about how to handle this; the code is not right. See http://mail.gnome.org/archives/desktop-devel-list/2004-December/msg00306.html. Extra sidenotes: (1) We need a library for single instance apps to make stuff like this (and a number of other startup-notification things and perhaps other stuff) easier. (*) (2) Even though you may be removing all uses of gtk_get_current_event_time() in order to fix this, I can't pass up the chance to explain why it's often the wrong function to use: gtk_get_current_event_time() is heavily misused. First of all, "current" time (which has a couple different meanings/uses, so I put it in quotes) may not be useful--the time that is wanted for messages being sent to Metacity is the timestamp of the event that caused the window to be launched. This excludes the xserver's time at the point you finally get around to running this code (which, luckily, is not what gtk_get_current_event_time() returns) and possibly also excludes the time of the event currently being processed (which is what it does return, assuming there is an event being processed and that it comes with a timestamp--both of which are pretty iffy assumptions to randomly make). So, if gtk_get_current_event_time() is called as part of processing an event and that event is the same one that caused the window to be shown and that event comes with a timestamp (i.e. isn't a FocusIn or non-X-generated event) then and only then would this function be okay to use in the context of sending messages to Metacity. (3) The short explanation for why you need to forward startup-notification information is that gtk+ is taking a guess at when the user did something to open the window, but its guess is off because you're doing some nasty stuff behind it's back without letting it know. Anyway, see the "If you have a new instance of your app tell a previously running instance to open a new window and then you quit the new instance" portion of the summary section I linked to above. (4) We may also be fighting a problem with braindead launchers not using startup-notification. While we need to continue to work on fixing those, you can also add a hack to approximate the time the app was launched in those cases. Needs to be done by the instance that was launched, though, and not the instance that is handling the open-a-window request. See http://mail.gnome.org/archives/nautilus-list/2005-February/msg00136.html for an example. This is also something that would be nice to have a lib handle for you. (*) It's becoming a royal pain to look at and figure out the vastly different single-instance code in Mozilla, Evolution, Nautilus, gnome-terminal, Epiphany, Galeon (well, those last two are alike and Crispin actually did it for me), gedit, and other random apps. Having a common lib would make life much nicer. I wish I had more time. :( If I ever do get more time, though, bonobo sucks so I won't be using it to write such a lib.
The context of Steve's bug is this: We have an ever-present (or mostly ever-present) button somewhere in the desktop/panel/etc. When you click on it, we tell a possibly-already-running instance of a program to bring its window to the front. So, taking in mind that we use Bonobo for the single-instance logic, am I right in assuming that we need to do this: click-the-button: timestamp = event->time; launch ("the-magic-app --server-timestamp %d", timestamp); the-magic-app: parse_command_line_args (×tamp); prev_instance = bonobo_activation_blah_blah(); if (prev_instance) pass_timestamp_to_instance (prev_instance, timestamp); else w = gtk_window_new (); gtk_widget_realize (w); gdk_window_set_user_time (w->window, timestamp); gtk_widget_show (w);
Federico: Some questions/comments since your setup isn't fully clear: (1) Is the ever-present button of which you speak part of the the-magic-app or is it a separate applet or whatever? (1a) If it is part of the-magic-app, what does launch mean and why are you doing it? (1b) If it isn't part of the-magic-app, what's the precise meaning of "launch"? Does launch mean just execing the-magic-app (possibly a 2nd instance of it?). (1b-I) If launch does mean a simple exec then that itself is not quite correct as you should be launching with startup-notification, for reasons other than just timestamps. There's a startup-notification lib (libsn) for this in freedesktop cvs (cvsmodule is startup-notification; it's considered part of the official desktop release set in Gnome too and has been for a while), or a slightly higher level wrapping in gnome-desktop. (1b-II) If you are using startup-notification, note that it will handle provinding a timestamp already (among multiple other things) so you shouldn't pass it as a command line argument (you would instead parse the DESKTOP_STARTUP_ID environment variable instead of parsing command line args). This was covered in more detail in the d-d-l email I linked to. (2) Am I correct in understanding that you don't seem to have any code in the example for the previous instance to handle a timestamp being passed to it, or did I misunderstand your pseudocode? If I did understand correctly, well, it'd explain a lot about why you're having problems. ;-) (3) It looks like you're having the very first instance of the-magic-app manually setting the user time for its first window. If the app is launched with startup-notification, that's totally unnecessary and a waste of time (uses up a roundtrip to the server). Perhaps you meant for this code to be executed by the first instance after receiving a timestamp from another instance? Because the code does look right for that, modulo the nitpick that: (4) It's gdk_x11_window_set_user_time() (function has an "x11_" in it)
(Having such a lib would help fix a lot of the buggy app issues tracked in bug 149028 as well)
We have GtkUnique now, and this will hopefully be integrated in GTK+ (not for GTK+ 2.12, but maybe 2.14?). Closing this bug.