summaryrefslogtreecommitdiff
path: root/libgstroke/gnome-stroke-draw.c
diff options
context:
space:
mode:
authorHamish Moffatt <hamish@debian.org>2002-01-06 13:02:15 +0100
committerHamish Moffatt <hamish@debian.org>2002-01-06 13:02:15 +0100
commit2679d213fe4eae9f00a496c9b5fa2a67c85e78e1 (patch)
tree8065f92eb2795042b55fa45c0ac74f539706e714 /libgstroke/gnome-stroke-draw.c
Import libstroke_0.5.1.orig.tar.gz
[dgit import orig libstroke_0.5.1.orig.tar.gz]
Diffstat (limited to 'libgstroke/gnome-stroke-draw.c')
-rw-r--r--libgstroke/gnome-stroke-draw.c330
1 files changed, 330 insertions, 0 deletions
diff --git a/libgstroke/gnome-stroke-draw.c b/libgstroke/gnome-stroke-draw.c
new file mode 100644
index 0000000..79665fe
--- /dev/null
+++ b/libgstroke/gnome-stroke-draw.c
@@ -0,0 +1,330 @@
+/*
+ GNOME stroke implementation
+ Copyright (c) 2000, 2001 Dan Nicolaescu
+ See the file COPYING for distribution information.
+*/
+
+#include "config.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include <gdk/gdkx.h>
+#include "gstroke.h"
+#include "gstroke-internal.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+
+static void gstroke_invisible_window_init (GtkWidget *widget);
+/*FIXME: Maybe these should be put in a structure, and not static...*/
+static Display * gstroke_disp;
+static Window gstroke_window;
+static GC gstroke_gc;
+
+#define GSTROKE_TIMEOUT_DURATION 10
+
+#define GSTROKE_SIGNALS "gstroke_signals"
+
+struct gstroke_func_and_data {
+ GtkSignalFunc func;
+ gpointer data;
+};
+
+
+/*FIXME: maybe it's better to just make 2 static variables, not a
+ structure */
+struct mouse_position {
+ struct s_point last_point;
+ gboolean invalid;
+};
+
+
+static struct mouse_position last_mouse_position;
+static guint timer_id;
+
+static void gstroke_execute (GtkWidget *widget, const gchar *name);
+
+static void
+record_stroke_segment (GtkWidget *widget)
+{
+ gint x, y;
+ struct gstroke_metrics *metrics;
+
+ gtk_widget_get_pointer (widget, &x, &y);
+
+ if (last_mouse_position.invalid)
+ last_mouse_position.invalid = FALSE;
+ else
+ {
+#if 1
+ XDrawLine (gstroke_disp, gstroke_window, gstroke_gc,
+ last_mouse_position.last_point.x,
+ last_mouse_position.last_point.y,
+ x, y);
+ /* XFlush (gstroke_disp); */
+#else
+ /* FIXME: this does not work. It will only work if we create a
+ corresponding GDK window for stroke_window and draw on
+ that... */
+ gdk_draw_line (widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
+ last_mouse_position.last_point.x,
+ last_mouse_position.last_point.y,
+ x,
+ y);
+#endif
+ }
+
+ if (last_mouse_position.last_point.x != x
+ || last_mouse_position.last_point.y != y)
+ {
+ last_mouse_position.last_point.x = x;
+ last_mouse_position.last_point.y = y;
+ metrics =
+ (struct gstroke_metrics*)gtk_object_get_data (GTK_OBJECT (widget),
+ GSTROKE_METRICS);
+ _gstroke_record (x, y, metrics);
+ }
+}
+
+static gint
+gstroke_timeout (gpointer data)
+{
+ GtkWidget *widget = GTK_WIDGET (data);
+ record_stroke_segment (widget);
+
+ return TRUE;
+}
+
+static gint
+process_event (GtkWidget *widget, GdkEvent *event, gpointer data G_GNUC_UNUSED)
+{
+ static GtkWidget *original_widget = NULL;
+ switch (event->type) {
+ case GDK_BUTTON_PRESS:
+ if (event->button.button != GSTROKE_MOUSE_BUTTON)
+ break;
+
+ original_widget = widget; /* remeber the widget where
+ the stroke started */
+
+ gstroke_invisible_window_init (widget);
+
+ record_stroke_segment (widget);
+
+ gdk_pointer_grab (widget->window, FALSE,
+ GDK_BUTTON_RELEASE_MASK, NULL, NULL,
+ event->button.time);
+ timer_id = gtk_timeout_add (GSTROKE_TIMEOUT_DURATION,
+ gstroke_timeout, widget);
+ return TRUE;
+
+ case GDK_BUTTON_RELEASE:
+ if ((event->button.button != GSTROKE_MOUSE_BUTTON)
+ || (original_widget == NULL))
+ /* the stroke probably did not start here... */
+ break;
+
+ last_mouse_position.invalid = TRUE;
+ original_widget = NULL;
+ gtk_timeout_remove (timer_id);
+ gdk_pointer_ungrab (event->button.time);
+ timer_id = 0;
+
+ {
+ char result[GSTROKE_MAX_SEQUENCE];
+ struct gstroke_metrics *metrics
+ = (struct gstroke_metrics*) gtk_object_get_data (GTK_OBJECT (widget),
+ GSTROKE_METRICS);
+ /* get rid of the invisible stroke window */
+ XUnmapWindow (gstroke_disp, gstroke_window);
+ XFlush (gstroke_disp);
+
+ _gstroke_canonical (result, metrics);
+ gstroke_execute (widget, result);
+ return FALSE;
+ }
+ return TRUE;
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+void
+gstroke_enable (GtkWidget *widget)
+{
+ struct gstroke_metrics*
+ metrics = (struct gstroke_metrics*)gtk_object_get_data (GTK_OBJECT (widget),
+ GSTROKE_METRICS);
+ if (metrics == NULL)
+ {
+ metrics = (struct gstroke_metrics *)g_malloc (sizeof
+ (struct gstroke_metrics));
+ metrics->pointList = NULL;
+ metrics->min_x = 10000;
+ metrics->min_y = 10000;
+ metrics->max_x = 0;
+ metrics->max_y = 0;
+ metrics->point_count = 0;
+
+ gtk_object_set_data (GTK_OBJECT (widget), GSTROKE_METRICS,
+ metrics);
+
+ gtk_signal_connect (GTK_OBJECT (widget), "event",
+ (GtkSignalFunc) process_event,
+ NULL);
+ }
+ else
+ _gstroke_init (metrics);
+
+ last_mouse_position.invalid = TRUE;
+}
+
+guint
+gstroke_signal_connect (GtkWidget *widget,
+ const gchar *name,
+ GtkSignalFunc func,
+ gpointer data)
+{
+ struct gstroke_func_and_data *func_and_data;
+ GHashTable *hash_table =
+ (GHashTable*)gtk_object_get_data (GTK_OBJECT (widget), GSTROKE_SIGNALS);
+
+ if (!hash_table)
+ {
+ hash_table = g_hash_table_new (g_str_hash, g_str_equal);
+ gtk_object_set_data (GTK_OBJECT (widget), GSTROKE_SIGNALS,
+ (gpointer)hash_table);
+ }
+ func_and_data = g_new (struct gstroke_func_and_data, 1);
+ func_and_data->func = func;
+ func_and_data->data = data;
+ g_hash_table_insert (hash_table, (gpointer)name, (gpointer)func_and_data);
+ return TRUE;
+}
+
+static void
+gstroke_execute (GtkWidget *widget, const gchar *name)
+{
+
+ GHashTable *hash_table =
+ (GHashTable*)gtk_object_get_data (GTK_OBJECT (widget), GSTROKE_SIGNALS);
+
+#ifdef DEBUG
+ printf ("gstroke %s\n", name);
+ fflush (stdout);
+#endif
+
+ if (hash_table)
+ {
+ struct gstroke_func_and_data *fd =
+ (struct gstroke_func_and_data*)g_hash_table_lookup (hash_table, name);
+ if (fd)
+ (*fd->func)(widget, fd->data);
+ }
+}
+
+void
+gstroke_cleanup (GtkWidget *widget)
+{
+ struct gstroke_metrics *metrics;
+ GHashTable *hash_table =
+ (GHashTable*)gtk_object_get_data (GTK_OBJECT (widget), GSTROKE_SIGNALS);
+ if (hash_table)
+ /* FIXME: does this delete the elements too? */
+ g_hash_table_destroy (hash_table);
+
+ gtk_object_remove_data (GTK_OBJECT (widget), GSTROKE_SIGNALS);
+
+ metrics = (struct gstroke_metrics*)gtk_object_get_data (GTK_OBJECT (widget),
+ GSTROKE_METRICS);
+ if (metrics)
+ g_free (metrics);
+ gtk_object_remove_data (GTK_OBJECT (widget), GSTROKE_METRICS);
+}
+
+
+/* This function should be written using Gtk+ primitives*/
+static void
+gstroke_invisible_window_init (GtkWidget *widget)
+{
+ XSetWindowAttributes w_attr;
+ XWindowAttributes orig_w_attr;
+ unsigned long mask, col_border, col_background;
+ unsigned int border_width;
+ XSizeHints hints;
+ Display *disp = GDK_WINDOW_XDISPLAY(widget->window);
+ Window wind = GDK_WINDOW_XWINDOW (widget->window);
+ int screen = DefaultScreen (disp);
+
+ gstroke_disp = disp;
+
+ /* X server should save what's underneath */
+ XGetWindowAttributes (gstroke_disp, wind, &orig_w_attr);
+ hints.x = orig_w_attr.x;
+ hints.y = orig_w_attr.y;
+ hints.width = orig_w_attr.width;
+ hints.height = orig_w_attr.height;
+ mask = CWSaveUnder;
+ w_attr.save_under = True;
+
+ /* inhibit all the decorations */
+ mask |= CWOverrideRedirect;
+ w_attr.override_redirect = True;
+
+ /* Don't set a background, transparent window */
+ mask |= CWBackPixmap;
+ w_attr.background_pixmap = None;
+
+ /* Default input window look */
+ col_background = WhitePixel (gstroke_disp, screen);
+
+ /* no border for the window */
+#ifdef DEBUG
+ border_width = 5;
+#else
+ border_width = 0;
+#endif
+ col_border = BlackPixel (gstroke_disp, screen);
+
+ gstroke_window = XCreateSimpleWindow (gstroke_disp, wind,
+ 0, 0,
+ hints.width - 2 * border_width,
+ hints.height - 2 * border_width,
+ border_width,
+ col_border, col_background);
+
+ gstroke_gc = XCreateGC (gstroke_disp, gstroke_window, 0, NULL);
+
+ XSetFunction (gstroke_disp, gstroke_gc, GXinvert);
+
+ XChangeWindowAttributes (gstroke_disp, gstroke_window, mask, &w_attr);
+
+ XSetLineAttributes (gstroke_disp, gstroke_gc, 2, LineSolid,
+ CapButt, JoinMiter);
+ XMapRaised (gstroke_disp, gstroke_window);
+
+#if 0
+ /*FIXME: is this call really needed? If yes, does it need the real
+ argc and argv? */
+ hints.flags = PPosition | PSize;
+ XSetStandardProperties (gstroke_disp, gstroke_window, "gstroke_test", NULL,
+ (Pixmap)NULL, NULL, 0, &hints);
+
+
+ /* Receive the close window client message */
+ {
+ /* FIXME: is this really needed? If yes, something should be done
+ with wmdelete...*/
+ Atom wmdelete = XInternAtom (gstroke_disp, "WM_DELETE_WINDOW",
+ False);
+ XSetWMProtocols (gstroke_disp, gstroke_window, &wmdelete, True);
+ }
+#endif
+}