diff -r 6941fece679b -r 2f45a03838e9 pidgin/plugins/gestures/stroke-draw.c --- a/pidgin/plugins/gestures/stroke-draw.c Thu Jul 23 20:13:47 2020 -0500 +++ b/pidgin/plugins/gestures/stroke-draw.c Fri Jul 24 04:43:46 2020 -0500 @@ -11,19 +11,14 @@ #include #include #include -#include +#include #include "gstroke.h" #include "gstroke-internal.h" -#include -#include - -static void gstroke_invisible_window_init (GtkWidget *widget); +static gboolean gstroke_draw_cb(GtkWidget *widget, cairo_t *cr, + gpointer user_data); /*FIXME: Maybe these should be put in a structure, and not static...*/ -static Display * gstroke_disp = NULL; -static Window gstroke_window; -static GC gstroke_gc; static int mouse_button = 2; static gboolean draw_strokes = FALSE; @@ -65,24 +60,7 @@ gdk_window_get_device_position(gtk_widget_get_window(widget), dev, &x, &y, NULL); - if (last_mouse_position.invalid) - last_mouse_position.invalid = FALSE; - else if (gstroke_draw_strokes()) { -#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(gtk_widget_get_window(widget), - widget->style->fg_gc[GTK_STATE_NORMAL], - last_mouse_position.last_point.x, - last_mouse_position.last_point.y, x, y); -#endif - } + last_mouse_position.invalid = FALSE; if (last_mouse_position.last_point.x != x || last_mouse_position.last_point.y != y) @@ -92,6 +70,10 @@ metrics = g_object_get_data(G_OBJECT(widget), GSTROKE_METRICS); _gstroke_record (x, y, metrics); } + + if (gstroke_draw_strokes()) { + gtk_widget_queue_draw(widget); + } } static gint @@ -107,7 +89,8 @@ return TRUE; } -static void gstroke_cancel(GdkEvent *event) +static void +gstroke_cancel(GtkWidget *widget, GdkEvent *event) { last_mouse_position.invalid = TRUE; @@ -120,16 +103,13 @@ gdk_seat_ungrab(gdk_event_get_seat(event)); } - if (gstroke_draw_strokes() && gstroke_disp != NULL) { - /* get rid of the invisible stroke window */ - XUnmapWindow (gstroke_disp, gstroke_window); - XFlush (gstroke_disp); + if (gstroke_draw_strokes()) { + gtk_widget_queue_draw(widget); } - } static gint -process_event (GtkWidget *widget, GdkEvent *event, gpointer data G_GNUC_UNUSED) +process_event(GtkWidget *widget, GdkEvent *event, gpointer data) { static GtkWidget *original_widget = NULL; static GdkCursor *cursor = NULL; @@ -141,7 +121,7 @@ * clicked after the middle button is clicked (but possibly * not released) */ - gstroke_cancel(event); + gstroke_cancel(widget, event); original_widget = NULL; break; } @@ -149,8 +129,6 @@ original_widget = widget; /* remeber the widget where the stroke started */ - gstroke_invisible_window_init (widget); - record_stroke_segment (widget); if (cursor == NULL) { @@ -171,7 +149,7 @@ /* Nice bug when you hold down one button and press another. */ /* We'll just cancel the gesture instead. */ - gstroke_cancel(event); + gstroke_cancel(widget, event); original_widget = NULL; break; } @@ -182,21 +160,20 @@ gdk_seat_ungrab(gdk_event_get_seat(event)); timer_id = 0; - { + { + GtkWidget *history = data; char result[GSTROKE_MAX_SEQUENCE]; struct gstroke_metrics *metrics; metrics = (struct gstroke_metrics *)g_object_get_data(G_OBJECT (widget), GSTROKE_METRICS); if (gstroke_draw_strokes()) { - /* get rid of the invisible stroke window */ - XUnmapWindow (gstroke_disp, gstroke_window); - XFlush (gstroke_disp); + gtk_widget_queue_draw(widget); } - _gstroke_canonical (result, metrics); - gstroke_execute (widget, result); - } + _gstroke_canonical(result, metrics); + gstroke_execute(history, result); + } return FALSE; default: @@ -233,58 +210,85 @@ void gstroke_enable (GtkWidget *widget) { - struct gstroke_metrics* - metrics = (struct gstroke_metrics *)g_object_get_data(G_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; + GtkWidget *event = gtk_widget_get_parent(widget); + struct gstroke_metrics *metrics = NULL; + + if (GTK_IS_EVENT_BOX(event)) { + metrics = (struct gstroke_metrics *)g_object_get_data(G_OBJECT(event), + GSTROKE_METRICS); + } + + if (metrics == NULL) { + GtkWidget *parent; + + metrics = g_new0(struct gstroke_metrics, 1); + metrics->pointList = NULL; + metrics->min_x = 10000; + metrics->min_y = 10000; + metrics->max_x = 0; + metrics->max_y = 0; + metrics->point_count = 0; - g_object_set_data(G_OBJECT(widget), GSTROKE_METRICS, metrics); + event = gtk_event_box_new(); + gtk_event_box_set_above_child(GTK_EVENT_BOX(event), TRUE); + gtk_widget_set_events(event, GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON2_MOTION_MASK); + gtk_widget_set_app_paintable(event, TRUE); + gtk_widget_show(event); - g_signal_connect(G_OBJECT(widget), "event", - G_CALLBACK(process_event), NULL); - } - else - _gstroke_init (metrics); + parent = gtk_widget_get_parent(widget); + g_object_ref(widget); + gtk_container_remove(GTK_CONTAINER(parent), widget); + gtk_container_add(GTK_CONTAINER(event), widget); + g_object_unref(widget); + gtk_container_add(GTK_CONTAINER(parent), event); + + g_object_set_data(G_OBJECT(event), GSTROKE_METRICS, metrics); - last_mouse_position.invalid = TRUE; + g_signal_connect(G_OBJECT(event), "event", G_CALLBACK(process_event), + widget); + g_signal_connect_after(G_OBJECT(event), "draw", + G_CALLBACK(gstroke_draw_cb), NULL); + } else { + _gstroke_init(metrics); + } + + last_mouse_position.invalid = TRUE; } void gstroke_disable(GtkWidget *widget) { - g_signal_handlers_disconnect_by_func(G_OBJECT(widget), G_CALLBACK(process_event), NULL); + GtkWidget *event = gtk_widget_get_parent(widget); + + g_return_if_fail(GTK_IS_EVENT_BOX(event)); + + g_signal_handlers_disconnect_by_func(G_OBJECT(event), + G_CALLBACK(process_event), widget); + g_signal_handlers_disconnect_by_func(G_OBJECT(event), + G_CALLBACK(gstroke_draw_cb), NULL); } -guint -gstroke_signal_connect (GtkWidget *widget, - const gchar *name, - void (*func)(GtkWidget *widget, void *data), - gpointer data) +void +gstroke_signal_connect(GtkWidget *widget, const gchar *name, + void (*func)(GtkWidget *widget, void *data), + gpointer data) { - struct gstroke_func_and_data *func_and_data; - GHashTable *hash_table = - (GHashTable*)g_object_get_data(G_OBJECT(widget), GSTROKE_SIGNALS); + struct gstroke_func_and_data *func_and_data; + GHashTable *hash_table = + (GHashTable *)g_object_get_data(G_OBJECT(widget), GSTROKE_SIGNALS); - if (!hash_table) - { - hash_table = g_hash_table_new (g_str_hash, g_str_equal); - g_object_set_data(G_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; + if (!hash_table) { + hash_table = + g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + g_object_set_data(G_OBJECT(widget), GSTROKE_SIGNALS, hash_table); + } + + func_and_data = g_new0(struct gstroke_func_and_data, 1); + func_and_data->func = func; + func_and_data->data = data; + g_hash_table_insert(hash_table, g_strdup(name), func_and_data); } static void @@ -310,100 +314,62 @@ void gstroke_cleanup (GtkWidget *widget) { - struct gstroke_metrics *metrics; - GHashTable *hash_table = - (GHashTable*)g_object_get_data(G_OBJECT(widget), GSTROKE_SIGNALS); - if (hash_table) - /* FIXME: does this delete the elements too? */ - g_hash_table_destroy (hash_table); + struct gstroke_metrics *metrics; + GHashTable *hash_table = (GHashTable *)g_object_steal_data(G_OBJECT(widget), + GSTROKE_SIGNALS); + if (hash_table) { + g_hash_table_destroy(hash_table); + } - g_object_steal_data(G_OBJECT(widget), GSTROKE_SIGNALS); - - metrics = (struct gstroke_metrics*)g_object_get_data(G_OBJECT(widget), - GSTROKE_METRICS); - g_free(metrics); - g_object_steal_data(G_OBJECT(widget), GSTROKE_METRICS); + metrics = (struct gstroke_metrics *)g_object_steal_data(G_OBJECT(widget), + GSTROKE_METRICS); + g_free(metrics); } - -/* This function should be written using GTK+ primitives*/ -static void -gstroke_invisible_window_init (GtkWidget *widget) +static gboolean +gstroke_draw_cb(GtkWidget *widget, cairo_t *cr, + G_GNUC_UNUSED gpointer user_data) { - 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(gtk_widget_get_window(widget)); - Window wind = gdk_x11_window_get_xid(gtk_widget_get_window(widget)); - int screen = DefaultScreen (disp); - - if (!gstroke_draw_strokes()) - return; - - gstroke_disp = disp; + struct gstroke_metrics *metrics = + (struct gstroke_metrics *)g_object_get_data(G_OBJECT(widget), + GSTROKE_METRICS); + GSList *iter = NULL; + p_point point; - /* 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; + if (last_mouse_position.invalid) { + return FALSE; + } - /* inhibit all the decorations */ - mask |= CWOverrideRedirect; - w_attr.override_redirect = True; + if (!metrics) { + return FALSE; + } - /* Don't set a background, transparent window */ - mask |= CWBackPixmap; - w_attr.background_pixmap = None; - - /* Default input window look */ - col_background = WhitePixel (gstroke_disp, screen); + iter = metrics->pointList; + if (!iter) { + return FALSE; + } - /* no border for the window */ -#if 0 - border_width = 5; -#endif - border_width = 0; - - col_border = BlackPixel (gstroke_disp, screen); + cairo_save(cr); - gstroke_window = XCreateSimpleWindow (gstroke_disp, wind, - 0, 0, - hints.width - 2 * border_width, - hints.height - 2 * border_width, - border_width, - col_border, col_background); + cairo_set_line_width(cr, 2.0); + cairo_set_dash(cr, NULL, 0, 0.0); + cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER); - gstroke_gc = XCreateGC (gstroke_disp, gstroke_window, 0, NULL); - - XSetFunction (gstroke_disp, gstroke_gc, GXinvert); - - XChangeWindowAttributes (gstroke_disp, gstroke_window, mask, &w_attr); + point = (p_point)iter->data; + iter = iter->next; + cairo_move_to(cr, point->x, point->y); - XSetLineAttributes (gstroke_disp, gstroke_gc, 2, LineSolid, - CapButt, JoinMiter); - XMapRaised (gstroke_disp, gstroke_window); + while (iter) { + point = (p_point)iter->data; + iter = iter->next; -#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); + cairo_line_to(cr, point->x, point->y); + } + cairo_stroke(cr); - /* 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 + cairo_restore(cr); + + return FALSE; }