[gromit: 1/13] First version of gromit.



commit a1ff753c63f61d83d5fab3059694e4177ed85add
Author: Simon Budig <simon budig de>
Date:   Mon Aug 28 12:00:00 2000 +0200

    First version of gromit.

 COPYING               |  339 ++++++++++++++++++++++++
 Makefile              |    6 +
 README                |   85 ++++++
 gromit.c              |  701 +++++++++++++++++++++++++++++++++++++++++++++++++
 gromitconf            |   14 +
 paint_cursor.xbm      |   16 ++
 paint_cursor_mask.xbm |   16 ++
 parser.c              |  107 ++++++++
 parsertest            |    4 +
 sawfish-config        |   24 ++
 10 files changed, 1312 insertions(+), 0 deletions(-)
---
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..4189933
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                      59 Temple Place, Suite 330, Boston, MA 02111 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., 59 Temple Place, Suite 330, Boston, MA 02111 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/Makefile b/Makefile
new file mode 100644
index 0000000..8ff0477
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,6 @@
+all: parser gromit
+
+gromit: gromit.c
+	gcc -o gromit gromit.c `gtk-config --libs --cflags`
+parser: parser.c
+	gcc -o parser parser.c `gtk-config --libs --cflags`
diff --git a/README b/README
new file mode 100644
index 0000000..bf5457b
--- /dev/null
+++ b/README
@@ -0,0 +1,85 @@
+Gromit
+----------
+
+Gromit (GRaphics Over MIscellaneous Things) is a small tool to make
+annotations on the screen.
+
+When making presentations of the Gimp I found myself often moving the
+mousepointer around the point of interest until hopefully everybody
+noticed it. This annoyed me, since it is a very vague way to highlight
+something. I dreamt of a small programm which allows me to simply draw
+on the screen, ignoring any window-borders.
+
+Gromit is a first implementation of this program.
+
+The main usage problem of gromit is its activation. You need a special
+command to make gromit grab the mouse, since you typically want to use
+the program you are demonstrating and highlighting something is a short
+interruption of your workflow. It should work *always*, regardless of
+the currently focused window. X11 does not have an easy way to make a
+program sensible for all events of a certain kind. You have to iterate
+over all windows and tell X that you are interested in the events of
+this window. However, this does not affect windows opened later, so you
+have to reiterate this permanently. At this point I decided to use
+another way: You can invoke gromit with various arguments to control an
+already running gromit (see below).  Configure your favourite
+windowmanager to invoke these commands on your favourite
+key-combination. I included a script that reconfigures the
+sawfish-windowmanager. (If you are interested: Internally this is done
+via a special X-Selection)
+
+Gromit is pressure sensitive, if you are using properly configured
+XInput-Devices you can draw lines with different thickness. It is
+possible to erase something with the other end of the (Wacom) pen.
+
+
+Usage:
+  gromit --quit
+      will cause the main gromit process to quit (or "-q")
+  gromit --toggle
+      will toggle the grabbing of the cursor (or "-t")
+  gromit --clear
+      will clear the screen (or "-c")
+
+  If activated gromit prevents you from using other programs with the
+  mouse. You can press the button and paint on the screen. Key presses
+  will still reach the currently active window but it may be difficult
+  to change the window-focus without mouse... 
+  The next "gromit --toggle" will deactivate gromit and you can use your
+  programs as usual - only the painted regions will be obscured.
+
+I included the (shell-)script "sawfish-config". If you are using the
+sawfish-windowmanager you can simply start this script. The "Pause"-Key
+will be bound to the (de)activation, the "Break"-Key (probably
+Shift+Pause) will clear the screen. If you have config-files for other
+window-managers I'd be happy to include them. Please send them to me.
+
+
+Building;
+
+Gromit is small and lightwight. It needs Gtk to build and the Makefile
+is straightforward. No need for autoconf/automake yet  :-)
+Simply type "make" and copy the resulting binary to a convenient place.
+Stripping the binary can reduce its size. I just tested it on
+Linux/XFree86, reports from other platforms are welcome.
+
+
+Problems:
+
+Gromit does not have a configuration-file yet. This is definitely an
+important thing, but probably the code to handle this is bigger than the
+drawing-code. So at the moment gromit is configurable via source  :-)
+
+Gromit may drastically slow down your X-Server. It makes heavily use of
+the shape extension, which is quite expensive if you paint a complex
+pattern on screen. Especially terminal-programs tend to scroll
+incredibly slow if something is painted over their window. There is
+nothing I can do about this.
+
+
+This Program is distributed under the Gnu General Public License. See
+the file COPYING for details.
+
+
+Have Fun,
+	Simon Budig <Simon Budig unix-ag org>
diff --git a/gromit.c b/gromit.c
new file mode 100644
index 0000000..07c2112
--- /dev/null
+++ b/gromit.c
@@ -0,0 +1,701 @@
+/* Gromit -- a program for painting on the screen
+ * Copyright (C) 2000 Simon Budig <Simon Budig unix-ag org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+
+#include "paint_cursor.xbm"
+#include "paint_cursor_mask.xbm"
+
+#define GROMIT_PAINT_AREA_EVENTS  ( GDK_EXPOSURE_MASK | \
+				    GDK_LEAVE_NOTIFY_MASK | \
+				    GDK_BUTTON_PRESS_MASK | \
+				    GDK_BUTTON_MOTION_MASK \
+				    /* | GDK_POINTER_MOTION_HINT_MASK */ )
+
+/* Atoms used to control Gromit */
+#define GA_CONTROL    gdk_atom_intern ("Gromit/control", FALSE)
+#define GA_STATUS     gdk_atom_intern ("Gromit/status", FALSE)
+#define GA_QUIT       gdk_atom_intern ("Gromit/quit", FALSE)
+#define GA_ACTIVATE   gdk_atom_intern ("Gromit/activate", FALSE)
+#define GA_DEACTIVATE gdk_atom_intern ("Gromit/deactivate", FALSE)
+#define GA_TOGGLE     gdk_atom_intern ("Gromit/toggle", FALSE)
+#define GA_CLEAR      gdk_atom_intern ("Gromit/clear", FALSE)
+
+typedef enum
+{
+   GROMIT_PEN,
+   GROMIT_ERASER,
+   GROMIT_RECOLOR
+} GromitPaintType;
+
+typedef struct
+{
+   GromitPaintType type;
+   guint	   width;
+   GdkColor	  *fg_color;
+   GdkGC	  *paint_gc;
+   GdkGC          *shape_gc;
+} GromitPaintContext;
+
+typedef struct
+{
+   GtkWidget	*win;
+   GtkWidget	*area;
+   GtkWidget	*panel;
+   GtkWidget	*button;
+   GdkCursor    *paint_cursor;
+   GdkCursor    *erase_cursor;
+   GdkPixmap	*pixmap;
+   GdkColormap  *cm;
+   GdkColor	*white;
+   GdkColor	*black;
+   GdkColor	*red;
+   GdkColor	*blue;
+
+   GromitPaintContext *contexts[6];
+   GromitPaintContext *cur_context;
+
+   GdkBitmap	*shape;
+   GdkGC	*shape_gc;
+   GdkGCValues  *shape_gcv;
+   GdkColor	*transparent;
+   GdkColor	*opaque;
+
+   gdouble	lastx;
+   gdouble	lasty;
+   guint32	motion_time;
+   gdouble	count;
+   guint	timeout_id;
+   guint	modified;
+   guint	delayed;
+   guint	maxwidth;
+   guint	width;
+   guint	height;
+   guint	hard_grab;
+   guint	client;
+} GromitData;
+
+
+GromitPaintContext *
+gromit_paint_context_new (GdkDrawable *pixmap,
+			  GdkDrawable *shape, GromitPaintType type,
+			  GdkColor *fg_color, guint width)
+{
+   GromitPaintContext *context;
+   GdkGCValues   shape_gcv;
+
+   context = g_malloc (sizeof (GromitPaintContext));
+
+   context->type = type;
+   context->width = width;
+   context->fg_color = fg_color;
+   
+   if (type == GROMIT_ERASER)
+      context->paint_gc = NULL;
+   else {
+      /* GROMIT_PEN || GROMIT_RECOLOR */
+      context->paint_gc = gdk_gc_new (pixmap);
+      gdk_gc_set_foreground (context->paint_gc, fg_color);
+      gdk_gc_set_line_attributes (context->paint_gc, width, GDK_LINE_SOLID,
+				  GDK_CAP_ROUND, GDK_JOIN_ROUND);
+   }
+   
+   if (type == GROMIT_RECOLOR)
+      context->shape_gc = NULL;
+   else {
+      /* GROMIT_PEN || GROMIT_ERASER */
+      context->shape_gc = gdk_gc_new (shape);
+      gdk_gc_get_values (context->shape_gc, &shape_gcv);
+      
+      if (type == GROMIT_ERASER)
+	 gdk_gc_set_foreground (context->shape_gc, &(shape_gcv.foreground));
+      else
+	 /* GROMIT_PEN */
+	 gdk_gc_set_foreground (context->shape_gc, &(shape_gcv.background));
+      gdk_gc_set_line_attributes (context->shape_gc, width, GDK_LINE_SOLID,
+	    GDK_CAP_ROUND, GDK_JOIN_ROUND);
+   }  
+   
+   return context;
+}
+
+
+void
+gromit_paint_context_free (GromitPaintContext *context)
+{
+   gdk_gc_unref (context->paint_gc);
+   gdk_gc_unref (context->shape_gc);
+   g_free (context);
+}
+
+
+void
+gromit_toggle_grab (GromitData *data)
+{
+   if (data->hard_grab)
+   {
+      data->hard_grab = 0;
+      /* gtk_grab_remove (gtk_grab_get_current ()); */
+      g_printerr ("Ungrabbing pointer\n");
+      gdk_pointer_ungrab (GDK_CURRENT_TIME);
+      /* gdk_pointer_grab (data->area->window, FALSE, GDK_POINTER_MOTION_MASK,
+                      0, NULL, GDK_CURRENT_TIME); */
+   } else {
+      int foo;
+      /* gtk_grab_add (data->area); */
+      g_printerr ("Grabbing pointer: ");
+      foo = gdk_pointer_grab (data->area->window, FALSE,
+	    /* GDK_POINTER_MOTION_MASK | */
+	    GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK,
+	    0, data->paint_cursor, GDK_CURRENT_TIME);
+      switch (foo) {
+       	 case Success:
+	    data->hard_grab = 1;
+	    g_printerr ("Success\n");
+	    break;
+	 case GrabNotViewable:
+	    g_printerr ("GrabNotViewable\n");
+	    break;
+	 case AlreadyGrabbed:
+	    g_printerr ("AlreadyGrabbed\n");
+	    break;
+	 case GrabFrozen:
+	    g_printerr ("GrabFrozen\n");
+	    break;
+	 case GrabInvalidTime:
+	    g_printerr ("GrabInvalidTime\n");
+	    break;
+	 default:
+	    g_printerr ("Huh?\n");
+      }
+   }
+}
+
+
+void
+gromit_clear_screen (GromitData *data)
+{
+   gdk_gc_set_foreground (data->shape_gc, data->transparent);
+   gdk_draw_rectangle (data->shape, data->shape_gc, 1,
+		       0, 0, data->width, data->height);
+   gtk_widget_shape_combine_mask (data->win, data->shape, 0,0);
+}
+
+
+gint
+reshape (gpointer user_data)
+{
+   GromitData *data = (GromitData *) user_data;
+   static delay_count = 0;
+
+   if (data->modified) {
+      if (gtk_events_pending () && data->delayed < 5) {
+	 data->delayed++ ;
+      } else {
+	 gtk_widget_shape_combine_mask (data->win, data->shape, 0,0);
+	 data->modified = 0;
+	 data->delayed = 0;
+      }
+   }
+
+   return 1;
+}
+
+
+void
+gromit_draw_line (GromitData *data, gint x1, gint y1,
+		  gint x2, gint y2)
+{
+   GdkRectangle rect;
+   
+   rect.x = MIN (x1,x2) - data->maxwidth / 2;
+   rect.y = MIN (y1,y2) - data->maxwidth / 2;
+   rect.width = ABS (x1-x2) + data->maxwidth;
+   rect.height = ABS (y1-y2) + data->maxwidth;
+   
+   if (data->cur_context->paint_gc)
+      gdk_gc_set_line_attributes (data->cur_context->paint_gc,
+				  data->maxwidth,
+				  GDK_LINE_SOLID, GDK_CAP_ROUND,
+				  GDK_JOIN_ROUND);
+   if (data->cur_context->shape_gc)
+      gdk_gc_set_line_attributes (data->cur_context->shape_gc,
+				  data->maxwidth,
+				  GDK_LINE_SOLID, GDK_CAP_ROUND,
+				  GDK_JOIN_ROUND);
+   
+   if (data->cur_context->paint_gc)
+      gdk_draw_line (data->pixmap, data->cur_context->paint_gc,
+		     x1, y1, x2, y2);
+   
+   if (data->cur_context->shape_gc) {
+      gdk_draw_line (data->shape, data->cur_context->shape_gc,
+		     x1, y1, x2, y2);
+      data->modified = 1;
+   }
+   
+   if (data->cur_context->paint_gc)
+      gtk_widget_draw (data->area, &rect);
+   
+}
+
+
+/*
+ * Event-Handlers that perform the drawing
+ */
+
+gboolean
+paint (GtkWidget *win, GdkEventButton *ev, gpointer user_data)
+{
+   GromitData *data = (GromitData *) user_data;
+   
+#if 0
+   if (ev->button == 1) {
+      if (ev->state & GDK_SHIFT_MASK)
+	 data->cur_context = data->contexts[1];
+      else
+	 data->cur_context = data->contexts[0];
+   } else if (ev->button == 2) {
+      if (ev->state & GDK_SHIFT_MASK)
+	 data->cur_context = data->contexts[3];
+      else
+	 data->cur_context = data->contexts[2];
+   } else if (ev->button == 3) {
+      if (ev->state & GDK_SHIFT_MASK)
+	 data->cur_context = data->contexts[5];
+      else
+	 data->cur_context = data->contexts[4];
+   } else if (ev->button == 4) {
+      gromit_clear_screen (data);
+   } else if (ev->button == 5) {
+      gtk_main_quit ();
+   } 
+#endif
+
+   g_printerr ("Source: %d\n", ev->source);
+   switch (ev->source) {
+      case GDK_SOURCE_MOUSE:
+      case GDK_SOURCE_CURSOR:
+	 data->cur_context = data->contexts[1];
+	 break;
+      case GDK_SOURCE_PEN:
+	 gdk_window_set_cursor (data->win->window, data->paint_cursor);
+	 data->cur_context = data->contexts[0];
+	 break;
+      case GDK_SOURCE_ERASER:
+	 gdk_window_set_cursor (data->win->window, data->erase_cursor);
+	 data->cur_context = data->contexts[4];
+	 break;
+      default:
+	 data->cur_context = data->contexts[0];
+   }
+
+   gdk_window_set_background (data->area->window,
+			      data->cur_context->fg_color);
+
+   data->lastx = ev->x;
+   data->lasty = ev->y;
+   data->motion_time = ev->time;
+
+   if (ev->source == GDK_SOURCE_MOUSE)
+      data->maxwidth = data->cur_context->width;
+   else
+      data->maxwidth = (CLAMP (ev->pressure * ev->pressure,0,1) *
+			(double) data->cur_context->width);
+
+   if (ev->button <= 3)
+      gromit_draw_line (data, ev->x, ev->y, ev->x, ev->y);
+
+   /* if (data->cur_context->shape_gc && !gtk_events_pending ())
+      gtk_widget_shape_combine_mask (data->win, data->shape, 0,0); */
+
+   return 1;
+}
+
+
+gboolean
+paintto (GtkWidget *win, GdkEventMotion *ev, gpointer user_data)
+{
+   GromitData *data = (GromitData *) user_data;
+   GdkTimeCoord *coords;
+   int nevents;
+   int i;
+
+   coords = gdk_input_motion_events (ev->window, ev->deviceid,
+				     data->motion_time, ev->time, &nevents);
+   // g_printerr ("Got %d coords\n", nevents);
+   if (coords)
+   {
+      for (i=0; i<nevents; i++) {
+	 if (ev->source == GDK_SOURCE_MOUSE)
+	    data->maxwidth = data->cur_context->width;
+	 else
+	    data->maxwidth = (CLAMP (coords[i].pressure*coords[i].pressure,0,1)*
+			      (double) data->cur_context->width);
+	 gromit_draw_line (data, data->lastx, data->lasty,
+			   coords[i].x, coords[i].y);
+	 data->lastx = coords[i].x;
+	 data->lasty = coords[i].y;
+      }
+      data->motion_time = coords[nevents-1].time;
+      g_free (coords);
+   } else {
+      if (ev->is_hint) {
+	 g_printerr ("Hint\n");
+	 gdk_input_window_get_pointer (ev->window, ev->deviceid,
+				       NULL, NULL, NULL, NULL, NULL, NULL);
+      }
+      if (ev->source == GDK_SOURCE_MOUSE)
+	 data->maxwidth = data->cur_context->width;
+      else
+	 data->maxwidth = (CLAMP (ev->pressure * ev->pressure,0,1) *
+			   (double) data->cur_context->width);
+      gromit_draw_line (data, data->lastx, data->lasty, ev->x, ev->y);
+      data->lastx = ev->x;
+      data->lasty = ev->y;
+   }
+
+   data->lastx=ev->x;
+   data->lasty=ev->y;
+
+   return 0;
+}
+
+
+/*
+ * Functions for handling various (GTK+)-Events
+ */
+
+void
+quiet_print_handler (const gchar *string)
+{
+   return;
+}
+
+
+guint
+event_key_snoop (GtkWidget *grab_widget,
+		 GdkEventKey *event,
+		 gpointer func_data)
+{
+   g_printerr ("Got Key!\n");
+   return 0;
+}
+
+
+gboolean
+event_configure (GtkWidget *widget,
+		 GdkEventExpose *event,
+		 gpointer user_data)
+{
+   GromitData *data = (GromitData *) user_data;
+
+   data->pixmap = gdk_pixmap_new (data->area->window, data->width,
+				  data->height, -1);
+   gdk_draw_rectangle (data->pixmap, data->area->style->black_gc,
+		       1, 0, 0, data->width, data->height);
+   gdk_window_set_transient_for (data->area->window, data->win->window);
+
+   return 1;
+}
+
+
+gboolean
+event_expose (GtkWidget *widget,
+	      GdkEventExpose *event,
+	      gpointer user_data)
+{
+   GromitData *data = (GromitData *) user_data;
+
+   gdk_draw_pixmap (data->area->window,
+		    data->area->style->fg_gc[GTK_WIDGET_STATE (data->area)],
+		    data->pixmap, event->area.x, event->area.y,
+		    event->area.x, event->area.y, event->area.width,
+		    event->area.height);
+   return 0;
+}
+
+
+/* Remote control */
+
+void  
+event_selection_get (GtkWidget          *widget,
+		     GtkSelectionData   *selection_data,
+		     guint               info,
+		     guint               time,
+		     gpointer            data)
+{
+   gchar *uri = "OK";
+
+   if (selection_data->target == GA_TOGGLE)
+      gromit_toggle_grab (data);
+   else if (selection_data->target == GA_CLEAR)
+      gromit_clear_screen (data);
+   else if (selection_data->target == GA_QUIT)
+      gtk_main_quit ();
+   else
+      uri = "NOK";
+
+   gtk_selection_data_set (selection_data,
+			   selection_data->target,
+			   8, uri, strlen (uri));
+}
+
+
+void
+event_selection_received (GtkWidget *widget,
+			  GtkSelectionData *selection_data,
+			  guint time,
+			  gpointer user_data)
+{
+   GromitData *data = (GromitData *) user_data;
+
+   /* If someone has a selection for us, Gromit is already running. */
+
+   if (selection_data->type == GDK_NONE)
+      data->client = 0;
+   else
+      data->client = 1;
+
+   gtk_main_quit ();
+}
+
+
+/*
+ * Functions for setting up (parts of) the application
+ */
+
+void
+setup_input_devices ()
+{
+   GList *tmp_list;
+   
+   tmp_list = gdk_input_list_devices ();
+   while (tmp_list)
+   {
+      GdkDeviceInfo *info = (GdkDeviceInfo *) tmp_list->data;
+      if (strstr (info->name, "raser"))  /* Guess "Eraser"-Type devices */
+	 gdk_input_set_source (info->deviceid, GDK_SOURCE_ERASER);
+      g_printerr ("Enabling No. %d: \"%s\" (Type: %d)\n",
+		  info->deviceid, info->name, info->source);
+      gdk_input_set_mode (info->deviceid, GDK_MODE_SCREEN);
+      tmp_list = tmp_list->next;
+   }
+}
+
+
+void
+setup_client_app (GromitData *data)
+{
+   data->width = gdk_screen_width ();
+   data->height = gdk_screen_height ();
+   data->count = 0;
+   data->hard_grab = 0;
+
+   data->win = gtk_window_new (GTK_WINDOW_POPUP);
+   gtk_widget_set_usize (GTK_WIDGET (data->win), data->width, data->height);
+   gtk_widget_set_uposition (GTK_WIDGET (data->win), 0, 0);
+
+   gtk_signal_connect (GTK_OBJECT (data->win), "delete-event", 
+		       GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+   gtk_signal_connect (GTK_OBJECT (data->win), "destroy", 
+		       GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+   gtk_signal_connect (GTK_OBJECT (data->win), "motion_notify_event",
+		       GTK_SIGNAL_FUNC (paintto), (gpointer) data);
+   gtk_signal_connect (GTK_OBJECT (data->win), "button_press_event",
+		       GTK_SIGNAL_FUNC (paint), (gpointer) data);
+   gtk_signal_connect (GTK_OBJECT (data->win), "selection_get",
+		       GTK_SIGNAL_FUNC (event_selection_get), (gpointer) data);
+   gtk_signal_connect (GTK_OBJECT (data->win), "selection_received",
+		       GTK_SIGNAL_FUNC (event_selection_received),
+		       (gpointer) data);
+}
+
+
+void
+setup_main_app (GromitData *data)
+{
+   GdkPixmap *cursor_src, *cursor_mask;
+
+   /* COLORMAP */
+   data->cm = gdk_colormap_get_system ();
+   data->white = g_malloc (sizeof (GdkColor));
+   data->black = g_malloc (sizeof (GdkColor));
+   data->red   = g_malloc (sizeof (GdkColor));
+   data->blue  = g_malloc (sizeof (GdkColor));
+   gdk_color_white (data->cm, data->white);
+   gdk_color_black (data->cm, data->black);
+   gdk_color_parse ("#FF0000", data->red);
+   gdk_colormap_alloc_color (data->cm, data->red, 0, 1);
+   gdk_color_parse ("#2266FF", data->blue);
+   gdk_colormap_alloc_color (data->cm, data->blue, 0, 1);
+
+   /* CURSORS */
+   cursor_src = gdk_bitmap_create_from_data (NULL, paint_cursor_bits,
+					     paint_cursor_width,
+					     paint_cursor_height);
+   cursor_mask = gdk_bitmap_create_from_data (NULL, paint_cursor_mask_bits,
+					      paint_cursor_width,
+					      paint_cursor_height);
+   data->paint_cursor = gdk_cursor_new_from_pixmap (cursor_src, cursor_mask,
+						    data->white, data->black,
+						    paint_cursor_x_hot,
+						    paint_cursor_y_hot);
+   gdk_pixmap_unref (cursor_src);
+   gdk_pixmap_unref (cursor_mask);
+
+   /*  data->paint_cursor = gdk_cursor_new (GDK_PLUS); */
+   data->erase_cursor = gdk_cursor_new (GDK_RTL_LOGO);
+
+   /* SHAPE PIXMAP */
+   data->shape = gdk_pixmap_new (NULL, data->width, data->height, 1);
+   data->shape_gc = gdk_gc_new (data->shape);
+   data->shape_gcv = g_malloc (sizeof (GdkGCValues));
+   gdk_gc_get_values (data->shape_gc, data->shape_gcv);
+   data->transparent = gdk_color_copy (&(data->shape_gcv->foreground));
+   data->opaque = gdk_color_copy (&(data->shape_gcv->background));
+   gdk_gc_set_foreground (data->shape_gc, data->transparent);
+   gdk_draw_rectangle (data->shape, data->shape_gc,
+		       1, 0, 0, data->width, data->height);
+
+   /* DRAWING AREA */
+   data->area = gtk_drawing_area_new ();
+   gtk_drawing_area_size (GTK_DRAWING_AREA (data->area),
+			  data->width, data->height);
+
+   gtk_widget_set_events (data->area, GROMIT_PAINT_AREA_EVENTS);
+   gtk_widget_set_extension_events (data->area, GDK_EXTENSION_EVENTS_CURSOR);
+   gtk_signal_connect (GTK_OBJECT (data->area), "expose_event",
+		       (GtkSignalFunc) event_expose, (gpointer) data);
+   gtk_signal_connect (GTK_OBJECT (data->area),"configure_event",
+		       (GtkSignalFunc) event_configure, (gpointer) data);
+
+   gtk_container_add (GTK_CONTAINER (data->win), data->area);
+
+   gtk_widget_shape_combine_mask (data->win, data->shape, 0,0);
+
+   gtk_widget_show_all (data->win);
+
+   data->timeout_id = gtk_timeout_add (20, reshape, data);
+   data->modified = 0;
+
+   data->contexts[0] = gromit_paint_context_new (data->pixmap, data->shape,
+						 GROMIT_PEN, data->red, 7);
+   data->contexts[1] = gromit_paint_context_new (data->pixmap, data->shape,
+						 GROMIT_PEN, data->blue, 7);
+   data->contexts[2] = gromit_paint_context_new (data->pixmap, data->shape,
+						 GROMIT_RECOLOR, data->red,
+						 10);
+   data->contexts[3] = gromit_paint_context_new (data->pixmap, data->shape,
+						 GROMIT_RECOLOR, data->blue,
+						 10);
+   data->contexts[4] = gromit_paint_context_new (data->pixmap, data->shape,
+						 GROMIT_ERASER, data->white,
+						 150);
+   data->contexts[5] = gromit_paint_context_new (data->pixmap, data->shape,
+						 GROMIT_ERASER, data->white,
+						 50);
+
+   gtk_key_snooper_install ((GtkKeySnoopFunc) event_key_snoop, NULL);
+
+   gtk_selection_owner_set (data->win, GA_CONTROL, GDK_CURRENT_TIME);
+
+   gtk_selection_add_target (data->win, GA_CONTROL, GA_STATUS, 0);
+   gtk_selection_add_target (data->win, GA_CONTROL, GA_QUIT, 1);
+   gtk_selection_add_target (data->win, GA_CONTROL, GA_ACTIVATE, 2);
+   gtk_selection_add_target (data->win, GA_CONTROL, GA_DEACTIVATE, 3);
+   gtk_selection_add_target (data->win, GA_CONTROL, GA_TOGGLE, 4);
+   gtk_selection_add_target (data->win, GA_CONTROL, GA_CLEAR, 5);
+
+   setup_input_devices ();
+}
+
+
+/*
+ * Main programs
+ */
+
+int
+main_client (int argc, char **argv, GromitData *data)
+{
+   GdkAtom action = GDK_NONE;
+   gint i;
+   gchar *arg;
+
+   for (i=1; i < argc ; i++)
+   {
+      arg = argv[i];
+      action = GDK_NONE;
+      if (strcmp (arg, "-t") == 0 ||
+	  strcmp (arg, "--toggle") == 0)
+	 action = GA_TOGGLE;
+      else if (strcmp (arg, "-q") == 0 ||
+	       strcmp (arg, "--quit") == 0)
+	 action = GA_QUIT;
+      else if (strcmp (arg, "-c") == 0 ||
+	       strcmp (arg, "--clear") == 0)
+	 action = GA_CLEAR;
+
+      if (action != GDK_NONE)
+      {
+	 gtk_selection_convert (data->win, GA_CONTROL,
+				action, GDK_CURRENT_TIME);
+	 gtk_main ();  /* Wait for the response */
+      }
+   }
+
+   return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+   GromitData *data;
+
+   data = g_malloc (sizeof (GromitData));
+   gtk_init (&argc, &argv);
+
+   /* g_set_printerr_handler (quiet_print_handler); */
+
+   setup_client_app (data);
+
+   /* Try to get a status message. If there is a response gromit
+    * is already acive.
+    */
+
+   gtk_selection_convert (data->win, GA_CONTROL, GA_STATUS,
+			  GDK_CURRENT_TIME);
+   gtk_main ();  /* Wait for the response */
+
+   if (data->client)
+      return main_client (argc, argv, data);
+
+   /* Main application */
+   setup_main_app (data);
+   gtk_main ();
+   gdk_pointer_ungrab (GDK_CURRENT_TIME);
+   gdk_cursor_destroy (data->paint_cursor);
+   gdk_cursor_destroy (data->erase_cursor);
+   g_free (data);
+   return 0;
+}
+
+/*    vim: sw=3 ts=8 cindent noai bs=2 cinoptions=(0       */
diff --git a/gromitconf b/gromitconf
new file mode 100644
index 0000000..fd514c8
--- /dev/null
+++ b/gromitconf
@@ -0,0 +1,14 @@
+# Configuration file for gromit
+
+# Tools
+
+"roter Stift" = PEN ( size = 12, color = "red" )
+"Radierer" = Eraser ( size = 50 )
+
+"Pen1" = "roter Stift"
+
+"Pen1"[SHIFT,CTRL] = "Radierer"
+"Pen1"[SHIFT+CTRL] = PEN ( SIZE=30, color="red" )
+"Eraser" = ERASER ( color="#0000ff", siZE=50 )
+"Mouse" = NULL
+
diff --git a/paint_cursor.xbm b/paint_cursor.xbm
new file mode 100644
index 0000000..fe19815
--- /dev/null
+++ b/paint_cursor.xbm
@@ -0,0 +1,16 @@
+#define paint_cursor_width 31
+#define paint_cursor_height 31
+#define paint_cursor_x_hot 14
+#define paint_cursor_y_hot 14
+static unsigned char paint_cursor_bits[] = {
+   0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
+   0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
+   0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0xf0, 0x1f,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
+   0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
+   0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
+   0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00};
diff --git a/paint_cursor_mask.xbm b/paint_cursor_mask.xbm
new file mode 100644
index 0000000..98c092f
--- /dev/null
+++ b/paint_cursor_mask.xbm
@@ -0,0 +1,16 @@
+#define paint_cursor_mask_width 31
+#define paint_cursor_mask_height 31
+#define paint_cursor_mask_x_hot 14
+#define paint_cursor_mask_y_hot 14
+static unsigned char paint_cursor_mask_bits[] = {
+   0x00, 0x40, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
+   0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
+   0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
+   0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0xf0, 0x1f,
+   0xfe, 0x03, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
+   0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
+   0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
+   0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00};
diff --git a/parser.c b/parser.c
new file mode 100644
index 0000000..d50370a
--- /dev/null
+++ b/parser.c
@@ -0,0 +1,107 @@
+#include <glib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#undef DEBUG
+
+gint main (void) {
+  GScanner *scanner;
+  GTokenType token;
+  int file;
+
+  scanner = g_scanner_new (NULL);
+  scanner->config->case_sensitive = 0;
+  scanner->config->scan_octal = 0;
+  scanner->config->identifier_2_string = 1;
+  scanner->config->char_2_token = 1;
+  scanner->config->numbers_2_int = 1;
+  scanner->config->int_2_float = 1;
+ 
+  g_scanner_scope_add_symbol (scanner, 1, "size", NULL);
+  g_scanner_scope_add_symbol (scanner, 1, "color", NULL);
+  g_scanner_scope_add_symbol (scanner, 0, "PEN", NULL);
+  g_scanner_scope_add_symbol (scanner, 0, "RECOLOR", NULL);
+  g_scanner_scope_add_symbol (scanner, 0, "ERASER", NULL);
+
+  g_scanner_set_scope (scanner, 1);
+  scanner->config->scope_0_fallback = 1;
+
+  file = open ("./gromitconf", O_RDONLY);
+  g_scanner_input_file (scanner, file);
+
+  while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF) {
+    switch (token) {
+      case G_TOKEN_LEFT_PAREN:
+        printf ("         (\n"); break;
+      case G_TOKEN_RIGHT_PAREN:
+        printf ("         )\n"); break;
+      case G_TOKEN_LEFT_BRACE:
+        printf ("         [\n"); break;
+      case G_TOKEN_RIGHT_BRACE:
+        printf ("         ]\n"); break;
+      case G_TOKEN_EQUAL_SIGN:
+        printf ("         =\n"); break;
+      case G_TOKEN_COMMA:
+        printf ("         ,\n"); break;
+      
+      case G_TOKEN_INT:
+        printf ("Integer: %d\n", scanner->value.v_int); break;
+      case G_TOKEN_FLOAT:
+        printf ("Float  : %f\n", scanner->value.v_float); break;
+
+      case G_TOKEN_STRING:
+        printf ("String : %s\n", scanner->value.v_string); break;
+      
+      case G_TOKEN_IDENTIFIER:
+      case G_TOKEN_IDENTIFIER_NULL:
+        printf ("Ident  : %s\n", scanner->value.v_identifier); break;
+      
+      case G_TOKEN_SYMBOL:
+        printf ("         SYMBOL!\n"); break;
+
+      case G_TOKEN_CHAR:
+        printf ("Char   : %c\n", scanner->value.v_char); break;
+
+      case G_TOKEN_ERROR:
+        printf ("*** Error!\n"); break;
+
+#ifdef DEBUG
+      case G_TOKEN_LAST:
+        printf ("G_TOKEN_LAST\n"); break;
+
+      case G_TOKEN_LEFT_CURLY:
+        printf ("G_TOKEN_LEFT_CURLY\n"); break;
+      case G_TOKEN_RIGHT_CURLY:
+        printf ("G_TOKEN_RIGHT_CURLY\n"); break;
+      case G_TOKEN_LEFT_BRACE:
+        printf ("G_TOKEN_LEFT_BRACE\n"); break;
+      case G_TOKEN_RIGHT_BRACE:
+        printf ("G_TOKEN_RIGHT_BRACE\n"); break;
+      case G_TOKEN_NONE:
+        printf ("G_TOKEN_NONE\n"); break;
+      case G_TOKEN_BINARY:
+        printf ("G_TOKEN_BINARY\n"); break;
+      case G_TOKEN_OCTAL:
+        printf ("G_TOKEN_OCTAL\n"); break;
+      case G_TOKEN_HEX:
+        printf ("G_TOKEN_HEX\n"); break;
+      case G_TOKEN_COMMENT_SINGLE:
+        printf ("G_TOKEN_COMMENT_SINGLE\n"); break;
+      case G_TOKEN_COMMENT_MULTI:
+        printf ("G_TOKEN_COMMENT_MULTI\n"); break;
+      case G_TOKEN_EOF:
+        printf ("G_TOKEN_EOF\n"); break;
+
+#endif
+      default:
+        printf ("Unknown Token: %d, '%s'!\n", scanner->token, scanner->value);
+
+    }
+  }
+  close (file);
+  g_scanner_destroy (scanner);
+}
+
+
diff --git a/parsertest b/parsertest
new file mode 100644
index 0000000..0fe03d5
--- /dev/null
+++ b/parsertest
@@ -0,0 +1,4 @@
+(Hallo /* C-Style Comment */ Welt)
+# This line is uninteresting!
+("Hallo Welt")
+(1 2 'nochn string' 00100101 3 1.2 0xa7, 012 12 "#ffaa99" )
diff --git a/sawfish-config b/sawfish-config
new file mode 100755
index 0000000..8d6a55d
--- /dev/null
+++ b/sawfish-config
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+sawfish-client -- >/dev/null <<ENDOFSAWFISHCONFIG
+
+(defun gromit-toggle-grab ()
+   (interactive)
+   (ungrab-pointer)
+   (ungrab-keyboard)
+   (sync-server)
+   (system "/home/simon/src/gromit/gromit --toggle &")
+)
+
+(defun gromit-clear-screen ()
+   (interactive)
+   (ungrab-pointer)
+   (ungrab-keyboard)
+   (sync-server)
+   (system "/home/simon/src/gromit/gromit --clear &")
+)
+
+(bind-keys global-keymap "Pause" 'gromit-toggle-grab)
+(bind-keys global-keymap "Break" 'gromit-clear-screen)
+
+ENDOFSAWFISHCONFIG



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]