Port GApplication to cppgir

This commit is contained in:
Ilya Fedin 2023-08-04 04:05:35 +04:00 committed by John Preston
parent bda3bae712
commit 8669e6a891
2 changed files with 156 additions and 168 deletions

View File

@ -17,79 +17,177 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtCore/QAbstractEventDispatcher>
#include <glibmm.h>
#include <gio/gio.hpp>
#include <xdpinhibit/xdpinhibit.hpp>
#include <giomm.h>
typedef GApplication TDesktopApplication;
typedef GApplicationClass TDesktopApplicationClass;
namespace Platform {
namespace {
G_DEFINE_TYPE(
TDesktopApplication,
t_desktop_application,
G_TYPE_APPLICATION)
using namespace gi::repository;
static void t_desktop_application_class_init(
TDesktopApplicationClass *klass) {
const auto application_class = G_APPLICATION_CLASS(klass);
class Application : public Gio::impl::ApplicationImpl {
public:
Application();
application_class->local_command_line = [](
GApplication *application,
char ***arguments,
int *exit_status) -> gboolean {
return false;
};
application_class->command_line = [](
GApplication *application,
GApplicationCommandLine *cmdline) {
return 0;
};
application_class->before_emit = [](
GApplication *application,
GVariant *platformData) {
void before_emit_(GLib::Variant platformData) noexcept override {
if (Platform::IsWayland()) {
static const auto keys = {
"activation-token",
"desktop-startup-id",
};
for (const auto &key : keys) {
const char *token = nullptr;
g_variant_lookup(platformData, key, "&s", &token);
if (token) {
qputenv("XDG_ACTIVATION_TOKEN", token);
if (auto token = platformData.lookup_value(key)) {
qputenv(
"XDG_ACTIVATION_TOKEN",
token.get_string(nullptr).c_str());
break;
}
}
}
};
}
application_class->add_platform_data = [](
GApplication *application,
GVariantBuilder *builder) {
void startup_() noexcept override {
// GNotification
InvokeQueued(qApp, [] {
Core::App().notifications().createManager();
});
Gio::impl::ApplicationImpl::startup_();
QEventLoop().exec();
quit();
}
void activate_() noexcept override {
Core::Sandbox::Instance().customEnterFromEventLoop([] {
Core::App().activate();
});
}
void open_(GFile **files, int n_files, const char*) noexcept override {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
for (int i = 0; i < n_files; ++i) {
QFileOpenEvent e(
QUrl(QString::fromUtf8(g_file_get_uri(files[i]))));
QGuiApplication::sendEvent(qApp, &e);
}
});
}
int command_line_(Gio::ApplicationCommandLine) noexcept override {
return 0;
}
gboolean local_command_line_(char***, int*) noexcept override {
return false;
}
void add_platform_data_(GLib::VariantBuilder builder) noexcept override {
if (Platform::IsWayland()) {
const auto token = qgetenv("XDG_ACTIVATION_TOKEN");
if (!token.isEmpty()) {
g_variant_builder_add(
builder,
"{sv}",
"activation-token",
g_variant_new_string(token.constData()));
builder.add_value(
GLib::Variant::new_dict_entry(
GLib::Variant::new_string("activation-token"),
GLib::Variant::new_variant(
GLib::Variant::new_string(token.toStdString()))));
qunsetenv("XDG_ACTIVATION_TOKEN");
}
}
};
}
};
Application::Application()
: Gio::impl::ApplicationImpl(this) {
const auto appId = QGuiApplication::desktopFileName().toStdString();
if (Gio::Application::id_is_valid(appId)) {
set_application_id(appId);
}
set_flags(Gio::ApplicationFlags::HANDLES_OPEN_);
auto actionMap = Gio::ActionMap(*this);
auto quitAction = Gio::SimpleAction::new_("quit");
quitAction.signal_activate().connect([](
Gio::SimpleAction,
GLib::Variant parameter) {
Core::Sandbox::Instance().customEnterFromEventLoop([] {
Core::Quit();
});
});
actionMap.add_action(quitAction);
using Window::Notifications::Manager;
using NotificationId = Manager::NotificationId;
using NotificationIdTuple = std::invoke_result_t<
decltype(&NotificationId::toTuple),
NotificationId*
>;
const auto notificationIdVariantType = [] {
try {
return gi::wrap(
Glib::create_variant(
NotificationId().toTuple()
).get_type().gobj_copy(),
gi::transfer_full,
gi::direction_out
);
} catch (...) {
return GLib::VariantType();
}
}();
auto notificationActivateAction = Gio::SimpleAction::new_(
"notification-activate",
notificationIdVariantType);
notificationActivateAction.signal_activate().connect([](
Gio::SimpleAction,
GLib::Variant parameter) {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
try {
const auto &app = Core::App();
app.notifications().manager().notificationActivated(
NotificationId::FromTuple(
Glib::wrap(
parameter.gobj_copy_()
).get_dynamic<NotificationIdTuple>()
)
);
} catch (...) {
}
});
});
actionMap.add_action(notificationActivateAction);
auto notificationMarkAsReadAction = Gio::SimpleAction::new_(
"notification-mark-as-read",
notificationIdVariantType);
notificationMarkAsReadAction.signal_activate().connect([](
Gio::SimpleAction,
GLib::Variant parameter) {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
try {
const auto &app = Core::App();
app.notifications().manager().notificationReplied(
NotificationId::FromTuple(
Glib::wrap(
parameter.gobj_copy_()
).get_dynamic<NotificationIdTuple>()
),
{}
);
} catch (...) {
}
});
});
actionMap.add_action(notificationMarkAsReadAction);
}
static void t_desktop_application_init(TDesktopApplication *application) {
}
namespace Platform {
namespace {
using namespace gi::repository;
namespace Gio = gi::repository::Gio;
class LinuxIntegration final : public Integration {
public:
LinuxIntegration();
@ -103,8 +201,6 @@ private:
void initInhibit();
static void LaunchNativeApplication();
XdpInhibit::InhibitProxy _inhibitProxy;
base::Platform::XDP::SettingWatcher _darkModeWatcher;
};
@ -146,8 +242,8 @@ LinuxIntegration::LinuxIntegration()
void LinuxIntegration::init() {
initInhibit();
Glib::signal_idle().connect_once([] {
LaunchNativeApplication();
GLib::idle_add_once([] {
gi::make_ref<Application>()->run(0, nullptr);
});
}
@ -207,115 +303,6 @@ void LinuxIntegration::initInhibit() {
nullptr);
}
void LinuxIntegration::LaunchNativeApplication() {
const auto appId = QGuiApplication::desktopFileName().toStdString();
const auto app = Glib::wrap(
G_APPLICATION(
g_object_new(
t_desktop_application_get_type(),
"application-id",
::Gio::Application::id_is_valid(appId)
? appId.c_str()
: nullptr,
"flags",
G_APPLICATION_HANDLES_OPEN,
nullptr)));
app->signal_startup().connect([weak = std::weak_ptr(app)] {
const auto app = weak.lock();
if (!app) {
return;
}
// GNotification
InvokeQueued(qApp, [] {
Core::App().notifications().createManager();
});
QEventLoop().exec();
app->quit();
}, true);
app->signal_activate().connect([] {
Core::Sandbox::Instance().customEnterFromEventLoop([] {
Core::App().activate();
});
}, true);
app->signal_open().connect([](
const ::Gio::Application::type_vec_files &files,
const Glib::ustring &hint) {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
for (const auto &file : files) {
QFileOpenEvent e(
QUrl(QString::fromStdString(file->get_uri())));
QGuiApplication::sendEvent(qApp, &e);
}
});
}, true);
app->add_action("quit", [] {
Core::Sandbox::Instance().customEnterFromEventLoop([] {
Core::Quit();
});
});
using Window::Notifications::Manager;
using NotificationId = Manager::NotificationId;
using NotificationIdTuple = std::invoke_result_t<
decltype(&NotificationId::toTuple),
NotificationId*
>;
const auto notificationIdVariantType = [] {
try {
return Glib::create_variant(
NotificationId().toTuple()
).get_type();
} catch (...) {
return Glib::VariantType();
}
}();
app->add_action_with_parameter(
"notification-activate",
notificationIdVariantType,
[](const Glib::VariantBase &parameter) {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
try {
const auto &app = Core::App();
app.notifications().manager().notificationActivated(
NotificationId::FromTuple(
parameter.get_dynamic<NotificationIdTuple>()
)
);
} catch (...) {
}
});
});
app->add_action_with_parameter(
"notification-mark-as-read",
notificationIdVariantType,
[](const Glib::VariantBase &parameter) {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
try {
const auto &app = Core::App();
app.notifications().manager().notificationReplied(
NotificationId::FromTuple(
parameter.get_dynamic<NotificationIdTuple>()
),
{}
);
} catch (...) {
}
});
});
app->run(0, nullptr);
}
} // namespace
std::unique_ptr<Integration> CreateIntegration() {

View File

@ -40,9 +40,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtGui/QWindow>
#if __has_include(<giomm.h>)
#include <giomm.h>
#endif // __has_include(<giomm.h>)
#if __has_include(<gio/gio.hpp>)
#include <gio/gio.hpp>
#endif // __has_include(<gio/gio.hpp>)
namespace Window {
namespace Notifications {
@ -90,11 +90,12 @@ base::options::toggle OptionGNotification({
.description = "Force enable GLib's GNotification."
" When disabled, autodetect is used.",
.scope = [] {
#if __has_include(<giomm.h>)
#if __has_include(<gio/gio.hpp>)
using namespace gi::repository;
return bool(Gio::Application::get_default());
#else // __has_include(<giomm.h>)
#else // __has_include(<gio/gio.hpp>)
return false;
#endif // __has_include(<giomm.h>)
#endif // __has_include(<gio/gio.hpp>)
},
.restartRequired = true,
});