[Pkg-wmaker-commits] [wmpinboard] 01/30: initial commit

Doug Torrance dtorrance-guest at moszumanska.debian.org
Wed Jan 27 23:31:36 UTC 2016


This is an automated email from the git hooks/post-receive script.

dtorrance-guest pushed a commit to branch master
in repository wmpinboard.

commit 8c6d76d5b1853411d07c64aadf1c4495555e84f6
Author: Brian Bidulock <bidulock at openss7.org>
Date:   Sun May 24 18:19:53 2015 -0600

    initial commit
    
     - this is wmpinboard-1.0 that used to be on dockapps.org and is
       no longer.  I imported it to git and github from the tarball
       that I had laying around.
---
 .gitignore                   |   32 +
 AUTHORS                      |    8 +
 COPYING                      |  340 +++++++
 CREDITS                      |    9 +
 INSTALL                      |  182 ++++
 Makefile.am                  |   31 +
 NEWS                         |    1 +
 README                       |   54 +
 TODO                         |   27 +
 acconfig.h                   |   12 +
 autogen.sh                   |   21 +
 configure.ac                 |  107 ++
 configure.in                 |  103 ++
 man/Makefile.am              |    8 +
 man/wmpinboard.1             |  983 ++++++++++++++++++
 man/wmpinboard.pod           | 1022 +++++++++++++++++++
 src/Makefile.am              |   17 +
 src/getopt.c                 | 1004 ++++++++++++++++++
 src/getopt.h                 |  134 +++
 src/getopt1.c                |  187 ++++
 src/memcmp.c                 |  394 ++++++++
 src/memcmp.h                 |    8 +
 src/misc.c                   |  117 +++
 src/misc.h                   |   24 +
 src/notes.c                  | 1013 +++++++++++++++++++
 src/notes.h                  |   67 ++
 src/wmpinboard.c             | 2299 ++++++++++++++++++++++++++++++++++++++++++
 src/wmpinboard.h             |  143 +++
 src/xmisc.c                  |  434 ++++++++
 src/xmisc.h                  |   35 +
 themes-kit/HOWTO             |   95 ++
 themes-kit/abar.xpm          |   42 +
 themes-kit/bbar.xpm          |   56 +
 themes-kit/board.xpm         |  135 +++
 themes-kit/default.wmpbtheme |  258 +++++
 themes-kit/digits.xpm        |   15 +
 themes-kit/sample.wmpbtheme  |  130 +++
 wmpb-convert.pl              |   39 +
 wmpinboard.lsm               |   11 +
 wmpinboard.spec.in           |   48 +
 xpm/abar.xpm                 |   42 +
 xpm/bbar.xpm                 |   56 +
 xpm/digits.xpm               |   15 +
 xpm/pinboard.xpm             |  136 +++
 44 files changed, 9894 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f679783
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,32 @@
+aclocal.m4
+autoconf.h
+autoconf.h.in
+autoconf.h.in~
+config.h
+config.h.in
+config.h.in~
+autom4te.cache/
+ChangeLog
+config.log
+config.status
+configure
+cscope.*
+.deps/
+Makefile
+Makefile.in
+wmblob
+*.o
+scripts/
+stamp-h*
+.*.sw[nop]
+*.tar.*
+_install
+*.log
+config.guess
+config.sub
+depcomp
+install-sh
+mkinstalldirs
+missing
+compile
+.cvsignore
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..3297402
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,8 @@
+wmpinboard and its accompanying documentation and pixmaps have been 
+created by Marco G"otze, <gomar at mindless.com>.  Mail bug reports, 
+comments, suggestions, and the like to this address.
+
+The package also contains portions of the GNU C library, which, just as 
+ThoughtTracker, is distributed under the terms of the GNU GPL.
+
+For additional information, see the CREDITS file.
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+

+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+

+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+

+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+

+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/CREDITS b/CREDITS
new file mode 100644
index 0000000..8bef9fa
--- /dev/null
+++ b/CREDITS
@@ -0,0 +1,9 @@
+ wmpinboard credits
+--------------------
+ - written by Marco G"otze, <mailto:gomar at mindless.com>
+ - closer looks at other WM dock apps as well as the Xlib documentation were
+   of some help
+ - the images were created using The GIMP
+ - wmpinboard uses XIC-related keyboard handling code taken from RXVT's source
+ - thanks to various people for making suggestions and pointing out bugs
+
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..b42a17a
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,182 @@
+Basic Installation
+==================
+
+   These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+   The file `configure.in' is used to create `configure' by a program
+called `autoconf'.  You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  You can give `configure'
+initial values for variables by setting them in the environment.  Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+     CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+     env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory.  After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+   By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on.  Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+     CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+   If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+     Use and save the results of the tests in FILE instead of
+     `./config.cache'.  Set FILE to `/dev/null' to disable caching, for
+     debugging `configure'.
+
+`--help'
+     Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--version'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..356c693
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,31 @@
+## Process this file with automake to produce Makefile.in
+
+SUBDIRS = src man
+EXTRA_DIST = CREDITS TODO wmpb-convert.pl wmpinboard.lsm wmpinboard.spec.in man/Makefile.* man/wmpinboard.* xpm/* themes-kit/*
+
+bin-dist: all
+	@test -x ../make_bin_package || ( echo "Not in development environment."; false )
+	strip src/$(PACKAGE)
+	../make_bin_package $(PACKAGE) $(VERSION) i386-linux-glibc wmpb-convert.pl
+
+rpm-dist: dist
+	cp $(PACKAGE)-$(VERSION).tar.gz ../SOURCES
+	rpm -ba $(PACKAGE).spec
+
+on-site: dist bin-dist rpm-dist
+	cp ChangeLog $(HOME)/public_html/stuff/$(PACKAGE)
+	cp $(PACKAGE).lsm $(HOME)/public_html/stuff/$(PACKAGE)
+	pod2html man/$(PACKAGE).pod >$(HOME)/public_html/stuff/$(PACKAGE)/$(PACKAGE).1.html
+	rm -f *~~
+	mv ../*RPMS/$(PACKAGE)*rpm ../ON-SITE
+	mv $(PACKAGE)-$(VERSION).tar.gz ../ON-SITE
+	cd ../ON-SITE && \
+	mkdir $(PACKAGE)-tmp && \
+	cd $(PACKAGE)-tmp && \
+	cp ../$(PACKAGE)*gz . && \
+	gz2bz2 $(PACKAGE)*gz && \
+	mv $(PACKAGE)*.bz2 .. && \
+	cd .. && \
+	rmdir $(PACKAGE)-tmp && \
+	mv $(PACKAGE)* $(HOME)/public_html/stuff/$(PACKAGE)
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..3cf8b2b
--- /dev/null
+++ b/NEWS
@@ -0,0 +1 @@
+See the ChangeLog.
diff --git a/README b/README
new file mode 100644
index 0000000..d63fd94
--- /dev/null
+++ b/README
@@ -0,0 +1,54 @@
+ wmpinboard
+============
+
+ License
+---------
+
+wmpinboard is distributed under the terms of the GNU General Public license,
+revision 2, or--at your choice--any later revision.  A copy of said document
+is included with this source package.
+
+ Requirements
+--------------
+
+ - an ANSI-compliant C compiler (preferably, GCC or one of its descendants)
+ - X11R6 including header files (installed separately as "xdevel" or similar
+   by some distributions)
+ - the XPM library
+ - wmpinboard is recommended to be run on a high-color (15bit or above) display
+
+wmpinboard has reportedly been successfully compiled on the following
+platforms:
+
+ - Linux 2.0.x through 2.2.x, various setups
+ - FreeBSD 3.1
+ - Solaris 2.6
+
+Reports about other platforms are always welcome.
+
+ Installation
+--------------
+
+If you're too lazy to read the generic instructions in the INSTALL 
+file, or already know how to install autoconf'ed programs in principle, 
+here are the quick instructions that should suffice in 99% of all cases:
+
+  $ ./configure
+  $ make
+  $ make install-strip
+
+The default prefix is "/usr/local".  If you want the binary and man 
+page to go anywhere else, use configure's "--prefix" switch (see 
+`configure --help`).  For further compile-time options, see configure's 
+"--help" output.
+
+ Upgrading from earlier versions
+---------------------------------
+
+If you're upgrading to wmpinboard 0.7+ from an earlier version, existing notes
+will get lost due to some major changes concerning its data file format.
+You can avoid this by running the included PERL script as the user in
+question beforehand:
+
+  $ perl /path/to/wmpinboard-x.x/wmpb-convert.pl
+
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..a7260fe
--- /dev/null
+++ b/TODO
@@ -0,0 +1,27 @@
+ wmpinboard
+============
+
+ Things TO DO
+--------------
+
+ - wait some more time, finally declare it stable and name it v1.0
+
+ Things perhaps TO DO
+----------------------
+
+ Things I'm NOT going TO DO
+----------------------------
+
+ - Make wmpinboard pop up any external windows.  Why?
+
+     See the man page, section "FREQUENTLY ASKED QUESTIONS".
+
+ - Render rough sketches of the notes' contents in pinboard view.
+
+     Judging by my personal experience, the notes' texts tend to cover them
+     uniformly due to the limitation in size, so doing this would invariably
+     result in just a mess of dark blobs.
+
+
+Further suggestions?  Mail to <gomar at mindless.com>.
+
diff --git a/acconfig.h b/acconfig.h
new file mode 100644
index 0000000..066d034
--- /dev/null
+++ b/acconfig.h
@@ -0,0 +1,12 @@
+/* define if the XPM library is available */
+#undef HAVE_LIBXPM
+
+/* define if there is an 8-bit-clean memcmp() */
+#undef HAVE_MEMCMP
+
+/* define the edit mode timeout in seconds (0 disables) */
+#undef TIMEOUT
+
+/* define if wear & tear of notes (creases) is to be simulated */
+#undef CREASES
+
diff --git a/autogen.sh b/autogen.sh
new file mode 100644
index 0000000..082fc28
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+#
+# autogen.sh glue for wmpinboard
+# $Id: autogen.sh,v 1.3 2001/07/03 02:14:16 hmh Exp $
+#
+set -e
+
+# The idea is that we make sure we're always using an up-to-date
+# version of all the auto* script chain for the build. The GNU autotools
+# are rather badly designed in that area.
+
+aclocal
+autoheader
+
+#we don't use symlinks because of debian's build system,
+#but they would be a better choice.
+[ -r /usr/share/automake/missing ] && cp -f /usr/share/automake/missing .
+[ -r /usr/share/automake/install-sh ] && cp -f /usr/share/automake/install-sh .
+
+automake
+autoconf
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..ab8849d
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,107 @@
+dnl Process this file with autoconf to produce a configure script.
+
+AC_INIT([wmpinboard], [1.0])
+AM_INIT_AUTOMAKE([-Wall silent-rules])
+AM_CONFIG_HEADER(config.h)
+
+AC_PROG_CC
+dnl don't want the -g flag
+CFLAGS=`echo "x $CFLAGS"|sed 's/^x //; s/\(^\| \)-g\($\| \)/ /g'`
+AC_ISC_POSIX
+AC_LANG_C
+
+dnl use POSIX and BSD stuff where available
+CFLAGS="$CFLAGS -D_BSD_SOURCE -D_POSIX_SOURCE=199506L"
+
+dnl additional compile flags when using gcc
+if test x$GCC = xyes; then
+  CFLAGS="$CFLAGS -Wall -ansi -pedantic"
+fi
+
+dnl X11 stuff
+AC_PATH_XTRA
+AC_CHECK_LIB(Xpm, main, AC_DEFINE([HAVE_LIBXPM], 1,
+  [define if the XPM library is available]),
+  AC_MSG_ERROR(The XPM library is required but wasn't found.),
+  $X_LIBS -lX11 -lXext)
+
+AC_CHECK_LIB(ife, sense)
+
+AC_C_CONST
+AC_C_INLINE
+dnl check for C headers and functions
+dnl more or less optional ones first
+AC_CHECK_HEADERS([getopt.h malloc.h signal.h string.h unistd.h])
+AC_CHECK_FUNC(getopt, , need_getopt=yes)
+AC_CHECK_FUNC(getopt_long, , need_getopt_long=yes)
+AC_FUNC_MEMCMP
+if test x"$ac_cv_func_memcmp_clean" = xyes; then
+  AC_DEFINE([HAVE_MEMCMP], 1,
+  [define if there is an 8-bit-clean memcmp()])
+else
+  need_memcmp=yes
+fi
+dnl required ones
+AC_CHECK_FUNC(strchr, ,
+  AC_MSG_ERROR(Your C library seems to be lacking the strchr() function.))
+AC_CHECK_FUNC(strcasecmp, ,
+  AC_MSG_ERROR(Your C library seems to be lacking the strcasecmp() function.))
+AC_CHECK_FUNC(ualarm, ,
+  AC_MSG_ERROR(Your C library seems to be lacking the ualarm() function.))
+AC_CHECK_FUNC(usleep, ,
+  AC_MSG_ERROR(Your C library seems to be lacking the usleep() function.))
+AC_CHECK_FUNC(kill, ,
+  AC_MSG_ERROR(Your C library seems to be lacking the kill() function.))
+
+dnl === compile-time options ===
+dnl TIMEOUT
+AC_ARG_ENABLE(timeout,
+[  --enable-timeout[=TIME] set edit mode timeout to TIME seconds (default = 60)],
+[case "${enableval}" in
+	yes)	timeout=60 ;;
+	no)		timeout=0 ;;
+	*)		timeout=`echo "${enableval}"|sed 's/[^0-9]//g'`
+			if test x"$timeout" = x; then
+				AC_MSG_ERROR(Bad value ${enableval} for --enable-timeout.)
+			fi
+			if test $timeout -gt 0 -a $timeout -lt 5; then
+				timeout=5
+				AC_MSG_WARN(Timeout value to low: increasing to 5 seconds.)
+			fi
+			;;
+esac], [timeout=60])
+AC_DEFINE_UNQUOTED(TIMEOUT, ${timeout},
+  [define the edit mode timeout in seconds (0 disables)])
+
+dnl CREASES
+AC_ARG_ENABLE(creases,
+[  --enable-creases        enable wear and tear (creases) (default = yes)],
+[case "${enableval}" in
+	yes)	creases=yes ;;
+	no)		creases=no ;;
+	*)		AC_MSG_ERROR(Bad value ${enableval} for --enable-creases.) ;;
+esac], [creases=yes])
+if test x"$creases" = xyes; then
+  AC_DEFINE([CREASES], 1,
+  [define if wear & tear of notes (creases) is to be simulated])
+fi
+
+dnl determine what conditional stuff has to be compiled
+if test x"$need_memcmp" = xyes; then
+  CONDITIONAL_SOURCES="$CONDITIONAL_SOURCES memcmp.c"
+fi
+if test x"$need_getopt" = xyes; then
+  CONDITIONAL_SOURCES="$CONDITIONAL_SOURCES getopt.c"
+fi
+if test x"$need_getopt_long" = xyes; then
+  CONDITIONAL_SOURCES="$CONDITIONAL_SOURCES getopt1.c"
+fi
+AC_SUBST(CONDITIONAL_SOURCES)
+
+AC_OUTPUT([
+Makefile
+src/Makefile
+man/Makefile
+wmpinboard.spec
+])
+
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..1e1a681
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,103 @@
+dnl Process this file with autoconf to produce a configure script.
+
+AC_INIT(configure.in)
+AM_INIT_AUTOMAKE(wmpinboard, 1.0)
+AM_CONFIG_HEADER(config.h)
+
+AC_PROG_CC
+dnl don't want the -g flag
+CFLAGS=`echo "x $CFLAGS"|sed 's/^x //; s/\(^\| \)-g\($\| \)/ /g'`
+AC_ISC_POSIX
+AC_LANG_C
+
+dnl use POSIX and BSD stuff where available
+CFLAGS="$CFLAGS -D_BSD_SOURCE -D_POSIX_SOURCE=199506L"
+
+dnl additional compile flags when using gcc
+if test x$GCC = xyes; then
+  CFLAGS="$CFLAGS -Wall -ansi -pedantic"
+fi
+
+dnl X11 stuff
+AC_PATH_XTRA
+AC_CHECK_LIB(Xpm, main, AC_DEFINE(HAVE_LIBXPM),
+  AC_MSG_ERROR(The XPM library is required but wasn't found.),
+  $X_LIBS -lX11 -lXext)
+
+AC_CHECK_LIB(ife, sense)
+
+AC_C_CONST
+AC_C_INLINE
+dnl check for C headers and functions
+dnl more or less optional ones first
+AC_CHECK_HEADERS([getopt.h malloc.h signal.h string.h unistd.h])
+AC_CHECK_FUNC(getopt, , need_getopt=yes)
+AC_CHECK_FUNC(getopt_long, , need_getopt_long=yes)
+AC_FUNC_MEMCMP
+if test x"$ac_cv_func_memcmp_clean" = xyes; then
+  AC_DEFINE(HAVE_MEMCMP)
+else
+  need_memcmp=yes
+fi
+dnl required ones
+AC_CHECK_FUNC(strchr, ,
+  AC_MSG_ERROR(Your C library seems to be lacking the strchr() function.))
+AC_CHECK_FUNC(strcasecmp, ,
+  AC_MSG_ERROR(Your C library seems to be lacking the strcasecmp() function.))
+AC_CHECK_FUNC(ualarm, ,
+  AC_MSG_ERROR(Your C library seems to be lacking the ualarm() function.))
+AC_CHECK_FUNC(usleep, ,
+  AC_MSG_ERROR(Your C library seems to be lacking the usleep() function.))
+AC_CHECK_FUNC(kill, ,
+  AC_MSG_ERROR(Your C library seems to be lacking the kill() function.))
+
+dnl === compile-time options ===
+dnl TIMEOUT
+AC_ARG_ENABLE(timeout,
+[  --enable-timeout[=TIME] set edit mode timeout to TIME seconds (default = 60)],
+[case "${enableval}" in
+	yes)	timeout=60 ;;
+	no)		timeout=0 ;;
+	*)		timeout=`echo "${enableval}"|sed 's/[^0-9]//g'`
+			if test x"$timeout" = x; then
+				AC_MSG_ERROR(Bad value ${enableval} for --enable-timeout.)
+			fi
+			if test $timeout -gt 0 -a $timeout -lt 5; then
+				timeout=5
+				AC_MSG_WARN(Timeout value to low: increasing to 5 seconds.)
+			fi
+			;;
+esac], [timeout=60])
+AC_DEFINE_UNQUOTED(TIMEOUT, ${timeout})
+
+dnl CREASES
+AC_ARG_ENABLE(creases,
+[  --enable-creases        enable wear and tear (creases) (default = yes)],
+[case "${enableval}" in
+	yes)	creases=yes ;;
+	no)		creases=no ;;
+	*)		AC_MSG_ERROR(Bad value ${enableval} for --enable-creases.) ;;
+esac], [creases=yes])
+if test x"$creases" = xyes; then
+  AC_DEFINE(CREASES)
+fi
+
+dnl determine what conditional stuff has to be compiled
+if test x"$need_memcmp" = xyes; then
+  CONDITIONAL_SOURCES="$CONDITIONAL_SOURCES memcmp.c"
+fi
+if test x"$need_getopt" = xyes; then
+  CONDITIONAL_SOURCES="$CONDITIONAL_SOURCES getopt.c"
+fi
+if test x"$need_getopt_long" = xyes; then
+  CONDITIONAL_SOURCES="$CONDITIONAL_SOURCES getopt1.c"
+fi
+AC_SUBST(CONDITIONAL_SOURCES)
+
+AC_OUTPUT([
+Makefile
+src/Makefile
+man/Makefile
+wmpinboard.spec
+])
+
diff --git a/man/Makefile.am b/man/Makefile.am
new file mode 100644
index 0000000..a2843c7
--- /dev/null
+++ b/man/Makefile.am
@@ -0,0 +1,8 @@
+## Process this file with automake to produce Makefile.in
+
+man_MANS = wmpinboard.1
+
+EXTRA_DIST = $(man_MANS) *.pod
+
+wmpinboard.1: wmpinboard.pod
+	-pod2man --release=$(VERSION) --center=wmpinboard wmpinboard.pod wmpinboard.1
diff --git a/man/wmpinboard.1 b/man/wmpinboard.1
new file mode 100644
index 0000000..f27b792
--- /dev/null
+++ b/man/wmpinboard.1
@@ -0,0 +1,983 @@
+.\" Automatically generated by Pod::Man version 1.02
+.\" Thu Apr 13 13:01:39 2000
+.\"
+.\" Standard preamble:
+.\" ======================================================================
+.de Sh \" Subsection heading
+.br
+.if t .Sp
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Ip \" List item
+.br
+.ie \\n(.$>=3 .ne \\$3
+.el .ne 3
+.IP "\\$1" \\$2
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+
+.fi
+..
+.\" Set up some character translations and predefined strings.  \*(-- will
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
+.\" double quote, and \*(R" will give a right double quote.  | will give a
+.\" real vertical bar.  \*(C+ will give a nicer C++.  Capital omega is used
+.\" to do unbreakable dashes and therefore won't be available.  \*(C` and
+.\" \*(C' expand to `' in nroff, nothing in troff, for use with C<>
+.tr \(*W-|\(bv\*(Tr
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.ie n \{\
+.    ds -- \(*W-
+.    ds PI pi
+.    if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.    if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\"  diablo 12 pitch
+.    ds L" ""
+.    ds R" ""
+.    ds C` `
+.    ds C' '
+'br\}
+.el\{\
+.    ds -- \|\(em\|
+.    ds PI \(*p
+.    ds L" ``
+.    ds R" ''
+'br\}
+.\"
+.\" If the F register is turned on, we'll generate index entries on stderr
+.\" for titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and
+.\" index entries marked with X<> in POD.  Of course, you'll have to process
+.\" the output yourself in some meaningful fashion.
+.if \nF \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
+.    .
+.    nr % 0
+.    rr F
+.\}
+.\"
+.\" For nroff, turn off justification.  Always turn off hyphenation; it
+.\" makes way too many mistakes in technical documents.
+.hy 0
+.if n .na
+.\"
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
+.\" Fear.  Run.  Save yourself.  No user-serviceable parts.
+.bd B 3
+.    \" fudge factors for nroff and troff
+.if n \{\
+.    ds #H 0
+.    ds #V .8m
+.    ds #F .3m
+.    ds #[ \f1
+.    ds #] \fP
+.\}
+.if t \{\
+.    ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+.    ds #V .6m
+.    ds #F 0
+.    ds #[ \&
+.    ds #] \&
+.\}
+.    \" simple accents for nroff and troff
+.if n \{\
+.    ds ' \&
+.    ds ` \&
+.    ds ^ \&
+.    ds , \&
+.    ds ~ ~
+.    ds /
+.\}
+.if t \{\
+.    ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+.    ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+.    ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+.    ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+.    ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+.    ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.\}
+.    \" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+.    \" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+.    \" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+.    ds : e
+.    ds 8 ss
+.    ds o a
+.    ds d- d\h'-1'\(ga
+.    ds D- D\h'-1'\(hy
+.    ds th \o'bp'
+.    ds Th \o'LP'
+.    ds ae ae
+.    ds Ae AE
+.\}
+.rm #[ #] #H #V #F C
+.\" ======================================================================
+.\"
+.IX Title "WMPINBOARD 1"
+.TH WMPINBOARD 1 "0.99.3" "2000-04-13" "wmpinboard"
+.UC
+.SH "NAME"
+\&\fBwmpinboard\fR \- a \fBWindow Maker\fR dock app resembling a miniature pinboard
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+.Vb 1
+\&  wmpinboard [options]
+.Ve
+.Sh "What wmpinboard is"
+.IX Subsection "What wmpinboard is"
+\&\fBwmpinboard\fR is a \fBWindow Maker\fR dock applet resembling a miniature 
+pinboard.  It's intended to somewhat relieve heavily littered desktops 
+by allowing you to place reminders on a graphical on-screen pinboard 
+rather than producing a mess of real notes all around your keyboard 
+(thus being environmentally A Good Thing, too \fB;\-)\fR ).  It supports 
+arbitrary 6x10 X fonts and has XLocale support, enabling you to enter 
+locale-dependent special characters if set up appropriately.  Besides 
+text, you can add small monochrome sketches to your notes or simply 
+encircle or underline words as a means of emphasis, and alarms can be 
+set to explicitly remind you of things.  Above all, \fBwmpinboard\fR is 
+animated in redundant ways to make it look even more attractive, and 
+themeability provides for a way of adapting its appearance to that of 
+the rest of your desktop.
+.Sh "What wmpinboard \s-1ISN\s0'T"
+.IX Subsection "What wmpinboard ISN'T"
+Clearly, \fBwmpinboard\fR doesn't allow you to keep an unlimited number of 
+notes holding arbitrary amounts of information, and that's not what 
+it's meant to do.  Just as real notes offer limited space, so do those 
+simulated by \fBwmpinboard\fR.  Besides, as a dock applet, it aims at 
+being small and neat and yet useful in a way, and that's what it is, 
+too, or considered to be by some people, anyway.  If you need room for 
+more comprehensive reminders, use another program, either additionally 
+or exclusively.  There's a variety of such out there, but their niche 
+is different from that which \fBwmpinboard\fR claims.
+.SH "OPTIONS"
+.IX Header "OPTIONS"
+\&\fBwmpinboard\fR's command-line options can be roughly divided into four 
+groups: configuration directives, run-time options, command-line 
+actions, and general options.  Generally, \fBwmpinboard\fR supports
+GNU-style long options (which may be abbreviated unambiguously) as well 
+as short ones for parameters used more commonly.
+.Sh "Configuration directives"
+.IX Subsection "Configuration directives"
+This type of command-line options changes some aspect of 
+\&\fBwmpinboard\fR's configuration that is saved along with the data and 
+thus set in a more permanent way.  Only one such parameter may be 
+specified per call, and there mustn't be another instance running.
+.Ip "\fB\f(CB\*(C`\-\-font=FONT\*(C'\fB\fR" 2
+.IX Item "--font=FONT"
+Makes \fBwmpinboard\fR use the specified font; \fB\f(CB\*(C`FONT\*(C'\fB\fR can be one of 
+the shortcuts listed when running the program with "\fB\f(CB\*(C`\-\-help\*(C'\fB\fR" as a
+parameter, or a complete X descriptor of a fixed size 6x10 font.  The
+pinboard \fImust be empty\fR in order for this option to be applicable.  
+For more details, see the section on "FREQUENTLY ASKED QUESTIONS".
+.Ip "\fB\f(CB\*(C`\-\-theme=FILE\*(C'\fB\fR" 2
+.IX Item "--theme=FILE"
+Configures \fBwmpinboard\fR to load the specified theme when started 
+interactively the next time.  \fB\f(CB\*(C`FILE\*(C'\fB\fR is the location of a 
+\&\fBwmpinboard\fR theme file (typically with a file name extension of 
+\&\fI.wmpbtheme\fR).  If it can't be loaded when run interactively, the 
+program will revert to its default theme.  If \fB\f(CB\*(C`FILE\*(C'\fB\fR is an empty 
+string or \*(L"default\*(R", the use of a custom theme will be deactivated.
+.Sp
+Themes affect \fBwmpinboard\fR's appearance, in particular, its pinboard, 
+edit mode and alarm panel pixmaps, the latter's digits, and possibly 
+the location of the pinboard mode label area (via which notes are 
+created).  For downloading themes, or if you're inclined to create one 
+yourself and need instructions, check out the program's home page (see 
+the section on "AUTHOR" or \fBwmpinboard\fR's "\fB\f(CB\*(C`\-\-help\*(C'\fB\fR" output for the \s-1URL\s0).  The 
+themes kit containing instructions and samples on how to create theme 
+files for \fBwmpinboard\fR that can be downloaded there is also included 
+with the source package of the program.
+.Ip "\fB\f(CB\*(C`\-\-alarm\-cmd=CMD\*(C'\fB\fR" 2
+.IX Item "--alarm-cmd=CMD"
+Configures \fB\f(CB\*(C`CMD\*(C'\fB\fR as the command to be executed on alarms.  E.g., 
+you could use "\f(CW\*(C`xkbbell\*(C'\fR" to cause the program to beep on such 
+occassions, or make it run some sound-playing program.  To reset the 
+alarm command to none, make \fB\f(CB\*(C`CMD\*(C'\fB\fR a zero-length string.
+.Sh "Run-time options"
+.IX Subsection "Run-time options"
+.Ip "\fB\f(CB\*(C`\-d DISPLAY\*(C'\fB\fR or \fB\f(CB\*(C`\-\-display=DISPLAY\*(C'\fB\fR" 2
+.IX Item "-d DISPLAY or --display=DISPLAY"
+Uses the specified X display rather than the default one.
+.Ip "\fB\f(CB\*(C`\-c\*(C'\fB\fR or \fB\f(CB\*(C`\-\-click\-to\-focus\*(C'\fB\fR" 2
+.IX Item "-c or --click-to-focus"
+This turns on some emulation of a click-based keyboard focus mode. See
+the section on "FREQUENTLY ASKED QUESTIONS".
+.Ip "\fB\f(CB\*(C`\-t TIME\*(C'\fB\fR or \fB\f(CB\*(C`\-\-timeout=TIME\*(C'\fB\fR" 2
+.IX Item "-t TIME or --timeout=TIME"
+Sets the edit mode timeout (i.e., the number of seconds of idleness 
+after which edit mode is terminated automatically) to \fB\f(CB\*(C`TIME\*(C'\fB\fR 
+seconds.  The compile-time default is 60s, but this may have been 
+changed for your particular build; run with \fB\f(CB\*(C`\-v\*(C'\fB\fR if in doubt to 
+check that.  Specifying a value of 0 (zero) will disable the timeout.
+.Ip "\fB\f(CB\*(C`\-n\*(C'\fB\fR or \fB\f(CB\*(C`\-\-normal\-state\*(C'\fB\fR" 2
+.IX Item "-n or --normal-state"
+Forces \fBwmpinboard\fR to run in so-called NormalState, which is 
+preferred by \fBAfterStep\fR's \fBWharf\fR.
+.Ip "\fB\f(CB\*(C`\-w\*(C'\fB\fR or \fB\f(CB\*(C`\-\-withdrawn\-state\*(C'\fB\fR" 2
+.IX Item "-w or --withdrawn-state"
+Forces the program to run in so-called WithdrawnState, as desired by 
+the \fBWindow Maker\fR dock.  This option and the previous one are mutually 
+exclusive.  Note also that \fBwmpinboard\fR tries to auto-detect whether 
+\&\fBWindow Maker\fR is running and sets itself up accordingly.  Using \fB\f(CB\*(C`\-n\*(C'\fB\fR
+or \fB\f(CB\*(C`\-w\*(C'\fB\fR should only be necessary in case those heuristics fail on 
+your system for some reason or other.
+.Ip "\fB\f(CB\*(C`\-\-light\*(C'\fB\fR" 2
+.IX Item "--light"
+Use this switch to suppress animations.
+.Sh "Command-line actions"
+.IX Subsection "Command-line actions"
+Even though \fBwmpinboard\fR is by design an interactive application, 
+there may be occasions when it comes in handy to be able to 
+access/manipulate notes from the command line.  That's why the program 
+offers a set of command-line options allowing for basic operations of 
+that kind.  Still, it should be kept in mind that \fBwmpinboard\fR is 
+primarily meant to be used interactively.
+.PP
+All of the options below will, if an interactive instance of 
+\&\fBwmpinboard\fR is running in the background, cause that to save its data 
+(and quit \fIedit mode\fR, if necessary), and if any changes are made by 
+the respective option, the interactive instance will then be signalled 
+to re-read the data file.  Even though the implemented methods of
+inter-process communication should generally be sufficiently safe 
+with respect to avoiding data file corruption, it's in theory possible 
+to undermine the concept and cause damage that way\*(--yet this won't 
+happen unless you deliberately take pains to achieve the goal.  
+Generally, everything should work fine as long as you don't try running 
+multiple non-interactive instances of \fBwmpinboard\fR simultaneously.
+.PP
+Only one of the below actions can be specified per call to \fBwmpinboard\fR.
+.Ip "\fB\f(CB\*(C`\-\-dump\*(C'\fB\fR" 2
+.IX Item "--dump"
+This dumps the contents of all notes, replacing line breaks by spaces 
+(unless preceded by a hyphen) and shortening sequences of blanks.  The 
+list of dumped strings will be sorted by color groups.  If you use 
+special characters in your notes, make sure your terminal's running 
+with the same character set as \fBwmpinboard\fR, or what you'll see might 
+have a garbage-like quality.
+.Sp
+Each line of output represents one note and is prefixed by the internal
+number \fIcurrently\fR identifying the respective note and, if an alarm is
+configured for the respective note, time and date (or \*(L"daily\*(R").
+.Ip "\fB\f(CB\*(C`\-\-dump\-raw\*(C'\fB\fR" 2
+.IX Item "--dump-raw"
+Unlike the \*(L"cooked\*(R" dump described above, this just dumps the raw 
+contents of all notes without applying any kind of formatting.  May 
+come in handy if your notes happen to contain E-mail addresses or other 
+things for which lines 10 characters wide are too narrow.
+.Ip "\fB\f(CB\*(C`\-\-del=NUMBER\*(C'\fB\fR" 2
+.IX Item "--del=NUMBER"
+This option will remove the note identified by \fB\f(CB\*(C`NUMBER\*(C'\fB\fR from the 
+pinboard.  \fB\f(CB\*(C`NUMBER\*(C'\fB\fR is a number determined by the output of either 
+dump option, which should be consulted right before using this one, 
+since note numbers may change when notes are moved around on the board 
+or others are removed.
+.Ip "\fB\f(CB\*(C`\-\-add=STRING\*(C'\fB\fR" 2
+.IX Item "--add=STRING"
+When run with this option, \fBwmpinboard\fR will add a new note (provided 
+the maximal number of notes has not yet been reached) at a random 
+position on the board, with contents \fB\f(CB\*(C`STRING\*(C'\fB\fR, word-wrapping the 
+text at the end of the note's lines where necessary (after white space 
+and hyphens).  If due to this wrapping, the entire string cannot be 
+stored on the note, the remainder will be discarded silently.
+.Sp
+In order to create a note with a certain color, the string can be
+prefixed by a color code specifying the group of colors which a random 
+color is to be selected from (code letters are recognized
+case-insensitively):
+.Sp
+.Vb 4
+\&  %G - green
+\&  %Y - yellow/white
+\&  %R - reddish
+\&  %B - blue
+.Ve
+Alternatively or additionally, you may specify a position code as \*(L"%1\*(R" 
+through \*(L"%9\*(R", defining an approximate position on the board where the 
+note is to be placed.  Each of the nine figures corresponds to a ninth 
+of the board with its index assigned in accordance with the layout of 
+your keypad (i.e., \*(L"%1\*(R" meaning lower left, \*(L"%9\*(R" upper right corner, 
+and so forth).
+.Sp
+Thus,
+.Sp
+.Vb 1
+\&  wmpinboard --add '%g%5test'
+.Ve
+will place a green note saying \*(L"test\*(R" at the center of the board.
+.Sp
+(Note: The \*(L"%\*(R" character can be escaped by a second one if you want to
+add an un-prefixed string starting with a percent character.)
+.Ip "\fB\f(CB\*(C`\-\-add\-raw=STRING\*(C'\fB\fR" 2
+.IX Item "--add-raw=STRING"
+Via this option, a new note can be added from the command line 
+(provided that this won't exceed the maximum number of notes).  
+\&\fB\f(CB\*(C`STRING\*(C'\fB\fR specifies the \fIraw\fR contents of the note, as printed by 
+\&\fB\f(CB\*(C`\-\-dump\-raw\*(C'\fB\fR.  The same set of color group and position codes as 
+for the previous option applies.
+.Sh "General options"
+.IX Subsection "General options"
+.Ip "\fB\f(CB\*(C`\-h\*(C'\fB\fR or \fB\f(CB\*(C`\-\-help\*(C'\fB\fR" 2
+.IX Item "-h or --help"
+This prints a help screen listing command line options together with 
+brief descriptions.
+.Ip "\fB\f(CB\*(C`\-i\*(C'\fB\fR or \fB\f(CB\*(C`\-\-info\*(C'\fB\fR" 2
+.IX Item "-i or --info"
+Prints information about the current user configuration (font, theme, 
+alarm command) and some useless statistics.
+.Ip "\fB\f(CB\*(C`\-v\*(C'\fB\fR or \fB\f(CB\*(C`\-\-version\*(C'\fB\fR" 2
+.IX Item "-v or --version"
+This prints some more detailed version information, in particular, 
+which compile-time settings this binary was built with.
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+\&\fBwmpinboard\fR operates in basically two different modes, namely, the 
+\&\fIpinboard view\fR and \fIedit mode\fR.  Furthermore, a \fIpanel\fR of buttons 
+granting access to extended options can be popped up in \fIedit mode\fR,
+which in turn allows you to display the \fIalarm panel\fR to configure
+alarm settings for the current note.
+.Sh "Pinboard view"
+.IX Subsection "Pinboard view"
+This is \fBwmpinboard\fR's normal mode of operation.  A potentially
+chaotic arrangement of tiny squares on a beige-colored oblong (default 
+theme) is meant to resemble notes pinned to a cork board.  Possible 
+actions include:
+.Ip "\(bu" 2
+\&\fIAdd\fR a note, by left-clicking on the board's \*(L"\s-1TO\s0 \s-1DO\s0\*(R" label.  This 
+creates a new, blank, randomly-colored note at a random position on the 
+board and puts \fBwmpinboard\fR in \fIedit mode\fR (see below).  If you 
+prefer to place a new note at a certain position before being prompted 
+to enter its contents, this can be done by moving the mouse cursor 
+after having clicked on the label.  This will realize the note and 
+allow you to drag it to a position of your choice.  \fBwmpinboard\fR will 
+switch to \fIedit mode\fR as soon as you release the mouse button.
+.Ip "\(bu" 2
+\&\fIEdit\fR/\fIview\fR a note, by left-clicking on a note.  This switches
+to \fIedit mode\fR (described below).
+.Ip "\(bu" 2
+\&\fIMove\fR a note, by dragging it using the right mouse button.
+This also raises the note in question on top of all others.
+Depending on its horizontal position, the note will be tilted
+automatically.  As a side-effect, a single brief right-click
+can be used to raise a note on top of overlapping ones without
+moving it.
+.Sp
+By dragging a note with the left mouse button, you can move it without 
+changing its level with respect to other notes, i.e., without raising 
+it on top of all others.
+.Sh "Edit mode"
+.IX Subsection "Edit mode"
+This mode serves two purposes: on the one hand, it presents you with a 
+\&\*(L"full-size\*(R" view of a note's contents, on the other, you can use the 
+occasion to edit it.  Due to its limited size, a note can hold up to 10 
+characters on 6 lines (minus one on the last, i.e., 59 characters 
+altogether), plus a monochrome sketch of some kind.  Possibly actions:
+.Ip "\(bu" 2
+\&\fIEnter\fR text.  \fBwmpinboard\fR supports user-selectable fonts and dead 
+keys, so you should be able to enter any characters that are usually 
+accessible via your keyboard and have them displayed correctly.  
+Furthermore, the cursor can be moved around using the arrow keys (or 
+EMACS-style via [Ctrl]\-[N]/[P]/[F]/[B], if you are so inclined).  
+Alternatively, it can be placed explicitly by left-clicking where you 
+want it to be.  Other special keys that are supported include:
+.RS 2
+.Ip "[PgUp]/[PgDn]" 2
+.IX Item "[PgUp]/[PgDn]"
+Places the cursor on character 1/59, respectively.
+.Ip "[Home]/[End]" 2
+.IX Item "[Home]/[End]"
+Places the cursor at the textual start or end of the current line.
+.Ip "[Del]" 2
+.IX Item "[Del]"
+Deletes the character currently under the text cursor and shifts the 
+remaining text on the current line to the left; if the current line is 
+blank, removes it and shifts all lines below up by one line.
+.Ip "[Backspace]" 2
+.IX Item "[Backspace]"
+See [Del], but affects the character on the left of the cursor.
+.Ip "[Ins]" 2
+.IX Item "[Ins]"
+Toggles inserting/overwriting of existing text; the current mode is 
+indicated by a cursor change (block cursor means insert mode).
+.Ip "[Enter]" 2
+.IX Item "[Enter]"
+In insert mode, wraps the current line at the cursor's position; in 
+overwrite mode (underscore cursor), merely moves the cursor to the 
+start of the next line.
+.Ip "[Ctrl]\-[Y], \-[Z]" 2
+.IX Item "[Ctrl]-[Y], -[Z]"
+Removes an entire (intermediate) line, shifting those below up by one, 
+and places the cursor at the start of the current line.
+.Ip "[Esc]" 2
+.IX Item "[Esc]"
+Quits \fIedit mode\fR and returns to the \fIpinboard view\fR.
+.Ip "[Shift]\-[Left]/[Right]" 2
+.IX Item "[Shift]-[Left]/[Right]"
+Cycles through all notes currently on the pinboard.
+.Ip "[Shift]\-[Up]/[Down]" 2
+.IX Item "[Shift]-[Up]/[Down]"
+Cycles through all notes that are \fIroughly\fR the same color as the 
+current one.  For this purpose, colors have internally been divided 
+into four groups: green, white/yellow, reddish, blue.
+.Ip "([Shift]\-)[Tab]" 2
+.IX Item "([Shift]-)[Tab]"
+Cycles (backwards) through availabe note colors.
+.RE
+.RS 2
+.RE
+.Ip "\(bu" 2
+\&\fICut'n'paste\fR text.  Despite the limitations implied, \fBwmpinboard\fR 
+has support for cutting & pasting to and from the X clipboard:
+.RS 2
+.Ip "\(bu" 2
+In order to copy text to the clipboard, select the desired segment via 
+either the left or the right mouse button: the left one will copy the 
+text post-formatted as done by the command line switch \fB\f(CB\*(C`\-\-dump\*(C'\fB\fR 
+(see the section on "OPTIONS"); the right button will copy the raw selection.  
+Similarly, a left double click will select the word (i.e., all 
+adjoining non-blank characters) at the respective position, a right one 
+will do the same but neglect line breaks as delimiters.  Additionally, 
+you can copy a note's entire raw contents by pressing [Ctrl]\-[R]; 
+[Ctrl]\-[C] will do the same with applied post-formatting.
+.Ip "\(bu" 2
+To paste the clipboard's contents, press the middle button wherever the 
+insertion is supposed to happen.  This will insert the clipboard's 
+current contents, trying to word-wrap the text (at white space and 
+after hyphens).  If in insert mode, following text will be shifted 
+towards the end of the note, trying to word-wrap that as well.
+.Sp
+If you wish to paste something without word-wrapping (e.g., an \s-1URL\s0 
+containing a hyphen), paste it via [Ctrl]\-[I] (think [i]nsert).  This 
+will paste the clipboard's raw contents at the current location of the 
+cursor, shifting subsequent text if in insert mode (not trying to
+word-wrap that either).
+.RE
+.RS 2
+.Sp
+Obvious limitations you should be aware of include:
+.RS 2
+.RE
+.Ip "\(bu" 2
+As is usually the case (about \fBwmpinboard\fR, anyway), size matters.  
+As you know, a note can hold only up to 59 characters, so trying to 
+paste longer strings will result in those being truncated.
+.Ip "\(bu" 2
+If the text to be pasted is formatted in some way or other, this won't 
+be the case any more after it has been pasted: \fBwmpinboard\fR replaces 
+new line characters by blanks and, when pasting using the mouse, tries
+to word-wrap text.
+.Ip "\(bu" 2
+The information stored in the cut buffer needn't necessarily be 
+compatible with \fBwmpinboard\fR in that it may be encoded with another 
+character set.
+.RE
+.RS 2
+.RE
+.Ip "\(bu" 2
+\&\fILeave\fR \fIedit mode\fR.  This is achieved by left-clicking on the
+triangle in the lower right-hand side corner.  If the note is
+completely empty, it will be removed from the board.  In any
+case, this returns to the \fIpinboard view\fR.
+.Ip "\(bu" 2
+\&\fIPop up\fR a \fIpanel\fR with some further options to choose from.  This
+is done by right-clicking on the aforementioned triangle.  To
+learn what the \fIpanel\fR is there for, see the corresponding section
+below.
+.Ip "\(bu" 2
+\&\fIDraw\fR a sketch.  This mode can be activated via the \fIpanel\fR, and
+deactivated by either right-clicking somewhere on the note
+or opening the \fIpanel\fR again.  While in drawing mode, the mouse
+pointer is pencil-shaped, and drawing can be done by keeping
+the left mouse button pressed and dragging the mouse, just as
+you'd expect.  Sketch and text may overlap each other, but keyboard 
+input is ignored while in drawing mode.
+.Ip "\(bu" 2
+\&\fIErase\fR a sketch.  Just like DRAWing mode, this mode is entered
+via the \fIpanel\fR, and can be quit just like the former.  In erase
+mode, the text is hidden, so you needn't guess whether a pixel
+belongs to an entered character or a drawn sketch.  Note that
+the erase cursor's point is slightly larger than the one used
+when drawing.
+.PP
+Note: \fBwmpinboard\fR remembers where you left the text cursor after 
+you last edited a note and restores this position when you edit it the 
+next time.
+.Sh "Edit mode panel"
+.IX Subsection "Edit mode panel"
+This \fIpanel\fR is intended to provide easy access to some options 
+affecting \fIedit mode\fR or the current note in general.  The \fIpanel\fR 
+looks like this (letters denoting the buttons for reference below):
+.PP
+.Vb 5
+\&    +---+---+---+---+
+\&    | a | c | e | g |
+\&    +---+---+---+---+
+\&    | b | d | f | h |
+\&    +---+---+---+---+
+.Ve
+The buttons bear tiny icons which are meant to suggest what they do, 
+which isn't all that easy on a 12x12 pixels area. \fB\f(CB\*(C`:^)\*(C'\fB\fR
+.PP
+Here's a description of what each button does:
+.Ip "(a)" 4
+.IX Item "(a)"
+Left-clicking on this button opens and closes the \fIalarm panel\fR (see 
+below), which allows you to configure alarm settings for the note being 
+edited.  When the \fIalarm panel\fR is visible, the alarm is activated.  
+To turn it off, press the button again and make the panel disappear.
+.Ip "(b)" 4
+.IX Item "(b)"
+This button allows one to cycle through all colors available for notes 
+(20 of them).  Clicking on it won't close the \fIpanel\fR, so this can be 
+done repeatedly.  Using the left mouse button traverses the colors in 
+ascending, using the right button in descending order.  \fINote:\fR colors 
+can also be changed via a keyboard shortcut in \fIedit mode\fR (see that 
+section).
+.Ip "(c)" 4
+.IX Item "(c)"
+This button closes the \fIpanel\fR and returns to \fIedit mode\fR, with
+the sketch-\fIdraw\fRing feature enabled (see above).
+.Ip "(d)" 4
+.IX Item "(d)"
+Closes the \fIpanel\fR and returns to \fIedit mode\fR, with the
+sketch-\fIeras\fRing feature enabled (see above).  Don't panic if entered 
+text vanishes all of a sudden when you do this: this is because 
+\&\fBwmpinboard\fR intentionally hides it to eradicate the need for you to 
+make wild guesses as to what's entered text and which pixels belong to 
+a sketch.
+.Ip "(e)" 4
+.IX Item "(e)"
+This button removes all entered text on the current note and places the 
+text cursor on the very first character.  Besides, it closes the 
+\&\fIpanel\fR, thus returning to \fIedit mode\fR.
+.Ip "(f)" 4
+.IX Item "(f)"
+Pressing this button completely removes a drawn sketch on the current 
+note and returns to \fIedit mode\fR.
+.Ip "(g)" 4
+.IX Item "(g)"
+This option removes the *entire* note from the board and returns to 
+\&\fIpinboard view\fR.
+.Ip "(h)" 4
+.IX Item "(h)"
+This button merely closes the \fIpanel\fR (and thus puts you back in 
+\&\fIedit mode\fR).  The same can be achieved by simply right-clicking in 
+this view.
+.Sh "Alarm panel"
+.IX Subsection "Alarm panel"
+This panel can be accessed from the \fIedit mode panel\fR described above.
+If the panel is visible while the \fIedit mode panel\fR is on, the alarm is
+set, otherwise, it's disabled.
+.PP
+The \fIalarm panel\fR consists of six distinct clickable areas.  The 
+digits to the left and right of the colon are the hour and minute which 
+an alarm is to be set for.  Below them, a date can be specified in 
+month, day order.  On the right, there are two toggle buttons (which 
+can be either green (on) or red (off) and are mutually exclusive).  The 
+top one represents a daily alarm whereas the bottom one indicates/sets 
+a date-specific one.
+.PP
+The hour, minute, month, and day of month fields can each be 
+incremented or decremented by left- or right-clicking on them, 
+respectively.  Clicking on one of the toggle buttons configures the 
+alarm as the respective type.
+.PP
+As the above description implies, there are two distinct kinds of 
+alarms: daily and date-specific ones.
+.PP
+Alarms are generally executed only when in \fIpinboard view\fR and not 
+moving any notes about.  If you're keeping the program busy at the time 
+an alarm would have to occur, it will be delayed until you're finished 
+(i.e., let the program return to idle \fIpinboard view\fR).  The same holds
+if an alarm occurs while another one is running.
+.PP
+If all prerequisites are given and an alarm becomes due, the 
+corresponding note is displayed in edit view, and the display starts to 
+flash on and off, along with the alarm command being executed (see 
+the section on "OPTIONS").  To stop the blinking, click on the note.  From then on, 
+the note will be in \fIedit mode\fR.
+.PP
+For daily alarms, the entered date is ignored, and as the name suggests,
+they're run every day at the specified time.  To deactivate such an 
+alarm, you have to open the \fIedit mode panel\fR and click button (a) to 
+make the \fIalarm panel\fR disappear, which turns the alarm off.
+.PP
+In contrast, date-specific alarms are executed only once, at the 
+specified day and time.  Since a year cannot be specified (explicitly), 
+the alarm will be run on this date's next occurrence within a year from 
+when the alarm was set.  After that, the alarm will automatically be 
+disabled.  If a date-specific alarm becomes due while \fBwmpinboard\fR 
+isn't running, it will be displayed as soon as the program is started 
+the next time\*(--which does \fBnot\fR go for daily alarms.
+.PP
+The default mode for alarms is date-specific, and time and date are 
+initialized with the next full hour when the alarm panel is opened the 
+first time for a given note.
+.PP
+Internally, alarm times are stored in universal format, i.e., if you 
+change the time zone after having set an alarm, the time will stay 
+universally the same but will differ relative to the new time zone from 
+what absolute time you originally set.  This behavior is intended.
+.PP
+Finally, it should be mentioned that there are a few limitations with 
+respect to command line actions (such as \fB\f(CB\*(C`\-\-add\*(C'\fB\fR, \fB\f(CB\*(C`\-\-del\*(C'\fB\fR,
+\&\fB\f(CB\*(C`\-i\*(C'\fB\fR, etc.).  See the section on "RESTRICTIONS".
+.SH "FREQUENTLY ASKED QUESTIONS"
+.IX Header "FREQUENTLY ASKED QUESTIONS"
+.Ip "\(bu" 2
+\&\fIQ:\fR Is a \*(L"pinboard\*(R" this small really of any use?
+.Sp
+\&\fIA:\fR Of course the limited size imposes certain restrictions, but if 
+you think about it, you'll agree that a real life pinboard reminds you 
+of things by the mere existence of notes being pinned to it.  In order 
+to read what they say, you have to step close and, possibly, detach the 
+note.
+.Sp
+Quite similarly, \fBwmpinboard\fR reminds you of things by facing you with 
+colored representations of notes on your screen.  To find out what it 
+was you intended them to remind you of, all you have to do is click on 
+a note, which will then be displayed full size.  Furthermore, the alarm 
+feature introduced in a later version allows for even more explicit 
+reminders and thus renders \fBwmpinboard\fR even more powerful in a way 
+than any real-life cork board. \fB\f(CB\*(C`:\-)\*(C'\fB\fR
+.Sp
+By choosing from a variety of possible colors, you can assign 
+particular colors to certain kinds of reminders, which may further 
+enhance \fBwmpinboard\fR's usability.  Moreover, you can place certain notes 
+on certain areas of the board to emphasize their category, urgency, 
+etc.  It's up to you what to make of it.
+.Sp
+Finally, by adding drawing capabilities, I've definitely overcome the 
+contents quantity barrier imposed by the maximum number of 59 
+characters, for as everyone knows, a picture is worth more than a 
+thousand words. *grin*
+.Ip "\(bu" 2
+\&\fIQ:\fR I don't live in an English-speaking country, so what about extended
+characters (umlauts, accents, cyrillic alphabet)?
+.Sp
+\&\fIA:\fR \fBwmpinboard\fR allows you to use an arbitrary 8bit X font, provided 
+that its characters are of a fixed size of 6x10 (or, deprecated but 
+possible, anything <= 7x10) pixels.  The default font is \*(L"6x10\*(R" (more 
+precisely, it's called
+\&\*(L"\-misc-fixed-medium-r-normal\*(--10\-100\-75\-75\-c-*\-ISO8859\-1\*(R"), an
+\&\s-1ISO8859\-1\s0 (Latin1) font which should be part of every XFree 
+installation.
+.Sp
+In order to make \fBwmpinboard\fR use another font, run it as
+.Sp
+.Vb 1
+\&  $ wmpinboard --font=FONT
+.Ve
+where \fB\s-1FONT\s0\fR is either a shortcut for a compiled-in font name (see 
+the section on "OPTIONS" for a list of those) or a valid, complete X font 
+descriptor.  This is a configuration directive, meaning that no other 
+instance of \fBwmpinboard\fR may be running at the time.  Note that this 
+\&\fIonly works if there are no more notes on the board\fR.  It's 
+intentionally been made impossible to change the font while there are 
+notes saved in \fBwmpinboard\fR's data file, since this might result in 
+garbage being displayed.  Of course even a font specified via a 
+shortcut has to exist on your system in order to be usable.
+.Sp
+If a configured custom font cannot be loaded or has invalid dimensions, 
+\&\fBwmpinboard\fR will try to revert.  Note that this won't affect the font 
+name saved along with the data, though.
+.Ip "\(bu" 2
+\&\fIQ:\fR How can I disable those vexing, superfluous animations?
+.Sp
+\&\fIA:\fR
+.Sp
+.Vb 1
+\&  $ wmpinboard --light
+.Ve
+.Ip "\(bu" 2
+\&\fIQ:\fR Why aren't those animations smooth all of the time?  Sometimes it 
+looks like they're being skipped entirely.
+.Sp
+\&\fIA:\fR This presumably is a multitasking issue: depending on the current 
+system load and \fBwmpinboard\fR's/the X server's recent \s-1CPU\s0 usage 
+history, it may take a moment until the scheduling has been adapted to 
+the suddenly increased \s-1CPU\s0 load implied by displaying the animation, 
+and short as it is, it may already be finished until this has happened, 
+i.e., it's the X server lagging behind in updating the program's 
+display if \fBwmpinboard\fR's been idle for some time prior to that.  It 
+may sound paradoxical, but the effect is the more likely to show the 
+lower the system's load is.  I don't see a way to avoid this
+effect\*(--either this, or you turn off animations altogether.
+.Ip "\(bu" 2
+\&\fIQ:\fR When I leave \fBwmpinboard\fR idle in edit mode for some time, edit 
+mode is terminated automatically.  Is that intended?
+.Sp
+\&\fIA:\fR Yes.  After 60 idle seconds (that's the default; see 
+the section on "OPTIONS") in edit mode (no mouse click and no keyboard input), edit 
+mode is terminated automatically.  If the note being edited happens to 
+be blank, it will be discarded (or removed if an existing note is being 
+edited).
+.Sp
+This timeout can, however, be adjusted according to your preferences or
+turned off using the \fB\f(CB\*(C`\-t\*(C'\fB\fR parameter.  See the section on "OPTIONS" for this.
+.Ip "\(bu" 2
+\&\fIQ:\fR When does \fBwmpinboard\fR save its data?
+.Sp
+\&\fIA:\fR Notes data is saved on each of these occasions:
+.RS 2
+.Ip "\(bu" 2
+whenever edit mode is terminated
+.Ip "\(bu" 2
+when you switch notes in edit mode (via [Shift]\-[arrow\ key])
+.Ip "\(bu" 2
+when a note has been moved on the board
+.Ip "\(bu" 2
+when an interactive instance is running and you run \fBwmpinboard\fR from 
+the command line, making it dump, add, or delete notes
+.Ip "\(bu" 2
+when killed via \s-1SIGINT\s0 or \s-1SIGTERM\s0 and edit mode is active
+.RE
+.RS 2
+.Sp
+Notes are saved to a file called \fI.wmpinboarddata\fR in your home 
+directory (see the section on "FILES").
+.RE
+.Ip "\(bu" 2
+\&\fIQ:\fR I've tried my best and littered the entire pinboard with quite a 
+lot of notes.  Now I can't seem to be able to add another one.
+.Sp
+\&\fIA:\fR There's a compile-time limit of 20 notes.  I think more notes on 
+this tiny a board really don't make any sense.
+.Ip "\(bu" 2
+\&\fIQ:\fR I've explicitly configured my window manager for click-based 
+rather than mouse-following focus, but \fBwmpinboard\fR's focus follows 
+the mouse regardless.  Can I change this?
+.Sp
+\&\fIA:\fR By default, \fBwmpinboard\fR actively claims the keyboard input 
+focus (if it's in note edit mode) whenever the pointer is moved over the 
+application's area.  Since \fBwmpinboard\fR is a dock applet, i.e., a 
+withdrawn rather than a \*(L"real\*(R" X window, it can't be assigned a focus 
+in the same way as to the latter ones.  However, running \fBwmpinboard\fR 
+with the parameter \fB\f(CB\*(C`\-c\*(C'\fB\fR will make it emulate some sort of
+click-based focusing.  This means, it actively claims the keyboard 
+focus only on these occasions:
+.RS 2
+.Ip "\(bu" 2
+when a new note is created (\fInot\fR when you click on an existing
+note\*(--you'll have to explicitly click on the editing area to make it 
+claim focus; this way, you can just view a note without any change to 
+keyboard focus)
+.Ip "\(bu" 2
+when you click somewhere on the text area in edit mode
+.RE
+.RS 2
+.Sp
+Once keyboard-focused, \fBwmpinboard\fR will keep it until another window 
+is explicitly focused (usually by clicking on its title bar or 
+border).  To focus \fBwmpinboard\fR again when it's lost focus, you'll 
+have to click on its text area in edit mode.  This click will only 
+focus the application and not have the usual cursor-positioning effect.
+.Sp
+This feature is to be considered experimental since I'm not sure of how 
+much use it really is.  A mouse-following focus is the recommended mode 
+of operation.
+.RE
+.Ip "\(bu" 2
+\&\fIQ:\fR I've noticed that after a while, some sort of darker stains 
+appear on my notes.  Is that a bug in some drawing routine?
+.Sp
+\&\fIA:\fR No, this is not a bug.  These \*(L"stains\*(R" are meant to resemble 
+creases, caused by frequent handling of a particular note (wear & tear, 
+you see?).  In fact, they're added with a certain probability whenever 
+you view a note by clicking on it (note that leafing through notes via 
+[Shift]\-[arrow\ keys] is \fInot\fR affected), when you clear its textual 
+or drawn contents via the \fIedit mode panel\fR (very outwearing, that 
+\&\fB;\-)\fR\ ), and when a note is moved.  This feature can be disabled at 
+compile time by running \fIconfigure\fR with \f(CW\*(C`\-\-disable\-creases\*(C'\fR as a
+parameter.
+.Sp
+To prevent the question, no, worn-out notes cannot be ironed to get rid 
+of the creases.  Sorry. \fB\f(CB\*(C`:\-p\*(C'\fB\fR
+.Ip "\(bu" 2
+\&\fIQ:\fR Is \fBwmpinboard\fR compatible with \fBAfterStep\fR's \fBWharf\fR?
+.Sp
+\&\fIA:\fR \fBwmpinboard\fR tries to autodetect whether \fBWindow Maker\fR is 
+running and sets itself up accordingly.  If this doesn't work for you 
+for some reason, you can explicitly make it run in either Withdrawn- or 
+NormalState using the \fB\f(CB\*(C`\-w\*(C'\fB\fR or \fB\f(CB\*(C`\-n\*(C'\fB\fR flag, respectively.  See 
+the section on "OPTIONS".
+.Sp
+Swallowing evidently works with \fBAfterStep\fR 1.6.10; I don't know about 
+earlier versions.  A \fBWharf\fR config line you might try is this:
+.Sp
+.Vb 1
+\&  *Wharf wmpinboard nil MaxSwallow "wmpinboard" wmpinboard &
+.Ve
+Besides, \fBwmpinboard\fR has been reported to work with \fBBlackbox\fR.
+.Ip "\(bu" 2
+\&\fIQ:\fR I have X running at a color depth of 8 bits, i.e., in palette 
+mode, and \fBwmpinboard\fR obviously requires too many colors and thus 
+looks real messy (or doesn't run at all, complaining about \*(L"not enough 
+free color cells\*(R").  What can I do about this?
+.Sp
+\&\fIA:\fR As of version 0.99.1, the recommended solution is to upgrade 
+whatever component of your system restricts you to a palette mode.
+.Ip "\(bu" 2
+\&\fIQ:\fR Can I run multiple instances of \fBwmpinboard\fR as the same user, 
+simultaneously?
+.Sp
+\&\fIA:\fR No, this is certainly not a good idea.  The run-time behavior may 
+be unpredictable, and your data file can get corrupted.  Therefore, any 
+\&\fBwmpinboard\fR process that's to be run interactively first checks 
+whether another interactive instance is running, and if so, refuses to 
+run.
+.Ip "\(bu" 2
+\&\fIQ:\fR I've just upgraded from a pre-0.7 version of \fBwmpinboard\fR and 
+noticed that its data file format has changed completely since.  Is 
+there a way to upgrade and yet keep my existing notes?
+.Sp
+\&\fIA:\fR There's a \fBPerl\fR script doing the conversion included with the 
+distribution (the source one, anyway).  If your package didn't include 
+that, feel free to mail to the author (see the section on "AUTHOR" at the end of 
+this documentation).
+.Ip "\(bu" 2
+\&\fIQ:\fR I find a mere 59 characters per note to be a real limitation.  
+How about making \fBwmpinboard\fR pop up an external window with more room 
+for that?  Or how about assigning that job to an external editor?
+.Sp
+\&\fIA:\fR There's a variety of comprehensive programs for keeping notes out 
+there, offering this functionality but being rather heavy-weight since 
+they are linked against one \s-1GUI\s0 library or another (\fBCoolNotes\fR or 
+\&\fBKNotes\fR come to mind).  On the other hand, I couldn't find a
+\&\fB\s-1WM\s0\fR\-conforming reminder I could omnipresently stick to my desktop 
+anywhere, so I wrote \fBwmpinboard\fR.  I wanted it to be small, neat, 
+easy to use, and yet useful in a way.
+.Sp
+I hope that's about what the program is currently like.  And I'd prefer 
+to keep it like that rather than inflate it by linking against a \s-1GUI\s0 
+library\*(--eventually, the note editing code would outweigh the rest of 
+the application by a factor, and people would probably still create 
+notes mostly shorter than 60 characters.  If you restrict your memos to 
+keywords and abbreviations, that's quite a lot.
+.Sp
+I want \fBwmpinboard\fR to remain an applet in that it doesn't open up 
+external windows and use (if just temporarily) additional desktop 
+space.  I explicitly wrote it to have something omnipresent at a fixed 
+position on my desktop.  I find it preferable to have the notes pop up 
+in place rather than somewhere else on the screen.
+.Sp
+Personally, I use other programs for larger notes too; \fBwmpinboard\fR
+has been designed for things smaller in size and greater in urgency,
+it's in no way meant to be a comprehensive knowledge base application
+of any kind.
+.Sp
+Summing up, I think a dock applet should be small both regarding its
+on-screen representation and the resources it uses.  That's why I 
+don't intend to add any pop-up dialogs or similar things to 
+\&\fBwmpinboard\fR.
+.Ip "\(bu" 2
+\&\fIQ:\fR I've tried the program, yet I can't help finding it utterly 
+useless.  What shall I do?
+.Sp
+\&\fIA:\fR The solution is simple.  Just don't use it.
+.Ip "\(bu" 2
+\&\fIQ:\fR Will your answer to this question be \*(L"no\*(R"?
+.Sp
+\&\fIA:\fR Nope.
+.SH "HINTS"
+.IX Header "HINTS"
+.Ip "\(bu" 2
+A good way of making the best of the organizational features offered by 
+\&\fBwmpinboard\fR is to use certain colors and locations on the pinboard to 
+indicate urgency and contents of a note.  For example, you might use 
+each of the color groups for a certain kind of reminder, because that 
+enables you to leaf through all notes with related contents via
+[Shift]\-[arrow\ keys] in edit mode.  Besides, you might assign each 
+corner of the board a specific urgency, altogether allowing you to 
+derive a note's type from its color and its urgency from its location 
+on the board.  Thanks again to the ability to leaf through all notes 
+belonging to the same group of colors, notes with similar contents will 
+still be clustered in a way.
+.SH "UNDOCUMENTED FEATURES"
+.IX Header "UNDOCUMENTED FEATURES"
+This piece of documentation doesn't cover any undocumented features.
+.SH "FILES"
+.IX Header "FILES"
+.Ip "\fI~/.wmpinboarddata\fR" 2
+.IX Item "~/.wmpinboarddata"
+the user's \fBwmpinboard\fR data file
+.Ip "\fI~/.wmpinboarddata.new\fR" 2
+.IX Item "~/.wmpinboarddata.new"
+temporary file created momentarily when saving data
+.SH "ENVIRONMENT VARIABLES"
+.IX Header "ENVIRONMENT VARIABLES"
+.Ip "$HOME" 2
+.IX Item "$HOME"
+the user's home directory
+.SH "RESTRICTIONS"
+.IX Header "RESTRICTIONS"
+.Ip "\(bu" 2
+\&\fBwmpinboard\fR relies on a dock app tile size of at least 64x64 pixels.  
+In fact, using smaller tiles renders the applet rather useless, as, 
+e.g., opening the edit mode panel becomes impossible.
+.Ip "\(bu" 2
+Unpredictable effects may be the results if a command line action is
+taken while an alarm is running and others are due simultaneously.
+If just a single alarm is active and no others are due, that alarm will
+be cancelled when the two instances of \fBwmpinboard\fR synchronize.
+If more instances are due during the process, a race conditions arises
+that can't be solved satisfactorily due to the program's internal
+structure and organization.  Still, in theory, nothing critical will
+happen, and the most you'll lose will be an alarm or two.
+.Ip "\(bu" 2
+\&\fBwmpinboard\fR data files are not designed to be portable across 
+architectures.  Due to differences in data type representations that 
+are likely otherwise, a datafile can only be reliably used by program 
+binaries running on machines of the same architecture.
+.Ip "\(bu" 2
+Certainly of no interest to anyone, but mentioned for the sake of 
+completeness: \fBwmpinboard\fR's alarm features will start to fail past 
+04:14:07 on Jan 19, 2037, which is due to the legacy Un*x time format.
+.SH "BUGS"
+.IX Header "BUGS"
+If you stumble on any bugs, feel free to mail the author.  The same 
+goes if you encounter any problems running/using the program.  Be sure 
+to include any information you consider relevant, i.e., at a minimum, 
+the version of \fBwmpinboard\fR you're using as well as your \s-1OS\s0 and X 
+versions.
+.PP
+Also, further suggestions are always welcome.  Please check the \fI\s-1TODO\s0\fR 
+file that's part of the distribution to see if what you're about to 
+suggest isn't already on my \*(L"to do\*(R" list, or has been suggested earlier 
+and was rejected for one reason or other.
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+\&\fIwmaker\fR\|(1)
+.SH "AUTHOR"
+.IX Header "AUTHOR"
+\&\fBwmpinboard\fR is copyrighted (c) 1998\-2000 by Marco Go\*:tze, 
+<gomar at mindless.com>.  It is distributed under the terms of the 
+\&\s-1GNU\s0 General Public License, revision 2 or any later revision thereof.  
+Use at your own risk.
+.PP
+New releases of and themes for \fBwmpinboard\fR can be found at
+<http://www.tu-ilmenau.de/~gomar/stuff/wmpinboard/>, or 
+that was true at least by the time this document was last updated.
diff --git a/man/wmpinboard.pod b/man/wmpinboard.pod
new file mode 100644
index 0000000..0e85b40
--- /dev/null
+++ b/man/wmpinboard.pod
@@ -0,0 +1,1022 @@
+=head1 NAME
+
+B<wmpinboard> - a B<Window Maker> dock app resembling a miniature pinboard
+
+=head1 SYNOPSIS
+
+  wmpinboard [options]
+
+=head2 What wmpinboard is
+
+B<wmpinboard> is a B<Window Maker> dock applet resembling a miniature 
+pinboard.  It's intended to somewhat relieve heavily littered desktops 
+by allowing you to place reminders on a graphical on-screen pinboard 
+rather than producing a mess of real notes all around your keyboard 
+(thus being environmentally A Good Thing, too B<;-)> ).  It supports 
+arbitrary 6x10 X fonts and has XLocale support, enabling you to enter 
+locale-dependent special characters if set up appropriately.  Besides 
+text, you can add small monochrome sketches to your notes or simply 
+encircle or underline words as a means of emphasis, and alarms can be 
+set to explicitly remind you of things.  Above all, B<wmpinboard> is 
+animated in redundant ways to make it look even more attractive, and 
+themeability provides for a way of adapting its appearance to that of 
+the rest of your desktop.
+
+=head2 What wmpinboard ISN'T
+
+Clearly, B<wmpinboard> doesn't allow you to keep an unlimited number of 
+notes holding arbitrary amounts of information, and that's not what 
+it's meant to do.  Just as real notes offer limited space, so do those 
+simulated by B<wmpinboard>.  Besides, as a dock applet, it aims at 
+being small and neat and yet useful in a way, and that's what it is, 
+too, or considered to be by some people, anyway.  If you need room for 
+more comprehensive reminders, use another program, either additionally 
+or exclusively.  There's a variety of such out there, but their niche 
+is different from that which B<wmpinboard> claims.
+
+=head1 OPTIONS
+
+B<wmpinboard>'s command-line options can be roughly divided into four 
+groups: configuration directives, run-time options, command-line 
+actions, and general options.  Generally, B<wmpinboard> supports
+GNU-style long options (which may be abbreviated unambiguously) as well 
+as short ones for parameters used more commonly.
+
+=head2 Configuration directives
+
+This type of command-line options changes some aspect of 
+B<wmpinboard>'s configuration that is saved along with the data and 
+thus set in a more permanent way.  Only one such parameter may be 
+specified per call, and there mustn't be another instance running.
+
+=over 2
+
+=item B<C<--font=FONT>>
+
+Makes B<wmpinboard> use the specified font; B<C<FONT>> can be one of 
+the shortcuts listed when running the program with "B<C<--help>>" as a
+parameter, or a complete X descriptor of a fixed size 6x10 font.  The
+pinboard I<must be empty> in order for this option to be applicable.  
+For more details, see L<"FREQUENTLY ASKED QUESTIONS">.
+
+=item B<C<--theme=FILE>>
+
+Configures B<wmpinboard> to load the specified theme when started 
+interactively the next time.  B<C<FILE>> is the location of a 
+B<wmpinboard> theme file (typically with a file name extension of 
+F<.wmpbtheme>).  If it can't be loaded when run interactively, the 
+program will revert to its default theme.  If B<C<FILE>> is an empty 
+string or "default", the use of a custom theme will be deactivated.
+
+Themes affect B<wmpinboard>'s appearance, in particular, its pinboard, 
+edit mode and alarm panel pixmaps, the latter's digits, and possibly 
+the location of the pinboard mode label area (via which notes are 
+created).  For downloading themes, or if you're inclined to create one 
+yourself and need instructions, check out the program's home page (see 
+L<"AUTHOR"> or B<wmpinboard>'s "B<C<--help>>" output for the URL).  The 
+themes kit containing instructions and samples on how to create theme 
+files for B<wmpinboard> that can be downloaded there is also included 
+with the source package of the program.
+
+=item B<C<--alarm-cmd=CMD>>
+
+Configures B<C<CMD>> as the command to be executed on alarms.  E.g., 
+you could use "C<xkbbell>" to cause the program to beep on such 
+occassions, or make it run some sound-playing program.  To reset the 
+alarm command to none, make B<C<CMD>> a zero-length string.
+
+=back
+
+=head2 Run-time options
+
+=over 2
+
+=item B<C<-d DISPLAY>> or B<C<--display=DISPLAY>>
+
+Uses the specified X display rather than the default one.
+
+=item B<C<-c>> or B<C<--click-to-focus>>
+
+This turns on some emulation of a click-based keyboard focus mode. See
+L<"FREQUENTLY ASKED QUESTIONS">.
+
+=item B<C<-t TIME>> or B<C<--timeout=TIME>>
+
+Sets the edit mode timeout (i.e., the number of seconds of idleness 
+after which edit mode is terminated automatically) to B<C<TIME>> 
+seconds.  The compile-time default is 60s, but this may have been 
+changed for your particular build; run with B<C<-v>> if in doubt to 
+check that.  Specifying a value of 0 (zero) will disable the timeout.
+
+=item B<C<-n>> or B<C<--normal-state>>
+
+Forces B<wmpinboard> to run in so-called NormalState, which is 
+preferred by B<AfterStep>'s B<Wharf>.
+
+=item B<C<-w>> or B<C<--withdrawn-state>>
+
+Forces the program to run in so-called WithdrawnState, as desired by 
+the B<Window Maker> dock.  This option and the previous one are mutually 
+exclusive.  Note also that B<wmpinboard> tries to auto-detect whether 
+B<Window Maker> is running and sets itself up accordingly.  Using B<C<-n>>
+or B<C<-w>> should only be necessary in case those heuristics fail on 
+your system for some reason or other.
+
+=item B<C<--light>>
+
+Use this switch to suppress animations.
+
+=back
+
+=head2 Command-line actions
+
+Even though B<wmpinboard> is by design an interactive application, 
+there may be occasions when it comes in handy to be able to 
+access/manipulate notes from the command line.  That's why the program 
+offers a set of command-line options allowing for basic operations of 
+that kind.  Still, it should be kept in mind that B<wmpinboard> is 
+primarily meant to be used interactively.
+
+All of the options below will, if an interactive instance of 
+B<wmpinboard> is running in the background, cause that to save its data 
+(and quit I<edit mode>, if necessary), and if any changes are made by 
+the respective option, the interactive instance will then be signalled 
+to re-read the data file.  Even though the implemented methods of
+inter-process communication should generally be sufficiently safe 
+with respect to avoiding data file corruption, it's in theory possible 
+to undermine the concept and cause damage that way--yet this won't 
+happen unless you deliberately take pains to achieve the goal.  
+Generally, everything should work fine as long as you don't try running 
+multiple non-interactive instances of B<wmpinboard> simultaneously.
+
+Only one of the below actions can be specified per call to B<wmpinboard>.
+
+=over 2
+
+=item B<C<--dump>>
+
+This dumps the contents of all notes, replacing line breaks by spaces 
+(unless preceded by a hyphen) and shortening sequences of blanks.  The 
+list of dumped strings will be sorted by color groups.  If you use 
+special characters in your notes, make sure your terminal's running 
+with the same character set as B<wmpinboard>, or what you'll see might 
+have a garbage-like quality.
+
+Each line of output represents one note and is prefixed by the internal
+number I<currently> identifying the respective note and, if an alarm is
+configured for the respective note, time and date (or "daily").
+
+=item B<C<--dump-raw>>
+
+Unlike the "cooked" dump described above, this just dumps the raw 
+contents of all notes without applying any kind of formatting.  May 
+come in handy if your notes happen to contain E-mail addresses or other 
+things for which lines 10 characters wide are too narrow.
+
+=item B<C<--del=NUMBER>>
+
+This option will remove the note identified by B<C<NUMBER>> from the 
+pinboard.  B<C<NUMBER>> is a number determined by the output of either 
+dump option, which should be consulted right before using this one, 
+since note numbers may change when notes are moved around on the board 
+or others are removed.
+
+=item B<C<--add=STRING>>
+
+When run with this option, B<wmpinboard> will add a new note (provided 
+the maximal number of notes has not yet been reached) at a random 
+position on the board, with contents B<C<STRING>>, word-wrapping the 
+text at the end of the note's lines where necessary (after white space 
+and hyphens).  If due to this wrapping, the entire string cannot be 
+stored on the note, the remainder will be discarded silently.
+
+In order to create a note with a certain color, the string can be
+prefixed by a color code specifying the group of colors which a random 
+color is to be selected from (code letters are recognized
+case-insensitively):
+
+  %G - green
+  %Y - yellow/white
+  %R - reddish
+  %B - blue
+
+Alternatively or additionally, you may specify a position code as "%1" 
+through "%9", defining an approximate position on the board where the 
+note is to be placed.  Each of the nine figures corresponds to a ninth 
+of the board with its index assigned in accordance with the layout of 
+your keypad (i.e., "%1" meaning lower left, "%9" upper right corner, 
+and so forth).
+
+Thus,
+
+  wmpinboard --add '%g%5test'
+
+will place a green note saying "test" at the center of the board.
+
+(Note: The "%" character can be escaped by a second one if you want to
+add an un-prefixed string starting with a percent character.)
+
+=item B<C<--add-raw=STRING>>
+
+Via this option, a new note can be added from the command line 
+(provided that this won't exceed the maximum number of notes).  
+B<C<STRING>> specifies the I<raw> contents of the note, as printed by 
+B<C<--dump-raw>>.  The same set of color group and position codes as 
+for the previous option applies.
+
+=back
+
+=head2 General options
+
+=over 2
+
+=item B<C<-h>> or B<C<--help>>
+
+This prints a help screen listing command line options together with 
+brief descriptions.
+
+=item B<C<-i>> or B<C<--info>>
+
+Prints information about the current user configuration (font, theme, 
+alarm command) and some useless statistics.
+
+=item B<C<-v>> or B<C<--version>>
+
+This prints some more detailed version information, in particular, 
+which compile-time settings this binary was built with.
+
+=back
+
+=head1 DESCRIPTION
+
+B<wmpinboard> operates in basically two different modes, namely, the 
+I<pinboard view> and I<edit mode>.  Furthermore, a I<panel> of buttons 
+granting access to extended options can be popped up in I<edit mode>,
+which in turn allows you to display the I<alarm panel> to configure
+alarm settings for the current note.
+
+=head2 Pinboard view
+
+This is B<wmpinboard>'s normal mode of operation.  A potentially
+chaotic arrangement of tiny squares on a beige-colored oblong (default 
+theme) is meant to resemble notes pinned to a cork board.  Possible 
+actions include:
+
+=over 2
+
+=item *
+
+I<Add> a note, by left-clicking on the board's "TO DO" label.  This 
+creates a new, blank, randomly-colored note at a random position on the 
+board and puts B<wmpinboard> in I<edit mode> (see below).  If you 
+prefer to place a new note at a certain position before being prompted 
+to enter its contents, this can be done by moving the mouse cursor 
+after having clicked on the label.  This will realize the note and 
+allow you to drag it to a position of your choice.  B<wmpinboard> will 
+switch to I<edit mode> as soon as you release the mouse button.
+
+=item *
+
+I<Edit>/I<view> a note, by left-clicking on a note.  This switches
+to I<edit mode> (described below).
+
+=item *
+
+I<Move> a note, by dragging it using the right mouse button.
+This also raises the note in question on top of all others.
+Depending on its horizontal position, the note will be tilted
+automatically.  As a side-effect, a single brief right-click
+can be used to raise a note on top of overlapping ones without
+moving it.
+
+By dragging a note with the left mouse button, you can move it without 
+changing its level with respect to other notes, i.e., without raising 
+it on top of all others.
+
+=back
+
+=head2 Edit mode
+
+This mode serves two purposes: on the one hand, it presents you with a 
+"full-size" view of a note's contents, on the other, you can use the 
+occasion to edit it.  Due to its limited size, a note can hold up to 10 
+characters on 6 lines (minus one on the last, i.e., 59 characters 
+altogether), plus a monochrome sketch of some kind.  Possibly actions:
+
+=over 2
+
+=item *
+
+I<Enter> text.  B<wmpinboard> supports user-selectable fonts and dead 
+keys, so you should be able to enter any characters that are usually 
+accessible via your keyboard and have them displayed correctly.  
+Furthermore, the cursor can be moved around using the arrow keys (or 
+EMACS-style via [Ctrl]-[N]/[P]/[F]/[B], if you are so inclined).  
+Alternatively, it can be placed explicitly by left-clicking where you 
+want it to be.  Other special keys that are supported include:
+
+=over 2
+
+=item [PgUp]/[PgDn]
+
+Places the cursor on character 1/59, respectively.
+
+=item [Home]/[End]
+
+Places the cursor at the textual start or end of the current line.
+
+=item [Del]
+
+Deletes the character currently under the text cursor and shifts the 
+remaining text on the current line to the left; if the current line is 
+blank, removes it and shifts all lines below up by one line.
+
+=item [Backspace]
+
+See [Del], but affects the character on the left of the cursor.
+
+=item [Ins]
+
+Toggles inserting/overwriting of existing text; the current mode is 
+indicated by a cursor change (block cursor means insert mode).
+
+=item [Enter]
+
+In insert mode, wraps the current line at the cursor's position; in 
+overwrite mode (underscore cursor), merely moves the cursor to the 
+start of the next line.
+
+=item [Ctrl]-[Y], -[Z]
+
+Removes an entire (intermediate) line, shifting those below up by one, 
+and places the cursor at the start of the current line.
+
+=item [Esc]
+
+Quits I<edit mode> and returns to the I<pinboard view>.
+
+=item [Shift]-[Left]/[Right]
+
+Cycles through all notes currently on the pinboard.
+
+=item [Shift]-[Up]/[Down]
+
+Cycles through all notes that are I<roughly> the same color as the 
+current one.  For this purpose, colors have internally been divided 
+into four groups: green, white/yellow, reddish, blue.
+
+=item ([Shift]-)[Tab]
+
+Cycles (backwards) through availabe note colors.
+
+=back
+
+=item *
+
+I<Cut'n'paste> text.  Despite the limitations implied, B<wmpinboard> 
+has support for cutting & pasting to and from the X clipboard:
+
+=over 2
+
+=item *
+
+In order to copy text to the clipboard, select the desired segment via 
+either the left or the right mouse button: the left one will copy the 
+text post-formatted as done by the command line switch B<C<--dump>> 
+(see L<"OPTIONS">); the right button will copy the raw selection.  
+Similarly, a left double click will select the word (i.e., all 
+adjoining non-blank characters) at the respective position, a right one 
+will do the same but neglect line breaks as delimiters.  Additionally, 
+you can copy a note's entire raw contents by pressing S<[Ctrl]-[R]>; 
+S<[Ctrl]-[C]> will do the same with applied post-formatting.
+
+=item *
+
+To paste the clipboard's contents, press the middle button wherever the 
+insertion is supposed to happen.  This will insert the clipboard's 
+current contents, trying to word-wrap the text (at white space and 
+after hyphens).  If in insert mode, following text will be shifted 
+towards the end of the note, trying to word-wrap that as well.
+
+If you wish to paste something without word-wrapping (e.g., an URL 
+containing a hyphen), paste it via S<[Ctrl]-[I]> (think [i]nsert).  This 
+will paste the clipboard's raw contents at the current location of the 
+cursor, shifting subsequent text if in insert mode (not trying to
+word-wrap that either).
+
+=back
+
+Obvious limitations you should be aware of include:
+
+=over 2
+
+=item *
+
+As is usually the case (about B<wmpinboard>, anyway), size matters.  
+As you know, a note can hold only up to 59 characters, so trying to 
+paste longer strings will result in those being truncated.
+
+=item *
+
+If the text to be pasted is formatted in some way or other, this won't 
+be the case any more after it has been pasted: B<wmpinboard> replaces 
+new line characters by blanks and, when pasting using the mouse, tries
+to word-wrap text.
+
+=item *
+
+The information stored in the cut buffer needn't necessarily be 
+compatible with B<wmpinboard> in that it may be encoded with another 
+character set.
+
+=back
+
+=item *
+
+I<Leave> I<edit mode>.  This is achieved by left-clicking on the
+triangle in the lower right-hand side corner.  If the note is
+completely empty, it will be removed from the board.  In any
+case, this returns to the I<pinboard view>.
+
+=item *
+
+I<Pop up> a I<panel> with some further options to choose from.  This
+is done by right-clicking on the aforementioned triangle.  To
+learn what the I<panel> is there for, see the corresponding section
+below.
+
+=item *
+
+I<Draw> a sketch.  This mode can be activated via the I<panel>, and
+deactivated by either right-clicking somewhere on the note
+or opening the I<panel> again.  While in drawing mode, the mouse
+pointer is pencil-shaped, and drawing can be done by keeping
+the left mouse button pressed and dragging the mouse, just as
+you'd expect.  Sketch and text may overlap each other, but keyboard 
+input is ignored while in drawing mode.
+
+=item *
+
+I<Erase> a sketch.  Just like DRAWing mode, this mode is entered
+via the I<panel>, and can be quit just like the former.  In erase
+mode, the text is hidden, so you needn't guess whether a pixel
+belongs to an entered character or a drawn sketch.  Note that
+the erase cursor's point is slightly larger than the one used
+when drawing.
+
+=back
+
+Note: B<wmpinboard> remembers where you left the text cursor after 
+you last edited a note and restores this position when you edit it the 
+next time.
+
+=head2 Edit mode panel
+
+This I<panel> is intended to provide easy access to some options 
+affecting I<edit mode> or the current note in general.  The I<panel> 
+looks like this (letters denoting the buttons for reference below):
+
+    +---+---+---+---+
+    | a | c | e | g |
+    +---+---+---+---+
+    | b | d | f | h |
+    +---+---+---+---+
+
+The buttons bear tiny icons which are meant to suggest what they do, 
+which isn't all that easy on a 12x12 pixels area. B<C<:^)>>
+
+Here's a description of what each button does:
+
+=over 4
+
+=item (a)
+
+Left-clicking on this button opens and closes the I<alarm panel> (see 
+below), which allows you to configure alarm settings for the note being 
+edited.  When the I<alarm panel> is visible, the alarm is activated.  
+To turn it off, press the button again and make the panel disappear.
+
+=item (b)
+
+This button allows one to cycle through all colors available for notes 
+(20 of them).  Clicking on it won't close the I<panel>, so this can be 
+done repeatedly.  Using the left mouse button traverses the colors in 
+ascending, using the right button in descending order.  I<Note:> colors 
+can also be changed via a keyboard shortcut in I<edit mode> (see that 
+section).
+
+=item (c)
+
+This button closes the I<panel> and returns to I<edit mode>, with
+the sketch-I<draw>ing feature enabled (see above).
+
+=item (d)
+
+Closes the I<panel> and returns to I<edit mode>, with the
+sketch-I<eras>ing feature enabled (see above).  Don't panic if entered 
+text vanishes all of a sudden when you do this: this is because 
+B<wmpinboard> intentionally hides it to eradicate the need for you to 
+make wild guesses as to what's entered text and which pixels belong to 
+a sketch.
+
+=item (e)
+
+This button removes all entered text on the current note and places the 
+text cursor on the very first character.  Besides, it closes the 
+I<panel>, thus returning to I<edit mode>.
+
+=item (f)
+
+Pressing this button completely removes a drawn sketch on the current 
+note and returns to I<edit mode>.
+
+=item (g)
+
+This option removes the *entire* note from the board and returns to 
+I<pinboard view>.
+
+=item (h)
+
+This button merely closes the I<panel> (and thus puts you back in 
+I<edit mode>).  The same can be achieved by simply right-clicking in 
+this view.
+
+=back
+
+=head2 Alarm panel
+
+This panel can be accessed from the I<edit mode panel> described above.
+If the panel is visible while the I<edit mode panel> is on, the alarm is
+set, otherwise, it's disabled.
+
+The I<alarm panel> consists of six distinct clickable areas.  The 
+digits to the left and right of the colon are the hour and minute which 
+an alarm is to be set for.  Below them, a date can be specified in 
+month, day order.  On the right, there are two toggle buttons (which 
+can be either green (on) or red (off) and are mutually exclusive).  The 
+top one represents a daily alarm whereas the bottom one indicates/sets 
+a date-specific one.
+
+The hour, minute, month, and day of month fields can each be 
+incremented or decremented by left- or right-clicking on them, 
+respectively.  Clicking on one of the toggle buttons configures the 
+alarm as the respective type.
+
+As the above description implies, there are two distinct kinds of 
+alarms: daily and date-specific ones.
+
+Alarms are generally executed only when in I<pinboard view> and not 
+moving any notes about.  If you're keeping the program busy at the time 
+an alarm would have to occur, it will be delayed until you're finished 
+(i.e., let the program return to idle I<pinboard view>).  The same holds
+if an alarm occurs while another one is running.
+
+If all prerequisites are given and an alarm becomes due, the 
+corresponding note is displayed in edit view, and the display starts to 
+flash on and off, along with the alarm command being executed (see 
+L<"OPTIONS">).  To stop the blinking, click on the note.  From then on, 
+the note will be in I<edit mode>.
+
+For daily alarms, the entered date is ignored, and as the name suggests,
+they're run every day at the specified time.  To deactivate such an 
+alarm, you have to open the I<edit mode panel> and click button (a) to 
+make the I<alarm panel> disappear, which turns the alarm off.
+
+In contrast, date-specific alarms are executed only once, at the 
+specified day and time.  Since a year cannot be specified (explicitly), 
+the alarm will be run on this date's next occurrence within a year from 
+when the alarm was set.  After that, the alarm will automatically be 
+disabled.  If a date-specific alarm becomes due while B<wmpinboard> 
+isn't running, it will be displayed as soon as the program is started 
+the next time--which does B<not> go for daily alarms.
+
+The default mode for alarms is date-specific, and time and date are 
+initialized with the next full hour when the alarm panel is opened the 
+first time for a given note.
+
+Internally, alarm times are stored in universal format, i.e., if you 
+change the time zone after having set an alarm, the time will stay 
+universally the same but will differ relative to the new time zone from 
+what absolute time you originally set.  This behavior is intended.
+
+Finally, it should be mentioned that there are a few limitations with 
+respect to command line actions (such as B<C<--add>>, B<C<--del>>,
+B<C<-i>>, etc.).  See L<"RESTRICTIONS">.
+
+=head1 FREQUENTLY ASKED QUESTIONS
+
+=over 2
+
+=item *
+
+I<Q:> Is a "pinboard" this small really of any use?
+
+I<A:> Of course the limited size imposes certain restrictions, but if 
+you think about it, you'll agree that a real life pinboard reminds you 
+of things by the mere existence of notes being pinned to it.  In order 
+to read what they say, you have to step close and, possibly, detach the 
+note.
+
+Quite similarly, B<wmpinboard> reminds you of things by facing you with 
+colored representations of notes on your screen.  To find out what it 
+was you intended them to remind you of, all you have to do is click on 
+a note, which will then be displayed full size.  Furthermore, the alarm 
+feature introduced in a later version allows for even more explicit 
+reminders and thus renders B<wmpinboard> even more powerful in a way 
+than any real-life cork board. B<C<:-)>>
+
+By choosing from a variety of possible colors, you can assign 
+particular colors to certain kinds of reminders, which may further 
+enhance B<wmpinboard>'s usability.  Moreover, you can place certain notes 
+on certain areas of the board to emphasize their category, urgency, 
+etc.  It's up to you what to make of it.
+
+Finally, by adding drawing capabilities, I've definitely overcome the 
+contents quantity barrier imposed by the maximum number of 59 
+characters, for as everyone knows, a picture is worth more than a 
+thousand words. *grin*
+
+=item *
+
+I<Q:> I don't live in an English-speaking country, so what about extended
+characters (umlauts, accents, cyrillic alphabet)?
+
+I<A:> B<wmpinboard> allows you to use an arbitrary 8bit X font, provided 
+that its characters are of a fixed size of 6x10 (or, deprecated but 
+possible, anything E<lt>= 7x10) pixels.  The default font is "6x10" (more 
+precisely, it's called
+"-misc-fixed-medium-r-normal--10-100-75-75-c-*-ISO8859-1"), an
+ISO8859-1 (Latin1) font which should be part of every XFree 
+installation.
+
+In order to make B<wmpinboard> use another font, run it as
+
+  $ wmpinboard --font=FONT
+
+where B<FONT> is either a shortcut for a compiled-in font name (see 
+L<"OPTIONS"> for a list of those) or a valid, complete X font 
+descriptor.  This is a configuration directive, meaning that no other 
+instance of B<wmpinboard> may be running at the time.  Note that this 
+I<only works if there are no more notes on the board>.  It's 
+intentionally been made impossible to change the font while there are 
+notes saved in B<wmpinboard>'s data file, since this might result in 
+garbage being displayed.  Of course even a font specified via a 
+shortcut has to exist on your system in order to be usable.
+
+If a configured custom font cannot be loaded or has invalid dimensions, 
+B<wmpinboard> will try to revert.  Note that this won't affect the font 
+name saved along with the data, though.
+
+=item *
+
+I<Q:> How can I disable those vexing, superfluous animations?
+
+I<A:>
+
+  $ wmpinboard --light
+
+=item *
+
+I<Q:> Why aren't those animations smooth all of the time?  Sometimes it 
+looks like they're being skipped entirely.
+
+I<A:> This presumably is a multitasking issue: depending on the current 
+system load and B<wmpinboard>'s/the X server's recent CPU usage 
+history, it may take a moment until the scheduling has been adapted to 
+the suddenly increased CPU load implied by displaying the animation, 
+and short as it is, it may already be finished until this has happened, 
+i.e., it's the X server lagging behind in updating the program's 
+display if B<wmpinboard>'s been idle for some time prior to that.  It 
+may sound paradoxical, but the effect is the more likely to show the 
+lower the system's load is.  I don't see a way to avoid this
+effect--either this, or you turn off animations altogether.
+
+=item *
+
+I<Q:> When I leave B<wmpinboard> idle in edit mode for some time, edit 
+mode is terminated automatically.  Is that intended?
+
+I<A:> Yes.  After 60 idle seconds (that's the default; see 
+L<"OPTIONS">) in edit mode (no mouse click and no keyboard input), edit 
+mode is terminated automatically.  If the note being edited happens to 
+be blank, it will be discarded (or removed if an existing note is being 
+edited).
+
+This timeout can, however, be adjusted according to your preferences or
+turned off using the B<C<-t>> parameter.  See L<"OPTIONS"> for this.
+
+=item *
+
+I<Q:> When does B<wmpinboard> save its data?
+
+I<A:> Notes data is saved on each of these occasions:
+
+=over 2
+
+=item *
+
+whenever edit mode is terminated
+
+=item *
+
+when you switch notes in edit mode (via [Shift]-[S<arrow key>])
+
+=item *
+
+when a note has been moved on the board
+
+=item *
+
+when an interactive instance is running and you run B<wmpinboard> from 
+the command line, making it dump, add, or delete notes
+
+=item *
+
+when killed via SIGINT or SIGTERM and edit mode is active
+
+=back
+
+Notes are saved to a file called F<.wmpinboarddata> in your home 
+directory (see L<"FILES">).
+
+=item *
+
+I<Q:> I've tried my best and littered the entire pinboard with quite a 
+lot of notes.  Now I can't seem to be able to add another one.
+
+I<A:> There's a compile-time limit of 20 notes.  I think more notes on 
+this tiny a board really don't make any sense.
+
+=item *
+
+I<Q:> I've explicitly configured my window manager for click-based 
+rather than mouse-following focus, but B<wmpinboard>'s focus follows 
+the mouse regardless.  Can I change this?
+
+I<A:> By default, B<wmpinboard> actively claims the keyboard input 
+focus (if it's in note edit mode) whenever the pointer is moved over the 
+application's area.  Since B<wmpinboard> is a dock applet, i.e., a 
+withdrawn rather than a "real" X window, it can't be assigned a focus 
+in the same way as to the latter ones.  However, running B<wmpinboard> 
+with the parameter B<C<-c>> will make it emulate some sort of
+click-based focusing.  This means, it actively claims the keyboard 
+focus only on these occasions:
+
+=over 2
+
+=item *
+
+when a new note is created (I<not> when you click on an existing
+note--you'll have to explicitly click on the editing area to make it 
+claim focus; this way, you can just view a note without any change to 
+keyboard focus)
+
+=item *
+
+when you click somewhere on the text area in edit mode
+
+=back
+
+Once keyboard-focused, B<wmpinboard> will keep it until another window 
+is explicitly focused (usually by clicking on its title bar or 
+border).  To focus B<wmpinboard> again when it's lost focus, you'll 
+have to click on its text area in edit mode.  This click will only 
+focus the application and not have the usual cursor-positioning effect.
+
+This feature is to be considered experimental since I'm not sure of how 
+much use it really is.  A mouse-following focus is the recommended mode 
+of operation.
+
+=item *
+
+I<Q:> I've noticed that after a while, some sort of darker stains 
+appear on my notes.  Is that a bug in some drawing routine?
+
+I<A:> No, this is not a bug.  These "stains" are meant to resemble 
+creases, caused by frequent handling of a particular note (wear & tear, 
+you see?).  In fact, they're added with a certain probability whenever 
+you view a note by clicking on it (note that leafing through notes via 
+[Shift]-[S<arrow keys>] is I<not> affected), when you clear its textual 
+or drawn contents via the I<edit mode panel> (very outwearing, that 
+S<B<;-)> )>, and when a note is moved.  This feature can be disabled at 
+compile time by running F<configure> with C<--disable-creases> as a
+parameter.
+
+To prevent the question, no, worn-out notes cannot be ironed to get rid 
+of the creases.  Sorry. B<C<:-p>>
+
+=item *
+
+I<Q:> Is B<wmpinboard> compatible with B<AfterStep>'s B<Wharf>?
+
+I<A:> B<wmpinboard> tries to autodetect whether B<Window Maker> is 
+running and sets itself up accordingly.  If this doesn't work for you 
+for some reason, you can explicitly make it run in either Withdrawn- or 
+NormalState using the B<C<-w>> or B<C<-n>> flag, respectively.  See 
+L<"OPTIONS">.
+
+Swallowing evidently works with B<AfterStep> 1.6.10; I don't know about 
+earlier versions.  A B<Wharf> config line you might try is this:
+
+  *Wharf wmpinboard nil MaxSwallow "wmpinboard" wmpinboard &
+
+Besides, B<wmpinboard> has been reported to work with B<Blackbox>.
+
+=item *
+
+I<Q:> I have X running at a color depth of 8 bits, i.e., in palette 
+mode, and B<wmpinboard> obviously requires too many colors and thus 
+looks real messy (or doesn't run at all, complaining about "not enough 
+free color cells").  What can I do about this?
+
+I<A:> As of version 0.99.1, the recommended solution is to upgrade 
+whatever component of your system restricts you to a palette mode.
+
+=item *
+
+I<Q:> Can I run multiple instances of B<wmpinboard> as the same user, 
+simultaneously?
+
+I<A:> No, this is certainly not a good idea.  The run-time behavior may 
+be unpredictable, and your data file can get corrupted.  Therefore, any 
+B<wmpinboard> process that's to be run interactively first checks 
+whether another interactive instance is running, and if so, refuses to 
+run.
+
+=item *
+
+I<Q:> I've just upgraded from a pre-0.7 version of B<wmpinboard> and 
+noticed that its data file format has changed completely since.  Is 
+there a way to upgrade and yet keep my existing notes?
+
+I<A:> There's a B<Perl> script doing the conversion included with the 
+distribution (the source one, anyway).  If your package didn't include 
+that, feel free to mail to the author (see L<"AUTHOR"> at the end of 
+this documentation).
+
+=item *
+
+I<Q:> I find a mere 59 characters per note to be a real limitation.  
+How about making B<wmpinboard> pop up an external window with more room 
+for that?  Or how about assigning that job to an external editor?
+
+I<A:> There's a variety of comprehensive programs for keeping notes out 
+there, offering this functionality but being rather heavy-weight since 
+they are linked against one GUI library or another (B<CoolNotes> or 
+B<KNotes> come to mind).  On the other hand, I couldn't find a
+B<WM>-conforming reminder I could omnipresently stick to my desktop 
+anywhere, so I wrote B<wmpinboard>.  I wanted it to be small, neat, 
+easy to use, and yet useful in a way.
+
+I hope that's about what the program is currently like.  And I'd prefer 
+to keep it like that rather than inflate it by linking against a GUI 
+library--eventually, the note editing code would outweigh the rest of 
+the application by a factor, and people would probably still create 
+notes mostly shorter than 60 characters.  If you restrict your memos to 
+keywords and abbreviations, that's quite a lot.
+
+I want B<wmpinboard> to remain an applet in that it doesn't open up 
+external windows and use (if just temporarily) additional desktop 
+space.  I explicitly wrote it to have something omnipresent at a fixed 
+position on my desktop.  I find it preferable to have the notes pop up 
+in place rather than somewhere else on the screen.
+
+Personally, I use other programs for larger notes too; B<wmpinboard>
+has been designed for things smaller in size and greater in urgency,
+it's in no way meant to be a comprehensive knowledge base application
+of any kind.
+
+Summing up, I think a dock applet should be small both regarding its
+on-screen representation and the resources it uses.  That's why I 
+don't intend to add any pop-up dialogs or similar things to 
+B<wmpinboard>.
+
+=item *
+
+I<Q:> I've tried the program, yet I can't help finding it utterly 
+useless.  What shall I do?
+
+I<A:> The solution is simple.  Just don't use it.
+
+=item *
+
+I<Q:> Will your answer to this question be "no"?
+
+I<A:> Nope.
+
+=back
+
+=head1 HINTS
+
+=over 2
+
+=item *
+
+A good way of making the best of the organizational features offered by 
+B<wmpinboard> is to use certain colors and locations on the pinboard to 
+indicate urgency and contents of a note.  For example, you might use 
+each of the color groups for a certain kind of reminder, because that 
+enables you to leaf through all notes with related contents via
+[Shift]-[S<arrow keys>] in edit mode.  Besides, you might assign each 
+corner of the board a specific urgency, altogether allowing you to 
+derive a note's type from its color and its urgency from its location 
+on the board.  Thanks again to the ability to leaf through all notes 
+belonging to the same group of colors, notes with similar contents will 
+still be clustered in a way.
+
+=back
+
+=head1 UNDOCUMENTED FEATURES
+
+This piece of documentation doesn't cover any undocumented features.
+
+=head1 FILES
+
+=over 2
+
+=item F<~/.wmpinboarddata>
+
+the user's B<wmpinboard> data file
+
+=item F<~/.wmpinboarddata.new>
+
+temporary file created momentarily when saving data
+
+=back
+
+=head1 ENVIRONMENT VARIABLES
+
+=over 2
+
+=item $HOME
+
+the user's home directory
+
+=back
+
+=head1 RESTRICTIONS
+
+=over 2
+
+=item *
+
+B<wmpinboard> relies on a dock app tile size of at least 64x64 pixels.  
+In fact, using smaller tiles renders the applet rather useless, as, 
+e.g., opening the edit mode panel becomes impossible.
+
+=item *
+
+Unpredictable effects may be the results if a command line action is
+taken while an alarm is running and others are due simultaneously.
+If just a single alarm is active and no others are due, that alarm will
+be cancelled when the two instances of B<wmpinboard> synchronize.
+If more instances are due during the process, a race conditions arises
+that can't be solved satisfactorily due to the program's internal
+structure and organization.  Still, in theory, nothing critical will
+happen, and the most you'll lose will be an alarm or two.
+
+=item *
+
+B<wmpinboard> data files are not designed to be portable across 
+architectures.  Due to differences in data type representations that 
+are likely otherwise, a datafile can only be reliably used by program 
+binaries running on machines of the same architecture.
+
+=item *
+
+Certainly of no interest to anyone, but mentioned for the sake of 
+completeness: B<wmpinboard>'s alarm features will start to fail past 
+04:14:07 on Jan 19, 2037, which is due to the legacy Un*x time format.
+
+=back
+
+=head1 BUGS
+
+If you stumble on any bugs, feel free to mail the author.  The same 
+goes if you encounter any problems running/using the program.  Be sure 
+to include any information you consider relevant, i.e., at a minimum, 
+the version of B<wmpinboard> you're using as well as your OS and X 
+versions.
+
+Also, further suggestions are always welcome.  Please check the F<TODO> 
+file that's part of the distribution to see if what you're about to 
+suggest isn't already on my "to do" list, or has been suggested earlier 
+and was rejected for one reason or other.
+
+=head1 SEE ALSO
+
+wmaker(1)
+
+=head1 AUTHOR
+
+B<wmpinboard> is copyrighted (c) 1998-2000 by Marco GE<ouml>tze, 
+E<lt>gomar at mindless.comE<gt>.  It is distributed under the terms of the 
+GNU General Public License, revision 2 or any later revision thereof.  
+Use at your own risk.
+
+New releases of and themes for B<wmpinboard> can be found at
+E<lt>http://www.tu-ilmenau.de/~gomar/stuff/wmpinboard/E<gt>, or 
+that was true at least by the time this document was last updated.
+
+=cut
+
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..24841fe
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,17 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = $(X_CFLAGS)
+LIBS = $(X_LIBS) -lX11 -lXext -lXpm
+
+bin_PROGRAMS = wmpinboard
+
+wmpinboard_SOURCES = @CONDITIONAL_SOURCES@ \
+	misc.c misc.h \
+	notes.c notes.h \
+	wmpinboard.c wmpinboard.h \
+	xmisc.c xmisc.h
+
+EXTRA_wmpinboard_SOURCES = \
+	getopt.c getopt1.c getopt.h \
+	memcmp.c memcmp.h
+
diff --git a/src/getopt.c b/src/getopt.c
new file mode 100644
index 0000000..0f41fb6
--- /dev/null
+++ b/src/getopt.c
@@ -0,0 +1,1004 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to roland at gnu.ai.mit.edu
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97
+   Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.  Its master source is NOT part of
+   the C library, however.  The master source lives in /gd/gnu/lib.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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 GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+

+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+   Ditto for AIX 3.2 and <stdlib.h>.  */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef	__GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+#include <stdlib.h>
+#include <unistd.h>
+#endif /* GNU C library.  */
+
+#ifdef VMS
+#include <unixlib.h>
+#if HAVE_STRING_H - 0
+#include <string.h>
+#endif
+#endif
+
+#if defined (WIN32) && !defined (__CYGWIN32__)
+/* It's not Unix, really.  See?  Capital letters.  */
+#include <windows.h>
+#define getpid() GetCurrentProcessId()
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.
+   When compiling libc, the _ macro is predefined.  */
+#ifdef HAVE_LIBINTL_H
+#include <libintl.h>
+#define _(msgid)	gettext (msgid)
+#else
+#define _(msgid)	(msgid)
+#endif
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* 1003.2 says this must be 1 before any call.  */
+int optind = 1;
+
+/* Formerly, initialization of getopt depended on optind==0, which
+   causes problems with re-calling getopt as programs generally don't
+   know that. */
+
+int __getopt_initialized = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return -1 with `optind' != ARGC.  */
+
+static enum
+{
+	REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+}
+ordering;
+
+/* Value of POSIXLY_CORRECT environment variable.  */
+static char *posixly_correct;
+

+#ifdef	__GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+#include <string.h>
+#define	my_index	strchr
+#else
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+char *getenv();
+
+static char *
+     my_index(str, chr)
+     const char *str;
+     int chr;
+{
+	while (*str)
+	{
+		if (*str == chr)
+			return (char *) str;
+		str++;
+	}
+	return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.  */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+   That was relevant to code that was here before.  */
+#if !defined (__STDC__) || !__STDC__
+/* gcc with -traditional declares the built-in strlen to return int,
+   and has done so at least since version 2.4.5. -- rms.  */
+extern int strlen(const char *);
+
+#endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+

+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+#ifdef _LIBC
+/* Bash 2.0 gives us an environment variable containing flags
+   indicating ARGV elements that should not be considered arguments.  */
+
+static const char *nonoption_flags;
+static int nonoption_flags_len;
+
+static int original_argc;
+static char *const *original_argv;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+   is valid for the getopt call we must make sure that the ARGV passed
+   to getopt is that one passed to the process.  */
+static void store_args(int argc, char *const *argv) __attribute__((unused));
+     static void
+          store_args(int argc, char *const *argv)
+{
+	/* XXX This is no good solution.  We should rather copy the args so
+	   that we can compare them later.  But we must not use malloc(3).  */
+	original_argc = argc;
+	original_argv = argv;
+}
+text_set_element(__libc_subinit, store_args);
+#endif
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+#if defined (__STDC__) && __STDC__
+static void exchange(char **);
+
+#endif
+
+static void
+     exchange(argv)
+     char **argv;
+{
+	int bottom = first_nonopt;
+	int middle = last_nonopt;
+	int top = optind;
+	char *tem;
+
+	/* Exchange the shorter segment with the far end of the longer segment.
+	   That puts the shorter segment into the right place.
+	   It leaves the longer segment in the right place overall,
+	   but it consists of two parts that need to be swapped next.  */
+
+	while (top > middle && middle > bottom)
+	{
+		if (top - middle > middle - bottom)
+		{
+			/* Bottom segment is the short one.  */
+			int len = middle - bottom;
+			register int i;
+
+			/* Swap it with the top part of the top segment.  */
+			for (i = 0; i < len; i++)
+			{
+				tem = argv[bottom + i];
+				argv[bottom + i] = argv[top - (middle - bottom) + i];
+				argv[top - (middle - bottom) + i] = tem;
+			}
+			/* Exclude the moved bottom segment from further swapping.  */
+			top -= len;
+		}
+		else
+		{
+			/* Top segment is the short one.  */
+			int len = top - middle;
+			register int i;
+
+			/* Swap it with the bottom part of the bottom segment.  */
+			for (i = 0; i < len; i++)
+			{
+				tem = argv[bottom + i];
+				argv[bottom + i] = argv[middle + i];
+				argv[middle + i] = tem;
+			}
+			/* Exclude the moved top segment from further swapping.  */
+			bottom += len;
+		}
+	}
+
+	/* Update records for the slots the non-options now occupy.  */
+
+	first_nonopt += (optind - last_nonopt);
+	last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made.  */
+
+#if defined (__STDC__) && __STDC__
+static const char *_getopt_initialize(int, char *const *, const char *);
+
+#endif
+static const char *
+     _getopt_initialize(argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+	/* Start processing options with ARGV-element 1 (since ARGV-element 0
+	   is the program name); the sequence of previously skipped
+	   non-option ARGV-elements is empty.  */
+
+	first_nonopt = last_nonopt = optind = 1;
+
+	nextchar = NULL;
+
+	posixly_correct = getenv("POSIXLY_CORRECT");
+
+	/* Determine how to handle the ordering of options and nonoptions.  */
+
+	if (optstring[0] == '-')
+	{
+		ordering = RETURN_IN_ORDER;
+		++optstring;
+	}
+	else if (optstring[0] == '+')
+	{
+		ordering = REQUIRE_ORDER;
+		++optstring;
+	}
+	else if (posixly_correct != NULL)
+		ordering = REQUIRE_ORDER;
+	else
+		ordering = PERMUTE;
+
+#ifdef _LIBC
+	if (posixly_correct == NULL
+	    && argc == original_argc && argv == original_argv)
+	{
+		/* Bash 2.0 puts a special variable in the environment for each
+		   command it runs, specifying which ARGV elements are the results of
+		   file name wildcard expansion and therefore should not be
+		   considered as options.  */
+		char var[100];
+
+		sprintf(var, "_%d_GNU_nonoption_argv_flags_", getpid());
+		nonoption_flags = getenv(var);
+		if (nonoption_flags == NULL)
+			nonoption_flags_len = 0;
+		else
+			nonoption_flags_len = strlen(nonoption_flags);
+	}
+	else
+		nonoption_flags_len = 0;
+#endif
+
+	return optstring;
+}
+

+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns -1.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+    _getopt_internal(argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+	optarg = NULL;
+
+	if (!__getopt_initialized || optind == 0)
+	{
+		optstring = _getopt_initialize(argc, argv, optstring);
+		optind = 1;	/* Don't scan ARGV[0], the program name.  */
+		__getopt_initialized = 1;
+	}
+
+	/* Test whether ARGV[optind] points to a non-option argument.
+	   Either it does not have option syntax, or there is an environment flag
+	   from the shell indicating it is not an option.  The later information
+	   is only used when the used in the GNU libc.  */
+#ifdef _LIBC
+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0'	      \
+		     || (optind < nonoption_flags_len			      \
+			 && nonoption_flags[optind] == '1'))
+#else
+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#endif
+
+	if (nextchar == NULL || *nextchar == '\0')
+	{
+		/* Advance to the next ARGV-element.  */
+
+		/* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+		   moved back by the user (who may also have changed the arguments).  */
+		if (last_nonopt > optind)
+			last_nonopt = optind;
+		if (first_nonopt > optind)
+			first_nonopt = optind;
+
+		if (ordering == PERMUTE)
+		{
+			/* If we have just processed some options following some non-options,
+			   exchange them so that the options come first.  */
+
+			if (first_nonopt != last_nonopt && last_nonopt != optind)
+				exchange((char **) argv);
+			else if (last_nonopt != optind)
+				first_nonopt = optind;
+
+			/* Skip any additional non-options
+			   and extend the range of non-options previously skipped.  */
+
+			while (optind < argc && NONOPTION_P)
+				optind++;
+			last_nonopt = optind;
+		}
+
+		/* The special ARGV-element `--' means premature end of options.
+		   Skip it like a null option,
+		   then exchange with previous non-options as if it were an option,
+		   then skip everything else like a non-option.  */
+
+		if (optind != argc && !strcmp(argv[optind], "--"))
+		{
+			optind++;
+
+			if (first_nonopt != last_nonopt && last_nonopt != optind)
+				exchange((char **) argv);
+			else if (first_nonopt == last_nonopt)
+				first_nonopt = optind;
+			last_nonopt = argc;
+
+			optind = argc;
+		}
+
+		/* If we have done all the ARGV-elements, stop the scan
+		   and back over any non-options that we skipped and permuted.  */
+
+		if (optind == argc)
+		{
+			/* Set the next-arg-index to point at the non-options
+			   that we previously skipped, so the caller will digest them.  */
+			if (first_nonopt != last_nonopt)
+				optind = first_nonopt;
+			return -1;
+		}
+
+		/* If we have come to a non-option and did not permute it,
+		   either stop the scan or describe it to the caller and pass it by.  */
+
+		if (NONOPTION_P)
+		{
+			if (ordering == REQUIRE_ORDER)
+				return -1;
+			optarg = argv[optind++];
+			return 1;
+		}
+
+		/* We have found another option-ARGV-element.
+		   Skip the initial punctuation.  */
+
+		nextchar = (argv[optind] + 1
+			    + (longopts != NULL && argv[optind][1] == '-'));
+	}
+
+	/* Decode the current option-ARGV-element.  */
+
+	/* Check whether the ARGV-element is a long option.
+
+	   If long_only and the ARGV-element has the form "-f", where f is
+	   a valid short option, don't consider it an abbreviated form of
+	   a long option that starts with f.  Otherwise there would be no
+	   way to give the -f short option.
+
+	   On the other hand, if there's a long option "fubar" and
+	   the ARGV-element is "-fu", do consider that an abbreviation of
+	   the long option, just like "--fu", and not "-f" with arg "u".
+
+	   This distinction seems to be the most useful approach.  */
+
+	if (longopts != NULL
+	    && (argv[optind][1] == '-'
+		|| (long_only && (argv[optind][2] || !my_index(optstring, argv[optind][1])))))
+	{
+		char *nameend;
+		const struct option *p;
+		const struct option *pfound = NULL;
+		int exact = 0;
+		int ambig = 0;
+		int indfound = -1;
+		int option_index;
+
+		for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+			/* Do nothing.  */ ;
+
+		/* Test all long options for either exact match
+		   or abbreviated matches.  */
+		for (p = longopts, option_index = 0; p->name; p++, option_index++)
+			if (!strncmp(p->name, nextchar, nameend - nextchar))
+			{
+				if ((unsigned int) (nameend - nextchar)
+				    == (unsigned int) strlen(p->name))
+				{
+					/* Exact match found.  */
+					pfound = p;
+					indfound = option_index;
+					exact = 1;
+					break;
+				}
+				else if (pfound == NULL)
+				{
+					/* First nonexact match found.  */
+					pfound = p;
+					indfound = option_index;
+				}
+				else
+					/* Second or later nonexact match found.  */
+					ambig = 1;
+			}
+
+		if (ambig && !exact)
+		{
+			if (opterr)
+				fprintf(stderr, _("%s: option `%s' is ambiguous\n"),
+					argv[0], argv[optind]);
+			nextchar += strlen(nextchar);
+			optind++;
+			optopt = 0;
+			return '?';
+		}
+
+		if (pfound != NULL)
+		{
+			option_index = indfound;
+			optind++;
+			if (*nameend)
+			{
+				/* Don't test has_arg with >, because some C compilers don't
+				   allow it to be used on enums.  */
+				if (pfound->has_arg)
+					optarg = nameend + 1;
+				else
+				{
+					if (opterr)
+						if (argv[optind - 1][1] == '-')
+							/* --option */
+							fprintf(stderr,
+								_("%s: option `--%s' doesn't allow an argument\n"),
+								argv[0], pfound->name);
+						else
+							/* +option or -option */
+							fprintf(stderr,
+								_("%s: option `%c%s' doesn't allow an argument\n"),
+								argv[0], argv[optind - 1][0], pfound->name);
+
+					nextchar += strlen(nextchar);
+
+					optopt = pfound->val;
+					return '?';
+				}
+			}
+			else if (pfound->has_arg == 1)
+			{
+				if (optind < argc)
+					optarg = argv[optind++];
+				else
+				{
+					if (opterr)
+						fprintf(stderr,
+							_("%s: option `%s' requires an argument\n"),
+						 argv[0], argv[optind - 1]);
+					nextchar += strlen(nextchar);
+					optopt = pfound->val;
+					return optstring[0] == ':' ? ':' : '?';
+				}
+			}
+			nextchar += strlen(nextchar);
+			if (longind != NULL)
+				*longind = option_index;
+			if (pfound->flag)
+			{
+				*(pfound->flag) = pfound->val;
+				return 0;
+			}
+			return pfound->val;
+		}
+
+		/* Can't find it as a long option.  If this is not getopt_long_only,
+		   or the option starts with '--' or is not a valid short
+		   option, then it's an error.
+		   Otherwise interpret it as a short option.  */
+		if (!long_only || argv[optind][1] == '-'
+		    || my_index(optstring, *nextchar) == NULL)
+		{
+			if (opterr)
+			{
+				if (argv[optind][1] == '-')
+					/* --option */
+					fprintf(stderr, _("%s: unrecognized option `--%s'\n"),
+						argv[0], nextchar);
+				else
+					/* +option or -option */
+					fprintf(stderr, _("%s: unrecognized option `%c%s'\n"),
+					argv[0], argv[optind][0], nextchar);
+			}
+			nextchar = (char *) "";
+			optind++;
+			optopt = 0;
+			return '?';
+		}
+	}
+
+	/* Look at and handle the next short option-character.  */
+
+	{
+		char c = *nextchar++;
+		char *temp = my_index(optstring, c);
+
+		/* Increment `optind' when we start to process its last character.  */
+		if (*nextchar == '\0')
+			++optind;
+
+		if (temp == NULL || c == ':')
+		{
+			if (opterr)
+			{
+				if (posixly_correct)
+					/* 1003.2 specifies the format of this message.  */
+					fprintf(stderr, _("%s: illegal option -- %c\n"),
+						argv[0], c);
+				else
+					fprintf(stderr, _("%s: invalid option -- %c\n"),
+						argv[0], c);
+			}
+			optopt = c;
+			return '?';
+		}
+		/* Convenience. Treat POSIX -W foo same as long option --foo */
+		if (temp[0] == 'W' && temp[1] == ';')
+		{
+			char *nameend;
+			const struct option *p;
+			const struct option *pfound = NULL;
+			int exact = 0;
+			int ambig = 0;
+			int indfound = 0;
+			int option_index;
+
+			/* This is an option that requires an argument.  */
+			if (*nextchar != '\0')
+			{
+				optarg = nextchar;
+				/* If we end this ARGV-element by taking the rest as an arg,
+				   we must advance to the next element now.  */
+				optind++;
+			}
+			else if (optind == argc)
+			{
+				if (opterr)
+				{
+					/* 1003.2 specifies the format of this message.  */
+					fprintf(stderr, _("%s: option requires an argument -- %c\n"),
+						argv[0], c);
+				}
+				optopt = c;
+				if (optstring[0] == ':')
+					c = ':';
+				else
+					c = '?';
+				return c;
+			}
+			else
+				/* We already incremented `optind' once;
+				   increment it again when taking next ARGV-elt as argument.  */
+				optarg = argv[optind++];
+
+			/* optarg is now the argument, see if it's in the
+			   table of longopts.  */
+
+			for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
+				/* Do nothing.  */ ;
+
+			/* Test all long options for either exact match
+			   or abbreviated matches.  */
+			for (p = longopts, option_index = 0; p->name; p++, option_index++)
+				if (!strncmp(p->name, nextchar, nameend - nextchar))
+				{
+					if ((unsigned int) (nameend - nextchar) == strlen(p->name))
+					{
+						/* Exact match found.  */
+						pfound = p;
+						indfound = option_index;
+						exact = 1;
+						break;
+					}
+					else if (pfound == NULL)
+					{
+						/* First nonexact match found.  */
+						pfound = p;
+						indfound = option_index;
+					}
+					else
+						/* Second or later nonexact match found.  */
+						ambig = 1;
+				}
+			if (ambig && !exact)
+			{
+				if (opterr)
+					fprintf(stderr, _("%s: option `-W %s' is ambiguous\n"),
+						argv[0], argv[optind]);
+				nextchar += strlen(nextchar);
+				optind++;
+				return '?';
+			}
+			if (pfound != NULL)
+			{
+				option_index = indfound;
+				if (*nameend)
+				{
+					/* Don't test has_arg with >, because some C compilers don't
+					   allow it to be used on enums.  */
+					if (pfound->has_arg)
+						optarg = nameend + 1;
+					else
+					{
+						if (opterr)
+							fprintf(stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+								argv[0], pfound->name);
+
+						nextchar += strlen(nextchar);
+						return '?';
+					}
+				}
+				else if (pfound->has_arg == 1)
+				{
+					if (optind < argc)
+						optarg = argv[optind++];
+					else
+					{
+						if (opterr)
+							fprintf(stderr,
+								_("%s: option `%s' requires an argument\n"),
+								argv[0], argv[optind - 1]);
+						nextchar += strlen(nextchar);
+						return optstring[0] == ':' ? ':' : '?';
+					}
+				}
+				nextchar += strlen(nextchar);
+				if (longind != NULL)
+					*longind = option_index;
+				if (pfound->flag)
+				{
+					*(pfound->flag) = pfound->val;
+					return 0;
+				}
+				return pfound->val;
+			}
+			nextchar = NULL;
+			return 'W';	/* Let the application handle it.   */
+		}
+		if (temp[1] == ':')
+		{
+			if (temp[2] == ':')
+			{
+				/* This is an option that accepts an argument optionally.  */
+				if (*nextchar != '\0')
+				{
+					optarg = nextchar;
+					optind++;
+				}
+				else
+					optarg = NULL;
+				nextchar = NULL;
+			}
+			else
+			{
+				/* This is an option that requires an argument.  */
+				if (*nextchar != '\0')
+				{
+					optarg = nextchar;
+					/* If we end this ARGV-element by taking the rest as an arg,
+					   we must advance to the next element now.  */
+					optind++;
+				}
+				else if (optind == argc)
+				{
+					if (opterr)
+					{
+						/* 1003.2 specifies the format of this message.  */
+						fprintf(stderr,
+							_("%s: option requires an argument -- %c\n"),
+							argv[0], c);
+					}
+					optopt = c;
+					if (optstring[0] == ':')
+						c = ':';
+					else
+						c = '?';
+				}
+				else
+					/* We already incremented `optind' once;
+					   increment it again when taking next ARGV-elt as argument.  */
+					optarg = argv[optind++];
+				nextchar = NULL;
+			}
+		}
+		return c;
+	}
+}
+
+int
+    getopt(argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+	return _getopt_internal(argc, argv, optstring,
+				(const struct option *) 0,
+				(int *) 0,
+				0);
+}
+
+#endif /* Not ELIDE_CODE.  */
+

+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+    main(argc, argv)
+     int argc;
+     char **argv;
+{
+	int c;
+	int digit_optind = 0;
+
+	while (1)
+	{
+		int this_option_optind = optind ? optind : 1;
+
+		c = getopt(argc, argv, "abc:d:0123456789");
+		if (c == -1)
+			break;
+
+		switch (c)
+		{
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+			case '8':
+			case '9':
+				if (digit_optind != 0 && digit_optind != this_option_optind)
+					printf("digits occur in two different argv-elements.\n");
+				digit_optind = this_option_optind;
+				printf("option %c\n", c);
+				break;
+
+			case 'a':
+				printf("option a\n");
+				break;
+
+			case 'b':
+				printf("option b\n");
+				break;
+
+			case 'c':
+				printf("option c with value `%s'\n", optarg);
+				break;
+
+			case '?':
+				break;
+
+			default:
+				printf("?? getopt returned character code 0%o ??\n", c);
+		}
+	}
+
+	if (optind < argc)
+	{
+		printf("non-option ARGV-elements: ");
+		while (optind < argc)
+			printf("%s ", argv[optind++]);
+		printf("\n");
+	}
+
+	exit(0);
+}
+
+#endif /* TEST */
diff --git a/src/getopt.h b/src/getopt.h
new file mode 100644
index 0000000..2fa12f7
--- /dev/null
+++ b/src/getopt.h
@@ -0,0 +1,134 @@
+/* Declarations for getopt.
+   Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.  Its master source is NOT part of
+   the C library, however.  The master source lives in /gd/gnu/lib.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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 GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef	__cplusplus
+extern "C"
+{
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+	extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+	extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+	extern int opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+	extern int optopt;
+
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument          (or 0) if the option does not take an argument,
+   required_argument    (or 1) if the option requires an argument,
+   optional_argument    (or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+	struct option
+	{
+#if defined (__STDC__) && __STDC__
+		const char *name;
+#else
+		char *name;
+#endif
+		/* has_arg can't be an enum because some compilers complain about
+		   type mismatches in all the code that assumes it is an int.  */
+		int has_arg;
+		int *flag;
+		int val;
+	};
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+#define	no_argument		0
+#define required_argument	1
+#define optional_argument	2
+
+#if defined (__STDC__) && __STDC__
+#ifdef __GNU_LIBRARY__
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+	extern int getopt(int argc, char *const *argv, const char *shortopts);
+#else				/* not __GNU_LIBRARY__ */
+	extern int getopt();
+#endif				/* __GNU_LIBRARY__ */
+	extern int getopt_long(int argc, char *const *argv, const char *shortopts,
+			       const struct option *longopts, int *longind);
+	extern int getopt_long_only(int argc, char *const *argv,
+				    const char *shortopts,
+			       const struct option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+	extern int _getopt_internal(int argc, char *const *argv,
+				    const char *shortopts,
+				const struct option *longopts, int *longind,
+				    int long_only);
+#else				/* not __STDC__ */
+	extern int getopt();
+	extern int getopt_long();
+	extern int getopt_long_only();
+
+	extern int _getopt_internal();
+#endif				/* __STDC__ */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif				/* _GETOPT_H */
diff --git a/src/getopt1.c b/src/getopt1.c
new file mode 100644
index 0000000..fe414f3
--- /dev/null
+++ b/src/getopt1.c
@@ -0,0 +1,187 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+   Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.  Its master source is NOT part of
+   the C library, however.  The master source lives in /gd/gnu/lib.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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 GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+

+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "getopt.h"
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#endif
+
+#ifndef	NULL
+#define NULL 0
+#endif
+
+int
+    getopt_long(argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+	return _getopt_internal(argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+
+int
+    getopt_long_only(argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+	return _getopt_internal(argc, argv, options, long_options, opt_index, 1);
+}
+
+#endif /* Not ELIDE_CODE.  */
+

+#ifdef TEST
+
+#include <stdio.h>
+
+int
+    main(argc, argv)
+     int argc;
+     char **argv;
+{
+	int c;
+	int digit_optind = 0;
+
+	while (1)
+	{
+		int this_option_optind = optind ? optind : 1;
+		int option_index = 0;
+		static struct option long_options[] =
+		{
+			{"add", 1, 0, 0},
+			{"append", 0, 0, 0},
+			{"delete", 1, 0, 0},
+			{"verbose", 0, 0, 0},
+			{"create", 0, 0, 0},
+			{"file", 1, 0, 0},
+			{0, 0, 0, 0}
+		};
+
+		c = getopt_long(argc, argv, "abc:d:0123456789",
+				long_options, &option_index);
+		if (c == -1)
+			break;
+
+		switch (c)
+		{
+			case 0:
+				printf("option %s", long_options[option_index].name);
+				if (optarg)
+					printf(" with arg %s", optarg);
+				printf("\n");
+				break;
+
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+			case '8':
+			case '9':
+				if (digit_optind != 0 && digit_optind != this_option_optind)
+					printf("digits occur in two different argv-elements.\n");
+				digit_optind = this_option_optind;
+				printf("option %c\n", c);
+				break;
+
+			case 'a':
+				printf("option a\n");
+				break;
+
+			case 'b':
+				printf("option b\n");
+				break;
+
+			case 'c':
+				printf("option c with value `%s'\n", optarg);
+				break;
+
+			case 'd':
+				printf("option d with value `%s'\n", optarg);
+				break;
+
+			case '?':
+				break;
+
+			default:
+				printf("?? getopt returned character code 0%o ??\n", c);
+		}
+	}
+
+	if (optind < argc)
+	{
+		printf("non-option ARGV-elements: ");
+		while (optind < argc)
+			printf("%s ", argv[optind++]);
+		printf("\n");
+	}
+
+	exit(0);
+}
+
+#endif /* TEST */
diff --git a/src/memcmp.c b/src/memcmp.c
new file mode 100644
index 0000000..6c87ad2
--- /dev/null
+++ b/src/memcmp.c
@@ -0,0 +1,394 @@
+/* Copyright (C) 1991, 1993, 1995, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Torbjorn Granlund (tege at sics.se).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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 GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#undef	__ptr_t
+#if defined __cplusplus || (defined __STDC__ && __STDC__)
+# define __ptr_t	void *
+#else /* Not C++ or ANSI C.  */
+# undef	const
+# define const
+# define __ptr_t	char *
+#endif /* C++ or ANSI C.  */
+
+#ifndef __P
+# if defined __GNUC__ || (defined __STDC__ && __STDC__)
+#  define __P(args) args
+# else
+#  define __P(args) ()
+# endif  /* GCC.  */
+#endif  /* Not __P.  */
+
+#if defined HAVE_STRING_H || defined _LIBC
+# include <string.h>
+#endif
+
+#undef memcmp
+
+#ifdef _LIBC
+
+# include <memcopy.h>
+# include <endian.h>
+
+# if __BYTE_ORDER == __BIG_ENDIAN
+#  define WORDS_BIGENDIAN
+# endif
+
+#else	/* Not in the GNU C library.  */
+
+# include <sys/types.h>
+
+/* Type to use for aligned memory operations.
+   This should normally be the biggest type supported by a single load
+   and store.  Must be an unsigned type.  */
+# define op_t	unsigned long int
+# define OPSIZ	(sizeof(op_t))
+
+/* Threshold value for when to enter the unrolled loops.  */
+# define OP_T_THRES	16
+
+/* Type to use for unaligned operations.  */
+typedef unsigned char byte;
+
+# ifndef WORDS_BIGENDIAN
+#  define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2)))
+# else
+#  define MERGE(w0, sh_1, w1, sh_2) (((w0) << (sh_1)) | ((w1) >> (sh_2)))
+# endif
+
+#endif	/* In the GNU C library.  */
+
+#ifdef WORDS_BIGENDIAN
+# define CMP_LT_OR_GT(a, b) ((a) > (b) ? 1 : -1)
+#else
+# define CMP_LT_OR_GT(a, b) memcmp_bytes ((a), (b))
+#endif
+
+/* BE VERY CAREFUL IF YOU CHANGE THIS CODE!  */
+
+/* The strategy of this memcmp is:
+
+   1. Compare bytes until one of the block pointers is aligned.
+
+   2. Compare using memcmp_common_alignment or
+      memcmp_not_common_alignment, regarding the alignment of the other
+      block after the initial byte operations.  The maximum number of
+      full words (of type op_t) are compared in this way.
+
+   3. Compare the few remaining bytes.  */
+
+#ifndef WORDS_BIGENDIAN
+/* memcmp_bytes -- Compare A and B bytewise in the byte order of the machine.
+   A and B are known to be different.
+   This is needed only on little-endian machines.  */
+
+static int memcmp_bytes __P((op_t, op_t));
+
+# ifdef  __GNUC__
+__inline
+# endif
+static int
+memcmp_bytes (a, b)
+     op_t a, b;
+{
+  long int srcp1 = (long int) &a;
+  long int srcp2 = (long int) &b;
+  op_t a0, b0;
+
+  do
+    {
+      a0 = ((byte *) srcp1)[0];
+      b0 = ((byte *) srcp2)[0];
+      srcp1 += 1;
+      srcp2 += 1;
+    }
+  while (a0 == b0);
+  return a0 - b0;
+}
+#endif
+
+static int memcmp_common_alignment __P((long, long, size_t));
+
+/* memcmp_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN `op_t'
+   objects (not LEN bytes!).  Both SRCP1 and SRCP2 should be aligned for
+   memory operations on `op_t's.  */
+#ifdef	__GNUC__
+__inline
+#endif
+static int
+memcmp_common_alignment (srcp1, srcp2, len)
+     long int srcp1;
+     long int srcp2;
+     size_t len;
+{
+  op_t a0, a1;
+  op_t b0, b1;
+
+  switch (len % 4)
+    {
+    default: /* Avoid warning about uninitialized local variables.  */
+    case 2:
+      a0 = ((op_t *) srcp1)[0];
+      b0 = ((op_t *) srcp2)[0];
+      srcp1 -= 2 * OPSIZ;
+      srcp2 -= 2 * OPSIZ;
+      len += 2;
+      goto do1;
+    case 3:
+      a1 = ((op_t *) srcp1)[0];
+      b1 = ((op_t *) srcp2)[0];
+      srcp1 -= OPSIZ;
+      srcp2 -= OPSIZ;
+      len += 1;
+      goto do2;
+    case 0:
+      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
+	return 0;
+      a0 = ((op_t *) srcp1)[0];
+      b0 = ((op_t *) srcp2)[0];
+      goto do3;
+    case 1:
+      a1 = ((op_t *) srcp1)[0];
+      b1 = ((op_t *) srcp2)[0];
+      srcp1 += OPSIZ;
+      srcp2 += OPSIZ;
+      len -= 1;
+      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
+	goto do0;
+      /* Fall through.  */
+    }
+
+  do
+    {
+      a0 = ((op_t *) srcp1)[0];
+      b0 = ((op_t *) srcp2)[0];
+      if (a1 != b1)
+	return CMP_LT_OR_GT (a1, b1);
+
+    do3:
+      a1 = ((op_t *) srcp1)[1];
+      b1 = ((op_t *) srcp2)[1];
+      if (a0 != b0)
+	return CMP_LT_OR_GT (a0, b0);
+
+    do2:
+      a0 = ((op_t *) srcp1)[2];
+      b0 = ((op_t *) srcp2)[2];
+      if (a1 != b1)
+	return CMP_LT_OR_GT (a1, b1);
+
+    do1:
+      a1 = ((op_t *) srcp1)[3];
+      b1 = ((op_t *) srcp2)[3];
+      if (a0 != b0)
+	return CMP_LT_OR_GT (a0, b0);
+
+      srcp1 += 4 * OPSIZ;
+      srcp2 += 4 * OPSIZ;
+      len -= 4;
+    }
+  while (len != 0);
+
+  /* This is the right position for do0.  Please don't move
+     it into the loop.  */
+ do0:
+  if (a1 != b1)
+    return CMP_LT_OR_GT (a1, b1);
+  return 0;
+}
+
+static int memcmp_not_common_alignment __P((long, long, size_t));
+
+/* memcmp_not_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN
+   `op_t' objects (not LEN bytes!).  SRCP2 should be aligned for memory
+   operations on `op_t', but SRCP1 *should be unaligned*.  */
+#ifdef	__GNUC__
+__inline
+#endif
+static int
+memcmp_not_common_alignment (srcp1, srcp2, len)
+     long int srcp1;
+     long int srcp2;
+     size_t len;
+{
+  op_t a0, a1, a2, a3;
+  op_t b0, b1, b2, b3;
+  op_t x;
+  int shl, shr;
+
+  /* Calculate how to shift a word read at the memory operation
+     aligned srcp1 to make it aligned for comparison.  */
+
+  shl = 8 * (srcp1 % OPSIZ);
+  shr = 8 * OPSIZ - shl;
+
+  /* Make SRCP1 aligned by rounding it down to the beginning of the `op_t'
+     it points in the middle of.  */
+  srcp1 &= -OPSIZ;
+
+  switch (len % 4)
+    {
+    default: /* Avoid warning about uninitialized local variables.  */
+    case 2:
+      a1 = ((op_t *) srcp1)[0];
+      a2 = ((op_t *) srcp1)[1];
+      b2 = ((op_t *) srcp2)[0];
+      srcp1 -= 1 * OPSIZ;
+      srcp2 -= 2 * OPSIZ;
+      len += 2;
+      goto do1;
+    case 3:
+      a0 = ((op_t *) srcp1)[0];
+      a1 = ((op_t *) srcp1)[1];
+      b1 = ((op_t *) srcp2)[0];
+      srcp2 -= 1 * OPSIZ;
+      len += 1;
+      goto do2;
+    case 0:
+      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
+	return 0;
+      a3 = ((op_t *) srcp1)[0];
+      a0 = ((op_t *) srcp1)[1];
+      b0 = ((op_t *) srcp2)[0];
+      srcp1 += 1 * OPSIZ;
+      goto do3;
+    case 1:
+      a2 = ((op_t *) srcp1)[0];
+      a3 = ((op_t *) srcp1)[1];
+      b3 = ((op_t *) srcp2)[0];
+      srcp1 += 2 * OPSIZ;
+      srcp2 += 1 * OPSIZ;
+      len -= 1;
+      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
+	goto do0;
+      /* Fall through.  */
+    }
+
+  do
+    {
+      a0 = ((op_t *) srcp1)[0];
+      b0 = ((op_t *) srcp2)[0];
+      x = MERGE(a2, shl, a3, shr);
+      if (x != b3)
+	return CMP_LT_OR_GT (x, b3);
+
+    do3:
+      a1 = ((op_t *) srcp1)[1];
+      b1 = ((op_t *) srcp2)[1];
+      x = MERGE(a3, shl, a0, shr);
+      if (x != b0)
+	return CMP_LT_OR_GT (x, b0);
+
+    do2:
+      a2 = ((op_t *) srcp1)[2];
+      b2 = ((op_t *) srcp2)[2];
+      x = MERGE(a0, shl, a1, shr);
+      if (x != b1)
+	return CMP_LT_OR_GT (x, b1);
+
+    do1:
+      a3 = ((op_t *) srcp1)[3];
+      b3 = ((op_t *) srcp2)[3];
+      x = MERGE(a1, shl, a2, shr);
+      if (x != b2)
+	return CMP_LT_OR_GT (x, b2);
+
+      srcp1 += 4 * OPSIZ;
+      srcp2 += 4 * OPSIZ;
+      len -= 4;
+    }
+  while (len != 0);
+
+  /* This is the right position for do0.  Please don't move
+     it into the loop.  */
+ do0:
+  x = MERGE(a2, shl, a3, shr);
+  if (x != b3)
+    return CMP_LT_OR_GT (x, b3);
+  return 0;
+}
+
+int
+memcmp (s1, s2, len)
+     const __ptr_t s1;
+     const __ptr_t s2;
+     size_t len;
+{
+  op_t a0;
+  op_t b0;
+  long int srcp1 = (long int) s1;
+  long int srcp2 = (long int) s2;
+  op_t res;
+
+  if (len >= OP_T_THRES)
+    {
+      /* There are at least some bytes to compare.  No need to test
+	 for LEN == 0 in this alignment loop.  */
+      while (srcp2 % OPSIZ != 0)
+	{
+	  a0 = ((byte *) srcp1)[0];
+	  b0 = ((byte *) srcp2)[0];
+	  srcp1 += 1;
+	  srcp2 += 1;
+	  res = a0 - b0;
+	  if (res != 0)
+	    return res;
+	  len -= 1;
+	}
+
+      /* SRCP2 is now aligned for memory operations on `op_t'.
+	 SRCP1 alignment determines if we can do a simple,
+	 aligned compare or need to shuffle bits.  */
+
+      if (srcp1 % OPSIZ == 0)
+	res = memcmp_common_alignment (srcp1, srcp2, len / OPSIZ);
+      else
+	res = memcmp_not_common_alignment (srcp1, srcp2, len / OPSIZ);
+      if (res != 0)
+	return res;
+
+      /* Number of bytes remaining in the interval [0..OPSIZ-1].  */
+      srcp1 += len & -OPSIZ;
+      srcp2 += len & -OPSIZ;
+      len %= OPSIZ;
+    }
+
+  /* There are just a few bytes to compare.  Use byte memory operations.  */
+  while (len != 0)
+    {
+      a0 = ((byte *) srcp1)[0];
+      b0 = ((byte *) srcp2)[0];
+      srcp1 += 1;
+      srcp2 += 1;
+      res = a0 - b0;
+      if (res != 0)
+	return res;
+      len -= 1;
+    }
+
+  return 0;
+}
+
+#ifdef weak_alias
+# undef bcmp
+weak_alias (memcmp, bcmp)
+#endif
diff --git a/src/memcmp.h b/src/memcmp.h
new file mode 100644
index 0000000..c0948f0
--- /dev/null
+++ b/src/memcmp.h
@@ -0,0 +1,8 @@
+#ifndef MEMCMP_H_INCLUDED
+#define MEMCMP_H_INCLUDED
+
+extern int memcmp __P ((__const __ptr_t __s1, __const __ptr_t __s2,
+  size_t __n));
+
+#endif  /* MEMCMP_H_INCLUDED */
+
diff --git a/src/misc.c b/src/misc.c
new file mode 100644
index 0000000..31d23d0
--- /dev/null
+++ b/src/misc.c
@@ -0,0 +1,117 @@
+/*
+ *  Copyright (C) 1998-2000 by Marco G"otze.
+ *
+ *  This code is part of the wmpinboard source package, which is
+ *  distributed under the terms of the GNU GPL2.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/stat.h>
+
+#include "wmpinboard.h"
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+extern const char *rc_file_name;
+
+/*
+ * prints an error message and exits
+ */ 
+void
+die(const char *text)
+{ 
+  fprintf(stderr, "Fatal error: %s\n", text);
+  exit(EXIT_FAILURE);
+}
+
+/*
+ * allocs <amount> bytes and die()s if that fails
+ */
+void*
+smalloc(long amount)
+{
+  void *p = 0;
+
+  p = malloc(amount);
+  if (!p) die("Out of memory!");
+  return p;
+}
+
+/*
+ * returns a true value if a text string is to be considered empty
+ * (if width > 0, limit the check to width characters)
+ */
+int
+string_empty(char *ptr, int width)
+{
+  int i = 0;
+
+  while (*ptr && (!width || i++ < width))
+    if (*ptr++ != ' ') return 0;
+  return 1;
+}
+
+/*
+ * flushes a possibly running interactive instance, returns a true value if
+ * another instance *is* evidently running
+ */
+int
+flush_instance(int pid)
+{
+  struct stat buf;
+  time_t t;
+  char *s;
+  int i;
+  int running = 0;
+
+  if (pid != (int) getpid()) {  /* not fulfilled if file doesn't exist */
+    s = smalloc(strlen(getenv("HOME")) + strlen(rc_file_name) + 1);
+    strcpy(s, getenv("HOME"));
+    strcat(s, rc_file_name);
+    stat(s, &buf);
+    t = buf.st_mtime;
+    /* make that other instance confirm its presence by modifying the file */
+    if (kill(pid, SIGUSR1) != -1) {
+      for (i = 0; i < 3; i++) {  /* wait up to 3 secs for a modification */
+        stat(s, &buf);
+        if (buf.st_mtime != t) break;
+        sleep(1);
+      }
+      running = buf.st_mtime != t;
+      /* we assume that modifying the file is safe now */
+    }
+    free(s);
+  }
+  return running;
+}
+
+/*
+ * u()ncsarbmel sht eoctnnesto  fs<>
+ * m(solt ysudef roc notss' ,osw  eod'n todi  tnip-alec)
+ */
+char*
+csarbmel(const char *s)
+{
+  char ch, *t;
+  int i;
+
+  t = smalloc(strlen(s)+1);
+  strcpy(t, s);
+  for (i = 0; i+1 < strlen(t); i += 2) {
+    ch = t[i];
+    t[i] = t[i+1];
+    t[i+1] = ch;
+  }
+  return t;
+}
+
diff --git a/src/misc.h b/src/misc.h
new file mode 100644
index 0000000..5d71daa
--- /dev/null
+++ b/src/misc.h
@@ -0,0 +1,24 @@
+/*
+ *  Copyright (C) 1998-2000 by Marco G"otze.
+ *
+ *  This code is part of the wmpinboard source package, which is
+ *  distributed under the terms of the GNU GPL2.
+ */
+
+#ifndef MISC_H_INCLUDED
+#define MISC_H_INCLUDED
+
+#include "wmpinboard.h"
+
+#define WARN(msg) fprintf(stderr, "Warning: %s\n", msg)
+
+void die(const char*);
+void *smalloc(long);
+int  string_empty(char*, int);
+int  flush_instance(int);
+char *csarbmel(const char *);
+void block_sigs();
+void unblock_sigs();
+
+#endif  /* MISC_H_INCLUDED */
+
diff --git a/src/notes.c b/src/notes.c
new file mode 100644
index 0000000..8fd2320
--- /dev/null
+++ b/src/notes.c
@@ -0,0 +1,1013 @@
+/*
+ *  Copyright (C) 1998-2000 by Marco G"otze.
+ *
+ *  This code is part of the wmpinboard source package, which is
+ *  distributed under the terms of the GNU GPL2.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include "wmpinboard.h"
+#include "misc.h"
+#include "xmisc.h"
+#include "notes.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifndef HAVE_MEMCMP
+#include "memcmp.h"
+#endif
+
+/* a list of the upper left corners of the separate areas of the alarm panel,
+   numbered from left to right and from top to bottom (double digits followed
+   by  switches) */
+typedef struct { int x, y; } coords_t;
+const coords_t abar_areas[6] = {
+  /* double digits, 12x9 each */
+  { 3, 4 }, { 19, 4 },
+  { 3, 15 }, { 19, 15 },
+  /* switches, 8x8 each */
+  { 47, 4 }, { 47, 16 }
+};
+
+/*
+ * adds a new note and returns its number (or -1 if notes limit exceeded)
+ */
+int
+add_note()
+{
+  int cols[C_NUM];
+  int rep = 20;
+  int i, j, n;
+
+  if (notes_count >= MAX_NOTES)
+    return -1;
+  n = notes_count++;
+
+  /* find a reasonable color */
+  for (i = 0; i < C_NUM; i++) cols[i] = 1;
+  for (i = 0; i < n; i++) cols[ndata[i].col] = 0;
+  for (i = j = 0; i < C_NUM; i++)
+    if (cols[i]) cols[j++] = i;
+  ndata[n].col = j ? cols[rand() % j] : rand() % C_NUM;
+
+  /* choose a random place to pin it, some pixels off any other note's origin
+     (possible if MAX_NOTES is sufficiently small) */
+  do {
+    ndata[n].x = 6 + rand() % 36;
+    ndata[n].y = 2 + rand() % 44;
+    j = 1;
+    for (i = 0; i < n; i++)
+      if (ndata[i].x - ndata[n].x < 5 && ndata[i].x - ndata[n].x > -5 &&
+          ndata[i].y - ndata[n].y < 5 && ndata[i].y - ndata[n].y > -5)
+      {
+        j = 0;
+        break;
+      }
+  } while (!j && --rep);
+
+  memset(ndata[n].text, 32, 59);
+  ndata[n].text[59] = '\0';
+  ndata[n].cursor = 0;
+  memset(ndata[n].sketch, 0, 512);
+  memset(ndata[n].creases, 0, 32);
+  ndata[n].a_time = -1;
+  ndata[n].a_flags = ALARM_DATE;
+
+  state.counter++;
+
+  return n;
+}
+
+/*
+ * removes a note
+ */
+void
+remove_note(int number)
+{
+  int i;
+
+  if (number >= notes_count) return;
+  /* in case memcpy() can't do overlapping copies... */
+  for (i = number; i < notes_count-1; i++)
+    memcpy(&ndata[i], &ndata[i+1], sizeof(data_t));
+  notes_count--;
+}
+
+/*
+ * moves a note on top of all others and returns the quote's new ID
+ */
+int
+raise_note(int number)
+{
+  data_t tmp;
+  int i;
+
+  if (number >= notes_count-1 || number < 0) return number;
+  memcpy(&tmp, &ndata[number], sizeof(data_t));
+  /* in case memcpy() can't do overlapping copies... */
+  for (i = number; i < notes_count-1; i++)
+    memcpy(&ndata[i], &ndata[i+1], sizeof(data_t));
+  memcpy(&ndata[notes_count-1], &tmp, sizeof(data_t));
+  return notes_count-1;
+}
+
+/*
+ * returns a value corresponding to how tilted a note is to be displayed
+ */
+inline int
+note_tilt(int note)
+{
+  return ndata[note].x < 14 ? 0 : (ndata[note].x < 36 ? 1 : 2);
+}
+
+/*
+ * returns true if the note in question is to be considered empty
+ */
+int
+note_empty(int note)
+{
+  char *ptr = ndata[note].sketch;
+  int i;
+
+  if (!string_empty(ndata[note].text, 0)) return 0;
+  for (i = 0; i < 511; i++, ptr++)  /* last byte ignored */
+    if (*ptr) return 0;
+  return 1;
+}
+
+/*
+ * creates templates for the icons suiting the specified note
+ */
+void
+color_notes(int note)
+{
+  XGetSubImage(display, app, 64, 0, 16, 48, ~0, ZPixmap, img, 64, 0);
+  if (ndata[note].sketch[511] & 1)
+    replace_color(img, 64, 0, 16, 48, C_EXTRA, palette[ndata[note].col].fg);
+  else
+    replace_color(img, 64, 0, 16, 48, C_EXTRA, palette[ndata[note].col].bg);
+  replace_color(img, 64, 0, 16, 48, C_INNER, palette[ndata[note].col].bg);
+#ifdef CREASES
+  render_wear(note);
+#endif
+}
+
+/*
+ * draws a note's miniature representation on the pinboard
+ */
+void
+pin_note(int note)
+{
+  merge_masked(img, 64, 16*note_tilt(note), ndata[note].x,
+    ndata[note].y, 16, 16, C_OUTER);
+}
+
+/*
+ * renders the pinboard with all of its notes excluding <exclude> if >= 0
+ */
+void
+render_pinboard(int exclude)
+{
+  int i;
+
+  XPutImage(display, app, normalGC, img, 0, 0, 0, 0, 64, 64);
+  for (i = 0; i < notes_count; i++)
+    if (i != exclude) {
+      color_notes(i);
+      pin_note(i);
+    }
+}
+
+/*
+ * if (<x>, <y>) is within a quote's area, returns the quote's ID, otherwise -1
+ */
+int
+selected_note(int x, int y)
+{
+  int i;
+
+  for (i = notes_count-1; i >= 0; i--)
+    if (x >= ndata[i].x && x < ndata[i].x+16 &&
+        y >= ndata[i].y && y < ndata[i].y+16 &&
+        XGetPixel(img, 128+x-ndata[i].x, note_tilt(i)*16+y-ndata[i].y) !=
+          C_OUTER)
+    {
+      return i;
+    }
+  return -1;
+}
+
+/*
+ * prints a letter identified by a note and a position in its text string, and
+ * overlays it by a possible sketch if sketch has a true value
+ */
+void
+print_letter(int note, int letter, int sketch)
+{
+  int a = 2+6*(letter%10), b = 2+10*(letter/10);
+
+
+  if (sketch) {
+    XFillRectangle(display, app, fillGC, a, b, 6, 10);
+#ifdef CREASES
+    render_edit_wear_area(note, a, b, 6, 10);
+#endif
+    draw_sketch_area(note, a, b, 6, 10);
+  }
+  XDrawString(display, app, fontGC, a, b + font->ascent,
+    &ndata[note].text[letter], 1);
+}
+
+/*
+ * prints a note's entire text *without* drawing a possibly existing sketch
+ */
+void
+print_text(int note)
+{
+  int i;
+
+  for (i = 0; i < 59; i++) print_letter(note, i, 0);
+}
+
+/*
+ * shifts part of a note's text to the right, inserting <ch> (step >= 1)
+ */
+void
+shift_string(int note, int at, int margin, int step, int ch)
+{
+  int i;
+
+  if (step < 1) return;
+
+  for (i = margin; i >= at+step; i--) {
+    ndata[note].text[i] = ndata[note].text[i-step];
+    print_letter(note, i, 1);
+  }
+  for (i = at; i < at+step; i++) {
+    ndata[note].text[i] = ch;
+    print_letter(note, i, 1);
+  }
+}
+
+/*
+ * draws a rectangular section of a sketch, according to the data saved along
+ * with a note
+ */
+void
+draw_sketch_area(int note, int x, int y, int w, int h)
+{
+  int i, j;
+
+  for (i = x; i < x+w; i++)
+    for (j = y; j < y+h; j++)
+      if (ndata[note].sketch[8*j + i/8] & (1<<(i%8)))
+        XDrawPoint(display, app, fontGC, i, j);
+}
+
+/*
+ * returns the number of the button bar's button corresponding to the given
+:* coordinates, or -1
+ */
+int
+bbar_button(int x, int y)
+{
+  int i;
+
+  for (i = 0; i < 8; i++)
+    if (x >= 4 + (i%4)*14 && x < 18 + (i%4)*14 && y >= 32 + (i/4)*14 &&
+      y < 46 + (i/4)*14)
+    {
+      return i;
+    }
+  return -1;
+}
+
+/*
+ * returns the number of that area on the alarm panel that corresponds to the
+ * given coordinates, or -1
+ */
+int
+abar_area(int x, int y)
+{
+  int i;
+
+  /* relativate positions */
+  x -= 3;
+  y -= 4;
+  for (i = 0; i < 6; i++) {
+    coords_t c = abar_areas[i];
+    if (x >= c.x && x < (c.x + (i < 4 ? 12 : 8)) &&
+        y >= c.y && y < (c.y + (i < 4 ?  9 : 8)))
+    {
+      return i;
+    }
+  }
+  return -1;
+}
+
+/*
+ * displays note <note> in edit mode view
+ */
+void
+render_note(int note)
+{
+  int i;
+
+  XSetForeground(display, fillGC, palette[ndata[note].col].bg);
+  XSetForeground(display, fontGC, BlackPixel(display, DefaultScreen(display)));
+  XSetBackground(display, fontGC, palette[ndata[note].col].bg);
+  set_mask(0);
+  XFillRectangle(display, app, fillGC, 0, 0, 64, 64);
+  XDrawRectangle(display, app, fontGC, 0, 0, 63, 63);
+  XSetForeground(display, fontGC, palette[ndata[note].col].fg);
+  for (i = 55; i < 62; i += 2)  /* draw triangle in the bottom right corner */
+    XDrawLine(display, app, fontGC, i, 62, 62, i);
+}
+
+/*
+ * prepares edit mode for note <note> (does NOT update the display)
+ */
+void
+init_edit_mode(int note)
+{
+#ifdef CREASES
+  XGCValues gcv;
+
+  gcv.foreground = palette[ndata[note].col].cr;
+  XChangeGC(display, creaseGC, GCForeground, &gcv);
+#endif
+  render_note(note);
+#ifdef CREASES
+  render_edit_wear(note);
+#endif
+  print_text(note);
+  draw_sketch(note);
+}
+
+/*
+ * updates a double digit area on the alarm panel
+ */
+inline void
+render_abar_number(int field)
+{
+  int a, b;
+
+  /* split two-digit number into separate digits */
+  b = state.a_edit[field] % 10;
+  a = (state.a_edit[field] / 10) % 10;
+  /* copy appropriate digits */
+  XCopyArea(display, digits, abar, normalGC, 6*a, 0, 6, 9,
+    abar_areas[field].x, abar_areas[field].y);
+  XCopyArea(display, digits, abar, normalGC, 6*b, 0, 6, 9,
+    abar_areas[field].x+7, abar_areas[field].y);
+}
+
+/*
+ * updates the alarm panel's switches for a given note
+ */
+inline void
+render_abar_switches(int note)
+{
+  XPutImage(display, abar, normalGC, img,
+    (ndata[note].a_flags & ALARM_DATE) ? 78 : 70, 55, 47, 4, 8, 8);
+  XPutImage(display, abar, normalGC, img, 
+    (ndata[note].a_flags & ALARM_DATE) ? 70 : 78, 55, 47, 16, 8, 8);
+}
+
+/*
+ * renders the alarm panel for a given note
+ */
+void
+render_abar(int note)
+{
+  int i;
+
+  for (i = 0; i < 4; i++) render_abar_number(i);
+  render_abar_switches(note);
+}
+
+/*
+ * converts <note>'s contents to what's referred to as "cooked" format (as
+ * opposed to raw data); returns a malloc()ed string that has to be freed
+ * later on!
+ */
+char*
+cook(int note, int pos, int len)
+{
+  char *s, *t;
+  int i;
+
+  s = smalloc(70);
+  for (t = s, i = pos; i < (pos+len > 59 ? 59 : pos+len); i++) {
+    if (!string_empty(&ndata[note].text[i], (i >= 50 ? 59 : 10*(i/10+1))-i))
+    {
+      if (t > s && !(i%10) && t[-1] != ' ' && t[-1] != '-')
+        *t++ = ' ';  /* replace virtual newlines by spaces */
+      if ((t > s && (ndata[note].text[i] != ' ' || t[-1] != ' ') &&
+        !(t[-1] == '-'
+        && string_empty(&ndata[note].text[10*(i/10)], i%10+1))) ||
+        (t == s && ndata[note].text[i] != ' '))
+      {
+        *t++ = ndata[note].text[i];
+      }
+    }
+  }
+  *t = '\0';
+  return s;
+}
+
+/*
+ * dumps all notes' contents on STDOUT (raw dump unless <cooked> is true)
+ */
+void
+dump_notes(int cooked)
+{
+  char *s;
+  int c = 0, i, alarms;
+
+  /* determine if any notes have alarms configured */
+  time_next_alarm();
+  alarms = state.alarm.note >= 0;
+
+  /* print existing notes */
+  for (; c < 4; c++)
+    for (i = 0; i < notes_count; i++)
+      if (c_group[ndata[i].col] == c) {
+        s = cooked ? cook(i, 0, 59) : ndata[i].text;
+        if (alarms) {  /* any alarms set at all? */
+          if (ndata[i].a_flags & ALARM_ON) {
+            explode_time(i);
+            if (ndata[i].a_flags & ALARM_DATE) {  /* date-specific alarm */
+              printf("%02d-%02d-%02d %02d:%02d #%02d: %s\n",
+                state.a_edit[4]%100, state.a_edit[2], state.a_edit[3],
+                state.a_edit[0], state.a_edit[1], i, s);
+            } else {  /* daily alarm */
+              printf("daily at %02d:%02d #%02d: %s\n", state.a_edit[0],
+                state.a_edit[1], i, s);
+            }
+          } else  /* no alarm set for this note */
+            printf("%14s #%02d: %s\n", "", i, s);
+        } else  /* no alarms set at all */
+          printf("#%02d: %s\n", i, s);
+        if (cooked) free(s);
+      }
+}
+
+/*
+ * returns the (serial) number of the character (<x>, <y>) belongs to on a
+ * note; prohibiting char #59 if <strict>
+ */
+int
+char_at(int x, int y, int strict)
+{
+  int i;
+
+  if (x < 2) x = 2;
+  if (x > 62) x = 62;  /* intentional! */
+  if (y > 61) y = 61;
+  if (y < 2) y = 2;
+  i = (x-2)/6 + ((y-2)/10)*10;
+  if (i > 59) i = 59;
+  return i;
+}
+
+#ifdef CREASES
+/*
+ * applies random wear & tear to a note (the default probability is multiplied
+ * by <factor>)
+ */
+void
+wear_note(int note)
+{
+  /* prefabricated crease patterns */
+  static const int pats = 8;
+  static const unsigned char pat[8][5][5] = {
+    { { 1,0,0,0,0 },
+      { 0,1,0,0,0 },
+      { 0,0,1,0,0 },
+      { 0,0,0,1,0 },
+      { 0,0,0,0,1 } },
+    { { 0,0,0,0,1 },
+      { 0,0,0,1,0 },
+      { 0,0,1,0,0 },
+      { 0,1,0,0,0 },
+      { 1,0,0,0,0 } },
+    { { 0,0,0,1,0 },
+      { 0,0,0,1,0 },
+      { 0,0,1,0,0 },
+      { 1,1,0,0,0 },
+      { 0,0,0,0,0 } },
+    { { 0,1,0,0,0 },
+      { 0,1,0,0,0 },
+      { 0,0,1,0,0 },
+      { 0,0,0,1,1 },
+      { 0,0,0,0,0 } },
+    { { 0,0,0,0,0 },
+      { 0,0,0,1,1 },
+      { 0,0,1,0,0 },
+      { 0,1,0,0,0 },
+      { 0,1,0,0,0 } },
+    { { 0,0,0,0,0 },
+      { 1,1,0,0,0 },
+      { 0,0,1,0,0 },
+      { 0,0,0,1,0 },
+      { 0,0,0,1,0 } },
+    { { 0,0,0,0,0 },
+      { 0,1,0,0,0 },
+      { 0,0,1,0,0 },
+      { 0,0,0,1,0 },
+      { 0,0,0,0,0 } },
+    { { 0,0,0,0,0 },
+      { 0,0,0,1,0 },
+      { 0,0,1,0,0 },
+      { 0,1,0,0,0 },
+      { 0,0,0,0,0 } }
+  };
+  int i, j, k = 0;
+
+  /* determine number of crease bits */
+  for (i = 0; i < 32; i++)
+   for (j = 0; j < 8; j++)
+     k += ndata[note].creases[i]>>(j) & 1;
+  /* don't cover more than 35% of a note's area with creases */
+  if (100*k/256 < 35 && !(rand() % (4+k/64))) {
+    int x, y;
+    int t = rand() % pats;  /* choose a prefab crease pattern to apply... */
+    int a = rand() % 11;    /* ...as well as its location */
+    int b = rand() % 11;
+
+    for (y = 0; y < 5; y++)
+      for (x = 0; x < 5; x++)
+        if (pat[t][y][x])
+          ndata[note].creases[2*(b+y) + (a+x<8)] |= 1<<(7-(a+x)%8);
+  }
+}
+
+/*
+ * makes an otherwise pre-rendered note look worn out
+ */
+void
+render_wear(int note)
+{
+  int x, y, z;
+
+  for (z = 0; z <= 48; z += 16)
+    for (y = 0; y < 16; y++)
+      for (x = 0; x < 16; x++)
+        if (ndata[note].creases[2*y+x/8]>>(7-x%8) & 1 &&
+          XGetPixel(img, 64+x, z+y) == palette[ndata[note].col].bg)
+        {
+          XPutPixel(img, 64+x, z+y, palette[ndata[note].col].cr);
+        }
+}
+
+/*
+ * renders wear & tear in edit mode in a specific window
+ */
+void
+render_edit_wear_area_win(Window win, int note, int a, int b, int w, int h)
+{
+#define m(x, y) (m[2*(y) + (x)/8]>>(7-(x)%8) & 1)
+#define l(x, y) (l[8*(y) + (x)/8]>>(7-(x)%8) & 1)
+  static unsigned char l[(64/8)*64];  /* high res crease map */
+  static unsigned char m[32];         /* low res crease map */
+  int x, y, z;
+
+  /* lazily render a high-res crease pattern */
+  if (memcmp(m, ndata[note].creases, sizeof(m))) {
+    memcpy(m, ndata[note].creases, sizeof(m));
+    memset(l, 0, sizeof(l));
+    /* now we have to somehow extrapolate a 64x64 crease pattern from a 16x16
+       sketch... */
+    for (z = 0; z < 3; z++)  /* three passes */
+      for (y = 2; y < 62; y++)
+        for (x = 2; x < 62; x++) {
+          int sx = x/4, sy = y/4;
+          int xx = x%4, yy = y%4;
+          int xi = (xx<<1)%3, yi = (yy<<1)%3;
+          int xd = xx<2 ? -1 : 1, yd = yy<2 ? -1 : 1;
+
+          if (z < 2 && (  /* during passes #0 and #1 */
+            (!z && xi && yi && m(sx, sy) &&
+              (m(sx+xd, sy+yd) || m(sx, sy+yd) || m(sx+xd, sy) ) &&
+              ((xd<0 && sx<2) || (xd>0 && sx>14) || (yd<0 && sy<2) ||
+               (yd>0 && sy>14) || m(sx+2*xd, sy+2*yd))
+            ) || (z && (
+              (!xi && !yi && l(x-xd, y-yd) && l(x+2*xd, y+2*yd)) ||
+              (!xi && yi && l(x-xd, y) && l(x+2*xd, y)) ||
+              (xi && !yi && l(x, y-yd) && l(x, y+2*yd))
+            ))))
+          {
+            l[8*y + x/8] |= 1<<(7-x%8);
+          }
+          /* during pass #2, remove isolated dots */
+          if (z == 2 && l(x, y) && !(l(x-1, y-1) || l(x, y-1) ||
+            l(x+1, y-1) || l(x-1, y) || l(x+1, y) || l(x-1, y+1) ||
+            l(x, y+1) || l(x+1, y+1)))
+          {
+            l[8*y + x/8] &= 0xff - (1<<(7-x%8));
+          }
+        }
+  }
+  for (y = b; y < b+h; y++)
+    for (x = a; x < a+w; x++)
+      if (x > 1 && y > 1 && x < 62 && y < 62 && x+y <= 116 && l(x, y))
+        XDrawPoint(display, win, creaseGC, x, y);
+#undef m
+#undef l
+}
+#endif
+
+#ifdef FUNSTUFF
+
+/*
+ * atek sparppoirta ecaitnoo  npsceai lcoacisno,sr terusnt ur efit ah tahppnede
+ */
+void
+check_occasion(int d, int m, int y)
+{
+  static const unsigned char sketch0[256] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x3d, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe7, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x4d, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x5d, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x0d, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x1f, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x18, 0x78, 0x9f, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xfe, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x10, 0x60, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x30, 0xf0, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x60, 0xf0, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3e, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x03, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
+  };
+  static const unsigned char sketch1[512] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x03, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x03, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x07, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x04, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x04, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0a, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0a, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0a, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x18, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x1b, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x30, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x66, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x08, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x48, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x61, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x97, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x90, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf8, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0xc0, 0x0d, 0xc0, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0x03,
+    0x00, 0x00, 0x00, 0x00, 0x60, 0x40, 0x80, 0x02,
+    0x00, 0x00, 0x00, 0x00, 0x20, 0x80, 0x03, 0x02,
+    0x00, 0x00, 0x00, 0x00, 0x20, 0x08, 0x56, 0x06,
+    0x00, 0x00, 0x00, 0x00, 0xe0, 0xf8, 0x1f, 0x06,
+    0x00, 0x00, 0x00, 0x00, 0xf8, 0x6f, 0xfd, 0x07,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x03,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x03, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x07, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
+  };
+  char *s;
+  int note;
+
+  if (!notes_count && !(state.state_bits & 1)) {  /* ewclmo een wsures */
+    if ((note = add_note()) >= 0) {
+      ndata[note].col = 15;
+      memcpy(&ndata[note].sketch[256], sketch0, 256);
+      s = csarbmel(
+        "EWCLMO EotmwipbnaodrhTnaskf rortiygni  tuo!t               ");
+      strcpy(ndata[note].text, s);
+      free(s);
+      ndata[note].cursor = 50;
+      state.state_bits |= 1;
+    }
+  } else if (notes_count)
+    state.state_bits |= 1;  /* purgdadeu essrw not'g tet ihs */
+
+  if (m == 12 && d >= 25 && d <= 26) {  /* mXsa */
+    if (!(state.state_bits & 2) && (note = add_note()) >= 0) {
+      ndata[note].col = 14;
+      memcpy(ndata[note].sketch, sketch1, 512);
+      s = csarbmel(
+        "          A M REYR    MXSA      T  O    Y UO !             ");
+      strcpy(ndata[note].text, s);
+      free(s);
+      state.state_bits |= 2;
+    }
+  } else state.state_bits &= ~2;
+
+  if (m == 1 && d <= 3) {  /* eN weYra */
+    if (!(state.state_bits & 4) && (note = add_note()) >= 0) {
+      ndata[note].col = 11;
+      ndata[note].sketch[511] = 0x01;
+      s = csarbmel(
+        "nOeca agni aeyrah saapssde.. .A ynaw,y  A H PAYP  EN WEYRA!");
+      strcpy(ndata[note].text, s);
+      free(s);
+      state.state_bits |= 4;
+    }
+  } else state.state_bits &= ~4;
+}
+#endif
+
+/*
+ * pastes <text> into note #<note>, starting at <offset>; returns the serial
+ * number of the character right after the pasted string's end; overwrites
+ * previous contents; tries to word-wrap unless <raw> has a true value
+ */
+int
+paste_string(int note, int offset, const char *s, int raw)
+{
+  const char *t;
+  int i, j;
+
+  if (!raw) {  /* paste "cooked" */
+    for (i = offset; *s && i < 59; ) {
+      for (; *s && (*s == ' ' || *s == '\t' || *s == '\n'); s++);
+      for (t = s; *t && (t == s || *t == '-' || *(t-1) != '-') &&
+        *t != ' ' && *t != '\t' && *t != '\n'; t++);
+      j = t-s;
+      if (i < 50 && i%10 && i/10 != (i+j-1)/10) i = (i/10+1)*10;  /* next l.? */
+      if (j && i <= 58) {
+        if (i+j >= 58) {  /* word too long for note? */
+          strncpy(&ndata[note].text[i], s, 59-i);
+          i = 59;
+        } else {
+          strncpy(&ndata[note].text[i], s, j);
+          i += j;
+        }
+        if (*(t-1) != '-' && i%10) i++;  /* insert blank? */
+        s = t;
+      }
+    }
+    if (ndata[note].text[i] == ' ')  /* place cursor right after the text */
+      for (; i > offset && ndata[note].text[i-1] == ' '; i--);
+    return i;
+  } else {  /* paste raw */
+    i = strlen(s);
+    if (offset+i > 59) i = 59-offset;
+    strncpy(&ndata[note].text[offset], s, i);
+    return offset+i;
+  }
+}
+
+/*
+ * pastes <data> into note #<note> at offset <pos>, inserting if <ins>,
+ * word-wrapping unless <raw>
+ */
+void
+paste(int note, int pos, const char *data, int ins, int raw)
+{
+  char *s = 0;
+  int i;
+
+  if (ins) {
+    if (raw) {
+      s = smalloc(60);
+      strcpy(s, ndata[note].text);
+    } else {
+      /* want to wrap subsequent text later, so we have to save it cooked */
+      s = cook(note, 0, 59);
+    }
+    memset(&ndata[note].text[pos], ' ', 59-pos);
+  } else
+    memset(&ndata[note].text[pos], ' ', pos+strlen(data) > 59 ? 59-pos :
+      strlen(data));
+  i = paste_string(note, pos, data, raw);
+  if (ins) {
+    if (i <= 58) paste_string(note, i, &s[pos], raw);
+    free(s);
+  }
+  ndata[note].cursor = i > 58 ? 58 : i;
+}
+
+/*
+ * checks whether state.a_edit is valid (mday range w/respect to month...),
+ * sets the hidden year field to a sensible value; the return value is boolean
+ */
+int
+check_time()
+{
+  struct tm data, *ptr;
+  time_t tt;
+
+  tt = time(0);
+  ptr = localtime(&tt);
+  memcpy(&data, ptr, sizeof(struct tm));
+  data.tm_isdst = -1;  /* let mktime() decide */
+  data.tm_year = state.a_edit[2]-1 > ptr->tm_mon ||
+    (state.a_edit[2]-1 == ptr->tm_mon && (state.a_edit[3] > ptr->tm_mday ||
+    (state.a_edit[3] == ptr->tm_mday && (state.a_edit[0] > ptr->tm_hour ||
+    (state.a_edit[0] == ptr->tm_hour && (state.a_edit[1] > ptr->tm_min ||
+    (state.a_edit[1] == ptr->tm_min && !ptr->tm_sec))))))) ? ptr->tm_year :
+    ptr->tm_year+1;
+  data.tm_mon = state.a_edit[2]-1;
+  data.tm_mday = state.a_edit[3];
+  data.tm_hour = state.a_edit[0];
+  data.tm_min = state.a_edit[1];
+  /* check if date is convertible, i.e., valid */
+  tt = mktime(&data);
+  if (tt == -1) return 0;
+  /* check if date has been adapted -> return failure */
+  if (data.tm_mon != state.a_edit[2]-1 || data.tm_mday != state.a_edit[3])
+    return 0;
+  /* adapt date and return */
+  state.a_edit[4] = (unsigned char) data.tm_year;  /* char suffices */
+  return 1;
+}
+
+/*
+ * transforms ndata[note].a_time to state.a_edit
+ */
+void
+explode_time(int note)
+{
+  struct tm *ptr;
+
+  if (ndata[note].a_time != -1) {
+    ptr = localtime(&ndata[note].a_time);
+    state.a_edit[0] = ptr->tm_hour;
+    state.a_edit[1] = ptr->tm_min;
+    state.a_edit[4] = ptr->tm_year;
+  } else {  /* initialize on first call */
+    time_t tt;
+    time(&tt);
+    tt += 60*60;
+    ptr = localtime(&tt);
+    state.a_edit[0] = ptr->tm_hour;
+    state.a_edit[1] = 0;  /* minute */
+    state.a_edit[4] = (unsigned char) ptr->tm_year;
+  }
+  state.a_edit[2] = ptr->tm_mon+1;
+  state.a_edit[3] = ptr->tm_mday;
+}
+
+/*
+ * transforms state.a_edit to ndata[note].a_time
+ */
+void
+implode_time(int note)
+{
+  struct tm data, *ptr;
+  time_t tt;
+
+  time(&tt);
+  ptr = localtime(&tt);
+  memcpy(&data, ptr, sizeof(struct tm));
+  data.tm_isdst = -1;  /* let mktime determine */
+  data.tm_hour = state.a_edit[0];
+  data.tm_min = state.a_edit[1];
+  data.tm_sec = 0;
+  /* the following 3 ain't required for daily notes, but this way, the date
+     will be saved even in this case, so we set them */
+  data.tm_year = state.a_edit[4];
+  data.tm_mon = state.a_edit[2]-1;
+  data.tm_mday = state.a_edit[3];
+  ndata[note].a_time = mktime(&data);  /* shouldn't fail */
+}
+
+/*
+ * evaluating its a_flags, returns an updated value of a note's a_time field,
+ * considering <now> the current time if != -1
+ */
+time_t
+adapt_time(int note, time_t now)
+{
+  time_t res = ndata[note].a_time;
+
+  /* adaption is only necessary in the case of a daily alarm */
+  if (!(ndata[note].a_flags & ALARM_DATE)) {
+    struct tm atm, *ptr;
+
+    if (now == -1) time(&now);
+    ptr = localtime(&res);  /* break down alarm time */
+    memcpy(&atm, ptr, sizeof(struct tm));
+    ptr = localtime(&now);                 /* break down current time */
+    atm.tm_year = ptr->tm_year;
+    atm.tm_mon  = ptr->tm_mon;
+    atm.tm_mday = ptr->tm_mday;
+    atm.tm_sec  = 0;  /* just making sure */
+    res = mktime(&atm);
+    if (res < now) res += 24*60*60;  /* NOT `<='! */
+  }
+
+  return res;
+}
+
+/*
+ * sets the state variable's alarm sub structure's values for the next alarm
+ */
+/*
+    Together with appropriate calls from wmpinboard.c, this function results
+    in the following strategy for scheduling alarms:
+
+      - firstly, alarms with ALARM_DATE set are executed only once and get
+        deactivated afterwards; daily alarms remain active even after an alarm
+      - if the program is started after some alarm time was reach, the alarm
+        is displayed if (and only if) it's a date-specific alarm
+      - if an alarm is running while another one becomes due, this subsequent
+        alarm will be run after the user has closed the other note
+      - to achieve the latter, time_next_alarm() considers all notes with an
+        alarm time equal to or greater than the previous one; if they're equal,
+        the new alarm's note's ID must be greater than that of the previous
+        alarm (this realizes a determined order for concurrent alarms and
+        allows the program to avoid running one daily alarm several times in
+        a row)
+*/
+void
+time_next_alarm()
+{
+  time_t prev_time = state.alarm.time;
+  int i, prev_note = state.alarm.note;
+
+  if (state.alarm.note >= 0 && !state.alarm.run) prev_note = -1;
+  if (prev_time == -1 || prev_time > time(0)) prev_time = time(0);
+  state.alarm.time = -1;
+  state.alarm.note = -1;
+  state.alarm.run = 0;
+  for (i = 0; i < notes_count; i++)
+    if (ndata[i].a_flags & ALARM_ON) {
+      time_t tt = adapt_time(i, prev_time);
+      if (((ndata[i].a_flags & ALARM_DATE) || (tt == prev_time &&
+        i > prev_note) || (tt > prev_time)) &&
+        (state.alarm.time == -1 || tt < state.alarm.time))
+      {
+        state.alarm.time = tt;
+        state.alarm.note = i;
+      }
+    }
+  if (state.alarm.note < 0 && prev_note >= 0 &&
+    (ndata[prev_note].a_flags & ALARM_ON))
+  { /* if there is just one daily alarm, it hasn't been set again above, so
+       let's do it here explicitly */
+    state.alarm.note = prev_note;
+    state.alarm.time = adapt_time(prev_note, prev_time+1);
+  }
+}
+
diff --git a/src/notes.h b/src/notes.h
new file mode 100644
index 0000000..b3b04db
--- /dev/null
+++ b/src/notes.h
@@ -0,0 +1,67 @@
+/*
+ *  Copyright (C) 1998-2000 by Marco G"otze.
+ *
+ *  This code is part of the wmpinboard source package, which is
+ *  distributed under the terms of the GNU GPL2.
+ */
+
+#ifndef NOTES_H_INCLUDED
+#define NOTES_H_INCLUDED
+
+#include <time.h>
+
+#include "wmpinboard.h"
+
+#define draw_sketch(note) draw_sketch_area(note, 1, 1, 62, 62)
+
+int    add_note();
+void   remove_note(int);
+int    raise_note(int);
+int    note_tilt(int);
+int    note_empty(int);
+void   color_notes(int);
+void   pin_note(int);
+void   render_pinboard(int);
+void   render_note(int);
+int    selected_note(int, int);
+void   print_letter(int, int, int);
+void   print_text(int);
+void   shift_string(int, int, int, int, int);
+void   draw_sketch_area(int, int, int, int, int);
+int    bbar_button(int, int);
+int    abar_area(int, int);
+void   init_edit_mode(int);
+void   render_abar_number(int);
+void   render_abar_switches(int);
+void   render_abar(int);
+char   *cook(int, int, int);
+void   dump_notes(int);
+int    char_at(int, int, int);
+int    paste_string(int, int, const char*, int);
+void   paste(int, int, const char*, int, int);
+int    check_time();
+void   explode_time(int);
+void   implode_time(int);
+time_t adapt_time(int, time_t);
+void   time_next_alarm();
+
+#ifdef CREASES
+
+#include <X11/Xlib.h>
+
+#define render_edit_wear_area(note, x, y, w, h) \
+  render_edit_wear_area_win(app, note, x, y, w, h)
+#define render_edit_wear(note) render_edit_wear_area(note, 1, 1, 62, 62)
+
+void wear_note(int);
+void render_wear(int);
+void render_edit_wear_area_win(Window, int, int, int, int, int);
+
+#endif
+
+#ifdef FUNSTUFF
+void check_occasion(int, int, int);
+#endif
+
+#endif  /* NOTES_H_INCLUDED */
+
diff --git a/src/wmpinboard.c b/src/wmpinboard.c
new file mode 100644
index 0000000..c1a6235
--- /dev/null
+++ b/src/wmpinboard.c
@@ -0,0 +1,2299 @@
+/*
+ *  Copyright (C) 1998-2000 by Marco G"otze.
+ *
+ *  This code is part of the wmpinboard source package, which is
+ *  distributed under the terms of the GNU GPL2.
+ */
+
+#include <ctype.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/cursorfont.h>
+#include <X11/keysym.h>
+#include <X11/xpm.h>
+#include <X11/extensions/shape.h>
+
+#include "wmpinboard.h"
+#include "misc.h"
+#include "notes.h"
+#include "xmisc.h"
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "../xpm/pinboard.xpm"
+#include "../xpm/bbar.xpm"
+#include "../xpm/abar.xpm"
+#include "../xpm/digits.xpm"
+
+const char *rc_file_name = "/.wmpinboarddata";  /* to be prepended with dir */
+
+const char c_group[C_NUM] =  /* group available note colors */
+  { 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 0, 0, 0 };
+
+#define NUM_FONTS 3
+const struct {  /* shortcuts for known fonts */
+  char name[8];
+  char desc[40];
+  char font[60];
+} fonts[NUM_FONTS] = {
+  { "Default", "default font (ISO8859-1)", "-*-fixed-*--10-*-iso8859-1" },
+  { "Latin2",  "Latin2 (ISO8859-2)",       "-*-fixed-*--10-*-iso8859-2" },
+  { "Russian", "cyrillic font (KOI8-R)",   "-*-fixed-*--10-*-koi8-r" }
+};
+const char *default_font = fonts[0].font;
+
+opts_t opts = { 0, 0, 0, -1, TIMEOUT, 1, "", "", "" };
+
+palette_t palette[C_NUM+1];
+Cursor cursors[3];  /* alternate X cursors */
+
+int label_coords[4] = { 12, 0, 39, 9 };  /* default "TO DO" label coords */
+
+data_t ndata[MAX_NOTES];  /* this holds all the notes */
+int notes_count = 0;
+
+state_t state = { 0, { 0, 0 }, 0, -1, -1, 0, 0, M_NOOP, -1, -1, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, { -1, -1, 0, 0, None } };
+
+Display *display;
+Window mainwin, iconwin, win;  /* win = visible window */
+Pixmap app = None, bbar = None, abar = None, digits = None;
+XImage *img = 0;
+GC normalGC = 0, fontGC = 0, fillGC = 0;
+#ifdef CREASES
+GC creaseGC = 0;
+#endif
+XFontStruct *font = 0;
+
+sigset_t sync_sig_set;  /* signals used for syncing with other instances */
+int sync_sig_block_counter = 0;
+
+                               /*************/
+/******************************* FUNCTIONS ***********************************/
+                             /*************/
+
+void s_block();
+void s_unblock();
+int  notes_io(int);
+void load_theme(const char*);
+void init(void);
+void done(void);
+int  try_font(const char*, int);
+void load_font(void);
+void set_kbfocus(int);
+void action(actions, const void*);
+void help(void);
+void parse_argv(int, char**);
+void draw_cursor(int, int);
+void set_cursor(int, int);
+void sel_text(int);
+void draw_pixel(int, int);
+void set_mode(modes);
+void quit_edit_mode(int, int);
+void timer(unsigned int);
+void animate_bbar(int);
+void animate_abar(int);
+void animate_note(int);
+void animate_alarm();
+void handle_ButtonPress(XEvent*);
+void handle_ButtonRelease(XEvent*);
+void handle_MotionNotify(XEvent*);
+void handle_KeyPress(XEvent*);
+void handle_sigs(int);
+
+/*
+ * blocks the signals in sync_sig_set
+ */
+inline void
+s_block()
+{
+  if (!sync_sig_block_counter++)
+    sigprocmask(SIG_BLOCK, &sync_sig_set, 0);
+}
+
+/*
+ * inverse of the above
+ */
+inline void
+s_unblock()
+{
+  if (!--sync_sig_block_counter)
+    sigprocmask(SIG_UNBLOCK, &sync_sig_set, 0);
+}
+
+/*
+ * reads or writes the data file; returns the PID the file was last written by
+ *
+ * file format revisions:
+ *   0 = v0.7+: introduced binary data file format
+ *   1 = v0.8+: added <data_t.{cursor,sketch}>
+ *   2 = v0.9+: added <data_t.creases>, <state.state_bits>
+ *   3 = v0.9.1+: added <PID>
+ *   4 = v0.10+: added <theme>
+ *   5 = v0.99: added <counter>
+ *   6 = v0.99.1: added <alarm_cmd>, <data_t.a_{time,flags}>
+ */
+int
+notes_io(int save)
+{
+  /* size of per-note records for specific revisions */
+  static const int size_0 = sizeof(struct { int a, b, c; char d[60]; });
+  static const int size_1 =
+    sizeof(struct { int a, b, c; char d[60]; int e; char f[512]; });
+  static const int size_2 =
+    sizeof(struct { int a, b, c; char d[60]; int e; char f[512]; char g[32]; });
+  static const int size_6 = sizeof(struct { int a, b, c; char d[60]; int e;
+    char f[512]; char g[32]; time_t h; char i; });
+  static const char *ext = ".new";
+  static const char *header = "WMPB6";  /* data file header */
+  char s[STRING_BUF_SIZE];
+  char t[STRING_BUF_SIZE];
+  FILE *file;
+  int pid = (int) getpid();
+  static int sizes[6];
+  sizes[0] = size_0;
+  sizes[1] = size_1;
+  sizes[2] = size_2;
+  sizes[3] = size_2;
+  sizes[4] = size_2;
+  sizes[5] = size_2;
+  sizes[6] = size_6;
+
+  s_block();
+
+  s[sizeof(s)-1] = '\0';
+  strncpy(s, getenv("HOME"), sizeof(s));
+  if (sizeof(s)-strlen(s)-1 < strlen(rc_file_name)+strlen(ext))
+    die("Buffer too small in notes_io().");
+  strcat(s, rc_file_name);
+  if (save) {  /* save to temporary file first, later rename it */
+    strcpy(t, s);
+    strcat(s, ext);
+  }
+
+  file = fopen(s, save ? "wb" : "rb");
+  if (!file) {
+    if (save)
+      die("Couldn't open data file for writing.");
+    else {
+      s_unblock();
+      return pid;  /* just don't read in anything if opening the file failed */
+    }
+  }
+
+  if (save) {  /*** SAVE ***/
+    fwrite(header, 5, 1, file);
+    fputs(opts.font, file);
+    fputc('\n', file);
+    fputs(opts.theme, file);
+    fputc('\n', file);
+    fputs(opts.alarm_cmd, file);
+    fputc('\n', file);
+    fwrite(&pid, sizeof(pid), 1, file);
+    fwrite(&state.state_bits, sizeof(state.state_bits), 1, file);
+    fwrite(&state.counter, sizeof(state.counter), 1, file);
+    fwrite(ndata, sizeof(data_t), notes_count, file);
+    fclose(file);
+
+    strcpy(s, t);
+    strcat(s, ext);
+    if (rename(s, t) == -1) {
+      fprintf(stderr, "Fatal error: Failed to rename file `%s' to `%s'.\n", t,
+        s);
+      exit(EXIT_FAILURE);
+    }
+  } else {  /*** LOAD ***/
+    int rev;
+
+    if (!fread(s, 5, 1, file) || strncmp(s, header, 4)) {  /* check header */
+      fprintf(stderr, "Fatal error: Corrupt data file encountered.\n"
+        "Delete `~%s' to start over.\n", rc_file_name);
+      fclose(file);
+      exit(EXIT_FAILURE);
+    }
+    /* file format revision check */
+    s[5] = '\0';
+    rev = strtol(&s[4], 0, 10);
+    if (rev > 6) {
+      fprintf(stderr, "Fatal error: The data file seems to have been created "
+        "by a more recent version\nof wmpinboard.  Try and find a newer "
+        "release, or remove `~%s'\nand lose all existing notes.\n",
+        rc_file_name);
+      fclose(file);
+      exit(EXIT_FAILURE);
+    }
+
+    fgets(opts.font, sizeof(opts.font), file);
+    if (strlen(opts.font) && opts.font[strlen(opts.font)-1] == '\n')
+      opts.font[strlen(opts.font)-1] = '\0';
+
+    if (rev >= 4) {
+      fgets(opts.theme, sizeof(opts.theme), file);
+      if (strlen(opts.theme) && opts.theme[strlen(opts.theme)-1] == '\n')
+        opts.theme[strlen(opts.theme)-1] = '\0';
+    }
+    if (rev >= 6) {
+      fgets(opts.alarm_cmd, sizeof(opts.alarm_cmd), file);
+      if (strlen(opts.alarm_cmd) && opts.alarm_cmd[strlen(opts.alarm_cmd)-1] ==
+        '\n')
+      {
+        opts.alarm_cmd[strlen(opts.alarm_cmd)-1] = '\0';
+      }
+    }
+    if (rev >= 3) fread(&pid, sizeof(pid), 1, file);  /* last writer's PID */
+    if (rev >= 2)  /* state.state_bits */
+      fread(&state.state_bits, sizeof(state.state_bits), 1, file);
+    else
+      state.state_bits = 0;
+    if (rev >= 5) /* counter */
+      fread(&state.counter, sizeof(state.counter), 1, file);
+    else
+      state.counter = 0;
+
+    notes_count = 0;
+    while (notes_count < MAX_NOTES)
+      if (fread(&ndata[notes_count], sizes[rev], 1, file)) {
+        switch (rev) {
+          case 0:
+            ndata[notes_count].cursor = 0;
+            memset(ndata[notes_count].sketch, 0, 512);
+          case 1:
+            memset(ndata[notes_count].creases, 0, 32);
+          case 2:
+          case 3:
+          case 4:
+          case 5:
+            ndata[notes_count].a_time = -1;
+            ndata[notes_count].a_flags = ALARM_DATE;
+          default:
+            notes_count++;
+        }
+      } else break;
+    if (!state.counter) state.counter = notes_count;
+    fclose(file);
+    state.alarm.time = -1;
+    state.alarm.note = -1;
+    time_next_alarm();
+  }
+
+  s_unblock();
+  return pid;
+}
+
+/*
+ * loads theme from <filename>
+ */
+void
+load_theme(const char *filename)
+{
+#ifdef LOW_COLOR
+  if (strlen(filename))
+    WARN("Skipped loading the configured theme since themes aren't\nsupported"
+      "at low color depths.");
+#else
+  int coords[4], eof = 0, i;
+  char s[STRING_BUF_SIZE], *t, *p, *q;
+  struct stat buf;
+  FILE *file;
+
+  if (!strlen(filename)) return;
+  file = fopen(filename, "r");
+  if (!file) {
+    WARN("Failed to open theme file; check whether the location you specified\n"
+      "is valid.  Reverting to default.");
+    return;
+  }
+  if (!fgets(s, sizeof(s), file) || strncmp(s, "WMPBtheme", 9)) {
+    fclose(file);
+    WARN("Configured theme file is corrupted!  Reverting to default.");
+    return;
+  }
+
+  /* we'll need at most <file size> bytes to buffer the XPM data read from it */
+  lstat(filename, &buf);
+  if (!(t = malloc(buf.st_size))) {
+    fclose(file);
+    WARN("Skipped loading configured theme due to memory shortage.");
+    return;
+  }
+
+  /* parse theme headers... */
+  if (s[strlen(s)-1] == '\n') s[strlen(s)-1] = '\0';
+  memset(s, ' ', 9);  /* kludge */
+  do {
+    if ((p = strchr(s, '#'))) *p = '\0';  /* # comments */
+    p = s;
+    while (*p) {
+      for (; *p == ' ' || *p == '\t'; p++);
+      for (q = p; isalpha(*q); q++);
+      if (q > p) {
+        if (!strncasecmp(p, "label", q-p)) {
+          for (p = q; *p == ' ' || *p == '\t'; p++);
+          if (*p == '=') {
+            for (p++; *p == ' ' || *p == '\t'; p++);
+            for (i = 0; *p && i < 4; i++) {
+              coords[i] = (int) strtol(p, &p, 10);
+              for (; *p && (*p < '0' || *p > '9'); p++);
+            }
+            q = p;
+            if (i >= 4)
+              if (
+                coords[0] < 0 || coords[0] > 51 ||
+                coords[2] < 0 || coords[2] > 51 ||
+                coords[1] < 0 || coords[1] > 59 ||
+                coords[3] < 0 || coords[3] > 59 ||
+                coords[0] >= coords[2] || coords[1] >= coords[3])
+              {
+                WARN("Theme header `label' followed by coordinates outside the"
+                  "\nallowed range--ignored.");
+              } else {
+                if ((coords[2]-coords[0])*(coords[3]-coords[1]) >= 16)
+                  memcpy(&label_coords, &coords, sizeof(coords));
+                else
+                  WARN("Label Label area defined by the configured theme's "
+                    "headers is too small--ignored.");
+              }
+            else
+              WARN("Theme header `label' followed by improper specification--"
+                "ignored.");
+          } else {
+            WARN("Theme header `label' lacks specification.");
+            q = p;
+          }
+        } else
+          fprintf(stderr, "Warning: Invalid header field in theme: `%s'.\n", p);
+      }
+      for (p = q; *p && *p != ' ' && *p != '\t'; p++);
+    }
+    eof = !fgets(s, sizeof(s), file);
+    if (strlen(s) && s[strlen(s)-1] == '\n') s[strlen(s)-1] = '\0';
+  } while (!eof && strlen(s));
+
+  /* now read all pixmap data sections from the remainder of the file... */
+  while (!eof) {
+    Pixmap pic;
+    XpmAttributes attr;
+
+    attr.valuemask = XpmExactColors | XpmCloseness;
+    attr.exactColors = False;
+    attr.closeness = 65536;
+    for (p = t; !(eof = !fgets(s, sizeof(s), file)) && strlen(s) && *s != '\n';)
+    {
+      strcpy(p, s);
+      p += strlen(s);
+    }
+    if (!strstr(t, "char")) continue;  /* silently ignore garbage */
+    if (XpmCreatePixmapFromBuffer(display, RootWindow(display,
+      DefaultScreen(display)), t, &pic, 0, &attr) == XpmSuccess)
+    {
+      if (attr.width == 52 && attr.height == 60)  /* board pixmap */
+        XGetSubImage(display, pic, 0, 0, 52, 60, ~0, ZPixmap, img, 6, 2);
+      else if (attr.width == 58 && attr.height == 30)  /* bbar pixmap */
+        XCopyArea(display, pic, bbar, normalGC, 0, 0, 58, 30, 0, 0);
+      else if (attr.width == 58 && attr.height == 28)  /* abar pixmap */
+        XCopyArea(display, pic, abar, normalGC, 0, 0, 58, 28, 0, 0);
+      else if (attr.width == 60 && attr.height == 9)  /* abar digits */
+        XCopyArea(display, pic, digits, normalGC, 0, 0, 60, 9, 0, 0);
+      else /* invalid pixmap */
+        WARN("Configured theme contains pixmap of invalid dimensions--"
+          "ignored.");
+      XFreePixmap(display, pic);
+    } else
+      WARN("Encountered invalid pixmap data in configured theme--ignored.");
+  }
+  free(t);
+#endif
+}
+
+/*
+ * tries to exit properly
+ */
+void
+done(void)
+{
+  if (normalGC) XFreeGC(display, normalGC);
+  if (fontGC) XFreeGC(display, fontGC);
+  if (fillGC) XFreeGC(display, fillGC);
+#ifdef CREASES
+  if (creaseGC) XFreeGC(display, creaseGC);
+#endif
+  if (font) XFreeFont(display, font);
+  if (app != None) XFreePixmap(display, app);
+  if (bbar != None) XFreePixmap(display, bbar);
+  if (abar != None) XFreePixmap(display, abar);
+  if (digits != None) XFreePixmap(display, digits);
+  if (state.alarm.buffer != None) XFreePixmap(display, state.alarm.buffer);
+  if (img) XDestroyImage(img);
+  XCloseDisplay(display);
+  if (opts.display) free(opts.display);
+}
+
+/*
+ * handler for caught signals
+ */
+void
+handle_sigs(int sig)
+{
+  /* note: the kludges below will result in the application being terminated
+     if the applet was destroyed via the respective WM option but not yet
+     terminated (apparently WM just destroys the window in this case) */
+  XWindowAttributes attr;
+  const char *s = 0;
+
+  s_block();
+
+  switch (sig) {
+    case SIGALRM:  /* used in animation timing */
+      state.alarmed = 1;
+      break;
+    case SIGUSR1:
+      XGetWindowAttributes(display, win, &attr);  /* kludge */
+      /* quit edit mode w/saving; if not in edit mode, just save */
+      if (state.mode == M_MOVE) set_mode(M_NOOP);
+      if (state.mode != M_NOOP)
+        quit_edit_mode(0, 1);  /* saves */
+      else
+        notes_io(1);
+      break;
+    case SIGUSR2:
+      XGetWindowAttributes(display, win, &attr);  /* kludge */
+      /* quit edit mode w/o saving... */
+      if (state.mode != M_NOOP && state.mode != M_MOVE) quit_edit_mode(0, 0);
+      notes_io(0);  /* reread data */
+      notes_io(1);  /* rewrite data file */
+      render_pinboard(-1);
+      redraw_window();
+      break;
+    case SIGINT:
+      s = "SIGINT";
+    case SIGTERM:
+      if (!s) s = "SIGTERM";
+      fprintf(stderr, "Caught %s.  Trying to exit cleanly...\n", s);
+      if (state.mode != M_NOOP) {
+        if (note_empty(state.cur_note)) remove_note(state.cur_note);
+        notes_io(1);
+      }
+      exit(EXIT_SUCCESS);
+  }
+
+  s_unblock();
+}
+
+/*
+ * initializes the application's X window, installs a signal handler
+ */
+void
+init(void)
+{
+  struct sigaction sigact;
+  XWMHints wmhints;
+  XSizeHints shints;
+  Atom atom;
+  XTextProperty name;
+  XGCValues gcv;
+  unsigned long gcm;
+  int screen;
+
+  /* set up syncsig_set */
+  sigemptyset(&sync_sig_set);
+  sigaddset(&sync_sig_set, SIGUSR1);
+  sigaddset(&sync_sig_set, SIGUSR2);
+  /* install signal handler */
+  sigact.sa_handler = handle_sigs;
+  sigemptyset(&sigact.sa_mask);
+  sigact.sa_flags = 0;
+  if (sigaction(SIGALRM, &sigact, 0) < 0 ||
+    sigaction(SIGUSR1, &sigact, 0) < 0 ||
+    sigaction(SIGUSR2, &sigact, 0) < 0 ||
+    sigaction(SIGINT, &sigact, 0) < 0 ||
+    sigaction(SIGTERM, &sigact, 0) < 0)
+  {
+    die("Unable to install signal handlers.");
+  }
+
+  if (!(display = XOpenDisplay(opts.display))) {
+    fprintf(stderr, "Fatal error: Can't open display `%s'.\n", 
+      XDisplayName(opts.display));
+    exit(EXIT_FAILURE);
+  }
+
+  /* try to set up done() to be called upon exit() */
+  if (atexit(done)) die("Failed to set up exit procedure.");
+
+  screen = DefaultScreen(display);
+
+  atom = XInternAtom(display, "WM_DELETE_WINDOW", 0);
+  if (atom == None) die("No window manager running.");
+
+  /* try to autodetect whether we're running Window Maker... */
+  if (opts.window_state < 0)  /* no window state explicitly specified */
+    opts.window_state = XInternAtom(display, "_WINDOWMAKER_WM_FUNCTION", 1) !=
+      None ? WithdrawnState : NormalState;
+
+  mainwin = create_win();
+  wmhints.window_group = mainwin;
+  wmhints.initial_state = opts.window_state;
+  wmhints.flags = StateHint | WindowGroupHint | IconWindowHint;
+  if (opts.animate) wmhints.flags |= XUrgencyHint;  /* of any use at all? */
+  if (opts.window_state == WithdrawnState) {
+    iconwin = create_win();
+    wmhints.icon_window = iconwin;
+    win = iconwin;
+  } else {
+    wmhints.icon_window = None;
+    win = mainwin;
+  }
+  XSetWMHints(display, mainwin, &wmhints);
+  XSetWMProtocols(display, mainwin, &atom, 1);
+
+  shints.min_width = 64;
+  shints.min_height = 64;
+  shints.max_width = 64;
+  shints.max_height = 64;
+  shints.x = 0;
+  shints.y = 0;
+  shints.flags = PMinSize | PMaxSize | USPosition;
+  XSetWMNormalHints(display, mainwin, &shints);
+
+  XSelectInput(display, win, ButtonPressMask | ExposureMask |
+    ButtonReleaseMask | PointerMotionMask | StructureNotifyMask |
+    KeyPressMask | EnterWindowMask | LeaveWindowMask | FocusChangeMask);
+  if (!XStringListToTextProperty(&opts.name, 1, &name))
+    die("Can't allocate window name.");
+  XSetWMName(display, mainwin, &name);
+
+  set_mask(1);
+  app = get_xpm((char**) pinboard_xpm);
+  XMapSubwindows(display, win);
+
+  gcm = GCForeground | GCBackground | GCGraphicsExposures;
+  gcv.foreground = WhitePixel(display, screen);
+  gcv.background = BlackPixel(display, screen);
+  gcv.graphics_exposures = 0;
+  normalGC = XCreateGC(display, RootWindow(display, screen), gcm, &gcv);
+}
+
+/*
+ * tries to load font name, dies upon an error if <fatal> is true
+ */
+int
+try_font(const char *name, int fatal)
+{
+  if (font) return 1;
+  if (!name || !*name) return 0;
+  font = XLoadQueryFont(display, name);
+  if (font) {
+    if (font->max_bounds.rbearing - font->min_bounds.lbearing > 7 ||
+      font->max_bounds.ascent + font->max_bounds.descent > 10)
+    {
+      fprintf(stderr, "Warning: The font `%s'\n"
+        "lacks a fixed character cell size of 6x10.\n", name);
+      XFreeFont(display, font);
+      font = 0;
+    } else {
+      if (!notes_count)
+        strncpy(opts.font, name, sizeof(opts.font));
+      return 1;
+    }
+  } else
+    fprintf(stderr, "Warning: The font `%s' doesn't exist.\n", name);
+  if (fatal)
+    die("No alternatives left, aborting.");
+  else
+    fprintf(stderr, "Trying to revert...\n");
+  return 0;
+}
+
+/*
+ * loads the font to be used
+ */
+void
+load_font(void)
+{
+  XGCValues gcv;
+  unsigned long gcm;
+
+  try_font(opts.font, 0);
+  try_font(default_font, 1);
+
+  gcm = GCForeground | GCBackground | GCFillStyle | GCLineStyle | GCFont |
+    GCGraphicsExposures;
+  gcv.foreground = C_OUTER;
+  gcv.background = C_INNER;
+  gcv.font = font->fid;
+  gcv.fill_style = FillSolid;
+  gcv.line_style = LineSolid;
+  gcv.graphics_exposures = 0;
+  fontGC = XCreateGC(display, app, gcm, &gcv);
+#ifdef CREASES
+  gcm ^= GCBackground | GCFont;
+  creaseGC = XCreateGC(display, app, gcm, &gcv);
+#endif
+}
+
+/*
+ * (un)sets the keyboard input focus to wmpinboard's window
+ */  
+void 
+set_kbfocus(int get_it)
+{
+  if (get_it)
+    XSetInputFocus(display, win, RevertToPointerRoot, CurrentTime);
+  else if (!opts.click_to_focus)
+    XSetInputFocus(display, PointerRoot, RevertToNone, CurrentTime);
+}
+
+/*
+ * takes an action as specified by <type> (for command-line options affection
+ * notes rather than interactive behavior)
+ */
+void
+action(actions type, const void *data)
+{
+  const char *s;
+  int pid, running;
+  int i, j, k;
+  FILE *file;
+
+  pid = notes_io(0);
+  running = flush_instance(pid);
+  if (running) pid = notes_io(0);
+  switch (type) {
+    case C_FONT:
+      if (running) die("Can't change font while another instance is running.");
+      if (notes_count) die("Can't change font if the pinboard isn't empty.");
+      for (i = 0; i < NUM_FONTS; i++)
+        if (!strcasecmp(data, fonts[i].name)) {
+          strcpy(opts.font, fonts[i].font);
+          break;
+        }
+      if (i >= NUM_FONTS) {  /* not a predefined font */
+        if (strlen(data) >= sizeof(opts.font)) {
+          /* avoid trouble when retrieving saved data... */
+          fprintf(stderr, "Fatal error: Specified font descriptor exceeds "
+            "buffer size of %d bytes.\n", sizeof(opts.font));
+          exit(EXIT_FAILURE);
+        }
+        strcpy(opts.font, data);
+      }
+      notes_io(1);
+      fprintf(stderr, "Successfully changed the font.\n");
+      break;
+    case C_THEME:
+      if (running) die("Can't change theme while another instance is running.");
+      if (!strlen(data) || !strcasecmp(data, "default")) {
+        opts.theme[0] = '\0';
+        fprintf(stderr, "Reverted to default theme.\n");
+      } else {
+        if (strlen(data) >= sizeof(opts.theme)) {
+          fprintf(stderr, "Fatal error: Specified theme file location exceeds "
+            "buffer size of %d bytes.\n", sizeof(opts.theme));
+          exit(EXIT_FAILURE);
+        }
+        strcpy(opts.theme, data);
+        if (!(file = fopen(opts.theme, "r")))
+          WARN("Can't open specified theme file.");
+        else
+          fclose(file);
+        fprintf(stderr, "Successfully configured for specified theme.\n");
+      }
+      notes_io(1);
+      break;
+    case C_ALARM_CMD:
+      if (!strlen(data)) {
+        opts.alarm_cmd[0] = '\0';
+        fprintf(stderr, "Disabled alarm command.\n");
+      } else {
+        if (strlen(data) >= sizeof(opts.alarm_cmd)) {
+          fprintf(stderr, "Fatal error: Specified theme file location exceeds "
+            "buffer size of %d bytes.\n", sizeof(opts.alarm_cmd));
+          exit(EXIT_FAILURE);
+        }
+        strcpy(opts.alarm_cmd, data);
+        fprintf(stderr, "Successfully configured specified alarm command.\n");
+      }
+      notes_io(1);
+      if (running) {
+        kill(pid, SIGUSR2);
+        sleep(1);  /* don't return to the prompt too quickly... */
+      }
+      break;
+    case A_DUMP:
+      dump_notes(1);
+      break;
+    case A_DUMP_RAW:
+      dump_notes(0);
+      break;
+#ifdef CREASES
+    case A_IRON:
+      for (i = 0; i < notes_count; memset(ndata[i++].creases, 0, 32));
+      notes_io(1);
+      if (running) {
+        kill(pid, SIGUSR2);
+        sleep(1);  /* don't return to the prompt too quickly... */
+      }
+      fprintf(stderr,
+        "Hey, ironing isn't part of my job contract, you know...\n");
+      break;
+#endif
+    case A_DEL:
+      i = (int) strtol((const char*) data, 0, 10);
+      if (i < 0 || i >= notes_count) die("Specified note doesn't exist.");
+      remove_note(i);
+      notes_io(1);
+      if (running) { 
+        kill(pid, SIGUSR2);
+        sleep(1);  /* don't return to the prompt too quickly... */
+      }
+      fprintf(stderr, "Deleted note #%d.\n", i);
+      break;
+    case A_ADD: case A_ADD_RAW:
+      if ((k = add_note()) < 0) die("Maximal number of notes reached.");
+      s = (const char*) data;
+      while (*s == '%') {
+        if (!strncmp("%%", s, 2))
+          s++;
+        else if (strlen(s) >= 2 && *s == '%') {  /* color/position code given */
+          if (isalpha(s[1])) {  /* color code? */
+            i = 0;
+            switch (toupper(s[1])) {
+              case 'G':  i = 0; break;
+              case 'Y':  i = 1; break;
+              case 'R':  i = 2; break;
+              case 'B':  i = 3; break;
+              default: die("Unknown color code.");
+            }
+            while (c_group[ndata[k].col] != i) ndata[k].col = rand() % C_NUM;
+          }
+          if (!isalpha(s[1])) {  /* position code? */
+            i = s[1] - '0';
+            if (!i--) die("Invalid position code.");
+            ndata[k].x = 6+i%3*12 + rand()%12;
+            ndata[k].y = 3+(2-i/3)*14 + rand()%14;
+          }
+          s += 2;
+        }
+      }
+      if (!strlen(s)) die("Won't add blank note.");
+      i = paste_string(k, 0, s, type == A_ADD_RAW);
+      ndata[k].cursor = i > 58 ? 58 : i;
+      notes_io(1);
+      if (running) { 
+        kill(pid, SIGUSR2);
+        sleep(1);  /* don't return to the prompt too quickly... */
+      }
+      fprintf(stderr, "Added note #%d.\n", k);
+      break;
+    case A_EXPORT:
+      k = strtol((const char*) data, 0, 10);
+      if (k < 0 || k > notes_count-1) die("Specified note doesn't exist.");
+      puts("static const char sketch[512] = {");
+      for (i = 0; i < 64; i++) {
+        printf("  ");
+        for (j = 0; j < 8; j++) {
+          if (j) printf(", ");
+          printf("0x%02x", (unsigned char) ndata[k].sketch[i*8+j]);
+        }
+        if (i < 63) printf(",");
+        printf("\n");
+      }
+      puts("};");
+      break;
+    case M_INFO:
+      for (i = 0, k = 0; i < notes_count; i++)
+        if (ndata[i].a_flags & ALARM_ON) k++;
+      printf("user configuration:\n"
+        "  - font: %s\n"
+        "  - theme: %s\n"
+        "  - alarm command: %s\n",
+        strlen(opts.font) ? opts.font : fonts[0].font,
+        strlen(opts.theme) ? opts.theme : "[default]",
+        strlen(opts.alarm_cmd) ? opts.alarm_cmd : "[none]");
+      printf("\nuseless statistics:\n"
+        "  - wmpinboard has saved you (at least) %d real note%s so far\n"
+        "  - there %s currently %d note%s on your board\n"
+        "  - %d note%s\n",
+        state.counter, (state.counter != 1 ? "s" : ""),
+        (notes_count != 1 ? "are" : "is"), notes_count,
+        (notes_count != 1 ? "s" : ""), k,
+        (k != 1 ? "s have alarms set" : " has an alarm set"));
+  }
+  exit(EXIT_SUCCESS);
+}
+
+/*
+ * prints a help screen and exits
+ */
+void
+help(void)
+{
+  int i;
+
+  printf("wmpinboard v" VERSION "\n\n"
+    "Copyright (C) 1998-2000 by Marco G\"otze, <mailto:gomar at mindless.com>.\n"
+    "This program is distributed under the terms of the GNU GPL2.\n\n"
+    "usage: %s [options]\n\n"
+    "configuration directives (see the documentation for detailed information):\n"
+    "           --font=FONT        use the specified font; FONT can be one of the\n"
+    "                              following:\n",
+    opts.name);
+  for (i = 0; i < NUM_FONTS; i++)
+    printf("                                %-8s  %s\n", fonts[i].name, fonts[i].desc);
+  printf(
+    "                              or a complete X descriptor of a fixed size 6x10\n"
+    "                              font\n"
+    "           --theme=FILE       use the specified theme rather than the default\n"
+    "                              board/panel images (\"default\" or zero-length\n"
+    "                              string reverts to default)\n"
+    "           --alarm-cmd=CMD    execute the specified command on alarms\n"
+    "                              (\"\" disables)\n\n"
+    "run-time options:\n"
+    "  -d DISP, --display=DISP     use the specified X display\n"
+    "  -n,      --normal-state     force NormalState (AS Wharf)   \\ mutually\n"
+    "  -w,      --withdrawn-state  force WithdrawnState (WM dock) / exclusive\n"
+    "  -t TIME, --timeout=TIME     set edit mode timeout to TIME seconds\n"
+    "                              (default %ds, 0 disables)\n"
+    "  -c,      --click-to-focus   emulate click-based keyboard focus\n"
+    "           --light            no animations\n\n"
+    "command-line actions:\n"
+    "           --dump             dump the contents of all notes\n"
+    "           --dump-raw         dump the *raw* contents of all notes\n"
+    "           --del=NUMBER       delete note NUMBER (as identified by a dump)\n"
+    "           --add=STRING       add a note with STRING as its contents, trying\n"
+    "                              to word-wrap the text\n"
+    "           --add-raw=STRING   add a note with STRING as its *raw* contents\n\n"
+    "general options:\n"
+    "  -h,      --help             print this help\n"
+    "  -i,      --info             print user configuration and statistical\n"
+    "                              information\n"
+    "  -v,      --version          print some more detailed version information\n\n"
+    "See the wmpinboard(1) man page for more information, hints, and explanations.\n"
+    "For themes and updates, check out the program's home page at\n"
+    "<http://www.tu-ilmenau.de/~gomar/stuff/wmpinboard/>.\n",
+    TIMEOUT);
+  exit(EXIT_FAILURE);
+}
+
+/*
+ * parses the list of command line arguments and initializes the application's
+ * opts structure accordingly; handles non-interactive actions, and eventually
+ * reads in the data file if the instance is to be run in interactive mode
+ */
+void
+parse_argv(int argc, char **argv)
+{
+  static const struct option long_opts[] = {
+    { "font", required_argument, 0, 'f' },
+    { "theme", required_argument, 0, 'p' },
+    { "alarm-cmd", required_argument, 0, 'r' },
+
+    { "display", required_argument, 0, 'd' },
+    { "normal-state", no_argument, 0, 'n' },
+    { "withdrawn-state", no_argument, 0, 'w' },
+    { "time", required_argument, 0, 't' },
+    { "click-to-focus", no_argument, 0, 'c' },
+    { "light", no_argument, 0, 'l' },
+
+    { "dump", no_argument, 0, 'u' },
+    { "dump-raw", no_argument, 0, 'y' },
+    { "del", required_argument, 0, 'e' },
+    { "add", required_argument, 0, 'a' },
+    { "add-raw", required_argument, 0, 'b' },
+#ifdef CREASES
+    { "iron", no_argument, 0, 'z' },
+#endif
+    { "export-sketch", required_argument, 0, 'x' },
+
+    { "help", no_argument, 0, 'h' },
+    { "info", no_argument, 0, 'i' },
+    { "version", no_argument, 0, 'v' },
+    { 0, 0, 0, 0 }
+  };
+  static const char short_opts[] = "d:nwt:chiv";
+
+  if (rindex(argv[0], '/'))
+    opts.name = (char*) rindex(argv[0], '/') + 1;
+  else
+    opts.name = argv[0];
+
+  for(;;) {
+    int idx = 0, c;
+
+    if ((c = getopt_long(argc, argv, short_opts, long_opts, &idx)) == -1)
+      break;
+    switch (c) {
+      case 'f': action(C_FONT, optarg);
+      case 'p': action(C_THEME, optarg);
+      case 'r': action(C_ALARM_CMD, optarg);
+      case 'd':  /* display */
+        if (opts.display) free(opts.display);
+        opts.display = smalloc(strlen(optarg)+1);
+        strcpy(opts.display, optarg);
+        break;
+      case 'n':  /* NormalState */
+        opts.window_state = NormalState;
+        break;
+      case 'w':  /* WithdrawnState */
+        opts.window_state = WithdrawnState;
+        break;
+      case 't':  /* timeout */
+        opts.timeout = strtol(optarg, 0, 10);
+        if (opts.timeout < 0) opts.timeout = -opts.timeout;
+        break;
+      case 'c':  /* click-to-focus emulation */
+        opts.click_to_focus = 1;
+        break;
+      case 'l':  /* light (no animations) */
+        opts.animate = 0;
+        break;
+      case 'u': action(A_DUMP, 0);
+      case 'y': action(A_DUMP_RAW, 0);
+      case 'e': action(A_DEL, optarg);
+      case 'a': action(A_ADD, optarg);
+      case 'b': action(A_ADD_RAW, optarg);
+#ifdef CREASES
+      case 'z': action(A_IRON, 0);
+#endif
+      case 'x': action(A_EXPORT, optarg);
+      case 'h': help();
+      case 'i': action(M_INFO, 0);
+      case 'v':
+        printf("wmpinboard v" VERSION "\n\ncompile-time configuration:\n"
+          "  - maximal number of notes is %d\n"
+#if TIMEOUT == 0
+          "  - edit mode timeout is disabled by default\n"
+#else
+          "  - default edit mode timeout is %d seconds\n"
+#endif
+          "  - wear & tear of notes (creases) is "
+#ifdef CREASES
+          "enabled\n"
+#else
+          "disabled\n"
+#endif
+#ifndef FUNSTUFF
+          "  - FUNSTUFF is disabled  :-/\n"
+#endif
+          , MAX_NOTES
+#if TIMEOUT != 0
+          , TIMEOUT
+#endif
+          );
+        exit(EXIT_SUCCESS);
+      default : exit(EXIT_FAILURE);
+    }
+  }
+  if (optind < argc) help();  /* exits */
+  if (flush_instance(notes_io(0)))
+    die("Another interactive instance is running.");
+}
+
+/*
+ * draws a text cursor at character <pos> (block cursor if <block> is true)
+ * _without_ updating the display
+ */
+void
+draw_cursor(int pos, int block)
+{
+  unsigned long c = palette[ndata[state.cur_note].col].fg;
+  unsigned long d = palette[ndata[state.cur_note].col].bg;
+  int i, j;
+
+  XGetSubImage(display, app, 2+6*(pos%10), 2+10*(pos/10), 6, 10, ~0, ZPixmap,
+    img, 64, 54);
+  for (i = 64; i < 70; i++)
+    for (j = 63; j > (block ? 53 : 62); j--)
+      XPutPixel(img, i, j, XGetPixel(img, i, j) == c ? d : c);
+  XPutImage(display, app, normalGC, img, 64, 54, 2+6*(pos%10), 2+10*(pos/10),
+    6, 10);
+}
+
+/*
+ * in edit mode, moves the cursor to a new position and updates the display
+ * if <update> has a true value
+ */ 
+void  
+set_cursor(int new_pos, int update)
+{
+  int in_sel = 0;
+
+  if (new_pos > 58) return;
+  in_sel = (state.sel_from >= 0 && state.sel_to >= 0 &&
+    ((state.sel_from <= new_pos && new_pos < state.sel_to) ||
+    (state.sel_to <= new_pos && new_pos < state.sel_from)));
+  if (!in_sel || state.insert)
+    print_letter(state.cur_note, ndata[state.cur_note].cursor, 1);
+  draw_cursor(ndata[state.cur_note].cursor = new_pos, !in_sel && state.insert);
+  if (update) redraw_window();
+}
+
+/*
+ * selects text in the character range state.sel_from..<to>, previously
+ * unselecting that between state.sel_from..state.sel_to
+ */
+void
+sel_text(int to)
+{
+  int i, t;
+ 
+  if (to == state.sel_to) return;
+  if (state.sel_to >= 0) {
+    i = state.sel_from < state.sel_to ? state.sel_from : state.sel_to;
+    t = state.sel_from < state.sel_to ? state.sel_to : state.sel_from;
+    for (; i < t; i++) print_letter(state.cur_note, i, 1);
+  }
+  print_letter(state.cur_note, ndata[state.cur_note].cursor, 1);
+  i = state.sel_from < to ? state.sel_from : to;
+  t = state.sel_from < to ? to : state.sel_from;
+  for (; i < t; i++) draw_cursor(i, 1);
+  state.sel_to = to;
+  set_cursor(ndata[state.cur_note].cursor, 1);
+}
+
+/*
+ * clears the selection if in edit mode and text is selected
+ */
+void
+clear_selection()
+{
+  if (state.mode == M_EDIT && state.sel_from >= 0) {
+    state.sel_from = state.sel_to = -1;
+    init_edit_mode(state.cur_note);
+    set_cursor(ndata[state.cur_note].cursor, 1);
+  }
+}
+
+/*
+ * in sketch mode, draws a pixel at (x, y)
+ */
+void
+draw_pixel(int x, int y)
+{
+  if (!x || !y || x > 62 || y > 62 || x+y >= 115) return;
+  XDrawPoint(display, win, state.sketchGC, x, y);  /* actual drawing */
+  if (state.mode == M_DRAW)  /* save bits */
+    ndata[state.cur_note].sketch[x/8 + y*8] |= 1<<(x%8);
+  else
+    ndata[state.cur_note].sketch[x/8 + y*8] &= ~(1<<(x%8));
+}
+
+/*
+ * sets the internal mode indicator and installs a corresponding mouse cursor
+ */
+void
+set_mode(modes new)
+{
+  switch (state.mode = new) {
+    case M_MOVE:
+      XDefineCursor(display, win, cursors[state.cur_note >= 0 ? 0 : 1]);
+      break;
+    case M_DRAW: case M_ERAS:
+      XDefineCursor(display, win, cursors[2]);
+      break;
+    case M_EDIT:
+      state.selecting = 0;
+      state.sel_from = state.sel_to = -1;
+      if (!opts.click_to_focus) set_kbfocus(1);
+    default:
+      XUndefineCursor(display, win);
+  }
+}
+
+/*
+ * returns from M_EDIT, M_DRAW, M_ERAS, or M_BBAR to M_NOOP; destroys the
+ * current note if empty or <destroy> is true
+ */
+void
+quit_edit_mode(int destroy, int save)
+{
+  if (state.mode == M_BBAR) {
+    if (ndata[state.cur_note].a_flags & ALARM_ON) animate_abar(0);
+    animate_bbar(0);
+  }
+  if (destroy || (state.cur_note >= 0 && note_empty(state.cur_note))) {
+    remove_note(state.cur_note);
+    destroy = 1;
+  }
+  animate_note(destroy ? 6 : 5);
+  set_mode(M_NOOP);
+  if (save) notes_io(1);  /* should be last when called from signal handler */
+  time_next_alarm();
+}
+
+/*
+ * sets a timer expiring every <intv> microseconds
+ */
+void
+timer(unsigned int intv)
+{
+#ifndef __GLIBC__
+  struct itimerval val = { { 0, intv }, { 0, intv } };
+
+  setitimer(ITIMER_REAL, &val, 0);
+#else
+  ualarm(intv, intv);
+#endif
+}
+
+/*
+ * adds some eyecandy to the popping-up of the button bar (slides in if <in>
+ * is true, otherwise, out)
+ */
+void
+animate_bbar(int in)
+{
+  int y;
+
+  init_edit_mode(state.cur_note);
+  set_cursor(ndata[state.cur_note].cursor, 0);
+  if (in) {  /* slide in */
+    if (opts.animate) {
+      redraw_window();
+      timer(PANEL_ANI_INT);
+      for (y = 27; y >= 0; y -= 3) {
+        state.alarmed = 0;
+        XCopyArea(display, bbar, win, normalGC, 0, 0, 58, 30-y, 3, 34+y);
+        flush_expose();
+        while (!state.alarmed);
+      }
+      alarm(0);
+      XCopyArea(display, bbar, win, normalGC, 0, 0, 58, 30, 3, 31);
+      XCopyArea(display, app, win, normalGC, 3, 61, 58, 3, 3, 61);
+      flush_expose();
+      /* for future refreshes... */
+      XCopyArea(display, bbar, app, normalGC, 0, 0, 58, 30, 3, 31);
+    } else {  /* no animation */
+      XCopyArea(display, bbar, app, normalGC, 0, 0, 58, 30, 3, 31);
+      redraw_window();
+    }
+  } else {  /* slide out */
+    if (opts.animate) {
+      timer(PANEL_ANI_INT);
+      for (y = 31; y <= 58; y += 3) {
+        state.alarmed = 0;
+        XCopyArea(display, app, win, normalGC, 3, y, 58, 3, 3, y);
+        XCopyArea(display, bbar, win, normalGC, 0, 0, 58, 61-y, 3, y+3);
+        flush_expose();
+        while (!state.alarmed);
+      }
+      alarm(0);
+      XCopyArea(display, app, win, normalGC, 3, 61, 58, 3, 3, 61);
+      flush_expose();
+    } else  /* no animation */
+      redraw_window();
+  }
+}
+
+/*
+ * like animate_bbar, but for abar (to be called when bbar is already visible)
+ */
+void 
+animate_abar(int in)
+{
+  int y;
+
+  if (in) {  /* slide in */
+    explode_time(state.cur_note);
+    render_abar(state.cur_note);
+    if (opts.animate) {
+      redraw_window();
+      timer(PANEL_ANI_INT);
+      for (y = 28; y >= 3; y -= 3) {
+        state.alarmed = 0;
+        XCopyArea(display, abar, win, normalGC, 0, 0, 58, 31-y, 3, y);
+        flush_expose();
+        while (!state.alarmed);
+      }
+      alarm(0);
+      XCopyArea(display, abar, win, normalGC, 0, 0, 58, 28, 3, 4);
+      flush_expose();
+      /* for future refreshes... */
+      XCopyArea(display, abar, app, normalGC, 0, 0, 58, 28, 3, 4);
+    } else {  /* no animation */
+      XCopyArea(display, abar, app, normalGC, 0, 0, 58, 28, 3, 4);
+      redraw_window();
+    }
+  } else {  /* slide out */
+    implode_time(state.cur_note);
+    /* render app as note plus bbar */
+    init_edit_mode(state.cur_note);
+    set_cursor(ndata[state.cur_note].cursor, 0);
+    XCopyArea(display, win, app, normalGC, 3, 31, 58, 30, 3, 31);
+    if (opts.animate) {
+      timer(PANEL_ANI_INT);
+      for (y = 4; y <= 25; y += 3) {
+        state.alarmed = 0;
+        XCopyArea(display, app, win, normalGC, 3, y, 58, 3, 3, y);
+        XCopyArea(display, abar, win, normalGC, 0, 0, 58, 28-y, 3, y+3);
+        flush_expose();
+        while (!state.alarmed);
+      }
+      alarm(0);
+      XCopyArea(display, app, win, normalGC, 3, 28, 58, 3, 3, 28);
+      flush_expose();
+    } else  /* no animation */
+      redraw_window();
+  }
+}
+
+/*
+ * animates the switching between two notes (replaces what's currently
+ * being displayed by state.cur_note), in a way specified by <style>
+ *
+ *   0 = right -> left   2 = bottom -> top   4 = pinboard -> edit mode
+ *   1 = left -> right   3 = top -> bottom   5 = edit mode -> pinboard
+ *                                           6 = note destruction
+ */
+void
+animate_note(int style)
+{
+  static const int seq[10] = { 2, 3, 6, 9, 12, 12, 9, 6, 3, 2 };
+  XRectangle mask[5] = { { 6, 2, 52, 60 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
+    { 0, 0, 0, 0 }, { 0, 0, 0, 0 } };
+  int i, j;
+
+  if (!opts.animate) {  /* animations disabled */
+    if (style < 5) {  /* display note */
+      set_mask(0);
+      init_edit_mode(state.cur_note);
+      set_cursor(ndata[state.cur_note].cursor, 1);
+    } else {  /* display pinboard */
+      set_mask(1);
+      render_pinboard(-1);
+      redraw_window();
+    }
+    return;
+  }
+  switch (style) {
+    case 0:  /* slide right -> left */
+      init_edit_mode(state.cur_note);
+      set_cursor(ndata[state.cur_note].cursor, 0);
+      timer(NOTE_ANI_INT);
+      for (i = 2, j = 0; j < 10; i += seq[++j]) {
+        state.alarmed = 0;
+        XCopyArea(display, win, win, normalGC, seq[j], 0, 64-seq[j], 64, 0, 0);
+        XCopyArea(display, app, win, normalGC, i-seq[j], 0, seq[j], 64,
+          64-seq[j], 0);
+        flush_expose();
+        while (!state.alarmed);
+      }
+      break;
+    case 1:  /* slide left -> right */
+      init_edit_mode(state.cur_note);
+      set_cursor(ndata[state.cur_note].cursor, 0);
+      timer(NOTE_ANI_INT);
+      for (i = 2, j = 0; j < 10; i += seq[++j]) {
+        state.alarmed = 0;
+        XCopyArea(display, win, win, normalGC, 0, 0, 64-seq[j], 64, seq[j], 0);
+        XCopyArea(display, app, win, normalGC, 64-i, 0, seq[j], 64, 0, 0);
+        flush_expose();
+        while (!state.alarmed);
+      }
+      break;
+    case 2:  /* slide top -> bottom */
+      init_edit_mode(state.cur_note);
+      set_cursor(ndata[state.cur_note].cursor, 0);
+      timer(NOTE_ANI_INT);
+      for (i = 2, j = 0; j < 10; i += seq[++j]) {
+        state.alarmed = 0;
+        XCopyArea(display, win, win, normalGC, 0, 0, 64, 64-seq[j], 0, seq[j]);
+        XCopyArea(display, app, win, normalGC, 0, 64-i, 64, seq[j], 0, 0);
+        flush_expose();
+        while (!state.alarmed);
+      }
+      break;
+    case 3:  /* slide bottom -> top */
+      init_edit_mode(state.cur_note);
+      set_cursor(ndata[state.cur_note].cursor, 0);
+      timer(NOTE_ANI_INT);
+      for (i = 2, j = 0; j < 10; i += seq[++j]) {
+        state.alarmed = 0;
+        XCopyArea(display, win, win, normalGC, 0, seq[j], 64, 64-seq[j], 0, 0);
+        XCopyArea(display, app, win, normalGC, 0, i-seq[j], 64, seq[j], 0,
+          64-seq[j]);
+        flush_expose();
+        while (!state.alarmed);
+      }
+      break;
+    case 4:  /* pinboard view -> edit mode */
+      mask[1].x = mask[1].y = 0;
+      init_edit_mode(state.cur_note);
+      set_cursor(ndata[state.cur_note].cursor, 0);
+      timer(NOTE_ANI_INT);
+      for (i = 2, j = 0; j < 10; i += seq[++j]) {
+        state.alarmed = 0;
+        mask[1].width = mask[1].height = i;
+        XShapeCombineRectangles(display, win, ShapeBounding, 0, 0, mask, 2,
+          ShapeSet, 0);
+        XCopyArea(display, app, win, normalGC, 64-i, 64-i, i, i, 0, 0);
+        flush_expose();
+        while (!state.alarmed);
+      }
+      break;
+    case 5:  /* edit mode -> pinboard view */
+      render_pinboard(-1);
+      timer(NOTE_ANI_INT);
+      for (i = 2, j = 0; j < 10; i += seq[++j]) {
+        state.alarmed = 0;
+        mask[1].x = mask[1].y = i;
+        mask[1].width = mask[1].height = 64-i;
+        XCopyArea(display, win, win, normalGC, i-seq[j], i-seq[j], 64-i, 64-i,
+          i, i);
+        XCopyArea(display, app, win, normalGC, i-seq[j], i-seq[j], seq[j], 64,
+          i-seq[j], i-seq[j]);
+        XCopyArea(display, app, win, normalGC, i, i-seq[j], 64-i, seq[j],
+          i, i-seq[j]);
+        XShapeCombineRectangles(display, win, ShapeBounding, 0, 0, mask, 2,
+          ShapeSet, 0);
+        flush_expose();
+        while (!state.alarmed);
+      }
+      break;
+    case 6:  /* note destruction */
+      render_pinboard(-1);
+      timer((int) 1.5*NOTE_ANI_INT);
+      /* mask[1].x = mask[1].y = mask[2].y = mask[3].x = 0; */
+      for (i = 4; i <= 32; i += 4) {
+        state.alarmed = 0;
+        for (j = 1; j < 5; j++) mask[j].width = mask[j].height = 32-i;
+        mask[2].x = mask[3].y = mask[4].x = mask[4].y = 32+i;
+        XCopyArea(display, win, win, normalGC, 4, 4, 32-i, 32-i, 0, 0);
+        XCopyArea(display, win, win, normalGC, 28+i, 4, 32-i, 32-i, 32+i, 0);
+        XCopyArea(display, win, win, normalGC, 4, 28+i, 32-i, 32-i, 0, 32+i);
+        XCopyArea(display, win, win, normalGC, 28+i , 28+i, 32-i, 32-i, 32+i,
+          32+i);
+        XCopyArea(display, app, win, normalGC, 32-i, 0, 2*i, 64, 32-i, 0);
+        XCopyArea(display, app, win, normalGC, 0, 32-i, 64, 2*i, 0, 32-i);
+        XShapeCombineRectangles(display, win, ShapeBounding, 0, 0, mask, 5,
+          ShapeSet, 0);
+        flush_expose();
+        while (!state.alarmed);
+      }
+  }
+  alarm(0);
+}
+
+/*
+ * displays the next phase of the alarm animation (flashing)
+ */
+void
+animate_alarm()
+{
+  XCopyArea(display, state.alarm.buffer, win, normalGC,
+    state.alarm.phase*64, 0, 64, 64, 0, 0);
+  flush_expose();
+  state.alarm.phase = !state.alarm.phase;
+}
+
+/*
+ * called from main event loop whenever a ButtonPress event occurs
+ */
+void
+handle_ButtonPress(XEvent *event)
+{
+  int i;
+
+  if (state.button) return;
+  state.button = event->xbutton.button;
+  switch (state.mode) {
+    case M_NOOP:  /* drag a note? */
+      state.cur_note = selected_note(event->xbutton.x, event->xbutton.y);
+      if (state.cur_note >= 0) {  /* drag existing note */
+        state.dx = event->xbutton.x - ndata[state.cur_note].x;
+        state.dy = event->xbutton.y - ndata[state.cur_note].y;
+        state.moved = 0;
+        render_pinboard(state.cur_note);
+        XCopyArea(display, app, app, normalGC,
+          ndata[state.cur_note].x, ndata[state.cur_note].y, 16, 16, 64, 48);
+        color_notes(state.cur_note);
+        pin_note(state.cur_note);
+        redraw_window();  /* necessary in case of a single raising click */
+        state.mode = M_MOVE;  /* don't set drag cursor immediately */
+      } else if (
+        event->xbutton.x >= 6+label_coords[0] &&
+        event->xbutton.x <= 6+label_coords[2] &&
+        event->xbutton.y >= 2+label_coords[1] &&
+        event->xbutton.y <= 2+label_coords[3] &&
+        selected_note(event->xbutton.x, event->xbutton.y) < 0 &&
+        notes_count < MAX_NOTES-1)
+      {  /* possibly drag new note from "TO DO" label */
+        state.moved = 0;
+        set_mode(M_MOVE);
+      }
+      break;
+    case M_EDIT:  /* claim focus in click-based focus emulation mode */
+      if (!opts.click_to_focus || state.clicks_count) {
+        if (state.button != 2) {
+          if (state.lp_btn == state.button &&
+            event->xbutton.time-state.lp_time < DCLICK_LIMIT)
+          {
+            state.sel_from = i = char_at(event->xbutton.x, event->xbutton.y, 0);
+            for (; state.sel_from &&
+              ndata[state.cur_note].text[state.sel_from-1] != ' ' &&
+              (state.button != 1 || state.sel_from%10 > 0); state.sel_from--);
+            for (; i < 59 && ndata[state.cur_note].text[i] != ' ' &&
+              (state.button != 1 || state.sel_from/10 == (i+1)/10 || i%10);
+              i++);
+            sel_text(i);
+            cb_copy(&ndata[state.cur_note].text[state.sel_from], i - 
+              state.sel_from);
+          } else {
+            clear_selection();
+            state.sel_from = char_at(event->xbutton.x, event->xbutton.y, 0);
+            state.selecting = 1;
+          }
+        }
+      }
+      if (opts.click_to_focus && event->xbutton.x+event->xbutton.y < 115) {
+        if (!state.clicks_count) set_kbfocus(1);
+        state.clicks_count++;
+      }
+      break;
+    case M_BBAR:  /* remember which button was *pressed* */
+      state.bbar_pressed = state.abar_pressed = -1;
+      /* button pressed on bbar? */
+      i = bbar_button(event->xbutton.x, event->xbutton.y);
+      if (i >= 0) {  /* bbar button */
+        state.bbar_pressed = i;
+      } else if (ndata[state.cur_note].a_flags & ALARM_ON) {  /* abar? */
+        i = abar_area(event->xbutton.x, event->xbutton.y);
+		if (i >= 0) state.abar_pressed = i;
+      }
+      break;
+    case M_DRAW: case M_ERAS:  /* draw in either sketch mode */
+      if (state.button == 1) {
+        draw_pixel(event->xbutton.x, event->xbutton.y);
+#ifdef CREASES
+        if (state.mode == M_ERAS) {
+          render_edit_wear_area_win(win, state.cur_note, event->xbutton.x,
+            event->xbutton.y, 1, 1);
+        }
+#endif
+      }
+      break;
+    default:  /* keep the compiler happy */
+      break;
+  }
+  state.lp_btn = state.button;
+  state.lp_time = event->xbutton.time;
+}
+
+/*
+ * called from main event loop whenever a ButtonRelease event occurs
+ */
+void
+handle_ButtonRelease(XEvent *event)
+{
+  XGCValues gcv;
+  char *s;
+  int i;
+
+  if (event->xbutton.button != state.button) return;
+  switch (state.mode) {
+    case M_NOOP: case M_MOVE:  /* add new note or edit existing one? */
+      if (!state.moved && state.button == 1) {  /* left-click */
+        if (
+          event->xbutton.x >= 6+label_coords[0] &&
+          event->xbutton.x <= 6+label_coords[2] &&
+          event->xbutton.y >= 2+label_coords[1] &&
+          event->xbutton.y <= 2+label_coords[3] &&
+          selected_note(event->xbutton.x, event->xbutton.y) < 0)
+        { /* add new note */
+          if ((state.cur_note = add_note()) >= 0) {
+            animate_note(4);
+            set_kbfocus(1);
+            set_mode(M_EDIT);
+          } else  /* beep if maximum number of notes reached */
+            XBell(display, 0);
+        } else if (state.cur_note >= 0 && state.cur_note ==
+          selected_note(event->xbutton.x, event->xbutton.y))
+        { /* open existing note in edit mode */
+#ifdef CREASES
+          wear_note(state.cur_note);
+#endif
+          animate_note(4);
+          state.clicks_count = 0;
+          set_mode(M_EDIT);
+        }
+      } else {  /* moved */
+        if (state.cur_note >= 0) {
+          if (string_empty(ndata[state.cur_note].text, 0)) {  /* new note */
+            animate_note(4);
+            set_kbfocus(1);
+            set_mode(M_EDIT);
+          } else {  /* existing note dragged via either left or right MB */
+#ifdef CREASES
+            wear_note(state.cur_note);
+#endif
+            notes_io(1);
+            if (state.button == 1) {  /* keep level */
+              render_pinboard(-1);
+              redraw_window();
+            } else {  /* raise */
+              state.cur_note = raise_note(state.cur_note);
+#ifdef CREASES
+              pin_note(state.cur_note);
+              redraw_window();
+#endif
+            }
+            time_next_alarm();  /* note IDs may have changed */
+          }
+        }
+      }
+      if (state.mode != M_EDIT) set_mode(M_NOOP);
+      break;
+    case M_EDIT: case M_DRAW: case M_ERAS:
+      i = char_at(event->xbutton.x, event->xbutton.y, 0);
+      if (event->xbutton.x + event->xbutton.y >= 115 &&
+        (!state.selecting || state.sel_from == i))
+      {  /* clicked triangle? */
+        if (state.button > 1) {  /* open panel */
+          animate_bbar(1);
+          if (ndata[state.cur_note].a_flags & ALARM_ON) {
+            animate_abar(1);
+            check_time(state.cur_note);  /* adjusts hidden year field */
+          }
+          if (!opts.click_to_focus) set_kbfocus(0);
+          set_mode(M_BBAR);
+        } else {  /* end edit mode */
+          if (state.mode == M_DRAW || state.mode == M_ERAS) {
+            XFreeGC(display, state.sketchGC);  /* free temporary GC */
+            if (M_ERAS) {  /* restore normal note display first */
+              print_text(state.cur_note);
+              draw_sketch(state.cur_note);
+              set_cursor(ndata[state.cur_note].cursor, 1);
+            }
+            set_mode(M_EDIT);
+          }
+          quit_edit_mode(0, 1);
+          if (!opts.click_to_focus) set_kbfocus(0);
+        }
+      } else {
+        if (state.mode == M_EDIT) {
+          if (!opts.click_to_focus || state.clicks_count > 1) {
+            if (state.button == 2) {
+              ndata[state.cur_note].cursor = char_at(event->xbutton.x,
+                event->xbutton.y, 1);
+              state.raw_paste = 0;
+              cb_paste(state.cur_note, state.insert);
+              init_edit_mode(state.cur_note);
+              set_cursor(ndata[state.cur_note].cursor, 1);
+            } else if (state.selecting && state.sel_from != i) {
+              sel_text(i);
+              if (state.sel_from > state.sel_to) {
+                i = state.sel_from;
+                state.sel_from = state.sel_to;
+                state.sel_to = i;
+              }
+              if (state.button == 1) {  /* copy cooked */
+                s = cook(state.cur_note, state.sel_from, state.sel_to -
+                  state.sel_from);
+                cb_copy(s, -1);
+                free(s);
+              } else {  /* copy raw */
+                cb_copy(&ndata[state.cur_note].text[state.sel_from],
+                  state.sel_to - state.sel_from);
+              }
+            } else
+              set_cursor(char_at(event->xbutton.x, event->xbutton.y, 1), 1);
+          }
+        } else if (state.button > 1) {  /* revert from sketch to edit mode */
+          XFreeGC(display, state.sketchGC);
+          init_edit_mode(state.cur_note);
+          set_cursor(ndata[state.cur_note].cursor, 1);
+          set_mode(M_EDIT);
+        }
+      }
+      state.selecting = 0;
+      break;
+    case M_BBAR:  /* actions in panel mode */
+      if (state.bbar_pressed >= 0) {
+        if (state.bbar_pressed == bbar_button(event->xbutton.x,
+          event->xbutton.y))  /* clicked on panel? */
+        {
+          switch (state.bbar_pressed) {
+            case 0:  /* open/close alarm panel */
+              if (!(ndata[state.cur_note].a_flags & ALARM_ON)) {
+                /* open alarm panel, turn alarm on */
+                animate_abar(1);
+                ndata[state.cur_note].a_flags |= ALARM_ON;
+              } else {  /* close alarm panel, turn alarm off */
+                animate_abar(0);
+                ndata[state.cur_note].a_flags &= ~ALARM_ON;
+              }
+              break;
+            case 4:  /* change note color */
+              i = ndata[state.cur_note].col;
+              if (state.button > 1) {  /* previous color */
+                if (--ndata[state.cur_note].col < 0)
+                  ndata[state.cur_note].col = C_NUM-1;
+              } else  /* next color */
+                if (++ndata[state.cur_note].col == C_NUM)
+                  ndata[state.cur_note].col = 0;
+              init_edit_mode(state.cur_note);
+              set_cursor(ndata[state.cur_note].cursor, 0);
+              XCopyArea(display, bbar, app, normalGC, 0, 0, 58, 30, 3, 31);
+              if (ndata[state.cur_note].a_flags & ALARM_ON)
+                XCopyArea(display, abar, app, normalGC, 0, 0, 58, 28, 3, 4);
+              redraw_window();
+              break;
+            case 1: case 5:  /* enter draw/erase mode */
+              gcv.foreground = state.bbar_pressed == 1 ?
+                palette[ndata[state.cur_note].col].fg :
+                palette[ndata[state.cur_note].col].bg;
+              state.sketchGC = XCreateGC(display, app, GCForeground, &gcv);
+              if (ndata[state.cur_note].a_flags & ALARM_ON) animate_abar(0);
+              animate_bbar(0);
+              render_note(state.cur_note);
+#ifdef CREASES
+              render_edit_wear(state.cur_note);
+#endif
+              if (state.bbar_pressed == 1) {  /* erase: hide text */
+                print_text(state.cur_note);
+                set_cursor(ndata[state.cur_note].cursor, 0);
+              }
+              draw_sketch(state.cur_note);
+              redraw_window();
+              set_mode(state.bbar_pressed == 1 ? M_DRAW : M_ERAS);
+              break;
+            case 2:  /* clear note's text */
+              memset(ndata[state.cur_note].text, 32, 59);
+#ifdef CREASES
+              wear_note(state.cur_note);
+              wear_note(state.cur_note);
+#endif
+              if (ndata[state.cur_note].a_flags & ALARM_ON) animate_abar(0);
+              animate_bbar(0);
+              init_edit_mode(state.cur_note);
+              set_cursor(0, 1);
+              set_mode(M_EDIT);
+              break;
+            case 6:  /* clear sketch */
+              memset(ndata[state.cur_note].sketch, 0, 511);  /* not last byte */
+#ifdef CREASES
+              wear_note(state.cur_note);
+              wear_note(state.cur_note);
+#endif
+              if (ndata[state.cur_note].a_flags & ALARM_ON) animate_abar(0);
+              animate_bbar(0);
+              init_edit_mode(state.cur_note);
+              set_cursor(ndata[state.cur_note].cursor, 1);
+              set_mode(M_EDIT);
+              break;
+            case 3:  /* remove note */
+              quit_edit_mode(1, 1);
+              if (!opts.click_to_focus) set_kbfocus(0);
+              break;
+            case 7:  /* close button bar */
+              if (ndata[state.cur_note].a_flags & ALARM_ON) animate_abar(0);
+              animate_bbar(0);
+              set_mode(M_EDIT);
+          }
+        }
+      } else if (state.abar_pressed >= 0) {
+        if (state.abar_pressed == abar_area(event->xbutton.x,
+          event->xbutton.y))  /* clicked on panel? */
+        {
+          if (state.abar_pressed < 4) {  /* clicked on number */
+            char c = state.a_edit[state.abar_pressed];
+            char delta = state.button == 1 ? 1 : -1;
+
+            switch (state.abar_pressed) {
+              case 0:  c = (24+c+delta)%24;  break;
+              case 1:  c = (60+c+delta)%60;  break;
+              case 2:  c = (11+c+delta)%12+1;  break;
+              case 3:  c = (30+c+delta)%31+1;
+            }
+            state.a_edit[state.abar_pressed] = c;
+            /* check validity of date, adapt month or day if necessary */
+            while (!check_time())
+              if (state.abar_pressed == 2) {  /* month was changed */
+                if (state.a_edit[3] > 1)
+                  state.a_edit[3]--;
+                else
+                  break;  /* just making sure */
+              } else {  /* presumably, the day was changed */
+                state.a_edit[3] = 1;
+                break;
+              }
+            /* update display */
+            render_abar_number(state.abar_pressed);
+            /* always update day in case the date had to be corrected */
+            if (state.abar_pressed != 3) render_abar_number(3);
+          } else {  /* clicked on switch */
+            if (state.abar_pressed == 4)  /* daily alarm */
+              ndata[state.cur_note].a_flags &= ~ALARM_DATE;
+            else  /* specific date */
+              ndata[state.cur_note].a_flags |= ALARM_DATE;
+            check_time(state.cur_note);  /* updates the hidden year field */
+            render_abar_switches(state.cur_note);
+          }
+          /* update display */
+          XCopyArea(display, abar, app, normalGC, 0, 0, 58, 28, 3, 4);
+          XCopyArea(display, abar, win, normalGC, 0, 0, 58, 28, 3, 4);
+        }
+      }
+      break;
+    case M_ALRM:
+      if (ndata[state.cur_note].a_flags & ALARM_DATE)
+        ndata[state.cur_note].a_flags &= ~ALARM_ON;
+      notes_io(1);
+      init_edit_mode(state.cur_note);
+      set_cursor(ndata[state.cur_note].cursor, 1);
+      redraw_window();
+      set_mode(M_EDIT);
+      time(&state.idle);
+  }
+  state.button = 0;
+}
+
+/*
+ * called from main event loop whenever a MotionNotify event occurs
+ */
+void
+handle_MotionNotify(XEvent *event)
+{
+  int i, j;
+
+  switch (state.mode) {
+    case M_MOVE:  /* note's being dragged, update position */
+      if (state.cur_note >= 0) {  /* update note that's being moved's pos. */
+        /* the drag cursor isn't set immediately... */
+        if (!state.moved) {
+          set_mode(M_MOVE);
+          state.moved = 1;
+        }
+        i = ndata[state.cur_note].x;
+        j = ndata[state.cur_note].y;
+        ndata[state.cur_note].x = event->xbutton.x - state.dx;
+        ndata[state.cur_note].x = ndata[state.cur_note].x < 6 ? 6 :
+          ndata[state.cur_note].x;
+        ndata[state.cur_note].x = ndata[state.cur_note].x > 42 ? 42 :
+          ndata[state.cur_note].x;
+        ndata[state.cur_note].y = event->xbutton.y - state.dy;
+        ndata[state.cur_note].y = ndata[state.cur_note].y < 2 ? 2 :
+          ndata[state.cur_note].y;
+        ndata[state.cur_note].y = ndata[state.cur_note].y > 46 ? 46 :
+          ndata[state.cur_note].y;
+        XCopyArea(display, app, app, normalGC, 64, 48, 16, 16, i, j);
+        XCopyArea(display, app, app, normalGC, ndata[state.cur_note].x,
+          ndata[state.cur_note].y, 16, 16, 64, 48);
+        pin_note(state.cur_note);
+        redraw_window();
+        time(&state.idle);
+      } else {  /* create note by dragging it "off" the "TO DO" label */
+        state.cur_note = add_note();
+        ndata[state.cur_note].x = event->xbutton.x-8;
+        ndata[state.cur_note].y = event->xbutton.y < 8 ? 0 :
+          event->xbutton.y-8;
+        state.dx = 8;
+        state.dy = event->xbutton.y - ndata[state.cur_note].y;
+        state.moved = 0;
+        XCopyArea(display, app, app, normalGC,
+          ndata[state.cur_note].x, ndata[state.cur_note].y, 16, 16, 64, 48);
+        color_notes(state.cur_note);
+        set_mode(M_MOVE);  /* update cursor */
+        pin_note(state.cur_note);
+        redraw_window();
+        time(&state.idle);
+      }
+      break;
+    case M_DRAW: case M_ERAS:  /* draw in either sketch mode */
+      if (state.button == 1) {
+        draw_pixel(event->xbutton.x, event->xbutton.y);
+        if (state.mode == M_ERAS) {  /* enlarge the cursor a bit when erasing */
+          draw_pixel(event->xbutton.x-1, event->xbutton.y);
+          draw_pixel(event->xbutton.x+1, event->xbutton.y);
+          draw_pixel(event->xbutton.x, event->xbutton.y-1);
+          draw_pixel(event->xbutton.x, event->xbutton.y+1);
+#ifdef CREASES
+          render_edit_wear_area_win(win, state.cur_note, event->xbutton.x-1,
+            event->xbutton.y, 3, 1);
+          render_edit_wear_area_win(win, state.cur_note, event->xbutton.x,
+            event->xbutton.y-1, 1, 3);
+#endif
+        }
+        time(&state.idle);
+      }
+      break;
+    case M_EDIT:
+      if (state.selecting) {
+        sel_text(char_at(event->xbutton.x, event->xbutton.y, 0));
+        time(&state.idle);
+      }
+      break;
+    default:  /* keep the compilter happy */
+      break;
+  }
+}
+
+/*
+ * called from main event loop whenever a KeyPress event occurs
+ */
+void
+handle_KeyPress(XEvent *event)
+{
+  KeySym ksym;
+  unsigned char ch[4];
+  char *s;
+  int i, j = 0;
+
+  if (state.mode != M_EDIT || event->xkey.state & 0xdfe8 ||
+    (InputContext && XFilterEvent(event, win)))
+  {
+    XSendEvent(display, RootWindow(display, DefaultScreen(display)), True,
+      KeyPressMask, event);
+    if (state.mode == M_EDIT) set_kbfocus(1);  /* make sure we keep focus */
+    return;
+  }
+  time(&state.idle);
+
+  clear_selection();
+  if (event->xkey.state & ControlMask) { /* [Ctrl]-anything -> special fn.s */
+    /* InputContext intentionally ignored here... */
+    XLookupString(&event->xkey, (char*) ch, sizeof(ch), &ksym, &state.compose);
+    switch (ksym) {
+      case XK_c: case XK_C:  /* copy cooked */
+        state.sel_from = 0;
+        sel_text(59);
+        s = cook(state.cur_note, 0, 59);
+        cb_copy(s, -1);
+        free(s);
+        return;
+      case XK_r: case XK_R:  /* copy raw */
+        state.sel_from = 0;
+        sel_text(59);
+        cb_copy(ndata[state.cur_note].text, -1);
+        return;
+      case XK_i: case XK_I:  /* paste raw */
+        state.raw_paste = 1;
+        cb_paste(state.cur_note, state.insert);
+        init_edit_mode(state.cur_note);
+        set_cursor(ndata[state.cur_note].cursor, 1);
+        return;
+      case XK_y: case XK_Y: case XK_z: case XK_Z:  /* zap line */
+        for (i = 10*(ndata[state.cur_note].cursor/10); i < 59; i++)
+          ndata[state.cur_note].text[i] =
+            i < 49 ? ndata[state.cur_note].text[i+10] : ' ';
+        init_edit_mode(state.cur_note);
+        set_cursor(10*(ndata[state.cur_note].cursor/10), 1);
+        return;
+      case XK_n: case XK_N:  /* EMACS-style down */
+        ksym = XK_Down;
+        break;
+      case XK_p: case XK_P:  /* EMACS-style up */
+        ksym = XK_Up;
+        break;
+      case XK_f: case XK_F:  /* EMACS-style right */
+        ksym = XK_Right;
+        break;
+      case XK_b: case XK_B:  /* EMACS-style left */
+        ksym = XK_Left;
+        break;
+      default:
+        return;
+    }
+  } else {
+    if (InputContext) {
+      j = XmbLookupString(InputContext, &event->xkey, (char*) ch, sizeof(ch),
+        &ksym, 0);
+    } else {
+      j = XLookupString(&event->xkey, (char*) ch, sizeof(ch), &ksym,
+        &state.compose);
+    }
+    if (!j && (ksym & 0xff00) == 0x0600) {  /* cyrillic keysyms */
+      ch[0] = (unsigned char) (ksym & 0x00ff);
+      ch[1] = '\0';
+      if (ch[0] >= 0xbf || ch[0] == 0xa3 || ch[0] == 0xb3)
+        j = 1;  /* filter extended KOI8 characters */
+    }
+  }
+  switch (ksym) {
+    case XK_Return: case XK_KP_Enter:
+      if (ndata[state.cur_note].cursor >= 50) break;
+      if (state.insert) {
+        shift_string(state.cur_note, 10*(ndata[state.cur_note].cursor/10+1), 58,
+          ndata[state.cur_note].cursor%10, ' ');
+        shift_string(state.cur_note, ndata[state.cur_note].cursor, 58,
+          10-ndata[state.cur_note].cursor%10, ' ');
+      }
+      set_cursor(10*(ndata[state.cur_note].cursor/10+1), 1);
+      break;
+    case XK_BackSpace: case 0xfd1a:
+      if (!ndata[state.cur_note].cursor) break;
+      if (ndata[state.cur_note].cursor == 58 &&
+        ndata[state.cur_note].text[58] != ' ')
+      { /* special behavior when on very last character */
+        ndata[state.cur_note].text[58] = ' ';
+        set_cursor(ndata[state.cur_note].cursor, 1);
+        break;
+      }
+      print_letter(state.cur_note, ndata[state.cur_note].cursor--, 1);
+    case XK_Delete: case XK_KP_Delete:
+      j = 1;  /* delete entire line if empty... */
+      if (((ksym != XK_BackSpace && ksym != 0xfd1a) ||
+        ndata[state.cur_note].cursor%10 == 9) &&
+        string_empty(&ndata[state.cur_note].text[10*
+          (ndata[state.cur_note].cursor/10)], 10))
+      {
+        ndata[state.cur_note].cursor = 10*(ndata[state.cur_note].cursor/10);
+        j = 10;
+      }
+      if (ksym == XK_BackSpace || ksym == 0xfd1a) {
+        if (ndata[state.cur_note].cursor%10 == 9 &&
+          ndata[state.cur_note].text[ndata[state.cur_note].cursor] == ' ')
+        {
+          for (; ndata[state.cur_note].text[ndata[state.cur_note].cursor-1] ==
+            ' ' && ndata[state.cur_note].cursor >
+            10*(ndata[state.cur_note].cursor/10);)
+          {
+            ndata[state.cur_note].text[ndata[state.cur_note].cursor--] = ' ';
+          }
+        }
+      }
+        
+      for (i = ndata[state.cur_note].cursor; i < (j == 1 &&
+        ndata[state.cur_note].cursor/10 < 5 ?
+        10*(ndata[state.cur_note].cursor/10+1)-j : 59-j); i++)
+      {
+        ndata[state.cur_note].text[i] = ndata[state.cur_note].text[i+j];
+        ndata[state.cur_note].text[i+j] = ' ';
+        print_letter(state.cur_note, i, 1);
+      }
+      if (ndata[state.cur_note].cursor%10 == 9 ||
+        ndata[state.cur_note].cursor == 58)
+      { /* exceptions to the loop */
+        ndata[state.cur_note].text[ndata[state.cur_note].cursor] = ' ';
+      }
+      if (j > 1)  /* only when lines have been shifted */
+        init_edit_mode(state.cur_note);
+      else
+        print_letter(state.cur_note, i, 1);
+      set_cursor(ndata[state.cur_note].cursor, 1);
+      break;
+    case XK_Up: case XK_KP_Up:
+      if ((event->xkey.state & 0x01) == 0x01) {  /* next note w/similar color */
+        for (i = state.cur_note == notes_count-1 ? 0 : state.cur_note+1;
+           i != state.cur_note;)
+        {
+           if (c_group[ndata[i].col] == c_group[ndata[state.cur_note].col])
+             break;
+           if (++i >= notes_count) i = 0;
+        }
+        if (i == state.cur_note) break;
+        if (note_empty(state.cur_note)) remove_note(state.cur_note);
+        notes_io(1);
+        state.cur_note = i;
+        animate_note(2);
+      } else  /* move ndata[state.cur_note].cursor */
+        if (ndata[state.cur_note].cursor > 9)
+          set_cursor(ndata[state.cur_note].cursor-10, 1);
+      break;
+    case XK_Down: case XK_KP_Down:
+      if ((event->xkey.state & 0x01) == 0x01) {  /* prev. note w/simil. color */
+        for (i = state.cur_note ? state.cur_note-1 : notes_count-1;
+          i != state.cur_note;)
+        {
+           if (c_group[ndata[i].col] == c_group[ndata[state.cur_note].col])
+             break;
+           if (--i < 0) i = notes_count-1;
+        }
+        if (i == state.cur_note) break;
+        if (note_empty(state.cur_note)) remove_note(state.cur_note);
+        notes_io(1);
+        state.cur_note = i;
+        animate_note(3);
+      } else  /* move ndata[state.cur_note].cursor */
+        if (ndata[state.cur_note].cursor < 49)
+          set_cursor(ndata[state.cur_note].cursor+10, 1);
+      break;
+    case XK_Left: case XK_KP_Left:
+      if ((event->xkey.state & 0x01) == 0x01) {  /* previous note */
+        if (notes_count == 1) break;
+        if (note_empty(state.cur_note)) remove_note(state.cur_note);
+        notes_io(1);
+        if (--state.cur_note < 0) state.cur_note = notes_count-1;
+        animate_note(1);
+      } else  /* move cursor */
+        if (ndata[state.cur_note].cursor)
+          set_cursor(ndata[state.cur_note].cursor-1, 1);
+      break;
+    case XK_Right: case XK_KP_Right:
+      if ((event->xkey.state & 0x01) == 0x01) {  /* next note */
+        if (notes_count == 1) break;
+        if (note_empty(state.cur_note)) {
+          remove_note(state.cur_note);
+          state.cur_note = notes_count-1;
+        }
+        notes_io(1);
+        if (++state.cur_note == notes_count) state.cur_note = 0;
+        animate_note(0);
+      } else  /* move cursor */
+        if (ndata[state.cur_note].cursor < 58)
+          set_cursor(ndata[state.cur_note].cursor+1, 1);
+      break;
+    case XK_Tab: case XK_ISO_Left_Tab: /* change color */
+      i = ndata[state.cur_note].col;
+      if ((ksym == XK_Tab && (event->xkey.state & 0x01) == 0x01) ||
+        ksym == XK_ISO_Left_Tab)
+      {  /* previous color */
+        if (--ndata[state.cur_note].col < 0)
+          ndata[state.cur_note].col = C_NUM-1;
+      } else  if (++ndata[state.cur_note].col == C_NUM)
+        ndata[state.cur_note].col = 0;
+      init_edit_mode(state.cur_note);
+      set_cursor(ndata[state.cur_note].cursor, 0);
+      redraw_window();
+      break;
+    case XK_Home: case XK_KP_Home:
+      set_cursor(10*(ndata[state.cur_note].cursor/10), 1);
+      break;
+    case XK_End: case XK_KP_End:
+      i = j = ndata[state.cur_note].cursor < 50 ?
+        10*(ndata[state.cur_note].cursor/10)+9 : 58;
+      if (ndata[state.cur_note].text[j] == ' ')
+        for (; i > 10*(j/10) && ndata[state.cur_note].text[i-1] == ' '; i--);
+      set_cursor(i, 1);
+      break;
+    case XK_Prior: case XK_KP_Prior:  /* page up */
+      set_cursor(0, 1);
+      break;
+    case XK_Next: case XK_KP_Next:  /* page down */
+      set_cursor(58, 1);
+      break;
+    case XK_Insert: case XK_KP_Insert:
+      state.insert = !state.insert;
+      set_cursor(ndata[state.cur_note].cursor, 1);
+      break;
+    case XK_Escape:
+      quit_edit_mode(0, 1);
+      if (!opts.click_to_focus) set_kbfocus(0);
+      break;
+    default:
+      if (j) {
+        if (state.insert)
+          shift_string(state.cur_note, ndata[state.cur_note].cursor,
+            ndata[state.cur_note].cursor < 50 ?
+            10*(ndata[state.cur_note].cursor/10)+9 : 58, 1, ch[0]);
+        else {
+          ndata[state.cur_note].text[ndata[state.cur_note].cursor] = ch[0];
+          print_letter(state.cur_note, ndata[state.cur_note].cursor, 1);
+        }
+        set_cursor(ndata[state.cur_note].cursor < 58 ?
+          ndata[state.cur_note].cursor+1 : ndata[state.cur_note].cursor, 1);
+      }
+  }
+}
+                                   /********/
+/*********************************** MAIN ************************************/
+                                 /********/
+int
+main(int argc, char **argv)
+{
+#ifdef FUNSTUFF
+  time_t tt = 0, t;
+  struct tm ltt, lt;
+#endif
+  XEvent event;
+  XGCValues gcv;
+  int i, j;
+
+  srand(time(0));
+  umask(077);  /* users' notes needn't be world-readable */
+
+  parse_argv(argc, argv);  /* evaluate command line parameters */
+  init();                  /* initialize X window */
+  XSetCommand(display, mainwin, argv, argc);
+  XMapWindow(display, mainwin);
+  init_xlocale();          /* initialize input context */
+
+  /* initialize internal images, palette, cursors */
+  bbar = get_xpm((char**) bbar_xpm);
+  abar = get_xpm((char**) abar_xpm);
+  digits = get_xpm((char**) digits_xpm);
+  img = XGetImage(display, app, 0, 0, 86, 64, ~0, ZPixmap);
+  XGetSubImage(display, abar, 47, 4, 8, 8, ~0, ZPixmap, img, 70, 55);
+  XGetSubImage(display, abar, 47, 16, 8, 8, ~0, ZPixmap, img, 78, 55);
+  for (i = 0; i < C_NUM; i++) {
+    palette[i].bg = XGetPixel(img, 80, i);
+    palette[i].fg = XGetPixel(img, 81, i);
+    palette[i].cr = XGetPixel(img, 82, i);
+  }
+  palette[C_NUM].fg = XGetPixel(img, 80, 63);  /* C_INNER */
+  palette[C_NUM].bg = XGetPixel(img, 81, 63);  /* C_OUTER */
+  palette[C_NUM].cr = XGetPixel(img, 82, 63);  /* C_EXTRA */
+  gcv.foreground = C_OUTER;  /* dummy value */
+  gcv.graphics_exposures = 0;
+  fillGC = XCreateGC(display, app, GCForeground | GCGraphicsExposures, &gcv);
+  cursors[0] = XCreateFontCursor(display, XC_fleur);  /* when moving a note */
+  cursors[1] = XCreateFontCursor(display, XC_dotbox);  /* drag-create */
+  cursors[2] = XCreateFontCursor(display, XC_pencil);  /* for sketch mode */
+
+  load_font();
+  load_theme(opts.theme);
+  notes_io(1);  /* saves PID */
+  render_pinboard(-1);
+  redraw_window();
+  set_mode(M_NOOP);
+
+  for(;;) {  /*** MAIN EVENT LOOP ***/
+    while (XPending(display)) {
+      XNextEvent(display, &event);
+
+      s_block();  /* BEGIN OF SYNC-PROHIBITING SECTION */
+
+      switch (event.type) {
+        case Expose:
+          redraw_window();
+          break;
+        case ButtonPress:
+          handle_ButtonPress(&event);
+          time(&state.idle);
+          break;
+        case ButtonRelease:
+          if (event.xbutton.button == state.button)
+            handle_ButtonRelease(&event);
+          time(&state.idle);
+          break;
+        case MotionNotify:
+          handle_MotionNotify(&event);
+          break;
+        case EnterNotify:
+          if (state.mode == M_EDIT && !opts.click_to_focus) set_kbfocus(1);
+          state.clicks_count = 0;
+          break;
+        case LeaveNotify:
+          if (state.mode == M_EDIT && !opts.click_to_focus) set_kbfocus(0);
+          break;
+        case KeyPress:
+          handle_KeyPress(&event);
+          break;
+        case SelectionClear:
+          clear_selection();
+          cb_clear();
+          break;
+        case SelectionNotify:
+          if (state.mode == M_EDIT) {
+            cb_paste_external(event.xselection.requestor,
+              event.xselection.property, 1, state.cur_note, state.insert,
+              state.raw_paste);
+            init_edit_mode(state.cur_note);
+            set_cursor(ndata[state.cur_note].cursor, 1);
+          }
+          break;
+        case SelectionRequest:
+          handle_SelectionRequest(&(event.xselectionrequest));
+      }
+    }
+    if (opts.timeout && (state.mode == M_EDIT || state.mode == M_BBAR ||
+      state.mode == M_DRAW || state.mode == M_ERAS) &&
+      time(0)-state.idle > opts.timeout)
+    {
+      quit_edit_mode(0, 1);  /* no set_kbfocus(0) here */
+    }
+#ifdef FUNSTUFF
+    if (state.mode == M_NOOP) {
+      time(&t);
+      if (t-tt > 10*60 && localtime_r(&tt, &ltt) && localtime_r(&t, &lt)) {
+        if (ltt.tm_mday != lt.tm_mday || ltt.tm_mon != lt.tm_mon ||
+          ltt.tm_year != lt.tm_year)
+        {
+          i = notes_count;
+          j = state.state_bits;
+          check_occasion(lt.tm_mday, 1+lt.tm_mon, 1900+lt.tm_year);
+          if (i != notes_count || j != state.state_bits) {  /* anything done? */
+            notes_io(1);
+            render_pinboard(-1);
+            redraw_window();
+          }
+        }
+        tt = t;
+      }
+    }
+#endif
+    if (state.mode == M_ALRM)
+      animate_alarm();
+    else if (state.mode == M_NOOP && state.alarm.note >= 0 &&
+      state.alarm.time <= time(0))
+    {  /* alarm due */
+      state.cur_note = state.alarm.note;
+      state.alarm.run = 1;
+      if (ndata[state.cur_note].a_flags & ALARM_DATE)
+        ndata[state.cur_note].a_flags &= ~ALARM_ON;
+      animate_note(4);
+      set_mode(M_ALRM);
+      if (strlen(opts.alarm_cmd)) {
+        char buf[STRING_BUF_SIZE+2];
+        strcpy(buf, opts.alarm_cmd);
+        strcat(buf, " &");
+        system(buf);
+      }
+      prepare_alarm_anim();
+      state.alarm.phase = 0;
+      animate_alarm();
+    }
+
+    s_unblock();  /* END OF SYNC-PROHIBITING SECTION */
+
+    /* sleep for a while... */
+    switch (state.mode) {
+      case M_NOOP: usleep(100000L); break;
+      case M_ALRM: usleep(500000L); break;  /* animation timing, 0.5s */
+      default:     usleep( 10000L);
+    }
+  }
+}
+
+/*
+                            CONCEPTUAL NOTES
+
+                                                      bbar =
+                                  show panel        +---------+
+ mainwin[, iconwin]        ,------------------------|::panel::| 30
+      (each) =             |       app =            |:::::::::|
+    +----------+           |  +----------+--+       +---------+
+    |          |           `->|          |::|           58     \
+    | visible  |    display   |   draw   |::| 48              dto. for abar
+ 64 |   area   | <=========== |  buffer  |::|
+    |          |     64x64    |          +-++
+    |          |          ,-->|         <->|| 16
+    +----------+          |   +----------+-++
+         64               |        64    16\3
+                          |                 \ used when
+                          |                 moving a note     server-side
+  ........................|...............................................
+                          |
+              restore     |                                   client-side
+            ,----------->-+
+            |  board      |    draw
+     img =  |   16        +-<--------[bitfield]
+    +----------+-++  pin  |   sketch
+    |::::::::::| |------>-+
+    |:copy:of::| || notes |
+ 64 |:pristine:| ||       |
+    |:pinboard:+++|  copy |
+    |:::::::10{||---<--->-'
+    +----------++-+ character/write it back
+         64    6\16
+                /\                                            :: = const
+               /  \ used to overlay a
+              / character with the cursor
+             /
+    buffer of (8+8)x8 @ 70,55 for alarm panel switches
+*/
+
diff --git a/src/wmpinboard.h b/src/wmpinboard.h
new file mode 100644
index 0000000..f9f81b3
--- /dev/null
+++ b/src/wmpinboard.h
@@ -0,0 +1,143 @@
+/*
+ *  Copyright (C) 1998-2000 by Marco G"otze.
+ *
+ *  This code is part of the wmpinboard source package, which is
+ *  distributed under the terms of the GNU GPL2.
+ */
+
+#ifndef WMPINBOARD_H_INCLUDED
+#define WMPINBOARD_H_INCLUDED
+
+#include <time.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MAX_NOTES 20  /* maximal number of notes */
+
+#define STRING_BUF_SIZE 128  /* size of buffers for font descr. & suchlike */
+
+#define C_NUM 20                   /* number of colors */
+#define C_INNER palette[C_NUM].fg  /* mask color (interior of notes etc.) */
+#define C_OUTER palette[C_NUM].bg  /* mask color (exterior of notes etc.) */
+#define C_EXTRA palette[C_NUM].cr  /* additional mask color */
+
+/* program modes with respect to interactive behavior... */
+typedef enum {
+  M_NOOP,  /* "normal" mode (pinboard view) */
+  M_EDIT,  /* edit mode */
+  M_MOVE,  /* note being dragged (implies M_NOOP) */
+  M_BBAR,  /* button bar being displayed (implies M_EDIT) */
+  M_DRAW,  /* sketch mode, drawing (implies M_EDIT) */
+  M_ERAS,  /* sketch mode, erasing (implies M_EDIT) */
+  M_ALRM   /* alarm active */
+} modes;
+
+typedef enum {
+  /* command line actions */
+  A_DUMP,       /* "cooked" dump */
+  A_DUMP_RAW,   /* raw dump */
+  A_IRON,       /* "iron" notes */
+  A_DEL,        /* delete a now */
+  A_ADD,        /* add "cooked" */
+  A_ADD_RAW,    /* add raw */
+  A_EXPORT,     /* export sketch */
+  /* configuration options */
+  C_FONT,       /* change font */
+  C_THEME,      /* change board/panel pixmap */
+  C_ALARM_CMD,  /* change alarm command */
+  /* miscellani */
+  M_INFO        /* prints miscellanous information */
+} actions;
+
+#define PANEL_ANI_INT  2000L  /* usecs interval for panel animation */
+#define NOTE_ANI_INT  15000L  /* usecs interval for note animation */
+
+#define DCLICK_LIMIT 500  /* ms */
+
+#define FUNSTUFF
+
+typedef enum {
+  ALARM_ON   = 1<<0,
+  ALARM_DATE = 1<<1
+} alarm_flags_e;
+
+typedef struct {
+  int col;
+  int x, y;
+  char text[10*6];
+  int cursor;
+  char sketch[(64/8)*64];   /* bitfield; last byte used for other purposes... */
+  char creases[(16/8)*16];  /* lower-res bitfield representing creases */
+  time_t a_time;            /* alarm time */
+  unsigned char a_flags;    /* alarm flags */
+} data_t;
+
+typedef struct {
+  unsigned long fg, bg, cr;  /* foreground, background, crease color */
+} palette_t;
+
+typedef struct {  /* options and parameters */
+  char *name;          /* the program's file name (argv[0]) */
+  char *display;       /* alternate X display to connect to */
+  int click_to_focus;  /* true if keyboard focus requires a click */
+  int window_state;    /* NormalState, WithdrawnState? */
+  int timeout;         /* timeout value in seconds */
+  int animate;         /* use animations? */
+  char font[STRING_BUF_SIZE];       /* font descriptor to remember */
+  char theme[STRING_BUF_SIZE];      /* theme file to remember */
+  char alarm_cmd[STRING_BUF_SIZE];  /* alarm command */
+} opts_t;
+
+typedef struct {  /* program state information */
+  GC sketchGC;             /* temporary GC in sketch mode */
+  XComposeStatus compose;  /* keyboard compose status */
+  int clicks_count;        /* while emulating click-based focusing */
+  int cur_note;            /* note currently being processed */
+  int moved;               /* true if a note was *moved* (not just raised) */
+  int button, dx, dy;      /* mouse-related stuff */
+  modes mode;              /* program's current mode of operation */
+  int bbar_pressed;        /* *pressed* panel button */
+  int abar_pressed;        /* area on alarm panel that last received a click */
+  int insert;              /* insert state in edit mode? */
+  int selecting;           /* selection in progress? */
+  int sel_from, sel_to;    /* used when selecting text via the mouse */
+  int lp_btn;              /* button last pressed */
+  Time lp_time;            /* time the last button was *pressed* */
+  time_t idle;             /* for the timeout feature */
+  volatile int alarmed;    /* used in animation timing */
+  unsigned int state_bits; /* bit vector with special information */
+  int raw_paste;           /* next paste to be raw? */
+  int counter;             /* total number of notes ever created */
+  struct {
+    time_t time;           /* time_t of next alarm that's due */
+    int note;              /* note that alarm.time is set for */
+    int run;               /* true if the specified alarm was run */
+    int phase;             /* phase of the animation */
+    Pixmap buffer;         /* buffer for the animation phases */
+  } alarm;
+  unsigned char a_edit[5]; /* hour, minute, month, day, year being edited */
+} state_t;
+
+extern Display *display;
+extern Window win;
+extern XImage *img;
+extern Pixmap app, bbar, abar, digits;
+extern GC normalGC, fontGC, fillGC;
+#ifdef CREASES
+extern GC creaseGC;
+#endif
+extern XFontStruct *font;
+
+extern const char c_group[C_NUM];
+extern int notes_count;
+extern data_t ndata[MAX_NOTES];
+extern palette_t palette[C_NUM+1];
+extern state_t state;
+
+#endif  /* WMPINBOARD_H_INCLUDED */
+
diff --git a/src/xmisc.c b/src/xmisc.c
new file mode 100644
index 0000000..1eb217b
--- /dev/null
+++ b/src/xmisc.c
@@ -0,0 +1,434 @@
+/*
+ *  Copyright (C) 1998-2000 by Marco G"otze.
+ *
+ *  This code is part of the wmpinboard source package, which is
+ *  distributed under the terms of the GNU GPL2.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+
+#include <X11/X.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xlocale.h>
+#include <X11/Xmd.h>
+#include <X11/xpm.h>
+#include <X11/extensions/shape.h>
+
+#include "wmpinboard.h"
+#include "misc.h"
+#include "notes.h"
+#include "xmisc.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+typedef CARD32 Atom32;
+
+XIC InputContext = 0;
+static char *rs_inputMethod = 0;
+static char *rs_preeditType = 0;
+static unsigned char *cb_buffer = 0;
+
+/*
+ * replaces <o_col> by <n_col> in an XImage ([no]_col are XGetPixel return
+ * values!)
+ */
+void
+replace_color(XImage *img, int x, int y, int w, int h, unsigned long o_col,
+  unsigned long n_col)
+{
+  int i, j;
+
+  for (i = x; i < x+w; i++)
+    for (j = y; j < y+h; j++)
+      if (XGetPixel(img, i, j) == o_col)
+        XPutPixel(img, i, j, n_col);
+}
+
+/*
+ * puts <dest> on app, copying pixels only where <src>'s color is !=
+ * <mask_col>'s
+ */
+void
+merge_masked(XImage *src, int sx, int sy, int dx, int dy, int w, int h,
+  unsigned long mask_col)
+{
+  GC tempGC;
+  XGCValues gcv;
+  unsigned long p;
+  int i, j;
+
+  gcv.foreground = mask_col;  /* dummy value */
+  tempGC = XCreateGC(display, app, GCForeground, &gcv);
+  for (i = 0; i < w; i++)
+    for (j = 0; j < h; j++) {
+      p = XGetPixel(src, sx+i, sy+j);
+      if (p != mask_col) {
+        XSetForeground(display, tempGC, p);
+        XDrawPoint(display, app, tempGC, dx+i, dy+j);
+      }
+    }
+  XFreeGC(display, tempGC);
+}
+
+/*
+ * converts a pixmap structure to a Pixmap
+ */
+void
+get_xpm_with_mask(char *pixmap_bytes[], Pixmap *pic, Pixmap *mask)
+{
+  XpmAttributes attr;
+
+  attr.valuemask = XpmExactColors | XpmCloseness;
+  attr.exactColors = False;
+  attr.closeness = 65536;
+  if (XpmCreatePixmapFromData(display, RootWindow(display,
+    DefaultScreen(display)), pixmap_bytes, pic, mask, &attr) != XpmSuccess)
+  {
+    die("Not enough free color cells.");
+  }
+}
+
+/*
+ * calls get_xpm_with_mask() but returns just the pixmap
+ */
+Pixmap
+get_xpm(char *pixmap_bytes[])
+{
+  Pixmap pic, mask;
+  get_xpm_with_mask(pixmap_bytes, &pic, &mask);
+  return pic;
+}
+
+/*
+ * flushes Expose events
+ */
+void
+flush_expose(void)
+{
+  XEvent dummy;
+
+  while (XCheckTypedWindowEvent(display, win, Expose, &dummy));
+}
+
+/*
+ * redraws the application's window
+ */
+void
+redraw_window(void)
+{
+  flush_expose();
+  XCopyArea(display, app, win, normalGC, 0, 0, 64, 64, 0, 0);
+}
+
+/*
+ * sets either the app's shape mask for normal operation or reverts to none
+ * (edit mode)
+ */
+void
+set_mask(int set)
+{
+  static XRectangle none = { 0, 0, 64, 64 };
+  static XRectangle mask = { 6, 2, 52, 60 };
+
+  if (set)
+    XShapeCombineRectangles(display, win, ShapeBounding, 0, 0, &mask, 1,
+      ShapeSet, 0);
+  else
+    XShapeCombineRectangles(display, win, ShapeBounding, 0, 0, &none, 1,
+      ShapeSet, 0);
+}
+
+/*
+ * sets up XIC-orientated keyboard handling
+ * [stolen from the RXVT, minor adaptations]
+ */
+void
+init_xlocale(void)
+{
+  char *p, *s, buf[32], tmp[1024];
+  XIM xim = 0;
+  XIMStyle input_style = 0;
+  XIMStyles *xim_styles = 0;
+  int found;
+
+  InputContext = 0;
+  setlocale(LC_ALL, "");
+
+  if (!rs_inputMethod || !*rs_inputMethod) {
+    if ((p = XSetLocaleModifiers("@im=none")) && *p)
+      xim = XOpenIM(display, 0, 0, 0);
+  } else {
+    strcpy(tmp, rs_inputMethod);
+    for (s = tmp; *s;) {
+      char *end, *next_s;
+      
+      for (; *s && isspace(*s); s++);
+      if (!*s) break;
+      end = s;
+      for (; *end && (*end != ','); end++);
+      next_s = end--;
+      for (; (end >= s) && isspace(*end); end--);
+      *(end + 1) = '\0';
+      
+      if (*s) {
+        strcpy(buf, "@im=");
+        strcat(buf, s);
+        if ((p = XSetLocaleModifiers(buf)) && *p
+          && (xim = XOpenIM(display, 0, 0, 0)))
+        {
+          break;
+        }
+      }
+      if (!*next_s) break;
+      s = (next_s + 1);
+    }
+  }
+
+  if (!xim && (p = XSetLocaleModifiers("")) && *p)
+    xim = XOpenIM(display, 0, 0, 0);
+    
+  if (!xim) {
+#ifdef DEBUG_IC
+    fprintf(stderr, "Failed to open input method.\n");
+#endif
+    return;
+  }
+
+  if (XGetIMValues(xim, XNQueryInputStyle, &xim_styles, 0) || !xim_styles) {
+    XCloseIM(xim);
+#ifdef DEBUG_IC
+    fprintf(stderr, "Input method doesn't support any style.\n");
+#endif
+    return;
+  }
+
+  strcpy(tmp, (rs_preeditType ? rs_preeditType : "Root"));
+  for (found = 0, s = tmp; *s && !found;) {
+    unsigned short i;
+    char *end, *next_s;
+  
+    while (*s && isspace(*s)) s++;
+    if (!*s) break;
+    end = s;
+    while (*end && (*end != ',')) end++;
+    next_s = end--;
+    while ((end >= s) && isspace(*end)) *end-- = 0;
+  
+    if (!strcmp(s, "OverTheSpot"))
+      input_style = (XIMPreeditPosition | XIMStatusArea);
+    else if (!strcmp(s, "OffTheSpot"))
+      input_style = (XIMPreeditArea | XIMStatusArea);
+    else if (!strcmp(s, "Root"))
+      input_style = (XIMPreeditNothing | XIMStatusNothing);
+  
+    for (i = 0; i < xim_styles->count_styles; i++) {
+      if (input_style == xim_styles->supported_styles[i]) {
+        found = 1;
+         break;
+      }
+    }
+    s = next_s;
+  }
+  XFree(xim_styles);
+    
+  if (found == 0) {
+    XCloseIM(xim);
+#ifdef DEBUG_IC
+    fprintf(stderr, "Input method doesn't support my preedit type.\n");
+#endif
+    return;
+  }
+
+  if (input_style != (XIMPreeditNothing | XIMStatusNothing)) {
+    XCloseIM(xim);
+#ifdef DEBUG_IC
+    fprintf(stderr, "This program only supports the `Root' preedit type.\n");
+#endif
+    return;
+  }
+
+  InputContext = XCreateIC(xim, XNInputStyle, input_style,
+    XNClientWindow, win, XNFocusWindow, win, 0);
+
+  if (!InputContext) {
+    XCloseIM(xim);
+  }
+}
+
+/*
+ * creates a dock-app-tailored window
+ */
+Window
+create_win()
+{
+  Window win;
+  XClassHint hint;
+  XSetWindowAttributes attr;
+
+  win = XCreateSimpleWindow(display,
+    RootWindow(display, DefaultScreen(display)), 0, 0, 64, 64, 0, 0, 0);
+  hint.res_name = (char*) "wmpinboard";
+  hint.res_class = (char*) "WMPINBOARD";
+  XSetClassHint(display, win, &hint);
+  attr.background_pixmap = ParentRelative;
+  XChangeWindowAttributes(display, win, CWBackPixmap, &attr);
+  return win;
+}
+
+/*
+ * copies <text> to the X clipboard
+ */
+void
+cb_copy(const char *text, int len)
+{
+  int l;
+
+  if (!text) return;
+
+  if (cb_buffer) free(cb_buffer);
+  l = len < 0 ? strlen(text) : len;
+  cb_buffer = smalloc(l+1);
+  strncpy(cb_buffer, text, l);
+  cb_buffer[l] = 0;
+
+  XSetSelectionOwner(display, XA_PRIMARY, win, CurrentTime);
+  if (XGetSelectionOwner(display, XA_PRIMARY) != win)
+    WARN("Failed to set XA_PRIMARY ownership.");
+  XChangeProperty(display, DefaultRootWindow(display), XA_CUT_BUFFER0,
+    XA_STRING, 8, PropModeReplace, cb_buffer, l);
+}
+
+/*
+ * responds to a SelectionRequest event
+ * [once again, thanks to the RXVT source]
+ */
+void
+handle_SelectionRequest(XSelectionRequestEvent *rq)
+{
+  XEvent ev;
+  Atom32 target_list[2];
+  static Atom xa_targets = None;
+
+  if (xa_targets == None) xa_targets = XInternAtom(display, "TARGETS", 0);
+
+  ev.xselection.type = SelectionNotify;
+  ev.xselection.property = None;
+  ev.xselection.display = rq->display;
+  ev.xselection.requestor = rq->requestor;
+  ev.xselection.selection = rq->selection;
+  ev.xselection.target = rq->target;
+  ev.xselection.time = rq->time;
+
+  if (rq->target == xa_targets) {
+    target_list[0] = (Atom32) xa_targets;
+    target_list[1] = (Atom32) XA_STRING;
+    XChangeProperty(display, rq->requestor, rq->property, rq->target,
+      8*sizeof(target_list[0]), PropModeReplace,
+      (unsigned char*) target_list,
+      sizeof(target_list)/sizeof(target_list[0]));
+    ev.xselection.property = rq->property;
+  } else if (rq->target == XA_STRING) {
+    XChangeProperty(display, rq->requestor, rq->property, rq->target,
+      8, PropModeReplace, cb_buffer, strlen((char*) cb_buffer));
+      ev.xselection.property = rq->property;
+  }
+  XSendEvent(display, rq->requestor, 0, 0, &ev);
+}
+
+/*
+ * handle's the user's request to paste text into a note
+ */
+void
+cb_paste(int note, int ins)
+{
+  Atom prop;
+
+  if (cb_buffer) {
+    paste(note, ndata[note].cursor, (const char*) cb_buffer, ins,
+      state.raw_paste);
+  } else if (XGetSelectionOwner(display, XA_PRIMARY) == None) {
+    cb_paste_external(DefaultRootWindow(display), XA_CUT_BUFFER0, 0, note,
+      ins, state.raw_paste);
+  } else {
+    prop = XInternAtom(display, "VT_SELECTION", 0);
+    XConvertSelection(display, XA_PRIMARY, XA_STRING, prop, win, CurrentTime);
+  }
+}
+
+/*
+ * pastes the current contents of the clipboard into <note> at <pos>, inserting
+ * or overwriting depending on <ins>, trying to word-wrap unless <raw>; moves
+ * the cursor
+ */
+void
+cb_paste_external(Window window, unsigned prop, int Delete, int note, int ins,
+  int raw)
+{
+  unsigned long bytes_after, nitems;
+  unsigned char *data;
+  Atom actual_type;
+  int actual_fmt;
+
+  if (prop == None) return;
+  if ((XGetWindowProperty(display, window, prop, 0, 64, Delete,
+    AnyPropertyType, &actual_type, &actual_fmt, &nitems, &bytes_after,
+    &data) != Success))
+  {
+    XFree(data);
+    return;
+  }
+  if (nitems) paste(note, ndata[note].cursor, (const char*) data, ins, raw);
+  XFree(data);
+}
+
+/*
+ * frees the copy made of a selected string
+ */
+void
+cb_clear()
+{
+  if (cb_buffer) {
+    free(cb_buffer);
+    cb_buffer = 0;
+  }
+}
+
+/*
+ * prepares the buffer which portions are copied from during an alarm animation
+ */
+void
+prepare_alarm_anim()
+{
+  unsigned long wh = WhitePixel(display, DefaultScreen(display));
+  unsigned long bl = BlackPixel(display, DefaultScreen(display));
+  XImage *i;
+  int x, y;
+
+  if (state.alarm.buffer != None) XFreePixmap(display, state.alarm.buffer);
+  /* create buffer pixmap */
+  state.alarm.buffer = XCreatePixmap(display, win, 128, 64,
+    DefaultDepth(display, DefaultScreen(display)));
+  /* copy current edit view (note: strangely, if we copy from win and are
+     running WM and this happens during WM start-up (so the dock isn't
+     finished while executing this), wmpinboard gets terminated) */
+  XCopyArea(display, app, state.alarm.buffer, normalGC, 0, 0, 64, 64, 0, 0);
+  /* create inverted version */
+  i = XGetImage(display, state.alarm.buffer, 0, 0, 64, 64, ~0, ZPixmap);
+  for (y = 0; y < 64; y++)
+    for (x = 0; x < 64; x++)
+      XPutPixel(i, x, y,
+        XGetPixel(i, x, y) == palette[ndata[state.cur_note].col].fg ? wh : bl);
+  XPutImage(display, state.alarm.buffer, normalGC, i, 0, 0, 64, 0, 64, 64);
+  XDestroyImage(i);
+}
+
diff --git a/src/xmisc.h b/src/xmisc.h
new file mode 100644
index 0000000..dfd9a25
--- /dev/null
+++ b/src/xmisc.h
@@ -0,0 +1,35 @@
+/*
+ *  Copyright (C) 1998-2000 by Marco G"otze.
+ *
+ *  This code is part of the wmpinboard source package, which is
+ *  distributed under the terms of the GNU GPL2.
+ */
+
+#ifndef XMISC_H_INCLUDED
+#define XMISC_H_INCLUDED
+
+#include <X11/Xlib.h>
+
+#include "wmpinboard.h"
+
+void replace_color(XImage*, int, int, int, int, unsigned long, unsigned long);
+void merge_masked(XImage*, int, int, int, int, int, int, unsigned long);
+
+void get_xpm_with_mask(char**, Pixmap*, Pixmap*);
+Pixmap get_xpm(char**);
+void flush_expose(void);
+void redraw_window(void);
+void set_mask(int);
+void init_xlocale(void);
+Window create_win(void);
+void cb_copy(const char*, int);
+void handle_SelectionRequest(XSelectionRequestEvent *rq);
+void cb_paste(int, int);
+void cb_paste_external(Window, unsigned, int, int, int, int);
+void cb_clear(void);
+void prepare_alarm_anim();
+
+extern XIC InputContext;
+
+#endif  /* XMISC_H_INCLUDED */
+
diff --git a/themes-kit/HOWTO b/themes-kit/HOWTO
new file mode 100644
index 0000000..23139d0
--- /dev/null
+++ b/themes-kit/HOWTO
@@ -0,0 +1,95 @@
+
+                How to create a theme for wmpinboard v0.99.1+
+              ================================================
+
+ Overview
+----------
+
+wmpinboard is themeable in that its pinboard, edit mode and alarm 
+panels, and the digits used on the alarm panel, as well as the location 
+of the board's "TO DO" label (via which notes are created) are run-time 
+configurable using theme files.  A wmpinboard theme file is a text file 
+with a recommended file name extension of ".wmpbtheme".
+
+ Theme file format
+-------------------
+
+As stated above, a wmpinboard theme file is a text file in a specific 
+format.  Roughly, it consists of a header section and one or two pixmap 
+data sections:
+
+  WMPBtheme
+  [header fields]
+  # comments
+
+  [pixmap[s]]
+
+The various sections are separated by zero-length lines.
+
+Each theme file has to start with the keyword "WMPBtheme", designating 
+the file to be a wmpinboard theme file.  Note that this identifier is
+checked for case-sensitively.
+
+Following on the same line or on the next, a "label" header field may
+be specified like this:
+
+  header = x1/y1, x2/y2
+
+x1, y1, etc. are integer numbers; white space within this specification 
+is optional.  The delimiters in between the numbers can be chosen 
+almost arbitrarily (when parsing, wmpinboard regards any non-digit 
+characters as delimiters).  The purpose of this field is to specify a 
+rectangular area (x1/y1 upper left, x2/y2 lower right corner; 
+coordinates are inclusive) identifying a modified location of the 
+default "TO DO" label, relative to the board pixmap.  The given 
+coordinates have to fulfil the following conditions:
+
+  x1, x2 = [0..51]
+  y1, y2 = [0..59]
+  x1 < x2
+  y1 < y2
+  (x2-x1) * (y2-y1) >= 16
+
+Furthermore, the header section may contain comments, which wmpinboard
+considers everything after `#'s.
+
+Each of the pixmap sections (only one is required) has to be standard 
+(C source) pixmap data WITH NO INTERMEDIATE ZERO-LENGTH LINES.  Since 
+themes are meant to work in high-color modes only, you needn't worry 
+about the number of colors used, or other palette issues.  To ease the 
+creation of custom pixmaps, this package includes the default pixmaps 
+as templates.
+
+Which themeable portion of wmpinboard a pixmap represents is determined
+by its size:
+
+  52x60 pinboard
+  58x30 edit mode panel
+  58x28 alarm panel
+  60x 9 alarm panel digits (6x9 each)
+
+To illustrate this formal description, the default and a sample theme 
+are included as ".wmpbtheme" files.  The former defines a label 
+location as well as all the pixmaps, the latter a label location and an 
+alternative board pixmap.
+
+ Restrictions
+--------------
+
+Generally, custom pixmap sizes are NOT supported, and neither is 
+transparency, meaning you'll have to stick with the design-implied 
+dimensions.  Also, the panels' buttons' area-to-function mapping is 
+fixed.
+
+There should be no lines longer than 127 characters in a theme file, or 
+else unpredictable things may happen.
+
+ Submission of themes
+----------------------
+
+If you've created a custom theme you wish to share with other users of 
+wmpinboard, mail it to <gomar at mindless.com>.  It will then most likely 
+be added to the program's home page at
+
+  <http://www.tu-ilmenau.de/~gomar/stuff/wmpinboard/>
+
diff --git a/themes-kit/abar.xpm b/themes-kit/abar.xpm
new file mode 100644
index 0000000..fcc2366
--- /dev/null
+++ b/themes-kit/abar.xpm
@@ -0,0 +1,42 @@
+/* XPM */
+static char * abar_xpm[] = {
+"58 28 11 1",
+" 	c None",
+".	c #000000",
+"+	c #EFD183",
+"@	c #D2AA5C",
+"#	c #6E3A1C",
+"$	c #878787",
+"%	c #6B9600",
+"&	c #AEFA04",
+"*	c #FEFEFC",
+"=	c #87003A",
+"-	c #F73D88",
+"..........................................................",
+".++++++++++++++++++++++++++++++++++++++++++++++++++++++++.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@..@@@@@@@@@@....@@@#.",
+".+@@@@@@@@@@@@@@+$@@@@@@@@@@@@@@@@@@@....@@@@@@@.%%%%.@@#.",
+".+@@@@@@@@@@@@@@..@@@@@@@@@@@@@@@@$........$@@@.%&&%%%.@#.",
+".+@@@@@@@@@@@@@@$#@@@@@@@@@@@@@@@$.@@....@@.$@@.%&&&%%.@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.@@@..@@@@@.@@.%%&%%%.@#.",
+".+@@@@@@@@@@@@@@+$@@@@@@@@@@@@@@@.@@@@@@@@@@.@@.%%%%%%.@#.",
+".+@@@@@@@@@@@@@@..@@@@@@@@@@@@@@@$.@@@@@@@@.$@@@.%%%%.@@#.",
+".+@@@@@@@@@@@@@@$#@@@@@@@@@@@@@@@@$........$@@@@@....@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@...........@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@...........@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.$$$$$$$$..@@@@....@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.***==***..@@@.====.@@#.",
+".+@@@@@@@@@@@@@@+$@@@@@@@@@@@@@@@@.**===***..@@.=--===.@#.",
+".+@@@@@@@@@@@@@@..@@@@@@@@@@@@@@@@.***==***..@@.=---==.@#.",
+".+@@@@@@@@@@@@@@$#@@@@@@@@@@@@@@@@.***==***..@@.==-===.@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.***==***..@@.======.@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.********...@@@.====.@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@...........@@@@@....@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@...........@@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.",
+".########################################################.",
+".........................................................."};
diff --git a/themes-kit/bbar.xpm b/themes-kit/bbar.xpm
new file mode 100644
index 0000000..7c7aea7
--- /dev/null
+++ b/themes-kit/bbar.xpm
@@ -0,0 +1,56 @@
+/* XPM */
+static char * bbar_xpm[] = {
+"58 30 23 1",
+" 	c None",
+".	c #000000",
+"+	c #EFD183",
+"@	c #6E3A1C",
+"#	c #D2AA5C",
+"$	c #FA0604",
+"%	c #7F6602",
+"&	c #FF0569",
+"*	c #FFFFFF",
+"=	c #FADA04",
+"-	c #AEFA04",
+";	c #6B9600",
+">	c #F48989",
+",	c #C16C6C",
+"'	c #894E4E",
+")	c #F73D88",
+"!	c #87003A",
+"~	c #9E0EDC",
+"{	c #FE821C",
+"]	c #62A6EF",
+"^	c #3E6599",
+"/	c #2A4668",
+"(	c #F2EE04",
+"..........................................................",
+".+++++++++++++ at +++++++++++++@+++++++++++++ at ++++++++++++++.",
+".+############@+############@+############@+############@.",
+".+####...@$###@+####%.%#####@+##########&#@+#.....#....#@.",
+".+##..*.*.&$##@+####.=.#####@+###.###.#&&#@+#.---.#.;-.#@.",
+".+##.**.**.@##@+###%=.######@+##.#.##.&&##@+#.---.#.--.#@.",
+".+#.***.***.##@+###.=%##..##@+#.###.#&&###@+#.--;.#.--.#@.",
+".+#.***.***.##@+##%=.##.##.#@+#.###.&&..##@+#....##.--.#@.",
+".+#.**.****.##@+##.=%#.####. at +#....&&.##.#@+######.;--.#@.",
+".+##.*****.###@+#%=.##.####. at +#.##&&#.##.#@+#....#.;--.#@.",
+".+##..***..###@+#.=%###.##.#@+#.#&&.#.##.#@+#.-;.##.--.#@.",
+".+##%.....%###@+#..#####..##@+#.&&#.#...##@+#.--;.#.;-.#@.",
+".+#...%#%...##@+#.......##.#@+#&&#########@+#.....##...#@.",
+".+############@+###########. at +############@+############@.",
+".@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.",
+".+++++++++++++ at +++++++++++++@+++++++++++++ at ++++++++++++++.",
+".+############@+####>>>>>>##@+############@+############@.",
+".+#-###......#@+###>,,,,,,'#@+#&#...######@+##########)#@.",
+".+#--###.....#@+###>,,,,,,'#@+#&&###.#####@+#########)!#@.",
+".+#~--###....#@+###>,,,,,,'#@+#.&&###.####@+########)!##@.",
+".+#~~--#.....#@+##>,,,,,,'##@+#.#&&#..####@+########)###@.",
+".+#$~~-...#..#@+##>,,,,,,'##@+#.##&&&.####@+#######)!###@.",
+".+#$$~...###.#@+##>,,,,,,'##@+##.#.#&&####@+#))###))####@.",
+".+#{$...--####@+##]^^,,,,'##@+###...#&&###@+#))))))!####@.",
+".+#{{..~~--###@+#]^^^^^^/###@+###.####&&##@+###)))!#####@.",
+".+#({{$$~~--##@+#]^^^^^^/###@+##.######&&#@+####))!#####@.",
+".+#(({{$$~~--#@+#]^^^^^^/###@+##........&#@+#####!######@.",
+".+############@+##//////####@+############@+############@.",
+".@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.",
+".........................................................."};
diff --git a/themes-kit/board.xpm b/themes-kit/board.xpm
new file mode 100644
index 0000000..666e4d2
--- /dev/null
+++ b/themes-kit/board.xpm
@@ -0,0 +1,135 @@
+/* XPM */
+static char *board[] = {
+/* width height num_colors chars_per_pixel */
+"    52    60       68            2",
+/* colors */
+".. c #d6fe04",
+".# c #565654",
+".a c #4e4e4c",
+".b c #362a14",
+".c c #121214",
+".d c #363634",
+".e c #6be520",
+".f c #020204",
+".g c #60c021",
+".h c #f22e96",
+".i c #aefa04",
+".j c #94d205",
+".k c #9a6e2c",
+".l c #fefefc",
+".m c #d5d5d4",
+".n c #562e1c",
+".o c #6e3a1c",
+".p c #8e421c",
+".q c #0a76ec",
+".r c #f9f14a",
+".s c #d1ca45",
+".t c #f6fe7c",
+".u c #6a6a6c",
+".v c #fada04",
+".w c #d2b705",
+".x c #febe04",
+".y c #d5a005",
+".z c #dec67c",
+".A c #d6ba6c",
+".B c #6a361c",
+".C c #66311c",
+".D c #d2aa5c",
+".E c #fe821c",
+".F c #d5721d",
+".G c #fe5e1c",
+".H c #d5561d",
+".I c #4e2a1c",
+".J c #fe8e8c",
+".K c #d57b7a",
+".L c #fa0604",
+".M c #c60805",
+".N c #bf2b79",
+".O c #ad067e",
+".P c #8a0868",
+".Q c #d6b66c",
+".R c #ca9e4c",
+".S c #8503c6",
+".T c #6d049d",
+".U c #2606c4",
+".V c #24089b",
+".W c #020684",
+".X c #040c54",
+".Y c #d2b264",
+".Z c #0b63ba",
+".0 c #8a421c",
+".1 c #0acaec",
+".2 c #0caac6",
+".3 c #0aea74",
+".4 c #0cc467",
+".5 c #0eda1c",
+".6 c #10b71d",
+".7 c #2e8e0c",
+".8 c #2e7b0e",
+".9 c #ceaa5c",
+"#. c #cea654",
+"## c #caa254",
+"#a c #c79849",
+"#b c #c2a454",
+/* pixels */
+".k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.b",
+".k.n.n.n.o.o.o.o.o.o.o.o.o.o.o.p.p.p.n.n.n.o.o.o.o.o.o.o.o.o.n.n.n.n.o.o.o.o.o.o.n.n.n.n.o.o.o.o.o.o.o.b",
+".k.o.o.o.o.o.o.n.n.o.o.o.n.t.t.t.t.t.o.p.t.t.t.n.o.o.o.t.t.t.o.o.o.o.t.t.t.o.o.n.o.o.o.o.p.p.o.o.p.o.o.b",
+".k.o.o.b.b.b.b.b.b.b.b.n.o.o.n.t.o.o.o.t.o.o.o.t.o.p.n.t.n.p.t.o.o.t.n.o.o.t.p.b.b.b.b.b.b.b.b.b.k.o.o.b",
+".k.o.o.b.z.z.z.z.A.z.z.A.o.o.o.t.p.o.n.t.o.o.o.t.o.o.o.t.B.B.C.t.B.t.C.C.B.t.o.b.D.D.z.z.z.A.A.A.k.n.o.b",
+".k.n.o.b.z.z.z.A.z.A.A.A.o.n.o.t.C.C.o.t.n.n.o.t.o.o.o.t.B.B.B.t.B.t.C.C.C.t.B.b.D.D.z.A.A.D.A.z.k.o.o.b",
+".k.o.o.b.z.A.A.A.A.A.A.A.o.o.I.t.C.C.o.t.o.o.o.t.o.n.n.t.p.p.o.t.p.t.p.n.n.t.p.b.D.D.A.A.A.A.A.z.k.o.o.b",
+".k.o.p.b.A.A.A.A.A.A.A.A.o.o.o.t.n.n.p.p.t.t.t.o.o.o.o.t.t.t.t.n.C.C.t.t.t.C.C.b.D.A.A.A.A.A.A.A.k.p.o.b",
+".k.o.o.b.D.A.A.A.A.A.A.A.n.n.o.o.B.C.C.C.C.I.I.I.o.C.o.p.C.o.o.o.C.C.C.C.C.C.C.b.D.D.D.D.A.A.A.A.k.o.n.b",
+".k.p.p.b.A.A.D.D.A.A.A.A.A.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.A.D.D.D.D.A.A.D.A.k.n.o.b",
+".k.p.o.b.A.Q.Q.Q.Q.Q.A.D.A.D.D.D.D.D.A.A.D.D.D.D.R.D.D.D.D.R.D.D.R.D.D.D.D.R.R.D.D.D.D.D.D.D.D.A.k.p.o.b",
+".k.o.o.b.A.Q.Q.Q.Q.D.Q.A.D.D.D.D.D.A.D.A.A.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.A.A.A.A.A.A.D.k.p.p.b",
+".k.p.o.b.A.Q.Q.Q.Q.D.D.D.D.A.D.D.A.A.A.A.A.A.D.D.A.D.A.D.A.D.D.D.A.D.A.D.A.D.D.A.D.A.D.A.A.A.A.A.k.o.o.b",
+".k.p.B.b.A.A.Q.Q.D.Q.Q.Q.Y.D.A.A.A.A.A.A.D.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.D.A.A.A.A.A.A.A.A.k.o.o.b",
+".k.B.0.b.A.A.D.Q.D.D.Q.Q.Y.Y.D.Q.Q.A.A.A.A.A.A.D.D.A.D.D.A.A.A.D.D.A.D.D.A.A.D.A.A.D.A.A.A.A.A.A.k.o.o.b",
+".k.o.B.b.A.A.Q.D.D.D.D.D.D.D.D.D.Q.Q.A.A.A.Q.Q.Y.Y.Q.Q.D.D.A.A.A.D.D.D.D.D.A.A.D.D.A.D.D.A.A.A.A.k.p.o.b",
+".k.0.B.b.A.A.Q.Q.Q.Q.D.D.D.D.D.D.D.D.D.D.D.Q.D.Y.Y.Y.Y.Y.D.Y.D.Q.D.D.D.D.D.Q.Q.A.D.A.A.D.A.A.D.D.k.p.o.b",
+".k.C.o.b.A.A.Q.Q.Q.Y.Y.D.Q.Q.Q.Y.Y.Y.D.D.A.Q.D.D.D.Y.Y.Y.Y.Y.D.D.D.Q.Q.Y.Y.Q.Q.A.D.A.A.D.D.D.D.A.k.o.o.b",
+".k.n.B.b.A.D.D.D.Q.Q.D.D.D.Y.Q.D.D.D.D.D.D.A.D.A.D.D.D.D.Y.Y.D.D.D.D.9.9.Y.Y.Q.9.A.A.D.D.D.D.D.D.k.p.o.b",
+".k.n.n.b.A.A.A.D.D.D.Y.D.D.D.D.9.9.9.9.9.D.D.D.D.D.9.9.D.D.D.D.9.9.9#..9#..9.9.A.9.A.D.A.D.D.A.D.k.p.o.b",
+".k.n.0.b.A.A.A.A.D.D.D.D.9.9.D.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9#.#.#.#..9.D.D#.#.#..A.D.D.A.D.D.D.k.o.o.b",
+".k.n.p.b.D.D.A.A.D.9.9.9.9#.#..D.D.D.9.9.9.9.9.9#.#..R.9.9.9#.#####..R.D.D.D.D.D.9.9.D.D.D.D.A.D.k.o.o.b",
+".k.n.p.b.D.A.D.D.D.9###.#.#.#####.#..D.A.D.D.9.R.R.R#.#.#.#..D.R.R.A.A.D.D.D.D.D.A.D.D.A.A.A.A.D.k.o.p.b",
+".k.o.o.b.D.D.D.D.D.D.9.D#.#.#.##.R#..Y.9.D.D.D.D.D.D.R#..9#..R.D#..R.R.9.D.A.D.D.D.D.D.D.A.A.D.A.k.o.p.b",
+".k.o.o.b.D.A.D.D.R.D.R.R.9.R.9.9.Q.D.D.R.R.9#a#.#a.A.D.D.D.D.D.D.D.D.A.D.D.D.D.D.D.D.D.D.D.A.A.A.k.n.o.b",
+".k.p.p.b.D.D.D.D.D.D.D#..D.9.9.R###..R###..9.A.9.9.9.D.D.9.9#b#.#.###..9.9.D.D.D.D.D.D.D.D.Q.A.A.k.o.o.b",
+".k.p.o.b.A.A.D.D.D.D.R.R.R.R.9.D.D#.#.#.#..9.9.D.D#..D.D.9.9.9##.9.9.9#..9.D.D.D.D.D.D.D.Y.Q.A.A.k.o.o.b",
+".k.o.o.b.A.A.A.A.D.D.D#.#.#..R##.9.D#.#.#..9.9.Y.D.D.D.D.9.D.D.Y.D.9.9.9.9.D.D.D.D.D.D.D.Y.Q.Q.A.k.p.o.b",
+".k.p.p.b.A.A.A.A.D.A.D.D.D.D.9.9.9.9.9.9.9.9.9.9.9.D.D.D.D.9.D.9.D.D.D#.#..D.9#.#..9.9.D.D.Q.Q.D.k.o.o.b",
+".k.o.o.b.A.A.D.D.A.D.A.Q.D.Y.Y.D.9.9.9.9.9.9.9.9.A.A.9.9.9.9.D.D.D.D.D.D.D.D.D.Y.Q.A.Q.Y.Y.D.Q.A.k.o.o.b",
+".k.o.o.b.z.z.z.A.A.D.D.A.D.D.D.9.9.A.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9#..9.9.9.9.Y.Y.9.D.D.A.D.k.o.o.b",
+".k.n.p.b.A.A.D.D.D.D.D.D.D.9.9.9.9.9.9.9.9.9#.#.#..9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.D.9.9.D.D.D.A.k.p.o.b",
+".k.n.o.b.D.D.D.D.D.D.D.D.9.9.9.9.9.9.9.9#..9#.#.#..D.9.9.9.9.9.9.D.D.D.9#.#..9.9.9.D.9.9.A.D.A.D.k.p.o.b",
+".k.n.n.b.z.A.z.A.A.D.A.D.D.9.9.9.9.9.9.9.D.9#.#.#.#..D#.#..9.9.D.9.Q.9.D.D.9.9.R.9.9.Y.9.A.A.A.A.k.n.o.b",
+".k.n.o.b.A.A.A.D.D.D.D.D.D.D.D.9.9#..9.9.9.D###a#a##.D.D#a.R#..D.D.D#a#a#a.R.R.R.9.9.Y.9.A.A.A.A.k.o.o.b",
+".k.n.o.b.D.D.D.D.D.D.D.D.D.D.D.A.9.R.R#..R#a.D.D.D#a#a#a.D###a#a#a#a.D#a.9#.#.#..D.Y.9.Y.D.D.A.D.k.p.o.b",
+".k.n.o.b.A.A.A.D.D.D.D.D.D.D.9.9.D.9#.#.#.#..D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.9#..Y.Y.Y.Y.D.A.D.k.p.p.b",
+".k.p.o.b.D.D.D.D.D.D.Y.Y.Y.D.9.D.D.D.9#.#.#.#.#####b#.#a.D#a#a.D#.#..D###..9.9#.#..9.Y.Y.Y.D.D.D.k.o.o.b",
+".k.o.o.b.D.D.D.D.D.D.D.D.D.D.D.D.D.9.9.9#.#.#.#####a#.#..D.D.D.D#b.9.D#..9.9.9.9.9.Y.D.D.Y.D.A.D.k.p.p.b",
+".k.n.n.b.D.D.D.Q.Y.D.Y.D.D.D.D.D.D.D.D.D#.#.#.#####..D.D#.#a#b###b.D#..D.9.D.9#a.9.D.Y.D.Q.A.A.A.k.n.o.b",
+".k.p.p.b.D.A.D.D.D.D.D.D.D.D.D.D.D.D.D.D.A.D.D.D.D.D.D.D.D.D.D###a.9#a.D#a#a#a.R#..D.Y.D.Q.A.A.A.k.o.n.b",
+".k.o.p.b.D.D.D.D.D.D.D.D.D.D.D.D.D.R.R#..R.D.D.D.D.D.D.D.D.9#a.D.D.D#a.D.D.D.D.D.D.Y.D.A.D.D.A.D.k.p.n.b",
+".k.o.p.b.D.D.A.D.D.D.D.D.D.D.D.D.D.9.9#..D.D.D.D#.#a.D.D.D.D.D.D.D.D.D#..D.D.D.D.D.Y.Q.A.A.D.A.D.k.p.n.b",
+".k.p.o.b.A.D.D.D.D.D.Q.Q.Y.D.D.D.D.D.D.D.9.9.9.9.D.D.D.D.9.9.D.D.9.9#..R.9.D.D.D.D.D.Q.A.A.D.D.D.k.o.n.b",
+".k.o.n.b.D.A.A.D.D.D.D.D.9.9.9#..9.D.D.D.D.D.9.9.9.9.9.9.9.9.9.D.D.9.9.9.9.D.D.D.9.D.D.D.A.D.D.D.k.n.n.b",
+".k.o.o.b.D.D.D.D.D.D.D.R.R.R#a.9.9.D.D.D.D.D.Y.D.9.9.9.9.9.D.D.A.D.D.9.9#..D.D.9.9.9.9.D.D.D.D.D.k.p.n.b",
+".k.o.o.b.D.D.D.D.D.D.D.D.9#..R#.##.9.9.D.D.D.D.D.9.9.9.9.9.D.D.9.A.A.D.D.9.D.9.9.D.D.D.D.D.D.D.R.k.o.o.b",
+".k.o.p.b.D.D.D.D.D.D.D.D.9.9.9.D.D.9.9.9.9.9.D.D.9.9.9.9.9.9#.#..9.9.9.D.D.9.9.9.D.Q.D.A.D.D.A.D.k.o.n.b",
+".k.o.p.b.A.D.D.D.D.D.D.A.D.9.9.D.D.9#..9#.#.#.#a#a.9.9.9.D.D#.#a#a.9.9.D#a.9##.9.9.Q.A.A.A.D.A.D.k.o.o.b",
+".k.n.o.b.A.A.D.D.D.D.D.D.A.9.9.R.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.9#.#a#b#..9.9.D.A.A.A.D.D.D.k.o.o.b",
+".k.n.o.b.D.D.D.D.D.D.D.D.D.9#..R#a.D#a#a#a.D.D.D.D#a#a#.#a#a.D.D#a#a#a#.#a#a#.#..D.D.D.D.A.D.D.D.k.o.p.b",
+".k.n.o.b.R.D.D.D.D.D.D.D.D.D.9#.#..D.R##.D.D#b#.#######..9#.#..9.D.9.9.9.9.9.9.9.D.D.D.D.D.D.D.D.k.o.p.b",
+".k.o.o.b.D.D.D.D.A.A.A.A.D.Q.D.9.9.9#.#.#..D.9.9.9#.#b#.#..9.9.9.D.D.9.9.D.D.D.D.D.D.D.D.D.D.D.R.k.o.n.b",
+".k.o.o.b.D.D.D.D.D.D.D.D.D.D.D.D.R.D.D.D.D.D.9.9.9#a.D.D.D.R.D.D.D.R.D.R.R.R.D.D.D.D.D.D.D.R.D.D.k.p.n.b",
+".k.o.o.b.R.R.R.R.D.D.D.D.D.R.R.R.R.R.R.R.D.D.D.9.R.R.R.R.R.R.D.D.R.R.R.R.R.R.R.D.D.D.D.D.D.R.R.D.k.o.n.b",
+".k.o.o.b.D.R.R.R.D.D.D.D.D.D.D.D.R.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.R.D.D.D.D.D.A.A.k.o.o.b",
+".k.o.n.b.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.o.o.b",
+".k.n.o.o.n.o.o.o.o.o.o.o.o.o.p.p.p.p.p.p.p.n.o.o.o.o.p.p.p.p.n.n.n.p.p.p.p.p.p.o.p.o.o.o.o.o.p.o.o.o.p.b",
+".k.o.o.o.o.o.p.p.p.n.n.p.o.o.o.o.o.o.n.n.n.n.n.o.o.o.o.n.o.o.o.p.p.o.o.o.o.o.o.p.p.o.p.p.o.o.o.n.n.n.p.b",
+".k.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b"
+};
diff --git a/themes-kit/default.wmpbtheme b/themes-kit/default.wmpbtheme
new file mode 100644
index 0000000..db28018
--- /dev/null
+++ b/themes-kit/default.wmpbtheme
@@ -0,0 +1,258 @@
+WMPBtheme
+#
+# sample wmpinboard theme equivalent to the default appearance
+#
+label = 12/0, 39/9
+
+/* XPM */
+static char * bbar_xpm[] = {
+"58 30 23 1",
+" 	c None",
+".	c #000000",
+"+	c #EFD183",
+"@	c #6E3A1C",
+"#	c #D2AA5C",
+"$	c #FA0604",
+"%	c #7F6602",
+"&	c #FF0569",
+"*	c #FFFFFF",
+"=	c #FADA04",
+"-	c #AEFA04",
+";	c #6B9600",
+">	c #F48989",
+",	c #C16C6C",
+"'	c #894E4E",
+")	c #F73D88",
+"!	c #87003A",
+"~	c #9E0EDC",
+"{	c #FE821C",
+"]	c #62A6EF",
+"^	c #3E6599",
+"/	c #2A4668",
+"(	c #F2EE04",
+"..........................................................",
+".+++++++++++++ at +++++++++++++@+++++++++++++ at ++++++++++++++.",
+".+############@+############@+############@+############@.",
+".+####...@$###@+####%.%#####@+##########&#@+#.....#....#@.",
+".+##..*.*.&$##@+####.=.#####@+###.###.#&&#@+#.---.#.;-.#@.",
+".+##.**.**.@##@+###%=.######@+##.#.##.&&##@+#.---.#.--.#@.",
+".+#.***.***.##@+###.=%##..##@+#.###.#&&###@+#.--;.#.--.#@.",
+".+#.***.***.##@+##%=.##.##.#@+#.###.&&..##@+#....##.--.#@.",
+".+#.**.****.##@+##.=%#.####. at +#....&&.##.#@+######.;--.#@.",
+".+##.*****.###@+#%=.##.####. at +#.##&&#.##.#@+#....#.;--.#@.",
+".+##..***..###@+#.=%###.##.#@+#.#&&.#.##.#@+#.-;.##.--.#@.",
+".+##%.....%###@+#..#####..##@+#.&&#.#...##@+#.--;.#.;-.#@.",
+".+#...%#%...##@+#.......##.#@+#&&#########@+#.....##...#@.",
+".+############@+###########. at +############@+############@.",
+".@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.",
+".+++++++++++++ at +++++++++++++@+++++++++++++ at ++++++++++++++.",
+".+############@+####>>>>>>##@+############@+############@.",
+".+#-###......#@+###>,,,,,,'#@+#&#...######@+##########)#@.",
+".+#--###.....#@+###>,,,,,,'#@+#&&###.#####@+#########)!#@.",
+".+#~--###....#@+###>,,,,,,'#@+#.&&###.####@+########)!##@.",
+".+#~~--#.....#@+##>,,,,,,'##@+#.#&&#..####@+########)###@.",
+".+#$~~-...#..#@+##>,,,,,,'##@+#.##&&&.####@+#######)!###@.",
+".+#$$~...###.#@+##>,,,,,,'##@+##.#.#&&####@+#))###))####@.",
+".+#{$...--####@+##]^^,,,,'##@+###...#&&###@+#))))))!####@.",
+".+#{{..~~--###@+#]^^^^^^/###@+###.####&&##@+###)))!#####@.",
+".+#({{$$~~--##@+#]^^^^^^/###@+##.######&&#@+####))!#####@.",
+".+#(({{$$~~--#@+#]^^^^^^/###@+##........&#@+#####!######@.",
+".+############@+##//////####@+############@+############@.",
+".@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.",
+".........................................................."};
+
+/* XPM */
+static char *board[] = {
+/* width height num_colors chars_per_pixel */
+"    52    60       68            2",
+/* colors */
+".. c #d6fe04",
+".# c #565654",
+".a c #4e4e4c",
+".b c #362a14",
+".c c #121214",
+".d c #363634",
+".e c #6be520",
+".f c #020204",
+".g c #60c021",
+".h c #f22e96",
+".i c #aefa04",
+".j c #94d205",
+".k c #9a6e2c",
+".l c #fefefc",
+".m c #d5d5d4",
+".n c #562e1c",
+".o c #6e3a1c",
+".p c #8e421c",
+".q c #0a76ec",
+".r c #f9f14a",
+".s c #d1ca45",
+".t c #f6fe7c",
+".u c #6a6a6c",
+".v c #fada04",
+".w c #d2b705",
+".x c #febe04",
+".y c #d5a005",
+".z c #dec67c",
+".A c #d6ba6c",
+".B c #6a361c",
+".C c #66311c",
+".D c #d2aa5c",
+".E c #fe821c",
+".F c #d5721d",
+".G c #fe5e1c",
+".H c #d5561d",
+".I c #4e2a1c",
+".J c #fe8e8c",
+".K c #d57b7a",
+".L c #fa0604",
+".M c #c60805",
+".N c #bf2b79",
+".O c #ad067e",
+".P c #8a0868",
+".Q c #d6b66c",
+".R c #ca9e4c",
+".S c #8503c6",
+".T c #6d049d",
+".U c #2606c4",
+".V c #24089b",
+".W c #020684",
+".X c #040c54",
+".Y c #d2b264",
+".Z c #0b63ba",
+".0 c #8a421c",
+".1 c #0acaec",
+".2 c #0caac6",
+".3 c #0aea74",
+".4 c #0cc467",
+".5 c #0eda1c",
+".6 c #10b71d",
+".7 c #2e8e0c",
+".8 c #2e7b0e",
+".9 c #ceaa5c",
+"#. c #cea654",
+"## c #caa254",
+"#a c #c79849",
+"#b c #c2a454",
+/* pixels */
+".k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.b",
+".k.n.n.n.o.o.o.o.o.o.o.o.o.o.o.p.p.p.n.n.n.o.o.o.o.o.o.o.o.o.n.n.n.n.o.o.o.o.o.o.n.n.n.n.o.o.o.o.o.o.o.b",
+".k.o.o.o.o.o.o.n.n.o.o.o.n.t.t.t.t.t.o.p.t.t.t.n.o.o.o.t.t.t.o.o.o.o.t.t.t.o.o.n.o.o.o.o.p.p.o.o.p.o.o.b",
+".k.o.o.b.b.b.b.b.b.b.b.n.o.o.n.t.o.o.o.t.o.o.o.t.o.p.n.t.n.p.t.o.o.t.n.o.o.t.p.b.b.b.b.b.b.b.b.b.k.o.o.b",
+".k.o.o.b.z.z.z.z.A.z.z.A.o.o.o.t.p.o.n.t.o.o.o.t.o.o.o.t.B.B.C.t.B.t.C.C.B.t.o.b.D.D.z.z.z.A.A.A.k.n.o.b",
+".k.n.o.b.z.z.z.A.z.A.A.A.o.n.o.t.C.C.o.t.n.n.o.t.o.o.o.t.B.B.B.t.B.t.C.C.C.t.B.b.D.D.z.A.A.D.A.z.k.o.o.b",
+".k.o.o.b.z.A.A.A.A.A.A.A.o.o.I.t.C.C.o.t.o.o.o.t.o.n.n.t.p.p.o.t.p.t.p.n.n.t.p.b.D.D.A.A.A.A.A.z.k.o.o.b",
+".k.o.p.b.A.A.A.A.A.A.A.A.o.o.o.t.n.n.p.p.t.t.t.o.o.o.o.t.t.t.t.n.C.C.t.t.t.C.C.b.D.A.A.A.A.A.A.A.k.p.o.b",
+".k.o.o.b.D.A.A.A.A.A.A.A.n.n.o.o.B.C.C.C.C.I.I.I.o.C.o.p.C.o.o.o.C.C.C.C.C.C.C.b.D.D.D.D.A.A.A.A.k.o.n.b",
+".k.p.p.b.A.A.D.D.A.A.A.A.A.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.A.D.D.D.D.A.A.D.A.k.n.o.b",
+".k.p.o.b.A.Q.Q.Q.Q.Q.A.D.A.D.D.D.D.D.A.A.D.D.D.D.R.D.D.D.D.R.D.D.R.D.D.D.D.R.R.D.D.D.D.D.D.D.D.A.k.p.o.b",
+".k.o.o.b.A.Q.Q.Q.Q.D.Q.A.D.D.D.D.D.A.D.A.A.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.A.A.A.A.A.A.D.k.p.p.b",
+".k.p.o.b.A.Q.Q.Q.Q.D.D.D.D.A.D.D.A.A.A.A.A.A.D.D.A.D.A.D.A.D.D.D.A.D.A.D.A.D.D.A.D.A.D.A.A.A.A.A.k.o.o.b",
+".k.p.B.b.A.A.Q.Q.D.Q.Q.Q.Y.D.A.A.A.A.A.A.D.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.D.A.A.A.A.A.A.A.A.k.o.o.b",
+".k.B.0.b.A.A.D.Q.D.D.Q.Q.Y.Y.D.Q.Q.A.A.A.A.A.A.D.D.A.D.D.A.A.A.D.D.A.D.D.A.A.D.A.A.D.A.A.A.A.A.A.k.o.o.b",
+".k.o.B.b.A.A.Q.D.D.D.D.D.D.D.D.D.Q.Q.A.A.A.Q.Q.Y.Y.Q.Q.D.D.A.A.A.D.D.D.D.D.A.A.D.D.A.D.D.A.A.A.A.k.p.o.b",
+".k.0.B.b.A.A.Q.Q.Q.Q.D.D.D.D.D.D.D.D.D.D.D.Q.D.Y.Y.Y.Y.Y.D.Y.D.Q.D.D.D.D.D.Q.Q.A.D.A.A.D.A.A.D.D.k.p.o.b",
+".k.C.o.b.A.A.Q.Q.Q.Y.Y.D.Q.Q.Q.Y.Y.Y.D.D.A.Q.D.D.D.Y.Y.Y.Y.Y.D.D.D.Q.Q.Y.Y.Q.Q.A.D.A.A.D.D.D.D.A.k.o.o.b",
+".k.n.B.b.A.D.D.D.Q.Q.D.D.D.Y.Q.D.D.D.D.D.D.A.D.A.D.D.D.D.Y.Y.D.D.D.D.9.9.Y.Y.Q.9.A.A.D.D.D.D.D.D.k.p.o.b",
+".k.n.n.b.A.A.A.D.D.D.Y.D.D.D.D.9.9.9.9.9.D.D.D.D.D.9.9.D.D.D.D.9.9.9#..9#..9.9.A.9.A.D.A.D.D.A.D.k.p.o.b",
+".k.n.0.b.A.A.A.A.D.D.D.D.9.9.D.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9#.#.#.#..9.D.D#.#.#..A.D.D.A.D.D.D.k.o.o.b",
+".k.n.p.b.D.D.A.A.D.9.9.9.9#.#..D.D.D.9.9.9.9.9.9#.#..R.9.9.9#.#####..R.D.D.D.D.D.9.9.D.D.D.D.A.D.k.o.o.b",
+".k.n.p.b.D.A.D.D.D.9###.#.#.#####.#..D.A.D.D.9.R.R.R#.#.#.#..D.R.R.A.A.D.D.D.D.D.A.D.D.A.A.A.A.D.k.o.p.b",
+".k.o.o.b.D.D.D.D.D.D.9.D#.#.#.##.R#..Y.9.D.D.D.D.D.D.R#..9#..R.D#..R.R.9.D.A.D.D.D.D.D.D.A.A.D.A.k.o.p.b",
+".k.o.o.b.D.A.D.D.R.D.R.R.9.R.9.9.Q.D.D.R.R.9#a#.#a.A.D.D.D.D.D.D.D.D.A.D.D.D.D.D.D.D.D.D.D.A.A.A.k.n.o.b",
+".k.p.p.b.D.D.D.D.D.D.D#..D.9.9.R###..R###..9.A.9.9.9.D.D.9.9#b#.#.###..9.9.D.D.D.D.D.D.D.D.Q.A.A.k.o.o.b",
+".k.p.o.b.A.A.D.D.D.D.R.R.R.R.9.D.D#.#.#.#..9.9.D.D#..D.D.9.9.9##.9.9.9#..9.D.D.D.D.D.D.D.Y.Q.A.A.k.o.o.b",
+".k.o.o.b.A.A.A.A.D.D.D#.#.#..R##.9.D#.#.#..9.9.Y.D.D.D.D.9.D.D.Y.D.9.9.9.9.D.D.D.D.D.D.D.Y.Q.Q.A.k.p.o.b",
+".k.p.p.b.A.A.A.A.D.A.D.D.D.D.9.9.9.9.9.9.9.9.9.9.9.D.D.D.D.9.D.9.D.D.D#.#..D.9#.#..9.9.D.D.Q.Q.D.k.o.o.b",
+".k.o.o.b.A.A.D.D.A.D.A.Q.D.Y.Y.D.9.9.9.9.9.9.9.9.A.A.9.9.9.9.D.D.D.D.D.D.D.D.D.Y.Q.A.Q.Y.Y.D.Q.A.k.o.o.b",
+".k.o.o.b.z.z.z.A.A.D.D.A.D.D.D.9.9.A.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9#..9.9.9.9.Y.Y.9.D.D.A.D.k.o.o.b",
+".k.n.p.b.A.A.D.D.D.D.D.D.D.9.9.9.9.9.9.9.9.9#.#.#..9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.D.9.9.D.D.D.A.k.p.o.b",
+".k.n.o.b.D.D.D.D.D.D.D.D.9.9.9.9.9.9.9.9#..9#.#.#..D.9.9.9.9.9.9.D.D.D.9#.#..9.9.9.D.9.9.A.D.A.D.k.p.o.b",
+".k.n.n.b.z.A.z.A.A.D.A.D.D.9.9.9.9.9.9.9.D.9#.#.#.#..D#.#..9.9.D.9.Q.9.D.D.9.9.R.9.9.Y.9.A.A.A.A.k.n.o.b",
+".k.n.o.b.A.A.A.D.D.D.D.D.D.D.D.9.9#..9.9.9.D###a#a##.D.D#a.R#..D.D.D#a#a#a.R.R.R.9.9.Y.9.A.A.A.A.k.o.o.b",
+".k.n.o.b.D.D.D.D.D.D.D.D.D.D.D.A.9.R.R#..R#a.D.D.D#a#a#a.D###a#a#a#a.D#a.9#.#.#..D.Y.9.Y.D.D.A.D.k.p.o.b",
+".k.n.o.b.A.A.A.D.D.D.D.D.D.D.9.9.D.9#.#.#.#..D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.9#..Y.Y.Y.Y.D.A.D.k.p.p.b",
+".k.p.o.b.D.D.D.D.D.D.Y.Y.Y.D.9.D.D.D.9#.#.#.#.#####b#.#a.D#a#a.D#.#..D###..9.9#.#..9.Y.Y.Y.D.D.D.k.o.o.b",
+".k.o.o.b.D.D.D.D.D.D.D.D.D.D.D.D.D.9.9.9#.#.#.#####a#.#..D.D.D.D#b.9.D#..9.9.9.9.9.Y.D.D.Y.D.A.D.k.p.p.b",
+".k.n.n.b.D.D.D.Q.Y.D.Y.D.D.D.D.D.D.D.D.D#.#.#.#####..D.D#.#a#b###b.D#..D.9.D.9#a.9.D.Y.D.Q.A.A.A.k.n.o.b",
+".k.p.p.b.D.A.D.D.D.D.D.D.D.D.D.D.D.D.D.D.A.D.D.D.D.D.D.D.D.D.D###a.9#a.D#a#a#a.R#..D.Y.D.Q.A.A.A.k.o.n.b",
+".k.o.p.b.D.D.D.D.D.D.D.D.D.D.D.D.D.R.R#..R.D.D.D.D.D.D.D.D.9#a.D.D.D#a.D.D.D.D.D.D.Y.D.A.D.D.A.D.k.p.n.b",
+".k.o.p.b.D.D.A.D.D.D.D.D.D.D.D.D.D.9.9#..D.D.D.D#.#a.D.D.D.D.D.D.D.D.D#..D.D.D.D.D.Y.Q.A.A.D.A.D.k.p.n.b",
+".k.p.o.b.A.D.D.D.D.D.Q.Q.Y.D.D.D.D.D.D.D.9.9.9.9.D.D.D.D.9.9.D.D.9.9#..R.9.D.D.D.D.D.Q.A.A.D.D.D.k.o.n.b",
+".k.o.n.b.D.A.A.D.D.D.D.D.9.9.9#..9.D.D.D.D.D.9.9.9.9.9.9.9.9.9.D.D.9.9.9.9.D.D.D.9.D.D.D.A.D.D.D.k.n.n.b",
+".k.o.o.b.D.D.D.D.D.D.D.R.R.R#a.9.9.D.D.D.D.D.Y.D.9.9.9.9.9.D.D.A.D.D.9.9#..D.D.9.9.9.9.D.D.D.D.D.k.p.n.b",
+".k.o.o.b.D.D.D.D.D.D.D.D.9#..R#.##.9.9.D.D.D.D.D.9.9.9.9.9.D.D.9.A.A.D.D.9.D.9.9.D.D.D.D.D.D.D.R.k.o.o.b",
+".k.o.p.b.D.D.D.D.D.D.D.D.9.9.9.D.D.9.9.9.9.9.D.D.9.9.9.9.9.9#.#..9.9.9.D.D.9.9.9.D.Q.D.A.D.D.A.D.k.o.n.b",
+".k.o.p.b.A.D.D.D.D.D.D.A.D.9.9.D.D.9#..9#.#.#.#a#a.9.9.9.D.D#.#a#a.9.9.D#a.9##.9.9.Q.A.A.A.D.A.D.k.o.o.b",
+".k.n.o.b.A.A.D.D.D.D.D.D.A.9.9.R.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.9#.#a#b#..9.9.D.A.A.A.D.D.D.k.o.o.b",
+".k.n.o.b.D.D.D.D.D.D.D.D.D.9#..R#a.D#a#a#a.D.D.D.D#a#a#.#a#a.D.D#a#a#a#.#a#a#.#..D.D.D.D.A.D.D.D.k.o.p.b",
+".k.n.o.b.R.D.D.D.D.D.D.D.D.D.9#.#..D.R##.D.D#b#.#######..9#.#..9.D.9.9.9.9.9.9.9.D.D.D.D.D.D.D.D.k.o.p.b",
+".k.o.o.b.D.D.D.D.A.A.A.A.D.Q.D.9.9.9#.#.#..D.9.9.9#.#b#.#..9.9.9.D.D.9.9.D.D.D.D.D.D.D.D.D.D.D.R.k.o.n.b",
+".k.o.o.b.D.D.D.D.D.D.D.D.D.D.D.D.R.D.D.D.D.D.9.9.9#a.D.D.D.R.D.D.D.R.D.R.R.R.D.D.D.D.D.D.D.R.D.D.k.p.n.b",
+".k.o.o.b.R.R.R.R.D.D.D.D.D.R.R.R.R.R.R.R.D.D.D.9.R.R.R.R.R.R.D.D.R.R.R.R.R.R.R.D.D.D.D.D.D.R.R.D.k.o.n.b",
+".k.o.o.b.D.R.R.R.D.D.D.D.D.D.D.D.R.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.R.D.D.D.D.D.A.A.k.o.o.b",
+".k.o.n.b.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.o.o.b",
+".k.n.o.o.n.o.o.o.o.o.o.o.o.o.p.p.p.p.p.p.p.n.o.o.o.o.p.p.p.p.n.n.n.p.p.p.p.p.p.o.p.o.o.o.o.o.p.o.o.o.p.b",
+".k.o.o.o.o.o.p.p.p.n.n.p.o.o.o.o.o.o.n.n.n.n.n.o.o.o.o.n.o.o.o.p.p.o.o.o.o.o.o.p.p.o.p.p.o.o.o.n.n.n.p.b",
+".k.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b"
+};
+
+/* XPM */
+static char * abar_xpm[] = {
+"58 28 11 1",
+" 	c None",
+".	c #000000",
+"+	c #EFD183",
+"@	c #D2AA5C",
+"#	c #6E3A1C",
+"$	c #878787",
+"%	c #6B9600",
+"&	c #AEFA04",
+"*	c #FEFEFC",
+"=	c #87003A",
+"-	c #F73D88",
+"..........................................................",
+".++++++++++++++++++++++++++++++++++++++++++++++++++++++++.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@..@@@@@@@@@@....@@@#.",
+".+@@@@@@@@@@@@@@+$@@@@@@@@@@@@@@@@@@@....@@@@@@@.%%%%.@@#.",
+".+@@@@@@@@@@@@@@..@@@@@@@@@@@@@@@@$........$@@@.%&&%%%.@#.",
+".+@@@@@@@@@@@@@@$#@@@@@@@@@@@@@@@$.@@....@@.$@@.%&&&%%.@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.@@@..@@@@@.@@.%%&%%%.@#.",
+".+@@@@@@@@@@@@@@+$@@@@@@@@@@@@@@@.@@@@@@@@@@.@@.%%%%%%.@#.",
+".+@@@@@@@@@@@@@@..@@@@@@@@@@@@@@@$.@@@@@@@@.$@@@.%%%%.@@#.",
+".+@@@@@@@@@@@@@@$#@@@@@@@@@@@@@@@@$........$@@@@@....@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@...........@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@...........@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.$$$$$$$$..@@@@....@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.***==***..@@@.====.@@#.",
+".+@@@@@@@@@@@@@@+$@@@@@@@@@@@@@@@@.**===***..@@.=--===.@#.",
+".+@@@@@@@@@@@@@@..@@@@@@@@@@@@@@@@.***==***..@@.=---==.@#.",
+".+@@@@@@@@@@@@@@$#@@@@@@@@@@@@@@@@.***==***..@@.==-===.@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.***==***..@@.======.@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.********...@@@.====.@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@...........@@@@@....@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@...........@@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.",
+".########################################################.",
+".........................................................."};
+
+/* XPM */
+static char * digits_xpm[] = {
+"60 9 3 1",
+" 	c None",
+".	c #D2AA5C",
+"+	c #000000",
+".+++.........+++...+++.........+++...+++...+++...+++...+++..",
+"+...+.....+.....+.....+.+...+.+.....+.........+.+...+.+...+.",
+"+...+.....+.....+.....+.+...+.+.....+.........+.+...+.+...+.",
+"+...+.....+.....+.....+.+...+.+.....+.........+.+...+.+...+.",
+".............+++...+++...+++...+++...+++.........+++...+++..",
+"+...+.....+.+.........+.....+.....+.+...+.....+.+...+.....+.",
+"+...+.....+.+.........+.....+.....+.+...+.....+.+...+.....+.",
+"+...+.....+.+.........+.....+.....+.+...+.....+.+...+.....+.",
+".+++.........+++...+++.........+++...+++.........+++...+++.."};
+
diff --git a/themes-kit/digits.xpm b/themes-kit/digits.xpm
new file mode 100644
index 0000000..617f4b1
--- /dev/null
+++ b/themes-kit/digits.xpm
@@ -0,0 +1,15 @@
+/* XPM */
+static char * digits_xpm[] = {
+"60 9 3 1",
+" 	c None",
+".	c #D2AA5C",
+"+	c #000000",
+".+++.........+++...+++.........+++...+++...+++...+++...+++..",
+"+...+.....+.....+.....+.+...+.+.....+.........+.+...+.+...+.",
+"+...+.....+.....+.....+.+...+.+.....+.........+.+...+.+...+.",
+"+...+.....+.....+.....+.+...+.+.....+.........+.+...+.+...+.",
+".............+++...+++...+++...+++...+++.........+++...+++..",
+"+...+.....+.+.........+.....+.....+.+...+.....+.+...+.....+.",
+"+...+.....+.+.........+.....+.....+.+...+.....+.+...+.....+.",
+"+...+.....+.+.........+.....+.....+.+...+.....+.+...+.....+.",
+".+++.........+++...+++.........+++...+++.........+++...+++.."};
diff --git a/themes-kit/sample.wmpbtheme b/themes-kit/sample.wmpbtheme
new file mode 100644
index 0000000..42b0914
--- /dev/null
+++ b/themes-kit/sample.wmpbtheme
@@ -0,0 +1,130 @@
+WMPBtheme
+#
+# sample wmpinboard theme
+#
+# compared to the default theme, it just moves the "TO DO" label to the bottom
+# of the board
+#
+label = 11/50, 39/59
+
+/* XPM */
+static char *board_alt[] = {
+/* width height num_colors chars_per_pixel */
+"    52    60       54            1",
+/* colors */
+". c #362a14",
+"# c #6e3a1c",
+"a c #8a421c",
+"b c #9a6e2c",
+"c c #c69a4c",
+"d c #f6fe7c",
+"e c #d6ba6c",
+"f c #562e1c",
+"g c #d2b264",
+"h c #ca9e4c",
+"i c #c2a654",
+"j c #66321c",
+"k c #d6aa54",
+"l c #d2aa54",
+"m c #dec67c",
+"n c #deb264",
+"o c #4e2a1c",
+"p c #dab25c",
+"q c #cea24c",
+"r c #d2ae5c",
+"s c #d6b664",
+"t c #d6a654",
+"u c #cea654",
+"v c #dabe6c",
+"w c #d6ae54",
+"x c #d2aa5c",
+"y c #d2a24c",
+"z c #6a361c",
+"A c #dab264",
+"B c #d2a64c",
+"C c #d6b25c",
+"D c #daae5c",
+"E c #d6b66c",
+"F c #ca9a4c",
+"G c #d6aa5c",
+"H c #ce9e4c",
+"I c #deb664",
+"J c #caa254",
+"K c #d6ae5c",
+"L c #d2ae64",
+"M c #dab664",
+"N c #e2c274",
+"O c #ceaa54",
+"P c #d2a654",
+"Q c #8e421c",
+"R c #debe74",
+"S c #ceae5c",
+"T c #d6b264",
+"U c #daae64",
+"V c #dab66c",
+"W c #ceaa5c",
+"X c #daba6c",
+"Y c #ce9a4c",
+"Z c #d29e4c",
+/* pixels */
+"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.",
+"bfff###########QQQfff#########ffff######ffff#######.",
+"b######ff###f######Q###f###############f####QQ##Q##.",
+"b##.............................................b##.",
+"b##.mmEEExxxxhhWhWWExxhhWcucexxxxxxxxexxxexeeeeebf#.",
+"bf#.mmEExEEEgxuxWWhJuhJuWeWWWxxWWiuuJuWWeeeeexemb##.",
+"b##.mexExxEEghhhhWxxuuuuWWxxuxxWWWJWWWuWexeeeeemb##.",
+"b#Q.eeExxxxxxxuuuhJWxuuuxWTxxxxWxxgxWWWuWggreeeebQ#.",
+"b##.xeEEEExxxxxxxxxxxEKgsssgxgxExxxxxLWWgxxggeeeb#f.",
+"bQQ.eeEEgOWggEEgggxxeXGpAMssggxxxEEgrWcWxgxEeexebf#.",
+"bQ#.eExxWWgxxgxxxxGKxvUNnnUKggxxxxWWhFhuxgxEeExebQ#.",
+"b##.eETucxxxxxxrlxuqGXpnInpKKhuWuhxuuxxxgxexxeexbQQ.",
+"bQ#.eEJFxxxgxEXXBTTRnIktpHGcexxxxxxxxxKGsXXexeeeb##.",
+"bQz.eePxxxgxeGrvAMtlwtkDCRWxWxxWWiuuuxxKURvvxreeb##.",
+"bza.eexxxxxxxxxXyCnDkwwlrrxxuxxWWWJWxxKKAnUvxseeb##.",
+"b#z.eexxxxxEeexrwyurKPllWWgxxxxWxxgxWLrTpspKTeeebQ#.",
+"baz.eeLxxWxxxexxKKKxKExgggggxgxExxxxxETADAAKeexxbQ#.",
+"bj#.eeVLWWWWxxKTggxxeExxxgggggxxxEEggVevUvvxxxxeb##.",
+"bfz.exxxLrxxxLExxxxxxexexGxxggxxxxWWggESeexxxxxxbQ#.",
+"bff.eeexxxgxxxxWWWWWxxxxxSxxxxxWWWuWuWWeWexexxexbQ#.",
+"bfa.eeeexxxxWWxWWWWWWWWrLrKLxWWuuuuWxxuuuexxexxxb##.",
+"bfQ.xxevxWWWWuuxxxWWWWrWkDPKSxuJJuhxxxxxWWxxxxexb##.",
+"bfQ.xvxKKxJOuPJJuuxexxrqytpKxOxhheexxxxxexxeeeexb#Q.",
+"b##.GxKUAKLGxxxuHugWxxxGTpykSPhxuhhWxexxxxxxeexeb#Q.",
+"b##.GvAntnqqCBKLEGxhhWcPFNKGxKxxxxexxxxxxxxxxeeebf#.",
+"bQQ.LKDppDCGAATqquhJuWeWSWxKWWiuuJuWWxxxxxxxxEeeb##.",
+"bQ#.XvUpAUqytkTKxPuuuWWxxPxxWWWJWWWuWxxxxxxxgEeeb##.",
+"b##.eeevKGGllkquxxuuuWWgxxxxWxxgxWWWWxxxxxxxgEEebQ#.",
+"bQQ.eeXexvWGxGLSWWWWWWWWWxxxxWxWxxxuuxWuuWWxxEExb##.",
+"b##.eexxexeErsgxWWWWWWWWeeWWWWxxxxxxxxxgEeEggxEeb##.",
+"b##.mmmeexxexxxWWeWWWWWWWWWWWWWWWWWWuWWWWggWxxexb##.",
+"bfQ.eexxxxxxxWWWWWWWWWuuuWWWWWWWWWWWxxxxWxWWxxxebQ#.",
+"bf#.xxxxxxxxWWWWWWWWuWuuuxxSxSWWxxxSOxLrrxWWexexbQ#.",
+"bff.memeexexxWWWWWWWxWuuuuKDKATKxVWxGCCPxrgWeeeebf#.",
+"bf#.eeexxxxxxxxWWuWWWxJFFuUIxxxxxxFFFPtPrrgWeeeeb##.",
+"bf#.xxxxxxxxxxxeWhhuhcxxxHqxxGyyxxDYKDDwUgxgxxexbQ#.",
+"bf#.eeexxxxxxxWWxWuuuuxxxDnnlGxxxnACKCDrlsgggxexbQQ.",
+"bQ#.xxxxxxgggxWxxxWuuuuJJikyIZyIDpnPlxrPuWgggxxxb##.",
+"b##.xxxxxxxxxxxxxWWWuuuJqFkDIxxGxxxxrWSxWgxxgxexbQQ.",
+"bff.xxxEgxgxxxxxxxxxuuxxxxxxxxxrSIDUrrWcWxgxEeeebf#.",
+"bQQ.xexxxxxxxxxxxxxxexxxxxxxGKDPHKHGFFcFuxgxEeeeb#f.",
+"b#Q.xxxxxxxxxxxxxhhuhxxxxxxxxWcrGKFLxPxxxgxexxexbQf.",
+"b#Q.xxexxxxxxxxxxWWuxxxxucxxxxxxxxGPxxxxxgEeexexbQf.",
+"bQ#.exxxxxEEgxxxxxxxWWWWxxxxWWxxWWuhWxxxxxEeexxxb#f.",
+"b#f.xeexxxxxWWWuWxxxxxWWWWWWWWWxxWWWWxxxWxxxexxxbff.",
+"b##.xxxxxxxhhhFWWxxxxxgxWWWWWxxexxWWuxxWWWWxxxxxbQf.",
+"b##.xxxxxxxxWuhuJWWxxxxxWWWWWxxWeexxWxWWxxxxxxxhb##.",
+"b#Q.xxxxxxxxWWWxxWWWWWxxWWWWWWuuWWWxxWWWxExexxexb#f.",
+"b#Q.exxxxxxexWWxxWuWuuuFcWWWxxuccWWxcWJWWEeeexexb##.",
+"bf#.eexxxxxxeWWhxxxxxxxxxxxxxxxPxxWuciuWWxeeexxxb##.",
+"bf#.xxxxxxxxbbbbbbbbbbbbbbbbbbbbbbbbbbbuxxxxexxxb#Q.",
+"bf#.hxxxxxxb###QQQfff#########ffff#####.xxxxxxxxb#Q.",
+"b##.xxxxeeebfddddd#Qdddf###ddd####ddd##.xxxxxxxhb#f.",
+"b##.xxxxxxxb##fd###d###d#QfdfQd##df##dQ.xxxxxhxxbQf.",
+"b##.hhhhxxxb###dQ#fd###d###dzzjdzdjjzd#.xxxxxhhxb#f.",
+"b##.xhhhxxxb#f#djj#dff#d###dzzzdzdjjjdz.hxxxxxeeb##.",
+"b#f.bbbbbbbb##odjjzd###d#ffdQQ#dQdQffdQ.bbbbbbbbb##.",
+"bf##f##########dffQQddd####ddddfjjdddjj#Q#####Q###Q.",
+"b#####QQQffQff##zjjjjooo#j#Qjz##jjjjjjj#Q#QQ###fffQ.",
+"b..................................................."
+};
diff --git a/wmpb-convert.pl b/wmpb-convert.pl
new file mode 100644
index 0000000..cfe6b9e
--- /dev/null
+++ b/wmpb-convert.pl
@@ -0,0 +1,39 @@
+#!/usr/bin/perl -w
+
+#
+# wmpinboard pre-0.7 to v0.7 data file converter
+#
+
+require 5.003;
+
+my($ifn, $ofn, $c) = ('.wmpinboardrc', '.wmpinboarddata', 0);
+
+die "This script should not be executed while an instance of wmpinboard is " .
+  "running.\n" if `ps x` =~ /\d wmpinboard/;
+
+if (open IN, "$ENV{HOME}/$ifn" and open OUT, ">$ENV{HOME}/$ofn") {
+  binmode OUT;
+  print OUT "WMPB0-*-fixed-*--10-*-iso8859-1\n";
+  while (<IN>) {
+    chomp;
+    if (@_ = /^(\d+) (\d+) (\d+) (.*)/) {
+      if (length $4 <= 39) {
+        $_[3] =~ s/.{8}/$&\n/gs;
+        $_[3] = join '  ', split /\n/, $_[3];
+      }
+      $_[3] .= ' ' x (59 - length $_[3]);
+      print OUT pack 'i3a60', @_;
+      $c++
+    } else {
+      die "Invalid data in `~/.$ifn'.\nAborting" if $_
+    }
+  }
+  close IN;
+  close OUT;
+  print "Conversion of $c note@{[$c != 1 ? 's' : '']} complete.\n";
+  unlink "$ENV{HOME}/$ifn"
+} else {
+  die "Couldn't open both `~/$ifn' and `~/$ofn'.\n" .
+      "Sure you've run this script as the right user?\n"
+}
+
diff --git a/wmpinboard.lsm b/wmpinboard.lsm
new file mode 100644
index 0000000..ef3db24
--- /dev/null
+++ b/wmpinboard.lsm
@@ -0,0 +1,11 @@
+Begin3
+Title:          wmpinboard
+Version:        1.0
+Entered-date:   13APR00
+Description:    Window Maker dock applet resembling a miniature pinboard
+Keywords:       WindowMaker WM X11 pinboard notes memo alarm
+Author:         gomar at mindless.com (Marco Goetze)
+Primary-site:   http://www.tu-ilmenau.de/~gomar/stuff/wmpinboard/
+Copying-policy: GPL
+End
+
diff --git a/wmpinboard.spec.in b/wmpinboard.spec.in
new file mode 100644
index 0000000..1c27f90
--- /dev/null
+++ b/wmpinboard.spec.in
@@ -0,0 +1,48 @@
+%define name @PACKAGE@
+%define version @VERSION@
+%define release 1
+%define prefix /usr/local
+
+Summary:	Window Maker dock applet resembling a miniature pinboard
+Name:		%{name}
+Version:	%{version}
+Release:	%{release}
+Copyright:	GPL
+Packager:	Marco Goetze <gomar at mindless.com>
+Url:		http://www.tu-ilmenau.de/~gomar/stuff/%{name}/#download
+Group:		X11/Utilities
+Source:		%{name}-%{version}.tar.gz
+Buildroot:	/home/gomar/Projects/BUILD/%{name}-%{version}-%{release}-root
+Requires:	xpm
+
+%description
+wmpinboard is a Window Maker dock applet resembling a miniature 
+pinboard, intended to somewhat relieve heavily littered desktops by 
+allowing you to place reminders on a graphical on-screen pinboard 
+rather than producing a mess of real notes all around your keyboard.  
+Features include support for arbitrary 6x10 X fonts, XLocale support, 
+drawing capabilities, alarms, animations, themeability, and command 
+line interoperability.
+
+%prep
+%setup
+
+%build
+CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%{prefix}
+if echo "$RPM_OPT_FLAGS" | grep -- -DBUILD_STATIC >/dev/null 2>&1; then
+  make static
+else
+  make
+fi
+
+%install
+make prefix=$RPM_BUILD_ROOT%{prefix} install-strip
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(644,root,root)
+%doc AUTHORS COPYING CREDITS ChangeLog NEWS README TODO %{name}.lsm
+%attr(755,root,root) %{prefix}/bin/%{name}
+%attr(755,root,root) %{prefix}/man/man1/%{name}.1
diff --git a/xpm/abar.xpm b/xpm/abar.xpm
new file mode 100644
index 0000000..fcc2366
--- /dev/null
+++ b/xpm/abar.xpm
@@ -0,0 +1,42 @@
+/* XPM */
+static char * abar_xpm[] = {
+"58 28 11 1",
+" 	c None",
+".	c #000000",
+"+	c #EFD183",
+"@	c #D2AA5C",
+"#	c #6E3A1C",
+"$	c #878787",
+"%	c #6B9600",
+"&	c #AEFA04",
+"*	c #FEFEFC",
+"=	c #87003A",
+"-	c #F73D88",
+"..........................................................",
+".++++++++++++++++++++++++++++++++++++++++++++++++++++++++.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@..@@@@@@@@@@....@@@#.",
+".+@@@@@@@@@@@@@@+$@@@@@@@@@@@@@@@@@@@....@@@@@@@.%%%%.@@#.",
+".+@@@@@@@@@@@@@@..@@@@@@@@@@@@@@@@$........$@@@.%&&%%%.@#.",
+".+@@@@@@@@@@@@@@$#@@@@@@@@@@@@@@@$.@@....@@.$@@.%&&&%%.@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.@@@..@@@@@.@@.%%&%%%.@#.",
+".+@@@@@@@@@@@@@@+$@@@@@@@@@@@@@@@.@@@@@@@@@@.@@.%%%%%%.@#.",
+".+@@@@@@@@@@@@@@..@@@@@@@@@@@@@@@$.@@@@@@@@.$@@@.%%%%.@@#.",
+".+@@@@@@@@@@@@@@$#@@@@@@@@@@@@@@@@$........$@@@@@....@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@...........@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@...........@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.$$$$$$$$..@@@@....@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.***==***..@@@.====.@@#.",
+".+@@@@@@@@@@@@@@+$@@@@@@@@@@@@@@@@.**===***..@@.=--===.@#.",
+".+@@@@@@@@@@@@@@..@@@@@@@@@@@@@@@@.***==***..@@.=---==.@#.",
+".+@@@@@@@@@@@@@@$#@@@@@@@@@@@@@@@@.***==***..@@.==-===.@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.***==***..@@.======.@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.********...@@@.====.@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@...........@@@@@....@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@...........@@@@@@@@@@@@#.",
+".+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.",
+".########################################################.",
+".........................................................."};
diff --git a/xpm/bbar.xpm b/xpm/bbar.xpm
new file mode 100644
index 0000000..7c7aea7
--- /dev/null
+++ b/xpm/bbar.xpm
@@ -0,0 +1,56 @@
+/* XPM */
+static char * bbar_xpm[] = {
+"58 30 23 1",
+" 	c None",
+".	c #000000",
+"+	c #EFD183",
+"@	c #6E3A1C",
+"#	c #D2AA5C",
+"$	c #FA0604",
+"%	c #7F6602",
+"&	c #FF0569",
+"*	c #FFFFFF",
+"=	c #FADA04",
+"-	c #AEFA04",
+";	c #6B9600",
+">	c #F48989",
+",	c #C16C6C",
+"'	c #894E4E",
+")	c #F73D88",
+"!	c #87003A",
+"~	c #9E0EDC",
+"{	c #FE821C",
+"]	c #62A6EF",
+"^	c #3E6599",
+"/	c #2A4668",
+"(	c #F2EE04",
+"..........................................................",
+".+++++++++++++ at +++++++++++++@+++++++++++++ at ++++++++++++++.",
+".+############@+############@+############@+############@.",
+".+####...@$###@+####%.%#####@+##########&#@+#.....#....#@.",
+".+##..*.*.&$##@+####.=.#####@+###.###.#&&#@+#.---.#.;-.#@.",
+".+##.**.**.@##@+###%=.######@+##.#.##.&&##@+#.---.#.--.#@.",
+".+#.***.***.##@+###.=%##..##@+#.###.#&&###@+#.--;.#.--.#@.",
+".+#.***.***.##@+##%=.##.##.#@+#.###.&&..##@+#....##.--.#@.",
+".+#.**.****.##@+##.=%#.####. at +#....&&.##.#@+######.;--.#@.",
+".+##.*****.###@+#%=.##.####. at +#.##&&#.##.#@+#....#.;--.#@.",
+".+##..***..###@+#.=%###.##.#@+#.#&&.#.##.#@+#.-;.##.--.#@.",
+".+##%.....%###@+#..#####..##@+#.&&#.#...##@+#.--;.#.;-.#@.",
+".+#...%#%...##@+#.......##.#@+#&&#########@+#.....##...#@.",
+".+############@+###########. at +############@+############@.",
+".@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.",
+".+++++++++++++ at +++++++++++++@+++++++++++++ at ++++++++++++++.",
+".+############@+####>>>>>>##@+############@+############@.",
+".+#-###......#@+###>,,,,,,'#@+#&#...######@+##########)#@.",
+".+#--###.....#@+###>,,,,,,'#@+#&&###.#####@+#########)!#@.",
+".+#~--###....#@+###>,,,,,,'#@+#.&&###.####@+########)!##@.",
+".+#~~--#.....#@+##>,,,,,,'##@+#.#&&#..####@+########)###@.",
+".+#$~~-...#..#@+##>,,,,,,'##@+#.##&&&.####@+#######)!###@.",
+".+#$$~...###.#@+##>,,,,,,'##@+##.#.#&&####@+#))###))####@.",
+".+#{$...--####@+##]^^,,,,'##@+###...#&&###@+#))))))!####@.",
+".+#{{..~~--###@+#]^^^^^^/###@+###.####&&##@+###)))!#####@.",
+".+#({{$$~~--##@+#]^^^^^^/###@+##.######&&#@+####))!#####@.",
+".+#(({{$$~~--#@+#]^^^^^^/###@+##........&#@+#####!######@.",
+".+############@+##//////####@+############@+############@.",
+".@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.",
+".........................................................."};
diff --git a/xpm/digits.xpm b/xpm/digits.xpm
new file mode 100644
index 0000000..617f4b1
--- /dev/null
+++ b/xpm/digits.xpm
@@ -0,0 +1,15 @@
+/* XPM */
+static char * digits_xpm[] = {
+"60 9 3 1",
+" 	c None",
+".	c #D2AA5C",
+"+	c #000000",
+".+++.........+++...+++.........+++...+++...+++...+++...+++..",
+"+...+.....+.....+.....+.+...+.+.....+.........+.+...+.+...+.",
+"+...+.....+.....+.....+.+...+.+.....+.........+.+...+.+...+.",
+"+...+.....+.....+.....+.+...+.+.....+.........+.+...+.+...+.",
+".............+++...+++...+++...+++...+++.........+++...+++..",
+"+...+.....+.+.........+.....+.....+.+...+.....+.+...+.....+.",
+"+...+.....+.+.........+.....+.....+.+...+.....+.+...+.....+.",
+"+...+.....+.+.........+.....+.....+.+...+.....+.+...+.....+.",
+".+++.........+++...+++.........+++...+++.........+++...+++.."};
diff --git a/xpm/pinboard.xpm b/xpm/pinboard.xpm
new file mode 100644
index 0000000..98f18e7
--- /dev/null
+++ b/xpm/pinboard.xpm
@@ -0,0 +1,136 @@
+/* XPM */
+static char * pinboard_xpm[] = {
+"86 64 69 1",
+" 	c None",
+".	c #D6FE04",
+"+	c #565654",
+"@	c #4E4E4C",
+"#	c #362A14",
+"$	c #121214",
+"%	c #363634",
+"&	c #6BE520",
+"*	c #020204",
+"=	c #60C021",
+"-	c #F22E96",
+";	c #AEFA04",
+">	c #94D205",
+",	c #9A6E2C",
+"'	c #FEFEFC",
+")	c #D5D5D4",
+"!	c #562E1C",
+"~	c #6E3A1C",
+"{	c #8E421C",
+"]	c #0A76EC",
+"^	c #F9F14A",
+"/	c #D1CA45",
+"(	c #F6FE7C",
+"_	c #6A6A6C",
+":	c #FADA04",
+"<	c #D2B705",
+"[	c #FEBE04",
+"}	c #D5A005",
+"|	c #DEC67C",
+"1	c #D6BA6C",
+"2	c #6A361C",
+"3	c #66311C",
+"4	c #D2AA5C",
+"5	c #FE821C",
+"6	c #D5721D",
+"7	c #FE5E1C",
+"8	c #D5561D",
+"9	c #4E2A1C",
+"0	c #FE8E8C",
+"a	c #D57B7A",
+"b	c #FA0604",
+"c	c #C60805",
+"d	c #BF2B79",
+"e	c #AD067E",
+"f	c #8A0868",
+"g	c #D6B66C",
+"h	c #CA9E4C",
+"i	c #8503C6",
+"j	c #6D049D",
+"k	c #2606C4",
+"l	c #24089B",
+"m	c #020684",
+"n	c #040C54",
+"o	c #D2B264",
+"p	c #0B63BA",
+"q	c #8A421C",
+"r	c #0ACAEC",
+"s	c #0CAAC6",
+"t	c #0AEA74",
+"u	c #0CC467",
+"v	c #0EDA1C",
+"w	c #10B71D",
+"x	c #2E8E0C",
+"y	c #2E7B0E",
+"z	c #CEAA5C",
+"A	c #CEA654",
+"B	c #CAA254",
+"C	c #C79849",
+"D	c #C2A454",
+".......................................................................+@#$%#+..&*=...",
+"..................................................................+%*#++-----+..;*>...",
+"......,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#......$++----------%..'*)...",
+"......,!!!~~~~~~~~~~~{{{!!!~~~~~~~~~!!!!~~~~~~!!!!~~~~~~~#......%---]]]]-----*..^*/...",
+"......,~~~~~~!!~~~!(((((~{(((!~~~(((~~~~(((~~!~~~~{{~~{~~#......$-----*_]]]--#..:*<...",
+"......,~~########!~~!(~~~(~~~(~{!(!{(~~(!~~({#########,~~#......$-----_*]]---+..[*}...",
+"......,~~#||||1||1~~~({~!(~~~(~~~(223(2(332(~#44|||111,!~#...... at ----]]------++.5*6...",
+"......,!~#|||1|111~!~(33~(!!~(~~~(222(2(333(2#44|1141|,~~#......*-----]]]]---- at .7'8...",
+"......,~~#|1111111~~9(33~(~~~(~!!({{~({({!!({#4411111|,~~#......++-----]]]----#.0*a...",
+"......,~{#11111111~~~(!!{{(((~~~~((((!33(((33#41111111,{~#.......#--]]]]------$.b'c...",
+"......,~~#41111111!!~~23333999~3~{3~~~3333333#44441111,~!#.......*---]]]]]]---%.-'d...",
+"......,{{#114411111##########################144441141,!~#.......%--------]---_+e'f...",
+"......,{~#1ggggg14144444114444h4444h44h4444hh444444441,{~#.......+------------ at _i'j...",
+"......,~~#1gggg4g1444441411444444444444444444441111114,{{#.......++-----++#*%++.k'l...",
+"......,{~#1gggg444414411111144141414441414144141411111,~~#........#++$$@+.......m'n...",
+"......,{2#11gg4gggo41111114111111111111111111411111111,~~#........_+............]'p...",
+"......,2q#114g44ggoo4gg1111114414411144144114114111111,~~#......................r*s...",
+"......,~2#11g444444444gg111ggoogg441114444411441441111,{~#.......**************.t*u...",
+"......,q2#11gggg44444444444g4ooooo4o4g44444gg141141144,{~#.......*------------*.v*w...",
+"......,3~#11gggoo4gggooo441g444ooooo444ggoogg141144441,~~#.......*------------*.x'y...",
+"......,!2#1444gg444og4444441414444oo4444zzoogz11444444,{~#.......*--]]]*_-----*.......",
+"......,!!#111444o4444zzzzz44444zz4444zzzAzAzz1z1414414,{~#.......*-----_*]]]--*.......",
+"......,!q#11114444zz4zzzzzzzzzzzzzzzzAAAAz44AAA1441444,~~#.......*-----]]]]---*.......",
+"......,!{#44114zzzzAA444zzzzzzAAhzzzABBAh44444zz444414,~~#.......*---]]]------*.......",
+"......,!{#41444zBAAABBAA4144zhhhAAAA4hh114444414411114,~{#.......*-----]]]]---*.......",
+"......,~~#444444z4AAABhAoz444444hAzAh4Ahhz414444441141,~{#.......*------]]]---*.......",
+"......,~~#4144h4hhzhzzg44hhzCAC14444444414444444444111,!~#.......*--]]]]]-----*.......",
+"......,{{#4444444A4zzhBAhBAz1zzz44zzDAABAzz44444444g11,~~#.......*----]]]]]]--*.......",
+"......,{~#114444hhhhz44AAAAzz44A44zzzBzzzAz4444444og11,~~#.......*---------]--*.......",
+"......,~~#1111444AAAhBz4AAAzzo4444z44o4zzzz4444444ogg1,{~#.......*------------*.......",
+"......,{{#1111414444zzzzzzzzzzz4444z4z444AA4zAAzz44gg4,~~#.......**************.......",
+"......,~~#1144141g4oo4zzzzzzzz11zzzz444444444og1goo4g1,~~#............................",
+"......,~~#|||11441444zz1zzzzzzzzzzzzzzzzzzAzzzzooz4414,~~#.........#%$#@+.............",
+"......,!{#114444444zzzzzzzzzAAAzzzzzzzzzzzzzzzz4zz4441,{~#........++----++#*%+........",
+"......,!~#44444444zzzzzzzzAzAAA4zzzzzz444zAAzzz4zz1414,{~#........%----------++$......",
+"......,!!#|1|114144zzzzzzz4zAAAA4AAzz4zgz44zzhzzoz1111,!~#........*--]]]]------%......",
+"......,!~#11144444444zzAzzz4BCCB44ChA444CCChhhzzoz1111,~~#........#-----_*]]---$......",
+"......,!~#444444444441zhhAhC444CCC4BCCCC4CzAAA4ozo4414,{~#........+----]*_]----$......",
+"......,!~#1114444444zz4zAAAA44444444444444444zAoooo414,{{#.......++---]]------- at ......",
+"......,{~#444444ooo4z444zAAAABBDAC4CC4AA4BAzzAAzooo444,~~#....... at -----]]]]----*......",
+"......,~~#4444444444444zzzAAABBCAA4444Dz4Azzzzzo44o414,{{#.......#------]]]---++......",
+"......,!!#444go4o444444444AAABBA44ACDBD4A4z4zCz4o4g111,!~#.......$---]]]]-----#.......",
+"......,{{#414444444444444414444444444BCzC4CCChA4o4g111,~!#.......+----]]]]]]--*.......",
+"......,~{#4444444444444hhAh44444444zC444C444444o414414,{!#...... at +---------]--%.......",
+"......,~{#4414444444444zzA4444AC444444444A44444og11414,{!#......_ at ------------+.......",
+"......,{~#144444ggo4444444zzzz4444zz44zzAhz44444g11444,~!#.......++%*#++-----++.......",
+"......,~!#41144444zzzAz44444zzzzzzzzz44zzzz444z4441444,!!#.............+@$$++#........",
+"......,~~#4444444hhhCzz44444o4zzzzz44144zzA44zzzz44444,{!#..................+_........",
+"......,~~#44444444zAhABzz44444zzzzz44z1144z4zz4444444h,~~#............................",
+"......,~{#44444444zzz44zzzzz44zzzzzzAAzzz44zzz4g414414,~!#............................",
+"......,~{#144444414zz44zAzAAACCzzz44ACCzz4CzBzzg111414,~~#............................",
+"......,!~#114444441zzh444444444444444444zACDAzz4111444,~~#............................",
+"......,!~#444444444zAhC4CCC4444CCACC44CCCACCAA44441444,~{#............................",
+"......,!~#h444444444zAA4hB44DABBBAzAAz4zzzzzzz44444444,~{#............................",
+"......,~~#444411114g4zzzAAA4zzzADAAzzz44zz44444444444h,~!#............................",
+"......,~~#444444444444h44444zzzC444h444h4hhh4444444h44,{!#............................",
+"......,~~#hhhh44444hhhhhhh444zhhhhhh44hhhhhhh444444hh4,~!#............................",
+"......,~~#4hhh44444444h44444444444444444444444h4444411,~~#............................",
+"......,~!#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,~~#............................",
+"......,!~~!~~~~~~~~~{{{{{{{!~~~~{{{{!!!{{{{{{~{~~~~~{~~~{#............................",
+"......,~~~~~{{{!!{~~~~~~!!!!!~~~~!~~~{{~~~~~~{{~{{~~~!!!{#............................",
+"......,###################################################............................",
+"......................................................................................",
+"................................................................................-.]..."};

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-wmaker/wmpinboard.git



More information about the Pkg-wmaker-commits mailing list