Disabling opening the app when a remote action in a notification is fired

Nemo notifications plugin allows to add remote actions to notifications using Notification::setRemoteActions. If the app is closed, it can be opened using the DBus service file, which is created automatically by Saijail from the .desktop file. When this is used, the app is also automatically brought to the front when a notification remote action is triggered. Is there a way to turn this behaviour off?

For example, my desktop file looks like this:

[Desktop Entry]
Type=Application
X-Nemo-Application-Type=silica-qt5
Icon=harbour-myapp
Exec=harbour-myapp
Name=My App

X-DBusActivatable=true
MimeType=x-scheme-handler/mycustomscheme
X-Maemo-Service=io.myorg.myapp
X-Maemo-Object-Path=/io/myorg/myapp
X-Maemo-Method=io.myorg.myapp.openUrl

[X-Sailjail]
OrganizationName=io.myorg
ApplicationName=myapp
ExecDBus=harbour-myapp -prestart

And I create a notification like this:

Notification *notification = new Notification();
notification->setAppName("My App");
notification->setSummary("Test notification");
notification->setBody("My test notification description.");

QVariantList actions;
actions << Notification::remoteAction("default", "", "io.myorg.myapp", "/io/myorg/myapp", "io.myorg.myapp", "openUrl");
actions << Notification::remoteAction("", "Do something", "io.myorg.myapp", "/io/myorg/myapp", "io.myorg.myapp", "triggerAction");
notification->setRemoteActions(actions);

notification->publish();

I want the “Do something” button to trigger an action without activating the app. But I can’t find a way to disable that behaviour. DBus handler for triggerAction method does not bring the app to front, and as I understood, lipstick does that on its own.

I haven’t looked into it or tried, but couldn’t you implement the “org.freedesktop.Application” interface, and override the ‘Activate’ method?

Assuming that’s what Lipstick uses:

/* Adaptor to provide the SFOS/FDO DBus-Activation interface */
class BusAdaptor : public  QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Application")
public:
    BusAdaptor(QGuiApplication *application, QQuickView *view)
        : QDBusAbstractAdaptor(application), app(application), view(view)
{
}

public slots:
  /* To test:
    busctl --user call foo bar org.freedesktop.Application Activate a{sv} 0
  */
  void Activate( const QVariantMap &platform_data ) const
  {
     Q_UNUSED(platform_data)
     view->show(); // or not
     QMetaObject::invokeMethod(view->rootObject(), "activate");
  }

private:
  QGuiApplication *app;
  QQuickView *view;
};


int main(int argc, char *argv[])
{
QScopedPointer<QGuiApplication> app(SailfishApp::application(argc, argv));
QScopedPointer<QQuickView> view(SailfishApp::createView());

// create the FDO activation adapter
new BusAdaptor(app.data(), view.data());
QDBusConnection::sessionBus().registerObject(APP_DBUS_PATH, app.data());

....

}

By remote action I mean a custom button in a notification. I need to use a custom interface because in the real example there are multiple buttons, both serving different purposes, and I need to pass custom arguments to the methods.

After some digging, I found that closed-source part of lipstick (namely, LaunchManager of Sailfish.Lipstick QML module) seems to be doing that. Weirdly enough, this doesn’t happen if the notification type is set to “input”.

Also, if you change service name to something which is not <X-Sailjail/OrganizationName>.<X-Sailjail/ApplicationName> (values from the .desktop file), it stops opening the app. But, this breaks calling the methods when app is not opened.

I made a minimal reproducible example here. The app is very simple, QML-only, and has minimal changes required to demonstrate the issue:

  1. addition of the ExecDBus=harbour-notification-open-test -prestart line in the X-Sailjail section of the desktop file
  2. replacement of the main QML file with this:
import QtQuick 2.0
import Sailfish.Silica 1.0
import Nemo.Notifications 1.0

ApplicationWindow {
    initialPage: Component {
        Page {
            id: page

            Notification {
                id: notification
                appName: "My app"
                summary: "My notification"
                // It's not even needed to implement the interface to demonstrate the problem
                Component.onCompleted: {
                    var actions = [remoteAction("", "My action", "org.myorg.notification-open-test", "/org/myorg/notification-open-test", "org.myorg.notification-open-test", "myMethod")]

                    var inputAction = remoteAction("", "Input action", "org.myorg.notification-open-test", "/org/myorg/notification-open-test", "org.myorg.notification-open-test", "myInputMethod")
                    inputAction.type = "input"
                    actions.push(inputAction)

                    remoteActions = actions
                }
            }

            Button {
                anchors.centerIn: parent
                text: "Publish notification"
                onClicked: notification.publish()
            }
        }
    }
}

To reproduce, click “Publish notification”, go to the Events view and select the “My action” action on the notification. After this, the app will open, even though the interface is not even implemented. This means that this is very likely to be done by lipstick. However, when the the action type is set to "input", this behaviour doesn’t happen.

EDIT:
Seems like commenting a line in the main compositor QML file does the trick:
SFOS 5.0.0.68, /usr/share/lipstick-jolla-home-qt5/compositor.qml, line 610:

    LaunchManager {
        id: launchManager

        launcherModel: root.launcherModel
        //onLaunching: Desktop.instance.switcher.activateWindowFor(item) // <-- need to comment this
    }

I still can’t find a proper way of doing it, per-app (or, ideally, per a notification action), without patching lipstick.

1 Like