pidgin/pidgin

Fix gestures plugin

2020-07-24, Elliott S
2f45a03838e9
Parents 6941fece679b
Children b119cf7a05b9
Fix gestures plugin

Update gestures plugin for gtkplugin.h removal.

Use correct alloc/free functions for gestures.

Use a GtkEventBox for the gestures event handling.

Convert gesture stroke drawing to Gdk/Cairo.

Always enable building the gestures plugin.
It no longer requires a platform-specific library.

Reviewed at https://reviews.imfreedom.org/r/47/
--- a/meson.build Thu Jul 23 20:13:47 2020 -0500
+++ b/meson.build Fri Jul 24 04:43:46 2020 -0500
@@ -331,11 +331,6 @@
endif
conf.set('HAVE_X11', x11.found())
-enable_gestures = get_option('gestures')
-if not get_option('gtkui') or not x11.found()
- enable_gestures = false
-endif
-
#######################################################################
# Check for LibXML2 (required)
#######################################################################
@@ -793,7 +788,6 @@
message('Build console UI.............. : ' + enable_consoleui.to_string())
message('Build for X11................. : ' + x11.found().to_string())
message('')
-message('Enable Gestures............... : ' + enable_gestures.to_string())
message('Protocols to build dynamically : @0@'.format(DYNAMIC_PRPLS))
message('')
message('Build with GStreamer support.. : ' + gstreamer.found().to_string())
--- a/meson_options.txt Thu Jul 23 20:13:47 2020 -0500
+++ b/meson_options.txt Fri Jul 24 04:43:46 2020 -0500
@@ -79,9 +79,6 @@
option('console-logging', type : 'boolean', value : false,
description : 'compile with console logging support')
-option('gestures', type : 'boolean', value : true,
- description : 'compile with the gestures plugin')
-
option('gevolution', type : 'feature', value : 'disabled',
description : 'compile with the Evolution plugin')
--- a/pidgin/plugins/gestures/gestures.c Thu Jul 23 20:13:47 2020 -0500
+++ b/pidgin/plugins/gestures/gestures.c Fri Jul 24 04:43:46 2020 -0500
@@ -18,13 +18,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02111-1301, USA.
*/
-#include "internal.h"
-#include "pidgin.h"
+
+#include <glib/gi18n-lib.h>
#include <purple.h>
#include "gtkconv.h"
-#include "gtkplugin.h"
#include "gtkutils.h"
#include "gstroke.h"
@@ -45,7 +44,7 @@
gtkconv = PIDGIN_CONVERSATION(conv);
- gstroke_cleanup(gtkconv->webview);
+ gstroke_cleanup(gtkconv->history);
g_object_unref(conv);
}
@@ -123,15 +122,15 @@
gtkconv = PIDGIN_CONVERSATION(conv);
- gstroke_enable(gtkconv->webview);
- gstroke_signal_connect(gtkconv->webview, "14789", stroke_close, conv);
- gstroke_signal_connect(gtkconv->webview, "1456", stroke_close, conv);
- gstroke_signal_connect(gtkconv->webview, "1489", stroke_close, conv);
- gstroke_signal_connect(gtkconv->webview, "74123", stroke_next_tab, conv);
- gstroke_signal_connect(gtkconv->webview, "7456", stroke_next_tab, conv);
- gstroke_signal_connect(gtkconv->webview, "96321", stroke_prev_tab, conv);
- gstroke_signal_connect(gtkconv->webview, "9654", stroke_prev_tab, conv);
- gstroke_signal_connect(gtkconv->webview, "25852", stroke_new_win, conv);
+ gstroke_enable(gtkconv->history);
+ gstroke_signal_connect(gtkconv->history, "14789", stroke_close, conv);
+ gstroke_signal_connect(gtkconv->history, "1456", stroke_close, conv);
+ gstroke_signal_connect(gtkconv->history, "1489", stroke_close, conv);
+ gstroke_signal_connect(gtkconv->history, "74123", stroke_next_tab, conv);
+ gstroke_signal_connect(gtkconv->history, "7456", stroke_next_tab, conv);
+ gstroke_signal_connect(gtkconv->history, "96321", stroke_prev_tab, conv);
+ gstroke_signal_connect(gtkconv->history, "9654", stroke_prev_tab, conv);
+ gstroke_signal_connect(gtkconv->history, "25852", stroke_new_win, conv);
}
static void
@@ -209,7 +208,7 @@
return ret;
}
-static PidginPluginInfo *
+static GPluginPluginInfo *
plugin_query(GError **error)
{
const gchar * const authors[] = {
@@ -217,7 +216,7 @@
NULL
};
- return pidgin_plugin_info_new(
+ return gplugin_plugin_info_new(
"id", GESTURES_PLUGIN_ID,
"name", N_("Mouse Gestures"),
"version", DISPLAY_VERSION,
@@ -288,8 +287,8 @@
gtkconv = PIDGIN_CONVERSATION(conv);
- gstroke_cleanup(gtkconv->webview);
- gstroke_disable(gtkconv->webview);
+ gstroke_cleanup(gtkconv->history);
+ gstroke_disable(gtkconv->history);
}
return TRUE;
--- a/pidgin/plugins/gestures/gstroke.h Thu Jul 23 20:13:47 2020 -0500
+++ b/pidgin/plugins/gestures/gstroke.h Fri Jul 24 04:43:46 2020 -0500
@@ -36,10 +36,9 @@
/* disable strokes for the widget */
void gstroke_disable(GtkWidget *widget);
-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);
/* frees all the memory allocated for stroke, should be called when
the widget is destroyed*/
--- a/pidgin/plugins/gestures/meson.build Thu Jul 23 20:13:47 2020 -0500
+++ b/pidgin/plugins/gestures/meson.build Fri Jul 24 04:43:46 2020 -0500
@@ -8,8 +8,7 @@
if PLUGINS
gestures = library('gestures', gestures_SOURCES,
- build_by_default: false,
- dependencies : [x11, libpurple_dep, libpidgin_dep, glib],
+ dependencies : [libpurple_dep, libpidgin_dep, glib],
name_prefix : '',
- install : false, install_dir : PIDGIN_PLUGINDIR)
+ install : true, install_dir : PIDGIN_PLUGINDIR)
endif
--- 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 <stdio.h>
#include <glib.h>
#include <gtk/gtk.h>
-#include <gdk/gdkx.h>
+#include <gdk/gdk.h>
#include "gstroke.h"
#include "gstroke-internal.h"
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-
-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;
}
--- a/pidgin/plugins/gestures/stroke.c Thu Jul 23 20:13:47 2020 -0500
+++ b/pidgin/plugins/gestures/stroke.c Fri Jul 24 04:43:46 2020 -0500
@@ -147,11 +147,11 @@
prev_bin = current_bin;
}
- /* move to next point, freeing current point from list */
-
- free (crt_elem->data);
- crt_elem = g_slist_next (crt_elem);
+ /* move to next point, freeing current point from list */
+ g_free(crt_elem->data);
+ crt_elem = g_slist_next(crt_elem);
}
+ metrics->pointList = NULL;
/* add the last run of points to the sequence */
sequence[sequence_count++] = '0' + current_bin;
/* printf ("DEBUG:: adding final sequence: %d\n", current_bin); */
--- a/pidgin/plugins/meson.build Thu Jul 23 20:13:47 2020 -0500
+++ b/pidgin/plugins/meson.build Fri Jul 24 04:43:46 2020 -0500
@@ -4,11 +4,8 @@
subdir('musicmessaging')
endif
-if enable_gestures
- subdir('gestures')
-endif
-
subdir('disco')
+subdir('gestures')
subdir('ticker')
subdir('xmppconsole')