Delay notifications until desktop session has loaded
ClosedPublic

Authored by vpilo on Feb 25 2017, 11:39 PM.

Details

Summary

The KNotifications library is immediately available for programs to send out notifications from the beginning of a desktop session. But if a startup program (or the frameworks themselves) sends out notifications before the desktop notifications service is ready, users will get old-school passive pop-ups, on top of the splash screen. In case other kinds of notifications were setup (e.g. sounds), those also gets in the way.

With this change, all notifications will be blocked until KSplash goes away.

NOTE: In case the splash screen is off, the change does nothing. You still get the passive popup. Anything that would make for a better "session is still loading" trigger than the D-Bus service of KSplash?
Test Plan

Testing with application:

  • put into list of Startup/Shutdown in SystemSettings a program that shows a KNotification on start (e.g. Yakuake from distro's package, to test binary compatibility).
  • from the program's settings, set a valid sound and ensure a popup is shown on the event occurrence
  • logout and login again
  • the notification(s) should appear as regular Plasma notifications only when the splash is over, along with the sound

Testing with system event:

  • On a laptop or a device with touchpad, set "Disable touchpad when mouse is plugged in" from Settings > Input Devices > Touchpad > Enable/Disable Touchpad tab. Ensure you login with a mouse plugged in
  • from rom Settings > Touchpad, set a valid sound and ensure a popup is shown on the event occurrence
  • logout and login again
  • the "touchpad disabled" notification should appear as regular Plasma notifications only when the splash is over, along with the sound

Diff Detail

Repository
R289 KNotifications
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.
vpilo created this revision.Feb 25 2017, 11:39 PM
Restricted Application added a project: Frameworks. · View Herald TranscriptFeb 25 2017, 11:39 PM
Restricted Application added a subscriber: Frameworks. · View Herald Transcript
mck182 added a subscriber: mck182.Feb 26 2017, 12:01 AM

Thanks for the patch! I wanted to do exactly this a long
time ago. However this solution brings a burden to all
apps using KNotification in form of a blocking dbus call
which is further only relevant when used in Plasma.

That's a no-no I'm afraid, we'd have to find a better solution.

I was thinking that maybe KSplash should have the notifications
dbus interface instead and handle it somehow on its own,
either just collecting the notifications and then reemitting them
once it's done splashing, or just displaying them directly, I dunno.

src/knotificationmanager.cpp
140 ↗(On Diff #11831)

The problem with this is that isServiceRegistered is
a blocking call. Blocking dbus calls are generally a nogo
because it can happen that it will get stuck in dbus
timeout, which is 25 secs by default. And that's bad.
Especially because this would be blocking the hosting
app.

Generally any dbus blocking calls are bad.

143 ↗(On Diff #11831)

The coding style of frameworks is *watcher

147 ↗(On Diff #11831)

We use the new signals/slots style in frameworks

268 ↗(On Diff #11831)

renotify is not entirely ideal name; something like
processQueue would be much more fitting.

Also, coding style is &serv

275 ↗(On Diff #11831)

Coding style is *n

src/knotificationmanager_p.h
71 ↗(On Diff #11831)

Coding style is & with the var name, also always
put the variable name in the header and use Q_UNUSED
in the implementation.

In D4799#89931, @mck182 wrote:

Thanks for the patch! I wanted to do exactly this a long
time ago. However this solution brings a burden to all
apps using KNotification in form of a blocking dbus call
which is further only relevant when used in Plasma.

That's a no-no I'm afraid, we'd have to find a better solution.

I understand. I'm out of the KDE development loop since a few years, so I wouldn't know what alternatives might there be that will be acceptable in the frameworks.
Straight away I am thinking about:

  1. A quick check if KSplashQML is found in the processes list (afaics, there's no alternatives to ksplash)
  2. KSplash could listen for registration of a new dbus instance of KNotifications and emit a message to it (most probably too slow)
  3. KNotifications could send an async call to KSplash with a very quick timeout and start deciding on its queued notifications if/after the answer arrives
  4. Any other way to check whether the start-up process is still running without relying on KSplash?

On a sidenote, I saw a couple comments about a 'new kde start system', but nothing more informative. Got any info?
e.g. kded/src/kded.cpp@770, before calling on dbus KSplash.setStage(): //NOTE: We are going to change how KDE starts and this certanly doesn't fit on the new design.

I was thinking that maybe KSplash should have the notifications
dbus interface instead and handle it somehow on its own,
either just collecting the notifications and then reemitting them
once it's done splashing, or just displaying them directly, I dunno.

That would add a lot of overhead & complexity to KSplash itself for a small case, I wouldn't like it.

  1. A quick check if KSplashQML is found in the processes list (afaics, there's no alternatives to ksplash)
  2. KNotifications could send an async call to KSplash with a very quick timeout and start deciding on its queued notifications if/after the answer arrives

The problem with these and practically any kind of
checking for KSplash *from* KNotifications is that
it is the wrong "direction", so to speak. The reason
being that KSplash runs for about 5 seconds on
average and only during the system startup. Any
check for KSplash in KNotification adds a performance
penalty to every single application using it and that's
only because of those ~5 secs during startup. Therefore
the solution should be different and/or at different
place altogether.

Another consideration is apps running in non-Plasma
sessions; this is after all just a problem of Plasma, which
makes me even more convinced that the solution shouldn't
be in KNotification but rather in KSplash/Plasma.

  1. KSplash could listen for registration of a new dbus instance of KNotifications and emit a message to it (most probably too slow)

I'm not sure I understand this one.

  1. Any other way to check whether the start-up process is still running without relying on KSplash?

As noted above, I think this whole logic should go
elsewhere, ideally.

On a sidenote, I saw a couple comments about a 'new kde start system', but nothing more informative. Got any info?
e.g. kded/src/kded.cpp@770, before calling on dbus KSplash.setStage(): //NOTE: We are going to change how KDE starts and this certanly doesn't fit on the new design.

I have no idea about that, sorry. Try emailing
plasma-devel@kde.org and ask there. Also check the
git blame on that line, if it's more than 18 months old
commit, there are most likely no plans at all.

That would add a lot of overhead & complexity to KSplash itself for a small case, I wouldn't like it.

Actually, it's not at all that bad. Assuming we're talking
only about collecting them and then reemitting them
once KSplash is done, this would be dead simple. If
that's a good/proper solution I can't tell.

I would say it is enough to just make plasma grab the interface early enough. It would result in the popups not show.

We don't need to show those notifications. It is a bug in ksplash that the popups are visible at all.

Another alternative could be to bind the checks suggested here to the env variable KDE_FULL_SESSION to make it at least a plasma only penalty

vpilo added a comment.Feb 26 2017, 6:38 PM

@graesslin I disagree. Some popups might be useful, some are very useful; we should aim to never drop any. Just as an example, the popup with the Yakuake console toggle key is pretty fundamental to be reminded of, the first few times you start it up.

It's all about saving users from annoyances. Papercuts, in Canonical terms.

@mck182 - I think your approach of taking them in, and replaying them at the end, is the best option I can see from my inexperienced POV.

It is a bug in ksplash that the popups are visible at all.

Fallback for KNotification is a KPassivePopup which is unredirect I think? Ksplash, in contrast to the splash screen, doesn't continuously re-raise itself and KWin doesn't do anything special to it either. (apart from some special cases in various effects)

Some popups might be useful, some are very useful

Most are not, however. PowerDevil, for instance, actually delays its notifications (e.g. you startup with a low battery) until a notification service registers itself to avoid the embarrassing popup ontop of KSplash while still showing the notification soon after logging in. Almost anything else ("You are now connected to network X") is pointless, and I hate this Yakuake notification when logging in.

dfaure added a subscriber: dfaure.Feb 26 2017, 8:41 PM

About the code in kded that calls ksplash: that code is obsolete and currently only kept for compatibility reasons, see https://git.reviewboard.kde.org/r/129010/
IOW you can ignore that code completely.

vpilo added a comment.Feb 26 2017, 9:08 PM
In D4799#90169, @dfaure wrote:

About the code in kded that calls ksplash: that code is obsolete and currently only kept for compatibility reasons, see https://git.reviewboard.kde.org/r/129010/
IOW you can ignore that code completely.

OK, thanks :)

Most are not, however. PowerDevil, for instance, actually delays its notifications (e.g. you startup with a low battery) until a notification service registers itself to avoid the embarrassing popup ontop of KSplash while still showing the notification soon after logging in. Almost anything else ("You are now connected to network X") is pointless, and I hate this Yakuake notification when logging in.

All notifications can be disabled if the user finds them useless and/or annoying - not a reason to prevent them from showing at all by means of frameworks, though, IMHO. And we can't expect the applications to all do what PowerDevil does. Unless we make this change happen (with another trigger to decide whether the splash is being shown).

vpilo added a comment.Feb 28 2017, 8:50 AM

@mck182 I didn't notice before, but KNotifications is already making blocking calls on creation:

src/notifybypopup.cpp@182:
    QDBusConnectionInterface *interface = QDBusConnection::sessionBus().interface();
    d->dbusServiceExists = interface && interface->isServiceRegistered(dbusServiceName);

And there's more.
I can make the KSplash notification relay; but I wouldn't know how to get rid of those..

Yes interface->isServiceRegistered(dbusServiceName) is technically blocking, but it can't block for a long time, since it's only talking to the dbus daemon. The reply comes in rather quickly, unlike a blocking call to another KDE process which could be busy or where the call itself could take a long time to be processed.
In summary, I don't think an existing call to isServiceRegistered can be used as an argument for making (potentially much much longer) blocking calls.

vpilo added a comment.Feb 28 2017, 9:50 PM
In D4799#91109, @dfaure wrote:

Yes interface->isServiceRegistered(dbusServiceName) is technically blocking, but it can't block for a long time, since it's only talking to the dbus daemon. The reply comes in rather quickly, unlike a blocking call to another KDE process which could be busy or where the call itself could take a long time to be processed.
In summary, I don't think an existing call to isServiceRegistered can be used as an argument for making (potentially much much longer) blocking calls.

Not trying to :) I was just concerned about those pre-existing calls. If those are fine, I'll just go on with my plan.

There is another solution that would work without any changes to KNotification.

DBus has a solution to buffer messages and wait for a name to become available, it happens in DBus activation. If plasmashell was DBus activated on org.freedesktop.Notifications we wouldn't have this problem at all.

Making plasmashell do that is probably a bit weird, but there is a hack we can do that I've seen done in Telepathy. Instead of activating plasmashell we have a small binary that gets DBus activated but simply idles waits for org.freedesktop.Notifications to become available then quits.

DBus-daemon thinks it's launched something and happily waits for the name to become available queuing the messages. Knotification can just fire and forget as normal.
The only time there's any performance penalty is if you do send a notification pre-plasmashell starting up, and it's quite minor.

I've tested this using, https://paste.kde.org/pwdqvevvo
running "notify-send foobar"
then waiting 10 seconds and starting plasmashell
Notification appeared perfectly.

We'd need to re-implement mc-wait-for-name in Plasma code (or just use Exec=sleep 30)

vpilo added a comment.Mar 2 2017, 11:58 AM

There is another solution that would work without any changes to KNotification.

DBus has a solution to buffer messages and wait for a name to become available, it happens in DBus activation. If plasmashell was DBus activated on org.freedesktop.Notifications we wouldn't have this problem at all.

Making plasmashell do that is probably a bit weird, but there is a hack we can do that I've seen done in Telepathy. Instead of activating plasmashell we have a small binary that gets DBus activated but simply idles waits for org.freedesktop.Notifications to become available then quits.

DBus-daemon thinks it's launched something and happily waits for the name to become available queuing the messages. Knotification can just fire and forget as normal.
The only time there's any performance penalty is if you do send a notification pre-plasmashell starting up, and it's quite minor.

I've tested this using, https://paste.kde.org/pwdqvevvo
running "notify-send foobar"
then waiting 10 seconds and starting plasmashell

Notification appeared perfectly.

We'd need to re-implement mc-wait-for-name in Plasma code (or just use Exec=sleep 30)

This sounds like a very good alternative to me. I can implement it in KSplash.

vpilo updated this revision to Diff 12310.Mar 9 2017, 12:41 AM

New version, using the idea suggested by @davidedmundson .

The KNotifications manager was clearing queued notifications also when the fd.o Notifications service initially registers; and while I get that it's done on unregistering to cleanup, I can't see why it should do it on register as well. Without that clearing, notifications queue up and get delivered naturally when the service gets restarted.

Also, I had to take out the KDE_FULL_SESSION check to make this work. Is there any drawback to this?

Cool, but we should put the blocking code in plasma, not here. Otherwise we'd interefere with other platforms.
Maybe in plasma-workspace/startkde

mck182 added a comment.Mar 9 2017, 4:26 PM

Looks like this could work. The KDE_FULL_SESSION check is
really old, I'm not sure if this has any implications.

As David noted, the waiting thing should go to Plasma workspace,
that's where it belongs. Also, it would be preferred if the implementation
was properly split into main.cpp and your class .h and .cpp

src/waitforname/main.cpp
39 ↗(On Diff #12310)

private in our code always goes to the bottom

vpilo updated this revision to Diff 12377.Mar 10 2017, 11:24 PM
vpilo marked an inline comment as done.
vpilo added reviewers: Plasma, Plasma: Workspaces.

New patchset.
I moved the waiting program to plasma-workspace, as per the suggestions (thanks). I also didn't like it much there, but didn't know where it would have fitted better.

The other diff is D5012

Restricted Application added a project: Plasma. · View Herald TranscriptMar 10 2017, 11:25 PM
Restricted Application added a subscriber: plasma-devel. · View Herald Transcript
vpilo added a comment.Mar 19 2017, 9:50 AM

I pushed D5012; this rev is now testable.

vpilo added a comment.Mar 22 2017, 2:31 PM

Ping

[my excuses if it's not good practice to do so]

davidedmundson accepted this revision.Mar 22 2017, 2:33 PM
This revision is now accepted and ready to land.Mar 22 2017, 2:33 PM
This revision was automatically updated to reflect the committed changes.