diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2b01059..62f4b19 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,408 +1,411 @@
cmake_minimum_required(VERSION 3.3)
find_package(ECM 5.40.0 REQUIRED NO_MODULE)
set(CMAKE_CXX_STANDARD 14)
set(QT_MIN_VERSION "5.10.0")
if(POLICY CMP0071)
cmake_policy(SET CMP0071 NEW)
endif()
project(kaidan)
set(APPLICATION_ID "im.kaidan.kaidan")
set(APPLICATION_NAME "kaidan")
set(APPLICATION_DISPLAY_NAME "Kaidan")
if(UBUNTU_TOUCH)
set(APPLICATION_NAME "${APPLICATION_ID}")
endif()
set(VERSION_STRING "0.5.0-dev")
set(DEVELOPMENT_BUILD TRUE)
set(ANDROID_VERSION_CODE 6)
# CMake options
option(I18N "Enable i18n support" FALSE)
option(STATIC_BUILD "Build Kaidan statically")
option(APPIMAGE "Build Kaidan as AppImage (will only work in the appimage script)" FALSE)
option(UBUNTU_TOUCH "Building an Ubuntu Touch click (internal use only!)" FALSE)
option(CLICK_ARCH "Architecture that will be used in the click's manifest")
option(CLICK_DATE "Date used in the version number in the click's manifest")
option(QUICK_COMPILER "Use QtQuick compiler to improve performance" FALSE)
option(USE_KNOTIFICATIONS "Use KNotifications for displaying notifications" TRUE)
option(BUNDLE_ICONS "Bundle breeze icons" FALSE)
# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Instruct CMake to run moc, uic and rcc automatically when needed.
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
set(AUTOMOC_MOC_OPTIONS -Muri=${APPLICATION_ID})
#
# Dependecies
#
# CMake module path
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR})
# CMake modules include
include(KDEInstallDirs)
include(KDECompilerSettings NO_POLICY_SCOPE)
include(KDECMakeSettings)
include(ECMInstallIcons)
include(FeatureSummary)
kde_enable_exceptions()
# Find packages
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED NO_MODULE COMPONENTS Core Qml Quick Svg Sql QuickControls2 Xml Multimedia Positioning Location)
find_package(KF5Kirigami2 REQUIRED)
find_package(ZXing REQUIRED COMPONENTS Core)
find_package(QXmpp 1.0.0 REQUIRED)
# Optional QtQuickCompiler
if(QUICK_COMPILER)
find_package(Qt5QuickCompiler)
set_package_properties(Qt5QuickCompiler PROPERTIES
DESCRIPTION "Compile QML at build time"
TYPE OPTIONAL
)
endif()
if(USE_KNOTIFICATIONS)
find_package(KF5Notifications REQUIRED)
set(__KF5Notifications_LIBRARIES KF5::Notifications)
add_definitions(-DHAVE_KNOTIFICATIONS)
endif()
# Optional QWidget style integration (not on mobile)
if(NOT UBUNTU_TOUCH AND NOT ANDROID AND NOT IOS)
find_package(Qt5Widgets)
set_package_properties(Qt5Widgets PROPERTIES
DESCRIPTION "Integration with QWidget based desktop styles"
TYPE OPTIONAL
)
endif()
# Platform-specific
if(Qt5Widgets_FOUND)
add_definitions(-DHAVE_QWIDGETS -DQAPPLICATION_CLASS=QApplication)
set(__Qt5Widgets_LIBRARIES Qt5::Widgets)
else()
add_definitions(-DQAPPLICATION_CLASS=QGuiApplication)
endif()
if(ANDROID)
find_package(Qt5 REQUIRED COMPONENTS AndroidExtras)
endif()
if(ANDROID OR WIN32)
find_package(PkgConfig REQUIRED)
pkg_search_module(OPENSSL REQUIRED openssl IMPORTED_TARGET)
message(STATUS "Using OpenSSL ${OPENSSL_VERSION}")
endif()
#
# Load submodules
#
# Main kaidan sources
include("${CMAKE_SOURCE_DIR}/src/CMakeLists.txt")
# I18n support
if(I18N)
include("${CMAKE_SOURCE_DIR}/i18n/CMakeLists.txt")
endif()
#
# Sources / Resources
#
# Include bundled icons on Ubuntu Touch, Android, Windows, macOS and iOS
if(BUNDLE_ICONS OR UBUNTU_TOUCH OR ANDROID OR WIN32 OR APPLE)
set(KAIDAN_ICONS_QRC kirigami-icons.qrc)
endif()
# Bundle images on Android, Windows, macOS and iOS
if(ANDROID OR WIN32 OR APPLE)
set(KAIDAN_IMAGES_QRC "data/images/images.qrc")
endif()
# Set app icon
if(APPLE)
set(KAIDAN_ICNS "${CMAKE_SOURCE_DIR}/misc/macos/kaidan.icns")
set_source_files_properties(${KAIDAN_ICNS} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
elseif(WIN32)
include(ECMAddAppIcon)
file(GLOB WIN_ICONS_SRCS "${CMAKE_SOURCE_DIR}/misc/windows/*kaidan.png")
message(STATUS ${WIN_ICONS_SRCS})
ecm_add_app_icon(KAIDAN_ICNS ICONS ${WIN_ICONS_SRCS})
message(STATUS ${KAIDAN_ICNS})
endif()
if(QUICK_COMPILER)
qtquick_compiler_add_resources(KAIDAN_QML_QRC kaidan_qml.qrc)
else()
qt5_add_resources(KAIDAN_QML_QRC kaidan_qml.qrc)
endif()
add_executable(${PROJECT_NAME}
MACOSX_BUNDLE
WIN32
${KAIDAN_ICNS}
${KAIDAN_SOURCES}
${KAIDAN_QML_QRC}
${KAIDAN_ICONS_QRC} # only set if enabled
${KAIDAN_IMAGES_QRC} #
${I18N_QRC_CPP} #
)
target_link_libraries(${PROJECT_NAME}
Qt5::Core
Qt5::Sql
Qt5::Qml
Qt5::Quick
Qt5::Svg
Qt5::Network
Qt5::Xml
Qt5::Multimedia
Qt5::Positioning
Qt5::Location
ZXing::Core
QXmpp::QXmpp
${__Qt5Widgets_LIBRARIES}
${__KF5Notifications_LIBRARIES}
)
if(ANDROID OR WIN32 OR IOS)
target_link_libraries(${PROJECT_NAME} Qt5::QuickControls2 KF5::Kirigami2)
endif()
if(ANDROID OR WIN32)
target_link_libraries(${PROJECT_NAME} PkgConfig::OPENSSL)
endif()
if(ANDROID)
target_link_libraries(${PROJECT_NAME} Qt5::AndroidExtras)
endif()
if(STATIC_BUILD)
add_definitions(-DQXMPP_BUILD)
find_package(Perl REQUIRED)
set(STATIC_DEPENDENCIES_CMAKE_FILE "${CMAKE_BINARY_DIR}/QtStaticDependencies.cmake")
if(EXISTS ${STATIC_DEPENDENCIES_CMAKE_FILE})
file(REMOVE ${STATIC_DEPENDENCIES_CMAKE_FILE})
endif()
get_target_property(QT_LIBDIR Qt5::Core LOCATION)
get_filename_component(QT_LIBDIR ${QT_LIBDIR} DIRECTORY)
macro(CONVERT_PRL_LIBS_TO_CMAKE _qt_component)
if(TARGET Qt5::${_qt_component})
get_target_property(_lib_location Qt5::${_qt_component} LOCATION)
execute_process(COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/utils/convert-prl-libs-to-cmake.pl
--lib ${_lib_location}
--libdir ${QT_LIBDIR}
--out ${STATIC_DEPENDENCIES_CMAKE_FILE}
--component ${_qt_component}
--compiler ${CMAKE_CXX_COMPILER_ID}
)
endif()
endmacro()
link_directories(${_qt5_install_prefix}/../)
foreach(qt_module Gui Quick QuickControls2 Network Qml Svg Sql QSQLiteDriverPlugin
QJpegPlugin QGifPlugin QSvgPlugin QSvgIconPlugin QICOPlugin QGenericEnginePlugin
QLocalClientConnectionFactory QTcpServerConnectionFactory)
CONVERT_PRL_LIBS_TO_CMAKE(${qt_module})
endforeach()
if(WIN32)
CONVERT_PRL_LIBS_TO_CMAKE(QWindowsIntegrationPlugin)
elseif(IOS)
foreach(qt_module QIOSIntegrationPlugin QMacHeifPlugin QMacJp2Plugin
QICNSPlugin QTgaPlugin QTiffPlugin QWbmpPlugin QWebpPlugin)
CONVERT_PRL_LIBS_TO_CMAKE(${qt_module})
endforeach()
endif()
if(NOT EXISTS ${STATIC_DEPENDENCIES_CMAKE_FILE})
message(FATAL_ERROR "Unable to find ${STATIC_DEPENDENCIES_CMAKE_FILE}")
endif()
include(${STATIC_DEPENDENCIES_CMAKE_FILE})
set(QT_QML_PATH ${_qt5Quick_install_prefix})
find_library(KIRIGAMI_PLUGIN kirigamiplugin PATHS ${Kirigami2_INSTALL_PREFIX}/${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2)
find_library(QUICK_PLUGIN qtquick2plugin PATHS ${QT_QML_PATH}/qml/QtQuick.2)
find_library(LABS_PLATFORM_PLUGIN qtlabsplatformplugin PATHS ${QT_QML_PATH}/qml/Qt/labs/platform)
find_library(GRAPHEFFECTS_PLUGIN qtgraphicaleffectsplugin PATHS ${QT_QML_PATH}/qml/QtGraphicalEffects)
find_library(GRAPHEFFECTS_PRIVATE_PLUGIN qtgraphicaleffectsprivate PATHS ${QT_QML_PATH}/qml/QtGraphicalEffects/private)
find_library(QQC2_PLUGIN qtquickcontrols2plugin PATHS ${QT_QML_PATH}/qml/QtQuick/Controls.2)
find_library(QQC2_MATERIAL_PLUGIN qtquickcontrols2materialstyleplugin PATHS ${QT_QML_PATH}/qml/QtQuick/Controls.2/Material)
find_library(QQC2_UNIVERSAL_PLUGIN qtquickcontrols2universalstyleplugin PATHS ${QT_QML_PATH}/qml/QtQuick/Controls.2/Universal)
find_library(QLAYOUTS_PLUGIN qquicklayoutsplugin PATHS ${QT_QML_PATH}/qml/QtQuick/Layouts)
find_library(QWINDOW_PLUGIN windowplugin PATHS ${QT_QML_PATH}/qml/QtQuick/Window.2)
find_library(QSHAPES_PLUGIN qmlshapesplugin PATHS ${QT_QML_PATH}/qml/QtQuick/Shapes)
find_library(QUICKSHAPES Qt5QuickShapes PATHS ${QT_LIBDIR})
find_library(QTEMPLATES_PLUGIN qtquicktemplates2plugin PATHS ${QT_QML_PATH}/qml/QtQuick/Templates.2)
find_library(QMODELS_PLUGIN modelsplugin PATHS ${QT_QML_PATH}/qml/QtQml/Models.2)
target_link_libraries(${PROJECT_NAME}
${plugin_libs}
Qt5::QSQLiteDriverPlugin
Qt5::QJpegPlugin
Qt5::QGifPlugin
Qt5::QSvgPlugin
Qt5::QSvgIconPlugin
Qt5::QICOPlugin
Qt5::QGenericEnginePlugin
Qt5::QLocalClientConnectionFactory
Qt5::QTcpServerConnectionFactory
${KIRIGAMI_PLUGIN}
${QUICK_PLUGIN}
${LABS_PLATFORM_PLUGIN}
${GRAPHEFFECTS_PLUGIN}
${GRAPHEFFECTS_PRIVATE_PLUGIN}
${QQC2_PLUGIN}
${QQC2_MATERIAL_PLUGIN}
${QQC2_UNIVERSAL_PLUGIN}
${QLAYOUTS_PLUGIN}
${QWINDOW_PLUGIN}
${QSHAPES_PLUGIN}
${QUICKSHAPES}
${QTEMPLATES_PLUGIN}
${QMODELS_PLUGIN}
${__Qt5Widgets_LIBRARIES}
)
if(WIN32)
target_link_libraries(${PROJECT_NAME}
Qt5::QWindowsIntegrationPlugin
)
elseif(IOS)
target_link_libraries(${PROJECT_NAME}
Qt5::QIOSIntegrationPlugin
Qt5::QMacHeifPlugin
Qt5::QMacJp2Plugin
Qt5::QICNSPlugin
Qt5::QTgaPlugin
Qt5::QTiffPlugin
Qt5::QWbmpPlugin
Qt5::QWebpPlugin
)
endif()
endif()
# Set a custom plist file for the app bundle
if(APPLE)
if(IOS)
set_target_properties(${PROJECT_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/misc/ios/Info.plist)
else()
set_target_properties(${PROJECT_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/misc/macos/Info.plist)
endif()
endif()
#
# Global C++ variables
#
# iOS-specific linker flags
if(IOS)
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} "-Wl,-e,_qt_main_wrapper -u _qt_registerPlatformPlugin")
endif()
if(UBUNTU_TOUCH)
set(KAIDAN_COMPILE_DEFINITIONS UBUNTU_TOUCH=True)
elseif(APPIMAGE)
- set(KAIDAN_COMPILE_DEFINITIONS APPIMAGE=True)
+ set(KAIDAN_COMPILE_DEFINITIONS
+ APPIMAGE=True
+ TARGET_GSTREAMER_PLUGINS="${TARGET_GSTREAMER_PLUGINS}"
+ )
endif()
if(STATIC_BUILD)
set(KAIDAN_COMPILE_DEFINITIONS
STATIC_BUILD=True
${KAIDAN_COMPILE_DEFINITIONS}
)
endif()
target_compile_definitions(${PROJECT_NAME} PRIVATE
DEBUG_SOURCE_PATH="${CMAKE_SOURCE_DIR}"
VERSION_STRING="${VERSION_STRING}"
APPLICATION_ID="${APPLICATION_ID}"
APPLICATION_NAME="${APPLICATION_NAME}"
APPLICATION_DISPLAY_NAME="${APPLICATION_DISPLAY_NAME}"
${KAIDAN_COMPILE_DEFINITIONS}
)
#
# Install Kaidan
#
if(ANDROID)
configure_file(${CMAKE_SOURCE_DIR}/misc/android/AndroidManifest.xml.in
${CMAKE_SOURCE_DIR}/misc/android/AndroidManifest.xml)
endif()
if(UBUNTU_TOUCH AND CLICK_ARCH)
set(CLICK_VERSION ${VERSION_STRING})
if(DEVELOPMENT_BUILD)
set(CLICK_VERSION "${CLICK_VERSION}.${CLICK_DATE}")
endif()
# will replace ${CLICK_ARCH} with its value
configure_file(${CMAKE_SOURCE_DIR}/misc/ubuntu-touch/manifest.json.in
${CMAKE_SOURCE_DIR}/misc/ubuntu-touch/manifest.json)
# install kaidan binary
install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/bin/${PROJECT_NAME}
DESTINATION ${CMAKE_INSTALL_PREFIX}
)
# install kaidan media
install(DIRECTORY "data/images"
DESTINATION "${CMAKE_INSTALL_FULL_DATADIR}/${APPLICATION_ID}"
)
# install icon
install(FILES "misc/kaidan.svg" "misc/ubuntu-touch/apparmor.json"
"misc/ubuntu-touch/kaidan.desktop" "misc/ubuntu-touch/manifest.json"
DESTINATION "${CMAKE_INSTALL_PREFIX}"
)
elseif(UNIX AND NOT APPLE)
# install kaidan binary
install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/bin/${PROJECT_NAME}
DESTINATION ${CMAKE_INSTALL_FULL_BINDIR}
)
# install kaidan media
install(DIRECTORY "data/images"
DESTINATION "${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME}"
)
# install icon (scalable + 128x)
install(FILES "misc/kaidan.svg"
DESTINATION "${CMAKE_INSTALL_FULL_DATADIR}/icons/hicolor/scalable/apps"
)
install(FILES "misc/kaidan-128x128.png"
DESTINATION "${CMAKE_INSTALL_FULL_DATADIR}/icons/hicolor/128x128/apps"
RENAME "kaidan.png"
)
# install desktop file
install(FILES "misc/kaidan.desktop"
DESTINATION "${KDE_INSTALL_APPDIR}"
)
# install metainfo
install(FILES "misc/metadata.xml"
DESTINATION "${KDE_INSTALL_METAINFODIR}"
RENAME "im.kaidan.kaidan.appdata.xml"
)
endif()
# KNotifications
if(USE_KNOTIFICATIONS)
install(FILES misc/kaidan.notifyrc DESTINATION ${KNOTIFYRC_INSTALL_DIR})
endif()
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/src/main.cpp b/src/main.cpp
index 546565f..57abdf4 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,355 +1,386 @@
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2016-2019 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kaidan. If not, see .
*/
// Qt
#include
#include
#include
+#include
#include
#include
#include
#include
#include
#include
+#include
#include
// QXmpp
#include "qxmpp-exts/QXmppUploadManager.h"
#include
// Kaidan
#include "AvatarFileStorage.h"
#include "EmojiModel.h"
#include "Enums.h"
#include "Globals.h"
#include "Kaidan.h"
#include "Message.h"
#include "MessageModel.h"
#include "PresenceCache.h"
#include "QmlUtils.h"
#include "RosterModel.h"
#include "RosterFilterProxyModel.h"
#include "StatusBar.h"
#include "UploadManager.h"
#include "EmojiModel.h"
#include "Utils.h"
#include "QrCodeScannerFilter.h"
#include "VCardModel.h"
#include "CameraModel.h"
#include "AudioDeviceModel.h"
#include "MediaSettingModel.h"
#include "MediaUtils.h"
#include "MediaRecorder.h"
#ifdef STATIC_BUILD
#include "static_plugins.h"
#endif
#ifndef QAPPLICATION_CLASS
#define QAPPLICATION_CLASS QApplication
#endif
#include QT_STRINGIFY(QAPPLICATION_CLASS)
#if !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID)
// SingleApplication (Qt5 replacement for QtSingleApplication)
#include "singleapp/singleapplication.h"
#endif
#ifdef STATIC_BUILD
#define KIRIGAMI_BUILD_TYPE_STATIC
#include "./3rdparty/kirigami/src/kirigamiplugin.h"
#endif
#ifdef Q_OS_ANDROID
#include
#endif
#ifdef Q_OS_WIN
#include
#endif
enum CommandLineParseResult {
CommandLineOk,
CommandLineError,
CommandLineVersionRequested,
CommandLineHelpRequested
};
CommandLineParseResult parseCommandLine(QCommandLineParser &parser, QString *errorMessage)
{
// application description
parser.setApplicationDescription(QString(APPLICATION_DISPLAY_NAME) +
" - " + QString(APPLICATION_DESCRIPTION));
// add all possible arguments
QCommandLineOption helpOption = parser.addHelpOption();
QCommandLineOption versionOption = parser.addVersionOption();
parser.addOption({"disable-xml-log", "Disable output of full XMPP XML stream."});
parser.addOption({{"m", "multiple"}, "Allow multiple instances to be started."});
parser.addPositionalArgument("xmpp-uri", "An XMPP-URI to open (i.e. join a chat).",
"[xmpp-uri]");
// parse arguments
if (!parser.parse(QGuiApplication::arguments())) {
*errorMessage = parser.errorText();
return CommandLineError;
}
// check for special cases
if (parser.isSet(versionOption))
return CommandLineVersionRequested;
if (parser.isSet(helpOption))
return CommandLineHelpRequested;
// if nothing special happened, return OK
return CommandLineOk;
}
Q_DECL_EXPORT int main(int argc, char *argv[])
{
#ifdef Q_OS_WIN
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
}
#endif
// initialize random generator
qsrand(time(nullptr));
//
// App
//
#ifdef UBUNTU_TOUCH
qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "true");
qputenv("QT_QUICK_CONTROLS_MOBILE", "true");
#endif
#ifdef APPIMAGE
qputenv("OPENSSL_CONF", "");
#endif
// name, display name, description
QGuiApplication::setApplicationName(APPLICATION_NAME);
QGuiApplication::setApplicationDisplayName(APPLICATION_DISPLAY_NAME);
QGuiApplication::setApplicationVersion(VERSION_STRING);
// attributes
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
// create a qt app
#if defined(Q_OS_IOS) || defined(Q_OS_ANDROID)
QGuiApplication app(argc, argv);
#else
SingleApplication app(argc, argv, true);
#endif
+#ifdef APPIMAGE
+ QFileInfo executable(QCoreApplication::applicationFilePath());
+
+ if (executable.isSymLink()) {
+ executable.setFile(executable.symLinkTarget());
+ }
+
+ QString gstreamerPluginsPath;
+
+ // Try to use deployed plugins if any...
+#if defined(TARGET_GSTREAMER_PLUGINS)
+ gstreamerPluginsPath = QString::fromLocal8Bit(TARGET_GSTREAMER_PLUGINS);
+
+ if (!gstreamerPluginsPath.isEmpty()) {
+ gstreamerPluginsPath = QDir::cleanPath(QString::fromLatin1("%1/../..%2")
+ .arg(executable.absolutePath(), gstreamerPluginsPath));
+ }
+#else
+ qFatal("Please provide the unified directory containing the gstreamer plugins and gst-plugin-scanner.");
+#endif
+
+#if defined(QT_DEBUG)
+ qputenv("GST_DEBUG", "ERROR:5,WARNING:5,INFO:5,DEBUG:5,LOG:5");
+#endif
+ qputenv("GST_PLUGIN_PATH_1_0", QByteArray());
+ qputenv("GST_PLUGIN_SYSTEM_PATH_1_0", gstreamerPluginsPath.toLocal8Bit());
+ qputenv("GST_PLUGIN_SCANNER_1_0", QString::fromLatin1("%1/gst-plugin-scanner").arg(gstreamerPluginsPath).toLocal8Bit());
+#endif
+
// register qMetaTypes
qRegisterMetaType("RosterItem");
qRegisterMetaType("RosterModel*");
qRegisterMetaType("Message");
qRegisterMetaType("MessageModel*");
qRegisterMetaType("AvatarFileStorage*");
qRegisterMetaType("PresenceCache*");
qRegisterMetaType("QXmppPresence");
qRegisterMetaType("Credentials");
qRegisterMetaType("Qt::ApplicationState");
qRegisterMetaType("QXmppClient::State");
qRegisterMetaType("MessageType");
qRegisterMetaType("DisconnectionReason");
qRegisterMetaType("TransferJob*");
qRegisterMetaType("QmlUtils*");
qRegisterMetaType>("QVector");
qRegisterMetaType>("QVector");
qRegisterMetaType>("QHash");
qRegisterMetaType>("std::function");
qRegisterMetaType>("std::function");
qRegisterMetaType("ClientWorker::Credentials");
qRegisterMetaType("QXmppVCardIq");
qRegisterMetaType();
qRegisterMetaType();
qRegisterMetaType();
qRegisterMetaType();
// qRegisterMetaType();
qRegisterMetaType();
qRegisterMetaType();
qRegisterMetaType();
// Enums for c++ member calls using enums
qRegisterMetaType();
qRegisterMetaType();
qRegisterMetaType();
qRegisterMetaType();
qRegisterMetaType();
qRegisterMetaType();
qRegisterMetaType();
qRegisterMetaType();
qRegisterMetaType();
qRegisterMetaType();
qRegisterMetaType();
qRegisterMetaType();
// Qt-Translator
QTranslator qtTranslator;
qtTranslator.load("qt_" + QLocale::system().name(),
QLibraryInfo::location(QLibraryInfo::TranslationsPath));
QCoreApplication::installTranslator(&qtTranslator);
// Kaidan-Translator
QTranslator kaidanTranslator;
// load the systems locale or none from resources
kaidanTranslator.load(QLocale::system().name(), ":/i18n");
QCoreApplication::installTranslator(&kaidanTranslator);
//
// Command line arguments
//
// create parser and add a description
QCommandLineParser parser;
// parse the arguments
QString commandLineErrorMessage;
switch (parseCommandLine(parser, &commandLineErrorMessage)) {
case CommandLineError:
qWarning() << commandLineErrorMessage;
return 1;
case CommandLineVersionRequested:
parser.showVersion();
return 0;
case CommandLineHelpRequested:
parser.showHelp();
return 0;
case CommandLineOk:
break;
}
#if !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID)
// check if another instance already runs
if (app.isSecondary() && !parser.isSet("multiple")) {
qDebug().noquote() << QString("Another instance of %1 is already running.")
.arg(APPLICATION_DISPLAY_NAME)
<< "You can enable multiple instances by specifying '--multiple'.";
// send a possible link to the primary instance
if (!parser.positionalArguments().isEmpty())
app.sendMessage(parser.positionalArguments().first().toUtf8());
return 0;
}
#endif
//
// Kaidan back-end
//
Kaidan kaidan(&app, !parser.isSet("disable-xml-log"));
#if !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID)
// receive messages from other instances of Kaidan
Kaidan::connect(&app, &SingleApplication::receivedMessage,
&kaidan, &Kaidan::receiveMessage);
#endif
// open the XMPP-URI/link (if given)
if (!parser.positionalArguments().isEmpty())
kaidan.addOpenUri(parser.positionalArguments().first());
//
// QML-GUI
//
if (QIcon::themeName().isEmpty()) {
QIcon::setThemeName("breeze");
}
QQmlApplicationEngine engine;
// QtQuickControls2 Style
if (qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE")) {
#ifdef Q_OS_WIN
const QString defaultStyle = QStringLiteral("Universal");
#else
const QString defaultStyle = QStringLiteral("Material");
#endif
qDebug() << "QT_QUICK_CONTROLS_STYLE not set, setting to" << defaultStyle;
qputenv("QT_QUICK_CONTROLS_STYLE", defaultStyle.toLatin1());
}
// QML type bindings
#ifdef STATIC_BUILD
KirigamiPlugin::getInstance().registerTypes();
#endif
qmlRegisterType("StatusBar", 0, 1, "StatusBar");
qmlRegisterType("EmojiModel", 0, 1, "EmojiModel");
qmlRegisterType("EmojiModel", 0, 1, "EmojiProxyModel");
qmlRegisterType(APPLICATION_ID, 1, 0, "QrCodeScannerFilter");
qmlRegisterType(APPLICATION_ID, 1, 0, "VCardModel");
qmlRegisterType(APPLICATION_ID, 1, 0, "RosterFilterProxyModel");
qmlRegisterType(APPLICATION_ID, 1, 0, "CameraModel");
qmlRegisterType(APPLICATION_ID, 1, 0, "AudioDeviceModel");
qmlRegisterType(APPLICATION_ID, 1, 0, "MediaSettingsContainerModel");
qmlRegisterType(APPLICATION_ID, 1, 0, "MediaSettingsResolutionModel");
qmlRegisterType(APPLICATION_ID, 1, 0, "MediaSettingsQualityModel");
qmlRegisterType(APPLICATION_ID, 1, 0, "MediaSettingsImageCodecModel");
qmlRegisterType(APPLICATION_ID, 1, 0, "MediaSettingsAudioCodecModel");
qmlRegisterType(APPLICATION_ID, 1, 0, "MediaSettingsAudioSampleRateModel");
qmlRegisterType(APPLICATION_ID, 1, 0, "MediaSettingsVideoCodecModel");
qmlRegisterType(APPLICATION_ID, 1, 0, "MediaSettingsVideoFrameRateModel");
qmlRegisterType(APPLICATION_ID, 1, 0, "MediaRecorder");
qmlRegisterUncreatableType("EmojiModel", 0, 1, "QAbstractItemModel", "Used by proxy models");
qmlRegisterUncreatableType("EmojiModel", 0, 1, "Emoji", "Used by emoji models");
qmlRegisterUncreatableType(APPLICATION_ID, 1, 0, "TransferJob", "TransferJob type usable");
qmlRegisterUncreatableType(APPLICATION_ID, 1, 0, "QMimeType", "QMimeType type usable");
qmlRegisterUncreatableType(APPLICATION_ID, 1, 0, "CameraInfo", "CameraInfo type usable");
qmlRegisterUncreatableType(APPLICATION_ID, 1, 0, "AudioDeviceInfo", "AudioDeviceInfo type usable");
qmlRegisterUncreatableType(APPLICATION_ID, 1, 0, "MediaSettings", "MediaSettings type usable");
qmlRegisterUncreatableType(APPLICATION_ID, 1, 0, "CommonEncoderSettings", "CommonEncoderSettings type usable");
qmlRegisterUncreatableType(APPLICATION_ID, 1, 0, "ImageEncoderSettings", "ImageEncoderSettings type usable");
qmlRegisterUncreatableType(APPLICATION_ID, 1, 0, "AudioEncoderSettings", "AudioEncoderSettings type usable");
qmlRegisterUncreatableType(APPLICATION_ID, 1, 0, "VideoEncoderSettings", "VideoEncoderSettings type usable");
qmlRegisterUncreatableMetaObject(Enums::staticMetaObject, APPLICATION_ID,
1, 0, "Enums", "Can't create object; only enums defined!");
qmlRegisterSingletonType("MediaUtils", 0, 1, "MediaUtilsInstance", [](QQmlEngine *, QJSEngine *) {
QObject *instance = new MediaUtils(qApp);
return instance;
});
engine.rootContext()->setContextProperty("kaidan", &kaidan);
engine.load(QUrl("qrc:/qml/main.qml"));
if(engine.rootObjects().isEmpty())
return -1;
#ifdef Q_OS_ANDROID
QtAndroid::hideSplashScreen();
#endif
// enter qt main loop
return app.exec();
}
diff --git a/utils/build-linux-appimage.sh b/utils/build-linux-appimage.sh
index a0b0de2..d80b707 100755
--- a/utils/build-linux-appimage.sh
+++ b/utils/build-linux-appimage.sh
@@ -1,136 +1,184 @@
#!/bin/bash -e
# NOTE: To use this script, you need to set $QT_LINUX to your Qt for Linux installation
# Path to Qt installation
QT_LINUX=${QT_LINUX:-/usr}
echo Using Qt installation from $QT_LINUX
# Build type is one of:
# Debug, Release, RelWithDebInfo and MinSizeRel
BUILD_TYPE="${BUILD_TYPE:-Debug}"
+MAKEFLAGS="-j$(nproc)"
+
KAIDAN_SOURCES=$(dirname "$(readlink -f "${0}")")/..
echo "-- Starting $BUILD_TYPE build of Kaidan --"
echo "*****************************************"
echo "Fetching dependencies if required"
echo "*****************************************"
if [ ! -f "$KAIDAN_SOURCES/3rdparty/kirigami/.git" ] || [ ! -f "$KAIDAN_SOURCES/3rdparty/breeze-icons/.git" ]; then
echo "Cloning Kirigami and Breeze icons"
git submodule update --init
fi
if [ ! -e "$KAIDAN_SOURCES/3rdparty/qxmpp/.git" ]; then
echo "Cloning QXmpp"
git clone https://github.com/qxmpp-project/qxmpp.git 3rdparty/qxmpp
fi
cdnew() {
if [ -d "$1" ]; then
rm -rf "$1"
fi
mkdir $1
cd $1
}
join_by() {
local IFS="$1"
shift
echo "$*"
}
if [ ! -f "$KAIDAN_SOURCES/3rdparty/linuxdeployqt/squashfs-root/AppRun" ]; then
echo "Downloading linuxdeployqt"
wget --continue -P $KAIDAN_SOURCES/3rdparty/ https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage
chmod +x $KAIDAN_SOURCES/3rdparty/linuxdeployqt-continuous-x86_64.AppImage
echo "Extracting linuxdeployqt"
cdnew $KAIDAN_SOURCES/3rdparty/linuxdeployqt
$KAIDAN_SOURCES/3rdparty/linuxdeployqt-continuous-x86_64.AppImage --appimage-extract
cd $KAIDAN_SOURCES
fi
export QT_SELECT=qt5
+SOURCE_GSTREAMER_PLUGINS=$(find /usr/lib -name libgstcoreelements.so -exec dirname {} \;)
+SOURCE_GSTREAMER_PLUGINS_SCANNER=$(find /usr/lib -name gst-plugin-scanner)
+TARGET_GSTREAMER_PLUGINS="/usr/lib/$(basename "${SOURCE_GSTREAMER_PLUGINS}")"
+
+echo "*****************************************"
+echo "Found GStreamer plugins in: ${SOURCE_GSTREAMER_PLUGINS}"
+echo "Found GStreamer plugins scanner in: ${SOURCE_GSTREAMER_PLUGINS_SCANNER}"
+echo "Target GStreamer plugins in: ${TARGET_GSTREAMER_PLUGINS}"
+echo "*****************************************"
+
if [ ! -f "$KAIDAN_SOURCES/build/bin/kaidan" ]; then
echo "*****************************************"
echo "Building Kaidan"
echo "*****************************************"
{
cdnew $KAIDAN_SOURCES/build
cmake .. \
-DECM_DIR=/usr/share/ECM/cmake \
-DCMAKE_PREFIX_PATH=$QT_LINUX\; \
-DI18N=1 \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_INSTALL_PREFIX=/usr \
- -DQUICK_COMPILER=ON -DAPPIMAGE=ON -DBUNDLE_ICONS=ON
+ -DQUICK_COMPILER=ON -DAPPIMAGE=ON -DBUNDLE_ICONS=ON \
+ -DTARGET_GSTREAMER_PLUGINS="${TARGET_GSTREAMER_PLUGINS}"
- make -j$(nproc)
+ cmake --build .
}
fi
if [ ! -f "$KAIDAN_SOURCES/AppDir/usr/bin/kaidan" ]; then
echo "*****************************************"
echo "Installing Kaidan"
echo "*****************************************"
{
cd $KAIDAN_SOURCES/build
DESTDIR=$KAIDAN_SOURCES/AppDir cmake --build . --target install
}
fi
echo "*****************************************"
echo "Packing into AppImage"
echo "*****************************************"
{
cd $KAIDAN_SOURCES
export LD_LIBRARY_PATH=$QT_LINUX/lib/:$LD_LIBRARY_PATH
export PATH=$QT_LINUX/bin/:$PATH
# set qmake binary when using portable Qt; linuxdeployqt will find it on its
# own on global installs
if [ -f $QT_LINUX/bin/qmake ]; then
QMAKE_BINARY="-qmake=$QT_LINUX/bin/qmake"
fi
export VERSION="continuous"
extra_plugins=(
# Image formats
imageformats/libqsvg.so
imageformats/libqjpeg.so
imageformats/libqgif.so
imageformats/libqwebp.so
# Icon formats
iconengines/libqsvgicon.so
# QtMultimedia
audio/libqtaudio_alsa.so
audio/libqtmedia_pulse.so
playlistformats/libqtmultimedia_m3u.so
mediaservice/libgstaudiodecoder.so
mediaservice/libgstcamerabin.so
mediaservice/libgstmediacapture.so
mediaservice/libgstmediaplayer.so
# QtLocation
geoservices/libqtgeoservices_esri.so
geoservices/libqtgeoservices_itemsoverlay.so
geoservices/libqtgeoservices_mapbox.so
geoservices/libqtgeoservices_mapboxgl.so
geoservices/libqtgeoservices_nokia.so
geoservices/libqtgeoservices_osm.so
# QtPositioning
position/libqtposition_geoclue.so
position/libqtposition_positionpoll.so
position/libqtposition_serialnmea.so
)
- $KAIDAN_SOURCES/3rdparty/linuxdeployqt/squashfs-root/AppRun \
- $KAIDAN_SOURCES/AppDir/usr/share/applications/kaidan.desktop \
- -qmldir=$KAIDAN_SOURCES/src/qml/ \
- -qmlimport=/opt/kf5/lib/x86_64-linux-gnu/qml \
- -extra-plugins="$(join_by , "${extra_plugins[@]}")" \
- -appimage -no-copy-copyright-files \
- $QMAKE_BINARY
+ # We need gstreamer plugins copied first so that their dependencies get deployed as well.
+ APPDIR=${KAIDAN_SOURCES}/AppDir
+ COPY_GSTREAMER_SCANNER=0
+
+ if [ "$(dirname "${SOURCE_GSTREAMER_PLUGINS_SCANNER}")" != "${TARGET_GSTREAMER_PLUGINS}" ]; then
+ COPY_GSTREAMER_SCANNER=1
+ fi
+
+ TARGET_GSTREAMER_PLUGINS="${APPDIR}${TARGET_GSTREAMER_PLUGINS}"
+
+ if [ -d "${SOURCE_GSTREAMER_PLUGINS}" ]; then
+ echo "Copying ${SOURCE_GSTREAMER_PLUGINS}/libgst* to ${TARGET_GSTREAMER_PLUGINS}..."
+ mkdir -p "${TARGET_GSTREAMER_PLUGINS}"
+ cp -fr "${SOURCE_GSTREAMER_PLUGINS}/libgst"* "${TARGET_GSTREAMER_PLUGINS}"
+
+ if [ ${COPY_GSTREAMER_SCANNER} -eq 1 ]; then
+ echo "Copying ${SOURCE_GSTREAMER_PLUGINS_SCANNER} to ${TARGET_GSTREAMER_PLUGINS}..."
+ cp -f "${SOURCE_GSTREAMER_PLUGINS_SCANNER}" "${TARGET_GSTREAMER_PLUGINS}"
+ fi
+ else
+ echo "*****************************************"
+ echo "GStreamer plugins not found!!!"
+ echo "*****************************************"
+ exit 42
+ fi
+
+ # linuxdeployqt would only deploy existing binaries in AppDir if they are located in AppDir/usr/lib
+ # We do not want to put gstreamer plugins in this location, so they are not deployed.
+ # We then do need one -executable=file entry per plugin...
+ GSTREAMER_PLUGINS=
+ while IFS= read -r gstreamer_plugin; do
+ GSTREAMER_PLUGINS="${GSTREAMER_PLUGINS} -executable=\"${gstreamer_plugin}\""
+ done < <( find "${TARGET_GSTREAMER_PLUGINS}" -type f )
+
+ eval $KAIDAN_SOURCES/3rdparty/linuxdeployqt/squashfs-root/AppRun \
+ $APPDIR/usr/share/applications/kaidan.desktop \
+ -qmldir=$KAIDAN_SOURCES/src/qml/ \
+ -qmlimport=/opt/kf5/lib/x86_64-linux-gnu/qml \
+ -extra-plugins="$(join_by , "${extra_plugins[@]}")" \
+ ${GSTREAMER_PLUGINS} \
+ -appimage -no-copy-copyright-files \
+ $QMAKE_BINARY
}