What am I doing wrong with the notify-send command?

First the constructor (all C language btw):

	pid = forkexec
	(
		"/bin/notify-send",
		"-i=\"/usr/share/icons/hicolor/scalable/apps/xfce-battery-plugin.svg\"",
		"-a=mybatsig.elf",
		"-u=critical",
		"-t=5000", "-e",
		"{Alert}",
		message,
		NULL
	);

Which eventually makes it’s way to:

	pid = fork();
	if ( pid == 0 )
	{
		execv( exe, (char * const *)argv );
		return -1;
	}
	return pid;

I’ve tried every variant of defining summary I can think of (the man page contains 0 information on that, ought to be fixed) but I keep getting the message “No summary specified.” and a distinct lack of the notification itself. Someone tell me what I’m doing wrong with it please (btw I already sanitised the message so newlines etc would be translated to \n etc).

Edit: Just in case it held any relevance, the full vforkexec which forkexec passes onto:

pid_t vforkexec( str exe, va_list va )
{
	int pid = 0;
	va_list dup;
	str arg = NULL;
	str *argv = NULL;
	size_t i = 0, argc = 0, size = 0;
	va_copy( dup, va );
	if ( !print )
		print = void_print;
	print( exe );
	while (1)
	{
		arg = va_arg( dup, str );
		if ( !arg )
			break;
		print( " %s", arg );
		++argc;
	}
	va_end( dup );
	print( "\n" );
	size = (argc + 1) * sizeof(str);
	argv = alloca(size);
	memset((void*)argv, 0, size);
	while ( i < argc )
	{
		argv[i++] = va_arg( va, str );
		if ( !arg )
			break;
	}
	pid = fork();
	if ( pid == 0 )
	{
		execv( exe, (char * const *)argv );
		exit(EXIT_FAILURE);
		return -1;
	}
	return pid;
}

I don’t think this is a valid argument to notify-send

If you must go lowlevel - why don’t you use dbus?

https://specifications.freedesktop.org/notification-spec/latest/ar01s09.html

1 Like

From

https://man.archlinux.org/man/notify-send.1.en

-e, –transient

Show a transient notification. Transient notifications by-pass the server’s persistence capability, if any. And so it won’t be preserved until the user acknowledges it.

Edit: As for why I don’t use D-Bus, isn’t that a C# interface? I’m using C here, not C++ or any other extension of it, just C

man notify-send

:man_facepalming: - my glasses needs polish - oh wait I don’t have then on …

1 Like

Oh btw I have been printing the command generated also just in case, here’s the version where both the summary and body were in quotes:

/bin/notify-send -i="/usr/share/icons/hicolor/scalable/apps/xfce-battery-plugin.svg" -a=mybatsig.elf -u=critical -t=5000 "Alert" "Test alert"

If I recall correct - you use the equal sign when using --argument and no equal sign with -a

So your generated command should look like

/bin/notify-send -i "/usr/share/icons/hicolor/scalable/apps/xfce-battery-plugin.svg" -a mybatsig.elf -u critical -t 5000 "Alert" "Test alert"

image

Did you try running that command manually?

$ /bin/notify-send -i="/usr/share/icons/hicolor/scalable/apps/xfce-battery-plugin.svg" -a=mybatsig.elf -u=critical -t=5000 "Alert" "Test alert"
Unknown option -i=/usr/share/icons/hicolor/scalable/apps/xfce-battery-plugin.svg

Ah, that worked out, must be a quirk in geany’s terminal then, didn’t get the accompanying alarm though so something must be wrong there too:

int alertsfx(void)
{
	/* Cheat for now, will use OpenAL or something later to make it a built in
	 * feature */
	int pid = forkexec( "/bin/paplay", "/usr/share/sounds/" ALERT_SOUND, NULL );
	return (pid < 0) ? -1 : 0;
}

Any ideas?

Yes [root tip] [Utility Script] Charger Notifier - battery state

Should be trivial to modify removing the loop and run as a systemd timer unit

1 Like

Ended up posting this in the wrong place by mistake, copied over to here now:

Trying to avoid the shell here since I’ll have to implement these features manually in the library I’m making, right now I’m only outsourcing the notifications and sound effects because I need an alarm to stop myself overcharging my battery by accident. Later when I start implementing battery, sound & notification APIs into my library I’ll need to implement them in full C so shell was a non-starter for me. Besides witch to do it the shell way I need to use the watch command and save the previous battery state to files, in C I can just use sleep() and store the previous state in VRAM.

Edit: btw this app I made is meant to watch individual batteries, these are the options I have so far:

	str opts[] =
	{
		"Usage: mybatsig.elf [options]",
		"--id <positive_number>: "
			"Which battery this instance should be checking",
		"--max <positive_number>: "
			"Alert if still charging when charge is at least this high",
		"--min <positive_number>: "
			"Alert if still discharging when charge is at least this low",
		"--wait <positive_number>: "
			"How many seconds to sleep between each check",
		NULL
	};

Guess it wasn’t a quirk with geany’s terminal, something seemed to have got mis-passed onto execv, the notifications now work correctly, just trying to figure out why the sounds aren’t playing as they should

Just stumpled on this and your little project came to mind

Either I’m failing to see the option/s for it or it doesn’t support an “almost full” type warning (in my case I set it to 80%) to indicate that should stop charging the battery to extend it’s lifespan, thank you for posting it anyways, now I at least know that it’s libnotify I need to remove external command dependencies altogether.

Libnotify can also do sound. This is a slightly expanded version of the example from https://wiki.archlinux.org/title/Desktop_notifications#C.

See also Libnotify Documentation and Desktop Notifications Specification.

// Compile with: gcc -o notify `pkg-config --cflags --libs libnotify` notify.c
#include <libnotify/notify.h>

// https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
// https://specifications.freedesktop.org/sound-naming-spec/sound-naming-spec-latest.html
//
// File paths also work (for sound change the "sound-name" hint to "sound-file") but
// standard names are preferred because those will match the user's desktop theme
#define ALERT_ICON  "battery-low"
#define ALERT_SOUND "battery-low"

int main()
{
  notify_init("mybatsig.elf");

  NotifyNotification *alert = notify_notification_new("Alert", "Test Alert", ALERT_ICON);
  notify_notification_set_hint_string(alert, "sound-name", ALERT_SOUND);
  notify_notification_set_urgency(alert, NOTIFY_URGENCY_CRITICAL);
  notify_notification_set_timeout(alert, 5000);
  notify_notification_show(alert, NULL);
  g_object_unref(G_OBJECT(alert));

  notify_uninit();
  return 0;
}

Couple of things to be aware of;

  • The notification server may ignore the timeout if NOTIFY_URGENCY_CRITICAL (because if it’s critical then it shouldn’t disappear without user intervention).

  • The notification server may not support sound hints (KDE doesn’t) and so ignore them. You can test for sound capability like this (handling it not being available is left as an exercise for the reader);

GList *caps = notify_get_server_caps();
bool has_sound = !!g_list_find_custom(caps, "sound", (GCompareFunc)g_ascii_strcasecmp);
g_list_free_full(caps, g_free);