<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
<!ENTITY sanduhr "<application>SandUhr</application>">
<!ENTITY timerref SYSTEM "timerref.sgml">
<!ENTITY alarmref SYSTEM "alarmref.sgml">
<!ENTITY factoryref SYSTEM "factoryref.sgml">
]>

<article id="index">

  <articleinfo>
    <title>SandUhr User's Guide</title>
    <author>
      <firstname>Jochen</firstname> <surname>Voss</surname>
      <affiliation>
	<address>
	  <email>voss@mathematik.uni-kl.de</email>
	</address>
      </affiliation>
    </author>

    <copyright>
      <year>2000-2001</year>
      <holder>Jochen Voß</holder>
    </copyright>

    <legalnotice id="legalnotice">
      <para>
	Permission is granted to copy, distribute and/or modify this
	document under the terms of the <ulink url="gnome-help:fdl"
	type="help"><citetitle>GNU Free Documentation
	License</citetitle></ulink>, Version 1.1 or any later version
	published by the Free Software Foundation with no Invariant
	Sections, no Front-Cover Texts, and no Back-Cover Texts.  A
	copy of the license can be found <ulink url="gnome-help:fdl"
	type="help">here</ulink> or in the file COPYING-DOCS which
	shipped as part of this package.
      </para>
    </legalnotice>

    <releaseinfo>
      This is version 1.0 of the SandUhr User's Guide.
    </releaseinfo>

  </articleinfo>


  <sect1 id="intro">
    <title>Introduction</title>

    <para>
      &sanduhr; is an alarm clock, which is
      shaped like a sand glass.  One may choose one of several
      possible alarm actions, <abbrev>e.g.</abbrev> it is possible to
      automatically play a sound file when the alarm time is reached.
      This program is useful for people which, like me, tend to forget
      the time when sitting in front of a computer.  It helps them to
      produce properly timed tea anyway.
    </para>

    <para>
      The program uses (and requires) the GNOME desktop environment.
      Thus it needs the <productname>X Window System</productname> to
      operate.  I built parts of it with the help of the
      <application>Glade</application> interface builder (see <ulink
      url="http://glade.gnome.org/">glade.gnome.org</ulink>) and the
      <productname>GTK+ object builder</productname> (see <ulink
      url="http://www.5z.com/jirka/gob.html/">http://www.5z.com/jirka/gob.html</ulink>).
    </para>

    <para>
      &sanduhr; is free software and comes without any warranty.  For
      details see <xref linkend="license">.
    </para>

    <para>
      I would be glad to receive any comment on my program, especially
      bug reports.  My email address is
      <email>voss@mathematik.uni-kl.de</email>.  Your message should
      include the program's version number.  This may be obtained from
      the program call <command>sanduhr --version</command> or may be
      found at the <guimenuitem>About</guimenuitem> window (the right
      mouse button opens a window where you should choose <menuchoice>
      <guisubmenu>Help</guisubmenu> <guimenuitem>About</guimenuitem>
      </menuchoice>).
    </para>
  </sect1>


  <sect1 id="usage">
    <title>Using SandUhr</title>

    <sect2 id="invocation">
      <title>Starting SandUhr</title>

      <para>
	There are two ways to start the &sanduhr; program.  The easy
	method is to use GNOME's start menu: &sanduhr; is installed in
	the System menus as <menuchoice>
	<guisubmenu>Programs</guisubmenu>
	<guisubmenu>Utilities</guisubmenu>
	<guimenuitem>SandUhr</guimenuitem> </menuchoice>.  The program
	first opens a dialog to enter the alarm time.  After closing
	this dialog the actual alarm clock launches.
      </para>

      <para>
	Alternatively you can launch &sanduhr; from
	the command line.  The calling syntax is as follows:
	<synopsis>
<command>sanduhr</command> <optional><replaceable class="option">options</replaceable></optional> <optional><replaceable class="parameter">time</replaceable></optional>
	</synopsis>
      </para>

      <para>
	The <replaceable class="parameter">time</replaceable> argument defines
	the time when the alarm action is to be triggered.  It is a string
	whose format is explained in <xref linkend="timespec">.  If no alarm
	time is given, the program opens a dialog window to enter this time
	there.  <replaceable class="option">Options</replaceable> may be
	chosen among these:

	<variablelist>
	  <varlistentry>
	    <term><parameter>-h</parameter></term>
	    <term><parameter>--help</parameter></term>
	    <listitem>
	      <para>
		shows the complete list of options.
	      </para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><parameter>-m <replaceable class="parameter">MSG</replaceable></parameter></term>
	    <term><parameter>--message=<replaceable class="parameter">MSG</replaceable></parameter></term>
	    <listitem>
	      <para>
		Use <replaceable class="parameter">MSG</replaceable> as the alarm message.
	      </para>
	    </listitem>
	  </varlistentry>
	</variablelist>

	<example>
	  <title>A real-life example</title>
	  <para>
	    When starting &sanduhr; from the command
	    line, the following call may make sense.  It makes
	    &sanduhr; wait for three minutes and 15
	    seconds and, after that, emits the message "tea is ready".
	    <screen>
<prompt>%</prompt> <userinput>sanduhr -m "tea is ready" +3m15s</userinput>
	    </screen>
	  </para>
	</example>
      </para>
    </sect2>


    <sect2 id="timespec">
      <title>The Alarm Time</title>

      <para>
	&sanduhr;'s main use is to wait until a specified alarm time
	is reached.  You tell this time to the program with the help
	of a time string, either as a command line argument or entered
	into the dialog window.  There are two fundamentally different
	ways to specify the alarm time.  You may specify the length of
	the alarm period or you may specify the point of time when the
	alarm should occur.
      </para>

      <para>
	Relative time specifications give the length of the time interval.
	They always start with a <userinput>+</userinput> sign, which is
	followed by the interval's length.  Examples are
	<userinput>+30s</userinput> (wait for 30 seconds) and
	<userinput>+1h30m</userinput> (one hour and a half).  The following
	abbreviations are used.
      </para>

      <variablelist>
	<varlistentry>
	  <term><userinput>d</userinput></term>
	  <term><userinput>days</userinput></term>
	  <listitem>
	    <para>the number of complete days</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><userinput>h</userinput></term>
	  <term><userinput>hours</userinput></term>
	  <listitem>
	    <para>the number of hours</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><userinput>m</userinput></term>
	  <term><userinput>min</userinput></term>
	  <listitem>
	    <para>minutes</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><userinput>s</userinput></term>
	  <term><userinput>sec</userinput></term>
	  <listitem>
	    <para>seconds</para>
	  </listitem>
	</varlistentry>
      </variablelist>

      <para>
	Absolute time specifications directly give the alarm time.
	They always start with a digit.  Examples are
	<userinput>20:15</userinput> (a quarter past eight in the
	evening) and <userinput>2003-12-31 23:59:59</userinput> (the
	very end of the year 2003).
      </para>

      <tip>
	<para>
	  As the preceding example illustrates, absolute time
	  specifications may include spaces.  When entering these on
	  the command line, you have to enclose the whole expression
	  within double quotes, to prevent the shell from splitting
	  it.
	</para>
      </tip>

      <example>
	<title>A command line argument including spaces</title>
	<screen>
<prompt>%</prompt> <userinput>sanduhr "1999-12-31 23:59:30"</userinput>
	</screen>
      </example>

      <para>
	The syntax for absolute time specifications is:
	<screen>
<userinput>
<optional><replaceable>year</replaceable>-<replaceable>month</replaceable>-<replaceable>day</replaceable></optional> <replaceable>hour</replaceable>:<replaceable>minute</replaceable><optional>:<replaceable>second</replaceable></optional>
</userinput>
	</screen>
	where <replaceable>year</replaceable> is a four-digit number, the
	<replaceable>month</replaceable> is in the range 1 through 12, the
	<replaceable>day</replaceable> of the month is in the range 1 through
	31, <replaceable>hour</replaceable> is the number of hours past
	midnight, in the range 0 through 23, and the
	<replaceable>minute</replaceable> and the
	<replaceable>second</replaceable> are in the range `0' through `59'.
      </para>
    </sect2>
  </sect1>


  <sect1 id="prefs">
    <title>Customisation</title>

    <sect2 id="properties">
      <title>Properties</title>

      <para>
	While the program is running you can use the right mouse
	button on the sand glass to open a popup menu.  This allows
	you to quit the program prematurely or to change the alarm
	time or the alarm message.  The menu's
	<menuchoice>
	  <guimenuitem>Properties</guimenuitem>
	</menuchoice>
	entry pops up the property dialog for the timer.
      </para>

      <para>
	The property dialog has four tabs.  Most of these should be
	self explanatory.  For example the <guilabel>action</guilabel>
	tab contains a sheet, where you can choose the alarm action.
	The options include ringing the terminal bell, playing a sound
	file or executing an arbitrary program.
      </para>

      <para>
	The final entry, titled <guilabel>External
	SandUhr::AlarmAction CORBA object</guilabel>, can be used to
	plug custom alarm actions into
	&sanduhr; with the help of
	&sanduhr;'s CORBA interface.  This is
	explained in detail in <xref linkend="corba">.
      </para>
    </sect2>

    <sect2 id="preferences">
      <title>Preferences</title>

      <para>
	The <menuchoice> <guimenuitem>Global Preferences</guimenuitem>
	</menuchoice> item of the timer's popup window opens the
	preferences dialog.  Here you can customise some default
	values, which are used for new timers.  The fields are similar
	to these of the <link linkend="properties">properties
	dialog</link>.
      </para>
    </sect2>
  </sect1>


  <sect1 id="corba">
    <title>Controlling SandUhr with CORBA</title>

    <para>
      &sanduhr; features a full-grown
      <productname>CORBA</productname> interface.  This can be used to
      create new timer objects from scripts or programs or to query or
      modify existing timer objects.  The interface even allows you to plug
      in custom alarm actions, for example to deliver an alarm message by
      email.
    </para>

    <sect2 id="corbaintro">
      <title>Introduction to CORBA</title>

      <para>
	<productname>CORBA</productname> is a complex framework,
	designed to tie together pieces of a program, which may be
	written in different programming languages and may run on
	different computers in a network.  The full list of buzz-words
	may be found at the official <productname>CORBA</productname>
	web site <ulink url="http://www.corba.org/">www.corba.org</ulink>.
      </para>

      <para>
	<productname>CORBA</productname> is object oriented.  A
	<productname>CORBA</productname> server implements objects.  A
	client sends requests to these object, to perform specific
	tasks.  The &sanduhr; application implements two classes of
	objects:

	<itemizedlist>
	  <listitem>
	    <para>
	      <classname>SandUhr::Timer</classname> objects.  These
	      correspond to the sand-glass shaped windows you see on
	      your screen.  They implement requests to set or query
	      the items from the timers properties dialog.
	    </para>
	  </listitem>

	  <listitem>
	    <para>
	      <classname>SandUhr::TimerFactory</classname> objects.
	      Each instance of the &sanduhr; program implements one
	      factory object.  This loosely corresponds to the SandUhr
	      control window from the timers' popup window.  The main
	      function of these factory objects is to create new
	      timers.
	    </para>
	  </listitem>
	</itemizedlist>
      </para>

      <para>
	The <productname>CORBA</productname> support of &sanduhr; is
	implemented with the help of <productname>ORBit</productname>,
	the standard <productname>CORBA</productname> ORB for use with
	the GNOME environment.  You can find more information about
	<productname>ORBit</productname> at the <ulink
	url="http://www.labs.redhat.com/orbit/">ORBit
	homepage</ulink>.  The inter-ORB-communication is
	standardised, so in theory you can use any ORB implementation
	to access &sanduhr;.  If you want to learn more about
	<productname>CORBA</productname> you should read the
	<citetitle>CORBA Applications In GNOME</citetitle> white-paper
	by Elliot Lee.  It is published on the <ulink
	url="http://developer.gnome.org/doc/whitepapers/ORBit/index.html">GNOME
	development site</ulink>.
      </para>

      <para>
	In all examples below I will use the Python bindings for
	<productname>ORBit</productname>.  You can find these at
	<ulink url="http://orbit-python.sault.org/">orbit-python.sault.org</ulink>.
	You will also need the GNOME OAF library.  I use the python
	bindings which are included in the bonobo-python package at
	<ulink url="http://bonobo-python.lajnux.nu/">bonobo-python.lajnux.nu</ulink>.
      </para>
    </sect2>


    <sect2 id="corbasimple">
      <title>Simple scripting with CORBA</title>

      <para>
	Using <productname>CORBA</productname> to create a new timer is
	easy.  The only problem is, to get hands on a
	<classname>SandUhr::TimerFactory</classname> object.  Once we have
	this object, we can ask it, to create a timer for us.  This problem is
	solved by the GNOME object activation framework OAF.  We can simple
	ask the OAF for a CORBA object, which implements the
	<classname>SandUhr::TimerFactory</classname> interface.  This is
	demonstrated by <xref linkend="ex-simple1">.
      </para>

      <example id="ex-simple1">
	<title>Creating timer objects with CORBA</title>
	<para>
	  The following Python script creates a timer which expires
	  after 30 seconds.  If you run this script, it should open a
	  new timer window, and terminate immediately (without waiting
	  for the timer to expire).  If you are not using ORBit-Python
	  you may need to call your ORB's IDL compiler to generate the
	  SandUhr module.
	</para>

	<para>
	  Of course you can do the same thing not only in Python, but
	  in any language which has bindings for
	  <productname>CORBA</productname> and liboaf.  The code will
	  look similar.
	</para>
	
	<programlisting id="ex-simple1.py">
import CORBA, oaf, SandUhr

oaf.init()
factory = oaf.activate("repo_ids.has('IDL:SandUhr/TimerFactory:1.0')",[])
factory.CreateTimer ("+30s", "timer expired")
	</programlisting>
      </example>

      <para>
	Once you have mastered this example, it is really easy to
	further customise the timer.  <xref linkend="ex-simple2">
	shows, how to create a pink timer, which beeps five times
	instead of three.  The full list of available requests is
	documented in <xref linkend="timerref">.
      </para>

      <example id="ex-simple2">
	<title>Customising timer objects with CORBA</title>
	<para>
	  The following Python script creates a pink timer which beeps
	  five times when the alarm time is reached.
	</para>

	<programlisting id="ex-simple2.py">
import CORBA, oaf, SandUhr

oaf.init()
factory = oaf.activate("repo_ids.has('IDL:SandUhr/TimerFactory:1.0')",[])
timer = factory.CreateTimer ("+20s", "pink timer expired")

timer.SandColor=SandUhr.Timer.Color(Red=212,Green=78,Blue=222)

alarm = factory.CreateAlarmBeep (5)
timer.Alarm = alarm
	</programlisting>
      </example>
    </sect2>


    <sect2 id="corbaadvanced">
      <title>Advanced CORBA examples</title>

      <para>
	A more involved usage of the <productname>CORBA</productname>
	interface is to plug new alarm actions into
	&sanduhr;.  This allows you to run arbitrary
	code to deliver an alarm message.  <xref linkend="ex-email"> below
	shows how you can deliver the alarm per email.
      </para>

      <para>
	Here your application has to act as a CORBA server, which
	implements the the <classname>SandUhr::AlarmAction</classname>
	interface.  The interface is documented in <xref
	linkend="alarmref">.  Your server has to implement the
	<literal>SandUhr::AlarmAction::NeedsPopup</literal> attribute
	and the <literal>SandUhr::AlarmAction::Attach</literal>,
	<literal>SandUhr::AlarmAction::Detach</literal>, and
	<literal>SandUhr::AlarmAction::Deliver</literal>
	methods.
      </para>

      <para>
	In object oriented programming languages usually the ORB
	implementation will provide a class named similar to
	<classname>SandUhr__POA::AlarmAction</classname>.  For the Python
	bindings it is called <classname>SandUhr__POA.AlarmAction</classname>.
	To implement the alarm action you have to derive a subclass of this
	class and to overload <literal>NeedsPopup</literal>,
	<literal>Attach</literal>, <literal>Detach</literal>, and
	<literal>Deliver</literal>.
      </para>

      <para>
	Because &sanduhr; must access the object implemented by your
	server, you have to keep your server running until the alarm
	is delivered.  Usually this is achived by calling the
	<literal>ORB::run</literal> method of your ORB implementation.
      </para>

      <example id="ex-email">
	<title>Delivering the alarm by email</title>
	<para>
	  The following Python script implements a SandUhr alarm
	  action to deliver the alarm via email.  You must adjust the
	  variables <literal>EMAIL</literal> and
	  <literal>SENDMAIL</literal> to fit your local setup.  If you
	  run this script it should open a timer window and start to
	  sleep.  After 60 seconds it should send an email and then
	  quit.
	</para>

	<programlisting id="ex-email.py">
EMAIL = "Addressee &lt;some@email.address&gt;"
SENDMAIL = "/usr/sbin/sendmail"

import os
import CORBA, oaf
import SandUhr, SandUhr__POA

orb = oaf.init()

class SendMailAlarm(SandUhr__POA.AlarmAction):
    def __init__(self):
        self.NeedsPopup = CORBA.FALSE

    def Attach(self, timer):
        pass

    def Detach(self, timer):
        orb.shutdown(1)

    def Deliver(self, timespec, message):
        p = os.popen("%s -t" % SENDMAIL, "w")
        p.write("To: %s\n" % EMAIL)
        p.write("Subject: SandUhr: %s\n" % message)
        p.write("\n") # blank line separating headers from body
        p.write("A SandUhr timer has expired.\n")
        p.write("  alarm message: %s\n" % message)
        p.write("  alarm time: %s\n" % timespec)
        sts = p.close()
        if sts:
            print "Sendmail exit status", sts

poa = orb.resolve_initial_references("RootPOA")
alarm = SendMailAlarm()._this()
poa._get_the_POAManager().activate()

factory = oaf.activate("repo_ids.has('IDL:SandUhr/TimerFactory:1.0')",[])
timer = factory.CreateTimer ("+60s", "The example timer has reached its time")
timer.Alarm = alarm

orb.run()
	</programlisting>
      </example>

      <para>
	There is another possibility to plug in an alarm action.  You
	can find out the IOR string of your <classname>AlarmAction</classname>
	object with the help of the <function>ORB::object_to_string</function>
	method.  If you fill in this string into the corresponding entry
	in the <guilabel>action</guilabel> tab of a timer's properties dialog,
	the timer will deliver the alarm with the help of your server.
	This is demonstrated by <xref linkend="ex-ior">.
      </para>

      <note>
	<para>
	  This technique will come in handy if you use a CORBA language
	  binding where there are no bindings for the OAF library.
	  This library is not needed here.
	</para>
      </note>

      <example id="ex-ior">
	<title>Plugging in CORBA alarm actions via the IOR string</title>

	<para>
	  The following Python script implements an example alarm action.  If
	  you run this script, it will output an IOR string and then just start
	  sleeping.  Fill in this string into the corresponding field of the
	  <guilabel>action</guilabel> tab in a timer's properties dialog.
	  The timer then will call the <function>Deliver()</function> action
	  of this script.
	</para>

	<programlisting id="ex-ior.py">
import CORBA, SandUhr, SandUhr__POA

class Wecker(SandUhr__POA.AlarmAction):
    def __init__(self):
        self.NeedsPopup = CORBA.FALSE

    def Attach(self, timer):
        pass

    def Detach(self, timer):
        orb.shutdown(1)

    def Deliver(self, timespec, message):
        print message

orb = CORBA.ORB_init()
poa = orb.resolve_initial_references("RootPOA")

ref = Wecker()._this()
print orb.object_to_string(ref)

poa.the_POAManager.activate()
orb.run()
	</programlisting>
      </example>
    </sect2>
  </sect1>


  <sect1 id="authors">
    <title>Authors</title>

    <para>
      &sanduhr; was written by Jochen Voss
      (<email>voss@mathematik.uni-kl.de</email>).  You can find my
      homepage at <ulink
      url="http://www.mathematik.uni-kl.de/~wwwstoch/voss/privat.html">http://www.mathematik.uni-kl.de/~wwwstoch/voss/privat.html</ulink>.
      The page includes a section about &sanduhr;.  There you may find
      new versions and further information.
    </para>

    <para>
      I would be glad to receive any comment on my program, especially bug
      reports.  Your message should include the program's version number.
      This may be obtained by calling <command>sanduhr --version</command>
      or may be found at the &sanduhr;
      <guimenuitem>About</guimenuitem> window.
    </para>
  </sect1>


  <sect1 id="license">
    <title>License</title>

    <para>
      &sanduhr; is free software; you can redistribute it and/or
      modify it under the terms of the <ulink url="gnome-help:gpl"
      type="help"> <citetitle>GNU General Public
      License</citetitle></ulink> as published by the Free Software
      Foundation; either version 2 of the License, or (at your option)
      any later version.
    </para>

    <para>
      This program is distributed in the hope that it will be useful, but
      WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      <citetitle>GNU General Public License</citetitle> for more details.
    </para>

    <para>
      A copy of the <citetitle>GNU General Public License</citetitle>
      is included as an appendix to the <citetitle>GNOME Users
      Guide</citetitle>.  You may also obtain a copy of the
      <citetitle>GNU General Public License</citetitle> from the Free
      Software Foundation by visiting <ulink url="http://www.fsf.org"
      type="http">their Web site</ulink> or by writing to
      <address>
	Free Software Foundation, Inc.
	<street>59 Temple Place</street> - Suite 330
	<city>Boston</city>, <state>MA</state> <postcode>02111-1307</postcode>
	<country>USA</country>
      </address>
    </para>
  </sect1>


  <appendix id="idl">
    <title>The SandUhr CORBA interface</title>

    <para>
      The &sanduhr; CORBA interface is defined in
      the file <filename>sanduhr.idl</filename>.  This file contains a
      description of the interface in OMG's Interface Description Language.
      The following sections explain the semantics of the interface.
    </para>

    &timerref;
    &alarmref;
    &factoryref;

  </appendix>

</article>
