GNOME Bugzilla – Bug 646328
Window manager warning: Got a request to focus ... with a timestamp of 0. This shouldn't happen!
Last modified: 2021-07-05 14:21:45 UTC
Sometimes gnome-shell emits the above warning. In particular, if you move into a notification in banner mode, and then back out of it again. In the specific case of the banner notification, this is because it doesn't close the message tray immediately after you leave it, but instead calls Mainloop.timeout_add(), and then closes it from there, reverting the focus back to the original window in the process. Since that code is not running from an event handler, shell_global_get_current_time() returns 0, and the shell passes that to metacity, and metacity complains. (In the past, shell_global_get_current_time() would return the timestamp of the most recent clutter event in this case, but that caused failed grabs in some situations, so it was changed to return 0 instead.) The trivial fix would be to just make metacity not warn in this case. A slightly better fix would be to find all of the metacity methods that will warn (or do the wrong thing) when passed a timestamp of 0, and make gnome-shell use Meta.Display.get_current_time_roundtrip() in those cases if shell_global_get_current_time() returns 0. However, really, gnome-shell is just wrong here; it shouldn't be focusing the window with CurrentTime or with the result of get_current_time_roundtrip() at the time of the timeout, it should be focusing it with the time of the leave event that caused the timeout to be queued. (There isn't actually a race condition in the current code, because MessageTray only restores focus to the previously-focused window if focus is still on the stage at the time the timeout handler runs, so if you leave and then very quickly click another window, you're ok.) One way to do that would be to make global.current_time a writable property, and then wrap Mainloop.timeout_add, Meta.later_add, etc to wrap their callback with a function that sets global.current_time to its value at the time the callback was queued, calls the original callback, and then sets it back to 0. (Somewhat like the current global->xdnd_timestamp special case.)
(In reply to comment #0) > One way to do that would be to make global.current_time a writable property, > and then wrap Mainloop.timeout_add, Meta.later_add, etc to wrap their callback > with a function that sets global.current_time to its value at the time the > callback was queued, calls the original callback, and then sets it back to 0. > (Somewhat like the current global->xdnd_timestamp special case.) Can't you do it with a closure? Like let current_time = global.get_current_time() || Meta.Display.get_current_time_roundtrip(); Mainloop.timeout_add(function() { Meta.foo(current_time) })
Yes, but you'd have to do it everywhere you used timeout_add. It would be easier to just make timeout_add and ShellGlobal handle it in the background for you. (Doing extra wrapping around JS callbacks also ties into vague ideas I've been trying to figure out about error catching. Eg: let callbackWrapper = function () { try { global.current_time = cachedCurrentTime; return callback.apply(null, arguments); } catch (e) { logError(e, 'Uncaught exception in callback'); Main.recoverFromUncaughtException(); return undefined; } finally { global.current_time = 0; } } where Main.recoverFromUncaughtException() would close the overview, fully pop the modal stack, fix keyboard focus, etc, in an attempt to ensure that the shell was still in a usable state. Or possibly just call global.reexec_self()...)
(In reply to comment #2) > Yes, but you'd have to do it everywhere you used timeout_add. It would be > easier to just make timeout_add and ShellGlobal handle it in the background for > you. But also more obscure. In the end, you still have to replace global.get_current_time() with global.current_time, so it's not a problem to make it a local variable outside the function. > (Doing extra wrapping around JS callbacks also ties into vague ideas I've been > trying to figure out about error catching. Eg: > > let callbackWrapper = function () { > try { > global.current_time = cachedCurrentTime; > return callback.apply(null, arguments); > } catch (e) { > logError(e, 'Uncaught exception in callback'); > Main.recoverFromUncaughtException(); > return undefined; > } finally { > global.current_time = 0; > } > } > > where Main.recoverFromUncaughtException() would close the overview, fully pop > the modal stack, fix keyboard focus, etc, in an attempt to ensure that the > shell was still in a usable state. Or possibly just call > global.reexec_self()...) If you wanted to recover from all JS exceptions you would have to monkey patch GObject.prototype.connect, DBusProxy.connect, Mainloop.idle_add, Mainloop.timeout_add, Meta.later_add, Main.initDeferredWork, Signals.connect... Maybe it is easier to place asserts everywhere, and let gnome-session respawn gnome-shell on failure.
*** Bug 678373 has been marked as a duplicate of this bug. ***
GNOME is going to shut down bugzilla.gnome.org in favor of gitlab.gnome.org. As part of that, we are mass-closing older open tickets in bugzilla.gnome.org which have not seen updates for a longer time (resources are unfortunately quite limited so not every ticket can get handled). If you can still reproduce the situation described in this ticket in a recent and supported software version, then please follow https://wiki.gnome.org/GettingInTouch/BugReportingGuidelines and create a new ticket at https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/ Thank you for your understanding and your help.