indicators

About Indicators

Application indicators provide a simple and effective API to provide an application icon in the notification area in the top-right part of the screen, and provide simple, accessible, and complete access to key parts of your application. With bindings for C, Python, and Mono, you can integrate your app into the Unity desktop quickly and easily.

Features

  • Application indicators are more consistent – no more left and right-click inconsistency. Always left click to see the items.
  • Scrubbing – you can click once on an app indicator and scrub left and right through other indicators with your mouse.
  • More accessible – importantly, scrubbing also applies to the keyboard: this means you could bind a key to the indicator applet, hit that key and then use the arrow keys to navigate through all the indicators.
  • Themable panel icons – you can set a specific icon to be a panel icon for an indicator: this should make it easier for creating single colour panel icons for light and dark themes.
  • KDE/GNOME compatability – KDE applications running in GNOME will have their application notification menus rendered with GTK widgets and vice-versa.

Porting Guide for Applications

The application indicators API is similar to the GtkStatusIcon API in some ways, but simpler and more opinionated in its design.

Indicators are grouped together by category, so it's important for the application to accurately specify its category. Possible categories for indicators include:

  • APP_INDICATOR_CATEGORY_APPLICATION_STATUS: used to tell the user the current state of the application and allow users to act on that.
  • APP_INDICATOR_CATEGORY_COMMUNICATIONS: might be used by applications such as IM clients to let the user know they have received new messages.
  • APP_INDICATOR_CATEGORY_SYSTEM_SERVICES: inform the user about system-related events. Maybe there are updates available?
  • APP_INDICATOR_CATEGORY_HARDWARE: used for hardware-related tasks, for example Bluetooth.
  • APP_INDICATOR_CATEGORY_OTHER: if the app doesn't belong in one of the other categories but needs an indicator, it should use other.

The category is set when the indicator is created and isn't changed.

Application indicators fall into one of three states:

  • APP_INDICATOR_STATUS_PASSIVE: the indicator should be hidden from the user
  • APP_INDICATOR_STATUS_ACTIVE: the indicator should be shown normally
  • APP_INDICATOR_STATUS_ATTENTION: the application wants the user's attention

The indicator status can be set using app_indicator_set_status().

The icons need to use icon names from themes, direct paths to icon files are not supported. For example, icon names used with gtk_status_icon_new_from_file() won't work.

Typical usage (C version)

Indicators should typically be created using the helper function app_indicator_new(). This returns a pointer to a newly created AppIndicator object, which is may be unref'd normally when it is no longer needed. This function expects three parameters:

  AppIndicator* app_indicator_new (const gchar          *id,
                                   const gchar          *icon_name,
                                   AppIndicatorCategory  category);

The id parameter should be unique to your application. Because app indicators are cross-desktop, the icon_name parameter expects an icon name according to the usual icon naming spec. The category parameter is the indicator category as described above.

Once an indicator object is created, the application may decide to set an attention icon using app_indicator_set_attention_icon().

Lastly, the indicator should be given a GtkMenu object. This can be either created manually or using some other method such as GtkUIManager. Below is an example using GtkUIManager.

   1 #include <gtk/gtk.h>
   2 #include <libappindicator/app-indicator.h>
   3 
   4 static void activate_action (GtkAction *action);
   5 
   6 static GtkActionEntry entries[] = {
   7   { "FileMenu", NULL, "_File" },
   8   { "New",      "document-new", "_New", "<control>N",
   9     "Create a new file", G_CALLBACK (activate_action) },
  10   { "Open",     "document-open", "_Open", "<control>O",
  11     "Open a file", G_CALLBACK (activate_action) },
  12   { "Save",     "document-save", "_Save", "<control>S",
  13     "Save file", G_CALLBACK (activate_action) },
  14   { "Quit",     "application-exit", "_Quit", "<control>Q",
  15     "Exit the application", G_CALLBACK (gtk_main_quit) },
  16 };
  17 static guint n_entries = G_N_ELEMENTS (entries);
  18 
  19 static const gchar *ui_info =
  20 "<ui>"
  21 "  <menubar name='MenuBar'>"
  22 "    <menu action='FileMenu'>"
  23 "      <menuitem action='New'/>"
  24 "      <menuitem action='Open'/>"
  25 "      <menuitem action='Save'/>"
  26 "      <separator/>"
  27 "      <menuitem action='Quit'/>"
  28 "    </menu>"
  29 "  </menubar>"
  30 "  <popup name='IndicatorPopup'>"
  31 "    <menuitem action='New' />"
  32 "    <menuitem action='Open' />"
  33 "    <menuitem action='Save' />"
  34 "    <menuitem action='Quit' />"
  35 "  </popup>"
  36 "</ui>";
  37 
  38 static void
  39 activate_action (GtkAction *action)
  40 {
  41         const gchar *name = gtk_action_get_name (action);
  42         GtkWidget *dialog;
  43 
  44         dialog = gtk_message_dialog_new (NULL,
  45                                          GTK_DIALOG_DESTROY_WITH_PARENT,
  46                                          GTK_MESSAGE_INFO,
  47                                          GTK_BUTTONS_CLOSE,
  48                                          "You activated action: \"%s\"",
  49                                          name);
  50 
  51         g_signal_connect (dialog, "response",
  52                           G_CALLBACK (gtk_widget_destroy), NULL);
  53 
  54         gtk_widget_show (dialog);
  55 }
  56 
  57 int main (int argc, char **argv)
  58 {
  59   GtkWidget *window;
  60   GtkWidget *menubar;
  61   GtkWidget *table;
  62   GtkWidget *sw;
  63   GtkWidget *contents;
  64   GtkWidget *statusbar;
  65   GtkWidget *indicator_menu;
  66   GtkActionGroup *action_group;
  67   GtkUIManager *uim;
  68   AppIndicator *indicator;
  69   GError *error = NULL;
  70 
  71   gtk_init (&argc, &argv);
  72 
  73   /* main window */
  74   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  75   gtk_window_set_title (GTK_WINDOW (window), "Indicator Demo");
  76   gtk_window_set_icon_name (GTK_WINDOW (window), "indicator-messages-new");
  77   g_signal_connect (G_OBJECT (window),
  78                     "destroy",
  79                     G_CALLBACK (gtk_main_quit),
  80                     NULL);
  81 
  82   table = gtk_table_new (1, 5, FALSE);
  83   gtk_container_add (GTK_CONTAINER (window), table);
  84 
  85   /* Menus */
  86   action_group = gtk_action_group_new ("AppActions");
  87   gtk_action_group_add_actions (action_group,
  88                                 entries, n_entries,
  89                                 window);
  90 
  91   uim = gtk_ui_manager_new ();
  92   g_object_set_data_full (G_OBJECT (window),
  93                           "ui-manager", uim,
  94                           g_object_unref);
  95   gtk_ui_manager_insert_action_group (uim, action_group, 0);
  96   gtk_window_add_accel_group (GTK_WINDOW (window),
  97                               gtk_ui_manager_get_accel_group (uim));
  98 
  99   if (!gtk_ui_manager_add_ui_from_string (uim, ui_info, -1, &error))
 100     {
 101       g_message ("Failed to build menus: %s\n", error->message);
 102       g_error_free (error);
 103       error = NULL;
 104     }
 105 
 106   menubar = gtk_ui_manager_get_widget (uim, "/ui/MenuBar");
 107   gtk_widget_show (menubar);
 108   gtk_table_attach (GTK_TABLE (table),
 109                     menubar,
 110                     0, 1,                    0, 1,
 111                     GTK_EXPAND | GTK_FILL,   0,
 112                     0,                       0);
 113 
 114   /* Document */
 115   sw = gtk_scrolled_window_new (NULL, NULL);
 116 
 117   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
 118                                   GTK_POLICY_AUTOMATIC,
 119                                   GTK_POLICY_AUTOMATIC);
 120 
 121   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
 122                                        GTK_SHADOW_IN);
 123 
 124   gtk_table_attach (GTK_TABLE (table),
 125                     sw,
 126                     /* X direction */       /* Y direction */
 127                     0, 1,                   3, 4,
 128                     GTK_EXPAND | GTK_FILL,  GTK_EXPAND | GTK_FILL,
 129                     0,                      0);
 130 
 131   gtk_window_set_default_size (GTK_WINDOW (window),
 132                                200, 200);
 133 
 134   contents = gtk_text_view_new ();
 135   gtk_widget_grab_focus (contents);
 136 
 137   gtk_container_add (GTK_CONTAINER (sw),
 138                      contents);
 139 
 140 
 141   /* Create statusbar */
 142   statusbar = gtk_statusbar_new ();
 143   gtk_table_attach (GTK_TABLE (table),
 144                     statusbar,
 145                     /* X direction */       /* Y direction */
 146                     0, 1,                   4, 5,
 147                     GTK_EXPAND | GTK_FILL,  0,
 148                     0,                      0);
 149 
 150   /* Show the window */
 151   gtk_widget_show_all (window);
 152 
 153   /* Indicator */
 154   indicator = app_indicator_new ("example-simple-client",
 155                                  "indicator-messages",
 156                                  APP_INDICATOR_CATEGORY_APPLICATION_STATUS);
 157 
 158   indicator_menu = gtk_ui_manager_get_widget (uim, "/ui/IndicatorPopup");
 159 
 160   app_indicator_set_status (indicator, APP_INDICATOR_STATUS_ACTIVE);
 161   app_indicator_set_attention_icon (indicator, "indicator-messages-new");
 162 
 163   app_indicator_set_menu (indicator, GTK_MENU (indicator_menu));
 164 
 165   gtk_main ();
 166 
 167   return 0;
 168 }

Python version

PyGI

   1 #!/usr/bin/env python
   2 #
   3 # Copyright 2009-2012 Canonical Ltd.
   4 #
   5 # Authors: Neil Jagdish Patel <neil.patel@canonical.com>
   6 #          Jono Bacon <jono@ubuntu.com>
   7 #          David Planella <david.planella@ubuntu.com>
   8 #
   9 # This program is free software: you can redistribute it and/or modify it 
  10 # under the terms of either or both of the following licenses:
  11 #
  12 # 1) the GNU Lesser General Public License version 3, as published by the 
  13 # Free Software Foundation; and/or
  14 # 2) the GNU Lesser General Public License version 2.1, as published by 
  15 # the Free Software Foundation.
  16 #
  17 # This program is distributed in the hope that it will be useful, but 
  18 # WITHOUT ANY WARRANTY; without even the implied warranties of 
  19 # MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR 
  20 # PURPOSE.  See the applicable version of the GNU Lesser General Public 
  21 # License for more details.
  22 #
  23 # You should have received a copy of both the GNU Lesser General Public 
  24 # License version 3 and version 2.1 along with this program.  If not, see 
  25 # <http://www.gnu.org/licenses/>
  26 #
  27 
  28 from gi.repository import Gtk
  29 from gi.repository import AppIndicator3 as appindicator
  30 
  31 
  32 def menuitem_response(w, buf):
  33   print buf
  34 
  35 if __name__ == "__main__":
  36   ind = appindicator.Indicator.new (
  37                         "example-simple-client",
  38                         "indicator-messages",
  39                         appindicator.IndicatorCategory.APPLICATION_STATUS)
  40   ind.set_status (appindicator.IndicatorStatus.ACTIVE)
  41   ind.set_attention_icon ("indicator-messages-new")
  42 
  43   # create a menu
  44   menu = Gtk.Menu()
  45 
  46   # create some 
  47   for i in range(3):
  48     buf = "Test-undermenu - %d" % i
  49 
  50     menu_items = Gtk.MenuItem(buf)
  51 
  52     menu.append(menu_items)
  53 
  54     # this is where you would connect your menu item up with a function:
  55     
  56     # menu_items.connect("activate", menuitem_response, buf)
  57 
  58     # show the items
  59     menu_items.show()
  60 
  61   ind.set_menu(menu)
  62 
  63   Gtk.main()

PyGTK

   1 #!/usr/bin/env python
   2 #
   3 # Copyright 2009 Canonical Ltd.
   4 #
   5 # Authors: Neil Jagdish Patel <neil.patel@canonical.com>
   6 #          Jono Bacon <jono@ubuntu.com>
   7 #
   8 # This program is free software: you can redistribute it and/or modify it 
   9 # under the terms of either or both of the following licenses:
  10 #
  11 # 1) the GNU Lesser General Public License version 3, as published by the 
  12 # Free Software Foundation; and/or
  13 # 2) the GNU Lesser General Public License version 2.1, as published by 
  14 # the Free Software Foundation.
  15 #
  16 # This program is distributed in the hope that it will be useful, but 
  17 # WITHOUT ANY WARRANTY; without even the implied warranties of 
  18 # MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR 
  19 # PURPOSE.  See the applicable version of the GNU Lesser General Public 
  20 # License for more details.
  21 #
  22 # You should have received a copy of both the GNU Lesser General Public 
  23 # License version 3 and version 2.1 along with this program.  If not, see 
  24 # <http://www.gnu.org/licenses/>
  25 #
  26 
  27 import gobject
  28 import gtk
  29 import appindicator
  30 
  31 
  32 def menuitem_response(w, buf):
  33   print buf
  34 
  35 if __name__ == "__main__":
  36   ind = appindicator.Indicator ("example-simple-client",
  37                               "indicator-messages",
  38                               appindicator.CATEGORY_APPLICATION_STATUS)
  39   ind.set_status (appindicator.STATUS_ACTIVE)
  40   ind.set_attention_icon ("indicator-messages-new")
  41 
  42   # create a menu
  43   menu = gtk.Menu()
  44 
  45   # create some 
  46   for i in range(3):
  47     buf = "Test-undermenu - %d" % i
  48 
  49     menu_items = gtk.MenuItem(buf)
  50 
  51     menu.append(menu_items)
  52 
  53     # this is where you would connect your menu item up with a function:
  54     
  55     # menu_items.connect("activate", menuitem_response, buf)
  56 
  57     # show the items
  58     menu_items.show()
  59 
  60   ind.set_menu(menu)
  61 
  62   gtk.main()

C# Example

   1 using Gtk;
   2 using AppIndicator;
   3 
   4 public class IndicatorExample
   5 {
   6         public static void Main ()
   7         {
   8                 Application.Init ();
   9 
  10                 Window win = new Window ("Test");
  11                 win.Resize (200, 200);
  12 
  13                 Label label = new Label ();
  14                 label.Text = "Hello, world!";
  15 
  16                 win.Add (label);
  17 
  18                 ApplicationIndicator indicator = new ApplicationIndicator ("my-id",
  19                                                                            "my-name",
  20                                                                            Category.ApplicationStatus);
  21 
  22                 indicator.Status = Status.Attention;
  23 
  24                 /*
  25                 Menu menu = new Menu ();
  26                 menu.Append (new MenuItem ("Foo"));
  27                 menu.Append (new MenuItem ("Bar"));
  28 
  29                 indicator.Menu = menu;
  30                 */
  31 
  32                 win.ShowAll ();
  33 
  34                 Application.Run ();
  35         }
  36 }

Vala Example

   1 /*
   2  * Copyright 2011 Canonical Ltd.
   3  *
   4  * This program is free software: you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 3, as published
   6  * by the Free Software Foundation.
   7  *
   8  * This program is distributed in the hope that it will be useful, but
   9  * WITHOUT ANY WARRANTY; without even the implied warranties of
  10  * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
  11  * PURPOSE.  See the GNU General Public License for more details.
  12  *
  13  * You should have received a copy of the GNU General Public License along
  14  * with this program.  If not, see <http://www.gnu.org/licenses/>.
  15  *
  16  * Authors:
  17  *   Marco Trevisan (Treviño) <mail@3v1n0.net>
  18  */
  19 
  20 using Gtk;
  21 using AppIndicator;
  22 
  23 public class IndicatorExample {
  24         public static int main(string[] args) {
  25                 Gtk.init(ref args);
  26         
  27                 var win = new Window();
  28                 win.title = "Indicator Test";
  29                 win.resize(200, 200);
  30                 win.destroy.connect(Gtk.main_quit);
  31 
  32                 var label = new Label("Hello, world!");
  33                 win.add(label);
  34 
  35                 var indicator = new Indicator(win.title, "indicator-messages",
  36                                               IndicatorCategory.APPLICATION_STATUS);
  37 
  38                 indicator.set_status(IndicatorStatus.ACTIVE);
  39                 indicator.set_attention_icon("indicator-messages-new");
  40 
  41                 var menu = new Menu();
  42 
  43                 var item = new MenuItem.with_label("Foo");
  44                 item.activate.connect(() => {
  45                         indicator.set_status(IndicatorStatus.ATTENTION);
  46                 });
  47                 item.show();
  48                 menu.append(item);
  49 
  50                 item = new MenuItem.with_label("Bar");
  51                 item.show();
  52                 item.activate.connect(() => {
  53                         indicator.set_status(IndicatorStatus.ATTENTION);
  54                 });
  55                 menu.append(item);
  56 
  57                 indicator.set_menu(menu);
  58 
  59                 win.show_all();
  60 
  61                 Gtk.main();
  62                 return 0;
  63         }
  64 }

Haskell example

   1 -- Either install the Haskell bindings through cabal (cabal install happindicator) or clone the git repository
   2 -- at https://github.com/A1kmm/happindicator and install from there.
   3 
   4 import Graphics.UI.AppIndicator
   5 import Graphics.UI.Gtk
   6 import Control.Monad
   7 
   8 main = do
   9   initGUI
  10   appInd <- appIndicatorNew "appIndicatorDemo" "appointment-soon" AppIndicatorCategoryApplicationStatus
  11   appIndicatorSetStatus appInd AppIndicatorStatusActive
  12   set appInd [ appIndicatorAttentionIconName := Just "folder", 
  13                appIndicatorIconDesc := Just "Demo - non-attention",
  14                appIndicatorAttentionIconDesc := Just "Demo - attention", 
  15                appIndicatorLabel := Just "1" ]
  16   indMenu <- menuNew
  17   forM_ ["Hello", "World", "I'm a MenuItem"] $ \itemName -> do
  18     item <- menuItemNewWithLabel itemName
  19     menuShellAppend indMenu item
  20     item `on` menuItemActivate $ do
  21       appIndicatorSetStatus appInd AppIndicatorStatusAttention
  22     widgetShow item
  23   widgetShow indMenu
  24   appIndicatorSetMenu appInd indMenu
  25   mainGUI

mhall119/devportal/indicators (last edited 2012-03-08 22:14:00 by mhall119)