diff options
author | Hamish Moffatt <hamish@debian.org> | 2002-01-06 13:02:15 +0100 |
---|---|---|
committer | Hamish Moffatt <hamish@debian.org> | 2002-01-06 13:02:15 +0100 |
commit | 2679d213fe4eae9f00a496c9b5fa2a67c85e78e1 (patch) | |
tree | 8065f92eb2795042b55fa45c0ac74f539706e714 /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.c | 330 |
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 +} |