Add basic support for app switching
authorScott Anderson <scott.anderson@collabora.com>
Wed, 4 Dec 2019 06:58:38 +0000 (19:58 +1300)
committerMarius Vlad <marius.vlad@collabora.com>
Tue, 21 Jan 2020 17:34:11 +0000 (19:34 +0200)
Signed-off-by: Scott Anderson <scott.anderson@collabora.com>
Change-Id: Ifd839ee15022f98987d46c454da90fc70de7fa38

homescreen/homescreen.pro
homescreen/protocol/agl-shell.xml
homescreen/qml/ShortcutArea.qml
homescreen/src/main.cpp
homescreen/src/shell.cpp [new file with mode: 0644]
homescreen/src/shell.h [new file with mode: 0644]

index 0ec86d4..0afb53b 100644 (file)
@@ -27,7 +27,8 @@ SOURCES += \
     src/statusbarmodel.cpp \
     src/statusbarserver.cpp \
     src/applicationlauncher.cpp \
-    src/mastervolume.cpp
+    src/mastervolume.cpp \
+    src/shell.cpp
 
 WAYLANDCLIENTSOURCES += \
     protocol/agl-shell.xml
@@ -36,7 +37,8 @@ HEADERS  += \
     src/statusbarmodel.h \
     src/statusbarserver.h \
     src/applicationlauncher.h \
-    src/mastervolume.h
+    src/mastervolume.h \
+    src/shell.h
 
 OTHER_FILES += \
     README.md
index 59548e7..5e31d98 100644 (file)
       <arg name="output" type="object" interface="wl_output"/>
       <arg name="edge" type="uint" enum="edge"/>
     </request>
+
+    <request name="activate_app">
+      <description summary="make client current window">
+        Asks the compositor to make a toplevel to become the current/focued
+        window for window management purposes.
+
+        See xdg_toplevel.set_app_id from the xdg-shell protocol for a
+        description app_id.
+
+        If multiple toplevels have the same app_id, the result is unspecified.
+
+        XXX: Do we need feedback to say it didn't work? (e.g. client does
+        not exist)
+      </description>
+      <arg name="app_id" type="string"/>
+      <arg name="output" type="object" interface="wl_output"/>
+    </request>
   </interface>
 </protocol>
index 9e404dc..d470231 100644 (file)
@@ -18,6 +18,7 @@
 
 import QtQuick 2.2
 import QtQuick.Layouts 1.1
+import QtQuick.Window 2.2
 
 Item {
     id: root
@@ -25,7 +26,7 @@ Item {
     ListModel {
         id: applicationModel
         ListElement {
-            appid: 'launcher'
+            appid: "launcher"
             name: 'launcher'
             application: 'launcher@0.1'
         }
@@ -59,7 +60,7 @@ Item {
                 name: model.name
                 active: model.name === launcher.current
                 onClicked: {
-                    homescreenHandler.tapShortcut(model.appid)
+                    shell.activate_app(Window.window, model.appid)
                 }
             }
         }
index ae1fff8..98cec6f 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <cstdlib>
 #include <cstring>
+#include <memory>
 #include <wayland-client.h>
 
 #include <weather.h>
@@ -36,6 +37,7 @@
 #include "statusbarmodel.h"
 #include "afm_user_daemon_proxy.h"
 #include "mastervolume.h"
+#include "shell.h"
 #include "hmi-debug.h"
 
 #include "wayland-agl-shell-client-protocol.h"
@@ -77,34 +79,35 @@ static const struct wl_registry_listener registry_listener = {
 static struct wl_surface *create_component(QPlatformNativeInterface *native,
                                            QQmlComponent *comp, QScreen *screen)
 {
-        QObject *obj = comp->create();
-        obj->setParent(screen);
+    QObject *obj = comp->create();
+    obj->setParent(screen);
 
-        QWindow *win = qobject_cast<QWindow *>(obj);
-        return static_cast<struct wl_surface *>(native->nativeResourceForWindow("surface", win));
+    QWindow *win = qobject_cast<QWindow *>(obj);
+    return static_cast<struct wl_surface *>(native->nativeResourceForWindow("surface", win));
 }
 
 int main(int argc, char *argv[])
 {
     setenv("QT_QPA_PLATFORM", "wayland", 1);
     QGuiApplication a(argc, argv);
-       QPlatformNativeInterface *native = qApp->platformNativeInterface();
+    QPlatformNativeInterface *native = qApp->platformNativeInterface();
     struct wl_display *wl;
     struct wl_registry *registry;
     struct agl_shell *agl_shell = nullptr;
 
-       wl = static_cast<struct wl_display *>(native->nativeResourceForIntegration("display"));
+    wl = static_cast<struct wl_display *>(native->nativeResourceForIntegration("display"));
     registry = wl_display_get_registry(wl);
 
     wl_registry_add_listener(registry, &registry_listener, &agl_shell);
     // Roundtrip to get all globals advertised by the compositor
     wl_display_roundtrip(wl);
     wl_registry_destroy(registry);
-    
+
     if (!agl_shell) {
         qFatal("Compositor does not support AGL shell protocol");
         return 1;
     }
+    std::shared_ptr<struct agl_shell> shell{agl_shell, agl_shell_destroy};
 
     // use launch process
     QScopedPointer<org::AGL::afm::user, Cleanup> afm_user_daemon_proxy(new org::AGL::afm::user("org.AGL.afm.user",
@@ -171,7 +174,7 @@ int main(int argc, char *argv[])
     QQuickWindow *window = qobject_cast<QQuickWindow *>(root);
 
     for (auto o : root_objects) {
-           qDebug() << o->dynamicPropertyNames();
+        qDebug() << o->dynamicPropertyNames();
     }
 
     QList<QObject *> sobjs = engine.rootObjects();
@@ -185,6 +188,7 @@ int main(int argc, char *argv[])
     context->setContextProperty("launcher", launcher);
     context->setContextProperty("weather", new Weather(bindingAddress));
     context->setContextProperty("bluetooth", new Bluetooth(bindingAddress, engine.rootContext()));
+    context->setContextProperty("shell", new Shell(shell, &a));
 
     QQmlComponent bg_comp(&engine, QUrl("qrc:/background.qml"));
     QQmlComponent top_comp(&engine, QUrl("qrc:/toppanel.qml"));
@@ -206,9 +210,8 @@ int main(int argc, char *argv[])
     }
 
     // Delay the ready signal until after Qt has done all of its own setup in a.exec()
-       QTimer::singleShot(0, [agl_shell](){
-        agl_shell_ready(agl_shell);
-        agl_shell_destroy(agl_shell);
+    QTimer::singleShot(0, [shell](){
+        agl_shell_ready(shell.get());
     });
 
     return a.exec();
diff --git a/homescreen/src/shell.cpp b/homescreen/src/shell.cpp
new file mode 100644 (file)
index 0000000..b4dd98d
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019 Collabora Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <QGuiApplication>
+#include <QDebug>
+#include "shell.h"
+#include <qpa/qplatformnativeinterface.h>
+#include <stdio.h>
+
+void Shell::activate_app(QWindow *win, const QString &app_id)
+{
+    QPlatformNativeInterface *native = qApp->platformNativeInterface();
+    QScreen *screen = win->screen();
+    struct wl_output *output;
+
+    output = static_cast<struct wl_output *>(native->nativeResourceForScreen(
+        "output", const_cast<QScreen *>(screen)));
+
+    agl_shell_activate_app(this->shell.get(),
+                           app_id.toStdString().c_str(),
+                           output);
+}
diff --git a/homescreen/src/shell.h b/homescreen/src/shell.h
new file mode 100644 (file)
index 0000000..c5e0b18
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2019 Collabora Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SHELLHANDLER_H
+#define SHELLHANDLER_H
+
+#include <QObject>
+#include <QString>
+#include <QScreen>
+#include <QWindow>
+#include <memory>
+#include "wayland-agl-shell-client-protocol.h"
+
+/*
+ * Basic type to wrap the agl_shell wayland object into a QObject, so that it
+ * can be used in callbacks from QML.
+ */
+
+class Shell : public QObject
+{
+    Q_OBJECT
+    std::shared_ptr<struct agl_shell> shell;
+public:
+    Shell(std::shared_ptr<struct agl_shell> shell, QObject *parent = nullptr) :
+        QObject(parent), shell(shell) 
+    {}
+public slots:
+    void activate_app(QWindow *win, const QString &app_id);
+};
+
+#endif // SHELLHANDLER_H