APIs

Feel free to poke around and explore our APIs! There's not a whole lot here at the moment, but our developers are adding new content every day. Watch this space (or the Journal) for any updates.

Coding Guidelines

Just as Human Interface Guidelines are necessary to ensure a consistent user experience across the elementary platform, coding guidelines are needed to ensure a consistent developer experience.

These guidelines are to be followed as strictly as possible by all contributors to the elementary project, be they core contributors or "drive-by" developers. While complete conformance is not always practical or possible, compliance is a general prerequisite for inclusion into the elementary code repositories, and should not be considered to be rules to be broken (if ever) without very good cause.

For convenience and readability, these rules have been organized into topical categories arranged in no particular order.

When in doubt, read them.

Switchboard

Switchboard is elementary's hub for system-wide and user-wide global settings. Settings are grouped by purpose into a single graphical display called a plug. Individual plugs are further grouped into categories. The metadata about these plugs is supplied by the plug developer in a text file format that Switchboard can understand. Switchboard consists of three distinct components:

  1. A graphical, user-facing application that gathers and sorts all of the plugs, based on their identification and allows the user to select and interact with them.
  2. An API that enables third-party developers, as well as internal elementary developers to create plugs usable by Switchboard.
  3. A standard for writing plugs, properly describing them, and putting them in the appropriate location.

Technical overview

Note: libpantheon is currently published only in the "Unstable Upstream" elementary PPA, which also contains an unreleased Vala and various other elementary development libraries. Use at your own risk. You can add it to your system by entering the following command into your Terminal: "sudo apt-add-repository ppa:elementaryart/unstable-upstream && sudo apt-get update".

Switchboard offers an API for plug developers that is clean, well-abstracted, and easy to use. Virtually all of the logic connecting your plug to Switchboard happens behind-the-scenes, in an abstract class that your plug will subclass. 

Switchboard.Plug, an abstract class, handles communication with Switchboard over X11's window embedding protocol and D-Bus. Additionally, it initializes a D-Bus interface enabling the plug to interact with the Switchboard window, and facilitate functions such as interacting with Switchboard's search bar, and manipulating its progress bar.

Switchboard's development tools are provided as a part of libpantheon. Pantheon is the elementary desktop environment, and libpantheon is the library that provides development headers and code needed to develop and extend the components of the Pantheon desktop environment, of which Switchboard is a part.

Plugs

Plugs are written for Switchboard in Vala, using the GTK+ toolkit. Explanations of how those work are out of the scope of this document; general understanding is assumed.

Switchboard understands plugs as two files: an executable binary and a .plug file. The latter describes and provides metadata for the former. These two files are discussed in-depth in the next two subsections of this documentation.

Switchboard looks for these in /usr/lib/plugs/. That said, your plugs should not be placed directly into this folder. Switchboard searches for files in the plugs directory recursively, which is to say that it searches all directories and sub-directories. What this means is that plugs can have arbitrary amounts of organization. For example, company foo has a number of distinct plugs, they can install their plugs to /usr/lib/plugs/foo/, and even create folders for each plug (/usr/lib/plugs/foo/plugA, and /usr/lib/plugs/foo/plugB).

This system provides helpful and flexible organization, but also avoids plugs "stepping on each other's toes", and makes packaging and installing plugs easier.

Generally speaking, the recommended organization of plugs is:

/usr/lib/plugs/<project name>/<plug name>/<plug files>

<project name> is the name of the project that the plugs is are a part of.

Ex: pantheon, for the pantheon desktop environment.

<plug name> is the name of the specific plug.

Ex: printers, for a plug dealing with printers and printing settings.

<plug files> are the plug files for the plug (the .plug and binary).

Ex: printers.plug, Printers.

Make your decision of the organization of plugs based on what works best for your project and what is easiest for you to understand.

 

Note: In Switchboard <= 0.8 plugs need to be placed in /usr/share/plugs not /usr/lib/plugs. This will be deprecated in the future so plug developers are recommended to put them in /usr/lib/plugs and use the latest switchboard from lp:switchboard for development.

Executable

The code and content of a plug is stored in an executable binary. This binary has three basic goals:

  1. Sub-class the abstract Pantheon.Switchboard.Plug class, which is a form of Gtk.Window. The contents of the plug class are "embedded" into the Switchboard application when the plug is launched.
  2. Instantiate the plug class and register it with Switchboard.
  3. Start the GTK+ main loop.

If you've worked with GTK+ before, you're probably thinking that this sounds very much like the workflow of a normal GTK+ standalone application. That's because it is :). The Switchboard API is designed to be easy to understand for GTK+ novices, yet still familiar to hardcore GTK+ veterans.

Generally speaking, plugs (and thus plug binaries) abstract a low-level settings backend, such as KeyFiles, gconf, dconf, or other APIs like ALSA and GStreamer, to a graphical user interface that is as adherent to the elementary HIG has possible.

The following is a very simple skeleton of a plug for changing the Desktop wallpaper. It is very well-commented, and provides a good starting point for just about every Plug.

 

// Sub-class the base plug from libpantheon.
public class WallpapersPlug : Pantheon.Switchboard.Plug {

    public WallpapersPlug () {

        // Add a normal GTK+ Label to the window.
        var l = new Gtk.Label("Wallpaper settings go here!");
        this.add(l);
    }
}

public static int main (string[] args) {

    Gtk.init (ref args);
    // Instantiate the plug, which handles
    // connecting to Switchboard.
    var plug = new WallpapersPlug ();
    // Connect to Switchboard and identify
    // as "Wallpapers". (For debugging)
    plug.register ("Wallpapers");
    plug.show_all ();
    // Start the GTK+ main loop.
    Gtk.main ();
    return 0;
}

 

Plugs are described (in a metadata sense) not by the binary, but rather by .plug files which reside in the same directory as the executable. Plug files are discussed in-depth in the next section.

.plug File

Switchboard uses keyfiles to store metadata about plugs.

A keyfile, if you're not familiar, is a simple plaintext syntax for storing key-value information that is both human readable and easily parse-able by various libraries. Discussing how keyfiles in-depth is out of the scope of this documentation, but a good resource is the freedesktop.org documentation on the .desktop file (which is a kind of keyfile.)

The following is an example plug keyfile that might be used to describe a plug for printing.

[printers.plug]
exec=Printers
icon=printers
title=Printers
category=hardware

All values are case sensitive!

 

The group header is a unique identifier for your plug. This is mainly useful when launching a specific plug in Switchboard via CLI (or by another app). It must be unique among all other plugs. It is typical to have the group header be your .plug file's filename with a company/organization prefix. For example, if you work for company "coolbeans", and you created a plug to manage your company's peripheral named "uberprinter", your group header might be something like "coolbeans-uberprinter.plug". You could then tell Switchboard to launch that plug specifically by running `switchboard -o coolbeans-uberprinter.plug`.

The exec entry must be the name of the binary (actual plug executable) that the .plug file is describing. For example, if your executable was called Printers, exec would be set to "Printers". The value must not be a path (relative or absolute). Switchboard expects the .plug file and the plug binary to be in the same directory.

The icon entry is the name of the system icon that your plug will be displayed with in the Switchboard application. The value must be the name of a valid system-wide icon. For example, if your plug was about printer settings, icon might be set to "printer", which is an alias of the printer icon in the elementary icon set. If you would like to use an icon that is not in the elementary icon set (for example, if your plug was about some third-party piece of hardware with a known logo), you should include the icon in the package that installs your .plug and have the package install it to the system icons directory. You should not install any icons to the plug directory, and don't expect to reference them in your .plug file if you do.

The title entry is the title that the Switchboard application shows to the user. It can be anything that is descriptive and logical. For example, if your plug was about printer settings, your title entry might be set to "Printers". Generally speaking, the title should be the pluralized, non-gerund form of the word (-ing word). So instead of "Device", use "Devices". Instead of "Printing, use "Printers". Don't obsess over this though -- it's a style guideline to ensure consistency, not cause hair loss.

The category entry is the category that the plug you're describing falls under. The Switchboard app shows plugs grouped together for convenience of the end-user. You can not make up your own category. Switchboard has pre-programmed valid categories, and will simply not add your plug if it's category is set to something invalid. The categories are localized into the language of the end-user's desktop, but the category entry is always in English. The valid values of the category entry are:

  • personal
  • hardware
  • network
  • system

 

Contractor

elementary provides an easy new way for applications to share files with each other. This will make your application more useful and extend it's functionality without adding hundreds of lines of code.

Take, for example, a photo management application.  Instead of writing many libraries to deal with uploading to popular photo websites, developers are encouraged to write "contracts" for these websites.  After writing contracts, developers can simply provide a MIME type or file extension to Contractor, and it will provide a working list of options for sharing the file.

Instead of having different libraries or interfaces to deal with the same types of services or applications, developers are encouraged to write .contracts to allow all applications to utilize a particular service. For example, a .contract might be an interface to upload a .jpg to Facebook. After adding the .contract, all applications that feed the .jpg extension to Contractor can then upload the .jpg to Facebook, very easily.

Writing a contract

Contracts are very easy to write. They're modeled after the .desktop format, with a couple of additions. Below is an example of a real contract for changing the wallpaper in a gnome environment:

[Contractor Entry]
Name=Wallpaper
Icon=wallpaper
Description=Set as wallpaper
MimeType=image
Exec=gsettings set org.gnome.desktop.background picture-uri %u

 

It follows the Desktop Entry Specification:

%f A single file name, even if multiple files are selected. The system reading the desktop entry should recognize that the program in question cannot handle multiple file arguments, and it should should probably spawn and execute multiple copies of a program for each selected file if the program is not able to handle additional file arguments. If files are not on the local file system (i.e. are on HTTP or FTP locations), the files will be copied to the local file system and %f will be expanded to point at the temporary file. Used for programs that do not understand the URL syntax.
%F A list of files. Use for apps that can open several local files at once. Each file is passed as a separate argument to the executable program.
%u A single URL. Local files may either be passed as file: URLs or as file path.
%U A list of URLs. Each URL is passed as a separate argument to the executable program. Local files may either be passed as file: URLs or as file path.

 

This file, named wallpaper.contract, is stored in /usr/share/contractor/ along with all of the other contracts.

Granite

The Granite framework is something we have cooking for developers to really make it easy to develop applications on elementary. Right now it's very much a work-in-progress, but in the future we hope it will provide useful libraries for storing settings and communicating with other applications, among other things.

Basically, the lead elementary developers noticed a lot of redundancy and unnecessary complications in writing applications for elementary, so Granite is our solution to these issues. Right now it is an amalgamation of some widgets and libraries whipped up by elementary developers, and some taken from the fantastic Docky/Plank projects.

As it's a work-in-progress, we do not yet have a stable API to document; however, we'll be adding more information to this area soon.

 

If you are impatient, you can go to the API Reference of Granite.

Programming Languages

Vala

The elementary project prefers to use Vala for all apps. We choose this because it's a simple, fast, and beautiful language. And that just so happens to match our vision.

It's also great that Vala is really easy to learn! You can learn more about Vala at the official Vala website.

Other Languages

While we prefer to use Vala, apps (and especially backends) written in other languages are also acceptable. It really depends on the use case. If it's a new app and you're in doubt, it's best to stick with Vala.