alexh’s blog

New Ubuntu ThinkPad Notification Program

Posted on: May 3, 2009

I’ve changed the program to also notify of changes in brightness for ThinkPads that have that problem, too. If the brightness node in ibm/acpi does not exist, then nothing is done for brightness; this way the program remains 100% compatible with T60 and similar ThinkPads.

To use this program, just: use the following steps

  1. sudo apt-get install libnotify-dev
  2. paste the Makefile below into a file called Makefile
  3. paste the code below (notify.c) into a file called notify.c in the same directory as the Makefile
  4. Type make in that same directory
  5. Execute ./notify

This is the Makefile, but keep in mind these two things:
1) the line starting with ${CC} MUST begin with a tab.
2) feel free to remove -g (create debug info) and change -O0 to -O3 to optmize properly.

GTKPATH = `pkg-config --cflags --libs gtk+-2.0`
CC = gcc
LIBS = -lnotify
OUTPUT = -o notify

all:
	${CC} -O0 -g -Wall ${GTKPATH} notify.c ${LIBS} ${OUTPUT}

And this is the updated program (notify.c). I hope that it is pasted correctly here; if not please leave a comment and I’ll try to fix the upload asap.

/*
 * Copyright (c) 2009 Alex Hornung.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <stdio.h>
#include <stdlib.h>

#include <string.h>

#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>

#include <sys/types.h>

#include <sys/stat.h>

#include<libnotify/notify.h>

#define VOLUME_NODE 		"/proc/acpi/ibm/volume"
#define BRIGHTNESS_NODE		"/proc/acpi/ibm/brightness"
#define BRIGHTNESS_NEW_NODE	"/proc/acpi/video/VID/LCD0/brightness"

#define NOTIFICATION_TIMEOUT 	500

#define SLEEP_MICROSECONDS	250000 //250 ms

void show_notify_volume(gint volume, int mute)

{

	char		name[] 		= "Volume";

	static gint 	volume_old 	= 255;

	static int 	mute_old 	= -1;

	NotifyNotification *not;

	if ((mute_old == mute) && (volume_old == volume))

		return;

	if (!notify_init(name)) {

		printf("no good at notify_init()\n");
		return;
	}

	if (mute) {

		not = notify_notification_new(name, NULL, "notification-audio-volume-muted", NULL);

	} else {
		if (volume > 10)

			not = notify_notification_new(name, NULL, "notification-audio-volume-high", NULL);

		else if (volume > 4)
			not = notify_notification_new(name, NULL, "notification-audio-volume-medium", NULL);

		else if (volume > 0)
			not = notify_notification_new(name, NULL, "notification-audio-volume-low", NULL);

		else
			not = notify_notification_new(name, NULL, "notification-audio-volume-off", NULL);

	}

	notify_notification_set_hint_int32(not, "value", volume<<3);
	notify_notification_set_hint_string(not, "x-canonical-private-synchronous", "");

	notify_notification_set_timeout(not, NOTIFICATION_TIMEOUT);
	notify_notification_show(not, NULL);

	g_object_unref(G_OBJECT(not));

	volume_old = volume;

	mute_old = mute;
}


void show_notify_brightness(gint brightness)

{
	char		name[] 		= "Brightness";
	
	static gint 	brightness_old 	= 255;

	NotifyNotification *not;

	if ((brightness_old == brightness))

		return;

	if (!notify_init(name)) {

		printf("no good at notify_init()\n");
		return;
	}

	if (brightness > 70)

		not = notify_notification_new(name, NULL, "notification-display-brightness-high", NULL);

	else if (brightness > 40)
		not = notify_notification_new(name, NULL, "notification-display-brightness-medium", NULL);

	else
		not = notify_notification_new(name, NULL, "notification-display-brightness-low", NULL);

	notify_notification_set_hint_int32(not, "value", brightness);
	notify_notification_set_hint_string(not, "x-canonical-private-synchronous", "");

	notify_notification_set_timeout(not, NOTIFICATION_TIMEOUT);
	notify_notification_show(not, NULL);

	g_object_unref(G_OBJECT(not));

	brightness_old = brightness;

}


int main(int argc, char *argv[])

{
	int 	fd,
		fd_brightness,
		fd_new_brightness,
		nread,
	 	mute;

	gint 	volume,
		brightness;

	char 	buf[1024];

	char 	*bufptr,
		*offset;

	gtk_init(&argc,&argv);

	daemon(0, 1);

	if ( (fd = open(VOLUME_NODE, O_RDONLY)) == -1 ) {

		perror("open");
		exit(1);
	}

	if ( (fd_brightness = open(BRIGHTNESS_NODE, O_RDONLY)) == -1 ) {

		perror("could not open brightness stuff");
		printf("ignoring...\n");
	}

	if ( (fd_new_brightness = open(BRIGHTNESS_NEW_NODE, O_RDONLY)) == -1 ) {

		perror("could not open new brightness stuff");
		printf("ignoring...\n");
	}

	for (;;) {
		usleep(SLEEP_MICROSECONDS);

		/* VOLUME STUFF */
		if ( (nread = read(fd, buf, 1024)) > 1) {

			lseek(fd, 0, SEEK_SET);
			buf[nread] = NULL;

			bufptr = buf;
			offset = strchr(bufptr, '\n');

			if (offset != NULL) {
				for (; !isdigit(*bufptr) && (*bufptr != NULL); bufptr++);

				if (*bufptr == NULL) {
					printf("crap occured\n");

					continue;
				}
				volume = g_ascii_strtoull(bufptr, NULL, 10);

				for (offset++; (*offset != 'o') && (*offset != NULL); offset++);

				if (*offset == NULL) {
					printf("more crap occured\n");

					continue;
				}

				(*(offset + 1) == 'n') ? (mute = 1) : (mute = 0);

				show_notify_volume(volume, mute);
			}
		}

		/* BRIGHTNESS STUFF */
		if ( fd_brightness != -1 )

		{
			if ( (nread = read(fd_brightness, buf, 1024)) > 1) {

				lseek(fd_brightness, 0, SEEK_SET);
				buf[nread] = NULL;

				bufptr = buf;

				for (; !isdigit(*bufptr) && (*bufptr != NULL); bufptr++);

				if (*bufptr == NULL) {
					printf("brightness crap occured\n");

					continue;
				}

				brightness = g_ascii_strtoull(bufptr, NULL, 10);

				show_notify_brightness(brightness*14);
			}
		}

		/* NEW BRIGHTNESS STUFF */
		if ( fd_new_brightness != -1 )

		{
			if ( (nread = read(fd_new_brightness, buf, 1024)) > 1) {

				lseek(fd_new_brightness, 0, SEEK_SET);
				buf[nread] = NULL;

				bufptr = strchr(buf, '\n');

				if (bufptr != NULL) {
					for (; !isdigit(*bufptr) && (*bufptr != NULL); bufptr++);

					if (*bufptr == NULL) {
						printf("brightness new crap occured\n");

						continue;
					}

					brightness = g_ascii_strtoull(bufptr, NULL, 10);

					show_notify_brightness(brightness);
				}
			}
		}

	}	

	//close(fd);

	//close(fd_brightness);

	return 0;
}

Leave a comment