agl-compositor: Conversion to agl-compositor
authorMarius Vlad <marius.vlad@collabora.com>
Sat, 25 Apr 2020 15:42:40 +0000 (18:42 +0300)
committerMarius Vlad <marius.vlad@collabora.com>
Fri, 12 Jun 2020 09:47:39 +0000 (12:47 +0300)
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
Change-Id: I7da44ec333217d355ba643d2d21bea7d8940ad2b

18 files changed:
homescreen/homescreen.pro
homescreen/protocol/agl-shell.xml [new file with mode: 0644]
homescreen/qml/MediaArea.qml
homescreen/qml/MediaAreaBlank.qml
homescreen/qml/ShortcutArea.qml
homescreen/qml/ShortcutIcon.qml
homescreen/qml/StatusArea.qml
homescreen/qml/TopArea.qml
homescreen/qml/background.qml [new file with mode: 0644]
homescreen/qml/bottompanel.qml [new file with mode: 0644]
homescreen/qml/qml.qrc
homescreen/qml/toppanel.qml [new file with mode: 0644]
homescreen/src/homescreenhandler.cpp
homescreen/src/homescreenhandler.h
homescreen/src/main.cpp
homescreen/src/shell.cpp [new file with mode: 0644]
homescreen/src/shell.h [new file with mode: 0644]
package/config.xml

index 2f3443f..caf30a1 100644 (file)
 
 TEMPLATE = app
 TARGET = HomeScreen
-QT = qml quick websockets
-CONFIG += c++11 link_pkgconfig
+QT = qml quick websockets gui-private
+CONFIG += c++11 link_pkgconfig wayland-scanner
 DESTDIR = $${OUT_PWD}/../package/root/bin
-PKGCONFIG += qlibwindowmanager qtappfw-weather qtappfw-network qtappfw-bt afb-helpers-qt
+PKGCONFIG += qtappfw-weather qtappfw-network qtappfw-bt afb-helpers-qt wayland-client json-c
 
 LIBS += -lhomescreen
 
@@ -29,6 +29,7 @@ SOURCES += \
     src/applicationlauncher.cpp \
     src/mastervolume.cpp \
     src/homescreenhandler.cpp \
+    src/shell.cpp \
     src/aglsocketwrapper.cpp \
     src/chromecontroller.cpp
 
@@ -38,6 +39,7 @@ HEADERS  += \
     src/applicationlauncher.h \
     src/mastervolume.h \
     src/homescreenhandler.h \
+    src/shell.h \
     src/aglsocketwrapper.h \
     src/chromecontroller.h \
     src/constants.h
@@ -54,3 +56,7 @@ RESOURCES += \
     qml/images/images.qrc \
     qml/qml.qrc \
     qml/images/SpeechChrome/speechchrome.qrc
+
+
+WAYLANDCLIENTSOURCES += \
+    protocol/agl-shell.xml
diff --git a/homescreen/protocol/agl-shell.xml b/homescreen/protocol/agl-shell.xml
new file mode 100644 (file)
index 0000000..1096c64
--- /dev/null
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="agl_shell">
+  <copyright>
+    Copyright © 2019 Collabora, Ltd.
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+  <interface name="agl_shell" version="1">
+    <description summary="user interface for weston-ivi">
+    </description>
+
+    <enum name="error">
+      <entry name="invalid_argument" value="0"/>
+      <entry name="background_exists" value="1"/>
+      <entry name="panel_exists" value="2"/>
+    </enum>
+
+    <enum name="edge">
+      <entry name="top" value="0"/>
+      <entry name="bottom" value="1"/>
+      <entry name="left" value="2"/>
+      <entry name="right" value="3"/>
+    </enum>
+
+    <request name="ready">
+      <description summary="client is ready to be shown">
+        Tell the server that this client is ready to be shown. The server
+        will delay presentation during start-up until all shell clients are
+        ready to be shown, and will display a black screen instead.
+        This gives the client an oppurtunity to set up and configure several
+        surfaces into a coherent interface.
+
+        The client that binds to this interface must send this request, otherwise
+        they may stall the compositor unnecessarily.
+
+        If this request is called after the compositor has already finished
+        start-up, no operation is performed.
+      </description>
+    </request>
+
+    <request name="set_background">
+      <description summary="set surface as output's background">
+        Set the surface to act as the background of an output. After this
+        request, the server will immediately send a configure event with
+        the dimensions the client should use to cover the entire output.
+
+        The surface must have a "desktop" surface role, as supported by
+        libweston-desktop.
+
+        Only a single surface may be the background for any output. If a
+        background surface already exists, a protocol error is raised.
+      </description>
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="output" type="object" interface="wl_output"/>
+    </request>
+
+    <request name="set_panel">
+      <description summary="set surface as panel">
+        Set the surface to act as a panel of an output. The 'edge' argument
+        says what edge of the output the surface will be anchored to.
+        After this request, the server will send a configure event with the
+        correponding width/height that the client should use, and 0 for the
+        other dimension. E.g. if the edge is 'top', the width will be the
+        output's width, and the height will be 0.
+
+        The surface must have a "desktop" surface role, as supported by
+        libweston-desktop.
+
+        The compositor will take the panel's window geometry into account when
+        positioning other windows, so the panels are not covered.
+
+        XXX: What happens if e.g. both top and left are used at the same time?
+        Who gets to have the corner?
+
+        Only a single surface may be the panel for an output's edge. If a
+        surface already exists on an edge, a protocol error is raised.
+      </description>
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <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">
+        Ask the compositor to make a toplevel to become the current/focused
+        window for window management purposes.
+
+        See xdg_toplevel.set_app_id from the xdg-shell protocol for a
+        description of 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 3b6d18a..88eaf1e 100644 (file)
@@ -20,8 +20,7 @@ import QtQuick.Controls 2.0
 
 StackView {
     id: root
-    width: parent.width
-    height: parent.height
+    anchors.fill: parent
 
     initialItem: blank
 
index 60d0c92..c971f6e 100644 (file)
@@ -22,8 +22,7 @@ import AGL.Demo.Controls 1.0
 import MasterVolume 1.0
 
 Image {
-    width: parent.width
-    height: parent.height
+    anchors.fill: parent
     source: './images/Utility_Logo_Background-01.svg'
     property bool displayVolume: false;
 
index a8ce127..489b1e0 100644 (file)
 
 import QtQuick 2.2
 import QtQuick.Layouts 1.1
+import QtQuick.Window 2.2
 
 Item {
     id: root
-    width: 785
-    height: 218
-
 
     ListModel {
         id: applicationModel
@@ -53,7 +51,7 @@ Item {
 
     RowLayout {
         anchors.fill: parent
-        spacing: 2
+        spacing: 0
         Repeater {
             model: applicationModel
             delegate: ShortcutIcon {
@@ -62,9 +60,10 @@ Item {
                 name: model.name
                 active: model.name === launcher.current
                 onClicked: {
+                    console.log("Activating: " + model.appid)
                     homescreenHandler.tapShortcut(model.appid)
                 }
             }
-        }
+       }
     }
 }
index 1100a7c..d039d36 100644 (file)
@@ -21,8 +21,6 @@ import QtGraphicalEffects 1.0
 
 MouseArea {
     id: root
-    width: 195
-    height: 216.8
     property string name: 'Home'
     property bool active: false
     Item {
@@ -32,12 +30,14 @@ MouseArea {
         Image {
             id: inactiveIcon
             anchors.fill: parent
-                     source: './images/Shortcut/%1.svg'.arg(root.name.toLowerCase())
+            source: './images/Shortcut/%1.svg'.arg(root.name.toLowerCase())
+            fillMode: Image.PreserveAspectFit
         }
         Image {
             id: activeIcon
             anchors.fill: parent
             source: './images/Shortcut/%1_active.svg'.arg(root.name.toLowerCase())
+            fillMode: Image.PreserveAspectFit
             opacity: 0.0
         }
         layer.enabled: true
@@ -49,12 +49,13 @@ MouseArea {
     }
     Label {
         id: name
-        y: 160
         width: root.width - 10
         font.pixelSize: 15
         font.letterSpacing: 5
         // wrapMode: Text.WordWrap
-        anchors.horizontalCenter: parent.horizontalCenter
+        anchors.centerIn: icon
+        anchors.verticalCenterOffset: icon.height * 0.2
+        //anchors.horizontalCenter: parent.horizontalCenter
         horizontalAlignment: Text.AlignHCenter
         color: "white"
         text: qsTr(model.name.toUpperCase())
index 14ccb8f..507b6db 100644 (file)
@@ -22,8 +22,8 @@ import HomeScreen 1.0
 
 Item {
     id: root
-    width: 295
-    height: 218
+    //width: 295
+    //height: 218
 
     property date now: new Date
     Timer {
index 2a75cf8..19bed91 100644 (file)
@@ -20,10 +20,10 @@ import QtQuick.Layouts 1.1
 import QtQuick.Controls 2.0
 
 Image {
-    width: 1920
-    height: 218
+    anchors.fill: parent
     source: './images/TopSection_NoText_NoIcons-01.svg'
-    fillMode: Image.PreserveAspectCrop
+    //fillMode: Image.PreserveAspectCrop
+    fillMode: Image.Stretch
 
     RowLayout {
         anchors.fill: parent
@@ -32,13 +32,13 @@ Image {
             id: shortcutArea
             Layout.fillWidth: true
             Layout.fillHeight: true
-            Layout.preferredWidth: 785
+            Layout.preferredWidth: 775
         }
         StatusArea {
             id: statusArea
             Layout.fillWidth: true
             Layout.fillHeight: true
-            Layout.preferredWidth: 295
+            Layout.preferredWidth: 291
         }
     }
 
diff --git a/homescreen/qml/background.qml b/homescreen/qml/background.qml
new file mode 100644 (file)
index 0000000..c2bb309
--- /dev/null
@@ -0,0 +1,15 @@
+import QtQuick 2.13
+import QtQuick.Window 2.13
+
+Window {
+    id: background
+    width: Screen.width
+    height: Screen.height
+    flags: Qt.FramelessWindowHint
+    visible: true
+
+    Image {
+        anchors.fill: parent
+        source: './images/AGL_HMI_Blue_Background_NoCar-01.png'
+    }
+}
diff --git a/homescreen/qml/bottompanel.qml b/homescreen/qml/bottompanel.qml
new file mode 100644 (file)
index 0000000..1e0b105
--- /dev/null
@@ -0,0 +1,50 @@
+import QtQuick 2.13
+import QtQuick.Window 2.13
+
+Window {
+    id: bottompanel
+    width: Screen.width
+    height: Screen.height * (215.0 / 1920.0)
+    flags: Qt.FramelessWindowHint
+    visible: true
+    //color: "#aaaa0000"
+    MediaArea {
+    }
+
+    Timer {
+        id:informationTimer
+        interval: 3000
+        running: false
+        repeat: true
+        onTriggered: {
+            bottomInformation.visible = false
+        }
+    }
+
+    Item {
+        id: bottomInformation
+        width: parent.width
+        height: 215
+        anchors.bottom: parent.bottom
+        visible: false
+        Text {
+            id: bottomText
+            anchors.centerIn: parent
+            font.pixelSize: 25
+            font.letterSpacing: 5
+            horizontalAlignment: Text.AlignHCenter
+            color: "white"
+            text: ""
+            z:1
+        }
+    }
+
+    Connections {
+        target: homescreenHandler
+        onShowInformation: {
+            bottomText.text = info
+            bottomInformation.visible = true
+            informationTimer.restart()
+        }
+    }
+}
index d901481..8381337 100644 (file)
@@ -7,9 +7,12 @@
         <file>MediaAreaRadio.qml</file>
         <file>ShortcutArea.qml</file>
         <file>ShortcutIcon.qml</file>
+        <file>SpeechChrome.qml</file>
         <file>StatusArea.qml</file>
         <file>TopArea.qml</file>
         <file>IconItem.qml</file>
-        <file>SpeechChrome.qml</file>
+        <file>background.qml</file>
+        <file>toppanel.qml</file>
+        <file>bottompanel.qml</file>
     </qresource>
 </RCC>
diff --git a/homescreen/qml/toppanel.qml b/homescreen/qml/toppanel.qml
new file mode 100644 (file)
index 0000000..4098c73
--- /dev/null
@@ -0,0 +1,69 @@
+import QtQuick 2.13
+import QtQuick.Window 2.13
+
+Window {
+    id: toppanel
+    width: Screen.width
+    height: Screen.height * (240.0 / 1920.0)
+    flags: Qt.FramelessWindowHint
+    visible: true
+    //color: "#aaaa0000"
+
+    TopArea {
+    }
+
+    Timer {
+        id:notificationTimer
+        interval: 3000
+        running: false
+        repeat: true
+        onTriggered: notificationItem.visible = false
+    }
+
+    Item {
+        id: notificationItem
+        x: 0
+        y: 0
+        z: 1
+        width: 1280
+        height: 100
+        opacity: 0.8
+        visible: false
+
+        Rectangle {
+            width: parent.width
+            height: parent.height
+            anchors.fill: parent
+            color: "gray"
+            Image {
+                id: notificationIcon
+                width: 70
+                height: 70
+                anchors.left: parent.left
+                anchors.leftMargin: 20
+                anchors.verticalCenter: parent.verticalCenter
+                source: ""
+            }
+
+            Text {
+                id: notificationtext
+                font.pixelSize: 25
+                anchors.left: notificationIcon.right
+                anchors.leftMargin: 5
+                anchors.verticalCenter: parent.verticalCenter
+                color: "white"
+                text: qsTr("")
+            }
+        }
+    }
+
+    Connections {
+        target: homescreenHandler
+        onShowNotification: {
+            notificationIcon.source = icon_path
+            notificationtext.text = text
+            notificationItem.visible = true
+            notificationTimer.restart()
+        }
+    }
+}
index 4db60fb..bf98a53 100644 (file)
  * limitations under the License.
  */
 
+#include <QGuiApplication>
 #include <QFileInfo>
 #include "homescreenhandler.h"
 #include <functional>
 #include "hmi-debug.h"
 
+#include <qpa/qplatformnativeinterface.h>
+
 void* HomescreenHandler::myThis = 0;
 
-HomescreenHandler::HomescreenHandler(QObject *parent) :
+HomescreenHandler::HomescreenHandler(Shell *_aglShell, QObject *parent) :
     QObject(parent),
-    mp_hs(NULL)
+    aglShell(_aglShell)
 {
 
 }
@@ -42,6 +45,7 @@ void HomescreenHandler::init(int port, const char *token)
 
     myThis = this;
 
+
     mp_hs->registerCallback(nullptr, HomescreenHandler::onRep_static);
 
     mp_hs->set_event_handler(LibHomeScreen::Event_OnScreenMessage, [this](json_object *object){
@@ -50,6 +54,7 @@ void HomescreenHandler::init(int port, const char *token)
         HMI_DEBUG("HomeScreen","set_event_handler Event_OnScreenMessage display_message = %s", display_message);
     });
 
+    // should be handled in the top panel
     mp_hs->set_event_handler(LibHomeScreen::Event_ShowNotification,[this](json_object *object){
        json_object *p_obj = json_object_object_get(object, "parameter");
        const char *icon = json_object_get_string(
@@ -70,6 +75,7 @@ void HomescreenHandler::init(int port, const char *token)
        emit showNotification(QString(QLatin1String(app_id)), icon_path, QString(QLatin1String(text)));
     });
 
+    // should be handled in the bottom panel
     mp_hs->set_event_handler(LibHomeScreen::Event_ShowInformation,[this](json_object *object){
        json_object *p_obj = json_object_object_get(object, "parameter");
        const char *info = json_object_get_string(
@@ -79,15 +85,34 @@ void HomescreenHandler::init(int port, const char *token)
     });
 }
 
+static struct wl_output *
+getWlOutput(QPlatformNativeInterface *native, QScreen *screen)
+{
+       void *output = native->nativeResourceForScreen("output", screen);
+       return static_cast<struct ::wl_output*>(output);
+}
+
 void HomescreenHandler::tapShortcut(QString application_id)
 {
-    HMI_DEBUG("HomeScreen","tapShortcut %s", application_id.toStdString().c_str());
-    struct json_object* j_json = json_object_new_object();
-    struct json_object* value;
-    value = json_object_new_string("normal.full");
-    json_object_object_add(j_json, "area", value);
+       HMI_DEBUG("HomeScreen","tapShortcut %s", application_id.toStdString().c_str());
+
+       struct json_object* j_json = json_object_new_object();
+       struct json_object* value;
+
+       struct agl_shell *agl_shell = aglShell->shell.get();
+       QPlatformNativeInterface *native = qApp->platformNativeInterface();
+       struct wl_output *output = getWlOutput(native, qApp->screens().first());
+
+       value = json_object_new_string("normal.full");
+       json_object_object_add(j_json, "area", value);
+
+       mp_hs->showWindow(application_id.toStdString().c_str(), j_json);
 
-    mp_hs->showWindow(application_id.toStdString().c_str(), j_json);
+       // this works (and it is redundant the first time), due to the default
+       // policy engine installed which actives the application, when starting
+       // the first time. Later calls to HomescreenHandler::tapShortcut will
+       // require calling 'agl_shell_activate_app'
+       agl_shell_activate_app(agl_shell, application_id.toStdString().c_str(), output);
 }
 
 void HomescreenHandler::onRep_static(struct json_object* reply_contents)
index 5dfe041..3d939ce 100644 (file)
 #define HOMESCREENHANDLER_H
 
 #include <QObject>
+
 #include <libhomescreen.hpp>
+
+#include "shell.h"
 #include <string>
 
 using namespace std;
@@ -27,7 +30,7 @@ class HomescreenHandler : public QObject
 {
     Q_OBJECT
 public:
-    explicit HomescreenHandler(QObject *parent = 0);
+    explicit HomescreenHandler(Shell *aglShell, QObject *parent = 0);
     ~HomescreenHandler();
 
     void init(int port, const char* token);
@@ -46,6 +49,7 @@ signals:
     void showInformation(QString info);
 private:
     LibHomeScreen *mp_hs;
+    Shell *aglShell;
 };
 
 #endif // HOMESCREENHANDLER_H
index b92ff60..db9eafe 100644 (file)
 #include <QtGui/QGuiApplication>
 #include <QtQml/QQmlApplicationEngine>
 #include <QtQml/QQmlContext>
+#include <QtQml/QQmlComponent>
 #include <QtQml/qqml.h>
 #include <QQuickWindow>
+#include <QTimer>
 
-#include <qlibwindowmanager.h>
 #include <weather.h>
 #include <bluetooth.h>
 #include "applicationlauncher.h"
 #include "hmi-debug.h"
 #include "chromecontroller.h"
 
+#include <qpa/qplatformnativeinterface.h>
+#include <wayland-client.h>
+
+#include "wayland-agl-shell-client-protocol.h"
+#include "shell.h"
+
+static void
+global_add(void *data, struct wl_registry *reg, uint32_t name,
+          const char *interface, uint32_t)
+{
+       struct agl_shell **shell = static_cast<struct agl_shell **>(data);
+
+       if (strcmp(interface, agl_shell_interface.name) == 0) {
+               *shell = static_cast<struct agl_shell *>(
+                       wl_registry_bind(reg, name, &agl_shell_interface, 1)
+               );
+       }
+}
+
+static void
+global_remove(void *data, struct wl_registry *reg, uint32_t id)
+{
+       /* Don't care */
+       (void) data;
+       (void) reg;
+       (void) id;
+}
+
+static const struct wl_registry_listener registry_listener = {
+       global_add,
+       global_remove,
+};
+
+static struct wl_surface *
+getWlSurface(QPlatformNativeInterface *native, QWindow *window)
+{
+       void *surf = native->nativeResourceForWindow("surface", window);
+       return static_cast<struct ::wl_surface *>(surf);
+}
+
+static struct wl_output *
+getWlOutput(QPlatformNativeInterface *native, QScreen *screen)
+{
+       void *output = native->nativeResourceForScreen("output", screen);
+       return static_cast<struct ::wl_output*>(output);
+}
+
+
+static struct agl_shell *
+register_agl_shell(QPlatformNativeInterface *native)
+{
+       struct wl_display *wl;
+       struct wl_registry *registry;
+       struct agl_shell *shell = nullptr;
+
+       wl = static_cast<struct wl_display *>(
+                       native->nativeResourceForIntegration("display")
+       );
+       registry = wl_display_get_registry(wl);
+
+       wl_registry_add_listener(registry, &registry_listener, &shell);
+
+       /* Roundtrip to get all globals advertised by the compositor */
+       wl_display_roundtrip(wl);
+       wl_registry_destroy(registry);
+
+       return shell;
+}
+
+static struct wl_surface *
+create_component(QPlatformNativeInterface *native, QQmlComponent *comp,
+                QScreen *screen, QObject **qobj)
+{
+       QObject *obj = comp->create();
+       obj->setParent(screen);
+
+       QWindow *win = qobject_cast<QWindow *>(obj);
+       *qobj = obj;
+
+       return getWlSurface(native, win);
+}
+
+static void
+load_agl_shell_app(QPlatformNativeInterface *native,
+                  QQmlApplicationEngine *engine,
+                  struct agl_shell *agl_shell, QUrl &bindingAddress)
+{
+       struct wl_surface *bg, *top, *bottom;
+       struct wl_output *output;
+
+       QObject *qobj_bg, *qobj_top, *qobj_bottom;
+
+       QQmlComponent bg_comp(engine, QUrl("qrc:/background.qml"));
+       qInfo() << bg_comp.errors();
+
+       QQmlComponent top_comp(engine, QUrl("qrc:/toppanel.qml"));
+       qInfo() << top_comp.errors();
+
+       QQmlComponent bot_comp(engine, QUrl("qrc:/bottompanel.qml"));
+       qInfo() << bot_comp.errors();
+
+       QScreen *screen = qApp->screens().first();
+       if (!screen)
+               return;
+
+       output = getWlOutput(native, screen);
+
+       bg = create_component(native, &bg_comp, screen, &qobj_bg);
+       top = create_component(native, &top_comp, screen, &qobj_top);
+       bottom = create_component(native, &bot_comp, screen, &qobj_bottom);
+
+       /* engine.rootObjects() works only if we had a load() */
+       StatusBarModel *statusBar = qobj_top->findChild<StatusBarModel *>("statusBar");
+       if (statusBar) {
+               qDebug() << "got statusBar objectname, doing init()";
+               statusBar->init(bindingAddress, engine->rootContext());
+       }
+
+       agl_shell_set_panel(agl_shell, top, output, AGL_SHELL_EDGE_TOP);
+       agl_shell_set_panel(agl_shell, bottom, output, AGL_SHELL_EDGE_BOTTOM);
+
+       agl_shell_set_background(agl_shell, bg, output);
+
+       /* Delay the ready signal until after Qt has done all of its own setup
+        * in a.exec() */
+       QTimer::singleShot(500, [agl_shell](){
+               agl_shell_ready(agl_shell);
+       });
+}
+
+
 int main(int argc, char *argv[])
 {
     QGuiApplication a(argc, argv);
+    QPlatformNativeInterface *native = qApp->platformNativeInterface();
+    struct agl_shell *agl_shell = nullptr;
 
     QCoreApplication::setOrganizationDomain("LinuxFoundation");
     QCoreApplication::setOrganizationName("AutomotiveGradeLinux");
@@ -62,6 +196,16 @@ int main(int argc, char *argv[])
 
     HMI_DEBUG("HomeScreen","port = %d, token = %s", port, token.toStdString().c_str());
 
+    agl_shell = register_agl_shell(native);
+    if (!agl_shell) {
+           fprintf(stderr, "agl_shell extension is not advertised. "
+                           "Are you sure that agl-compositor is running?\n");
+           exit(EXIT_FAILURE);
+    }
+
+    std::shared_ptr<struct agl_shell> shell{agl_shell, agl_shell_destroy};
+    Shell *aglShell = new Shell(shell, &a);
+
     // import C++ class to QML
     // qmlRegisterType<ApplicationLauncher>("HomeScreen", 1, 0, "ApplicationLauncher");
     qmlRegisterType<StatusBarModel>("HomeScreen", 1, 0, "StatusBarModel");
@@ -70,33 +214,8 @@ int main(int argc, char *argv[])
                                                  QLatin1String("SpeechChromeController is uncreatable."));
 
     ApplicationLauncher *launcher = new ApplicationLauncher();
-    QLibWindowmanager* layoutHandler = new QLibWindowmanager();
-    if(layoutHandler->init(port,token) != 0){
-        exit(EXIT_FAILURE);
-    }
-
-    AGLScreenInfo screenInfo(layoutHandler->get_scale_factor());
-
-    if (layoutHandler->requestSurface(graphic_role) != 0) {
-        exit(EXIT_FAILURE);
-    }
 
-    layoutHandler->set_event_handler(QLibWindowmanager::Event_SyncDraw, [layoutHandler, &graphic_role](json_object *object) {
-        layoutHandler->endDraw(graphic_role);
-    });
-
-    layoutHandler->set_event_handler(QLibWindowmanager::Event_ScreenUpdated, [layoutHandler, launcher](json_object *object) {
-        json_object *jarray = json_object_object_get(object, "ids");
-        int arrLen = json_object_array_length(jarray);
-        for( int idx = 0; idx < arrLen; idx++)
-        {
-            QString label = QString(json_object_get_string(    json_object_array_get_idx(jarray, idx) ));
-            HMI_DEBUG("HomeScreen","Event_ScreenUpdated application: %s.", label.toStdString().c_str());
-            QMetaObject::invokeMethod(launcher, "setCurrent", Qt::QueuedConnection, Q_ARG(QString, label));
-        }
-    });
-
-    HomescreenHandler* homescreenHandler = new HomescreenHandler();
+    HomescreenHandler* homescreenHandler = new HomescreenHandler(aglShell);
     homescreenHandler->init(port, token.toStdString().c_str());
 
     QUrl bindingAddress;
@@ -109,25 +228,22 @@ int main(int argc, char *argv[])
     query.addQueryItem(QStringLiteral("token"), token);
     bindingAddress.setQuery(query);
 
-    // mail.qml loading
     QQmlApplicationEngine engine;
-    engine.rootContext()->setContextProperty("bindingAddress", bindingAddress);
-    engine.rootContext()->setContextProperty("layoutHandler", layoutHandler);
-    engine.rootContext()->setContextProperty("homescreenHandler", homescreenHandler);
-    engine.rootContext()->setContextProperty("launcher", launcher);
-    engine.rootContext()->setContextProperty("weather", new Weather(bindingAddress));
-    engine.rootContext()->setContextProperty("bluetooth", new Bluetooth(bindingAddress, engine.rootContext()));
-    engine.rootContext()->setContextProperty("speechChromeController", new ChromeController(bindingAddress, &engine));
-    engine.rootContext()->setContextProperty("screenInfo", &screenInfo);
-    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
-
-    QObject *root = engine.rootObjects().first();
-    QQuickWindow *window = qobject_cast<QQuickWindow *>(root);
-    QObject::connect(window, SIGNAL(frameSwapped()), layoutHandler, SLOT(slotActivateSurface()));
-
-    QList<QObject *> sobjs = engine.rootObjects();
-    StatusBarModel *statusBar = sobjs.first()->findChild<StatusBarModel *>("statusBar");
-    statusBar->init(bindingAddress, engine.rootContext());
+    QQmlContext *context = engine.rootContext();
+    context->setContextProperty("bindingAddress", bindingAddress);
+
+    context->setContextProperty("homescreenHandler", homescreenHandler);
+    context->setContextProperty("launcher", launcher);
+    context->setContextProperty("weather", new Weather(bindingAddress));
+    context->setContextProperty("bluetooth", new Bluetooth(bindingAddress, context));
+    context->setContextProperty("speechChromeController", new ChromeController(bindingAddress, &engine));
+    // we add it here even if we don't use it
+    context->setContextProperty("shell", aglShell);
+
+    /* instead of loading main.qml we load one-by-one each of the QMLs,
+     * divided now between several surfaces: panels, background.
+     */
+    load_agl_shell_app(native, &engine, agl_shell, bindingAddress);
 
     return a.exec();
 }
diff --git a/homescreen/src/shell.cpp b/homescreen/src/shell.cpp
new file mode 100644 (file)
index 0000000..1427b7c
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright © 2019 Collabora Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <QGuiApplication>
+#include <QDebug>
+#include "shell.h"
+#include <qpa/qplatformnativeinterface.h>
+#include <stdio.h>
+
+static struct wl_output *
+getWlOutput(QPlatformNativeInterface *native, QScreen *screen)
+{
+       void *output = native->nativeResourceForScreen("output", screen);
+       return static_cast<struct ::wl_output*>(output);
+}
+
+void Shell::activate_app(QWindow *win, const QString &app_id)
+{
+    QPlatformNativeInterface *native = qApp->platformNativeInterface();
+    QScreen *screen = win->screen();
+
+    struct wl_output *output = getWlOutput(native, screen);
+
+    qDebug() << "++ activating app_id " << app_id.toStdString().c_str();
+
+    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..8bf0e9b
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright © 2019 Collabora Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#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
+
+public:
+    std::shared_ptr<struct agl_shell> shell;
+
+    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
index d866513..0586a12 100644 (file)
@@ -11,7 +11,6 @@
     <param name="network-manager" value="ws" />
     <param name="weather" value="ws" />
     <param name="Bluetooth-Manager" value="ws" />
-    <param name="windowmanager" value="ws" />
     <param name="audiomixer" value="ws" />
     <param name="vshl-core" value="ws" />
   </feature>