<!doctype book PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
<!ENTITY panel-init           SYSTEM "sgml/applet-widget.sgml">
<!ENTITY panel-interact       SYSTEM "sgml/interact.sgml">
<!ENTITY panel-menu           SYSTEM "sgml/menu.sgml">
<!ENTITY panel-misc           SYSTEM "sgml/misc.sgml">
<!ENTITY panel-status-docklet SYSTEM "sgml/status-docklet.sgml">
]>

<book id="index">
  <bookinfo>
    <title>The GNOME Panel Libraries</title>

    <authorgroup>
      <author>
        <firstname>Jacob</firstname>
	<surname>Berkman</surname>
	<affiliation>
	  <address>
	    <email>jacob@helixcode.com</email>
	  </address>
	</affiliation>
      </author>
      <author>
        <firstname>George</firstname>
	<surname>Lebl</surname>
	<affiliation>
	  <address>
	    <email>jirka@5z.com</email>
	  </address>
	</affiliation>
      </author>
    </authorgroup>

    <copyright>
      <year>2000</year>
      <holder>The Free Software Foundation</holder>
    </copyright>
    <copyright>
      <year>2000</year>
      <holder>Helix Code, Inc.</holder>
    </copyright>
    <copyright>
      <year>2000</year>
      <holder>Eazel, Inc.</holder>
    </copyright>
  </bookinfo>

  <chapter id="unnamed1">
    <title>The Art of Applet Writing</title>
    <sect1 id="unnamed2">
      <title>Introduction</title>
      <para>
        Applets are basically GNOME applications whose window sits inside the 
	panel. Also the panel &quot;takes care&quot; of the applets by 
	providing them with session saving and restarting, window management 
	(inside of the panel), and a context menu.
      </para>
    </sect1>

    <sect1 id="unnamed3">
      <title>The Hello World of Applets</title>
      <para>
        The simplest applet one can write would be along the lines of:

	<example>
	  <title>hello-world_applet</title>
	  <programlisting>
#include &lt;config.h&gt;
#include &lt;applet-widget.h&gt;

int
main(int argc, char **argv)
{
        GtkWidget *applet;
        GtkWidget *label;

        /* Initialize the i18n stuff */
        bindtextdomain (PACKAGE, GNOMELOCALEDIR);
        textdomain (PACKAGE);

        /* intialize, this will basically set up the applet, corba and
           call gnome_init */
        applet_widget_init("hello-applet", NULL, argc, argv, NULL,0,NULL);

        /* create a new applet_widget */
        applet = applet_widget_new("hello-applet");
        /* in the rare case that the communication with the panel
           failed, error out */
        if (!applet)
                g_error("Can't create applet!\n");

        /* create the widget we are going to put on the applet */
        label = gtk_label_new(_("Hello There!"));
        gtk_widget_show(label);

        /* add the widget to the applet-widget, and thereby actually
           putting it "onto" the panel */
        applet_widget_add (APPLET_WIDGET (applet), label);
        gtk_widget_show (applet);

        /* special corba main loop */
        applet_widget_gtk_main ();

        return 0;
}
          </programlisting>
	</example>
      </para>

      <para>
        This creates an applet which just sits on the panel, not really doing
	anything, in real life the label would be substituted by something
	which actually does something useful. As you can see the applet 
	doesn't really take care of restarting itself.
      </para>
    </sect1>

    <sect1 id="unnamed4">
      <title>The .gnorba and .desktop Files</title>
      <para>
        For the applet to be added to the menus, you need to install two files.
	Your x.gnorba file goes into $sysconfdir/CORBA/servers/ and the
	x.desktop file goes into $prefix/share/applets/&lt;category&gt;/.
      </para>

      <para>
        Example files are:

	<example>
	  <title>hello.desktop</title>
	    <programlisting>
[Desktop Entry]
Name=Hello Applet
Comment=An example Hello World type Applet
Type=PanelApplet
Exec=hello_applet
Icon=gnome-hello.png
Terminal=0
            </programlisting>
	  </example>

	  <example>
	    <title>hello.gnorba</title>
	    <programlisting>
[hello_applet]
type=exe
repo_id=IDL:GNOME/Applet:1.0
description=Hello Applet
location_info=hello_applet
            </programlisting>
	  </example>
	</para>

	<para>
	  One thing to keep in mind is that the Exec line for the .desktop
	  doesn't actually get executed when the Type is PanelApplet. The 
	  Exec line should be the GOAD ID specified in the .gnorba file
	  (the &quot;hello_applet&quot; enclosed by brackets). For a simple
	  applet all you need to do is replace the hello_applet with the name 
	  of your applet executable.
        </para>
      </sect1>

      <sect1 id="unnamed5">
        <title>The Applet's Context Menu</title>
	<para>
	  When the user right clicks on the applet, a menu appears, this is all
	  handeled by the panel, so in order to add items to it you use a
	  special interface to &quot;add callbacks&quot; to the menu. A very
	  simple example would be (making our hello applet even more feature
	  full):

	  <example>
	    <title>hello_applet with menu items</title>
	      <programlisting>
#include &lt;config.h&gt;
#include &lt;applet-widget.h&gt;

static void
hello_there (AppletWidget *applet, gpointer data)
{
        g_print(_("Hello There"));
}

int
main (int argc, char **argv)
{
        GtkWidget *applet;
        GtkWidget *label;

        /* Initialize the i18n stuff */
        bindtextdomain (PACKAGE, GNOMELOCALEDIR);
        textdomain (PACKAGE);

        /* intialize, this will basically set up the applet, corba and
           call gnome_init */
        applet_widget_init("hello_applet", NULL, argc, argv, NULL, 0, NULL);

        /* create a new applet_widget */
        applet = applet_widget_new("hello_applet");
        /* in the rare case that the communication with the panel
           failed, error out */
        if (!applet)
                g_error("Can't create applet!\n");

        /* create the widget we are going to put on the applet */
        label = gtk_label_new(_("Hello There!"));
        gtk_widget_show(label);

        /* add the widget to the applet-widget, and thereby actually
           putting it "onto" the panel */
        applet_widget_add (APPLET_WIDGET (applet), label);
        gtk_widget_show (applet);

        /* add an item to the applet menu */
        applet_widget_register_callback(APPLET_WIDGET(applet),
                                        "hello",
                                        _("Hello There"),
                                        hello_there,
                                        NULL);

        /* special corba main loop */
        applet_widget_gtk_main ();

        return 0;
}
            </programlisting>
          </example>
	</para>

	<para>
	  Now the user will see a &quot;Hello There&quot; menu item on the
	  applet menu, and when selected, the applet will print &quot;Hello
	  There&quot;. Useful huh?
	</para>

	<para>
	  Note that the second argument to the register_callback is just a
	  string identifier of this callback, and can really be whatever you
	  want. But it should NOT be translated as the label (the 3rd 
	  argument) should be.
	</para>
      </sect1>

      <sect1 id="unnamed6">
        <title>Advanced Menu Stuff</title>
	<para>
	  It is also possible to have submenus, remove menus and use 
	  gnome-stock icons on the menus.
	</para>
	<sect2 id="unnamed7">
	  <title>Submenus</title>
	  <para>
	    To do submenus, you have to first call 
	    applet_widget_register_callback_dir,
	    which only takes the callback name and the menu text. The callback
	     name should end with '/'.  The callback name works as a 
	     &quot;path&quot; for the submenus.
	   </para>

	   <para>
	     So to add a submenu &quot;Foo&quot; and in item &quot;Bar&quot;
	     (into the submenu &quot;Foo&quot;) you would do:

	     <example>
	       <title>Adding a Submenu</title>
	       <programlisting>
applet_widget_register_callback_dir (APPLET_WIDGET (applet),
                                     "foo",
                                     _("Foo"));
applet_widget_register_callback (APPLET_WIDGET (applet),
                                 "foo/bar",
                                 _("Bar"),
                                 bar_callback,
                                 NULL);
	       </programlisting>
	     </example>
	   </para>
	</sect2>
	<sect2 id="unnamed8">
	  <title>Deleting</title>
	  <para>
	    To delete a menu item, just call applet_widget_unregister_callback
	    or applet_widget_unregister_callback_dir, with the proper callback
	    name.
          </para>
	</sect2>

	<sect2 id="unnamed9">
	  <title>Stock Icons</title>
	  <para>
	    You use the _stock derivatives of the callback functions and pass
	     an extra argument with the GNOME_STOCK_MENU_* type. For example
	     to add an about menu item:

	     <example>
	       <title>Adding Items with Stock Pixmaps</title>
	       <programlisting>
applet_widget_register_stock_callback(APPLET_WIDGET(applet),
                                      "about",
                                      GNOME_STOCK_MENU_ABOUT,
                                      _("About..."),
                                      about_cb,
                                      NULL);
	       </programlisting>
	     </example>
	  </para>
	</sect2>
      </sect1>

      <sect1 id="unnamed10">
        <title>Session Saving</title>
	<para>
	  The panel is session manager aware but the applets don't have to be,
	  they can depend on the panel to save their information in a proper
	  place. Basically session saving has two parts, loading the info, and 
	  saving the info. Loading is pretty simple, after you do
	  applet_widget_new, you can get the correct paths to load your 
	  properties from the widget's structure. For example:

	  <example>
	    <title>Getting Private Data</title>
	    <programlisting>
gnome_config_push_prefix(APPLET_WIDGET(applet)-&gt;privcfgpath);
hello = gnome_config_get_bool(&quot;section/hello=true&quot;);
gnome_config_pop_prefix();
	    </programlisting>
	  </example>
	  will do the trick.
	</para>

	<para>
	  For saving it's a little bit more complicated but not by much, let's
	  make our original example save a global variable hello.

	  <example>
	    <title>Saving Private HelloWorld</title>
	    <programlisting>
#include &lt;config.h&gt;
#include &lt;applet-widget.h&gt;

/* useless variable that we want to save the state of*/
gint hello = TRUE;

/* sesion save signal handler*/
static gint
applet_save_session(GtkWidget *w,
                    const char *privcfgpath,
                    const char *globcfgpath)
{
        gnome_config_push_prefix(privcfgpath);
        gnome_config_set_string(&quot;section/hello&quot;,hello);
        gnome_config_pop_prefix();

        gnome_config_sync();
        /* you need to use the drop_all here since we're all writing to
           one file, without it, things might not work too well */
        gnome_config_drop_all();

        /* make sure you return FALSE, otherwise your applet might not
           work compeltely, there are very few circumstances where you
           want to return TRUE. This behaves similiar to GTK events, in
           that if you return FALSE it means that you haven't done
           everything yourself, meaning you want the panel to save your
           other state such as the panel you are on, position,
           parameter, etc ... */
        return FALSE;
}


int
main(int argc, char **argv)
{
        GtkWidget *applet;
        GtkWidget *label;

        /* Initialize the i18n stuff */
        bindtextdomain (PACKAGE, GNOMELOCALEDIR);
        textdomain (PACKAGE);

        /* intialize, this will basically set up the applet, corba and
           call gnome_init */
        applet_widget_init(&quot;hello_applet&quot;, NULL, argc, argv, NULL, 0, NULL);

        /* create a new applet_widget */
        applet = applet_widget_new(&quot;hello_applet&quot;);
        /* in the rare case that the communication with the panel
           failed, error out */
        if (!applet)
                g_error(&quot;Can't create applet!\n&quot;);

        /* read the contents of the stored value of hello from the
           config file */
        gnome_config_push_prefix(APPLET_WIDGET(applet)-&gt;privcfgpath);
        hello = gnome_config_get_bool(&quot;section/hello=true&quot;);
        gnome_config_pop_prefix();

        /* create the widget we are going to put on the applet */
        label = gtk_label_new(_(&quot;Hello There!&quot;));
        gtk_widget_show(label);

        /* bind the session save signal */
        gtk_signal_connect(GTK_OBJECT(applet),&quot;save_session&quot;,
                           GTK_SIGNAL_FUNC(applet_save_session),
                           NULL);

        /* add the widget to the applet-widget, and thereby actually
           putting it &quot;onto&quot; the panel */
        applet_widget_add (APPLET_WIDGET (applet), label);
        gtk_widget_show (applet);

        /* special corba main loop */
        applet_widget_gtk_main ();

        return 0;
}
	    </programlisting>
	  </example>
	</para>
	<para>
	  That's basically it. Make sure you return FALSE from the save_session
	  handler, else the panel will not remember your applet next time. Also
	  note the presence of gnome_config_drop_all, that needs to be done,
	  especially for multi applets (discussed below), or your info might
	  get lost.
	</para>

	<para>
	  If you need to store information global to all applets you can use
	  the globcfgpath counterpart of privcfgpath, which gives you a path 
	  to a file which is the same for all applets.
	</para>

	<para>
	  <emphasis>IMPORTANT!</emphasis>
	  Make sure you only use two levels of config path below
	  privcfgpath/globcfgpath. Which means you only tack on
	  &quot;section/key&quot;.
	  Also don't just use &quot;key&quot;. You need to tack on both the 
	  section and the key, no more, no less.

	  <example>
	    <title>Retrieving Global Data</title>
	    <programlisting>
gnome_config_push_prefix(APPLET_WIDGET(applet)-&gt;globcfgpath);
hello = gnome_config_get_bool(&quot;all_hello_applets/hello=true&quot;);
gnome_config_pop_prefix();
	    </programlisting>
	  </example>
	  Similarly for the save_session.
	</para>

	<para>
	  <emphasis>Note:</emphasis>
	  When you update your configuration in some properties dialog, or
	  however lse, you should call applet_widget_sync_config (AppletWidget
	  *applet), it will tell the panel to send a session save signal to
	  the applet with the correct paths etc. This is not 100&percnt; neccessary,
	  but makes it nice so that configuration is not lost during crashes
	  (when the panel couldn't do it's complete save during shutdown) [ed:
	  you should still do this, even though the panel doesn't crash
	  anymore]
	</para>
      </sect1>

      <sect1 id="unnamed11">
        <title>Panel Orientation</title>
	<para>
	  How to tell which way the panel on which your applet sits is 
	  fairly simply. You bind the &quot;change_orient&quot; signal of the
	  applet. To modify our original hello applet, we'd do:

	  <example>
	    <title>Freshman Orientation</title>
	    <programlisting>
#include &lt;config.h&gt;
#include &lt;applet-widget.h&gt;

/*this is when the panel orientation changes*/
static void
applet_change_orient(GtkWidget *w, PanelOrientType o, gpointer data)
{
        switch(o) {
                case ORIENT_UP: puts(&quot;ORIENT UP&quot;); break;
                case ORIENT_DOWN: puts(&quot;ORIENT DOWN&quot;); break;
                case ORIENT_LEFT: puts(&quot;ORIENT LEFT&quot;); break;
                case ORIENT_RIGHT: puts(&quot;ORIENT RIGHT&quot;); break;
        }
}

int
main(int argc, char **argv)
{
        GtkWidget *applet;
        GtkWidget *label;

        /* Initialize the i18n stuff */
        bindtextdomain (PACKAGE, GNOMELOCALEDIR);
        textdomain (PACKAGE);

        /* intialize, this will basically set up the applet, corba and
           call gnome_init */
        applet_widget_init(&quot;hello_applet&quot;, NULL, argc, argv, NULL, 0, NULL);

        /* create a new applet_widget */
        applet = applet_widget_new(&quot;hello_applet&quot;);
        /* in the rare case that the communication with the panel
           failed, error out */
        if (!applet)
                g_error(&quot;Can't create applet!\n&quot;);

        /* create the widget we are going to put on the applet */
        label = gtk_label_new(_(&quot;Hello There!&quot;));
        gtk_widget_show(label);

        /*we have to bind change_orient before we do applet_widget_add 
          since we need to get an initial change_orient signal to set our
          initial oriantation, and we get that during the _add call*/
        gtk_signal_connect(GTK_OBJECT(applet),&quot;change_orient&quot;,
                           GTK_SIGNAL_FUNC(applet_change_orient),
                           NULL);

        /* add the widget to the applet-widget, and thereby actually
           putting it &quot;onto&quot; the panel */
        applet_widget_add (APPLET_WIDGET (applet), label);
        gtk_widget_show (applet);

        /* special corba main loop */
        applet_widget_gtk_main ();

        return 0;
}

	    </programlisting>
	  </example>
	</para>	
      </sect1>

      <sect1 id="unnamed12">
        <title>Panel Size</title>
	<para>
	  (Note: this is not included in versions of the panel prior to 1.2)
	</para>

	<para>
	  One new feature of the panel is the size support.  The panel supports
	  the following sizes:

	  <itemizedlist mark="bullet">
	    <listitem><para>Tiny: 24 pixels</para></listitem>
	    <listitem><para>Small: 36 pixels</para></listitem>
	    <listitem><para>Standard: 48 pixels</para></listitem>
	    <listitem><para>Large: 64 pixels</para></listitem>
	    <listitem><para>Huge: 80 pixls</para></listitem>
	  </itemizedlist>
	</para>

	<para>
	  It would be nice to let your applet pick it's layout so that it
	  doesn't stretch the panel out of it's preffered size (the panel is
	  always as thick as the thickest applet)
	</para>

	<para>
	  The way this works is very similiar to the way orientation works.
	  You bind the &quot;change_pixel_size&quot; signal to the applet, so
	  to modify our original hello applet, we'd do:

	  <example>
	    <title>The Sizes, The Keep A-Changin'</title>
	    <programlisting>
#include &lt;config.h&gt;
#include &lt;applet-widget.h&gt;

#ifdef HAVE_PANEL_PIXEL_SIZE
/*this is when the panel size changes*/
static void
applet_change_pixel_size(GtkWidget *w, int size, gpointer data)
{
        printf(&quot;Got size of &percnt;d pixels\n&quot;,size);
}
#endif

int
main(int argc, char **argv)
{
        GtkWidget *applet;
        GtkWidget *label;

        /* Initialize the i18n stuff */
        bindtextdomain (PACKAGE, GNOMELOCALEDIR);
        textdomain (PACKAGE);

        /* intialize, this will basically set up the applet, corba and
           call gnome_init */
        applet_widget_init(&quot;hello_applet&quot;, NULL, argc, argv, NULL, 0, NULL);

        /* create a new applet_widget */
        applet = applet_widget_new(&quot;hello_applet&quot;);
        /* in the rare case that the communication with the panel
           failed, error out */
        if (!applet)
                g_error(&quot;Can't create applet!\n&quot;);

        /* create the widget we are going to put on the applet */
        label = gtk_label_new(_(&quot;Hello There!&quot;));
        gtk_widget_show(label);

#ifdef HAVE_PANEL_PIXEL_SIZE
        /*we have to bind change_pixel_size before we do applet_widget_add 
          since we need to get an initial change_pixel_size signal to set our
          initial size, and we get that during the _add call*/
        gtk_signal_connect(GTK_OBJECT(applet),&quot;change_pixel_size&quot;,
                           GTK_SIGNAL_FUNC(applet_change_pixel_size),
                           NULL);
#endif

        /* add the widget to the applet-widget, and thereby actually
           putting it &quot;onto&quot; the panel */
        applet_widget_add (APPLET_WIDGET (applet), label);
        gtk_widget_show (applet);

        /* special corba main loop */
        applet_widget_gtk_main ();

        return 0;
}
	    </programlisting>
	  </example>
        </para>

	<para>
	   Notice the &quot;#ifdef HAVE_PANEL_PIXEL_SIZE&quot; line, this will
	   make sure your applet compiles correctly even on a panel from
	   gnome-core 1.0 which doesn't have support for multiple sizes. 
	   Note that in gnome-core 1.1.0 release there was another
	   implementation of panel sizes which is now deprecated, so you
	   should use the method above.
	</para>

	<para>
	  If you want to say compare to the standard sizes (You shouldn't
	  assume that they are the only ones that exist!), you can use the
	  PIXEL_SIZE_TINY, PIXEL_SIZE_STANDARD, PIXEL_SIZE_LARGE and
	  PIXEL_SIZE_HUGE constants as in:

	  <example>
	    <title>Using Standard Pixel Sizes</title>
	    <programlisting>
if(size &lt; PIXEL_SIZE_STANDARD) {
        ... do something for very small applet ...
} else {
        ... do something else for standard size applet ...
}
	    </programlisting>
	  </example>
	</para>
      </sect1>

      <sect1 id="unnamed13">
        <title>Rebinding Events</title>
	<para>
	  (Note: this is not included in versions of the panel prior to 1.2)
	</para>

      <para>
	  Sometimes you want to change the way the applet looks after it has 
	  already been added to the panel, and you want the right and middle 
	  mouse button clicks to still work. In this case you need to notify 
	  the panel that it should try to rebind the events. You do this with:

	<example>
	  <title>Rebinding</title>
	  <programlisting>
#ifdef HAVE_APPLET_BIND_EVENTS
applet_widget_bind_events(APPLET_WIDGET(applet),GTK_WIDGET(widget));
#endif
	  </programlisting>
	</example>	  
	which will bind mouseclicks (2nd and 3rd button) on the
	&quot;widget&quot;.
      </para>

      <para>
        Note that this is NOT in the panel in gnome-core 1.0, so if you use
	this feature, make sure to put the &quot;#ifdef 
	HAVE_APPLET_BIND_EVENTS&quot; around the code.
      </para>      
    </sect1>

    <sect1 id="unnamed14">
      <title>Multiple Applet Support</title>
      <para>
        Having one process per applet might be ok, but when you have many 
	applets it can be quite a hit on the memory.  There is an easy way to
	multiple applets from one process, even different types of applets.
      </para>

      <para>
	For a simple example let's modify our  original hello applet to make 
	it possible to have multiple instances of it from just one executable. 
	We will create a factory corba service that can create new instances of
	the applet.

	<example>
	  <title>Industrialization of hello_applet</title>
	  <programlisting>
#include &lt;config.h&gt;
#include &lt;applet-widget.h&gt;


/*when we get a command to start a new widget*/
static GtkWidget *
applet_start_new_applet(const gchar *goad_id, const gchar **params, gint nparams)
{
        GtkWidget *applet;
        GtkWidget *label;

        /*if we weren't asked to start hello_applet, just return*/
        if(strcmp(goad_id, quot;hello_appletquot;)!=0) return NULL;

        /*now we do the same exact thing as we do in the main function for
          creating the applet*/

        /* create a new applet_widget */
        applet = applet_widget_new(quot;hello_appletquot;);
        if (!applet)
                g_error(quot;Can't create applet!\nquot;);

        /* create the widget we are going to put on the applet */
        label = gtk_label_new(_(quot;Hello There!quot;));
        gtk_widget_show(label);

        /* add the widget to the applet-widget, and thereby actually
           putting it quot;ontoquot; the panel */
        applet_widget_add (APPLET_WIDGET (applet), label);
        gtk_widget_show (applet);

        /* return the applet widget from this function */
        return applet;
}

int
main(int argc, char **argv)
{
        GtkWidget *applet;
        GtkWidget *label;
        gchar *goad_id;

        /* Initialize the i18n stuff */
        bindtextdomain (PACKAGE, GNOMELOCALEDIR);
        textdomain (PACKAGE);

        /* intialize, this will basically set up the applet, corba and
           call gnome_init */
        applet_widget_init(quot;hello_appletquot;, NULL, argc, argv, NULL, 0, NULL);

        /*make new factory and get us the goad_id that was used to start us*/
        applet_factory_new(quot;hello_applet_factoryquot;, NULL, applet_start_new_applet);
        goad_id = (gchar *)goad_server_activation_id();

        /*if the goad_id was hello_applet, we create a new instance of
          our applet, otherwise don't do anything*/
        if(goad_id && strcmp(goad_id, quot;hello_appletquot;)==0) {
                /* create a new applet_widget */
                applet = applet_widget_new(quot;hello_appletquot;);
                if (!applet)
                        g_error(quot;Can't create applet!\nquot;);

                /* create the widget we are going to put on the applet */
                label = gtk_label_new(_(quot;Hello There!quot;));
                gtk_widget_show(label);

                /* add the widget to the applet-widget, and thereby actually
                   putting it quot;ontoquot; the panel */
                applet_widget_add (APPLET_WIDGET (applet), label);
                gtk_widget_show (applet);

        }

        /* special corba main loop */
        applet_widget_gtk_main ();

        return 0;
}
	  </programlisting>
	</example>
      </para>

      <para>
        What you will notice is that what we do is just make a factory service
	with applet_factory_new, to which we pass a function pointer to a 
	function that just creates new applets for us.
      </para>

      <para>
        Now we need to create a .gnorba and .desktop files for an applet of 
	this type. The .desktop file is the exact same as for normal applets. 
	The .gnorba file however must now describe the factory as well.

	<example>
	  <title>Industrialization of hello.gnorba</title>
	  <programlisting>
[hello_applet_factory]
type=exe
repo_id=IDL:GNOME/GenericFactory:1.0
description=Hello Applet
location_info=hello_applet

[hello_applet]
type=factory
repo_id=IDL:GNOME/Applet:1.0
description=Hello Applet
location_info=hello_applet_factory
	  </programlisting>
	</example>
      </para>

      <para>
        Sometimes you may want to have two applets that have very similiar
	functionality, but that appear to the user as two different applets,
	and you want to manage them from the same process. This is extremely 
	simple. Just take the above example and add more types into the
	.gnorba file, then wherever we check the goad_id, just add another
	&quot;else if&quot; to check for another goad_id. Then in your 
	desktops on the Exec line, you would have in one .desktop:

	<programlisting>
Exec=hello_version_1_applet
        </programlisting>

	and in a second:

	<programlisting>
Exec=hello_version_2_applet
	</programlisting>
      </para>
    </sect1>

    <sect1 id="unnamed15">
      <title>Shared Library Applets</title>
      <para>
        It is possible to make applets which will not be separate processes, 
	but will be loaded directly into the panel. This saves on memory, but
	can make the panel less stable if the applet is less stable.
      </para>

      <para>
        Here is an example, George will comment on stuff unless I sleep:

	<example>
	  <title>piCommander</title>
	  <programlisting>
#include &lt;config.&gt;
#include &lt;applet-widget.h&gt;

typedef struct {
	GtkWidget *applet;
	GtkWidget *fentry;
	GtkWidget *gentry;
	GtkWidget *entry;
} PicoData;

static void
entry_activate (GtkWidget *w, PicoData *pico)
{
	char *s;
	s = gtk_editable_get_chars (GTK_EDITABLE (pico-&gt;entry), 0, -1);
	gtk_editable_delete_text (GTK_EDITABLE (pico-&gt;entry), 0, -1);
	
	if (strlen (s) == 0) {
		g_free (s);
		return;
	}

	gnome_execute_shell (NULL, s);

	gnome_entry_save_history (GNOME_ENTRY (pico-&gt;gentry));
	gnome_config_sync ();

	g_free (s);	
}

static int
applet_save_session (GtkWidget *applet,
		     const char *privcfgpath,
		     const char *globcfgpath,
		     PicoData *pico)
{
	gnome_entry_save_history (GNOME_ENTRY (pico-&gt;gentry));
	gnome_config_sync ();
	return FALSE;
}

static void
applet_destroy (GtkWidget *applet, PicoData *pico)
{
	g_free (pico);
}

static CORBA_Object
pico_begin (PortableServer_POA poa,
	    const char *goad_id,
	    const char **params,
	    gpointer *impl_ptr,
	    CORBA_Environment *ev)
{
	PicoData *pico = g_new0 (PicoData, 1);

	pico-&gt;applet = applet_widget_new (goad_id);
	pico-&gt;fentry = gnome_file_entry_new (&quot;pico-commander&quot;, _(&quot;Run...&quot;));
	pico-&gt;gentry = gnome_file_entry_gnome_entry (GNOME_FILE_ENTRY (pico-&gt;fentry));
	pico-&gt;entry = gnome_file_entry_gtk_entry (GNOME_FILE_ENTRY (pico-&gt;fentry));

	gnome_entry_set_max_saved (GNOME_ENTRY (pico-&gt;gentry), 50);
	gnome_entry_prepend_history (GNOME_ENTRY (pico-&gt;gentry), FALSE, &quot;&quot;);
	gtk_combo_set_use_arrows_always (GTK_COMBO (pico-&gt;gentry), TRUE);

	applet_widget_add (APPLET_WIDGET (pico-&gt;applet), pico-&gt;fentry);

	gtk_signal_connect (GTK_OBJECT (pico-&gt;entry), &quot;activate&quot;,
			    GTK_SIGNAL_FUNC (entry_activate), pico);
	gtk_signal_connect (GTK_OBJECT (pico-&gt;applet), &quot;save_session&quot;,
			    GTK_SIGNAL_FUNC (applet_save_session), pico);
	gtk_signal_connect (GTK_OBJECT (pico-&gt;applet), &quot;destroy&quot;,
			    GTK_SIGNAL_FUNC (applet_destroy), pico);

	gtk_widget_show_all (pico-&gt;applet);

	return applet_widget_corba_activate (APPLET_WIDGET (pico-&gt;applet),
					     poa, goad_id, params, 
					     impl_ptr, ev);
}

static void
pico_end (PortableServer_POA poa,
	  const char *goad_id,
	  gpointer impl_ptr,
	  CORBA_Environment *ev)
{
	applet_widget_corba_deactivate (poa, goad_id, impl_ptr, ev);
}

static const char *repo_id[] = { &quot;IDL:GNOME/Applet:1.0&quot;, NULL };
static GnomePluginObject applets_list[] = {
	{ repo_id, &quot;pico-commander_applet&quot;, NULL, &quot;50 line launcher&quot;,
	  &amp;pico_begin, &amp;pico_end },
	{ NULL }
};

GnomePlugin GNOME_Plugin_info = { applets_list, NULL };
	  </programlisting>
	</example>
      </para>
    </sect1>

    <sect1 id="unnamed16">
      <title>Building the Applets</title>
      <para>
        Here's a simple makefile you can use (this one is for the fish applet)
	if you want to compile applets outside of the gnome-core source tree. 
	It was sent to me by John Ellis &lt;johne@bellatlantic.net&gt;
      </para>

      <para>
        FIXME! More up-to-date example.
      </para>
    </sect1>
  </chapter>

  <reference>
    <title>GNOME Panel Applet Library</title>
    <partintro>
      <para>
        This describes the API for the GNOME panel applet library, as of the
	1.2.0 release.
      </para>
    </partintro>
    &panel-init;
    &panel-interact;
    &panel-menu;
    &panel-misc;
  </reference>

  <reference>
    <title>GNOME Status Docklet Library</title>

    <partintro>
      <para>
        This describes the API for the GNOME status docklet library, as
	of the 1.2.0 release of gnome-core.
      </para>
    </partintro>

    &panel-status-docklet;
  </reference>
</book>

