GNOME Bugzilla – Bug 165939
"save as" doesn't get the focus -- gedit shouldn't use gtk_window_present
Last modified: 2005-02-26 10:56:44 UTC
- open gedit - enter some chars - click on the save icon the dialog doesn't get the focus, it should
This happens because when saving we make sure that we gtk_window_present the window of the document that is being saved. That is necessary for "Save All" which may need to save document in other windows. AFAICS the problem is that the presented gedit windows get the timestamp of the last user interaction, so it steals focus from the dialog. I tried to explicitely gtk_window_present also the dialog, but it doesn't work... wild guess (forgive my metacity ignorance): may it be that in both cases the window and the dialog get exactly the same timestamp... if that is the case shouldn't metacity focus a window which is presented and that which has the same timestamp as the currently focused window?
Note that the close dialog is affected as well
I was planning to ask elijah on irc, but it looks like he knew that and didn't connect ;-) so I'm cc'ing him. elijah: any idea?
As mentioned on irc, you are apparently calling gtk_window_present() for the main window _after_ already creating the save dialog. The log from Metacity: Window 0x2a00004 (*Unsaved D) has _NET_WM_USER_TIME of 177323150 Window 0x2a00004 (*Unsaved D) has _NET_WM_USER_TIME of 177323302 Metacity set 0x2a00004 (*Unsaved D)'s net_wm_user_time to 177324758. Window 0x2a00004 (*Unsaved D) has _NET_WM_USER_TIME of 177324758 Updated 0x2a00004 (*Unsaved D) user_time to 177324787 due to activate call. Window 0x2a012a2 (Save as...) has _NET_WM_USER_TIME of 177324758 COMPARISON: net_wm_user_time_set : 1 net_wm_user_time : 177324758 initial_timestamp_set: 0 initial_timestamp : 0 focus_window : 0x2a00004 (*Unsaved D) fw->net_wm_user_time : 177324787 (You can duplicate this log with the patch at http://www.gnome.org/~newren/temp/debug-focus-problems.patch--just run 'metacity --replace' in a terminal). The "Unsaved D[ocument]" window is the focus window at the time the "Save as..." dialog appears. Metacity notices that it has a timestamp later than that of the dialog, which to it means that the user has continued interacting with the main window while waiting for the dialog to appear. This was due to the "activate" call (which is triggered by gtk_window_present()). You'll need to move your gtk_window_present() call elsewhere, or remove it, or use a different function. This could possibly be considered a gtk+ bug, but it'd be hard to tell without looking closer at the gedit code. This is because gtk_window_present() uses gtk_get_current_event_time(), which can be the totally wrong timestamp to use. Personally, I think gtk_window_present should be deprecated and an alternate version with a timestamp argument added in its place. gtk_window_present() also needs to be modified due to bug 128380, though that's another story, as is the fact that I need someone to remind me to file a gtk+ bug about this function...
Okay, two bugs: (1) gtk_window_present is broken and needs to be fixed (2) gedit shouldn't be using gtk_window_present. There's not a single useful thing it does for you as far as I can tell (bonobo_mdi_set_active_view() is the call that switches the to appropriate tab so I can't see what you're hoping to achieve with gtk_window_present, though I'd love to be corrected)
Oops, forgot one more comment. On IRC today I was suggesting to pbor to use gtk_widget_show or something similar, but I think that was just due to misunderstanding and thinking that gtk_window_present was needed for something for you. I really don't think you need to do that. Just nuke the line with the gtk_window_present call. If you think that line used to do something useful, please point out to me exactly what it is and I'll look for the right solution. :)
The line is required: bonobo_mdi_set_active_view() raises the proper tab in the current window, but the document we want to make sure is displayed under the dialog may also be in another window and may even be in another workspace. As discussed on irc I'll try to use gtk_widget_show.
How does one open another gedit window (everytime I tried, it merely showed me the one that already existed)? How does one close a gedit window which is on another workspace? (I tried showing windows in all workspaces in the tasklist and then right-clicking and selecting "close", but that just results in the dialog also appearing on the other workspace)
for instance by opening two tabs, then right clicking on the tab label, selecting Move to another window, and then using the menu Documents->Save All.
Ah, I see. You could use libwnck for that (wnck_screen_get_active_workspace && wnck_window_move_to_workspace), or even copy the relevant xutils.c code from libwnck and make direct use of it (gnome-panel does something similar for using many EWMH hints...). I'm about to file a bug against gtk+ about gtk_window_present--perhaps I should also suggest a new API for putting windows on the current workspace without focusing them (since that's what you really want and since the code will need to be written to fix another bug with that function anyway)? Granted, you wouldn't be able to use it in Gnome 2.10, but you could switch over to it in later releases after gtk+-2.8 came out...
I filed bug 166379 about the problems with gtk_window_present(). I also asked for a switch_window_to_current_workspace() API though, considering suggestion 2 I made in that bug, it's possible that a switch_to_workspace_of_this_window() API would be better...
a more complete api to deal with workspaces would definately be useful, for instance we would also love to have a nice api to see if there is a gedit window on the current workspace when launching a new instance so that we could decide if open a new toplevel or if open in a new tab... however I'm going OT. With regard to this particular topic I would be inclined to think that the correct behavior would be to make Save all, Close all and quit only act on all the document in the current workspace, making the user believe that gedit windows on different workspaces are completely independent (even if it isn't the case). To do this once again the api needed is something to allow to get the list of gedit windows on the workspace... paolo: what do you think? do you agree?
Both suggestions are not too difficult to implement right now using libwnck (or by making a special xutils.c similar to gnome-panel's xstuff.c, though going that route would obligate you to keep up with any EWMH changes made). For what it's worth (probably nothing), I like the idea of having save all and close all only acting on documents in the current workspace; personally I think of workspaces as disjoint and find it very odd to have an action on a window in one workspace affecting windows on other workspaces. (But then again, I find save all and close all confusing altogether as it's in the menu for *a single window* and yet acts on other windows; it seems that the item for acting on all windows should be separate from any one of them--to me at least)
I think Close All and Save All should act only on the documents in the current window. And the document list shoul contains only the documents in the current window too. We use gtk_window_present a lot of times in gedit. Is this the only wrong case? [paolo@elilix gedit]$ grep "gtk_window_present" -R . --include=*.c ./gedit/gedit-commands.c: gtk_window_present (GTK_WINDOW (about)); ./gedit/gedit-commands.c: gtk_window_present (GTK_WINDOW (about)); ./gedit/gedit-file.c: gtk_window_present (window); ./gedit/gedit-file.c: gtk_window_present (window); ./gedit/gedit-file.c: gtk_window_present (window); ./gedit/gedit-window-server.c: gtk_window_present (GTK_WINDOW (window)); ./gedit/bonobo-mdi.c: gtk_window_present (window); ./gedit/dialogs/gedit-preferences-dialog.c: gtk_window_present (GTK_WINDOW (dialog->dialog)); ./gedit/dialogs/gedit-dialog-goto-line.c: gtk_window_present (GTK_WINDOW (dialog->dialog)); ./gedit/dialogs/gedit-plugin-manager.c: gtk_window_present (GTK_WINDOW (about)); ./gedit/dialogs/gedit-dialog-replace.c: gtk_window_present (GTK_WINDOW (dialog->dialog)); ./gedit/dialogs/gedit-dialog-replace.c: gtk_window_present (GTK_WINDOW (dialog->dialog)); ./gedit/dialogs/gedit-page-setup-dialog.c: gtk_window_present (GTK_WINDOW (dialog->dialog)); ./gedit/gedit-mdi.c: gtk_window_present (window); ./gedit/gedit-mdi.c: gtk_window_present (GTK_WINDOW (window)); ./plugins/taglist/gedit-taglist-plugin-window.c: gtk_window_present (tag_list_window->window); ./plugins/taglist/gedit-taglist-plugin-window.c: gtk_window_present (GTK_WINDOW (gedit_get_active_window ())); ./plugins/spell/gedit-spell-language-dialog.c: gtk_window_present (GTK_WINDOW (dialog->dialog)); ./plugins/time/time.c: gtk_window_present (GTK_WINDOW (dialog->dialog)); ./plugins/docinfo/docinfo.c: gtk_window_present (GTK_WINDOW (dialog->dialog)); ./plugins/shell_output/shell_output.c: gtk_window_present (GTK_WINDOW (dialog->dialog)); ./plugins/sort/sort.c: gtk_window_present (GTK_WINDOW (dialog->dialog));
BTW, I don't understand why, in this case, you think the problem is gtk_window_present.
Oh, now I see. I see two possible solutions: 1. Change Save all, Close all, etc. to work only on the documents of the current window. 2. Instead of moving the gedit window to the current workspace, we should probably swith to the workspace of the window (is this possible?) BTW, I think we should really go for solution #1.
> I think Close All and Save All should act only on the documents in the current window. > And the document list shoul contains only the documents in the current window too. I do not agree. Having in the document list only the documents in the current window makes it not useful: such a list is already available on tabs. People like to have different gedit windows open, for instance I often use two or three windows open with some tabs in each one (e.g. grouped per project) and many of our users prefer to use a different window for each document instead of an MDI: the documents menu should allow to fast switch document in this use case. Beside note that also making save all and close all only act on the current window, doesn't solve our problem complitely: for instance the problem shows up again when using Quit, which closes all gedit windows With regard to the other uses of gtk_window_present, I think that most of them are ok: the problematic sequence happens only when in response to a user interaction (button clicked) we present a window and then show a dialog which showld be on top of the presented window: in this case the presented window ends up with a timestamp more recent than the dialog and thus the dialog is not focused.
I don't know if it is an important new, but I have just noticed that if I use "Ctrl + S" instead of clicking with the mouse on the toolbar or on the menu, the "Save As" dialog gets the focus as expected.
Just my $.02: > I do not agree. Having in the document list only the documents in the current > window makes it not useful: such a list is already available on tabs. Perhaps it should be removed then? Or placed in a separate window entirely? Users may want to work with one document per window, but if so, why does each document have a link to all the other ones? (Okay, so it's a gedit window that links to all the other ones and not the document itself, but users shouldn't need to distinguish between the two--at least not when they're using one document per window.) That sounds like inherently confusing UI, to me at least. > Beside note that also making save all and close all only act on the current > window, doesn't solve our problem complitely: for instance the problem shows > up again when using Quit, which closes all gedit windows It does solve the problem completely if you actually fix all three (if "quit" acts like "quit all" then obviously its behavior should be changed if "close all" and "save all" are). Personally, I think it's confusing that Quit acts on all gedit windows when I merely selected a menu option from one of them--just as with close all and save all.
Oops, forgot to comment on some other things: > Instead of moving the gedit window to the current workspace, we should > probably swith to the workspace of the window (is this possible?) Yes, see bug 128380. (Note that gtk_window_present sends a _NET_ACTIVE_WINDOW message). If you get bug reports about not doing that, feel free to mark them as duplicates of that bug. If you want I'll put that bug on the 2.10.x milestone for Metacity (I've been meaning to get to it anyway). You could also add a hack to do this yourself manually, but you'd have focus problems due to bug 161361; I don't suggest it. > We use gtk_window_present a lot of times in gedit. Is this the only wrong > case? I think pbor is right about this. Also, since I believe you don't have any cases where you have a timeout after a user interaction to display something (e.g. like a user typing in a URL in a web browser and then being notified 10-15 seconds later that the URL can't be found), I believe we can modify gtk_window_present in 2.6.x to use display_x11->user_time instead of gtk_get_current_event_time(), which should solve any problems for you.
> I believe we can modify > gtk_window_present in 2.6.x to use display_x11->user_time instead of > gtk_get_current_event_time(), which should solve any problems for you. That would be awesome. Please, do :)
> It does solve the problem completely if you actually fix all three (if "quit" > acts like "quit all" then obviously its behavior should be changed if "close > all" and "save all" are). Personally, I think it's confusing that Quit acts on > all gedit windows when I merely selected a menu option from one of them--just as > with close all and save all. By "not completely", I was thinking at cases when quitting is triggered by external events... I seem to recall that if you logout from gnome with some unsaved documents in gedit you get prompted for saving them... I may be wrong though. About the fact to not have documents of other windows listed in the Documents menu, I see your point and may indeed be the simpler and better solution... still it's a bit unfortunate since I think it is an useful feature: I happen often to have two windows open with some tabs each and switching to a particular doc in the other window with the menu is faster than clicking your way out of the app, raise the other window and then switch to the correct tab in the other window. With regard to window_present, is there any way in which we can get the display_x11->user_time from outside gtk, so that we can have our local non-brcken copy of window_present?
> That [making gtk_window_present() less broken] would be awesome. Please, do > :) I'm not sure exactly how to do it (accessing an implementational detail for the x11 version of gdk from within gtk doesn't sound trivial), but I'll try to write a patch for that if the gtk+ maintainers don't do so soon. Of course, it's up to the gtk+ maintainers whether they'll accept such a patch (though I don't see why they wouldn't so long as it can be done cleanly). > By "not completely", I was thinking at cases when quitting is triggered by > external events... Good point. > With regard to window_present, is there any way in which we can get the > display_x11->user_time from outside gtk Not in gtk+-2.6.x. In gtk+ HEAD there's gdk_x11_display_get_last_user_time().
There's a patch in bug 166379 to make gtk_window_present() less broken now. It'd be great if you could test with that; the bug listed here goes away for me...
Yup, I confirm that the patch in bug 166379 fixes the problem.
The patch in bug 166379 has been committed; you may want to update configure.in to depend on gtk+ >= 2.6.3, so that people make sure to run with the version of gtk+ with the fix. :-)
Ok, so this has been fixed in gtk. Closing. (We decided to not bump the required gtk version: even if this bug is annoying, gedit can still be built and used with an older gtk, so forcing a user to download and build gtk+ 2,6.3 seems unpolite. Obviously distros are encouraged to ship gtk >= 2.6.3 anyway)