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 <QtCore/QAbstractEventDispatcher>
#include <glibmm.h>
#include <gio/gio.hpp>
#include <xdpinhibit/xdpinhibit.hpp> #include <xdpinhibit/xdpinhibit.hpp>
#include <giomm.h>
typedef GApplication TDesktopApplication; namespace Platform {
typedef GApplicationClass TDesktopApplicationClass; namespace {
G_DEFINE_TYPE( using namespace gi::repository;
TDesktopApplication,
t_desktop_application,
G_TYPE_APPLICATION)
static void t_desktop_application_class_init( class Application : public Gio::impl::ApplicationImpl {
TDesktopApplicationClass *klass) { public:
const auto application_class = G_APPLICATION_CLASS(klass); Application();
application_class->local_command_line = []( void before_emit_(GLib::Variant platformData) noexcept override {
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) {
if (Platform::IsWayland()) { if (Platform::IsWayland()) {
static const auto keys = { static const auto keys = {
"activation-token", "activation-token",
"desktop-startup-id", "desktop-startup-id",
}; };
for (const auto &key : keys) { for (const auto &key : keys) {
const char *token = nullptr; if (auto token = platformData.lookup_value(key)) {
g_variant_lookup(platformData, key, "&s", &token); qputenv(
if (token) { "XDG_ACTIVATION_TOKEN",
qputenv("XDG_ACTIVATION_TOKEN", token); token.get_string(nullptr).c_str());
break; break;
} }
} }
} }
}; }
application_class->add_platform_data = []( void startup_() noexcept override {
GApplication *application, // GNotification
GVariantBuilder *builder) { 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()) { if (Platform::IsWayland()) {
const auto token = qgetenv("XDG_ACTIVATION_TOKEN"); const auto token = qgetenv("XDG_ACTIVATION_TOKEN");
if (!token.isEmpty()) { if (!token.isEmpty()) {
g_variant_builder_add( builder.add_value(
builder, GLib::Variant::new_dict_entry(
"{sv}", GLib::Variant::new_string("activation-token"),
"activation-token", GLib::Variant::new_variant(
g_variant_new_string(token.constData())); GLib::Variant::new_string(token.toStdString()))));
qunsetenv("XDG_ACTIVATION_TOKEN"); 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 { class LinuxIntegration final : public Integration {
public: public:
LinuxIntegration(); LinuxIntegration();
@ -103,8 +201,6 @@ private:
void initInhibit(); void initInhibit();
static void LaunchNativeApplication();
XdpInhibit::InhibitProxy _inhibitProxy; XdpInhibit::InhibitProxy _inhibitProxy;
base::Platform::XDP::SettingWatcher _darkModeWatcher; base::Platform::XDP::SettingWatcher _darkModeWatcher;
}; };
@ -146,8 +242,8 @@ LinuxIntegration::LinuxIntegration()
void LinuxIntegration::init() { void LinuxIntegration::init() {
initInhibit(); initInhibit();
Glib::signal_idle().connect_once([] { GLib::idle_add_once([] {
LaunchNativeApplication(); gi::make_ref<Application>()->run(0, nullptr);
}); });
} }
@ -207,115 +303,6 @@ void LinuxIntegration::initInhibit() {
nullptr); 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 } // namespace
std::unique_ptr<Integration> CreateIntegration() { std::unique_ptr<Integration> CreateIntegration() {

View file

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