add popover component

This commit is contained in:
2025-12-20 20:52:04 +01:00
parent 3558fd3ebc
commit 47f052f913
8 changed files with 119 additions and 89 deletions

View File

@@ -3,10 +3,10 @@
#include <gio/gio.h>
#include <iostream>
static constexpr const char* kNotificationsObjectPath = "/org/freedesktop/Notifications";
static constexpr const char* kNotificationsInterface = "org.freedesktop.Notifications";
static constexpr const char *kNotificationsObjectPath = "/org/freedesktop/Notifications";
static constexpr const char *kNotificationsInterface = "org.freedesktop.Notifications";
static const char* kNotificationsIntrospectionXml = R"XML(
static const char *kNotificationsIntrospectionXml = R"XML(
<node>
<interface name="org.freedesktop.Notifications">
<method name="Notify">
@@ -47,15 +47,15 @@ static const char* kNotificationsIntrospectionXml = R"XML(
</interface>
</node>)XML";
static void on_method_call(GDBusConnection* /*connection*/,
const gchar* /*sender*/,
const gchar* /*object_path*/,
const gchar* interface_name,
const gchar* method_name,
GVariant* parameters,
GDBusMethodInvocation* invocation,
static void on_method_call(GDBusConnection * /*connection*/,
const gchar * /*sender*/,
const gchar * /*object_path*/,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data) {
auto* self = static_cast<NotificationService*>(user_data);
auto *self = static_cast<NotificationService *>(user_data);
if (g_strcmp0(interface_name, kNotificationsInterface) != 0) {
g_dbus_method_invocation_return_dbus_error(
@@ -66,13 +66,13 @@ static void on_method_call(GDBusConnection* /*connection*/,
}
if (g_strcmp0(method_name, "Notify") == 0) {
const gchar* app_name = "";
guint32 replaces_id = 0;
const gchar* app_icon = "";
const gchar* summary = "";
const gchar* body = "";
GVariant* actions = nullptr;
GVariant* hints = nullptr;
const gchar *app_name = "";
guint32 replaces_id = 0;
const gchar *app_icon = "";
const gchar *summary = "";
const gchar *body = "";
GVariant *actions = nullptr;
GVariant *hints = nullptr;
gint32 expire_timeout = -1;
g_variant_get(parameters, "(&su&s&s&s@as@a{sv}i)",
@@ -90,8 +90,10 @@ static void on_method_call(GDBusConnection* /*connection*/,
std::cout << "Title: " << (summary ? summary : "") << std::endl;
std::cout << "Body: " << (body ? body : "") << std::endl;
if (actions) g_variant_unref(actions);
if (hints) g_variant_unref(hints);
if (actions)
g_variant_unref(actions);
if (hints)
g_variant_unref(hints);
guint32 id = self->allocateNotificationId(replaces_id);
g_dbus_method_invocation_return_value(invocation, g_variant_new("(u)", id));
@@ -101,15 +103,14 @@ static void on_method_call(GDBusConnection* /*connection*/,
if (g_strcmp0(method_name, "GetCapabilities") == 0) {
// Advertise common capabilities so clients don't disable notifications.
// (Many apps probe this first and may skip Notify if it's empty.)
const gchar* caps[] = {
const gchar *caps[] = {
"body",
"actions",
"body-markup",
"icon-static",
"persistence",
nullptr
};
GVariant* capsV = g_variant_new_strv(caps, -1);
nullptr};
GVariant *capsV = g_variant_new_strv(caps, -1);
g_dbus_method_invocation_return_value(invocation, g_variant_new("(@as)", capsV));
return;
}
@@ -128,7 +129,7 @@ static void on_method_call(GDBusConnection* /*connection*/,
// reason: 3 = closed by call to CloseNotification
if (self && self->getConnection()) {
g_dbus_connection_emit_signal(
self->getConnection(),
self->getConnection(),
nullptr,
kNotificationsObjectPath,
kNotificationsInterface,
@@ -148,12 +149,13 @@ static void on_method_call(GDBusConnection* /*connection*/,
}
guint32 NotificationService::allocateNotificationId(guint32 replacesId) {
if (replacesId != 0) return replacesId;
if (replacesId != 0)
return replacesId;
return this->nextNotificationId++;
}
static const GDBusInterfaceVTable kVTable = {
.method_call = on_method_call,
.method_call = on_method_call,
.get_property = nullptr,
.set_property = nullptr,
};
@@ -162,8 +164,8 @@ NotificationService::~NotificationService() {
if (this->connection) {
// Best-effort release of the well-known name.
{
GError* error = nullptr;
GVariant* releaseResult = g_dbus_connection_call_sync(
GError *error = nullptr;
GVariant *releaseResult = g_dbus_connection_call_sync(
this->connection,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
@@ -175,8 +177,10 @@ NotificationService::~NotificationService() {
-1,
nullptr,
&error);
if (releaseResult) g_variant_unref(releaseResult);
if (error) g_error_free(error);
if (releaseResult)
g_variant_unref(releaseResult);
if (error)
g_error_free(error);
}
if (this->registrationId != 0) {
@@ -195,16 +199,17 @@ NotificationService::~NotificationService() {
}
void NotificationService::intialize() {
GError* error = nullptr;
GError *error = nullptr;
if (this->connection) {
return;
}
gchar* address = g_dbus_address_get_for_bus_sync(G_BUS_TYPE_SESSION, nullptr, &error);
gchar *address = g_dbus_address_get_for_bus_sync(G_BUS_TYPE_SESSION, nullptr, &error);
if (!address) {
std::cerr << "Failed to get session bus address: " << (error ? error->message : "unknown error") << std::endl;
if (error) g_error_free(error);
if (error)
g_error_free(error);
return;
}
@@ -225,7 +230,8 @@ void NotificationService::intialize() {
if (!this->connection) {
std::cerr << "Failed to connect to session bus: " << (error ? error->message : "unknown error") << std::endl;
if (error) g_error_free(error);
if (error)
g_error_free(error);
return;
}
@@ -237,11 +243,12 @@ void NotificationService::intialize() {
this->nodeInfo = g_dbus_node_info_new_for_xml(kNotificationsIntrospectionXml, &error);
if (!this->nodeInfo) {
std::cerr << "Failed to create introspection data: " << (error ? error->message : "unknown error") << std::endl;
if (error) g_error_free(error);
if (error)
g_error_free(error);
return;
}
GDBusInterfaceInfo* iface = g_dbus_node_info_lookup_interface(this->nodeInfo, kNotificationsInterface);
GDBusInterfaceInfo *iface = g_dbus_node_info_lookup_interface(this->nodeInfo, kNotificationsInterface);
if (!iface) {
std::cerr << "Missing interface info for org.freedesktop.Notifications" << std::endl;
return;
@@ -258,13 +265,14 @@ void NotificationService::intialize() {
if (this->registrationId == 0) {
std::cerr << "Failed to register notifications object: " << (error ? error->message : "unknown error") << std::endl;
if (error) g_error_free(error);
if (error)
g_error_free(error);
return;
}
// Request the well-known name synchronously so we can detect conflicts.
// Reply codes: 1=PRIMARY_OWNER, 2=IN_QUEUE, 3=EXISTS, 4=ALREADY_OWNER
GVariant* requestResult = g_dbus_connection_call_sync(
GVariant *requestResult = g_dbus_connection_call_sync(
this->connection,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
@@ -280,7 +288,8 @@ void NotificationService::intialize() {
if (!requestResult) {
std::cerr << "Failed to RequestName(org.freedesktop.Notifications): "
<< (error ? error->message : "unknown error") << std::endl;
if (error) g_error_free(error);
if (error)
g_error_free(error);
return;
}