First commit
5 files changed, 433 insertions(+), 0 deletions(-)

A => .hgignore
A => README.md
A => inc/notify.h
A => meson.build
A => src/notify.c
A => .hgignore +6 -0
@@ 0,0 1,6 @@ 
+^\.cproject$
+^\.project$
+^\.settings$
+^\.hgrepos$
+^build$
+^Debug$

          
A => README.md +16 -0
@@ 0,0 1,16 @@ 
+# libnotif
+libnotif is a library providing a rudimentary notificatoin daemon
+
+## Dependencies
+	libglib2.0-dev
+	pkg-config
+	meson
+## Building
+	hg clone https://hg.sr.ht/~scoopta/libnotif
+	cd libnotif
+	meson build
+	ninja -C build
+## Installing
+	sudo ninja -C build install
+## Uninstalling
+	sudo ninja -C build uninstall

          
A => inc/notify.h +27 -0
@@ 0,0 1,27 @@ 
+/*
+ *  Copyright (C) 2020 Scoopta
+ *  This file is part of libnotif
+ *  libnotif is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    libnotif 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with libnotif.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NOTIFY_H
+#define NOTIFY_H
+
+void libnotif_init(void);
+
+char** libnotif_get_info(void);
+
+void libnotif_register_cb(void (*cb)(const char* app_name, const char* summary, const char* body));
+
+#endif

          
A => meson.build +12 -0
@@ 0,0 1,12 @@ 
+project('notif', 'c', default_options : ['buildtype=release', 'warning_level=2'])
+
+inc = include_directories('inc')
+gio = dependency('gio-2.0')
+
+shared_library(
+	meson.project_name(),
+	'src/notify.c',
+	include_directories : inc,
+	dependencies : gio,
+	install : true,
+)

          
A => src/notify.c +372 -0
@@ 0,0 1,372 @@ 
+/*
+ *  Copyright (C) 2020 Scoopta
+ *  This file is part of libnotif
+ *  libnotif is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    libnotif 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with libnotif.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <notify.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+#include <sys/wait.h>
+
+#include <gio/gio.h>
+
+static bool running = false;
+static char* notif_data[3];
+static uint32_t id;
+static void (*callback)(const char* app_name, const char* summary, const char* body) = NULL;
+
+static void dbus_method_call(GDBusConnection* connection, const gchar* sender, const gchar* object_path, const gchar* interface_name, const gchar* method_name, GVariant* parameters, GDBusMethodInvocation* invocation, gpointer data) {
+	(void) sender;
+	(void) data;
+	if(strcmp(method_name, "GetServerInformation") == 0) {
+		GVariant* ret = g_variant_new("(ssss)", "libnotif", "Scoopta", "0.0.1", "1.2");
+		g_dbus_method_invocation_return_value(invocation, ret);
+	} else if(strcmp(method_name, "Notify") == 0) {
+		const gchar* app_name, *app_icon, *summary, *body;
+		uint32_t replaces_id;
+		GVariantIter* actions;
+		GVariant* hints;
+		int32_t expire_timeout;
+		g_variant_get(parameters, "(&su&s&s&sasa{sv}i)", &app_name, &replaces_id, &app_icon, &summary, &body, &actions, &hints, &expire_timeout);
+		g_variant_iter_free(actions);
+		if(notif_data[0] != NULL) {
+			free(notif_data[0]);
+		}
+		if(notif_data[1] != NULL) {
+			free(notif_data[1]);
+		}
+		if(notif_data[2] != NULL) {
+			free(notif_data[2]);
+		}
+		notif_data[0] = strdup(app_name);
+		notif_data[1] = strdup(summary);
+		notif_data[2] = strdup(body);
+		if(callback != NULL) {
+			callback(app_name, summary, body);
+		}
+		GVariant* ret = g_variant_new("(u)", ++id);
+		g_dbus_method_invocation_return_value(invocation, ret);
+	} else if(strcmp(method_name, "GetCapabilities") == 0) {
+		GVariantBuilder* builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
+		g_variant_builder_add(builder, "s", "body");
+		g_variant_builder_add(builder, "s", "actions");
+		GVariant* ret = g_variant_new("(as)", builder);
+		g_variant_builder_unref(builder);
+		g_dbus_method_invocation_return_value(invocation, ret);
+	} else if(strcmp(method_name, "CloseNotification") == 0) {
+		uint32_t id;
+		g_variant_get(parameters, "(u)", &id);
+		GVariant* param = g_variant_new("(uu)", id, 3);
+		g_dbus_method_invocation_return_value(invocation, NULL);
+		g_dbus_connection_emit_signal(connection, NULL, object_path, interface_name, "NotificationClosed", param, NULL);
+	}
+}
+
+static void name_acquired(GDBusConnection* connection, const gchar* name, gpointer data) {
+	(void) name;
+	(void) data;
+
+	//GetCapabilities return
+	GDBusArgInfo* get_capabilities_ret = malloc(sizeof(GDBusArgInfo));
+	get_capabilities_ret->ref_count = -1;
+	get_capabilities_ret->name = NULL;
+	get_capabilities_ret->signature = "as";
+	get_capabilities_ret->annotations = NULL;
+
+	//GetCapabilities args
+	GDBusArgInfo** get_capabilities_args = calloc(2, sizeof(GDBusArgInfo*));
+	get_capabilities_args[0] = get_capabilities_ret;
+	get_capabilities_args[1] = NULL;
+
+	//GetCapabilities method
+	GDBusMethodInfo* get_capabilities = malloc(sizeof(GDBusMethodInfo));
+	get_capabilities->ref_count = -1;
+	get_capabilities->name = "GetCapabilities";
+	get_capabilities->in_args = NULL;
+	get_capabilities->out_args = get_capabilities_args;
+	get_capabilities->annotations = NULL;
+
+	//Notify return
+	GDBusArgInfo* notify_ret = malloc(sizeof(GDBusArgInfo));
+	notify_ret->ref_count = -1;
+	notify_ret->name = NULL;
+	notify_ret->signature = "u";
+	notify_ret->annotations = NULL;
+
+	//Notify out args
+	GDBusArgInfo** notify_out_args = calloc(2, sizeof(GDBusArgInfo*));
+	notify_out_args[0] = notify_ret;
+	notify_out_args[1] = NULL;
+
+	//Notify method app_name argument
+	GDBusArgInfo* notify_app_name = malloc(sizeof(GDBusArgInfo));
+	notify_app_name->ref_count = -1;
+	notify_app_name->name = "app_name";
+	notify_app_name->signature = "s";
+	notify_app_name->annotations = NULL;
+
+	//Notify method replaces_id argument
+	GDBusArgInfo* notify_replaces_id = malloc(sizeof(GDBusArgInfo));
+	notify_replaces_id->ref_count = -1;
+	notify_replaces_id->name = "replaces_id";
+	notify_replaces_id->signature = "u";
+	notify_replaces_id->annotations = NULL;
+
+	//Notify method app_icon argument
+	GDBusArgInfo* notify_app_icon = malloc(sizeof(GDBusArgInfo));
+	notify_app_icon->ref_count = -1;
+	notify_app_icon->name = "app_icon";
+	notify_app_icon->signature = "s";
+	notify_app_icon->annotations = NULL;
+
+	//Notify method summary argument
+	GDBusArgInfo* notify_summary = malloc(sizeof(GDBusArgInfo));
+	notify_summary->ref_count = -1;
+	notify_summary->name = "summary";
+	notify_summary->signature = "s";
+	notify_summary->annotations = NULL;
+
+	//Notify method body argument
+	GDBusArgInfo* notify_body = malloc(sizeof(GDBusArgInfo));
+	notify_body->ref_count = -1;
+	notify_body->name = "body";
+	notify_body->signature = "s";
+	notify_body->annotations = NULL;
+
+	//Notify method actions argument
+	GDBusArgInfo* notify_actions = malloc(sizeof(GDBusArgInfo));
+	notify_actions->ref_count = -1;
+	notify_actions->name = "actions";
+	notify_actions->signature = "as";
+	notify_actions->annotations = NULL;
+
+	//Notify method hints argument
+	GDBusArgInfo* notify_hints = malloc(sizeof(GDBusArgInfo));
+	notify_hints->ref_count = -1;
+	notify_hints->name = "hints";
+	notify_hints->signature = "a{sv}";
+	notify_hints->annotations = NULL;
+
+	//Notify method expire_timeout argument
+	GDBusArgInfo* notify_expire_timeout = malloc(sizeof(GDBusArgInfo));
+	notify_expire_timeout->ref_count = -1;
+	notify_expire_timeout->name = "expire_timeout";
+	notify_expire_timeout->signature = "i";
+	notify_expire_timeout->annotations = NULL;
+
+	//Notify method args
+	GDBusArgInfo** notify_args = calloc(9, sizeof(GDBusArgInfo*));
+	notify_args[0] = notify_app_name;
+	notify_args[1] = notify_replaces_id;
+	notify_args[2] = notify_app_icon;
+	notify_args[3] = notify_summary;
+	notify_args[4] = notify_body;
+	notify_args[5] = notify_actions;
+	notify_args[6] = notify_hints;
+	notify_args[7] = notify_expire_timeout;
+	notify_args[8] = NULL;
+
+	//Notify method
+	GDBusMethodInfo* notify = malloc(sizeof(GDBusMethodInfo));
+	notify->ref_count = -1;
+	notify->name = "Notify";
+	notify->in_args = notify_args;
+	notify->out_args = notify_out_args;
+	notify->annotations = NULL;
+
+	//CloseNotification method notification_id argument
+	GDBusArgInfo* close_notification_id = malloc(sizeof(GDBusArgInfo));
+	close_notification_id->ref_count = -1;
+	close_notification_id->name = "id";
+	close_notification_id->signature = "u";
+	close_notification_id->annotations = NULL;
+
+	//CloseNotification method args
+	GDBusArgInfo** close_notification_args = calloc(2, sizeof(GDBusArgInfo*));
+	close_notification_args[0] = close_notification_id;
+	close_notification_args[1] = NULL;
+
+	//CloseNotification method
+	GDBusMethodInfo* close_notification = malloc(sizeof(GDBusMethodInfo));
+	close_notification->ref_count = -1;
+	close_notification->name = "CloseNotification";
+	close_notification->in_args = close_notification_args;
+	close_notification->out_args = NULL;
+	close_notification->annotations = NULL;
+
+	//GetServerInformation name argument
+	GDBusArgInfo* get_server_information_name = malloc(sizeof(GDBusArgInfo));
+	get_server_information_name->ref_count = -1;
+	get_server_information_name->name = "name";
+	get_server_information_name->signature = "s";
+	get_server_information_name->annotations = NULL;
+
+	//GetServerInformation vendor argument
+	GDBusArgInfo* get_server_information_vendor = malloc(sizeof(GDBusArgInfo));
+	get_server_information_vendor->ref_count = -1;
+	get_server_information_vendor->name = "vendor";
+	get_server_information_vendor->signature = "s";
+	get_server_information_vendor->annotations = NULL;
+
+	//GetServerInformation version argument
+	GDBusArgInfo* get_server_information_version = malloc(sizeof(GDBusArgInfo));
+	get_server_information_version->ref_count = -1;
+	get_server_information_version->name = "version";
+	get_server_information_version->signature = "s";
+	get_server_information_version->annotations = NULL;
+
+	//GetServerInformation spec_version argument
+	GDBusArgInfo* get_server_information_spec_version = malloc(sizeof(GDBusArgInfo));
+	get_server_information_spec_version->ref_count = -1;
+	get_server_information_spec_version->name = "spec_version";
+	get_server_information_spec_version->signature = "s";
+	get_server_information_spec_version->annotations = NULL;
+
+	//GetServerInformation args
+	GDBusArgInfo** get_server_information_args = calloc(5, sizeof(GDBusArgInfo*));
+	get_server_information_args[0] = get_server_information_name;
+	get_server_information_args[1] = get_server_information_vendor;
+	get_server_information_args[2] = get_server_information_version;
+	get_server_information_args[3] = get_server_information_spec_version;
+	get_server_information_args[4] = NULL;
+
+	//GetServerInformation method
+	GDBusMethodInfo* get_server_information = malloc(sizeof(GDBusMethodInfo));
+	get_server_information->ref_count = -1;
+	get_server_information->name = "GetServerInformation";
+	get_server_information->in_args = NULL;
+	get_server_information->out_args = get_server_information_args;
+	get_server_information->annotations = NULL;
+
+	//DBus methods
+	GDBusMethodInfo** methods = calloc(5, sizeof(GDBusMethodInfo*));
+	methods[0] = get_capabilities;
+	methods[1] = notify;
+	methods[2] = close_notification;
+	methods[3] = get_server_information;
+	methods[4] = NULL;
+
+	//NotificationClosed id argument
+	GDBusArgInfo* notification_closed_id = malloc(sizeof(GDBusArgInfo));
+	notification_closed_id->ref_count = -1;
+	notification_closed_id->name = "id";
+	notification_closed_id->signature = "u";
+	notification_closed_id->annotations = NULL;
+
+	//NotificationClosed reason argument
+	GDBusArgInfo* notification_closed_reason = malloc(sizeof(GDBusArgInfo));
+	notification_closed_reason->ref_count = -1;
+	notification_closed_reason->name = "reason";
+	notification_closed_reason->signature = "u";
+	notification_closed_reason->annotations = NULL;
+
+	//NotificationClosed args
+	GDBusArgInfo** notification_closed_args = calloc(3, sizeof(GDBusArgInfo*));
+	notification_closed_args[0] = notification_closed_id;
+	notification_closed_args[1] = notification_closed_reason;
+	notification_closed_args[2] = NULL;
+
+	//NotificationClosed signal
+	GDBusSignalInfo* notification_closed = malloc(sizeof(GDBusSignalInfo));
+	notification_closed->ref_count = -1;
+	notification_closed->name = "NotificationClosed";
+	notification_closed->args = notification_closed_args;
+	notification_closed->annotations = NULL;
+
+	//ActionInvoked id argument
+	GDBusArgInfo* action_invoked_id = malloc(sizeof(GDBusArgInfo));
+	action_invoked_id->ref_count = -1;
+	action_invoked_id->name = "id";
+	action_invoked_id->signature = "u";
+	action_invoked_id->annotations = NULL;
+
+	//ActionInvoked action_key argument
+	GDBusArgInfo* action_invoked_action_key = malloc(sizeof(GDBusArgInfo));
+	action_invoked_action_key->ref_count = -1;
+	action_invoked_action_key->name = "action_key";
+	action_invoked_action_key->signature = "s";
+	action_invoked_action_key->annotations = NULL;
+
+	//ActionInvoked args
+	GDBusArgInfo** action_invoked_args = calloc(3, sizeof(GDBusArgInfo*));
+	action_invoked_args[0] = action_invoked_id;
+	action_invoked_args[1] = action_invoked_action_key;
+	action_invoked_args[2] = NULL;
+
+	//ActionInvoked signal
+	GDBusSignalInfo* action_invoked = malloc(sizeof(GDBusSignalInfo));
+	notification_closed->ref_count = -1;
+	notification_closed->name = "ActionInvoked";
+	notification_closed->args = action_invoked_args;
+	notification_closed->annotations = NULL;
+
+	//DBus signals
+	GDBusSignalInfo** signals = calloc(3, sizeof(GDBusSignalInfo*));
+	signals[0] = notification_closed;
+	signals[1] = action_invoked;
+	signals[2] = NULL;
+
+	GDBusInterfaceInfo* interface = malloc(sizeof(GDBusInterfaceInfo));
+	interface->ref_count = -1;
+	interface->name = "org.freedesktop.Notifications";
+	interface->methods = methods;
+	interface->signals = signals;
+	interface->signals = NULL;
+	interface->properties = NULL;
+	interface->annotations = NULL;
+
+	GDBusInterfaceVTable vtable = {
+		.method_call = dbus_method_call,
+		.get_property = NULL,
+		.set_property = NULL
+	};
+
+	g_dbus_connection_register_object(connection, "/org/freedesktop/Notifications", interface, &vtable, NULL, NULL, NULL);
+	free(signals);
+	free(action_invoked);
+	free(action_invoked_args);
+	free(action_invoked_action_key);
+	free(action_invoked_id);
+	free(notification_closed);
+	free(notification_closed_args);
+	free(notification_closed_reason);
+	free(notification_closed_id);
+}
+
+static void name_lost(GDBusConnection* connection, const gchar* name, gpointer data) {
+	(void) connection;
+	(void) data;
+	fprintf(stderr, "Lost connection for %s\n", name);
+}
+
+void libnotif_init(void) {
+	if(!running) {
+		running = true;
+		g_bus_own_name(G_BUS_TYPE_SESSION, "org.freedesktop.Notifications", G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE, NULL, name_acquired, name_lost, NULL, NULL);
+	}
+}
+
+char** libnotif_get_info(void) {
+	return notif_data;
+}
+
+void libnotif_register_cb(void (*cb)(const char* app_name, const char* summary, const char* body)) {
+	callback = cb;
+}