4.2 libgnome


4.2 libgnome

The libgnome library contains core GNOME code that has nothing to do with X11 (the graphical part is in libgnomeui ). If you want to write command-line tools that use GNOME, you can do this if you use the features only in libgnome , not libgnomeui .

Other libraries reflect this separation between graphical and nongraphical modules. For example, Bonobo and Gnome-Print exhibit the same division. One of the consequences of the split in the core library, though, is that libgnome doesn't do a whole lot.

4.2.1 Initializing GNOME

Recall from Chapter 3 that all pure GTK+ programs share a common gtk_init() call and run gtk_main() to start the main event loop. GNOME applications also use gtk_main() , but their initialization is different because they must initialize every piece of the GNOME system.

To set up a GNOME application, create an object of the GnomeProgram ( GNOME_TYPE_PROGRAM ) class. You do this with a generator function:

 #include <gnome.h> GnomeProgram *  app  ;  app  = gnome_program_init(  application_id  ,  application_version  ,  module_info  ,  argc  ,  argv  ,  [property list,]  NULL); 

The parameters are as follows :

  • application_id ( char * ): The application identifier string. The identifier is normally the name of the executable file. Later, this string serves as a directory name in the GNOME directory tree for any application-specific files.

  • application_version ( char * ): The application's version number, as a string.

  • module_info ( GnomeModuleInfo * ): The GNOME module identifier. The most useful values are LIBGNOMEUI_MODULE for graphical applications and LIBGNOME_MODULE for other programs.

  • argc ( int ): Command-line argument count; normally argc from main() .

  • argv ( char ** ): Command-line arguments; normally argc from main() .

  • property list : A list of key-value properties. The important keys and values are

    • GNOME_PARAM_POPT_TABLE : A table of command-line parameters for the popt library (GNOME uses popt to parse parameters). If you have application-specific parameters, you can recognize them with the popt API. See [Johnson] for more information.

    • GNOME_PARAM_POPT_FLAGS : Options for popt .

    • GNOME_PARAM_POPT_CONTEXT : Context for popt .

    • GNOME_PARAM_ENABLE_SOUND ( gboolean ): If TRUE , the application can make noise.

    • GNOME_PARAM_HUMAN_READABLE_NAME ( gchararray ): The familiar name of the application, that is, something that humans might recognize. This string goes in menus and other locations. For example, "MiracleText" might be the human-readable name of miracletext .

    • GNOME_PARAM_SM_CONNECT ( gboolean ): Set this to FALSE if you want this program to ignore the session manager. Normally, you want to be able to respond, so the default for this property is TRUE .

You should always specify GNOME_PARAM_STANDARD_PROPERTIES in the list in addition to the preceding properties. This isn't a true key; you do not supply a value with it. Instead, this is a macro that expands to the GNU-style directory identifiers and locations:

  • PREFIX : Installation prefix (for example, /opt/gnome or /usr/local ).

  • SYSCONFDIR : Installation file directory (for example, $(PREFIX)/etc ).

  • DATADIR : Application data directory (for example, $(PREFIX)/share ).

  • LIBDIR : Library directory (for example, $(PREFIX)/lib ).

The GNU autotools (see Section 6.2) can set these macros for you. Otherwise , you should define them in your Makefile.

Here is a simple program skeleton:

 #include <gnome.h> int main(int argc, char **argv) {   GnomeProgram *program;   program = gnome_program_init("skeleton",                                "0.1",                                LIBGNOMEUI_MODULE,                                argc, argv,                                GNOME_PROGRAM_STANDARD_PROPERTIES,                                GNOME_PARAM_HUMAN_READABLE_NAME, "Skeleton",                                GNOME_PARAM_ENABLE_SOUND, FALSE,                                NULL);   /* rest of main program goes here */   gtk_main();   exit(0); } 

Without GNU autotools, the Makefile looks something like this:

 PREFIX = /opt/gnome CFLAGS = `pkg-config --cflags libgnomeui-2.0` -ansi -Wall \             -DPREFIX=\""$(PREFIX)"\" \             -DDATADIR=\""$(PREFIX)/share"\" \             -DSYSCONFDIR=\""$(PREFIX)/etc"\" \             -DLIBDIR=\""$(PREFIX)/lib"\" LIBS = `pkg-config --libs libgnomeui-2.0` skeleton: skeleton.c         gcc -o skeleton skeleton.c $(CFLAGS) $(LIBS) 

4.2.2 Utility Functions

One of the most important functions in the GNOME libraries locates a file:

 char  *path  ;  path  = gnome_program_locate_file(  program, domain, file_name, if_exists,   ret_locations  ); 

The return value is a newly allocated string pointer containing a file pathname if any file matched the criteria:

  • program ( GnomeProgram * ): Your program object.

  • domain ( GnomeFileDomain ): Determines the file type. Possible values include

    • GNOME_FILE_DOMAIN_LIBDIR : GNOME libraries.

    • GNOME_FILE_DOMAIN_DATADIR : GNOME data files.

    • GNOME_FILE_DOMAIN_SOUND : GNOME sound files.

    • GNOME_FILE_DOMAIN_PIXMAP : GNOME images.

    • GNOME_FILE_DOMAIN_CONFIG : GNOME configuration files.

    • GNOME_FILE_DOMAIN_HELP : GNOME help files.

    • GNOME_FILE_DOMAIN_APP_LIBDIR : Application libraries.

    • GNOME_FILE_DOMAIN_APP_DATADIR : Application data files.

    • GNOME_FILE_DOMAIN_APP_SOUND : Application sound files.

    • GNOME_FILE_DOMAIN_APP_PIXMAP : Application images.

    • GNOME_FILE_DOMAIN_APP_CONFIG : Application configuration files.

    • GNOME_FILE_DOMAIN_HELP : Application files.

    Each of these names pertains to a directory with a standard path prefix. _APP_ domains refer to application-specific directories obtained from program (described earlier); they don't necessarily need to be anywhere near the GNOME core libraries, but they should at least have the same directory structure ( lib for libraries, share for data, and so on).

  • file_name ( char * ): The desired filename.

  • if_exists ( gboolean ): If TRUE , GNOME returns the full pathname if there is actually a file in that location (and NULL otherwise). However, if you set if_exists to FALSE , a full pathname comes back even if the file doesn't exist.

  • ret_locations ( GSList ** ): If you need to know if there are multiple files matching file_name , pass the address of a GSList pointer here; GNOME creates a new list containing all matching pathnames at that pointer. You need to free the list when you're done. You can specify NULL here if you don't care.

The gnome_program_file_locate() function is the GNOME-approved method of finding application configuration and data files because it guarantees a correct pathname (at least with a properly installed system) and makes problems easier to track down.

Here is an example:

 char *path; /* find the green apple image; it should be in the standard    GNOME pixmap directory */ path = gnome_program_locate_file(program,                                  GNOME_FILE_DOMAIN_PIXMAP,                                  "apple-green.png",                                  TRUE,                                  NULL); g_print("Path for green apple: %s\n", path); g_free(path); /* look for an application-specific sound file --    do not verify that it exists */ path = gnome_program_locate_file(program,                                  GNOME_FILE_DOMAIN_APP_SOUND,                                  "plop.wav",                                  FALSE,                                  NULL); g_print("Alleged path for plop sound: %s\n", path); g_free(path); /* look for the same application-specific sound file --    this time, return a path only if the file exists */ path = gnome_program_locate_file(program,                                  GNOME_FILE_DOMAIN_APP_SOUND,                                  "plop.wav",                                  TRUE,                                  NULL); if (path) {    g_print(" ... the actual location is %s.\n", path);    g_free(path); } else {    g_print(" ... however, plop.wav isn't there.\n"); } 

Another useful function is

 gnome_util_prepend_user_home(  relative_path  ) 

This returns a newly allocated string with the current user 's home directory prepended to relative_path . If you want to go even further and specify a file in the user's personal GNOME directory ( .gnome2 ), call

 gnome_util_home_file(  relative_path  ) 

As usual, you have to free up the return value:

 /* directory prepend functions */ path = gnome_util_prepend_user_home("pictures/house.png"); g_print("Path for house.png: %s\n", path); g_free(path); path = gnome_util_home_file("mega-app/config"); g_print("Path for mega-app configuration: %s\n", path); g_free(path); 
Note  

You will likely call gnome_util_home_file() more than its counterpart , because it really isn't good style to clutter a user's home directory with nonstandard (and sometimes weird) configuration files and subdirectories. Furthermore, you should use GConf to store application configuration (see Chapter 7).

If you need to find a file extension in a path, use the strangely named

 g_extension_pointer(  path  ) 

If path ends with an extension, this function returns a pointer to that extension, after the period. This utility does not allocate new memory. If there is no extension, a pointer to the end of path comes back as the return value.

Executing Programs

The GNOME libraries include several functions for running external programs. Among these are asynchronous calls that fork off a program and let it run in the background.

These functions look somewhat similar to Unix system calls that use an array of command-line arguments ( argv ). The array's first element is a string containing the program name, followed by the program's parameters. You must provide the total count of program and parameters names separately with argc .

Note  

Many of the following functions partially duplicate GLib GSpawn facilities (and are thus around for compatibility). You may want to look at the GLib reference documentation before using one of these.

  • int gnome_execute_async(const char * dir , int argc , char *const argv [])

    Runs the new process in dir . For the current directory, use NULL for dir . The return value is the process ID (PID) of the new program. If the program fails to start at all (that is, if it doesn't exist or some other problem occurs), the return value is -1.

  • int gnome_execute_async_fds(const char * dir , int argc , char *const argv [], gboolean close_fds )

    Like the preceding function, but if close_fds is TRUE , the new process does not share any file descriptors with its parent other than the standard input, output, and error.

  • int gnome_execute_async_with_env(const char * dir , int argc , char *const argv [], int envc , char *const envv [])

    Like gnome_execute_async() , but adds the environment variables in envv to the new child process. One entry in envv has the form VAR= value ; envc is the number of elements in envv .

  • int gnome_execute_async_with_env_fds(const char * dir , int argc , char *const argv [], int envc , char *const envv [], gboolean close_fds )

    Like the preceding function, but with the file description behavior in gnome_execute_async_fds() .

If you want to run a process in a terminal window with one of the preceding functions, you can alter your argc and argv with this function:

 int gnome_prepend_terminal_to_vector(int *  argc  , char ***  argv  ) 

This function writes a new argument vector containing a terminal program and sets the * argv pointer to the new vector.

Warning  

You must create *argv with g_malloc() , and you must also individually create each of this array's component strings with g_malloc() . This function deallocates your original vector, so you can expect a core dump if you give it some nondynamic memory or try to use your original argument vector after the call.

If you would rather start your new process with a shell, use one of these functions:

  • int gnome_execute_shell(const char * dir , const char * command )

    Runs command in the directory dir with the user's default shell. Use NULL for the current directory. As with all other functions in this section, the command is forked off; the return value is the new process ID, or -1 if the command does not execute properly.

  • int gnome_execute_terminal_shell(const char * dir , const char * command )

    Like the preceding function, but runs the command in a terminal window.

  • int gnome_execute_shell_fds(const char * dir , const char * command , gboolean close_fds )

    Like gnome_execute_shell() , but does not pass any file descriptors other than standard input, output, and error if close_fds is TRUE .

  • int gnome_execute_terminal_shell_fds(const char * dir , const char * command , gboolean close_fds )

    Like the preceding function, but runs the command in a terminal window.

Warning  

For any function in this section, be careful if some of your arguments come from the network. It's far too easy to open security holes this way. Be especially careful when starting things with the shell ” it is a very powerful tool.

Displaying URLs

You can make GNOME show a URL without worrying about the program responsible for viewing the content behind the URL. There is a central configuration mapping; if you want to show a website or FTP index to the user, you can do it with a single function:

 gboolean gnome_url_show(const char *  url  , GError **  error  ) 

Here, url is a string containing the target URL, and error is a GError pointer (error class: GNOME_URL_ERROR ). This function attempts to interpret the URL and send it to the appropriate helper program. Upon success, this function returns TRUE .

At the moment, the only error code you might get in error if there's a problem is GNOME_ERROR_URL_PARSE if a syntax error occurs in the URL.

Here is a short example:

 GError *error; gnome_url_show("http://www.gnome.org/" &error); if (error != NULL) {   g_printerr("Can't open URL: %s\n", error->message);   g_error_free(error); } 
Note  

For the most part, your applications should display a URL in response to user input. In this case, you shouldn't use gnome_url_show() . GnomeHRef widgets work better. See Section 4.3.11 for more information.

If you need to change the environment of the helper program (for example, to send to a different display), put the new environment variables in an array of strings envp (each string should be in the form VAR=value ) and call this function:

 gboolean gnome_url_show_with_env(const char  *url  , char  **envp  , GError  **error  ) 

Displaying Help

Help files use a special URI protocol ( ghelp: ), separate from other URL mechanisms. GNOME sends help data to a browser such as Yelp rather than a generic web browser.

To view a help file, use

 gnome_help_display(  filename  ,  link_id  ,  error  ) 

If GNOME finds a help file matching filename , it displays the content, skipping to the section named link_id (this can be NULL if there is no section). Upon success, this function returns TRUE . The GError class for error is GNOME_HELP_ERROR , with one of these codes:

  • GNOME_HELP_ERROR_NOT_FOUND : There is no such help file.

  • GNOME_HELP_ERROR_INTERNAL : Unspecified help system error.

If you tell gnome_help_display() to look for foo , GNOME goes to the help directory for the current application to look for a matching file, including foo.xml , foo.docbook , foo.sgml , and foo.html . Therefore, if you install your help documents according to the conventions in Section 6.4.1, you do not need to worry about a subdirectory or extension.

Your program's help file ( filename ) should match the application identifier string because this makes it especially easy to jump to the main help index page. For example, assume that miracletext is your application ID and you choose miracletext.xml as the help filename.

Here are a few gnome_help_display() examples:

 /* show main help page */ gnome_help_display("miracletext", NULL, NULL); /* show main_window section of the same help page */ gnome_help_display("miracletext", "main_window", NULL); 

4.2.3 Sound

GNOME has a primitive API for attaching sounds to events. On systems that do not support sound, these functions are harmless.

Note  

Although you can decorate events with sound in your application, don't expect miracles and do not make the usability of your programs depend on sounds. In addition, remember that some people find computer sounds annoying and therefore disable sound.

If you just want to play a sound somewhere in your code, call

 gnome_sound_play(  sound_file  ) 

where sound_file is the name of a sound file.

It's more likely that you want to attach a sound to an event in your application. Follow these steps:

  1. Install the default sound file for the event in the GNOME sound directory (normally $(PREFIX)/share/sounds ). You should try to put the file in a new directory that matches the name of your application (for example, /opt/gnome/share/sounds/miracletext ).

  2. Create a file called appname .soundlist in $(PREFIX)/etc/sound/events , where appname is your program's application identifier string (see the following discussion for the format). For the continuing example, it would be /opt/gnome/etc/sound/events/miracletext.soundlist .

  3. Call gnome_triggers_do() in your event handlers to play the sound (more on this shortly).

Note  

Use a .wav file for your sound, not an esoteric format. The user should find the sound comfortable ” not too shrill, not too low, not too loud, not too quiet, and most important, not too long. Five seconds is the extreme maximum, but that can be an eternity when the user repeatedly encounters the sound.

Here's a sample .soundlist file (encode this in UTF-8):

 [__section_info__] description=MiracleText [miracle] file=miracletext/miracle.wav description=Miracle description[de]=Wunder description[es]=Milagro [miracle_big] file=miracletext/miracle_big.wav description=Big Miracle description[de]=Wunderbares Wunder description[es]=Milagro Grande 

This file breaks down into several sections, denoted with square brackets ( [] ). In the first section, __section_info__ is a special identifier; this section contains global definitions for the following sections. In the second and third sections, [miracle] and [miracle_big] define specific sound events.

The keys and settings in the sections are as follows:

  • description describes the sound event. In __section_info__ , this is the program description.

  • file is the filename relative to $(PREFIX)/share/sounds .

Note  

You can override a setting for a particular language by placing the language code within square brackets after the key.

If all files are in the right locations, the user can also change the sound events with the Sound preference tool.

To connect the sounds to events, call

 gnome_triggers_do(  message  , "program",  app_id  ,  event_id  , NULL) 

Here, message is an optional additional message, app_id is your application identifier, and event_id is the event identifier from the .soundlist file ( gnome_triggers_do() does much more than this, so that is why the syntax looks a little strange ). Here is an example:

 /* event that tells you that a miracle happened */ gnome_triggers_do("A miracle occurred!",                   "program", "miracletext", "miracle", NULL); /* for really big miracles, you don't need to put it in writing */ gnome_triggers_do("", "program", "miracletext", "miracle_big", NULL); 

4.2.4 Scores

If your GNOME application happens to be a game, you will inevitably run into the problem of how to maintain a high score table. Maintaining a high score table with fairly strict permissions is not terribly easy. The traditional Unix solution is to keep the scores in a directory accessible by the games group and make the game executables set-groupid games . However, GNOME offers a slightly easier way with three function calls that you will probably call in this order:

  1. When you initialize your main program, call gint gnome_score_init(const char *game_name ) . Set game_name to your application identifier. This function returns 0 upon success and -1 if something goes wrong.

  2. At the end of each game, call gint gnome_score_log(gfloat score , const gchar *score , gboolean descending ) to enter score and score into the high score table. Set descending to TRUE if a lower score is better in your game (a golf game, for example). This function returns the new score's rank in the table (starting at 1), or 0 if an error occurs.

  3. If you need to get the data in a high score table, use gint gnome_score_get_notable(const gchar *game_name , const gchar *level , gchar ***names , gfloat **scores , time_t **score_times ) to fill arrays for the high scores, the player names, and times of the scores for game_name at level . This function returns the number of entries in the high score table. All of the the new information goes into newly allocated arrays; you must free everything inside with g_free() .

Note  

It may ease your mind to know that you do not normally need to bother with the terrifying gnome_score_get_notable() . You can create a GnomeScores widget to display a high score list (see Section 4.3.12).




The Official GNOME 2 Developers Guide
The Official GNOME 2 Developers Guide
ISBN: 1593270305
EAN: 2147483647
Year: 2004
Pages: 108

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net