From bb4c83e294f109497f504c0dd8e23143c07883d6 Mon Sep 17 00:00:00 2001 From: Marius Vlad Date: Tue, 1 Nov 2022 13:29:43 +0200 Subject: homescreen: Add support for defining an activation area This is an example on how to use it, and it enables a new variable HOMESCREEN_EMBEDDED_PANELS to test it out. It gives out the same rectangle are we have in the homescreen demo, but the panels are this time embedded into the background surface, rather than being a separate surface. This introduces a new Qml file, background_with_panels which integrates both the top and the bottom panel into a single qml, which main.cpp loads. While at it, this corrects up the indentation we have in shell.cpp file and sets up the default output in homeScreenHandler constructor. Due to this way integrates and works, it should *not* be visual change between the two (the normal, two panel surfaces) and this version. It can used as a example how to integrate this better, when managing multiple surfaces is not easy to be done by the toolkit or runtime. Bug-AGL: SPEC-4594 Signed-off-by: Marius Vlad Change-Id: Ibe274b336b15e9713d0cdded5424cc8e92257d7f --- homescreen/qml/background_with_panels.qml | 159 ++++++++++++++++++++++++++++++ homescreen/qml/qml.qrc | 1 + homescreen/src/homescreenhandler.cpp | 9 +- homescreen/src/homescreenhandler.h | 1 + homescreen/src/main.cpp | 81 ++++++++++++--- homescreen/src/shell.cpp | 8 ++ homescreen/src/shell.h | 20 ++-- 7 files changed, 252 insertions(+), 27 deletions(-) create mode 100644 homescreen/qml/background_with_panels.qml diff --git a/homescreen/qml/background_with_panels.qml b/homescreen/qml/background_with_panels.qml new file mode 100644 index 0000000..f0cb958 --- /dev/null +++ b/homescreen/qml/background_with_panels.qml @@ -0,0 +1,159 @@ +import QtQuick 2.13 +import QtQuick.Window 2.13 +import QtQuick.Layouts 1.15 + +Window { + id: background + width: Screen.width + height: Screen.height + flags: Qt.FramelessWindowHint + visible: true + + Grid { + rows: 3 + spacing: 0 + + Rectangle { + width: Screen.width + height: 216 + color: "#33363a" + + 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() + } + } + + Image { + anchors.fill: parent + source: './images/TopSection_NoText_NoIcons-01.svg' + //fillMode: Image.PreserveAspectCrop + fillMode: Image.Stretch + + RowLayout { + anchors.fill: parent + spacing: 0 + ShortcutArea { + id: shortcutArea + Layout.fillWidth: true + Layout.fillHeight: true + Layout.preferredWidth: 775 + } + StatusArea { + id: statusArea + Layout.fillWidth: true + Layout.fillHeight: true + Layout.preferredWidth: 291 + } + } + } + + } + + Rectangle { + width: Screen.width + height: Screen.height - (2 * 216) + Image { + anchors.fill: parent + source: './images/AGL_HMI_Blue_Background_NoCar-01.png' + } + + } + + Rectangle { + width: Screen.width + height: 216 + color: "#33363a" + + MediaArea { + } + + Timer { + id:informationTimer + interval: 3000 + running: false + repeat: true + onTriggered: { + bottomInformation.visible = false + } + } + + Item { + id: bottomInformation + width: parent.width + height: 216 + 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() + } + } + + } + } +} diff --git a/homescreen/qml/qml.qrc b/homescreen/qml/qml.qrc index 319e1da..3c0dbcd 100644 --- a/homescreen/qml/qml.qrc +++ b/homescreen/qml/qml.qrc @@ -10,6 +10,7 @@ TopArea.qml IconItem.qml background.qml + background_with_panels.qml toppanel.qml bottompanel.qml background_demo.qml diff --git a/homescreen/src/homescreenhandler.cpp b/homescreen/src/homescreenhandler.cpp index 2858ef4..e61f0de 100644 --- a/homescreen/src/homescreenhandler.cpp +++ b/homescreen/src/homescreenhandler.cpp @@ -18,12 +18,17 @@ // a user session by systemd #define LAUNCHER_APP_ID "launcher" +static struct wl_output * +getWlOutput(QPlatformNativeInterface *native, QScreen *screen); + HomescreenHandler::HomescreenHandler(Shell *_aglShell, ApplicationLauncher *launcher, QObject *parent) : QObject(parent), aglShell(_aglShell) { mp_launcher = launcher; mp_applauncher_client = new AppLauncherClient(); + QPlatformNativeInterface *native = qApp->platformNativeInterface(); + m_output = getWlOutput(native, qApp->screens().first()); // // The "started" event is received any time a start request is made to applaunchd, @@ -88,15 +93,13 @@ void HomescreenHandler::addAppToStack(const QString& app_id) void HomescreenHandler::activateApp(const QString& app_id) { struct agl_shell *agl_shell = aglShell->shell.get(); - QPlatformNativeInterface *native = qApp->platformNativeInterface(); - struct wl_output *output = getWlOutput(native, qApp->screens().first()); if (mp_launcher) { mp_launcher->setCurrent(app_id); } HMI_DEBUG("HomeScreen", "Activating application %s", app_id.toStdString().c_str()); - agl_shell_activate_app(agl_shell, app_id.toStdString().c_str(), output); + agl_shell_activate_app(agl_shell, app_id.toStdString().c_str(), m_output); } void HomescreenHandler::deactivateApp(const QString& app_id) diff --git a/homescreen/src/homescreenhandler.h b/homescreen/src/homescreenhandler.h index a2baeb2..751457e 100644 --- a/homescreen/src/homescreenhandler.h +++ b/homescreen/src/homescreenhandler.h @@ -40,6 +40,7 @@ public slots: private: ApplicationLauncher *mp_launcher; AppLauncherClient *mp_applauncher_client; + struct wl_output *m_output; Shell *aglShell; diff --git a/homescreen/src/main.cpp b/homescreen/src/main.cpp index c910727..674ef5d 100644 --- a/homescreen/src/main.cpp +++ b/homescreen/src/main.cpp @@ -112,7 +112,7 @@ global_add(void *data, struct wl_registry *reg, uint32_t name, if (ver >= 2) { shell_data->shell = static_cast( - wl_registry_bind(reg, name, &agl_shell_interface, MIN(3, ver))); + wl_registry_bind(reg, name, &agl_shell_interface, MIN(4, ver))); #ifdef AGL_SHELL_BOUND_OK_SINCE_VERSION agl_shell_add_listener(shell_data->shell, &shell_listener, data); #endif @@ -213,15 +213,14 @@ static void load_agl_shell_app(QPlatformNativeInterface *native, QQmlApplicationEngine *engine, struct agl_shell *agl_shell, - const char *screen_name, - bool is_demo) + const char *screen_name, bool is_demo, bool embedded_panels) { struct wl_surface *bg, *top, *bottom; struct wl_output *output; QObject *qobj_bg, *qobj_top, *qobj_bottom; QScreen *screen = nullptr; - if (is_demo) { + if (is_demo && !embedded_panels) { QQmlComponent bg_comp(engine, QUrl("qrc:/background_demo.qml")); qInfo() << bg_comp.errors(); @@ -234,7 +233,16 @@ load_agl_shell_app(QPlatformNativeInterface *native, top = create_component(native, &top_comp, screen, &qobj_top); bottom = create_component(native, &bot_comp, screen, &qobj_bottom); bg = create_component(native, &bg_comp, screen, &qobj_bg); - } else { + + /* engine.rootObjects() works only if we had a load() */ + StatusBarModel *statusBar = qobj_top->findChild("statusBar"); + if (statusBar) { + qDebug() << "got statusBar objectname, doing init()"; + statusBar->init(engine->rootContext()); + } + + qDebug() << "init debug mode"; + } else if (!embedded_panels) { QQmlComponent bg_comp(engine, QUrl("qrc:/background.qml")); qInfo() << bg_comp.errors(); @@ -247,6 +255,24 @@ load_agl_shell_app(QPlatformNativeInterface *native, top = create_component(native, &top_comp, screen, &qobj_top); bottom = create_component(native, &bot_comp, screen, &qobj_bottom); bg = create_component(native, &bg_comp, screen, &qobj_bg); + + /* engine.rootObjects() works only if we had a load() */ + StatusBarModel *statusBar = qobj_top->findChild("statusBar"); + if (statusBar) { + qDebug() << "got statusBar objectname, doing init()"; + statusBar->init(engine->rootContext()); + } + + qDebug() << "init normal mode"; + } else { + // this incorporates the panels directly, but in doing so, it + // would also need to specify an activation area the same area + // in order to void overlapping any new activation window + QQmlComponent bg_comp(engine, QUrl("qrc:/background_with_panels.qml")); + qInfo() << bg_comp.errors(); + + bg = create_component(native, &bg_comp, screen, &qobj_bg); + qDebug() << "init embedded panels mode"; } if (!screen_name) @@ -263,22 +289,39 @@ load_agl_shell_app(QPlatformNativeInterface *native, "first screen " << qApp->screens().first()->name(); output = getWlOutput(native, screen); - /* engine.rootObjects() works only if we had a load() */ - StatusBarModel *statusBar = qobj_top->findChild("statusBar"); - if (statusBar) { - qDebug() << "got statusBar objectname, doing init()"; - statusBar->init(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); qDebug() << "Setting homescreen to screen " << screen->name(); - agl_shell_set_background(agl_shell, bg, output); + if (embedded_panels) { + int32_t x, y; + int32_t width, height; + QSize size = screen->size(); + + x = 0; + y = 216; + + width = size.width(); + height = size.height() - (2 * y); + + qDebug() << "Using custom rectangle " << width << "x" << height + << "+" << x << "x" << y << " for activation"; + qDebug() << "Panels should be embedded the background surface"; + +#ifdef AGL_SHELL_SET_ACTIVATE_REGION_SINCE_VERSION + agl_shell_set_activate_region(agl_shell, output, + x, y, width, height); +#endif + + } else { + agl_shell_set_panel(agl_shell, top, output, AGL_SHELL_EDGE_TOP); + agl_shell_set_panel(agl_shell, bottom, output, AGL_SHELL_EDGE_BOTTOM); + qDebug() << "Setting regular panels"; + } + /* Delay the ready signal until after Qt has done all of its own setup * in a.exec() */ QTimer::singleShot(500, [agl_shell](){ + qDebug() << "sending ready to compositor"; agl_shell_ready(agl_shell); }); } @@ -291,6 +334,7 @@ int main(int argc, char *argv[]) QGuiApplication app(argc, argv); const char *screen_name; bool is_demo_val = false; + bool is_embedded_panels = false; int ret = 0; struct shell_data shell_data = { nullptr, nullptr, true, false, 0 }; @@ -301,6 +345,10 @@ int main(int argc, char *argv[]) if (is_demo && strcmp(is_demo, "1") == 0) is_demo_val = true; + const char *embedded_panels = getenv("HOMESCREEN_EMBEDDED_PANELS"); + if (embedded_panels && strcmp(embedded_panels, "1") == 0) + is_embedded_panels = true; + QCoreApplication::setOrganizationDomain("LinuxFoundation"); QCoreApplication::setOrganizationName("AutomotiveGradeLinux"); QCoreApplication::setApplicationName("HomeScreen"); @@ -358,7 +406,8 @@ int main(int argc, char *argv[]) // 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, shell_data.shell, screen_name, is_demo_val); + load_agl_shell_app(native, &engine, shell_data.shell, + screen_name, is_demo_val, is_embedded_panels); return app.exec(); } diff --git a/homescreen/src/shell.cpp b/homescreen/src/shell.cpp index ffb4439..b7583c1 100644 --- a/homescreen/src/shell.cpp +++ b/homescreen/src/shell.cpp @@ -50,3 +50,11 @@ void Shell::activate_app(QWindow *win, const QString &app_id) app_id.toStdString().c_str(), output); } + +void Shell::set_activate_region(struct wl_output *output, int32_t x, int32_t y, + int32_t width, int32_t height) +{ +#ifdef AGL_SHELL_SET_ACTIVATE_REGION_SINCE_VERSION + agl_shell_set_activate_region(this->shell.get(), output, x, y, width, height); +#endif +} diff --git a/homescreen/src/shell.h b/homescreen/src/shell.h index a6e3f7e..51990d8 100644 --- a/homescreen/src/shell.h +++ b/homescreen/src/shell.h @@ -41,16 +41,20 @@ class Shell : public QObject { - Q_OBJECT + Q_OBJECT public: - std::shared_ptr shell; - - Shell(std::shared_ptr shell, QObject *parent = nullptr) : - QObject(parent), shell(shell) - {} -public slots: - void activate_app(QWindow *win, const QString &app_id); + std::shared_ptr shell; + + Shell(std::shared_ptr shell, QObject *parent = nullptr) : + QObject(parent), shell(shell) + {} + public slots: + void activate_app(QWindow *win, const QString &app_id); + void set_activate_region(struct wl_output *output, int32_t x, int32_t y, + int32_t width, int32_t height); +private: + struct wl_region *m_region = nullptr; }; #endif // SHELLHANDLER_H -- cgit 1.2.3-korg