summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--COPYING22
-rw-r--r--LICENSE54
-rw-r--r--README.md18
-rw-r--r--app/CMakeLists.txt46
-rw-r--r--app/hmi-debug.h117
-rw-r--r--app/main.cpp874
-rw-r--r--app/shell-desktop.cpp117
-rw-r--r--app/shell-desktop.h68
-rw-r--r--app/surface.cpp146
-rw-r--r--app/surface.hpp54
-rw-r--r--app/zalloc.h45
-rw-r--r--conf.d/cmake/config.cmake14
13 files changed, 874 insertions, 702 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bf284f7..b61d900 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,4 +18,5 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.3)
+project(xdg-cluster-receiver)
include(${CMAKE_CURRENT_SOURCE_DIR}/conf.d/cmake/config.cmake)
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..74eaa45
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,22 @@
+Copyright © 2020 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.
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 31c692a..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,54 +0,0 @@
-Apache License
-
-Version 2.0, January 2004
-
-http://www.apache.org/licenses/
-
-TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-1. Definitions.
-
-"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
-
-"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
-
-"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
-
-"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
-
-"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
-
-"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
-
-"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
-
-"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
-
-"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
-
-"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
-
-2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
-
-3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
-
-4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
-
- You must give any other recipients of the Work or Derivative Works a copy of this License; and
- You must cause any modified files to carry prominent notices stating that You changed the files; and
- You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
- If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
-
- You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
-
-5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
-
-6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
-
-7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
-
-8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
-
-9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
-
-END OF TERMS AND CONDITIONS
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..17a1bba
--- /dev/null
+++ b/README.md
@@ -0,0 +1,18 @@
+xdg-cluster-receiver
+--------------------
+
+This is a variant of the cluster-demo-receiver but without any toolkit
+involvement, using wayland-protocols (to gain access to XDG-Shell) and
+agl-shell* private extensions provided by the compositor.
+
+We use XDG-Shell to create a top-level XDG window and set an application id for
+it. We use agl-shell-desktop to be able to position indepedently the surface
+on top of the cluster-dashbboard application, and in the same time specify
+a bounding box.
+
+Underneath, waylandsink requires a parent surface (wl_surface) as to create a
+sub-subsurface where it will draw, on its own, the incoming stream.
+
+We don't pass out that parent surface to the compositor, but instead of use the
+app_id to identify applications, that is why it is import to set, for the parent
+surface an application id.
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index ff8eb93..9008b9e 100644
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -1,7 +1,9 @@
###########################################################################
# Copyright 2018 Konsulko Group
+# Copyright 2020 Collabora, Ltd.
#
# Author: Scott Murray <scott.murray@konsulko.com>
+# Author: Marius Vlad <marius.vlad@collabora.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,18 +19,13 @@
###########################################################################
set(CMAKE_INCLUDE_CURRENT_DIR ON)
-set(CMAKE_AUTOMOC ON)
-set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
-set(OE_QMAKE_PATH_EXTERNAL_HOST_BINS $ENV{OE_QMAKE_PATH_HOST_BINS})
-find_package(Qt5 COMPONENTS Core Gui QuickControls2 QuickWidgets REQUIRED)
-find_package(Qt5Gui ${QT_MIN_VERSION} CONFIG REQUIRED Private)
find_package(PkgConfig REQUIRED)
find_program(WAYLAND_SCANNER_EXECUTABLE NAMES wayland-scanner)
-PROJECT_TARGET_ADD(cluster-receiver)
+PROJECT_TARGET_ADD(xdg-cluster-receiver)
add_custom_command(
OUTPUT agl-shell-desktop-client-protocol.h
@@ -55,25 +52,51 @@ add_custom_command(
DEPENDS ${CMAKE_SOURCE_DIR}/app/protocol/agl-shell-desktop.xml
)
+
pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)
pkg_check_modules(GSTREAMER_PLUGINS_BASE REQUIRED gstreamer-plugins-base-1.0)
pkg_check_modules(GSTREAMER_VIDEO REQUIRED gstreamer-video-1.0)
pkg_check_modules(GSTREAMER_PLUGINS_BAD REQUIRED gstreamer-plugins-bad-1.0)
pkg_check_modules(WAYLAND_CLIENT REQUIRED wayland-client)
+pkg_check_modules(WAYLAND_PROTOCOLS REQUIRED wayland-protocols>=1.18)
+pkg_get_variable(WAYLAND_PROTOCOLS_BASE wayland-protocols pkgdatadir)
+
+add_custom_command(
+ OUTPUT xdg-shell-client-protocol.h
+ COMMAND ${WAYLAND_SCANNER_EXECUTABLE} client-header
+ < ${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml
+ > ${CMAKE_SOURCE_DIR}/app/xdg-shell-client-protocol.h
+ DEPENDS ${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml
+)
+
+
+add_custom_command(
+ OUTPUT ${CMAKE_BINARY_DIR}/app/xdg-shell-client-protocol.h
+ COMMAND ${WAYLAND_SCANNER_EXECUTABLE} client-header
+ < ${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml
+ > ${CMAKE_SOURCE_DIR}/app/xdg-shell-client-protocol.h
+ DEPENDS ${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml
+)
+
+add_custom_command(
+ OUTPUT xdg-shell-protocol.c
+ COMMAND ${WAYLAND_SCANNER_EXECUTABLE} code
+ < ${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml
+ > ${CMAKE_BINARY_DIR}/app/xdg-shell-protocol.c
+ DEPENDS ${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml
+)
add_executable(${TARGET_NAME}
main.cpp
- surface.cpp
agl-shell-desktop-protocol.c
agl-shell-desktop-client-protocol.h
- shell-desktop.cpp
+ xdg-shell-protocol.c
+ xdg-shell-client-protocol.h
${RESOURCES}
)
include_directories(
- include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
- ${QTAPPFW_INCLUDE_DIRS}
"${GSTREAMER_INCLUDE_DIRS}"
"${GSTREAMER_PLUGINS_BASE_INCLUDE_DIRS}"
"${GSTREAMER_PLUGINS_BAD_INCLUDE_DIRS}"
@@ -90,13 +113,10 @@ set_target_properties(${TARGET_NAME} PROPERTIES
)
target_link_libraries(${TARGET_NAME}
- Qt5::QuickControls2
- Qt5::QuickWidgets
${GSTREAMER_LIBRARIES}
"${GSTREAMER_PLUGINS_BASE_LIBRARIES}"
"${GSTREAMER_PLUGINS_BAD_LIBRARIES}"
"${GSTREAMER_VIDEO_LIBRARIES}"
- ${QTAPPFW_LIBRARIES}
${WAYLAND_CLIENT_LIBRARIES}
-lgstwayland-1.0
)
diff --git a/app/hmi-debug.h b/app/hmi-debug.h
deleted file mode 100644
index 697ac80..0000000
--- a/app/hmi-debug.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
- *
- * 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 __HMI_DEBUG_H__
-#define __HMI_DEBUG_H__
-
-#include <time.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <stdlib.h>
-
-enum LOG_LEVEL{
- LOG_LEVEL_NONE = 0,
- LOG_LEVEL_ERROR,
- LOG_LEVEL_WARNING,
- LOG_LEVEL_NOTICE,
- LOG_LEVEL_INFO,
- LOG_LEVEL_DEBUG,
- LOG_LEVEL_MAX = LOG_LEVEL_DEBUG
-};
-
-#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
-
-#define HMI_ERROR(prefix, args,...) _HMI_LOG(LOG_LEVEL_ERROR, __FILENAME__, __FUNCTION__, __LINE__, prefix, args, ##__VA_ARGS__)
-#define HMI_WARNING(prefix, args,...) _HMI_LOG(LOG_LEVEL_WARNING, __FILENAME__, __FUNCTION__,__LINE__, prefix, args,##__VA_ARGS__)
-#define HMI_NOTICE(prefix, args,...) _HMI_LOG(LOG_LEVEL_NOTICE, __FILENAME__, __FUNCTION__,__LINE__, prefix, args,##__VA_ARGS__)
-#define HMI_INFO(prefix, args,...) _HMI_LOG(LOG_LEVEL_INFO, __FILENAME__, __FUNCTION__,__LINE__, prefix, args,##__VA_ARGS__)
-#define HMI_DEBUG(prefix, args,...) _HMI_LOG(LOG_LEVEL_DEBUG, __FILENAME__, __FUNCTION__,__LINE__, prefix, args,##__VA_ARGS__)
-
-#define HMI_SEQ_ERROR(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_ERROR, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__)
-#define HMI_SEQ_WARNING(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_WARNING, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__)
-#define HMI_SEQ_NOTICE(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_NOTICE, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__)
-#define HMI_SEQ_INFO(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_INFO, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__)
-#define HMI_SEQ_DEBUG(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_DEBUG, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__)
-
-#define DUMP(args, ...) _DUMP(LOG_LEVEL_DEBUG, args, ##__VA_ARGS__)
-
-static char ERROR_FLAG[6][20] = {"NONE", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG"};
-
-static void _HMI_LOG(enum LOG_LEVEL level, const char* file, const char* func, const int line, const char* prefix, const char* log, ...)
-{
- const int log_level = (getenv("USE_HMI_DEBUG") == NULL)?LOG_LEVEL_ERROR:atoi(getenv("USE_HMI_DEBUG"));
- if(log_level < level)
- {
- return;
- }
-
- char *message;
- struct timespec tp;
- unsigned int time;
-
- clock_gettime(CLOCK_REALTIME, &tp);
- time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
-
- va_list args;
- va_start(args, log);
- if (log == NULL || vasprintf(&message, log, args) < 0)
- message = NULL;
- fprintf(stderr, "[%10.3f] [%s %s] [%s, %s(), Line:%d] >>> %s \n", time / 1000.0, prefix, ERROR_FLAG[level], file, func, line, message);
- va_end(args);
- free(message);
-}
-
-static void _HMI_SEQ_LOG(enum LOG_LEVEL level, const char* file, const char* func, const int line, unsigned seq_num, const char* log, ...){
- const int log_level = (getenv("USE_HMI_DEBUG") == NULL) ? LOG_LEVEL_ERROR:atoi(getenv("USE_HMI_DEBUG"));
- if(log_level < level)
- {
- return;
- }
-
- char *message;
- struct timespec tp;
- unsigned int time;
-
- clock_gettime(CLOCK_REALTIME, &tp);
- time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
-
- va_list args;
- va_start(args, log);
- if (log == NULL || vasprintf(&message, log, args) < 0)
- message = NULL;
- fprintf(stderr, "[%10.3f] [wm %s] [%s, %s(), Line:%d] >>> req %d: %s \n", time / 1000.0, ERROR_FLAG[level], file, func, line, seq_num, message);
- va_end(args);
- free(message);
-}
-
-static void _DUMP(enum LOG_LEVEL level, const char *log, ...)
-{
- const int log_level = (getenv("USE_HMI_DEBUG") == NULL) ? LOG_LEVEL_ERROR : atoi(getenv("USE_HMI_DEBUG"));
- if (log_level < level)
- {
- return;
- }
- char *message;
- va_list args;
- va_start(args, log);
- if (log == NULL || vasprintf(&message, log, args) < 0)
- message = NULL;
- fprintf(stderr, "%s \n", message);
- va_end(args);
- free(message);
-}
-#endif //__HMI_DEBUG_H__ \ No newline at end of file
diff --git a/app/main.cpp b/app/main.cpp
index b68aeac..fe2fce2 100644
--- a/app/main.cpp
+++ b/app/main.cpp
@@ -1,83 +1,534 @@
/*
- * Copyright (C) 2018 Konsulko Group
+ * Copyright © 2020 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
+ * 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:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
*
- * 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.
+ * 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 <QApplication>
-#include <QtCore/QDebug>
-#include <QtCore/QCommandLineParser>
-#include <QtCore/QUrlQuery>
-#include <QtGui/QGuiApplication>
-#include <QtQml/QQmlApplicationEngine>
-#include <QtQml/QQmlContext>
-#include <QtQml/qqml.h>
-#include <QQuickWindow>
-#include <QtQuickControls2/QQuickStyle>
-#include <QtGui/QGuiApplication>
-#include <qpa/qplatformnativeinterface.h>
-#include <QTimer>
#define GST_USE_UNSTABLE_API
-
-#include <QWidget>
+#define HAVE_MEMFD_CREATE
#include <string>
#include <iostream>
#include <cstring>
+#include <cstdio>
+#include <cstdlib>
+
+#include <signal.h>
+#include <wayland-client.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#include "xdg-shell-client-protocol.h"
+#include "agl-shell-desktop-client-protocol.h"
+#include "zalloc.h"
#include <gst/gst.h>
#include <gst/video/videooverlay.h>
#include <gst/wayland/wayland.h>
-#include "surface.hpp"
-
#define WINDOW_WIDTH_SIZE 640
#define WINDOW_HEIGHT_SIZE 720
#define WINDOW_WIDTH_POS_X 640
#define WINDOW_WIDTH_POS_Y 180
-struct cluster_window_data {
- int x; int y;
- int width; int height;
+
+// C++ requires a cast and we in wayland we do the cast implictly
+#define WL_ARRAY_FOR_EACH(pos, array, type) \
+ for (pos = (type)(array)->data; \
+ (const char *) pos < ((const char *) (array)->data + (array)->size); \
+ (pos)++)
+
+struct display {
+ struct wl_display *wl_display;
+ struct wl_registry *wl_registry;
+ struct wl_compositor *wl_compositor;
+ struct wl_output *wl_output;
+ struct wl_shm *shm;
+
+ struct {
+ int width;
+ int height;
+ } output_data;
+
+ struct xdg_wm_base *wm_base;
+ struct agl_shell_desktop *agl_shell_desktop;
+
+ int has_xrgb;
+};
+
+struct buffer {
+ struct wl_buffer *buffer;
+ void *shm_data;
+ int busy;
+};
+
+struct window {
+ struct display *display;
+
+ int x, y;
+ int width, height;
+
+ struct wl_surface *surface;
+
+ struct xdg_surface *xdg_surface;
+ struct xdg_toplevel *xdg_toplevel;
+ bool wait_for_configure;
+
+ int fullscreen, maximized;
+
+ struct buffer buffers[2];
+ struct wl_callback *callback;
};
+
struct cluster_receiver_data {
- QWidget *widget;
- QPlatformNativeInterface *native;
+ struct window *window;
GstElement *pipeline;
GstWaylandVideo *wl_video;
GstVideoOverlay *overlay;
+};
+
+static int running = 1;
+
+static void
+redraw(void *data, struct wl_callback *callback, uint32_t time);
+
+static void
+paint_pixels(void *image, int padding, int width, int height, uint32_t time)
+{
+ memset(image, 0x00, width * height * 4);
+}
+
+static void
+buffer_release(void *data, struct wl_buffer *buffer)
+{
+ struct buffer *mybuf = static_cast<struct buffer *>(data);
+ mybuf->busy = 0;
+}
+
+static const struct wl_buffer_listener buffer_listener = {
+ buffer_release
+};
+
+static int
+os_fd_set_cloexec(int fd)
+{
+ long flags;
+
+ if (fd == -1)
+ return -1;
+
+ flags = fcntl(fd, F_GETFD);
+ if (flags == -1)
+ return -1;
+
+ if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+ return -1;
+
+ return 0;
+}
+
+static int
+set_cloexec_or_close(int fd)
+{
+ if (os_fd_set_cloexec(fd) != 0) {
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+
+static int
+create_tmpfile_cloexec(char *tmpname)
+{
+ int fd;
+
+#ifdef HAVE_MKOSTEMP
+ fd = mkostemp(tmpname, O_CLOEXEC);
+ if (fd >= 0)
+ unlink(tmpname);
+#else
+ fd = mkstemp(tmpname);
+ if (fd >= 0) {
+ fd = set_cloexec_or_close(fd);
+ unlink(tmpname);
+ }
+#endif
+
+ return fd;
+}
+
+/*
+ * Create a new, unique, anonymous file of the given size, and
+ * return the file descriptor for it. The file descriptor is set
+ * CLOEXEC. The file is immediately suitable for mmap()'ing
+ * the given size at offset zero.
+ *
+ * The file should not have a permanent backing store like a disk,
+ * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
+ *
+ * The file name is deleted from the file system.
+ *
+ * The file is suitable for buffer sharing between processes by
+ * transmitting the file descriptor over Unix sockets using the
+ * SCM_RIGHTS methods.
+ *
+ * If the C library implements posix_fallocate(), it is used to
+ * guarantee that disk space is available for the file at the
+ * given size. If disk space is insufficient, errno is set to ENOSPC.
+ * If posix_fallocate() is not supported, program may receive
+ * SIGBUS on accessing mmap()'ed file contents instead.
+ *
+ * If the C library implements memfd_create(), it is used to create the
+ * file purely in memory, without any backing file name on the file
+ * system, and then sealing off the possibility of shrinking it. This
+ * can then be checked before accessing mmap()'ed file contents, to
+ * make sure SIGBUS can't happen. It also avoids requiring
+ * XDG_RUNTIME_DIR.
+ */
+static int
+os_create_anonymous_file(off_t size)
+{
+ static const char weston_template[] = "/weston-shared-XXXXXX";
+ const char *path;
+ char *name;
+ int fd;
+ int ret;
+
+#ifdef HAVE_MEMFD_CREATE
+ fd = memfd_create("weston-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ if (fd >= 0) {
+ /* We can add this seal before calling posix_fallocate(), as
+ * the file is currently zero-sized anyway.
+ *
+ * There is also no need to check for the return value, we
+ * couldn't do anything with it anyway.
+ */
+ fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK);
+ } else
+#endif
+ {
+ path = getenv("XDG_RUNTIME_DIR");
+ if (!path) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ name = static_cast<char *>(malloc(strlen(path) + sizeof(weston_template)));
+ if (!name)
+ return -1;
+
+ strcpy(name, path);
+ strcat(name, weston_template);
+
+ fd = create_tmpfile_cloexec(name);
+
+ free(name);
+
+ if (fd < 0)
+ return -1;
+ }
+
+#ifdef HAVE_POSIX_FALLOCATE
+ do {
+ ret = posix_fallocate(fd, 0, size);
+ } while (ret == EINTR);
+ if (ret != 0) {
+ close(fd);
+ errno = ret;
+ return -1;
+ }
+#else
+ do {
+ ret = ftruncate(fd, size);
+ } while (ret < 0 && errno == EINTR);
+ if (ret < 0) {
+ close(fd);
+ return -1;
+ }
+#endif
+
+ return fd;
+}
+
+static int
+create_shm_buffer(struct display *display, struct buffer *buffer,
+ int width, int height, uint32_t format)
+{
+ struct wl_shm_pool *pool;
+ int fd, size, stride;
+ void *data;
+
+ stride = width * 4;
+ size = stride * height;
+
+ fd = os_create_anonymous_file(size);
+ if (fd < 0) {
+ fprintf(stderr, "creating a buffer file for %d B failed: %s\n",
+ size, strerror(errno));
+ return -1;
+ }
+
+ data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (data == MAP_FAILED) {
+ fprintf(stderr, "mmap failed: %s\n", strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ pool = wl_shm_create_pool(display->shm, fd, size);
+ buffer->buffer = wl_shm_pool_create_buffer(pool, 0, width,
+ height, stride, format);
+ wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
+ wl_shm_pool_destroy(pool);
+ close(fd);
+
+ buffer->shm_data = data;
+ return 0;
+}
+
+static struct buffer *
+get_next_buffer(struct window *window)
+{
+ struct buffer *buffer;
+ int ret = 0;
+
+ if (!window->buffers[0].busy)
+ buffer = &window->buffers[0];
+ else if (!window->buffers[1].busy)
+ buffer = &window->buffers[1];
+ else
+ return NULL;
+
+ if (!buffer->buffer) {
+ fprintf(stdout, "get_next_buffer() buffer is not set, setting with "
+ "width %d, height %d\n", window->width, window->height);
+ ret = create_shm_buffer(window->display, buffer, window->width,
+ window->height, WL_SHM_FORMAT_XRGB8888);
+
+ if (ret < 0)
+ return NULL;
+
+ /* paint the padding */
+ memset(buffer->shm_data, 0x00, window->width * window->height * 4);
+ }
+
+ return buffer;
+}
+
+
+static const struct wl_callback_listener frame_listener = {
+ redraw
+};
+
+static void
+redraw(void *data, struct wl_callback *callback, uint32_t time)
+{
+ struct window *window = static_cast<struct window *>(data);
+ struct buffer *buffer;
+
+ buffer = get_next_buffer(window);
+ if (!buffer) {
+ fprintf(stderr,
+ !callback ? "Failed to create the first buffer.\n" :
+ "Both buffers busy at redraw(). Server bug?\n");
+ abort();
+ }
+
+ // do the actual painting
+ paint_pixels(buffer->shm_data, 0x0, window->width, window->height, time);
+
+ wl_surface_attach(window->surface, buffer->buffer, 0, 0);
+ wl_surface_damage(window->surface, 0, 0, window->width, window->height);
+
+ if (callback)
+ wl_callback_destroy(callback);
+
+ window->callback = wl_surface_frame(window->surface);
+ wl_callback_add_listener(window->callback, &frame_listener, window);
+ wl_surface_commit(window->surface);
+
+ buffer->busy = 1;
+}
+
+static void
+shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
+{
+ struct display *d = static_cast<struct display *>(data);
+
+ if (format == WL_SHM_FORMAT_XRGB8888)
+ d->has_xrgb = true;
+}
+
+static const struct wl_shm_listener shm_listener = {
+ shm_format
+};
+
+static void
+xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial)
+{
+ xdg_wm_base_pong(shell, serial);
+}
+
+static const struct xdg_wm_base_listener xdg_wm_base_listener = {
+ xdg_wm_base_ping,
+};
+
+static void
+display_handle_geometry(void *data, struct wl_output *wl_output,
+ int x, int y, int physical_width, int physical_height,
+ int subpixel, const char *make, const char *model, int transform)
+{
+ (void) data;
+ (void) wl_output;
+ (void) x;
+ (void) y;
+ (void) physical_width;
+ (void) physical_height;
+ (void) subpixel;
+ (void) make;
+ (void) model;
+ (void) transform;
+}
+
+static void
+display_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags,
+ int width, int height, int refresh)
+{
+ struct display *d = static_cast<struct display *>(data);
+
+ if (wl_output == d->wl_output && (flags & WL_OUTPUT_MODE_CURRENT)) {
+ d->output_data.width = width;
+ d->output_data.height = height;
+
+ fprintf(stdout, "Found output with width %d and height %d\n",
+ d->output_data.width, d->output_data.height);
+ }
+}
- bool widget_has_buffer_mapped;
- struct cluster_window_data window_data;
+static void
+display_handle_scale(void *data, struct wl_output *wl_output, int scale)
+{
+ (void) data;
+ (void) wl_output;
+ (void) scale;
+}
+
+static void
+display_handle_done(void *data, struct wl_output *wl_output)
+{
+ (void) data;
+ (void) wl_output;
+}
+
+static const struct wl_output_listener output_listener = {
+ display_handle_geometry,
+ display_handle_mode,
+ display_handle_done,
+ display_handle_scale
+};
+
+static void
+application_id(void *data, struct agl_shell_desktop *agl_shell_desktop,
+ const char *app_id)
+{
+ (void) data;
+ (void) agl_shell_desktop;
+ (void) app_id;
+}
+
+static void
+application_id_state(void *data, struct agl_shell_desktop *agl_shell_desktop,
+ const char *app_id, const char *app_data,
+ uint32_t app_state, uint32_t app_role)
+{
+ (void) data;
+ (void) app_data;
+ (void) agl_shell_desktop;
+ (void) app_id;
+ (void) app_state;
+ (void) app_role;
+}
+
+static const struct agl_shell_desktop_listener agl_shell_desktop_listener = {
+ application_id,
+ application_id_state,
};
-static struct wl_surface *
-getWlSurface(QPlatformNativeInterface *native, QWindow *window)
+static void
+registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
+ const char *interface, uint32_t version)
{
- void *surf = native->nativeResourceForWindow("surface", window);
- return static_cast<struct ::wl_surface *>(surf);
+ struct display *d = static_cast<struct display *>(data);
+
+ if (strcmp(interface, "wl_compositor") == 0) {
+ d->wl_compositor =
+ static_cast<struct wl_compositor *>(wl_registry_bind(registry, id,
+ &wl_compositor_interface, 1));
+ } else if (strcmp(interface, "xdg_wm_base") == 0) {
+ d->wm_base = static_cast<struct xdg_wm_base *>(wl_registry_bind(registry,
+ id, &xdg_wm_base_interface, 1));
+ xdg_wm_base_add_listener(d->wm_base, &xdg_wm_base_listener, d);
+ } else if (strcmp(interface, "wl_shm") == 0) {
+ d->shm = static_cast<struct wl_shm *>(wl_registry_bind(registry,
+ id, &wl_shm_interface, 1));
+ wl_shm_add_listener(d->shm, &shm_listener, d);
+ } else if (strcmp(interface, "agl_shell_desktop") == 0) {
+ d->agl_shell_desktop = static_cast<struct agl_shell_desktop *>(wl_registry_bind(registry, id,
+ &agl_shell_desktop_interface, 1));
+ /* as an example, show how to register for events from the compositor */
+ agl_shell_desktop_add_listener(d->agl_shell_desktop,
+ &agl_shell_desktop_listener, d);
+ } else if (strcmp(interface, "wl_output") == 0) {
+ d->wl_output = static_cast<struct wl_output *>(wl_registry_bind(registry, id,
+ &wl_output_interface, 1));
+ wl_output_add_listener(d->wl_output, &output_listener, d);
+ }
}
+static void
+registry_handle_global_remove(void *data, struct wl_registry *reg, uint32_t id)
+{
+ (void) data;
+ (void) reg;
+ (void) id;
+}
+
+static const struct wl_registry_listener registry_listener = {
+ registry_handle_global,
+ registry_handle_global_remove,
+};
+
static void
error_cb(GstBus *bus, GstMessage *msg, gpointer user_data)
{
- struct cluster_receiver_data *d = static_cast<struct cluster_receiver_data *>(user_data);
+ struct cluster_receiver_data *d =
+ static_cast<struct cluster_receiver_data *>(user_data);
gchar *debug = NULL;
GError *err = NULL;
@@ -98,31 +549,20 @@ error_cb(GstBus *bus, GstMessage *msg, gpointer user_data)
static GstBusSyncReply
bus_sync_handler(GstBus *bus, GstMessage *message, gpointer user_data)
{
- struct cluster_receiver_data *d = static_cast<struct cluster_receiver_data *>(user_data);
+ struct cluster_receiver_data *d =
+ static_cast<struct cluster_receiver_data *>(user_data);
if (gst_is_wayland_display_handle_need_context_message(message)) {
GstContext *context;
- struct wl_display *display_handle;
-
- display_handle =
- static_cast<struct wl_display *>(
- d->native->nativeResourceForIntegration("display")
- );
+ struct wl_display *display_handle = d->window->display->wl_display;
context = gst_wayland_display_handle_context_new(display_handle);
-
d->wl_video = GST_WAYLAND_VIDEO(GST_MESSAGE_SRC(message));
gst_element_set_context(GST_ELEMENT(GST_MESSAGE_SRC(message)), context);
goto drop;
} else if (gst_is_video_overlay_prepare_window_handle_message(message)) {
- struct wl_surface *window_handle;
- QWindow *win = d->widget->windowHandle();
-
- if (!d->widget_has_buffer_mapped) {
- d->widget->setVisible(true);
- d->widget_has_buffer_mapped = true;
- }
+ struct wl_surface *window_handle = d->window->surface;
/* GST_MESSAGE_SRC(message) will be the overlay object that we
* have to use. This may be waylandsink, but it may also be
@@ -131,16 +571,15 @@ bus_sync_handler(GstBus *bus, GstMessage *message, gpointer user_data)
* window handle and render_rectangle after restarting playback
* and the actual window size is lost */
d->overlay = GST_VIDEO_OVERLAY(GST_MESSAGE_SRC(message));
- window_handle = getWlSurface(d->native, win);
g_print("setting window handle and size (%d x %d) w %d, h %d\n",
- d->window_data.x, d->window_data.y,
- d->window_data.width, d->window_data.height);
+ d->window->x, d->window->y,
+ d->window->width, d->window->height);
gst_video_overlay_set_window_handle(d->overlay, (guintptr) window_handle);
gst_video_overlay_set_render_rectangle(d->overlay,
- d->window_data.x, d->window_data.y,
- d->window_data.width, d->window_data.height);
+ d->window->x, d->window->y,
+ d->window->width, d->window->height);
goto drop;
}
@@ -152,40 +591,227 @@ drop:
return GST_BUS_DROP;
}
-int main(int argc, char *argv[])
+static void
+handle_xdg_surface_configure(void *data, struct xdg_surface *surface, uint32_t serial)
{
- int port = 0;
- std::string token;
- std::string role = "receiver";
- QString my_role = "receiver";
+ struct window *window = static_cast<struct window *>(data);
- struct cluster_receiver_data receiver_data = {};
- struct cluster_window_data window_data = {};
+ xdg_surface_ack_configure(surface, serial);
+
+ if (window->wait_for_configure) {
+ redraw(window, NULL, 0);
+ window->wait_for_configure = false;
+ }
+}
+
+static const struct xdg_surface_listener xdg_surface_listener = {
+ handle_xdg_surface_configure,
+};
+
+static void
+handle_xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
+ int32_t width, int32_t height,
+ struct wl_array *states)
+{
+ struct window *window = static_cast<struct window *>(data);
+ uint32_t *p;
+
+ window->fullscreen = 0;
+ window->maximized = 0;
+
+ // use our own macro as C++ can't typecast from (void *) directly
+ WL_ARRAY_FOR_EACH(p, states, uint32_t *) {
+ uint32_t state = *p;
+ switch (state) {
+ case XDG_TOPLEVEL_STATE_FULLSCREEN:
+ window->fullscreen = 1;
+ break;
+ case XDG_TOPLEVEL_STATE_MAXIMIZED:
+ window->maximized = 1;
+ break;
+ }
+ }
+
+ fprintf(stdout, "Got handle_xdg_toplevel_configure() "
+ "width %d, height %d, full %d, max %d\n", width, height,
+ window->fullscreen, window->maximized);
+
+ if (width > 0 && height > 0) {
+ if (!window->fullscreen && !window->maximized) {
+ window->width = width;
+ window->height = height;
+ }
+ window->width = width;
+ window->height = height;
+ } else if (!window->fullscreen && !window->maximized) {
+ if (width == 0)
+ window->width = WINDOW_WIDTH_SIZE;
+ else
+ window->width = width;
+
+ if (height == 0)
+ window->height = WINDOW_HEIGHT_SIZE;
+ else
+ window->height = height;
+ }
+
+ fprintf(stdout, "settting width %d, height %d\n",
+ window->width, window->height);
+}
+
+static void
+handle_xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
+{
+ running = 0;
+}
+
+static const struct xdg_toplevel_listener xdg_toplevel_listener = {
+ handle_xdg_toplevel_configure,
+ handle_xdg_toplevel_close,
+};
+
+static struct window *
+create_window(struct display *display, int width, int height, const char *app_id)
+{
+ struct window *window;
+
+ assert(display->wm_base != NULL);
+
+ window = static_cast<struct window *>(zalloc(sizeof(*window)));
+ if (!window)
+ return NULL;
- window_data.x = 0;
- window_data.y = 0;
+ window->callback = NULL;
+ window->display = display;
+ window->width = width;
+ window->height = height;
+ window->surface = wl_compositor_create_surface(display->wl_compositor);
- window_data.width = WINDOW_WIDTH_SIZE;
- window_data.height = WINDOW_HEIGHT_SIZE;
+ if (display->wm_base) {
+ window->xdg_surface =
+ xdg_wm_base_get_xdg_surface(display->wm_base, window->surface);
+ assert(window->xdg_surface);
- receiver_data.window_data = window_data;
+ xdg_surface_add_listener(window->xdg_surface,
+ &xdg_surface_listener, window);
+ window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface);
+ assert(window->xdg_toplevel);
+
+ xdg_toplevel_add_listener(window->xdg_toplevel,
+ &xdg_toplevel_listener, window);
+
+ xdg_toplevel_set_app_id(window->xdg_toplevel, app_id);
+
+ wl_surface_commit(window->surface);
+ window->wait_for_configure = true;
+ }
+
+ return window;
+}
+
+
+static void
+destroy_window(struct window *window)
+{
+ if (window->callback)
+ wl_callback_destroy(window->callback);
+
+ if (window->xdg_toplevel)
+ xdg_toplevel_destroy(window->xdg_toplevel);
+
+ if (window->xdg_surface)
+ xdg_surface_destroy(window->xdg_surface);
+
+ wl_surface_destroy(window->surface);
+ free(window);
+}
+
+static void
+signal_int(int sig, siginfo_t *si, void *_unused)
+{
+ running = 0;
+}
+
+static struct display *
+create_display(int argc, char *argv[])
+{
+ struct display *display;
+
+ display = static_cast<struct display *>(zalloc(sizeof(*display)));
+ if (display == NULL) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+ display->wl_display = wl_display_connect(NULL);
+ assert(display->wl_display);
+
+ display->has_xrgb = false;
+ display->wl_registry = wl_display_get_registry(display->wl_display);
+
+ wl_registry_add_listener(display->wl_registry, &registry_listener, display);
+ wl_display_roundtrip(display->wl_display);
+
+ if (display->shm == NULL) {
+ fprintf(stderr, "No wl_shm global\n");
+ return NULL;
+ }
+
+ if (display->agl_shell_desktop == NULL) {
+ fprintf(stderr, "No agl_shell extension present\n");
+ return NULL;
+ }
+
+ wl_display_roundtrip(display->wl_display);
+
+ if (!display->has_xrgb) {
+ fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n");
+ return NULL;
+ }
+
+ return display;
+}
+
+static void
+destroy_display(struct display *display)
+{
+ if (display->shm)
+ wl_shm_destroy(display->shm);
+
+ if (display->wm_base)
+ xdg_wm_base_destroy(display->wm_base);
+
+ if (display->agl_shell_desktop)
+ agl_shell_desktop_destroy(display->agl_shell_desktop);
+
+ if (display->wl_compositor)
+ wl_compositor_destroy(display->wl_compositor);
+
+ wl_registry_destroy(display->wl_registry);
+ wl_display_flush(display->wl_display);
+ wl_display_disconnect(display->wl_display);
+ free(display);
+}
+
+int main(int argc, char *argv[])
+{
+ int ret = 0;
+ struct sigaction sa;
+ struct cluster_receiver_data receiver_data = {};
+ struct display *display;
+ struct window *window;
+
+ std::string role = "receiver";
+
+ sa.sa_sigaction = signal_int;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESETHAND | SA_SIGINFO;
+ sigaction(SIGINT, &sa, NULL);
int gargc = 2;
char **gargv = (char**) malloc(2 * sizeof(char*));
gargv[0] = strdup(argv[0]);
gargv[1] = strdup("--gst-debug-level=2");
- try {
- port = std::stol(argv[1]);
- token = argv[2];
- } catch (const std::invalid_argument& e) {
- std::cerr << "Invalid argument" << std::endl;
- exit(1);
- } catch (const std::out_of_range& e) {
- std::cerr << "Port out of range" << std::endl;
- exit(1);
- }
-
std::string pipeline_str = \
"rtpbin name=rtpbin udpsrc "
"caps=\"application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=JPEG,payload=26\" "
@@ -196,37 +822,37 @@ int main(int argc, char *argv[])
std::cout << "Using pipeline: " << pipeline_str << std::endl;
- QApplication app(argc, argv);
- QPlatformNativeInterface *native = qApp->platformNativeInterface();
- receiver_data.native = native;
-
- // mark the application id -> my_role
- app.setDesktopFileName(my_role);
-
- SurfaceHandler handler(port, token, role);
-
- // we already have the app_id -> role this will set-up the x and y
- // position and a bounding box that will be used to clip out the
- // surface. Note, that in this example, the surface area is the same as
- // the bounding box
- handler.set_bounding_box(WINDOW_WIDTH_POS_X, WINDOW_WIDTH_POS_Y,
- 0, 0, WINDOW_WIDTH_SIZE, WINDOW_HEIGHT_SIZE);
-
- QWidget *widget = new QWidget;
- widget->resize(WINDOW_WIDTH_SIZE,
- WINDOW_HEIGHT_SIZE);
- widget->setVisible(false);
- // this is necessary to trigger a buffer attach on the xdg surface;
- // waylandsink will use that surface to create a sub-surface and will
- // perform a commit on the parent one; without doing a show() here
- // QtWayland will not attach the buffer to the surface, and the parent
- // surface will not be 'committed'; most likely this require more
- // fiddling as to keep the buffer attached but not displayed or use
- // some kind of local alpha to display that cluster is showing
- widget->show();
-
- receiver_data.widget = widget;
- receiver_data.widget_has_buffer_mapped = true;
+ display = create_display(argc, argv);
+ if (!display)
+ return -1;
+
+ // this will set-up the x and y position and a bounding box that will
+ // be used to clip out the surface. Note, that in this example, the
+ // surface area is the same as the bounding box.
+ agl_shell_desktop_set_app_property(display->agl_shell_desktop, role.c_str(),
+ AGL_SHELL_DESKTOP_APP_ROLE_POPUP,
+ WINDOW_WIDTH_POS_X, WINDOW_WIDTH_POS_Y,
+ 0, 0, WINDOW_WIDTH_SIZE, WINDOW_HEIGHT_SIZE,
+ display->wl_output);
+
+ // we use the role to set a correspondence between the top level
+ // surface and our application, with the previous call letting the
+ // compositor know that we're one and the same
+ window = create_window(display, WINDOW_WIDTH_SIZE,
+ WINDOW_HEIGHT_SIZE, role.c_str());
+
+ if (!window)
+ return -1;
+
+ window->display = display;
+ receiver_data.window = window;
+
+ /* Initialise damage to full surface, so the padding gets painted */
+ wl_surface_damage(window->surface, 0, 0,
+ window->width, window->height);
+
+ if (!window->wait_for_configure)
+ redraw(window, NULL, 0);
GstElement *pipeline = gst_parse_launch(pipeline_str.c_str(), NULL);
if (!pipeline) {
@@ -242,21 +868,15 @@ int main(int argc, char *argv[])
gst_bus_set_sync_handler(bus, bus_sync_handler, &receiver_data, NULL);
gst_object_unref(bus);
- // Start the pipeline, giving Qt the time to create everything; not
- // waiting here will cause both Qt and Gstreamer to race, running as
- // different threads. So this gives Qt sufficient time to create the
- // Widget, the surface the buffer and attach it to the surface. The
- // drawback is that it will displayed until the remote side start
- // sending frames to decode.
- std::cout << "wainting for Qt to be ready..." << std::endl;
- QTimer::singleShot(500, [pipeline](){
- gst_element_set_state(pipeline, GST_STATE_PLAYING);
- std::cout << "gstreamer pipeline running" << std::endl;
- });
+ gst_element_set_state(pipeline, GST_STATE_PLAYING);
+ std::cout << "gstreamer pipeline running" << std::endl;
// run the application
- int ret = app.exec();
- widget->hide();
+ while (running && ret != -1)
+ ret = wl_display_dispatch(display->wl_display);
+
+ destroy_window(window);
+ destroy_display(display);
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);
diff --git a/app/shell-desktop.cpp b/app/shell-desktop.cpp
deleted file mode 100644
index 1be7327..0000000
--- a/app/shell-desktop.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright © 2020 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-desktop.h"
-#include <qpa/qplatformnativeinterface.h>
-#include <stdio.h>
-
-static struct wl_output *
-getWlOutput(QScreen *screen)
-{
- QPlatformNativeInterface *native = qApp->platformNativeInterface();
-
- void *output = native->nativeResourceForScreen("output", screen);
- return static_cast<struct ::wl_output*>(output);
-}
-
-static void
-flush_connection(void)
-{
- QPlatformNativeInterface *native = qApp->platformNativeInterface();
- struct wl_display *wl = static_cast<struct wl_display *>(native->nativeResourceForIntegration("display"));
-
- wl_display_roundtrip(wl);
-}
-
-void Shell::activate_app(QWindow *win, const QString &app_id, const QString &app_data)
-{
- QScreen *screen = nullptr;
- struct wl_output *output;
-
- if (!win || !win->screen()) {
- screen = qApp->screens().first();
- } else {
- screen = win->screen();
- }
-
- if (!screen) {
- return;
- }
-
- output = getWlOutput(screen);
- agl_shell_desktop_activate_app(this->shell.get(),
- app_id.toStdString().c_str(),
- app_data.toStdString().c_str(), output);
-
-}
-
-void Shell::deactivate_app(const QString &app_id)
-{
- agl_shell_desktop_deactivate_app(this->shell.get(),
- app_id.toStdString().c_str());
-}
-
-void Shell::set_window_props(QWindow *win, const QString &app_id, uint32_t
- props, int x, int y, int bx, int by, int bwidth, int bheight)
-{
- QScreen *screen = nullptr;
- struct wl_output *output;
-
- if (!win || !win->screen()) {
- screen = qApp->screens().first();
- } else {
- screen = win->screen();
- }
-
- if (!screen) {
- return;
- }
-
- output = getWlOutput(screen);
- agl_shell_desktop_set_app_property(this->shell.get(),
- app_id.toStdString().c_str(),
- props, x, y, bx, by, bwidth, bheight, output);
-}
-
-void
-Shell::set_window_props(const QString &app_id, uint32_t props,
- int x, int y, int bx, int by, int bwidth, int bheight)
-{
- QScreen *screen;
- struct wl_output *output;
-
- screen = qApp->primaryScreen();
- if (!screen) {
- return;
- }
-
- output = getWlOutput(screen);
- agl_shell_desktop_set_app_property(this->shell.get(),
- app_id.toStdString().c_str(),
- props, x, y, bx, by, bwidth, bheight,
- output);
-}
diff --git a/app/shell-desktop.h b/app/shell-desktop.h
deleted file mode 100644
index 06da981..0000000
--- a/app/shell-desktop.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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 SHELLDESKTOP_H
-#define SHELLDESKTOP_H
-
-#include <QObject>
-#include <QString>
-#include <QScreen>
-#include <QWindow>
-#include <memory>
-
-#include <wayland-client.h>
-#include "agl-shell-desktop-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_desktop> shell;
-
-public:
- Shell(std::shared_ptr<struct agl_shell_desktop> shell, QObject *parent = nullptr) :
- QObject(parent), shell(shell)
- {}
-
-signals:
- // using Qobject::connect(), callins into qml
- void showOnScreen();
-
-public slots: // calls out of qml into CPP
- void activate_app(QWindow *win, const QString &app_id, const QString &app_data);
- void deactivate_app(const QString &app_id);
- void set_window_props(QWindow *win, const QString &app_id, uint32_t
- props, int x, int y, int bx, int by, int bwidth, int bheight);
-
- void set_window_props(const QString &app_id, uint32_t props,
- int x, int y,
- int bx, int by, int bwidth, int bheight);
-};
-
-#endif // SHELLDESKTOP_H
diff --git a/app/surface.cpp b/app/surface.cpp
deleted file mode 100644
index c0cd8ac..0000000
--- a/app/surface.cpp
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (c) 2017 Panasonic Corporation
- * Copyright (c) 2018 Konsulko Group
- *
- * 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 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 <cstdio>
-#include <cstdarg>
-#include "surface.hpp"
-#include "hmi-debug.h"
-
-#include <QGuiApplication>
-#include <QtGui/QGuiApplication>
-#include <qpa/qplatformnativeinterface.h>
-
-#include <QObject>
-#include <QString>
-#include <QScreen>
-#include <QWindow>
-
-#include "agl-shell-desktop-client-protocol.h"
-
-static void
-global_add(void *data, struct wl_registry *reg, uint32_t name,
- const char *interface, uint32_t version)
-{
- struct agl_shell_desktop **shell =
- static_cast<struct agl_shell_desktop **>(data);
-
- if (strcmp(interface, agl_shell_desktop_interface.name) == 0) {
- *shell = static_cast<struct agl_shell_desktop *>(
- wl_registry_bind(reg, name, &agl_shell_desktop_interface, version)
- );
- }
-}
-
-static void
-global_remove(void *data, struct wl_registry *reg, uint32_t id)
-{
- (void) data;
- (void) reg;
- (void) id;
-}
-
-static const struct wl_registry_listener registry_listener = {
- global_add,
- global_remove,
-};
-
-
-static void
-application_id_event(void *data, struct agl_shell_desktop *agl_shell_desktop,
- const char *app_id)
-{
-
-}
-
-static void
-application_id_state(void *data, struct agl_shell_desktop *agl_shell_desktop,
- const char *app_id, const char *app_data,
- uint32_t app_state, uint32_t app_role)
-{
- (void) app_data;
- (void) agl_shell_desktop;
- (void) app_id;
- (void) app_state;
- (void) app_role;
-}
-
-static const struct agl_shell_desktop_listener agl_shell_desk_listener = {
- application_id_event,
- application_id_state,
-};
-
-static struct agl_shell_desktop *
-register_agl_shell_desktop(QPlatformNativeInterface *native)
-{
- struct wl_display *wl;
- struct wl_registry *registry;
- struct agl_shell_desktop *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;
-}
-
-SurfaceHandler::SurfaceHandler(const int port, const std::string &token, const std::string &role)
-{
- m_port = port;
- m_token = token;
- m_role = role;
-
- if (init_agl_shell()) {
- exit(1);
- }
-
- agl_shell_desktop_add_listener(shell, &agl_shell_desk_listener, this);
-}
-
-int
-SurfaceHandler::init_agl_shell(void)
-{
- QPlatformNativeInterface *native = qApp->platformNativeInterface();
- shell = register_agl_shell_desktop(native);
- if (!shell) {
- return -1;
- }
-
- std::shared_ptr<struct agl_shell_desktop>
- agl_shell{shell, agl_shell_desktop_destroy};
-
- aglShell = new Shell(agl_shell, nullptr);
-
- return 0;
-}
-
-void
-SurfaceHandler::set_bounding_box(int x, int y, int bx, int by, int width, int height)
-{
- QString app_id = QString::fromUtf8(m_role.c_str(), -1);
- aglShell->set_window_props(app_id, AGL_SHELL_DESKTOP_APP_ROLE_POPUP,
- x, y, bx, by, width, height);
-}
diff --git a/app/surface.hpp b/app/surface.hpp
deleted file mode 100644
index 82b5c86..0000000
--- a/app/surface.hpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2017 Panasonic Corporation
- * Copyright (c) 2018 Konsulko Group
- *
- * 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 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 SURFACE_HPP
-#define SURFACE_HPP
-
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-#include <vector>
-#include <map>
-#include <algorithm>
-
-#include "shell-desktop.h"
-
-class SurfaceHandler
-{
-public:
- SurfaceHandler(const int port, const std::string &token, const std::string &role);
- void set_bounding_box(int x, int y, int bx, int by, int width, int height);
-
-private:
- int m_port;
- std::string m_token;
- std::string m_role;
-
- int init_agl_shell(void);
-
- struct agl_shell_desktop *shell;
- Shell *aglShell;
-};
-
-#endif // SURFACE_HPP
diff --git a/app/zalloc.h b/app/zalloc.h
new file mode 100644
index 0000000..9a98230
--- /dev/null
+++ b/app/zalloc.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2013 Red Hat, Inc.
+ *
+ * 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 WESTON_ZALLOC_H
+#define WESTON_ZALLOC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+
+static inline void *
+zalloc(size_t size)
+{
+ return calloc(1, size);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WESTON_ZALLOC_H */
diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake
index 2a3c9d7..b85fe6e 100644
--- a/conf.d/cmake/config.cmake
+++ b/conf.d/cmake/config.cmake
@@ -1,9 +1,11 @@
###########################################################################
# Copyright 2015-2018 IoT.bzh
# Copyright 2018,2019 Konsulko Group
+# Copyright 2020 Collabora Ltd.
#
# author: Fulup Ar Foll <fulup@iot.bzh>
# cluster-receiver: Scott Murray <scott.murray@konsulko.com>
+# xdg-cluster-receiver: Marius Vlad <marius.vlad@collabora.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -20,15 +22,15 @@
# Project Info
# ------------------
-set(PROJECT_NAME cluster-receiver)
+set(PROJECT_NAME xdg-cluster-receiver)
set(PROJECT_PRETTY_NAME "Cluster Receiver Demo")
set(PROJECT_DESCRIPTION "Cluster receiver demo application")
-set(PROJECT_URL "https://gerrit.automotivelinux.org/gerrit/apps/agl-cluster-demo-receiver")
+set(PROJECT_URL "https://gerrit.automotivelinux.org/gerrit/app/xdg-cluster-demo-receiver.git")
set(PROJECT_VERSION "1.0")
set(PROJECT_ICON "icon.png")
-set(PROJECT_AUTHOR "Scott Murray")
-set(PROJECT_AUTHOR_MAIL "scott.murray@konsulko.com")
-set(PROJECT_LICENSE "APL2.0")
+set(PROJECT_AUTHOR "Marius Vlad")
+set(PROJECT_AUTHOR_MAIL "marius.vlad@collabora.com")
+set(PROJECT_LICENSE "MIT")
set(PROJECT_LANGUAGES "CXX")
# Where are stored the project configuration files
@@ -155,7 +157,7 @@ set(WIDGET_TYPE application/vnd.agl.native)
# This is the file that will be executed, loaded,
# at launch time by the application framework.
#
-set(WIDGET_ENTRY_POINT bin/cluster-receiver)
+set(WIDGET_ENTRY_POINT bin/xdg-cluster-receiver)
# Optional dependencies order
# ---------------------------