Ximba Radio: Developing a GTK+/Glade GUI to XM Satellite Radio
As American TV slowly sinks into the abyss of fictional reality, you may find yourself, like me, returning to the roots of electronic entertainment—radio. Satellite radio is the latest incarnation of this medium, offering a wide range of stations accessible from nearly anywhere you can drive your car.
Because I spend more of my time in front of a monitor than behind a steering wheel, I was fortunate to find a PC-based solution for satellite radio. XMPCR is a USB-connected receiver for the XM Radio satellite system that is sold primarily for Microsoft Windows systems. The device is supported under Linux by the OpenXM Project, a set of Perl scripts that acts as a network dæmon for controlling the device. Unfortunately, the only user interface for the dæmon is a limited text-based tool.
Ximba Radio was born as a graphical front end to OpenXM. The application provides a minimalist main window with current channel information that can be expanded to show channel listings and user favorites. A button bar across the top offers easy management of the radio and station navigation as well as quick access to configuration options. The menu bar gives users the comfort of a traditional desktop application.
Channel listings are shown in multiple formats. A main channel listing window shows all channels, and category-specific tabs show related channels. Separate tabs provide access to user-selectable artist and channel favorites along with a current session history. Category tabs can be hidden using the Preferences dialog, which also allows a user to set performance settings and favorites notices.
On the back side of Ximba Radio is the OpenXM dæmon. This Perl script and associated Perl module drive the connection to the USB port. The dæmon reads from a configuration file or can take command-line arguments. Communication with the dæmon occurs on a configurable TCP port with a list of acceptable clients. The dæmon also can run on Windows systems.
My goals for this application were to match the functionality of the Windows version, provide a minimalist interface and be simple to configure. Also, implementation would need to be completed in less than one man-week (40 hours).
Another goal was to keep the user-interface code as independent of the application code as possible. Application code should be able to be used with any suitable user interface, so a good design could have a curses or Web interface dropped on top with little additional work. This goal is in line with GNOME development guidelines as well as future plans for Glade.
To meet these goals, I planned to use a single header file and a single C module. To speed the implementation and solve some time-consuming problems, I opted to use global variables. Remember, this is a prototype of a simple desktop application, not an enterprise-ready 24/7 fault-tolerant behemoth. If managed correctly, the use of globals can be removed with future updates.
With goals in hand, I started working with Glade to sculpt the user interface; I cover specific code details in the next section. I configured Glade to generate C code and took the default settings for everything else in the Options dialog. Most important here are the source and header files that hold the user-interface definitions (interface.c) and the widget callbacks (callbacks.c), along with the option to generate a main.c file.
Glade generates a complete build environment for building an application. This includes the source directory (src) and a directory for image files (pixmaps). Image files used in GtkImage widgets need to be in .xpm format. Other generated files include autoconf and automake templates and pot files for internationalized strings.
Internationalization is optional and handled with GNU gettext support. The interface.c file, for example, has gettext-enabled strings. Even with this option enabled, you don't have to create pot files for any language; Glade simply uses any text strings you provide as the default language.
I found that prototyping Ximba Radio with Glade required hand-editing only two of the generated files, main.c and callbacks.c. The former required only minor additions for initialization options related to configuration handling for the application. The callbacks.c file was modified mostly to pass calls to my C module, utils.c.
As I edited my project in Glade and regenerated the C code, the callbacks.c file was appended with new functions. Fortunately, Glade does a good job of knowing when a callback already exists and didn't destroy any of my changes. Unfortunately, it sometimes re-adds an existing function. It was necessary to pull out those extra functions manually from time to time. When using libGlade, which processes the Glade XML file directly instead of using generated C code, this problem does not exist. Discussion of libGlade is beyond the scope of this article.
|Raspi-Sump||Dec 16, 2014|
|diff -u: What's New in Kernel Development||Dec 12, 2014|
|Non-Linux FOSS: Don't Type All Those Words!||Dec 10, 2014|
|Computing without a Computer||Dec 08, 2014|
|Autokey: Shorthand for Typists||Dec 04, 2014|
|How Can We Get Business to Care about Freedom, Openness and Interoperability?||Dec 03, 2014|
- Readers' Choice Awards 2014
- diff -u: What's New in Kernel Development
- Cooking with Linux - Serious Cool, Sysadmin Style!
- How Can We Get Business to Care about Freedom, Openness and Interoperability?
- Synchronize Your Life with ownCloud
- Days Between Dates?
- Computing without a Computer
- Non-Linux FOSS: Don't Type All Those Words!
- Autokey: Shorthand for Typists
Editorial Advisory Panel
Thank you to our 2014 Editorial Advisors!
- Jeff Parent
- Brad Baillio
- Nick Baronian
- Steve Case
- Chadalavada Kalyana
- Caleb Cullen
- Keir Davis
- Michael Eager
- Nick Faltys
- Dennis Frey
- Philip Jacob
- Jay Kruizenga
- Steve Marquez
- Dave McAllister
- Craig Oda
- Mike Roberts
- Chris Stark
- Patrick Swartz
- David Lynch
- Alicia Gibb
- Thomas Quinlan
- Carson McDonald
- Kristen Shoemaker
- Charnell Luchich
- James Walker
- Victor Gregorio
- Hari Boukis
- Brian Conner
- David Lane