Using the libgnome Library

The libgnome library is the non-toolkit specific utility library for GNOME applications, and includes things like configuration file reading, .desktop file handling, special GLib like utility routines, getting the standard file locations for GNOME, handling mime types, handling meta-data on files, sound, "triggers", and other useful things one could want to use. Also say that you are writing an application in say motif, but you want your app to be more GNOME friendly. Then you could use this library to make your application work well with other GNOME programs.

Configuration Files

The gnome-config routines provide an easy way to store configuration info in files. To see a full list of the routines, look in the libgnome/gnome-config.h header file.

The routines all working with a path. The path is a Unix like path, but the root is set to the ~/.gnome/ directory. So /some/config/path/file/sectionA/keyB, refers to the file ~/.gnome/some/config/path/file, and inside the file using section sectionA and key keyB.

Reading Configuration Info

To read configuration information gnome_config_get_* functions are used. the * is replaced by the type of the data, it can be int, float, string, bool and vector. The int functions work with gint, float functions work with gdouble, string functions work with gchar *, bool functions work with gboolean and vector work with an argc like array of strings (gint and gchar **). For the gnome_config_get_* functions, the default to be returned if the file section or key are not found can be appended to the path after an equals sign. If you need to know if the default was used, you can append _with_default to the function name and add a parameter which is a gboolean *, though which the function returns whether it used the default or if it actually found a real value. Example follows:

int counter;
char *text;
gboolean def;
...
counter = gnome_config_get_int_with_default("/example/section/counter=1",
					    &def);
if(def) g_print("Default used for counter!\\n");
text = gnome_config_get_string("/example/section/text=TEXT");
...
g_free(text);

Note that the string returned by gnome_config_get_string should be freed with g_free, the vector from gnome_config_get_vector should also be freed with g_free.

Writing Configuration Info

To write configuration info to files, the gnome_config_set_* functions are used. The use is very similar to above to the gnome_config_get_* functions. The types used are exactly the same. Except with the "set" functions, you pass the data you want to store after the path, and there is no default inside the path. If the directory in the path doesn't exist it will get created when the functions are written to disk. After you set all your data, you need to call gnome_config_sync to actually write your data to file. The library will not write the data to file immediately for efficiency reasons. Example follows:

char *text;
int counter;
...
/*after we have set text and counter to some values we can
  write them to our config location*/
gnome_config_set_int("/example/section/counter",counter);
gnome_config_set_string("/example/section/text",text);
gnome_config_sync();

Privacy Functions

If you want to store sensitive data, that other users should not read, use the gnome_config_private_* functions, which have exactly the same behavior as the above functions, with the exception of gnome_config_sync (and a few others) which doesn't have a private equivalent since it works for both. The difference is that these functions write to a directory called ~/.gnome_private on which 0700 permissions are enforced. This is not extremely secure, but because of the highly brain-dead US export restrictions, we can't really use encryption.

Using gnome-config for Arbitrary Files

If you wish to use gnome-config for reading and writing of arbitrary files on the file-system (as long as those files are in the gnome-config format), you can just prepend '=' to the beginning of the path and another '=' to the end of the file name. Example follows:

char buf[256];
...
/*write some bogus data to a temporary file*/
g_snprintf(buf,256,"=%s=/section/key",tmpnam(tmpnam));
gnome_config_set_int(buf,999);
gnome_config_sync();

Note that it doesn't really make sense to use the private versions when using an arbitrary absolute path, as there will be absolutely no difference between the two.

Automatic Prefixes

Sometime, especially if you have a long path, would be much easier to say have the config automatically prefix the path with a given string. This is what gnome_config_push_prefix and gnome_config_pop_prefix are for. You pass the string you want to prefix to gnome_config_push_prefix and call gnome_config_pop_prefix when you are done. Note that these functions are common between private and normal config functions. Example:

gnome_config_push_prefix("/file/section/");
gnome_config_set_int("key1",1);
gnome_config_set_int("key2",2);
gnome_config_set_int("key3",-88);
gnome_config_pop_prefix();

Misc gnome-config Stuff

If you need to remove a file in your configuration file, you will use gnome_config_clean_file. This function will schedule that file to be deleted on the next gnome_config_sync. You can do a gnome_config_clean_file and then use the file and then do gnome_config_sync, and it will have the expected behavior.

If you have written to a file or read from a file and want gnome-config to drop it from memory, use gnome_config_drop_file. This is used if you want to forget changes done to that file, or to simply conserve memory, since gnome-config will otherwise keep a copy of the data in memory for faster access.

.desktop Files

The .desktop files are the files that contain information about programs. The files are in the gnome-config format and are internally read using gnome-config. Your app definitely needs one of these files installed in the system menu paths if it wants to be added to the menu.

You can use gnome_desktop_entry_* functions to manipulate these files. These functions work with a structure called GnomeDesktopEntry and you should look at the libgnome/gnome-dentry.h header file for the format of this structure.

The basic functions that you use to manipulate these files are gnome_desktop_entry_load which returns a newly allocated GnomeDesktopEntry structure, gnome_desktop_entry_launch which takes the GnomeDesktopEntry structure as an argument and launches the program it describes and gnome_desktop_entry_free which frees the allocated memory with the structure.

An example .desktop file for your app might look like:

[Desktop Entry]
Name=Clock
Name[cz]=Hodiny
Comment=Digital Clock
Comment[cz]=Digitalni Hodiny
Exec=digital-clock
Icon=clock.png
Terminal=0
Type=Application

You will notice that there are translations for Name and Comment fields in Czech. For gnome programs to notice your .desktop file, it is usually located somewhere under <prefix>/share/apps/, which contains the hierarchy of the system menus. For the system to find your icon, your icon should be placed inside the <prefix>/share/pixmaps directory. Note that the prefix refers to the location where GNOME was installed.

Utility and Files

Files

There is a standard way to find files that belong to gnome installation, you shouldn't really be using your own logic to find them and you should use these functions to get filenames for icons, sounds or other data. The functions are:

char *gnome_libdir_file (const char *filename); 
char *gnome_datadir_file (const char *filename);
char *gnome_sound_file (const char *filename); 
char *gnome_pixmap_file (const char *filename); 
char *gnome_config_file (const char *filename);
char *gnome_unconditional_libdir_file (const char *filename); 
char *gnome_unconditional_datadir_file (const char *filename); 
char *gnome_unconditional_sound_file (const char *filename); 
char *gnome_unconditional_pixmap_file (const char *filename); 
char *gnome_unconditional_config_file (const char *filename);

These functions return a newly g_malloced string and you should use g_free on the string when you are done. The gnome_unconditional_* functions don't check if the file actually exist and will just return a file name. The normal functions will check and return NULL if the file doesn't exist. So you shouldn't use those functions when you will do saving. As an example we want to get a pixmap from the standard pixmap directory, for example we need to get the "gnome-help.png" icon:

char *name;
...
name = gnome_pixmap_file("gnome-help.png");
if(!name) {
	g_warning("gnome-help.png doesn't exist!");
} else {
	/*here we use the file*/
	...
	g_free(name);
}

Also of interest are the functions (actually macros) gnome_util_home_file and gnome_util_user_home. gnome_util_home_file takes one argument (string) and returns a newly allocated string with the home directory and .gnome prepended to the file. So for example if you pass it say someconfigfile, it would return /home/jirka/.gnome/someconfigfile. Similar is the gnome_util_user_home, it takes one argument and returns the file with just the home directory added. So if you pass it .dotfile, it would return /home/jirka/.dotfile.

Utility

There are also a number of GLib like named functions to make your life easier, of note would be g_file_exists which takes a filename and returns TRUE if it exists or FALSE if it doesn't, or g_concat_dir_and_file which takes a directory name and a file name, and takes care of the '/' issue, this is useful when working with strings where you don't want to check for the '/', you just want to append a directory to some file, or another directory. Note that you should g_free the string you get as usual. For more utility functions, look into libgnome/gnome-util.h, it is well commented.

Mime Types

Sometimes it's useful to know the mime-type of a file. You can do this by using the gnome_mime_type_or_default function, which takes two arguments, the filename and a default mime-type string which it will return if it can't figure out the mime type from the filename. This call doesn't actually look into the file, it tries to guess the type by looking at the filename itself. Also the string it returns is a pointer to it's internal database and you should not free it as that would likely result in a segfault later on. You can also use gnome_mime_type which will return NULL if it can't guess the mime-type.

It is also possible to work with URI lists, such as the ones used sometimes in Drag and Drop. Usually from an URI list you want to extract a list of filenames that you just received. For that you use the gnome_uri_list_extract_filenames function, which takes the URI list as a string argument, and returns a GList * of newly allocated strings. Once you are done with the files, you should free the strings and the list. You can use the utility routine gnome_uri_list_free_strings to do this for you.

In the following example I write a drag and drop handler that takes the files and finds out their mime information, then you could just write code that can do things based on the mime type of the files.

/*this is the handler for the drag_data_receive signal, assuming our
  widget only accepts the "text/uri-list" mime type of data, drag and
  drop is a more complicated topic and you should read up on GTK+
  documentation for better treatment*/
static void
dnd_drop_internal (GtkWidget        *widget,
		   GdkDragContext   *context,
		   gint              x,
		   gint              y,
		   GtkSelectionData *selection_data,
		   guint             info,
		   guint             time)
{
	GList *files, *li;

	/*here we extract the filenames from the URI-list we received*/
	files = gnome_uri_list_extract_filenames(selection_data->data);

	/*here we loop though the files and get their mime-type*/
	for(li = files; li!=NULL ; li = g_list_next(li)) {
		  char *mimetype;
		  char *filename = li->data;

		  /*guess the mime type of the file*/
		  mimetype = gnome_mime_type(filename);

		  /*if we can't guess it, just loop to the
		    next filename*/
		  if(!mimetype) continue;

		  /*here comes code that can actually do something
		    based on the mime-type of the file we received*/
		  ...
	}
	/*free the list of files we got*/
	gnome_uri_list_free_strings (files);
}

Note how easy it is to find out what files you got, and what type they are. You would just need to add some code instead of the three dots that actually compares the mime strings you got to some you have to figure out what you can do with the files.

Meta Data

Sometimes it is useful to store some information along with a filename, this can be done easily with the gnome-metadata. It is a set of functions to manage this data. Since Unix doesn't natively support meta-data, you have to help it yourself. For example if your app copies, renames or deletes files, use the following functions.

int gnome_metadata_rename (const char *from, const char *to);
int gnome_metadata_copy (const char *from, const char *to);
int gnome_metadata_delete (const char *file);

These functions don't actually do the operations on the files, they just change the meta-data accordingly. So if your app does any of these operations, it is nicer towards other apps, that it notifies the meta-data database of the changes. You shouldn't rely on the data being stored. Only non-critical data should be stored in the meta-data, since apps that do not notify the database with these functions will make you loose your data for the file. These functions will return 0 if there was an error, or an error-code, for more descriptions of errors, see libgnome/gnome-metadata.h.

Now if you actually want to use the meta-data to store information about files, you will most likely use the functions gnome_metadata_set, gnome_metadata_remove and gnome_metadata_get. Again these functions return an integer, which is 0 in case there was no error, or they use the same error codes as the previous functions.

The functions work with a a key string for which they store a piece of data. The data is represented by a size integer and a character pointer. gnome_metadata_set takes the filename as the first argument, the name or key of the data as the second argument, the size as the third and the pointer to the actual data as the forth argument. This function just sets that data for that file and key. gnome_metadata_remove will clear a particular data item on a file, so it takes a file and then the key name as the second argument. gnome_metadata_get takes the filename as the first argument and the key name as the second, then it returns data size though an integer pointer you pass though the third argument and the actual data though a pointer to a pointer you pass as the fourth argument. The data returned is newly allocated and should be freed after use. Small example follows (in real life you should also check the return of the functions for errors):

int size;
char *data;
...
/*set some bogus data on a file*/
gnome_metadata_set("/some/file/name","bogus",5,"BLAH");
...
/*retrieve the data back*/
gnome_metadata_get("/some/file/name","bogus",&size,&data);