Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a new pull request by comparing changes across two branches #639

Merged
merged 4 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
304 changes: 140 additions & 164 deletions Telegram/SourceFiles/platform/linux/integration_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,78 +17,167 @@ For license and copyright information please follow this link:

#include <QtCore/QAbstractEventDispatcher>

#include <glibmm.h>
#include <gio/gio.hpp>
#include <xdpinhibit/xdpinhibit.hpp>
#include <giomm.h>

typedef GApplication TDesktopApplication;
typedef GApplicationClass TDesktopApplicationClass;

G_DEFINE_TYPE(
TDesktopApplication,
t_desktop_application,
G_TYPE_APPLICATION)

static void t_desktop_application_class_init(
TDesktopApplicationClass *klass) {
const auto application_class = G_APPLICATION_CLASS(klass);
namespace Platform {
namespace {

application_class->local_command_line = [](
GApplication *application,
char ***arguments,
int *exit_status) -> gboolean {
return false;
};
using namespace gi::repository;

application_class->command_line = [](
GApplication *application,
GApplicationCommandLine *cmdline) {
return 0;
};
class Application : public Gio::impl::ApplicationImpl {
public:
Application();

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;
}
}
}
};
}

void activate_() noexcept override {
Core::Sandbox::Instance().customEnterFromEventLoop([] {
Core::App().activate();
});
}

application_class->add_platform_data = [](
GApplication *application,
GVariantBuilder *builder) {
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);
}
});
}

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");
}
}
};
}
}
};

static void t_desktop_application_init(TDesktopApplication *application) {
}
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_);

namespace Platform {
namespace {
auto actionMap = Gio::ActionMap(*this);

using namespace gi::repository;
namespace Gio = gi::repository::Gio;
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);
}

gi::ref_ptr<Application> MakeApplication() {
const auto result = gi::make_ref<Application>();
if (const auto registered = result->register_(); !registered) {
LOG(("App Error: Failed to register: %1").arg(
QString::fromStdString(registered.error().message_())));
return nullptr;
}
return result;
}

class LinuxIntegration final : public Integration {
public:
Expand All @@ -103,14 +192,14 @@ class LinuxIntegration final : public Integration {

void initInhibit();

static void LaunchNativeApplication();

const gi::ref_ptr<Application> _application;
XdpInhibit::InhibitProxy _inhibitProxy;
base::Platform::XDP::SettingWatcher _darkModeWatcher;
};

LinuxIntegration::LinuxIntegration()
: _inhibitProxy(
: _application(MakeApplication())
, _inhibitProxy(
XdpInhibit::InhibitProxy::new_for_bus_sync(
Gio::BusType::SESSION_,
Gio::DBusProxyFlags::DO_NOT_AUTO_START_AT_CONSTRUCTION_,
Expand Down Expand Up @@ -139,16 +228,12 @@ LinuxIntegration::LinuxIntegration()
if (!QCoreApplication::eventDispatcher()->inherits(
"QEventDispatcherGlib")) {
g_warning("Qt is running without GLib event loop integration, "
"except various functionality to not to work.");
"expect various functionality to not to work.");
}
}

void LinuxIntegration::init() {
initInhibit();

Glib::signal_idle().connect_once([] {
LaunchNativeApplication();
});
}

void LinuxIntegration::initInhibit() {
Expand Down Expand Up @@ -207,115 +292,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() {
Expand Down
13 changes: 7 additions & 6 deletions Telegram/SourceFiles/window/notifications_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ For license and copyright information please follow this link:

#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 {
Expand Down Expand Up @@ -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,
});
Expand Down
Loading
Loading