From:
https://web.archive.org/web/20021210035511/http://lucille.dhs.org/washerDryer-1.1.tar.bz2
---
 washerdryer/COPYING                          |  339 ++++++++
 washerdryer/Changelog                        |   14 +
 washerdryer/INSTALL                          |   19 +
 washerdryer/README                           |   67 ++
 washerdryer/washerDryer/.washerDryer.c.swp   |  Bin 0 -> 57344 bytes
 washerdryer/washerDryer/Makefile             |   52 ++
 washerdryer/washerDryer/man/washerDryer.1.gz |  Bin 0 -> 772 bytes
 washerdryer/washerDryer/washerDryer.c        | 1181 ++++++++++++++++++++++++++
 washerdryer/washerDryer/wdryer.xpm           |  112 +++
 washerdryer/washerDryer/wdryerrc             |   24 +
 washerdryer/wmgeneral/list.c                 |  165 ++++
 washerdryer/wmgeneral/list.h                 |   61 ++
 washerdryer/wmgeneral/misc.c                 |  229 +++++
 washerdryer/wmgeneral/misc.h                 |    9 +
 washerdryer/wmgeneral/wmgeneral.c            |  444 ++++++++++
 washerdryer/wmgeneral/wmgeneral.h            |   62 ++
 16 files changed, 2778 insertions(+)
 create mode 100644 washerdryer/COPYING
 create mode 100644 washerdryer/Changelog
 create mode 100644 washerdryer/INSTALL
 create mode 100644 washerdryer/README
 create mode 100644 washerdryer/washerDryer/.washerDryer.c.swp
 create mode 100644 washerdryer/washerDryer/Makefile
 create mode 100644 washerdryer/washerDryer/man/washerDryer.1.gz
 create mode 100644 washerdryer/washerDryer/washerDryer.c
 create mode 100644 washerdryer/washerDryer/wdryer.xpm
 create mode 100644 washerdryer/washerDryer/wdryerrc
 create mode 100644 washerdryer/wmgeneral/list.c
 create mode 100644 washerdryer/wmgeneral/list.h
 create mode 100644 washerdryer/wmgeneral/misc.c
 create mode 100644 washerdryer/wmgeneral/misc.h
 create mode 100644 washerdryer/wmgeneral/wmgeneral.c
 create mode 100644 washerdryer/wmgeneral/wmgeneral.h

diff --git a/washerdryer/COPYING b/washerdryer/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/washerdryer/COPYING
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, 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
+
+       Appendix: 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) 19yy  <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., 675 Mass Ave, Cambridge, MA 02139, 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) 19yy 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/washerdryer/Changelog b/washerdryer/Changelog
new file mode 100644
index 0000000..3c5d32e
--- /dev/null
+++ b/washerdryer/Changelog
@@ -0,0 +1,14 @@
+September 21, 2001 : washerDryer-1.0
+    Mike Foley <fo...@ucsd.edu> :
+    - Initial release.
+
+December 18, 2001 : washerDryer-1.0.1
+    Mike Foley <fo...@ucsd.edu> :
+    - Updated CFLAGS in Makefile to be compatible with most Linux 
distributions.
+
+March 23, 2002 : washerDryer-1.1
+    Mike Foley <fo...@ucsd.edu> :
+    - Added feature to change process times on the fly.
+    - Configuration window no longer automatically closes.
+    - Replaced strcpy calls with strncpy
+
diff --git a/washerdryer/INSTALL b/washerdryer/INSTALL
new file mode 100644
index 0000000..a1a5df9
--- /dev/null
+++ b/washerdryer/INSTALL
@@ -0,0 +1,19 @@
+Requirements
+------------
+* UNIX compatible system running X11
+* GTK libraries
+
+Installation
+------------
+1)  % cd washerDryer
+2)  % make
+3)  % make install
+
+    Install is optional. Must be root to install.
+    If any problems with make or make install, try editing the Makefile.
+
+4)  % vi ~/.wdryerrc
+
+    Adjust ~/.wdryerrc to your preferences.
+
+5)  % washerDryer &
diff --git a/washerdryer/README b/washerdryer/README
new file mode 100644
index 0000000..df28919
--- /dev/null
+++ b/washerdryer/README
@@ -0,0 +1,67 @@
+washerDryer-1.1  Public Release
+Mike Foley (fo...@ucsd.edu)
+
+washerDryer keeps track of the loads in your washer and
+dryer, and alerts you when they are ready.
+
+I'm bad at remembering when to take my clothes out, so I wrote
+this program to help me. Hopefully other people will find it
+useful as well.
+
+Some features are:
+
+    * Keeps track of up to 10 loads at once
+    * Alerts you with system beep, or any command you specify
+    * Fully compatible with WindowMaker as a dockapp
+    * Command line options (-h for help)
+    * Customize the program through config file, command line
+      options, or on the fly
+       
+
+Files
+--------------------------------------------------------------
+README      This file.
+INSTALL     Installation instructions.
+Changelog   Description of changes.
+COPYING     GNU General Public License Version 2.
+     
+
+Program Usage
+--------------------------------------------------------------
+Please read the man page for details.
+
+
+Credits
+--------------------------------------------------------------
+This application started out as a heavily modified version of
+WMTimer 2.2, written by Josh King. The source code provided
+the framework for my program, and it was an invaluable
+resource.
+
+I used methods from the wmgeneral libraries, written by
+Martijn Pieterse. The wmgeneral libraries make it much easier
+to write dockapps.
+
+I used the config file reading methods from WMiNET 2.0.3,
+written by Dave Clark, Antoine Nulle, and Martijn Pieterse.
+I also used some of its documentation as a framework for mine.
+
+
+Bugs & Feedback
+--------------------------------------------------------------
+If you discover any bugs in this software, or have any
+suggestions about the program, please send a report to
+the author.
+
+I appreciate user feedback. If you find this program useful,
+send me an email. I would be glad to know if I helped people
+out there who are as disorganized as I am!
+
+
+Copyright
+--------------------------------------------------------------
+washerDryer 1.1 is copyright (c) 2001 by Mike Foley
+
+washerDryer 1.1 is licensed through the GNU General Public License.
+Read the COPYING file for the complete GNU license.
+
diff --git a/washerdryer/washerDryer/.washerDryer.c.swp 
b/washerdryer/washerDryer/.washerDryer.c.swp
new file mode 100644
index 
0000000000000000000000000000000000000000..11454bb8c173c0f6ee921735617f3950b7a91c1e
GIT binary patch
literal 57344
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

literal 0
HcmV?d00001

diff --git a/washerdryer/washerDryer/Makefile b/washerdryer/washerDryer/Makefile
new file mode 100644
index 0000000..71e8674
--- /dev/null
+++ b/washerdryer/washerDryer/Makefile
@@ -0,0 +1,52 @@
+LIBDIR = -L/usr/X11R6/lib -L/usr/lib -L/opt/gnome/lib
+LIBS   = -lXpm -lXext -lX11 -lm  -lgtk -lgdk -rdynamic -lgmodule -lglib -ldl 
+CFLAGS = -I/usr/X11R6/include -I/usr/lib/glib/include 
-I/opt/gnome/include/gtk-1.2 -I/opt/gnome/include/glib-1.2 
-I/opt/gnome/lib/glib/include
+OBJS = washerDryer.o \
+               ../wmgeneral/wmgeneral.o \
+               ../wmgeneral/misc.o \
+               ../wmgeneral/list.o
+
+.c.o:
+       cc -c -O2 -Wall $< -o $*.o $(CFLAGS)
+
+washerDryer: $(OBJS)
+       cc -Wall -pedantic -o washerDryer $^ $(LIBDIR) $(LIBS)
+
+all:: washerDryer
+
+clean::
+       for i in $(OBJS) ; do \
+               rm -f $$i; \
+       done
+       rm -f washerDryer
+
+install::   washerDryer
+       @echo
+       @echo "Installing config file..."
+       cp wdryerrc $(HOME)/.wdryerrc
+       chmod 600 $(HOME)/.wdryerrc
+       @echo
+       @echo "Installing executable..."
+       cp -f washerDryer /usr/local/bin/
+       chmod 755 /usr/local/bin/washerDryer
+       chown root:root /usr/local/bin/washerDryer
+       @echo
+       @echo "Installing man page..."
+       cp -f man/washerDryer.1.gz /usr/man/man1/
+       chmod 644 /usr/man/man1/washerDryer.1.gz
+       @echo
+       @echo "washerDryer installation finished."
+
+uninstall::
+       @echo
+       @echo "Removing executable..."
+       rm -f /usr/local/bin/washerDryer
+       @echo
+       @echo "Removing config file..."
+       rm -f $(HOME)/.wdryerrc
+       @echo
+       @echo "Removing man page..."
+       rm -f /usr/man/man1/washerDryer.1.gz
+       @echo
+       @echo "washerDryer uninstall finished."
+
diff --git a/washerdryer/washerDryer/man/washerDryer.1.gz 
b/washerdryer/washerDryer/man/washerDryer.1.gz
new file mode 100644
index 
0000000000000000000000000000000000000000..5894b23e83a94be8080ca546dd71baf320b27c12
GIT binary patch
literal 772
zcmV+f1N;0RiwFq8be%i^19xF_Xk~Ila(QKPE-?U|Rl#oCFbuuxD~Md$0*SW_I~BvQ
zw#m?7Z4<;Px?$NtmFZZBY#EXqFPDA$C|OR@qL=Mtiy_}5pB|lLbqg)G1)7Q3qk%CD
zK8!~x)}#010ZY<bc(}TsveT3il)92m8w=KP*I3Xw>~&)z5b!F4%%_I>^vA<|k<L<<
zT%R(rpX*Vv`vvq6u+C?>R9Nv6*ZCp@pL|eOu0Ky+om+nvx-5yUk7ci7fqybhZ<e#g
zYBqmh-w<mH&Tz5yO}hd?C`}IwvO3Nns|}P~&=ZftBy3&@^hs1_bPF7m=9w?_IB|Au
zy6hnVOV85%%In(b+DPsYr0_uvLN}FzOt)Q%lO@7=gpszdRG7PAhuMdW+!XF2VXF?9
zc({}FTPu~Kd>4A$R@7o!U>vJ!)e;@e^t=a@&htEzAbwhE8-Jr{oIh}g8WJ1t&}@xD
z=KF-P8(rmc)0jYMfg1!%lu-pEz+WVsTSWLeyPKvL!yuvH6_J4`c(uWdT6M*NMR}cd
z9RP>El{jav_FbYs^t`0BtVpy3R&PXm9xj~Rk=U7^HQYp)vcoMobz5`edJm9@N$|>G
z9(<Ax*gC&HG3z>C5~RS|*{(CKlx{ubTQgj;WVL{gjGWCLEk^MqH6ud1L81gEnDa(C
ze=B6$Kkt$@+_DkGc0hPyDXAO0k?VfLhF<PcR*gfO98xDQQ=<*v%4|bsv|60N>q(vT
z^8_!Ekew_1jUB8M>rNfzX{<vEL`AbWo842mBp{`Z^jV<qEd9^yUD^MW7i?kZGeXXV
z0#yxG7$odyjnnHql<fKvpRq$@{jya}`Fvc-mv!W%;C*&>b{0WiU+^WoSfpqPia9c;
z_2_6ceOl?Wu`#^#JLY$j_Jfl&G-z8$Q3ShlW%cQ99k-`5bvm8G)m=KL5AYJ&l5eT)
z^YO(noWJ|mkaqRBx}7iCz1-5~YK43FRE~51@}&_rOE7Cb58?3Vkg&f|hUua^1^@sd
C|9n0G

literal 0
HcmV?d00001

diff --git a/washerdryer/washerDryer/washerDryer.c 
b/washerdryer/washerDryer/washerDryer.c
new file mode 100644
index 0000000..89eed3a
--- /dev/null
+++ b/washerdryer/washerDryer/washerDryer.c
@@ -0,0 +1,1181 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/wait.h>
+#include <X11/xpm.h>
+#include <gtk/gtk.h>
+
+#include "../wmgeneral/wmgeneral.h"
+#include "../wmgeneral/misc.h"
+#include "wdryer.xpm"
+
+#define CHAR_WIDTH 5
+#define CHAR_HEIGHT 7
+#define VERSION "1.1"
+
+/* function headers */
+int Read_Config_File(char* filename);
+void DrawStatus(int intProcNum, int intStatus);
+void DecrementTimer ();
+void ExecAction (char chrType);
+void displayUsage ();
+int configure_washerdryer ();
+void callback (GtkWidget * widget, gpointer data);
+int delete_event (GtkWidget * widget, GdkEvent * event, gpointer data);
+void destroy (GtkWidget * widget, gpointer data);
+void destroyAndReloadConfig(GtkWidget* widget);
+
+/* globals */
+//I put these Widgets here to grab
+//text in event handler (callback)
+static GtkWidget *wEntry;
+static GtkWidget *dEntry;
+static GtkWidget *txtNewTime;
+static GtkWidget *mainConfigWindow;
+
+char cmdDry[256];
+char *commandDry = cmdDry;
+char cmdWash[256];
+char *commandWash = cmdWash;
+char wdryer_mask_bits[64 * 64];
+int wdryer_mask_width = 64;
+int wdryer_mask_height = 64;
+
+int wInCommandMode = 0;      // 0 = default/bell     1 = command
+int dInCommandMode = 0; 
+
+int tmp_wInCmdMode = 0;
+int tmp_dInCmdMode = 0;
+int oldsec = 0;
+
+//starting times of washer and dryer
+int intDefaultWasherTime = 0;
+int intDefaultDryerTime = 0;
+int intStartingTimes[10] = {0,0,0,0,0,0,0,0,0,0};
+
+//washer and dryer processes
+int intMin[10]   = {0,0,0,0,0,0,0,0,0,0};
+int intSec[10]   = {0,0,0,0,0,0,0,0,0,0};
+char chrType[10] = {'w','w','w','w','w',
+                    'w','w','w','w','w'};
+//for drawing status
+int intPrevStatus[10] = {0,0,0,0,0,0,0,0,0,0};
+
+
+/*************
+* main method
+*************/
+int main (int argc, char *argv[])
+{
+  char config_file[256] = {'\0'};
+  int intFreeChk;
+  int intFullCount = 0;
+  int i, intTemp;
+  XEvent Event;
+  int buttonStatus = -1;
+  long starttime;
+  long curtime;
+  struct tm *time_struct;
+  struct tm old_time_struct;
+
+  //gtk_init (&argc, &argv);
+
+  commandDry[0] = '\0';
+  commandWash[0] = '\0';
+
+  //parse command line
+  for (i = 1; i < argc; i++)
+  {
+    char *arg = argv[i];
+    if (*arg == '-')
+    {
+      switch (arg[1])
+      {
+        case 'd':
+          if(argc > (i+1))
+          {
+            strncpy(commandDry, argv[i + 1], 256);
+            ++i;
+            dInCommandMode = 1;
+          }
+          break;
+        case 'w':
+          if(argc > (i+1))
+          {
+            strncpy (commandWash, argv[i + 1], 256);
+            ++i;
+            wInCommandMode = 1;
+          }
+          break;
+        case 'W':
+          if(argc > (i+1))
+          {
+              intDefaultWasherTime = atoi(argv[i+1]);
+              for(intTemp = 0; intTemp < 10; ++intTemp)
+                  intStartingTimes[intTemp] = atoi(argv[i+1]);
+              ++i;
+          }
+          break;
+        case 'D':
+          if(argc > (i+1))
+          {
+              intDefaultDryerTime = atoi(argv[i+1]);
+              ++i;
+          }
+          break;
+        case 'v':
+          printf ("%s\n", VERSION);
+          _exit (0);
+          break;
+        case 'c':
+          if(argc > (i+1))
+          {
+            strncpy(config_file, argv[i+1], 256);
+            ++i;
+          }
+          break;
+        default:
+          fprintf(stderr, "Unrecognized option: %s\n", arg);
+          displayUsage ();
+          _exit (0);
+          break;
+      }
+    }
+    else
+    {
+        fprintf(stderr, "Unrecognized option: %s\n", arg);
+        displayUsage ();
+    }
+  }
+
+  //read config file
+  if(config_file[0] != 0)
+  {
+    //fprintf(stderr, "Using user-specified config file '%s'.\n", config_file);
+    Read_Config_File(config_file);
+  }
+  else
+  {
+    sprintf(config_file, "%s/.wdryerrc", getenv("HOME"));
+    Read_Config_File(config_file);
+  }
+
+  //insure sanity
+  if(intDefaultWasherTime < 1)
+    intDefaultWasherTime = 1;
+  if(intDefaultDryerTime < 1)
+    intDefaultDryerTime = 1;
+  for(intTemp = 0; intTemp<10; ++intTemp)
+  {
+      if(intStartingTimes[intTemp] < 1)
+        intStartingTimes[intTemp] = 1;
+  }
+
+
+  gtk_init (&argc, &argv);
+  createXBMfromXPM (wdryer_mask_bits, wdryer_xpm, wdryer_mask_width,
+        wdryer_mask_height);
+
+  openXwindow (argc, argv, wdryer_xpm, wdryer_mask_bits, wdryer_mask_width,
+         wdryer_mask_height);
+
+  //setMaskXY(-64, 0);
+
+  //clickable regions
+  AddMouseRegion (0, 8, 6, 28, 24); //0: washer
+  AddMouseRegion (1, 32, 6, 52, 24); //1: dryer 
+  AddMouseRegion (2, 6, 26, 57, 57); //2: main area
+
+  starttime = time (0);
+  curtime = time (0);
+
+  time_struct = localtime (&curtime);
+
+  /*****************************
+  * while program is running...
+  *****************************/
+  while (1)
+  {
+    curtime = time (0);
+
+    waitpid (0, NULL, WNOHANG);
+
+    old_time_struct = *time_struct;
+    time_struct = localtime (&curtime);
+
+    if (curtime >= starttime)
+    {
+        //decrement timer, draw status
+        if (oldsec < time_struct->tm_sec)
+          DecrementTimer ();
+        oldsec = (time_struct->tm_sec); 
+
+        RedrawWindow ();
+
+        // X Events
+        while (XPending (display))
+        {
+            XNextEvent (display, &Event);
+            switch (Event.type)
+            {
+                case Expose:
+                    RedrawWindow ();
+                    break;
+                case DestroyNotify:
+                    XCloseDisplay (display);
+                    _exit (0);
+                    break;
+                case ButtonPress:
+                    i = CheckMouseRegion (Event.xbutton.x, Event.xbutton.y);
+                    buttonStatus = i;
+                    if (buttonStatus == i && buttonStatus >= 0)
+                    {
+                        switch (buttonStatus)
+                        {
+                            /*****************
+                            * click on washer
+                            *****************/
+                            case 0:
+                              intFullCount = 0;
+                              for(intFreeChk=0;intFreeChk<10;++intFreeChk)
+                              {
+                                if(  (intSec[intFreeChk] == 0) &&
+                                  (intMin[intFreeChk] == 0) &&
+                                  (intFullCount < 5))
+                                {
+                                  intMin[intFreeChk] = intDefaultWasherTime;
+                                  intStartingTimes[intFreeChk] = 
intDefaultWasherTime;
+                                  chrType[intFreeChk] = 'w';
+                                  break;
+                                }
+                                if(chrType[intFreeChk] == 'w')
+                                  ++intFullCount;
+                              }
+                              break;
+                            /****************
+                            * click on dryer
+                            ****************/
+                            case 1:
+                              intFullCount = 0;
+                              for(intFreeChk=0;intFreeChk<10;++intFreeChk)
+                              {
+                                if((intSec[intFreeChk] == 0) &&
+                                  (intMin[intFreeChk] == 0) &&
+                                  (intFullCount < 5))
+                                {
+                                  intMin[intFreeChk] = intDefaultDryerTime;
+                                  intStartingTimes[intFreeChk] = 
intDefaultDryerTime;
+                                  chrType[intFreeChk] = 'd';
+                                  break;
+                                }
+                                if(chrType[intFreeChk] == 'd')
+                                  ++intFullCount;
+                              }
+                              break;
+                            /***************
+                            * click on main
+                            ***************/    
+                            case 2:  // main area
+                                //open GUI
+                                configure_washerdryer ();
+                                break;
+                        } //end switch
+                    } //end if
+
+                    break;
+
+                case ButtonRelease:
+                    i = CheckMouseRegion (Event.xbutton.x, Event.xbutton.y);
+
+                    if (buttonStatus == i && buttonStatus >= 0)
+                    {
+                        switch (buttonStatus)
+                        {
+                            case 0:
+                                break;
+                            case 1:
+                                break;
+                            case 2:
+                                break;
+                            case 3:
+                                break;
+                            case 4:
+                                break;
+                            case 5:
+                                break;
+                        }
+                    }
+                    buttonStatus = -1;
+                    RedrawWindow ();
+                    break;
+
+            } //end switch Event.type
+
+        } //end X events
+
+        usleep (100000L);
+
+    } //end big if
+
+  } //end infinite loop
+
+  return 0;
+
+} //end main
+
+/***********************************
+* Draws status bar. Given the slot
+* number (intProcNum) and the
+* percentage completed (intStatus),
+* implements the copyXPMArea
+* command on the xpm file.
+***********************************/
+void DrawStatus(int intProcNum, int intStatus)
+{
+  int intXPMx;
+
+  //error correcting
+  if((intProcNum > 9) || (intProcNum < 0))
+    return;
+  if(intStatus > 100)
+    intStatus = 100;
+  if(intStatus < 0)
+    intStatus = 0;
+
+  //location of image on xpm
+  //just accept the math :-)
+  intXPMx = ((100 - intStatus) * 9) / 10;
+  intXPMx = intXPMx - (intXPMx%3);
+
+  //draws if necessary
+  if(intPrevStatus[intProcNum] != intXPMx)
+  {
+    copyXPMArea (intXPMx, 64,
+      3, 30,
+      8 + intProcNum*5, 27);
+   
+    intPrevStatus[intProcNum] = intXPMx;
+  }
+}
+
+/******************************
+* calls DrawStatus, decrements
+* timer, and executes command
+* or beep if timer reaches zero
+*******************************/
+void DecrementTimer ()
+{
+  int intCurrWDisplay = 0;
+  int intCurrDDisplay = 0;
+  int intCtr;
+  int intStatus;
+  //for each instance...
+  for(intCtr=0; intCtr < 10; ++intCtr)
+  {
+    /*******
+    * draws
+    *******/
+    //calculate percentage
+    intStatus = ((
+      (intMin[intCtr] * 60) +
+      intSec[intCtr])
+      * 100)
+      / (intStartingTimes[intCtr]*60);
+
+    //draw status bar
+    if((chrType[intCtr] == 'w') && (intCurrWDisplay < 5))
+    {
+      DrawStatus(intCurrWDisplay, intStatus);
+      ++intCurrWDisplay;
+    }
+    else if(intCurrDDisplay < 10)
+    {
+      DrawStatus(5 + intCurrDDisplay, intStatus);
+      ++intCurrDDisplay;
+    }
+
+    /*****************
+    * decrements time
+    *****************/
+    //if it's already 0, don't decrement it
+    if((intSec[intCtr] == 0) && (intMin[intCtr] == 0))
+      continue;
+
+    --intSec[intCtr];
+    if (intSec[intCtr] == -1)
+    {
+      intSec[intCtr] = 59;
+      --intMin[intCtr];
+    }
+
+    //executes action/beeps, if necessazry
+    if (intSec[intCtr] == 0 && intMin[intCtr] == 0)
+      ExecAction (chrType[intCtr]);
+
+  } //end for
+
+}
+
+/***************************
+* executes action, or beeps
+***************************/
+void ExecAction (char chrType)
+{
+  if(chrType == 'd')
+  {
+    if (dInCommandMode)
+    {
+      execCommand (commandDry);
+    }
+    else
+    {
+      printf ("\07"); //beep
+      fflush (stdout);
+    }
+  }
+  else
+  {
+    if (wInCommandMode)
+    {
+      execCommand (commandWash);
+    }
+    else
+    {
+      printf ("\07"); //beep
+      fflush (stdout);
+    }
+  }
+}
+
+/*************************
+* gives command line help
+*************************/
+void displayUsage (void)
+{
+  fprintf (stderr, "\nwasherDryer - by Mike Foley <fo...@ucsd.edu>\n\n");
+  fprintf (stderr, "usage:\n");
+  fprintf (stderr, "    -c    <filename> use specified config file\n");
+  fprintf (stderr, "    -W    <int> washer time\n");
+  fprintf (stderr, "    -D    <int> dryer time\n");
+  fprintf (stderr, "    -w    <command> washer command (system bell is 
default)\n");
+  fprintf (stderr, "    -d    <command> dryer command (system bell is 
default)\n");
+  fprintf (stderr, "    -h    this help screen\n");
+  fprintf (stderr, "    -v    print the version number\n\n");
+  _exit (0);
+}
+
+/**********************
+* handles click events
+* in GUI window
+**********************/
+void callback (GtkWidget * widget, gpointer data)
+{
+  int intProcToChange;
+  GtkWidget *dialog, *btnOK, *lblMain;
+  char strInputText[4];
+
+  //fprintf(stderr,"event received: %s\n", (char *)data);
+  /*****************************
+  * if user clicked bell button
+  *****************************/
+  if ((char *) data == "d_bell_button") {
+    tmp_dInCmdMode = 0;
+    gtk_entry_set_text (GTK_ENTRY (dEntry), "");
+    gtk_entry_set_editable (GTK_ENTRY (dEntry), FALSE);
+  }
+  else if ((char *) data == "w_bell_button") {
+    tmp_wInCmdMode = 0;
+    gtk_entry_set_text (GTK_ENTRY (wEntry), "");
+    gtk_entry_set_editable (GTK_ENTRY (wEntry), FALSE);
+  }
+
+  /********************************
+  * if user clicked command button
+  ********************************/
+  else if ((char *) data == "d_command_button") {
+    tmp_dInCmdMode = 1;
+    gtk_entry_set_editable (GTK_ENTRY (dEntry), TRUE);
+    gtk_entry_set_text (GTK_ENTRY (dEntry), commandDry);
+  }
+  else if ((char *) data == "w_command_button") {
+    tmp_wInCmdMode = 1;
+    gtk_entry_set_editable (GTK_ENTRY (wEntry), TRUE);
+    gtk_entry_set_text (GTK_ENTRY (wEntry), commandWash);
+  }
+
+  /********************
+  * if user clicked ok
+  ********************/
+  else if ((char *) data == "ok")
+  {
+    if (tmp_dInCmdMode == 1)
+      strncpy (commandDry, gtk_entry_get_text (GTK_ENTRY (dEntry)), 256);
+    if (tmp_wInCmdMode == 1)
+      strncpy (commandWash, gtk_entry_get_text (GTK_ENTRY (wEntry)), 256);
+    wInCommandMode = tmp_wInCmdMode;
+    dInCommandMode = tmp_dInCmdMode;
+  }
+  /************************
+  * if user changed a time
+  ************************/
+  else if(strstr((char *) data, "Change_"))
+  {
+      intProcToChange = ((char *)data)[7] - 48;
+
+      //min = sec = starting time = new time
+      intMin[intProcToChange] = intSec[intProcToChange] =
+        intStartingTimes[intProcToChange] =
+        atoi(gtk_entry_get_text(GTK_ENTRY (txtNewTime)));
+
+      if(intMin[intProcToChange] == 0)
+      {
+        intSec[intProcToChange] =
+          intStartingTimes[intProcToChange] = 1;
+      }
+
+      //fprintf(stderr, "intMin[%i], intStartingTimes[%i] changed to %i, %i\n",
+      //  intProcToChange, intProcToChange, intMin[intProcToChange],
+      //  intStartingTimes[intProcToChange]);
+  }
+  /************************
+  * if user clicked cancel
+  ************************/
+  else if (!strcmp ((char *) data, "cancel"))
+  {
+  }
+
+  /***********************
+  * if user clicked clear
+  ***********************/
+  /*if (!strcmp ((char *) data, "clear"))
+  {
+    commandDry[0] = '\0';
+    commandWash[0] = '\0';
+    gtk_entry_set_text (GTK_ENTRY (dEntry), commandDry);
+    gtk_entry_set_text (GTK_ENTRY (wEntry), commandWash);
+  }*/
+
+  /************************************
+  * if user clicked one of the Deletes
+  ************************************/
+  else if(strstr((char *) data, "Delete"))
+  {
+    intProcToChange = ((char *)data)[6] - 48;
+    intMin[intProcToChange] = 0;
+    intSec[intProcToChange] = 0;
+  }
+
+  /****************************************
+  * if user clicked one of the Change btns
+  ****************************************/
+  else if(strstr((char *) data, "Change"))
+  {
+    intProcToChange = ((char *)data)[6] - 48;
+
+    /* Create the widgets */
+    dialog = gtk_dialog_new();
+
+    lblMain = gtk_label_new("New time (min):");
+
+    txtNewTime = gtk_entry_new_with_max_length(3);
+    sprintf(strInputText, "%i", intMin[intProcToChange]);
+    gtk_entry_set_text((GtkEntry *)txtNewTime, (char *)strInputText);
+
+    btnOK = gtk_button_new_with_label("Ok");
+    //sprintf(buffer, "Change_%i", intProcToChange);
+    //I am so dumb
+      switch(intProcToChange)
+      {
+          case 0:
+            gtk_signal_connect (GTK_OBJECT (btnOK), "clicked",
+                GTK_SIGNAL_FUNC (callback), (gpointer) "Change_0");
+            break;
+          case 1:
+            gtk_signal_connect (GTK_OBJECT (btnOK), "clicked",
+                GTK_SIGNAL_FUNC (callback), (gpointer) "Change_1");
+            break;
+          case 2:
+            gtk_signal_connect (GTK_OBJECT (btnOK), "clicked",
+                GTK_SIGNAL_FUNC (callback), (gpointer) "Change_2");
+            break;
+          case 3:
+            gtk_signal_connect (GTK_OBJECT (btnOK), "clicked",
+                GTK_SIGNAL_FUNC (callback), (gpointer) "Change_3");
+            break;
+          case 4:
+            gtk_signal_connect (GTK_OBJECT (btnOK), "clicked",
+                GTK_SIGNAL_FUNC (callback), (gpointer) "Change_4");
+            break;
+          case 5:
+            gtk_signal_connect (GTK_OBJECT (btnOK), "clicked",
+                GTK_SIGNAL_FUNC (callback), (gpointer) "Change_5");
+            break;
+          case 6:
+            gtk_signal_connect (GTK_OBJECT (btnOK), "clicked",
+                GTK_SIGNAL_FUNC (callback), (gpointer) "Change_6");
+            break;
+          case 7:
+            gtk_signal_connect (GTK_OBJECT (btnOK), "clicked",
+                GTK_SIGNAL_FUNC (callback), (gpointer) "Change_7");
+            break;
+          case 8:
+            gtk_signal_connect (GTK_OBJECT (btnOK), "clicked",
+                GTK_SIGNAL_FUNC (callback), (gpointer) "Change_8");
+            break;
+          case 9:
+            gtk_signal_connect (GTK_OBJECT (btnOK), "clicked",
+                GTK_SIGNAL_FUNC (callback), (gpointer) "Change_9");
+            break;
+      }
+    /* Ensure that the dialog box is destroyed when the user clicks ok. */
+    //###
+    /*
+    gtk_signal_connect_object(GTK_OBJECT(btnOK),
+      "clicked", gtk_widget_destroy, GTK_OBJECT(dialog));
+    gtk_signal_connect_object (GTK_OBJECT (btnOK),
+      "clicked", gtk_widget_destroy, GTK_OBJECT (mainConfigWindow));
+    */
+    gtk_signal_connect_object (GTK_OBJECT (btnOK),
+      "clicked", destroyAndReloadConfig, GTK_OBJECT (dialog));
+
+    /* add stuff */
+    //gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), lblMain);
+    //gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area), 
btnOK);
+    //gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), txtNewTime);
+    gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area),
+      btnOK, TRUE, TRUE, 0);
+    gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->vbox),
+      lblMain, TRUE, TRUE, 0);
+    gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->vbox),
+      txtNewTime, TRUE, TRUE, 0);
+    gtk_widget_show_all (dialog);
+  }
+}
+
+/* This callback quits the program */
+int delete_event (GtkWidget * widget, GdkEvent * event, gpointer data)
+{
+  return (FALSE);
+}
+
+//destroys a widget, plus reloads mainConfigWindow
+void destroyAndReloadConfig(GtkWidget* widget)
+{
+  if(widget != NULL)
+    gtk_widget_destroy(widget);
+  gtk_widget_destroy(mainConfigWindow);
+  configure_washerdryer();
+}
+
+//destroys window 
+void destroy (GtkWidget * widget, gpointer data)
+{
+  gtk_main_quit ();
+}
+
+/******************************
+* pops up configuration window
+******************************/
+int configure_washerdryer ()
+{
+  int intLoadsIn = 0;
+  int intProcNo;
+  char buffer[32];
+  char bufferChangeBtn[16];
+  int intTimeElapsed;
+  GtkWidget *frame;
+  GtkWidget *button;
+  GtkWidget *buttonChange;
+  GtkWidget *buttonDryC;
+  GtkWidget *buttonWashC;
+  GtkWidget *box1;
+  GtkWidget *box2;
+  GtkWidget *innerHbox;
+  GtkWidget *sub_vbox;
+  GtkWidget *label;
+
+  tmp_wInCmdMode = wInCommandMode;
+  tmp_dInCmdMode = dInCommandMode;
+
+  // Create a new window
+  mainConfigWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title (GTK_WINDOW (mainConfigWindow), "Configure");
+  gtk_window_set_wmclass (GTK_WINDOW (mainConfigWindow), "washerdryerconf", 
"");
+
+  gtk_signal_connect (GTK_OBJECT (mainConfigWindow), "destroy",
+     GTK_SIGNAL_FUNC (destroy), NULL);
+
+  // Sets the border width of the window.
+  gtk_container_set_border_width (GTK_CONTAINER (mainConfigWindow), 10);
+
+  // Create Vertical box
+  box1 = gtk_vbox_new (FALSE, 0);
+  // Add vertical box to main window
+  gtk_container_add (GTK_CONTAINER (mainConfigWindow), box1);
+  gtk_widget_show (box1);
+
+/////
+
+  /********************
+  * washer action frame
+  ********************/
+  frame = gtk_frame_new ("Washer Action");
+  gtk_box_pack_start (GTK_BOX (box1), frame, TRUE, TRUE, 2);
+  gtk_widget_show (frame);
+
+  //Create Vertical box
+  sub_vbox = gtk_vbox_new (FALSE, 0);
+  //Add vertical box to main window
+  gtk_container_add (GTK_CONTAINER (frame), sub_vbox);
+  gtk_widget_show (sub_vbox);
+
+  box2 = gtk_hbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (sub_vbox), box2, TRUE, TRUE, 2);
+
+  //Bell radio button
+  button = gtk_radio_button_new_with_label (NULL, "System Bell");
+  gtk_signal_connect (GTK_OBJECT (button), "clicked",
+          GTK_SIGNAL_FUNC (callback), (gpointer) "w_bell_button");
+  gtk_box_pack_start (GTK_BOX (box2), button, FALSE, FALSE, 2);
+  gtk_widget_show (button);
+
+  //Command radio button
+  buttonWashC = gtk_radio_button_new_with_label (gtk_radio_button_group
+              (GTK_RADIO_BUTTON (button)),
+              "Command");
+  gtk_signal_connect (GTK_OBJECT (buttonWashC), "clicked",
+          GTK_SIGNAL_FUNC (callback),
+          (gpointer) "w_command_button");
+  gtk_box_pack_start (GTK_BOX (box2), buttonWashC, FALSE, FALSE, 2);
+  gtk_widget_show (buttonWashC);
+  gtk_widget_show (box2);
+
+
+  box2 = gtk_hbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (sub_vbox), box2, TRUE, TRUE, 2);
+
+  label = gtk_label_new ("Command: ");
+  gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
+  gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 2);
+  gtk_widget_show (label);
+
+  /* Create "Command" text entry area */
+  wEntry = gtk_entry_new_with_max_length (100);
+  gtk_entry_set_editable (GTK_ENTRY (wEntry), FALSE);
+  gtk_signal_connect (GTK_OBJECT (wEntry), "activate",
+          GTK_SIGNAL_FUNC (callback), wEntry);
+  gtk_box_pack_start (GTK_BOX (box2), wEntry, FALSE, FALSE, 2);
+  gtk_widget_show (wEntry);
+  gtk_widget_show (box2);
+
+  box2 = gtk_hbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 2);
+
+/////
+
+  /********************
+  * dryer action frame
+  ********************/
+  frame = gtk_frame_new ("Dryer Action");
+  gtk_box_pack_start (GTK_BOX (box1), frame, TRUE, TRUE, 2);
+  gtk_widget_show (frame);
+
+  // Create Vertical box
+  sub_vbox = gtk_vbox_new (FALSE, 0);
+  // Add vertical box to main window
+  gtk_container_add (GTK_CONTAINER (frame), sub_vbox);
+  gtk_widget_show (sub_vbox);
+  
+  box2 = gtk_hbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (sub_vbox), box2, TRUE, TRUE, 2);
+
+  //Bell radio button
+  button = gtk_radio_button_new_with_label (NULL, "System Bell");
+  gtk_signal_connect (GTK_OBJECT (button), "clicked",
+          GTK_SIGNAL_FUNC (callback), (gpointer) "d_bell_button");
+  gtk_box_pack_start (GTK_BOX (box2), button, FALSE, FALSE, 2);
+  gtk_widget_show (button);
+
+  //Command radio button
+  buttonDryC = gtk_radio_button_new_with_label (gtk_radio_button_group
+              (GTK_RADIO_BUTTON (button)),
+              "Command");
+  gtk_signal_connect (GTK_OBJECT (buttonDryC), "clicked",
+          GTK_SIGNAL_FUNC (callback),
+          (gpointer) "d_command_button");
+  gtk_box_pack_start (GTK_BOX (box2), buttonDryC, FALSE, FALSE, 2);
+  gtk_widget_show (buttonDryC);
+  gtk_widget_show (box2);
+
+
+  /**************
+  * Status frame
+  **************/
+  frame = gtk_frame_new ("Status");
+  gtk_box_pack_start (GTK_BOX (box1), frame,TRUE, TRUE, 2);
+  gtk_widget_show (frame);
+
+  for(intProcNo = 0; intProcNo<10; ++intProcNo)
+  {
+    //if process is still running
+    if((intSec[intProcNo] != 0) || (intMin[intProcNo] != 0))
+    {
+      ++intLoadsIn;
+
+      if(intLoadsIn == 1)
+      {
+        box2 = gtk_vbox_new (FALSE, 0);
+        gtk_container_add (GTK_CONTAINER (frame), box2);
+        gtk_widget_show (box2);
+      }
+
+      innerHbox = gtk_hbox_new (FALSE, 2);
+      gtk_container_add (GTK_CONTAINER (box2), innerHbox);
+      gtk_widget_show (innerHbox);
+
+      if(chrType[intProcNo] == 'w')
+        sprintf(buffer,"Washer:   ");
+      else
+        sprintf(buffer," Dryer:   ");
+
+      label = gtk_label_new (buffer);
+      gtk_misc_set_alignment (GTK_MISC (label), 2, 2);
+      gtk_box_pack_start (GTK_BOX (innerHbox), label, TRUE, FALSE, 2);
+      gtk_widget_show (label);
+
+      sprintf(bufferChangeBtn, "%2i", intMin[intProcNo]);
+      buttonChange = gtk_button_new_with_label (bufferChangeBtn);
+      sprintf(bufferChangeBtn,"Change%i", intProcNo);
+      /**************************************
+      * why do I do it this way? because I'm
+      * dumb and I don't know a better way
+      **************************************/
+      switch(intProcNo)
+      {
+          case 0:
+            gtk_signal_connect (GTK_OBJECT (buttonChange), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Change0");
+            break;
+          case 1:
+            gtk_signal_connect (GTK_OBJECT (buttonChange), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Change1");
+            break;
+          case 2:
+            gtk_signal_connect (GTK_OBJECT (buttonChange), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Change2");
+            break;
+          case 3:
+            gtk_signal_connect (GTK_OBJECT (buttonChange), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Change3");
+            break;
+          case 4:
+            gtk_signal_connect (GTK_OBJECT (buttonChange), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Change4");
+            break;
+          case 5:
+            gtk_signal_connect (GTK_OBJECT (buttonChange), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Change5");
+            break;
+          case 6:
+            gtk_signal_connect (GTK_OBJECT (buttonChange), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Change6");
+            break;
+          case 7:
+            gtk_signal_connect (GTK_OBJECT (buttonChange), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Change7");
+            break;
+          case 8:
+            gtk_signal_connect (GTK_OBJECT (buttonChange), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Change8");
+            break;
+          case 9:
+            gtk_signal_connect (GTK_OBJECT (buttonChange), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Change9");
+            break;
+      }
+      gtk_box_pack_start (GTK_BOX(innerHbox), buttonChange, FALSE, FALSE, 2);
+      gtk_widget_show (buttonChange);
+
+      sprintf(buffer, " min remaining"); 
+      label = gtk_label_new (buffer);
+      gtk_misc_set_alignment (GTK_MISC (label), 2, 2);
+      gtk_box_pack_start (GTK_BOX (innerHbox), label, FALSE, FALSE, 2);
+      gtk_widget_show (label);
+
+      button = gtk_button_new_with_label ("Delete");
+      sprintf(buffer,"Delete%i", intProcNo);
+
+      /*************************************
+      * why this way? see above switch stmt
+      *************************************/
+      switch(intProcNo)
+      {
+          case 0:
+            gtk_signal_connect (GTK_OBJECT (button), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Delete0");
+            break;
+          case 1:
+            gtk_signal_connect (GTK_OBJECT (button), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Delete1");
+            break;
+          case 2:
+            gtk_signal_connect (GTK_OBJECT (button), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Delete2");
+            break;
+          case 3:
+            gtk_signal_connect (GTK_OBJECT (button), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Delete3");
+            break;
+          case 4:
+            gtk_signal_connect (GTK_OBJECT (button), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Delete4");
+            break;
+          case 5:
+            gtk_signal_connect (GTK_OBJECT (button), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Delete5");
+            break;
+          case 6:
+            gtk_signal_connect (GTK_OBJECT (button), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Delete6");
+            break;
+          case 7:
+            gtk_signal_connect (GTK_OBJECT (button), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Delete7");
+            break;
+          case 8:
+            gtk_signal_connect (GTK_OBJECT (button), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Delete8");
+            break;
+          case 9:
+            gtk_signal_connect (GTK_OBJECT (button), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer)"Delete9");
+            break;
+      }
+
+      /*
+      gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+          GTK_SIGNAL_FUNC (gtk_widget_destroy),
+          GTK_OBJECT (mainConfigWindow));
+      */
+
+    gtk_signal_connect_object (GTK_OBJECT (button),
+      "clicked", destroyAndReloadConfig, NULL);
+
+      gtk_box_pack_start (GTK_BOX (innerHbox), button, FALSE, FALSE, 4);
+      gtk_widget_show (button);
+      
+    }
+  } //end for
+
+
+  //if no loads
+  if(intLoadsIn == 0)
+  {
+    box2 = gtk_hbox_new (FALSE, 0);
+    gtk_container_add (GTK_CONTAINER (frame), box2);
+    gtk_widget_show (box2);
+
+    label = gtk_label_new ("   No loads in washer/dryer.");
+    gtk_misc_set_alignment (GTK_MISC (label), 2, 2);
+    gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 2);
+    gtk_widget_show (label);
+  }
+
+  /****************************
+  * doing some more dryer shit
+  ****************************/
+  box2 = gtk_hbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (sub_vbox), box2, TRUE, TRUE, 2);
+
+  label = gtk_label_new ("Command: ");
+  gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
+  gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 2);
+  gtk_widget_show (label);
+
+  /* Create "Command" text entry area */
+  dEntry = gtk_entry_new_with_max_length (100);
+  gtk_entry_set_editable (GTK_ENTRY (dEntry), FALSE);
+  gtk_signal_connect (GTK_OBJECT (dEntry), "activate",
+          GTK_SIGNAL_FUNC (callback), dEntry);
+  gtk_box_pack_start (GTK_BOX (box2), dEntry, FALSE, FALSE, 2);
+  gtk_widget_show (dEntry);
+  gtk_widget_show (box2);
+
+  box2 = gtk_hbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 2);
+
+  // Create "Cancel" button
+  button = gtk_button_new_with_label ("Cancel");
+  //gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC 
(delete_event), NULL);
+  gtk_signal_connect (GTK_OBJECT (button), "clicked",
+          GTK_SIGNAL_FUNC (callback), "cancel");
+  gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+           GTK_SIGNAL_FUNC (gtk_widget_destroy),
+           GTK_OBJECT (mainConfigWindow));
+  gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 2);
+  gtk_widget_show (button);
+
+  // Create "Clear" button
+/*  button = gtk_button_new_with_label ("Clear");
+  gtk_signal_connect (GTK_OBJECT (button), "clicked",
+          GTK_SIGNAL_FUNC (callback), "clear");
+  gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 2);
+  gtk_widget_show (button);
+*/
+
+
+  // Create "Ok" button
+  button = gtk_button_new_with_label ("Ok");
+  gtk_signal_connect (GTK_OBJECT (button), "clicked",
+          GTK_SIGNAL_FUNC (callback), "ok");
+  gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+           GTK_SIGNAL_FUNC (gtk_widget_destroy),
+           GTK_OBJECT (mainConfigWindow));
+  gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 2);
+  gtk_widget_show (button);
+  gtk_widget_show (box2);
+
+  gtk_widget_show (mainConfigWindow);
+
+  if (dInCommandMode == 1)
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (buttonDryC), TRUE);
+  if (wInCommandMode == 1)
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (buttonWashC), TRUE);
+
+  intTimeElapsed = time(0);
+  gtk_main ();
+  intTimeElapsed = time(0) - intTimeElapsed;
+  while(intTimeElapsed > 0)
+  {
+    DecrementTimer();
+    --intTimeElapsed;
+  }
+  return 0;
+}
+
+/***********************************
+* Reads a string from configuration
+* file. Taken from wminet
+***********************************/
+int ReadConfigString(FILE *fp, char *setting, char *value)
+{
+    char str[1024];
+    char buf[1024];
+    int i;
+    int len;
+    int slen;
+    char *p=NULL;
+
+
+    if (!fp)
+    {
+        return 0;
+    }
+
+    sprintf(str, "%s=", setting);
+    slen = strlen(str);
+
+    fseek(fp, 0, SEEK_SET);
+
+    while ( !feof(fp) )
+    {
+        if (!fgets(buf, 512, fp))
+            break;
+
+        len = strlen(buf);
+
+        // strip linefeed
+        for (i=0; i!=len; i++)
+        {
+            if (buf[i] == '\n')
+            {
+                buf[i] = 0;
+            }
+        }
+
+        if ( strncmp(buf, str, strlen(str)) == 0)
+        {
+            // found our setting
+            for(i=0; i!=slen; i++)
+            {
+                if ( buf[i] == '=' )
+                {
+                    p=buf+i+1;
+                    strcpy(value, p);
+                    return 1;
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+
+/*****************************
+* reads int from config file.
+* taken from wminet
+*****************************/
+int ReadConfigInt(FILE *fp, char *setting, int *value)
+{
+    char buf[1024];
+
+    if (ReadConfigString(fp, setting, (char *) &buf))
+    {
+        *value = atoi(buf);
+        return 1;
+    }
+
+    return 0;
+}
+
+
+/*****************************
+* Read config file and stores
+* values to local variables
+*****************************/
+int Read_Config_File(char* filename )
+{
+    FILE* fp;
+
+    fp = fopen(filename, "r");
+    if (fp)
+    {
+        if(intDefaultWasherTime == 0)
+        {
+          ReadConfigInt(fp, "washer_time", &intDefaultWasherTime);
+        }
+        if(intDefaultDryerTime == 0)
+        {
+          ReadConfigInt(fp, "dryer_time", &intDefaultDryerTime);
+        }
+        if(commandWash[0] == '\0')
+        {
+          ReadConfigInt(fp, "exec_washer_action", &wInCommandMode);
+        }
+        if(commandDry[0] == '\0')
+        {
+          ReadConfigInt(fp, "exec_dryer_action", &dInCommandMode);
+        }
+        tmp_wInCmdMode = wInCommandMode;
+        tmp_dInCmdMode = dInCommandMode;
+        if(commandWash[0] == '\0')
+        {
+          ReadConfigString(fp, "washer_action", commandWash);
+        }
+        if(commandDry[0] == '\0')
+        {
+          ReadConfigString(fp, "dryer_action", commandDry);
+        }
+
+        fclose(fp);
+        return 1;
+    }
+    else
+    {
+        perror("Read_Config_File");
+        fprintf(stderr, "Unable to open %s, no settings read.\n", filename);
+        return 0;
+    }
+}
+
diff --git a/washerdryer/washerDryer/wdryer.xpm 
b/washerdryer/washerDryer/wdryer.xpm
new file mode 100644
index 0000000..9a4fffc
--- /dev/null
+++ b/washerdryer/washerDryer/wdryer.xpm
@@ -0,0 +1,112 @@
+/* XPM */
+static char * wdryer_xpm[] = {
+"93 95 14 1",
+"      c None",
+".     c #000000",
+"+     c #1A2827",
+"@     c #BBBBBB",
+"#     c #0E0E0E",
+"$     c #FFFBF0",
+"%     c #C2C2C2",
+"&     c #E6E6E6",
+"*     c #4A4A4A",
+"=     c #CECECE",
+"-     c #FFFFFF",
+";     c #B2B2B2",
+">     c #52ABC9",
+",     c #3A7A72",
+"                                                                              
               ",
+"                                                                              
               ",
+"                                                                              
               ",
+"    ........................................................                  
               ",
+"    ........................................................                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..+++++#############+++++++++++#############++++++++++@.                  
               ",
+"    ..+++++#$$$$%%%%%$$#+++++++++++#$$&&$$$&&&&#++++++++++@.                  
               ",
+"    ..+++++#$***%%%%%**#+++++++++++#$$**$$$*&*&#++++++++++@.                  
               ",
+"    ..+++++#&&&&%%%%%&&##++++++++++#&&&&&&&&&&&##+++++++++@.                  
               ",
+"    ..+++++#==&&*****&&&##+++++++++#==&&&&&&&&&&##++++++++@.                  
               ",
+"    ..+++++#===&&&&&&&&&&##++++++++#===&&&&&&&&&&##+++++++@.                  
               ",
+"    ..+++++#===-----------#++++++++#===-----------#+++++++@.                  
               ",
+"    ..+++++#===-----------#++++++++#===--;;;;;;;--#+++++++@.                  
               ",
+"    ..+++++#===-----------#++++++++#===--;------;-#+++++++@.                  
               ",
+"    ..+++++#===-----------#++++++++#===--;------;-#+++++++@.                  
               ",
+"    ..+++++#===-----------#++++++++#===--;---&*-;-#+++++++@.                  
               ",
+"    ..+++++#===-----------#++++++++#===--;---&*-;-#+++++++@.                  
               ",
+"    ..+++++#===-----------#++++++++#===--;---&*-;-#+++++++@.                  
               ",
+"    ..+++++##==-----------#++++++++##==--;------;-#+++++++@.                  
               ",
+"    ..++++++##=-----------#+++++++++##=--;;;;;;;--#+++++++@.                  
               ",
+"    ..+++++++##-----------#++++++++++##-----------#+++++++@.                  
               ",
+"    ..++++++++#############+++++++++++#############+++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..++++++++++++++++++++++++++++++++++++++++++++++++++++@.                  
               ",
+"    ..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                  
               ",
+"    ........................................................                  
               ",
+"                                                                              
               ",
+"                                                                              
               ",
+"                                                                              
               ",
+"                                                                              
               ",
+"+>++>++>++>++>++>++>++>++>++>++>++>++>++>++>++>++>++>++>++>++>++>++>++>++>++>++>++>++>++>++>+",
+",,,+,++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+",,,,,,+,+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+",,,,,,,,,+,++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+",,,,,,,,,,,,+,+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+",,,,,,,,,,,,,,,+,++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+",,,,,,,,,,,,,,,,,,+,+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+",,,,,,,,,,,,,,,,,,,,,+,++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,+,+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,+,++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,++++++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,+++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,++++++++++++++++++++++++++++++++++++++++++++++++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,+++++++++++++++++++++++++++++++++++++++++++++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,++++++++++++++++++++++++++++++++++++++++++++++",
+">,,>,,>,,>,,>,,>,,>,,>,,>,,>,,>,,>,,>,,>,,>,,>,,>,+>++>++>++>++>++>++>++>++>++>++>++>++>++>++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,++++++++++++++++++++++++++++++++++++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,+++++++++++++++++++++++++++++++++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,++++++++++++++++++++++++++++++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,+++++++++++++++++++++++++++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,++++++++++++++++++++++++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,+++++++++++++++++++++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,++++++++++++++++++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,+++++++++++++++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,++++++++++++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,+++++++++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,++++++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,+++++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,++++",
+",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,+"};
diff --git a/washerdryer/washerDryer/wdryerrc b/washerdryer/washerDryer/wdryerrc
new file mode 100644
index 0000000..f128429
--- /dev/null
+++ b/washerdryer/washerDryer/wdryerrc
@@ -0,0 +1,24 @@
+# ~/.wdryerrc
+#
+# washerDryer configuration file
+# Mike Foley, 9/21/01
+#
+# All options except for washer_time and
+# dryer_time can be changed while program
+# is running. To configure, click on the
+# main part of the app.
+
+# time of washer and dryer (in minutes)
+washer_time=30
+dryer_time=40
+
+# do we execute a command when the load
+# is done, or beep?
+exec_washer_action=1
+exec_dryer_action=1
+
+# commands for washer and dryer, if they
+# are being executed
+washer_action=xmessage -center "Washer done!" -buttons "cool"
+dryer_action=xmessage -center "Dryer done!" -buttons "time to fold"
+
diff --git a/washerdryer/wmgeneral/list.c b/washerdryer/wmgeneral/list.c
new file mode 100644
index 0000000..1342aab
--- /dev/null
+++ b/washerdryer/wmgeneral/list.c
@@ -0,0 +1,165 @@
+/* Generic single linked list to keep various information 
+   Copyright (C) 1993, 1994 Free Software Foundation, Inc.
+
+
+   Author: Kresten Krab Thorup
+
+   Many modifications by Alfredo K. Kojima
+
+
+   This file is part of GNU CC.
+
+   GNU CC 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, or (at your option)
+   any later version.
+
+   GNU CC 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 GNU CC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with files compiled with
+   GCC to produce an executable, this does not cause the resulting executable
+   to be covered by the GNU General Public License. This exception does not
+   however invalidate any other reasons why the executable file might be
+   covered by the GNU General Public License.  */
+
+#include "list.h"
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <stdlib.h>
+
+/* Return a cons cell produced from (head . tail) */
+
+INLINE LinkedList * list_cons (void *head, LinkedList * tail)
+{
+  LinkedList *cell;
+
+  cell = (LinkedList *) malloc (sizeof (LinkedList));
+  cell->head = head;
+  cell->tail = tail;
+  return cell;
+}
+
+/* Return the length of a list, list_length(NULL) returns zero */
+
+INLINE int list_length (LinkedList * list)
+{
+  int i = 0;
+  while (list)
+    {
+      i += 1;
+      list = list->tail;
+    }
+  return i;
+}
+
+/* Return the Nth element of LIST, where N count from zero.  If N 
+   larger than the list length, NULL is returned  */
+
+INLINE void * list_nth (int index, LinkedList * list)
+{
+  while (index-- != 0)
+    {
+      if (list->tail)
+       list = list->tail;
+      else
+       return 0;
+    }
+  return list->head;
+}
+
+/* Remove the element at the head by replacing it by its successor */
+
+INLINE void list_remove_head (LinkedList ** list)
+{
+  if (!*list)
+    return;
+  if ((*list)->tail)
+    {
+      LinkedList *tail = (*list)->tail;                /* fetch next */
+      *(*list) = *tail;                /* copy next to list head */
+      free (tail);             /* free next */
+    }
+  else
+    /* only one element in list */
+    {
+      free (*list);
+      (*list) = 0;
+    }
+}
+
+
+/* Remove the element with `car' set to ELEMENT */
+/*
+   INLINE void
+   list_remove_elem(LinkedList** list, void* elem)
+   {
+   while (*list)
+   {
+   if ((*list)->head == elem)
+   list_remove_head(list);
+   *list = (*list ? (*list)->tail : NULL);
+   }
+   } */
+
+INLINE LinkedList * list_remove_elem (LinkedList * list, void *elem)
+{
+  LinkedList *tmp;
+
+  if (list)
+    {
+      if (list->head == elem)
+       {
+         tmp = list->tail;
+         free (list);
+         return tmp;
+       }
+      list->tail = list_remove_elem (list->tail, elem);
+      return list;
+    }
+  return NULL;
+}
+
+
+/* Return element that has ELEM as car */
+
+INLINE LinkedList * list_find (LinkedList * list, void *elem)
+{
+  while (list)
+    {
+      if (list->head == elem)
+       return list;
+      list = list->tail;
+    }
+  return NULL;
+}
+
+/* Free list (backwards recursive) */
+
+INLINE void list_free (LinkedList * list)
+{
+  if (list)
+    {
+      list_free (list->tail);
+      free (list);
+    }
+}
+
+/* Map FUNCTION over all elements in LIST */
+
+INLINE void list_mapcar (LinkedList * list, void (*function) (void *))
+{
+  while (list)
+    {
+      (*function) (list->head);
+      list = list->tail;
+    }
+}
diff --git a/washerdryer/wmgeneral/list.h b/washerdryer/wmgeneral/list.h
new file mode 100644
index 0000000..de4b9fe
--- /dev/null
+++ b/washerdryer/wmgeneral/list.h
@@ -0,0 +1,61 @@
+/* Generic single linked list to keep various information 
+   Copyright (C) 1993, 1994 Free Software Foundation, Inc.
+
+   Author: Kresten Krab Thorup
+
+   This file is part of GNU CC.
+
+   GNU CC 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, or (at your option)
+   any later version.
+
+   GNU CC 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 GNU CC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with files compiled with
+   GCC to produce an executable, this does not cause the resulting executable
+   to be covered by the GNU General Public License. This exception does not
+   however invalidate any other reasons why the executable file might be
+   covered by the GNU General Public License.  */
+
+#ifndef __LIST_H_
+#define __LIST_H_
+
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+#define INLINE inline
+#else
+#define INLINE
+#endif
+
+typedef struct LinkedList
+  {
+    void *head;
+    struct LinkedList *tail;
+  }
+LinkedList;
+
+INLINE LinkedList *list_cons (void *head, LinkedList * tail);
+
+INLINE int list_length (LinkedList * list);
+
+INLINE void *list_nth (int index, LinkedList * list);
+
+INLINE void list_remove_head (LinkedList ** list);
+
+INLINE LinkedList *list_remove_elem (LinkedList * list, void *elem);
+
+INLINE void list_mapcar (LinkedList * list, void (*function) (void *));
+
+INLINE LinkedList *list_find (LinkedList * list, void *elem);
+
+INLINE void list_free (LinkedList * list);
+
+#endif
diff --git a/washerdryer/wmgeneral/misc.c b/washerdryer/wmgeneral/misc.c
new file mode 100644
index 0000000..90a43d9
--- /dev/null
+++ b/washerdryer/wmgeneral/misc.c
@@ -0,0 +1,229 @@
+/* dock.c- built-in Dock module for WindowMaker
+
+ *  WindowMaker window manager
+ * 
+ *  Copyright (c) 1997 Alfredo K. Kojima
+ * 
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "list.h"
+#include "misc.h"
+
+/*
+ *----------------------------------------------------------------------
+ * parse_command--
+ *      Divides a command line into a argv/argc pair.
+ *---------------------------------------------------------------------- 
+ */
+#define PRC_ALPHA      0
+#define PRC_BLANK      1
+#define PRC_ESCAPE     2
+#define PRC_DQUOTE     3
+#define PRC_EOS                4
+#define PRC_SQUOTE     5
+
+typedef struct
+  {
+    short nstate;
+    short output;
+  }
+DFA;
+
+
+static DFA mtable[9][6] =
+{
+  {
+    {3, 1},
+    {0, 0},
+    {4, 0},
+    {1, 0},
+    {8, 0},
+    {6, 0}},
+  {
+    {1, 1},
+    {1, 1},
+    {2, 0},
+    {3, 0},
+    {5, 0},
+    {1, 1}},
+  {
+    {1, 1},
+    {1, 1},
+    {1, 1},
+    {1, 1},
+    {5, 0},
+    {1, 1}},
+  {
+    {3, 1},
+    {5, 0},
+    {4, 0},
+    {1, 0},
+    {5, 0},
+    {6, 0}},
+  {
+    {3, 1},
+    {3, 1},
+    {3, 1},
+    {3, 1},
+    {5, 0},
+    {3, 1}},
+  {
+    {-1, -1},
+    {0, 0},
+    {0, 0},
+    {0, 0},
+    {0, 0},
+    {0, 0}},                   /* final state */
+  {
+    {6, 1},
+    {6, 1},
+    {7, 0},
+    {6, 1},
+    {5, 0},
+    {3, 0}},
+  {
+    {6, 1},
+    {6, 1},
+    {6, 1},
+    {6, 1},
+    {5, 0},
+    {6, 1}},
+  {
+    {-1, -1},
+    {0, 0},
+    {0, 0},
+    {0, 0},
+    {0, 0},
+    {0, 0}},                   /* final state */
+};
+
+char * next_token (char *word, char **next)
+{
+  char *ptr;
+  char *ret, *t;
+  int state, ctype;
+
+  t = ret = malloc (strlen (word) + 1);
+  ptr = word;
+
+  state = 0;
+  *t = 0;
+  while (1)
+    {
+      if (*ptr == 0)
+       ctype = PRC_EOS;
+      else if (*ptr == '\\')
+       ctype = PRC_ESCAPE;
+      else if (*ptr == '"')
+       ctype = PRC_DQUOTE;
+      else if (*ptr == '\'')
+       ctype = PRC_SQUOTE;
+      else if (*ptr == ' ' || *ptr == '\t')
+       ctype = PRC_BLANK;
+      else
+       ctype = PRC_ALPHA;
+
+      if (mtable[state][ctype].output)
+       {
+         *t = *ptr;
+         t++;
+         *t = 0;
+       }
+      state = mtable[state][ctype].nstate;
+      ptr++;
+      if (mtable[state][0].output < 0)
+       {
+         break;
+       }
+    }
+
+  if (*ret == 0)
+    t = NULL;
+  else
+    t = strdup (ret);
+
+  free (ret);
+
+  if (ctype == PRC_EOS)
+    *next = NULL;
+  else
+    *next = ptr;
+
+  return t;
+}
+
+
+extern void parse_command (char *command, char ***argv, int *argc)
+{
+  LinkedList *list = NULL;
+  char *token, *line;
+  int count, i;
+
+  line = command;
+  do
+    {
+      token = next_token (line, &line);
+      if (token)
+       {
+         list = list_cons (token, list);
+       }
+    }
+  while (token != NULL && line != NULL);
+
+  count = list_length (list);
+  *argv = malloc (sizeof (char *) * count);
+  i = count;
+  while (list != NULL)
+    {
+      (*argv)[--i] = list->head;
+      list_remove_head (&list);
+    }
+  *argc = count;
+}
+
+extern pid_t execCommand (char *command)
+{
+  pid_t pid;
+  char **argv;
+  int argc;
+
+  parse_command (command, &argv, &argc);
+
+  if (argv == NULL)
+    {
+      return 0;
+    }
+
+  if ((pid = fork ()) == 0)
+    {
+      char **args;
+      int i;
+
+      args = malloc (sizeof (char *) * (argc + 1));
+      if (!args)
+       exit (10);
+      for (i = 0; i < argc; i++)
+       {
+         args[i] = argv[i];
+       }
+      args[argc] = NULL;
+      execvp (argv[0], args);
+      exit (10);
+    }
+  return pid;
+}
diff --git a/washerdryer/wmgeneral/misc.h b/washerdryer/wmgeneral/misc.h
new file mode 100644
index 0000000..ce3321e
--- /dev/null
+++ b/washerdryer/wmgeneral/misc.h
@@ -0,0 +1,9 @@
+#ifndef __MISC_H
+#define __MISC_H
+
+#include <unistd.h>
+
+extern void parse_command (char *, char ***, int *);
+
+extern pid_t execCommand (char *);
+#endif /* __MISC_H */
diff --git a/washerdryer/wmgeneral/wmgeneral.c 
b/washerdryer/wmgeneral/wmgeneral.c
new file mode 100644
index 0000000..2d4b2fb
--- /dev/null
+++ b/washerdryer/wmgeneral/wmgeneral.c
@@ -0,0 +1,444 @@
+/*
+   Best viewed with vim5, using ts=4
+
+   wmgeneral was taken from wmppp.
+
+   It has a lot of routines which most of the wm* programs use.
+
+   ------------------------------------------------------------
+
+   Author: Martijn Pieterse (piete...@xs4all.nl)
+
+   ---
+   CHANGES:
+   ---
+   14/09/1998 (Dave Clark, cla...@skyia.com)
+   * Updated createXBMfromXPM routine
+   * Now supports >256 colors
+   11/09/1998 (Martijn Pieterse, piete...@xs4all.nl)
+   * Removed a bug from parse_rcfile. You could
+   not use "start" in a command if a label was 
+   also start.
+   * Changed the needed geometry string.
+   We don't use window size, and don't support
+   negative positions.
+   03/09/1998 (Martijn Pieterse, piete...@xs4all.nl)
+   * Added parse_rcfile2
+   02/09/1998 (Martijn Pieterse, piete...@xs4all.nl)
+   * Added -geometry support (untested)
+   28/08/1998 (Martijn Pieterse, piete...@xs4all.nl)
+   * Added createXBMfromXPM routine
+   * Saves a lot of work with changing xpm's.
+   02/05/1998 (Martijn Pieterse, piete...@xs4all.nl)
+   * changed the read_rc_file to parse_rcfile, as suggested by Marcelo E. 
Magallon
+   * debugged the parse_rc file.
+   30/04/1998 (Martijn Pieterse, piete...@xs4all.nl)
+   * Ripped similar code from all the wm* programs,
+   and put them in a single file.
+
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+#include <X11/Xlib.h>
+#include <X11/xpm.h>
+#include <X11/extensions/shape.h>
+
+#include "wmgeneral.h"
+
+/*****************/
+ /* X11 Variables */
+/*****************/
+
+Window Root;
+int screen;
+int x_fd;
+int d_depth;
+XSizeHints mysizehints;
+XWMHints mywmhints;
+Pixel back_pix, fore_pix;
+char *Geometry = "";
+Window iconwin, win;
+GC NormalGC;
+XpmIcon wmgen;
+Pixmap pixmask;
+
+/*****************/
+ /* Mouse Regions */
+/*****************/
+
+typedef struct
+  {
+    int enable;
+    int top;
+    int bottom;
+    int left;
+    int right;
+  }
+MOUSE_REGION;
+
+MOUSE_REGION mouse_region[MAX_MOUSE_REGION];
+
+/***********************/
+ /* Function Prototypes */
+/***********************/
+
+static void GetXPM (XpmIcon *, char **);
+static Pixel GetColor (char *);
+void RedrawWindow (void);
+void AddMouseRegion (int, int, int, int, int);
+int CheckMouseRegion (int, int);
+
+/*******************************************************************************\
+|* GetXPM                                                                      
                                                                   *|
+\*******************************************************************************/
+
+static void GetXPM (XpmIcon * wmgen, char *pixmap_bytes[])
+{
+
+  XWindowAttributes attributes;
+  int err;
+
+  /* For the colormap */
+  XGetWindowAttributes (display, Root, &attributes);
+
+  wmgen->attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
+
+  err = XpmCreatePixmapFromData (display, Root, pixmap_bytes, &(wmgen->pixmap),
+                                &(wmgen->mask), &(wmgen->attributes));
+
+  if (err != XpmSuccess)
+    {
+      fprintf (stderr, "Not enough free colorcells.\n");
+      exit (1);
+    }
+}
+
+/*******************************************************************************\
+|* GetColor                                                                    
                                                                   *|
+\*******************************************************************************/
+
+static Pixel GetColor (char *name)
+{
+
+  XColor color;
+  XWindowAttributes attributes;
+
+  XGetWindowAttributes (display, Root, &attributes);
+
+  color.pixel = 0;
+  if (!XParseColor (display, attributes.colormap, name, &color))
+    {
+      fprintf (stderr, "wm.app: can't parse %s.\n", name);
+    }
+  else if (!XAllocColor (display, attributes.colormap, &color))
+    {
+      fprintf (stderr, "wm.app: can't allocate %s.\n", name);
+    }
+  return color.pixel;
+}
+
+/*******************************************************************************\
+|* flush_expose                                                                
                                                                   *|
+\*******************************************************************************/
+
+static int flush_expose (Window w)
+{
+
+  XEvent dummy;
+  int i = 0;
+
+  while (XCheckTypedWindowEvent (display, w, Expose, &dummy))
+    i++;
+
+  return i;
+}
+
+/*******************************************************************************\
+|* RedrawWindow                                                                
                                                                   *|
+\*******************************************************************************/
+
+void RedrawWindow (void)
+{
+
+  flush_expose (iconwin);
+  XCopyArea (display, wmgen.pixmap, iconwin, NormalGC,
+            0, 0, wmgen.attributes.width, wmgen.attributes.height, 0, 0);
+  flush_expose (win);
+  XCopyArea (display, wmgen.pixmap, win, NormalGC,
+            0, 0, wmgen.attributes.width, wmgen.attributes.height, 0, 0);
+}
+
+/*******************************************************************************\
+|* RedrawWindowXY                                                              
                                                           *|
+\*******************************************************************************/
+
+void RedrawWindowXY (int x, int y)
+{
+
+  flush_expose (iconwin);
+  XCopyArea (display, wmgen.pixmap, iconwin, NormalGC,
+            x, y, wmgen.attributes.width, wmgen.attributes.height, 0, 0);
+  flush_expose (win);
+  XCopyArea (display, wmgen.pixmap, win, NormalGC,
+            x, y, wmgen.attributes.width, wmgen.attributes.height, 0, 0);
+}
+
+/*******************************************************************************\
+|* AddMouseRegion                                                              
                                                           *|
+\*******************************************************************************/
+
+void AddMouseRegion (int index, int left, int top, int right, int bottom)
+{
+
+  if (index < MAX_MOUSE_REGION)
+    {
+      mouse_region[index].enable = 1;
+      mouse_region[index].top = top;
+      mouse_region[index].left = left;
+      mouse_region[index].bottom = bottom;
+      mouse_region[index].right = right;
+    }
+}
+
+/*******************************************************************************\
+|* CheckMouseRegion                                                            
                                                           *|
+\*******************************************************************************/
+
+int CheckMouseRegion (int x, int y)
+{
+
+  int i;
+  int found;
+
+  found = 0;
+
+  for (i = 0; i < MAX_MOUSE_REGION && !found; i++)
+    {
+      if (mouse_region[i].enable &&
+         x <= mouse_region[i].right &&
+         x >= mouse_region[i].left &&
+         y <= mouse_region[i].bottom &&
+         y >= mouse_region[i].top)
+       found = 1;
+    }
+  if (!found)
+    return -1;
+  return (i - 1);
+}
+
+/*******************************************************************************\
+|* createXBMfromXPM                                                            
                                                           *|
+\*******************************************************************************/
+void createXBMfromXPM (char *xbm, char **xpm, int sx, int sy)
+{
+
+  int i, j, k;
+  int width, height, numcol, depth;
+  int zero = 0;
+  unsigned char bwrite;
+  int bcount;
+  int curpixel;
+
+  sscanf (*xpm, "%d %d %d %d", &width, &height, &numcol, &depth);
+
+
+  for (k = 0; k != depth; k++)
+    {
+      zero <<= 8;
+      zero |= xpm[1][k];
+    }
+
+  for (i = numcol + 1; i < numcol + sy + 1; i++)
+    {
+      bcount = 0;
+      bwrite = 0;
+      for (j = 0; j < sx * depth; j += depth)
+       {
+         bwrite >>= 1;
+
+         curpixel = 0;
+         for (k = 0; k != depth; k++)
+           {
+             curpixel <<= 8;
+             curpixel |= xpm[i][j + k];
+           }
+
+         if (curpixel != zero)
+           {
+             bwrite += 128;
+           }
+         bcount++;
+         if (bcount == 8)
+           {
+             *xbm = bwrite;
+             xbm++;
+             bcount = 0;
+             bwrite = 0;
+           }
+       }
+    }
+}
+
+/*******************************************************************************\
+|* copyXPMArea                                                                 
                                                           *|
+\*******************************************************************************/
+
+void copyXPMArea (int x, int y, int sx, int sy, int dx, int dy)
+{
+
+  XCopyArea (display, wmgen.pixmap, wmgen.pixmap, NormalGC, x, y, sx, sy, dx, 
dy);
+
+}
+
+/*******************************************************************************\
+|* copyXBMArea                                                                 
                                                           *|
+\*******************************************************************************/
+
+void copyXBMArea (int x, int y, int sx, int sy, int dx, int dy)
+{
+
+  XCopyArea (display, wmgen.mask, wmgen.pixmap, NormalGC, x, y, sx, sy, dx, 
dy);
+}
+
+
+/*******************************************************************************\
+|* setMaskXY                                                                   
                                                           *|
+\*******************************************************************************/
+
+void setMaskXY (int x, int y)
+{
+
+  XShapeCombineMask (display, win, ShapeBounding, x, y, pixmask, ShapeSet);
+  XShapeCombineMask (display, iconwin, ShapeBounding, x, y, pixmask, ShapeSet);
+}
+
+/*******************************************************************************\
+|* openXwindow                                                                 
                                                           *|
+\*******************************************************************************/
+void openXwindow (int argc, char *argv[], char *pixmap_bytes[], char 
*pixmask_bits, int pixmask_width, int pixmask_height)
+{
+
+  unsigned int borderwidth = 1;
+  XClassHint classHint;
+  char *display_name = NULL;
+  char *wname = argv[0];
+  XTextProperty name;
+
+  XGCValues gcv;
+  unsigned long gcm;
+
+  char *geometry = NULL;
+
+  int dummy = 0;
+  int i, wx, wy;
+
+  for (i = 1; argv[i]; i++)
+    {
+      if (!strcmp (argv[i], "-display"))
+       {
+         display_name = argv[i + 1];
+         i++;
+       }
+      if (!strcmp (argv[i], "-geometry"))
+       {
+         geometry = argv[i + 1];
+         i++;
+       }
+    }
+
+  if (!(display = XOpenDisplay (display_name)))
+    {
+      fprintf (stderr, "%s: can't open display %s\n",
+              wname, XDisplayName (display_name));
+      exit (1);
+    }
+  screen = DefaultScreen (display);
+  Root = RootWindow (display, screen);
+  d_depth = DefaultDepth (display, screen);
+  x_fd = XConnectionNumber (display);
+
+  /* Convert XPM to XImage */
+  GetXPM (&wmgen, pixmap_bytes);
+
+  /* Create a window to hold the stuff */
+  mysizehints.flags = USSize | USPosition;
+  mysizehints.x = 0;
+  mysizehints.y = 0;
+
+  back_pix = GetColor ("white");
+  fore_pix = GetColor ("black");
+
+  XWMGeometry (display, screen, Geometry, NULL, borderwidth, &mysizehints,
+              &mysizehints.x, &mysizehints.y, &mysizehints.width, 
&mysizehints.height, &dummy);
+
+  mysizehints.width = 64;
+  mysizehints.height = 64;
+
+  win = XCreateSimpleWindow (display, Root, mysizehints.x, mysizehints.y,
+    mysizehints.width, mysizehints.height, borderwidth, fore_pix, back_pix);
+
+  iconwin = XCreateSimpleWindow (display, win, mysizehints.x, mysizehints.y,
+    mysizehints.width, mysizehints.height, borderwidth, fore_pix, back_pix);
+
+  /* Activate hints */
+  XSetWMNormalHints (display, win, &mysizehints);
+  classHint.res_name = wname;
+  classHint.res_class = wname;
+  XSetClassHint (display, win, &classHint);
+
+  XSelectInput (display, win, ButtonPressMask | ExposureMask | 
ButtonReleaseMask | PointerMotionMask | StructureNotifyMask);
+  XSelectInput (display, iconwin, ButtonPressMask | ExposureMask | 
ButtonReleaseMask | PointerMotionMask | StructureNotifyMask);
+
+  if (XStringListToTextProperty (&wname, 1, &name) == 0)
+    {
+      fprintf (stderr, "%s: can't allocate window name\n", wname);
+      exit (1);
+    }
+
+  XSetWMName (display, win, &name);
+
+  /* Create GC for drawing */
+
+  gcm = GCForeground | GCBackground | GCGraphicsExposures;
+  gcv.foreground = fore_pix;
+  gcv.background = back_pix;
+  gcv.graphics_exposures = 0;
+  NormalGC = XCreateGC (display, Root, gcm, &gcv);
+
+  /* ONLYSHAPE ON */
+
+  pixmask = XCreateBitmapFromData (display, win, pixmask_bits, pixmask_width, 
pixmask_height);
+
+  XShapeCombineMask (display, win, ShapeBounding, 0, 0, pixmask, ShapeSet);
+  XShapeCombineMask (display, iconwin, ShapeBounding, 0, 0, pixmask, ShapeSet);
+
+  /* ONLYSHAPE OFF */
+
+  mywmhints.initial_state = WithdrawnState;
+  mywmhints.icon_window = iconwin;
+  mywmhints.icon_x = mysizehints.x;
+  mywmhints.icon_y = mysizehints.y;
+  mywmhints.window_group = win;
+  mywmhints.flags = StateHint | IconWindowHint | IconPositionHint | 
WindowGroupHint;
+
+  XSetWMHints (display, win, &mywmhints);
+
+  XSetCommand (display, win, argv, argc);
+  XMapWindow (display, win);
+
+  if (geometry)
+    {
+      if (sscanf (geometry, "+%d+%d", &wx, &wy) != 2)
+       {
+         fprintf (stderr, "Bad geometry string.\n");
+         exit (1);
+       }
+      XMoveWindow (display, win, wx, wy);
+    }
+}
diff --git a/washerdryer/wmgeneral/wmgeneral.h 
b/washerdryer/wmgeneral/wmgeneral.h
new file mode 100644
index 0000000..00872b5
--- /dev/null
+++ b/washerdryer/wmgeneral/wmgeneral.h
@@ -0,0 +1,62 @@
+#ifndef WMGENERAL_H_INCLUDED
+#define WMGENERAL_H_INCLUDED
+
+/***********/
+ /* Defines */
+/***********/
+
+#define MAX_MOUSE_REGION (16)
+
+/************/
+ /* Typedefs */
+/************/
+
+typedef struct _rckeys rckeys;
+
+struct _rckeys
+  {
+    const char *label;
+    char **var;
+  };
+
+typedef struct _rckeys2 rckeys2;
+
+struct _rckeys2
+  {
+    const char *family;
+    const char *label;
+    char **var;
+  };
+
+typedef struct
+  {
+    Pixmap pixmap;
+    Pixmap mask;
+    XpmAttributes attributes;
+  }
+XpmIcon;
+
+/*******************/
+ /* Global variable */
+/*******************/
+
+Display *display;
+
+/***********************/
+ /* Function Prototypes */
+/***********************/
+
+void AddMouseRegion (int index, int left, int top, int right, int bottom);
+int CheckMouseRegion (int x, int y);
+
+void openXwindow (int argc, char *argv[], char **, char *, int, int);
+void RedrawWindow (void);
+void RedrawWindowXY (int x, int y);
+
+void createXBMfromXPM (char *, char **, int, int);
+void copyXPMArea (int, int, int, int, int, int);
+void copyXBMArea (int, int, int, int, int, int);
+void setMaskXY (int, int);
+
+
+#endif
-- 
2.7.4


-- 
To unsubscribe, send mail to wmaker-dev-unsubscr...@lists.windowmaker.org.

Reply via email to