[GSoC] GObjectification of PurpleAccount and PurpleConversation, June 30, 2013

Ankit Vani a at nevitus.org
Sun Jun 30 16:26:14 EDT 2013

Hi everyone.

I had been working on some of the bigger components of libpurple, and so I
couldn't post an update sooner. Anyways, here are the details of my progress of
GObjectification since my last update :)

My repo: http://hg.pidgin.im/soc/2013/ankitkv/gobjectification
(branch soc.2013.gobjectification)

NOTE: file.[ch] is used here to denote both file.c and file.h.


Account object hierarchy:


Accounts subsystem:
To provide a seperation between the account object and the accounts subsystem,
the files for the object and the subsystem have been seperated. The account
object and it's API (purple_account_*) can be found in account.[ch], whereas the
subsystem API (purple_accounts_*) can be found in accounts.[ch].

Regarding privacy:
The current privacy implementation (ie. privacy.[ch]) basically only included
methods of PurpleAccount, that also used the private members of PurpleAccount
such as the permit list and the deny list. Thus, I decided it makes sense that
these methods be moved to PurpleAccount.
- privacy.[ch] files have been deleted, and the purple_privacy_* functions are
  now purple_account_privacy_* functions.
- PurplePrivacyType is now PurpleAccountPrivacyType.
- purple_account_privacy_allow() and purple_account_privacy_deny() used the
  arguments 'local' and 'restore', that were always passed as FALSE - and there
  was no reason to ever use TRUE. Thus, these arguments have been removed.
  purple_account_privacy_[permit,deny]_[add,remove]() can be used to make local
  privacy changes.
- Added purple_account_privacy_get_permitted() and
  purple_account_privacy_get_denied() functions to return the permit and deny
  lists. This is necessary as the members of PurpleAccount are no longer
  directly accessible, and have been moved to the private account structure

Other changes:
- PurpleAccountSetting had a PurplePrefType field and a union field to hold
  generic values. These fields have been removed and GValue is used instead.
  Eventually, it would be possible to simplify PurpleType, PurpleSubType,
  PurplePrefType and PurpleValue by using GType and GValue instead, once
  GObjectification is done.
- Renamed alias to private_alias. The functions purple_account_[get,set]_alias
  have been renamed to purple_account[get,set]_private_alias. This provides
  clear distinction between private_alias and public_alias.


Conversation objects hierarchy:

  +----PurpleConversation     (abstract type denoting any type of conversation)
        +----PurpleIMConversation    (IM's)
        +----PurpleChatConversation  (Multiuser chats)

PurpleConversation is now a abstract type, and cannot be instantiated directly.
A conversation must either be an IM conversation or a Chat conversation.
A conversation can be created as either an IM, or a chat:
- purple_im_conversation_new(account, name) returns a PurpleIMConversation *
- purple_chat_conversation_new(account, name) returns a PurpleChatConversation *

PurpleConversationType has been removed. If, for instance, you wish to know
whether a given conversation is an IM, the following can be done:

PurpleConversation *conv

    /* conv is an IM */
    /* conv is a chat */

used. However, PURPLE_CONV_TYPE_ANY was used to include any kind of conversation
in functions that filtered a specific type. Such functions now appear in three
forms for simplicity. For example:
- purple_conversations_find_with_account(name, account)
                                                  returns a PurpleConversation *
- purple_conversations_find_im_with_account(name, account)
                                                returns a PurpleIMConversation *
- purple_conversations_find_chat_with_account(name, account)
                                              returns a PurpleChatConversation *

If however, you wish to use a type parameter in your function, you can use
GType type, and pass in PURPLE_TYPE_IM_CONVERSATION,
conversation respectively.

Arguments and return types that used 'PurpleConversation *' throughout
libpurple, pidgin and finch have been changed to either 'PurpleIMConversation *'
or 'PurpleChatConversation *' wherever applicable, instead of generic
'PurpleConversation *'. However, where any kind of conversation may be used, the
abstract type PurpleConversation is to be used.
- This provides for better compile-time checking - the compiler warns you if you
  are providing a wrong type of conversation.
- It becomes obvious what kind of conversation a function is expecting or
  returns, and a type check is no longer necessary in most cases.

Functions and enums have been renamed to use the appropriate object names that
they belong to. Some examples:
- purple_conv_* are purple_conversation_*
- purple_conv_im_* are purple_im_conversation_*
- purple_conv_chat_* are purple_chat_conversation_*
- purple_conversations_* denote the functions that belong to the subsystem
- PurpleTypingState is now PurpleIMTyping state

Notable changes in the conversations API:
- purple_conversations_get_all() returns a GList of all conversations
- purple_conversations_get_ims() returns a GList of all IM's
- purple_conversations_get_chats() returns a GList of all chats
- purple_conversations_add() adds a conversation to the conversations list, and
  to either IM's or chats depending on it's type.
- purple_conversations_remove() removes a conversation from the lists

Virtual methods:

purple_conv_im_write() and purple_conv_chat_write() are now a virtual
PurpleConversation method. So, using purple_conversation_write_message() on your
conversation will invoke the write method of whatever type your conversation is

Similarly, if in the future, an existing function has to provide different
behavior depending on the conversation type, an existing purple_conversation_
method can be made virtual, without having to change the rest of the codebase.


As with accounts, a seperate conversations.[ch] is provided for the subsystem,
and conversation.[ch] for the PurpleConversation base object.
conversationtypes.[ch] is created for IM's and chats.

This is because many conversation-related files would be floating around in the
main libpurple directory if every object got it's own files. And my mentor,
Ethan, suggested making subdirectories slows down the build considerably. Also,
if we started making subdirectories, as GObjectification of libpurple continues,
more and more subdirectories would start coming up. Thus, I have attempted to
keep the file system as flat as possible.

If you have a better idea for organization of the various conversation objects
(base type, IM, chat, chat user), please let me know. Or if you have a better
name for conversationtypes.[ch] :P

Some other stuff:
- PurpleConversationMessage is a GBoxed structure.
- Renamed purple_chat_conversation_find_user to a more appropriate
  purple_chat_conversation_has_user as it returns boolean
- Changed the argument of chat_update_user of PurpleConversationUiOps to
  PurpleChatUser *. Similarly, replaced chatname, buddyname arguments of
  "chat-buddy-flags" signal with PurpleChatUser *
- Removed purple_chat_conversation_set_user_flags() and
  purple_chat_conversation_get_user_flags() as these are now methods of

There are many other changes in conversations, please see conversation.h,
conversations.h and conversationtypes.h for the full GObjectified API.

Chat users

Chat user object hierarchy:


A PurpleChatUser represents a user in a multiuser chat.

PurpleConvChatBuddy has been renamed to PurpleChatUser, to avoid confusion such
as buddies (in the buddy list) and chat buddies (which are just chat users).
Functions such as purple_conv_chat_cb_is_buddy (is chat buddy a buddy) renamed
to purple_chat_user_is_buddy() is more understandable and obvious.

- purple_conv_chat_cb_* functions are now purple_chat_user_*
- Added purple_chat_user_set_chat() and purple_chat_user_get_chat() to associate
  a PurpleChatConversation with the chat user that it belongs to.
- PurpleConvChatBuddyFlags are now PurpleChatUserFlags.
- Replaced 'chat-buddy' with 'chat-user' in conversation signals.
- Added purple_chat_user_set_flags() and purple_chat_user_get_flags() methods
  for the chat user's flags.

Attributes from PurpleChatUser have been removed, along with the associated API
functions. GObject provides g_object_set_data() and g_object_get_data() that can
be used for setting and getting of user attributes, without wasting memory on an
unnecessary hash table.

Some other changes

- Autogeneration of GEnums using glib-mkenums to enums.c and enums.h using
  template files enums.c.template and enums.h.template (taken from the old
  gobjectification branch)
- Removed data field from PurpleConversation. all set_data() and get_data()
  functions will be removed henceforth, and g_object_set_data() and
  g_object_get_data() will be used in all GObjectified entities, saving up on
  memory taken by an unnecessary hash table. The exception to this is
  PurpleAccount (and others like it) that uses the data and stores it in an .xml
  file, which cannot be done via GObject's data as far as I know, since it is
  not possible to retrieve the hast table.
- Moved ui_data field from PurpleAccount, PurpleConversation and
  PurpleChatUser's private structures to the public object structures. This is a
  convinience field not used by libpurple, that the UI uses as it sees fit.

The changes described in this mail do not cover everything. However, I have to
make changes to ChangeLog.API describing the changes to the API. Ethan suggested
against adding every little detail in that file as the number of changes are too
numerous. He suggests that major changes to functionality should be documented,
and a note put in to the effect of "These subsystems have been made into
GObjects, please see the documentation for more details".

Please suggest any improvement that I can do.
I will now be starting with GObjectification of the buddy list. If you have
suggestions regarding how I should go about with that, please let me know. :)

                                                                   -- Ankit Vani

More information about the Devel mailing list