3D User Interface for Operating Systems

I just finished the final year project presentation for my bachelor’s degree in computer engineering. My project was a 3D natural user interface for operating systems. As I had to explain this over and over to many people throughout the year, I will follow the most common lines that I have repeated in order to do so.

You must have seen science fiction movies, such as Minority Report, Iron Man, Star Wars and yada yada. The futuristic computers and the technology you see in such movies, have one thing in common, when it comes to the user interface. Everything is 3D, and windows are objects – that you can hold, move around and throw around. The goal of this project is to make this form of HCI a reality, and it really isn’t all that hard to do so. For this, a specialized hardware – known as a depth sensor (for example, Kinect) is used. A PrimeSense Carmine 1.09 was used for this project.

More information and the source code of this project can be found on my github: https://github.com/ankitkv/NUI.
I will just showcase some of the results we have achieved from the work done by me and my teammates (Siddharth Kulkarni, Ronit Kulkarni, Humayun Mulla).

To communicate with the depth sensor, the OpenNI SDK is used. For this project, a library, called libnui is written, which handles all interaction with OpenNI. This library is responsible for getting the appropriate points, performing calibration calculations and sending the received points to a registered listener. Any program that wishes to use the NUI functionality must link with libnui. In this project, the calibration tool and the gesture plugin use libnui.

First off, since none of us own a 3D monitor, we had to resort to the classic way of 3D: anaglyph. Anaglyph requires you to wear red/cyan glasses, and the 3D image is split into two overlapping images, with red and cyan color components each. A compiz plugin for this had already been written by wodor. This plugin has mostly been taken as-is from compiz’s git repositories.


To convert the coordinates that the sensor sees into screen coordinates (including Z coordinate), calibration is required. Calibration calculates two matrices: a rotation matrix, to align the screen with the sensor’s Z axis, and a homography matrix, that maps the sensor’s world coordinates to the screen coordinates (approximately, sensor’s Z corresponds to screen’s X; sensor’s X corresponds to screen’s Z; and sensor’s Y corresponds to screen’s Y). The exact process of generation of these matrices can be found in calibration.cpp.

To actually perform the calibration process, a calib tool is provided which lets the user touch the four corners of the screen and tap the keys Q, W, A, S to map a particular point to the particular screen corner. The rotation and homography matrices generated by libnui using this data is stored by the calib tool in ~/.nuicalib.xml. The gesture plugin reads this file to obtain the calibration information.


libnui tracks a number of points close to the screen. Applications using libnui make use of these points as necessary. The gesture plugin uses these points to identify clicks on windows in 3D space and for the ability to hold and move windows. The calib tool provides a way to view all the tracked points by passing the argument debug (ie. ./calib debug), as shown below. The points are calculated from the borders of objects near the screen, so that windows know when a physical object is touching it, and in which way. In most cases, these physical objects would be fingers, however, you can actually use anything. After all, the real world doesn’t restrict object interaction to just fingers, and this project simulates the behavior of windows as if they existed in the physical world, in 3D space. :)


The overall system setup can be demonstrated by the following image (starring Ronit Kulkarni with anaglyph glasses). However, please note that this isn’t an accurate representation of the system. Practically, the depth sensor would be a little more to the right from the screen and a little backward.


So as I said, head over to github for more information and the source code for this project. :)

Unity integration for Pidgin

This post describes my experience and approach towards writing a plugin for pidgin that provides integration with Unity’s messaging menu and the launcher icon. It covers bits of libpurple’s API as well as Unity’s APIs used in implementation of this plugin. The plugin will be available in Pidgin 2.10.8 (stable) and Pidgin 3.0.0 (devel). :)

A little about Unity

Unity is a user interface for the GNOME desktop environment, developed by Canonical Ltd. It debuted with the netbook edition of Ubuntu 10.10 (Maverick Meerkat), and has been shipped out of the box for the desktop edition since Ubuntu 11.04 (Natty Narwhal). It’s goal is to make more efficient use of the screen and improve user interaction.

Personally, it’s initial release had me curious. Although equipped with a great deal of powerful software and excellent development tools, linux hasn’t really had the best graphical user interfaces available for it in the past, especially when compared to the likes of Mac OS X and Microsoft Windows. KDE came close to providing a competitive user experience, but I had always been more impressed by how well-written KDE was, than it’s actual usability. I tried to like it, I really did. But some things are just not meant to be. I found it suffocating to use. So when Unity claimed to be something that brought simplicity and beauty to the linux desktop, I welcomed the change. But after a bit of using it – I hated it. I found the product far from complete. It was buggy and slow and made me want to kill something. Around the same time, GNOME 3 was in the making, and after trying it out, well, I wanted to kill more things. It seemed everyone was conspiring against the usability of the desktop, in favor of shiny things.

Unity has come a long way since it’s first release. Many of the issues were fixed and the usability was enhanced in the following versions. I had decided to give Unity a shot again after the release of Ubuntu 11.10 (Oneiric Ocelot). It took a little time getting used to, but it wasn’t really all that bad once I did. The Unity dash is a very handy desktop search utility. The launcher is placed out of the way and programs can report their status via the launcher icon – which supports quicklists, and can show urgency, progress and counters. The application menus are merged with the title bar, which can be confusing at first, but you get used to it. It gives you a greater screen area and less clutter. The indicators provide a common landing ground for various notifications. Music and sound can be handled from the sound menu. E-mail, chat and other messaging applications can be accessed from the messaging menu, which also notifies the users of new/unread content.

Unity integration plugin for Pidgin

Pidgin is an instant messaging and chat client, and Unity provides some very neat features for users to use chat applications. Ubuntu arguably is the most popular linux distribution in home use today, and I noticed that pidgin makes no use of the features provided by Unity to enhance the chat experience. On my quest to study the pidgin codebase and work on it, I decided to implement the missing integration of Unity for pidgin. Not only would this help me gain a better insight into pidgin and libpurple, I also get to learn a bit about Unity’s API.

Pidgin is available for a number of operating systems, and people on various linux distributions with different desktop environments use it. Thus, Unity integration is best implemented as a plugin, that Unity users can load to take advantage of. This also gives them a choice to disable it completely if they wish – and in an open source world, more choice is always welcome. :)

The plugin deals with notifying the users of new messages via the messaging menu and the launcher icon. To alert the user when new messages arrive in a conversation, the function int alert(PurpleConversation *) is used. This adds the appropriate entries to the messaging menu, indicates the availability of new messages and updates the launcher icon count. Similarly, to reset a conversation to a read state when the conversation is brought into focus, the function void unalert(PurpleConversation *) is used, which removes the conversation from the messaging menu and decrements the launcher icon count. libpurple has it’s own signaling mechanism that is used for registering callbacks for alerting and unalerting a conversation on various events. For instance, when a new message is displayed, alert(conv) is called (signals "displayed-im-msg", "displayed-chat-msg").

Integration with the Messaging Menu


Messaging menu with unread message count

The messaging menu can be accessed from the mail indicator in the top-right corner of a Unity screen. It provides quick access to your messaging status and your chat applications, and also lists and notifies you of new messages. When a chat application is running, the menu is divided into:

  • Chat status section
    The chat status section appears only when an application is registered to use it. It contains radio items for “Available”, “Away”, “Busy”, “Invisible”, and “Offline”.
  • Application sections
    This is where the various chat applications are listed, and running applications are represented with an inward-pointing triangle at the leading edge of the menu item.
  • Sources
    A chat application may define sources, which are listed below the application name in the menu. Examples of sources are new messages or e-mails, accompanied by a count of unread messages, or the elapsed time since the message was recieved. When a new message arrives, the source may request to draw attention, in which case the indicator icon becomes blue to do so.
  • “Clear” item
    The “Clear” item of the menu appears at the very end, and it is used to clear off the new message state of the indicator. That is, turns it back to the default color from blue.

Messaging menu with elapsed time

As I mentioned, the chat status section is only visible when a chat application is registered to use it. For this, the “pidgin.desktop” file (which informs the desktop environment how the pidgin is to be handled with regard to menu placement, display, etc), must contain the key-value pair X-MessagingMenu-UsesChatSection=true. You may add this line to “pidgin.desktop” directly in /usr/share/applications/pidgin.desktop. However, if you build pidgin from source, a more permanent solution would be to add the line to the file “pidgin.desktop.in” in the root directory of the source code. The “pidgin.desktop” file is generated during a build based on the entries of this file, adding translations to the application name and comment.

A plugin written using the libpurple plugin API, needs an object of type PurplePluginInfo, which defines details about how libpurple should handle the plugin, such as the functions to be called when the plugin is loaded or unloaded, the plugin id, name, description and various other properties. For more information on plugin development for pidgin, see https://developer.pidgin.im/wiki/CHowTo/BasicPluginHowto. All pidgin plugins define their on-load function as gboolean plugin_load(PurplePlugin *) and on-unload function as gboolean plugin_unload(PurplePlugin *).

A pointer MessagingMenuApp *mmapp is used to represent an application in the messaging menu. To bind the application pidgin to mmapp, we need to initialize mmapp with pidgin’s desktop file id. Once initialized, we then register mmapp with the messaging menu. These steps form the initialization of the pidgin messaging menu integration, and are written in plugin_load(PurplePlugin *).

mmapp = messaging_menu_app_new("pidgin.desktop");
g_object_ref(mmapp); /* increment the reference count */

All the operations regarding the messaging menu entry for pidgin are done using mmapp. Finally, when the plugin is unloaded, we can assume the user no longer wants any kind of Unity integration. Thus, we need to completely remove the application from the messaging menu and destroy mmapp. These steps are written in plugin_unload(PurplePlugin *).

g_object_unref(mmapp); /* decrement the reference count */

When the status is changed from chat status section of the messaging menu, the signal "status-changed" is emitted from mmapp. A callback is connected to handle this signal in the plugin, which is void messaging_menu_status_changed(MessagingMenuApp *, MessagingMenuStatus, gpointer user_data). Here, we need to update pidgin’s chat status based on the status set from the messaging menu. One way I found to set a global chat status in pidgin, was by using a saved status. A PurpleStatusPrimitive primitive variable can hold a possible primitive chat status such as PURPLE_STATUS_AVAILABLEPURPLE_STATUS_AWAY, etc. We set this value based on the MessagingMenuStatus argument of the function, which holds values like MESSAGING_MENU_STATUS_AVAILABLEMESSAGING_MENU_STATUS_AWAY, etc. A saved status corresponding to the PurpleStatusPrimitive can be found, and then activated using purple_savedstatus_activate(saved_status).

saved_status = purple_savedstatus_find_transient_by_type_and_message(primitive, NULL);
if (saved_status == NULL)
	saved_status = create_transient_status(primitive, NULL);

Now, when the status is changed from pidgin, it also needs to be updated on the messaging menu. In fact, even when a status is changed from the messaging menu, pidgin needs to report back its new status before it is updated on the messaging menu. We did not have to worry about that above though, because a purple signal "savedstatus-changed" is emitted whenever a saved status is changed. All we have to do, is connect this purple signal to a callback void status_changed_cb(PurpleSavedStatus *saved_status), which will update the messaging menu with the new pidgin status. In this function, we set the value of MessagingMenuStatus status based on the primitive type of saved_status. Finally, the chat status on the messaging menu is updated by calling messaging_menu_app_set_status(mmapp, status).

status_changed_cb(PurpleSavedStatus *) also needs to be called when the plugin is loaded, so that the messaging menu is initialized with the current pidgin status. The following lines written in plugin_load(PurplePlugin *plugin) connect the purple signal "savedstatus-changed" to the callback, after calling it to initialize the messaging menu status.

void *savedstat_handle = purple_savedstatuses_get_handle();
PurpleSavedStatus *saved_status = purple_savedstatus_get_current();
purple_signal_connect(savedstat_handle, "savedstatus-changed", plugin, PURPLE_CALLBACK(status_changed_cb), NULL);

Whenever a new message comes, we want it to show up in the messaging menu. Below the application name, as new messages come, the unread conversations will listed along with either the count of unread messages, or the time since the last message. These list items are termed as sources. The messaging menu can list up to six sources. When this message arrives, we want the conversation to be added to the messaging menu as a source if it doesn’t already exist using void messaging_menu_app_append_source(MessagingMenuApp *mmapp, const gchar *id, GIcon *icon, const gchar *label). If it is already a source, it has to be updated with the new count or time. Sources can draw attention by calling messaging_menu_app_draw_attention(mmapp, id). This turns the messaging indicator blue to notify the user of new unread messages.

The number of unread messages are saved for each conversation as data for the PurpleConversation *conv with the key "unityinteg-message-count". When a new message arrives for a conversation, it’s "unityinteg-message-count" is incremented by one; and when it unalert(conv) is called, this data is reset to zero by calling purple_conversation_set_data(conv, "unityinteg-message-count", GINT_TO_POINTER(0)). The unread message count for any conversation conv can be read by calling GPOINTER_TO_INT(purple_conversation_get_data(conv, "unityinteg-message-count")).

Every source is uniquely identified by a string gchar *id. For the purpose of adding conversations as sources and finding conversations by source id, the id must have all the details required to get a unique PurpleConversation. The function PurpleConversation *purple_find_conversation_with_account(PurpleConversationType, const char *name, const PurpleAccount *) is provided by the libpurple API to find a unique conversation for the given conversation type, name and an account. PurpleAccount *purple_accounts_find(const char *name, const char *protocol_id) is provided to find an account for a given account name and purple protocol id. Overall, it turns out there are four values we need to have, to get to a unique conversation:

  1. The purple conversation type (denotes whether a conversation is an IM, chat, or something else)
  2. The conversation name
  3. The account name
  4. The purple protocol id

The function gchar *conversation_id(PurpleConversation *) generates an id for a conversation by concatenating these fields seperated by a ‘:’, to be used when a source is added or removed, or clicked. An example of a generated conversation id is: "1:NickServ:ankitkv@irc.freenode.net:prpl-irc".

I have written void messaging_menu_add_conversation(PurpleConversation *conv, gint count) to handle adding or updating conversations when new messages arrive. The id for the conversation is generated by gchar *conversation_id(PurpleConversation *). If a source with the generated id does not already exist, a new source is added by calling messaging_menu_app_append_source(mmapp, id, NULL, purple_conversation_get_title(conv)). Then depending on the user’s preference, the source is updated with a message count (by calling messaging_menu_app_set_source_count(mmapp, id, count)) or an elapsed time (by calling messaging_menu_app_set_source_time(mmapp, id, g_get_real_time())). Then, the source is set to draw attention and turn the messaging indicator blue by calling messaging_menu_app_draw_attention(mmapp, id). Ideally, a message source for a PurpleConversation *conv is added when alert(conv) is called.

The function void messaging_menu_remove_conversation(PurpleConversation *conv) calls messaging_menu_app_remove_source(mmapp, id) to remove a conversation from the messaging menu. This is done by unalert(conv), when an unread conversation is brought into focus by the user.

When a message source is clicked in the messaging menu, mmapp emits the signal "activate-source". This signal is handled by the callback void message_source_activated(MessagingMenuApp *mmapp, const gchar *id, gpointer user_data). When a message source is activated, the source is automatically removed from the messaging menu. The user now expects the conversation corresponding to the source to be presented in front of them. To do this, we need to find the conversation using the received source id. Parsing the id, we find the conversation as demonstrated:

gchar **sections = g_strsplit(id, ":", 0);
PurpleConversation *conv = NULL;
PurpleAccount *account;
PurpleConversationType conv_type;

char *type     = sections[0];
char *cname    = sections[1];
char *aname    = sections[2];
char *protocol = sections[3];

conv_type = type[0] - '0';
account = purple_accounts_find(aname, protocol);
conv = purple_find_conversation_with_account(conv_type, cname, account);

If conv is a valid conversation, we can now remove alerts from conv and bring the conversation into focus.

PidginWindow *purplewin = PIDGIN_CONVERSATION(conv)->win;
pidgin_conv_window_switch_gtkconv(purplewin, PIDGIN_CONVERSATION(conv));
gdk_window_focus(gtk_widget_get_window(purplewin->window), time(NULL));

For more information on the messaging menu API, please see http://developer.ubuntu.com/api/ubuntu-12.10/c/messaging-menu/MessagingMenuApp.html.

Integration with the Launcher


Unread messages/conversations in launcher icon

The Unity launcher supports quicklists, and can show urgency, progress and counters. It makes sense for pidgin to show a count of unread messages or conversations on the launcher. For more details about the count, the user can consult the messaging menu. However, the messaging menu is limited to showing a maximum of six sources, so if the number of unread conversations is more than that, the launcher counter can reflect it. Similar to mmapp for the messaging menu, the Unity launcher icon for an application is handled through a UnityLauncherEntry *launcher variable. This launcher entry can be retrieved by passing the desktop id to UnityLauncherEntry *unity_launcher_entry_get_for_desktop_id(char *id).

The launcher API is pretty straightforward and simple. Once you have launcher, you can use it to set a counter on the application icon. unity_launcher_entry_set_count_visible (UnityLauncherEntry *, gboolean visible) can be used to show or hide the count, based on the value passed to the variable visible (TRUE to show, FALSE to hide). unity_launcher_entry_set_count (UnityLauncherEntry *launcher, gint64 count) is used to set the counter to count for launcher.

I have written the function void update_launcher() to update the count on the launcher. It is called whenever alert(conv) or unalert(conv) is called for a PurpleConversation *conv. If the launcher count is disabled by the user in the plugin preferences, no count is displayed. Otherwise, depending on the preference, either the number of unread messages or the number of unread conversations is displayed. In case of unread messages, the count is calculated by iterating over all conversations returned by purple_get_conversations(), and showing the summation of every conversation’s "unityinteg-message-count" data. In case of unread conversations count, a value n_sources is displayed, which is updated whenever alert(conv) or unalert(conv) is called. If during alert(conv), the "unityinteg-message-count" data is 0, n_sources is incremented as we have a new unread conversation. And, during unalert(conv), n_sources is decremented if the "unityinteg-message-count" for conv was greater than 0.

For more information on the Unity launcher API, please see https://wiki.ubuntu.com/Unity/LauncherAPI.

Plugin Preferences

A preferences window is also provided to configure the behavior of the plugin. In a multiuser chatroom, users may not be interested in every message that is displayed, as it may not be intended for them. Thus, an option is provided to display chatroom message alerts only when someone in the chat says your username. The plugin preferences also lets you configure the behavior of Unity integration. The launcher icon integration can be disabled, or can be set to display the number of unread messages, or the number of unread conversations. The messaging menu integration can be configured to display unread message count for every conversation, or the elapsed time since the last message received in that conversation.


The plugin uses the variable gboolean alert_chat_nick to keep track of the preference for alerting only on mention of username in chatrooms. The variable gint launcher_count holds the behavior of the launcher icon. It can be either LAUNCHER_COUNT_DISABLELAUNCHER_COUNT_MESSAGES or LAUNCHER_COUNT_SOURCES. The variable gint messaging_menu_text holds the behavior of the messaging menu sources. It can be either MESSAGING_MENU_COUNT or MESSAGING_MENU_TIME.

libpurple stores preferences in a file ~/.purple/prefs.xml. The preferences API allows setting and getting of preference values based on a string key, which is a path to a nested <pref> tag in prefs.xml. The type for the values can be specified when the preferences are added and set. When the plugin is initialized, the required preference keys for the plugin are added to the preferences. If the specified preferences do not already exist in prefs.xml, they are added with the specified default values.

purple_prefs_add_int("/plugins/gtk/unityinteg/launcher_count", LAUNCHER_COUNT_SOURCES);
purple_prefs_add_int("/plugins/gtk/unityinteg/messaging_menu_text", MESSAGING_MENU_COUNT);
purple_prefs_add_bool("/plugins/gtk/unityinteg/alert_chat_nick", TRUE);

A structure PidginPluginUiInfo is used to define the UI information for a plugin. This value is specified in PurplePluginInfo‘s ui_info field so that a preferences screen can be created for the plugin. The first field of PidginPluginUiInfo is a function pointer to a function to be called to get the plugin’s preferences frame. In case of this plugin, this function is GtkWidget *get_config_frame(PurplePlugin *). This function creates the preferences window and attaches signals of the preferences being toggled to appropriate callbacks that modify the variables alert_chat_nick, launcher_count and messaging_menu_text.

alert_chat_nick is used when handling received chatroom messages to check if the username has been mentioned. If this preference is TRUE and the username has not been mentioned, we return from the callback function gboolean message_displayed_cb(PurpleAccount *, const char *who, char *message, PurpleConversation *, PurpleMessageFlags flags) without doing anything.

if ((purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT && alert_chat_nick && !(flags & PURPLE_MESSAGE_NICK)))
    return FALSE;

launcher_count is used in void update_launcher(), where the launcher is updated with a count depending on the user’s preferences.

guint count = 0;
GList *convs = NULL;
g_return_if_fail(launcher != NULL && launcher_count != LAUNCHER_COUNT_DISABLE);

if (launcher_count == LAUNCHER_COUNT_MESSAGES) {
	for (convs = purple_get_conversations(); convs != NULL; convs = convs->next) {
		PurpleConversation *conv = convs->data;
		count += GPOINTER_TO_INT(purple_conversation_get_data(conv,
} else {
	count = n_sources;

messaging_menu_text is used in void messaging_menu_add_conversation(PurpleConversation *, gint count) to either set the count or the time for a particular conversation source in the messaging menu.

if (messaging_menu_text == MESSAGING_MENU_TIME)
	messaging_menu_app_set_source_time(mmapp, id, g_get_real_time());
else if (messaging_menu_text == MESSAGING_MENU_COUNT)
	messaging_menu_app_set_source_count(mmapp, id, count);

Source code

Check out the full source code for more information on the plugin. If compiling manually on a version prior to 2.10.8, make sure your “pidgin.desktop” file has X-MessagingMenu-UsesChatSection=true if you wish to use the chat status section of the messaging menu. If you face any problems or find any bugs, please let me know. :)

Pidgin 2.10.x: http://hg.pidgin.im/pidgin/main/file/release-2.x.y/pidgin/plugins/unity.c
Pidgin 3.0.0: http://hg.pidgin.im/pidgin/main/file/default/pidgin/plugins/unity.c

Pidgin, and colored nickname logging

Pidgin (formerly Gaim) is a quite popular internet messenger. It is a graphical client that uses libpurple at it’s core. It supports various protocols for instant messaging and chat, such as IRC, XMPP (also used for Google Talk, Facebook Chat), Yahoo!, MSN etc. out of the box. I have been using pidgin on and off on linux for many years – long ago for Yahoo, then MSN, IRC and now for Google Talk and Facebook chat.

I have only recently started playing around with it’s source code. The project makes heavy use of GLib and comprises of libpurple (the backend that manages all your accounts, connections, buddies, logging, conversations and so on), pidgin (the graphical frontend based on GTK+) and finch (a text-based frontend based on ncurses). I have been studying the source code and through my journey, have learnt a lot and have written some small patches.

To add something to pidgin as a start, I decided to remedy a small drawback with the HTML logging that pidgin uses. In chatrooms such as IRC, pidgin shows every nickname with it’s own unique color. Some other IRC clients, notably XChat, also does this. During a conversation in a chatroom, this makes it very easy to discern who is talking even when users have very similar nicks. It also makes it easier on the cognitive mind to recognize users by their color instead of reading their nicks. However, users may often want to display and read these chat logs. Regardless of the format in which the log files are saved on disk, a log viewer must present the logs in a nice and friendly manner.

In Pidgin, the log viewer displays the logs in a proper and readable manner as expected, however, minus the colored nicknames. So just for the hack of it (sad pun?), I decided to write a logger that would provide users with more or less the same convenience that they get when witnessing a live chat with regard to colored nicknames. The initial problem was that the logging mechanism is implemented in libpurple, whereas the colored nicknames are implemented by pidgin, which uses libpurple as it’s core. The solution to this was fairly obvious – the logging would have to be implemented in pidgin, so that it could read the colored nicknames to log. Thus, I had to write a plugin for pidgin.

The one very important thing about the pidgin codebase that makes this possible is the ability to add custom loggers. All I had to do, was create my own logger, colornicks_logger, and then add it using purple_log_logger_add(colornicks_logger). libpurple uses an in-built HTML logger, which is used by pidgin for logging by default. The logger I was making – was basically just the HTML logger with a few new things. Therefore, most of the logger implementation was based on the HTML logger found in libpurple/log.c. The user can choose the logging mechanism from the preferences, and pidgin automatically shows all available loggers to choose from in this window. The logging format for pidgin is stored by the preference key "/purple/logging/format".


If you are loading this plugin, it is no mystery that you want to use the colored nicks logger. So when the plugin loads, it automatically sets your current logger to colored nicks logger, if it was previously set as the HTML logger. Unsurprisingly, when you unload the plugin, if your current logger was colored nicks logger, it sets back to the HTML logger. This behavior also makes sure that your preference of using the colored nicks logger sticks between sessions, since it is required to remove colored nicks logger as the current logger when unloading the plugin, to avoid problems regarding the missing logger. A problem I faced with this plugin at first, was that when it is unloaded (or pidgin is exited, which unloads the plugin first), and any conversation is open, pidgin crashed whenever the conversation was changed or closed. This was because every PurpleConversation keeps a pointer to its logger, which it uses for its logging purposes. Thus, even after the plugin was unloaded, it was possible that open conversations kept a pointer to the now-extinct colored nicks logger. However, the API does not provide any way to check which logger a conversation is currently using. The only function the API provided to was to close a conversation’s logs. Thus, before removing the logger during the plugin unload, I had to close the logs for every open PurpleConversation *conv using purple_conversation_close_logs(conv).

The HTML logger saves nickname colors as blue for the user, and red for everyone else. The colored nicks logger produces logs with colored nicknames as shown by the log viewer below:


I have written this plugin for Pidgin 3.0.0devel (from the pidgin-main repository of pidgin’s hg).

The source code for colornicks_logger can be found on my Github, and binaries are also linked below.
Source: https://github.com/ankitkv/PidginPlugins/blob/master/pidgin-plugins/colornicks_logger.c
Binary: http://nevitus.com/files/pidgin/3.0.0/colornicks_logger.so