From 4acb982e2d5b82ddfe603414665256323a25ad5e Mon Sep 17 00:00:00 2001 From: Mavridis Philippe Date: Thu, 1 Feb 2024 16:44:26 +0200 Subject: [PATCH] Initial commit Adds implementation of FileChooser interface Signed-off-by: Mavridis Philippe --- .gitignore | 4 + CMakeLists.txt | 54 ++++ ConfigureChecks.cmake | 23 ++ config.h.cmake | 6 + interfaces/CMakeLists.txt | 45 +++ interfaces/filechooser.xml | 32 +++ ...ktop.impl.portal.desktop.tde.service.cmake | 3 + interfaces/tde.portal | 4 + .../xdg-desktop-portal-tde.desktop.cmake | 5 + src/CMakeLists.txt | 42 +++ src/file_chooser_portal.cpp | 269 ++++++++++++++++++ src/file_chooser_portal.h | 114 ++++++++ src/main.cpp | 65 +++++ src/portal.cpp | 37 +++ src/portal.h | 48 ++++ src/portal_service.cpp | 75 +++++ src/portal_service.h | 47 +++ src/util.h | 126 ++++++++ 18 files changed, 999 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 ConfigureChecks.cmake create mode 100644 config.h.cmake create mode 100644 interfaces/CMakeLists.txt create mode 100644 interfaces/filechooser.xml create mode 100644 interfaces/org.freedesktop.impl.portal.desktop.tde.service.cmake create mode 100644 interfaces/tde.portal create mode 100644 interfaces/xdg-desktop-portal-tde.desktop.cmake create mode 100644 src/CMakeLists.txt create mode 100644 src/file_chooser_portal.cpp create mode 100644 src/file_chooser_portal.h create mode 100644 src/main.cpp create mode 100644 src/portal.cpp create mode 100644 src/portal.h create mode 100644 src/portal_service.cpp create mode 100644 src/portal_service.h create mode 100644 src/util.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9d4e3ee --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.~ +*~ +build +*.kdev* diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..93a23f2 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,54 @@ +################################################################################ +# XDG Desktop Portal implementation for TDE # +# Copyright (C) 2024 Mavridis Philippe # +# # +# Improvements and feedback are welcome! # +# This software is licensed under the terms of the GNU GPL v3 license. # +################################################################################ + +cmake_minimum_required( VERSION 3.1 ) + +project( xdg-desktop-portal-tde ) + +### Required modules ########################################################### +include( FindPkgConfig ) +include( CheckFunctionExists ) +include( CheckSymbolExists ) +include( CheckIncludeFile ) +include( CheckLibraryExists ) +include( CheckCSourceCompiles ) +include( CheckCXXSourceCompiles ) + +### TDE macros ################################################################# +include( TDEMacros ) +tde_set_project_version( ) + +include( TDESetupPaths ) +tde_setup_paths( ) + +### Optional support ########################################################### +# option( WITH_ALL_OPTIONS "Enable all optional support" OFF ) + +### Modules to build ########################################################### +option( BUILD_ALL "Build all" ON ) +option( BUILD_DOC "Build documentation" ${BUILD_ALL} ) +# option( BUILD_TRANSLATIONS "Build translations" ${BUILD_ALL} ) + +### Configure checks ########################################################### +include( ConfigureChecks.cmake ) + +### Compiler settings ########################################################## +add_definitions( -DHAVE_CONFIG_H ) + +set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TQT_CXX_FLAGS}" ) +set( CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined" ) +set( CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined" ) + +### Add subdirectories ######################################################### +add_subdirectory( src ) +add_subdirectory( interfaces ) +tde_conditional_add_project_docs( BUILD_DOC ) +# tde_conditional_add_project_translations( BUILD_TRANSLATIONS ) + +### Write configuration ######################################################## +configure_file( config.h.cmake config.h @ONLY ) \ No newline at end of file diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake new file mode 100644 index 0000000..8a2c606 --- /dev/null +++ b/ConfigureChecks.cmake @@ -0,0 +1,23 @@ +################################################################################ +# XDG Desktop Portal implementation for TDE # +# Copyright (C) 2024 Mavridis Philippe # +# # +# Improvements and feedback are welcome! # +# This software is licensed under the terms of the GNU GPL v3 license. # +################################################################################ + +find_package( TQt ) +find_package( TDE ) + +tde_setup_architecture_flags( ) + +include( TestBigEndian ) +test_big_endian( WORDS_BIGENDIAN ) + +tde_setup_largefiles( ) + +if( WITH_GCC_VISIBILITY ) + tde_setup_gcc_visibility( ) +endif( WITH_GCC_VISIBILITY ) + +tde_setup_dbus( dbus-1-tqt ) \ No newline at end of file diff --git a/config.h.cmake b/config.h.cmake new file mode 100644 index 0000000..2031ece --- /dev/null +++ b/config.h.cmake @@ -0,0 +1,6 @@ +// Defined if you have fvisibility and fvisibility-inlines-hidden support. +#cmakedefine __KDE_HAVE_GCC_VISIBILITY 1 + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#cmakedefine WORDS_BIGENDIAN @WORDS_BIGENDIAN@ \ No newline at end of file diff --git a/interfaces/CMakeLists.txt b/interfaces/CMakeLists.txt new file mode 100644 index 0000000..df05b75 --- /dev/null +++ b/interfaces/CMakeLists.txt @@ -0,0 +1,45 @@ +################################################################################ +# XDG Desktop Portal implementation for TDE # +# Copyright (C) 2024 Mavridis Philippe # +# # +# Improvements and feedback are welcome! # +# This software is licensed under the terms of the GNU GPL v3 license. # +################################################################################ + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${DBUS_TQT_INCLUDE_DIRS} +) + +link_directories( + ${DBUS_TQT_LIBRARY_DIRS} +) + +set(filechooser_HDRS filechooserInterface.h filechooserProxy.h introspectableInterface.h) +set(filechooser_SRCS filechooserInterface.cpp filechooserProxy.cpp introspectableInterface.cpp) + +add_custom_command( + OUTPUT ${filechooser_HDRS} ${filechooser_SRCS} + COMMAND ${DBUSXML2QT3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/filechooser.xml + DEPENDS filechooser.xml + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) + +tde_add_library(portalinterfaces STATIC_PIC AUTOMOC + SOURCES ${filechooser_SRCS} + LINK ${DBUS_TQT_LIBRARIES} +) + +configure_file(org.freedesktop.impl.portal.desktop.tde.service.cmake + org.freedesktop.impl.portal.desktop.tde.service @ONLY) + +configure_file(xdg-desktop-portal-tde.desktop.cmake + xdg-desktop-portal-tde.desktop @ONLY) + +install(FILES tde.portal DESTINATION ${SHARE_INSTALL_PREFIX}/xdg-desktop-portal/portals) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.freedesktop.impl.portal.desktop.tde.service + DESTINATION ${DBUS_SESSION_DIRECTORY}) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/xdg-desktop-portal-tde.desktop + DESTINATION ${SHARE_INSTALL_PREFIX}/applications) \ No newline at end of file diff --git a/interfaces/filechooser.xml b/interfaces/filechooser.xml new file mode 100644 index 0000000..da6bed2 --- /dev/null +++ b/interfaces/filechooser.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/interfaces/org.freedesktop.impl.portal.desktop.tde.service.cmake b/interfaces/org.freedesktop.impl.portal.desktop.tde.service.cmake new file mode 100644 index 0000000..eb697a1 --- /dev/null +++ b/interfaces/org.freedesktop.impl.portal.desktop.tde.service.cmake @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.freedesktop.impl.portal.desktop.tde +Exec=@LIBEXEC_INSTALL_DIR@/xdg-desktop-portal-tde \ No newline at end of file diff --git a/interfaces/tde.portal b/interfaces/tde.portal new file mode 100644 index 0000000..5bcf81a --- /dev/null +++ b/interfaces/tde.portal @@ -0,0 +1,4 @@ +[portal] +DBusName=org.freedesktop.impl.portal.desktop.tde +Interfaces=org.freedesktop.impl.portal.FileChooser +UseIn=Trinity diff --git a/interfaces/xdg-desktop-portal-tde.desktop.cmake b/interfaces/xdg-desktop-portal-tde.desktop.cmake new file mode 100644 index 0000000..267f91d --- /dev/null +++ b/interfaces/xdg-desktop-portal-tde.desktop.cmake @@ -0,0 +1,5 @@ +[Desktop Entry] +Type=Application +Name=Portal +NoDisplay=true +Exec=@LIBEXEC_INSTALL_DIR@/xdg-desktop-portal-tde \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..afcd9fd --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,42 @@ +################################################################################ +# XDG Desktop Portal implementation for TDE # +# Copyright (C) 2024 Mavridis Philippe # +# # +# Improvements and feedback are welcome! # +# This software is licensed under the terms of the GNU GPL v3 license. # +################################################################################ + +include_directories( + ${CMAKE_BINARY_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${TDE_INCLUDE_DIR} + ${TQT_INCLUDE_DIRS} + ${DBUS_TQT_INCLUDE_DIRS} + ${CMAKE_BINARY_DIR}/interfaces +) + +link_directories( + ${TQT_LIBRARY_DIRS} + ${DBUS_TQT_LIBRARY_DIRS} + ${CMAKE_BINARY_DIR}/interfaces +) + +tde_add_executable( + xdg-desktop-portal-tde AUTOMOC + + SOURCES + main.cpp + portal_service.cpp + file_chooser_portal.cpp + + LINK + tdecore-shared + tdeio-shared + ${DBUS_TQT_LIBRARIES} + portalinterfaces-static + + DESTINATION ${LIBEXEC_INSTALL_DIR} +) + +# kate: replace-tabs true; tab-width 4; indent-width 4; \ No newline at end of file diff --git a/src/file_chooser_portal.cpp b/src/file_chooser_portal.cpp new file mode 100644 index 0000000..1d037ec --- /dev/null +++ b/src/file_chooser_portal.cpp @@ -0,0 +1,269 @@ +/******************************************************************************* + XDG desktop portal implementation for TDE + Copyright © 2024 Mavridis Philippe + + This program or library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + This library 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 Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Improvements and feedback are welcome! +*******************************************************************************/ + +// TQt +#include +#include + +// TDE +#include +#include +#include +#include + +// Portal +#include "file_chooser_portal.h" +#include "file_chooser_portal.moc" +#include "util.h" + +#define OPTION_VALID(opt, sig) \ + options.keys().contains(opt) && check_variant(options[opt], sig) + + +TDEFileChooserPortal::TDEFileChooserPortal(TQT_DBusConnection &connection) + : m_connection(connection) +{} + +TDEFileChooserPortal::~TDEFileChooserPortal() +{} + +bool TDEFileChooserPortal::OpenFile(const TQT_DBusObjectPath& handle, + const TQString& app_id, + const TQString& parent_window, + const TQString& title, + const TQMap &options, + TQ_UINT32& response, + TQMap &results, + TQT_DBusError& error) +{ + FileDialogOpts opts; + + opts.caption = title; + + if (OPTION_VALID("accept_label", "s")) + opts.okButtonText = options["accept_label"].value.toString(); + + if (OPTION_VALID("directory", "b")) + opts.directory = options["directory"].value.toBool(); + + if (OPTION_VALID("multiple", "b")) + opts.multiple = options["multiple"].value.toBool(); + + if (OPTION_VALID("modal", "b")) + opts.modal = options["modal"].value.toBool(); + + if (OPTION_VALID("filters", "a(sa(us))")) + opts.filters = parseFilterList(options["filters"], options["current_filter"]); + + opts.windowId = parseWindowId(parent_window); + + return execFileDialog(opts, handle, response, results, error); +} + +bool TDEFileChooserPortal::SaveFile(const TQT_DBusObjectPath& handle, + const TQString& app_id, + const TQString& parent_window, + const TQString& title, + const TQMap &options, + TQ_UINT32& response, + TQMap &results, + TQT_DBusError& error) +{ + FileDialogOpts opts; + + opts.caption = title; + + if (OPTION_VALID("accept_label", "s")) + opts.okButtonText = options["accept_label"].value.toString(); + + if (OPTION_VALID("directory", "b")) + opts.directory = options["directory"].value.toBool(); + + if (OPTION_VALID("multiple", "b")) + opts.multiple = options["multiple"].value.toBool(); + + if (OPTION_VALID("modal", "b")) + opts.modal = options["modal"].value.toBool(); + + if (OPTION_VALID("filters", "a(sa(us))")) + opts.filters = parseFilterList(options["filters"], options["current_filter"]); + + if (OPTION_VALID("current_folder", "ay")) + opts.startDir = bytelist_to_string(options["current_folder"].value.toList().toByteList()); + + if (OPTION_VALID("current_name", "s")) + opts.startName = options["current_name"].value.toString(); + + opts.windowId = parseWindowId(parent_window); + + return execFileDialog(opts, handle, response, results, error); +} + +bool TDEFileChooserPortal::SaveFiles(const TQT_DBusObjectPath& handle, + const TQString& app_id, + const TQString& parent_window, + const TQString& title, + const TQMap &options, + TQ_UINT32& response, + TQMap &results, + TQT_DBusError& error) +{ + return false; +} + +void TDEFileChooserPortal::handleMethodReply(const TQT_DBusMessage &reply) +{ + m_connection.send(reply); +} + +bool TDEFileChooserPortal::execFileDialog(FileDialogOpts options, + const TQT_DBusObjectPath& handle, + TQ_UINT32& response, + TQMap &results, + TQT_DBusError& error) +{ + KFileDialog *dialog = new KFileDialog(options.startDir, TQString::null, + nullptr, "xdg-tde-file-chooser", + options.modal); + uint mode = KFile::LocalOnly; + if (options.savingMode) + { + dialog->setOperationMode(KFileDialog::Saving); + } + else { + mode |= KFile::ExistingOnly; + } + dialog->setMode(mode | options.mode()); + + if (!options.caption.isNull()) + dialog->setPlainCaption(options.caption); + + if (!options.okButtonText.isNull()) + dialog->okButton()->setText(options.okButtonText); + + if (!options.filters.isNull()) + dialog->setFilter(options.filters); + + dialog->setSelection(options.startName); + + if (options.windowId > 0) KWin::setMainWindow(dialog, options.windowId); + + if (dialog->exec() == TQDialog::Accepted) + { + response = 0; + TQT_DBusDataList urls = kurl_list_to_datalist(dialog->selectedURLs()); + TQT_DBusVariant var = TQT_DBusData::fromList(urls).getAsVariantData().toVariant(); + results.insert("uris", var); + } + else response = 1; + return true; +} + +WId TDEFileChooserPortal::parseWindowId(const TQString data) +{ + if (!data.startsWith("x11:")) + { + kdWarning() << "[FileChooser] Window Identifiers are currently only " + << "supported for X11. Created dialog will be parentless." + << endl; + return 0; + } + + bool ok; + WId wid = data.mid(4).toInt(&ok, 16); + return ok ? wid : 0; +} + +TQString TDEFileChooserPortal::parseFilter(const TQT_DBusData data) +{ + TQStringList patternList; + + TQValueList filterData = data.toStruct(); + + TQString label = filterData[0].toString(); + TQValueList patterns = filterData[1].toTQValueList(); + + TQValueList::iterator fp; + for (fp = patterns.begin(); fp != patterns.end(); ++fp) + { + TQValueList patternData = (*fp).toStruct(); + bool isMime = (patternData[0].toUInt32() == 1); + if (isMime) { + // KFileDialog cannot handle both a mime and a simple + // extension filter, so in case we get a mimetype, + // we just get the associated extensions from the + // MIME system + TQString mime = patternData[1].toString(); + patternList += KMimeType::mimeType(mime)->patterns(); + } + else { + TQString patternString = patternData[1].toString(); + + // Regex patterns like *.[hH][tT][mM][lL] are unnecessary for us + // and causes a problem with the save dialog's extension autoselection + TQString finalPattern = patternString; + if (TQRegExp("[*.](?:[[](?:[A-Za-z]{2})[]])+").search(patternString) != -1) + { + finalPattern = "*."; + int pos = patternString.find('['); + while (pos != -1) + { + finalPattern += patternString[pos + 1]; + pos = patternString.find('[', patternString.find(']', pos)); + } + } + patternList += finalPattern; + } + } + + TQString patternString = patternList.join(" "); + + return TQString("%1|%2 (%3)").arg(patternString, label, patternString); +} + +TQString TDEFileChooserPortal::parseFilterList(const TQT_DBusVariant filterData, + const TQT_DBusVariant currentFilterData) +{ + TQStringList filterList; + TQValueList filters = filterData.value.toTQValueList(); + if (filters.count() > 0) { + TQValueList::iterator f; + for (f = filters.begin(); f != filters.end(); ++f) + filterList += parseFilter((*f)); + } + + if (check_variant(currentFilterData, "(sa(us))")) + { + TQString currentFilter = parseFilter(currentFilterData.value); + if (filterList.contains(currentFilter)) + { + // We have no way to affect the filter selection of the dialog, + // so we just move the current filter to the top of the list + // to get it selected automatically + filterList.remove(currentFilter); + filterList.prepend(currentFilter); + } + } + + return filterList.join("\n"); +} + +// kate: replace-tabs true; tab-width 4; indent-width 4; \ No newline at end of file diff --git a/src/file_chooser_portal.h b/src/file_chooser_portal.h new file mode 100644 index 0000000..375b7c8 --- /dev/null +++ b/src/file_chooser_portal.h @@ -0,0 +1,114 @@ +/******************************************************************************* + XDG desktop portal implementation for TDE + Copyright © 2024 Mavridis Philippe + + This program or library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + This library 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 Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Improvements and feedback are welcome! +*******************************************************************************/ + +#ifndef __FILE_CHOOSER_PORTAL_H +#define __FILE_CHOOSER_PORTAL_H + +// TQt +#include +#include +#include +#include +#include + +// TDE +#include + +// Portal +#include "filechooserInterface.h" + +struct FileDialogOpts +{ + TQString caption; + TQString okButtonText; + TQString startDir; + TQString startName; + TQString filters; + bool multiple = false; + bool directory = false; + bool savingMode = false; + bool modal = true; + WId windowId = 0; + + inline KFile::Mode mode() + { + if (directory) return KFile::Directory; + return multiple ? KFile::Files : KFile::File; + } +}; + +class KFileDialog; + +class TDEFileChooserPortal : public TQObject, + public org::freedesktop::impl::portal::FileChooserInterface +{ + public: + TDEFileChooserPortal(TQT_DBusConnection &connection); + virtual ~TDEFileChooserPortal(); + + protected: + virtual bool OpenFile(const TQT_DBusObjectPath& handle, + const TQString& app_id, + const TQString& parent_window, + const TQString& title, + const TQMap &options, + TQ_UINT32& response, + TQMap &results, + TQT_DBusError& error); + + virtual bool SaveFile(const TQT_DBusObjectPath& handle, + const TQString& app_id, + const TQString& parent_window, + const TQString& title, + const TQMap &options, + TQ_UINT32& response, + TQMap &results, + TQT_DBusError& error); + + virtual bool SaveFiles(const TQT_DBusObjectPath& handle, + const TQString& app_id, + const TQString& parent_window, + const TQString& title, + const TQMap &options, + TQ_UINT32& response, + TQMap &results, + TQT_DBusError& error); + + virtual void handleMethodReply(const TQT_DBusMessage &reply); + + private: + TQT_DBusConnection m_connection; + + WId parseWindowId(const TQString data); + TQString parseFilter(const TQT_DBusData data); + TQString parseFilterList(const TQT_DBusVariant filterData, + const TQT_DBusVariant currentFilterData); + + bool execFileDialog(FileDialogOpts options, + const TQT_DBusObjectPath& handle, + TQ_UINT32& response, + TQMap &results, + TQT_DBusError& error); +}; + +#endif // __FILE_CHOOSER_PORTAL_H + +// kate: replace-tabs true; tab-width 4; indent-width 4; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..278d754 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,65 @@ +/******************************************************************************* + XDG desktop portal implementation for TDE + Copyright © 2024 Mavridis Philippe + + This program or library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + This library 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 Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Improvements and feedback are welcome! +*******************************************************************************/ + +// TQt +#include + +// TDE +#include +#include +#include +#include + +// Portal +#include "portal_service.h" + + +static const char description[] = I18N_NOOP("TDE XDG desktop portal"); +static TDECmdLineOptions options[] = {}; + +int main(int argc, char **argv) +{ + TDEAboutData about("xdg-desktop-portal-tde", "xdg-desktop-portal-tde", "1.0", + description, TDEAboutData::License_LGPL, + I18N_NOOP("Copyright © 2024 Mavridis Philippe")); + + TDECmdLineArgs::init(argc, argv, &about); + TDECmdLineArgs::addCmdLineOptions(options); + KUniqueApplication::addCmdLineOptions(); + + if (!KUniqueApplication::start()) + return 0; + + KUniqueApplication app; + + TQT_DBusConnection connection = TQT_DBusConnection::sessionBus(); + if (!connection.isConnected()) + tqFatal("Failed to connect to session bus!"); + + if (!connection.requestName("org.freedesktop.impl.portal.desktop.tde")) + tqFatal("Failed to register XDG portal service!"); + + TDEPortalService portal(connection); + + return app.exec(); +} + +// kate: replace-tabs true; tab-width 4; indent-width 4; \ No newline at end of file diff --git a/src/portal.cpp b/src/portal.cpp new file mode 100644 index 0000000..e69a1d8 --- /dev/null +++ b/src/portal.cpp @@ -0,0 +1,37 @@ +/******************************************************************************* + XDG desktop portal implementation for TDE + Copyright © 2024 Mavridis Philippe + + This program or library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + This library 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 Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Improvements and feedback are welcome! +*******************************************************************************/ + +// Portal +#include "portal.h" +#include "portal.moc" + + +Portal::Portal(const TQT_DBusConnection &connection) +: m_connection(connection) +{} + +Portal::~Portal() +{} + +bool Portal::handleMethodCall(const TQT_DBusMessage &message) +{ + return false; +} \ No newline at end of file diff --git a/src/portal.h b/src/portal.h new file mode 100644 index 0000000..ee30d0d --- /dev/null +++ b/src/portal.h @@ -0,0 +1,48 @@ +/******************************************************************************* + XDG desktop portal implementation for TDE + Copyright © 2024 Mavridis Philippe + + This program or library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + This library 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 Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Improvements and feedback are welcome! +*******************************************************************************/ + +#ifndef __PORTAL_H +#define __PORTAL_H + +// TQt +#include +#include +#include + + +class Portal : public TQObject, public TQT_DBusObjectBase +{ + TQ_OBJECT + + public: + Portal(const TQT_DBusConnection &connection); + virtual ~Portal(); + + const TQT_DBusConnection connection() { return m_connection; } + + protected: + virtual bool handleMethodCall(const TQT_DBusMessage &message); + + private: + TQT_DBusConnection m_connection; +}; + +#endif // __PORTAL_H \ No newline at end of file diff --git a/src/portal_service.cpp b/src/portal_service.cpp new file mode 100644 index 0000000..86baa63 --- /dev/null +++ b/src/portal_service.cpp @@ -0,0 +1,75 @@ +/******************************************************************************* + XDG desktop portal implementation for TDE + Copyright © 2024 Mavridis Philippe + + This program or library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + This library 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 Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Improvements and feedback are welcome! +*******************************************************************************/ + +// TQt +#include + +// TDE +#include +#include + +// Portal +#include "file_chooser_portal.h" +#include "portal_service.h" + + +static const char *dbusObjectPath = "/org/freedesktop/portal/desktop"; +static const char *dbusInterfaceRoot = "org.freedesktop.impl.portal"; + +TDEPortalService::TDEPortalService(TQT_DBusConnection &connection) +: m_connection(connection) +{ + if (!m_connection.registerObject(dbusObjectPath, this)) + kdFatal() << "Unable to register XDG desktop portal object " << dbusObjectPath << endl; + else + kdDebug() << "Registered XDG desktop portal object " << dbusObjectPath << endl; +} + +TDEPortalService::~TDEPortalService() +{ + m_connection.unregisterObject(dbusObjectPath); +} + +TQT_DBusObjectBase* TDEPortalService::getPortalInterface(TQCString portal) +{ + if (portal == "FileChooser") + return new TDEFileChooserPortal(m_connection); + + return nullptr; +} + +bool TDEPortalService::handleMethodCall(const TQT_DBusMessage &message) +{ + if (!message.interface().startsWith(dbusInterfaceRoot)) + return false; + + TQCString portal = message.interface().mid(TQString(dbusInterfaceRoot).length() + 1).local8Bit(); + TQT_DBusObjectBase *iface = getPortalInterface(portal); + if (!iface) + { + kdWarning() << "Unsupported XDG portal requested: " << portal << endl; + return false; + } + + return delegateMethodCall(message, iface); +} + +// kate: replace-tabs true; tab-width 4; indent-width 4; \ No newline at end of file diff --git a/src/portal_service.h b/src/portal_service.h new file mode 100644 index 0000000..8e7c400 --- /dev/null +++ b/src/portal_service.h @@ -0,0 +1,47 @@ +/******************************************************************************* + XDG desktop portal implementation for TDE + Copyright © 2024 Mavridis Philippe + + This program or library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + This library 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 Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Improvements and feedback are welcome! +*******************************************************************************/ + +#ifndef __PORTAL_SERVICE_H +#define __PORTAL_SERVICE_H + +// TQt +#include +#include + +class TDEFileChooserPortal; + +class TDEPortalService : public TQT_DBusObjectBase +{ + public: + TDEPortalService(TQT_DBusConnection &connection); + ~TDEPortalService(); + + protected: + bool handleMethodCall(const TQT_DBusMessage &message); + + private: + TQT_DBusConnection m_connection; + TQT_DBusObjectBase* getPortalInterface(TQCString portal); +}; + +#endif // __DESTKOP_PORTAL_H + +// kate: replace-tabs true; tab-width 4; indent-width 4; \ No newline at end of file diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..656bfff --- /dev/null +++ b/src/util.h @@ -0,0 +1,126 @@ +/******************************************************************************* + XDG desktop portal implementation for TDE + Copyright © 2024 Mavridis Philippe + + This program or library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + This library 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 Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Improvements and feedback are welcome! +*******************************************************************************/ + +#ifndef __UTIL_H +#define __UTIL_H + +// TQt +#include +#include +#include + +// TDE +#include + +inline bool check_variant(TQT_DBusVariant variant, TQString signature) +{ + return !variant.signature.isNull() && variant.signature == signature; +} + +inline TQString bytelist_to_string(TQT_DBusDataList list) +{ + if (list.type() != TQT_DBusData::Byte) return TQString::null; + TQCString bytes; + TQValueList vl = list.toByteList(); + TQValueList::iterator vlit; + for (vlit = vl.begin(); vlit != vl.end(); ++vlit) + { + bytes += (*vlit); + } + return TQString::fromLocal8Bit(bytes.data(), bytes.size()); +} + +inline TQT_DBusDataList string_to_bytelist(TQString str) +{ + TQCString bytes = str.latin1(); + TQValueList vl; + char *bit; + for (bit = bytes.begin(); bit != bytes.end(); ++bit) + { + vl << (TQ_UINT8)(*bit); + } + return TQT_DBusDataList(vl); +} + +inline TQT_DBusDataList kurl_list_to_datalist(KURL::List urls) +{ + return TQT_DBusDataList(urls.toStringList()); +} + +inline bool make_variant(TQVariant variant, TQT_DBusVariant &other) +{ + TQString signature; + switch (variant.type()) { + case TQVariant::String: + case TQVariant::Color: + case TQVariant::Font: + case TQVariant::Date: + case TQVariant::DateTime: + case TQVariant::Time: + case TQVariant::KeySequence: + other.signature = "s"; + other.value = TQT_DBusData::fromString(variant.toString()); + break; + + case TQVariant::Int: + other.signature = "i"; + other.value = TQT_DBusData::fromInt32(variant.toInt()); + break; + + case TQVariant::UInt: + other.signature = "u"; + other.value = TQT_DBusData::fromUInt32(variant.toUInt()); + break; + + case TQVariant::Double: + case TQVariant::LongLong: + case TQVariant::ULongLong: + other.signature = "d"; + other.value = TQT_DBusData::fromDouble(variant.toDouble()); + break; + + case TQVariant::Bool: + other.signature = "b"; + other.value = TQT_DBusData::fromBool(variant.toBool()); + break; + + case TQVariant::StringList: + other.signature = "as"; + other.value = TQT_DBusData::fromList(TQT_DBusDataList(variant.toStringList())); + break; + + default: + if (variant.canCast(TQVariant::String)) { + other.signature = "s"; + other.value = TQT_DBusData::fromString(variant.toString()); + } + else { + kdDebug() << "Cannot cast TQVariant of type " << variant.type() + << "to TQT_DBusVariant!" << endl; + return false; + } + } + return true; +} + +#endif // __UTIL_H + +// kate: replace-tabs true; tab-width 4; indent-width 4; \ No newline at end of file