pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Add a get_minimum_search_length to PurpleProtocolContacts
default
tip
4 days ago, Gary Kramlich
5ebb4beb29b7
Add a get_minimum_search_length to PurpleProtocolContacts
This can be used by user interfaces, to not call
PurpleProtocolContacts.search_async with strings smaller than this length.
Testing Done:
Called in the turtles and ran the protocol_contacts test under valgrind.
Reviewed at https://reviews.imfreedom.org/r/3164/
/*
GNOME stroke implementation
Copyright (c) 2000, 2001 Dan Nicolaescu
See the file COPYING for distribution information.
*/
#include
"purpleconfig.h"
#ifdef HAVE_UNISTD_H
#include
<unistd.h>
#endif
#include
<stdlib.h>
#include
<stdio.h>
#include
<glib.h>
#include
<gtk/gtk.h>
#include
<gdk/gdk.h>
#include
"gstroke.h"
#include
"gstroke-internal.h"
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
int
mouse_button
=
2
;
static
gboolean
draw_strokes
=
FALSE
;
#define GSTROKE_TIMEOUT_DURATION 10
#define GSTROKE_SIGNALS "gstroke_signals"
struct
gstroke_func_and_data
{
void
(
*
func
)(
GtkWidget
*
,
void
*
);
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
;
GdkSeat
*
seat
;
GdkDevice
*
dev
;
g_return_if_fail
(
widget
!=
NULL
);
seat
=
gdk_display_get_default_seat
(
gtk_widget_get_display
(
widget
));
dev
=
gdk_seat_get_pointer
(
seat
);
gdk_window_get_device_position
(
gtk_widget_get_window
(
widget
),
dev
,
&
x
,
&
y
,
NULL
);
last_mouse_position
.
invalid
=
FALSE
;
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
=
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
gstroke_timeout
(
gpointer
data
)
{
GtkWidget
*
widget
;
g_return_val_if_fail
(
data
!=
NULL
,
FALSE
);
widget
=
GTK_WIDGET
(
data
);
record_stroke_segment
(
widget
);
return
TRUE
;
}
static
void
gstroke_cancel
(
GtkWidget
*
widget
,
GdkEvent
*
event
)
{
last_mouse_position
.
invalid
=
TRUE
;
g_clear_handle_id
(
&
timer_id
,
g_source_remove
);
if
(
event
!=
NULL
)
{
gdk_seat_ungrab
(
gdk_event_get_seat
(
event
));
}
if
(
gstroke_draw_strokes
())
{
gtk_widget_queue_draw
(
widget
);
}
}
static
gint
process_event
(
GtkWidget
*
widget
,
GdkEvent
*
event
,
gpointer
data
)
{
static
GtkWidget
*
original_widget
=
NULL
;
static
GdkCursor
*
cursor
=
NULL
;
switch
(
event
->
type
)
{
case
GDK_BUTTON_PRESS
:
if
(
event
->
button
.
button
!=
gstroke_get_mouse_button
())
{
/* Similar to the bug below catch when any other button is
* clicked after the middle button is clicked (but possibly
* not released)
*/
gstroke_cancel
(
widget
,
event
);
original_widget
=
NULL
;
break
;
}
original_widget
=
widget
;
/* remember the widget where
the stroke started */
record_stroke_segment
(
widget
);
if
(
cursor
==
NULL
)
{
GdkDisplay
*
display
=
gtk_widget_get_display
(
widget
);
cursor
=
gdk_cursor_new_for_display
(
display
,
GDK_PENCIL
);
}
gdk_seat_grab
(
gdk_event_get_seat
(
event
),
gtk_widget_get_window
(
widget
),
GDK_SEAT_CAPABILITY_ALL_POINTING
,
FALSE
,
cursor
,
event
,
NULL
,
NULL
);
timer_id
=
g_timeout_add
(
GSTROKE_TIMEOUT_DURATION
,
gstroke_timeout
,
widget
);
return
TRUE
;
case
GDK_BUTTON_RELEASE
:
if
((
event
->
button
.
button
!=
gstroke_get_mouse_button
())
||
(
original_widget
==
NULL
))
{
/* Nice bug when you hold down one button and press another. */
/* We'll just cancel the gesture instead. */
gstroke_cancel
(
widget
,
event
);
original_widget
=
NULL
;
break
;
}
last_mouse_position
.
invalid
=
TRUE
;
original_widget
=
NULL
;
g_clear_handle_id
(
&
timer_id
,
g_source_remove
);
gdk_seat_ungrab
(
gdk_event_get_seat
(
event
));
{
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
())
{
gtk_widget_queue_draw
(
widget
);
}
_gstroke_canonical
(
result
,
metrics
);
gstroke_execute
(
history
,
result
);
}
return
FALSE
;
default
:
break
;
}
return
FALSE
;
}
void
gstroke_set_draw_strokes
(
gboolean
draw
)
{
draw_strokes
=
draw
;
}
gboolean
gstroke_draw_strokes
(
void
)
{
return
draw_strokes
;
}
void
gstroke_set_mouse_button
(
gint
button
)
{
mouse_button
=
button
;
}
guint
gstroke_get_mouse_button
(
void
)
{
return
mouse_button
;
}
void
gstroke_enable
(
GtkWidget
*
widget
)
{
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
;
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_set_visible
(
event
,
TRUE
);
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
);
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
)
{
GtkWidget
*
event
=
gtk_widget_get_parent
(
widget
);
g_return_if_fail
(
GTK_IS_EVENT_BOX
(
event
));
g_signal_handlers_disconnect_by_func
(
event
,
process_event
,
widget
);
g_signal_handlers_disconnect_by_func
(
event
,
gstroke_draw_cb
,
NULL
);
}
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
);
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
gstroke_execute
(
GtkWidget
*
widget
,
const
gchar
*
name
)
{
GHashTable
*
hash_table
=
(
GHashTable
*
)
g_object_get_data
(
G_OBJECT
(
widget
),
GSTROKE_SIGNALS
);
#if 0
purple_debug_misc("gestures", "gstroke %s", name);
#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
*
)
g_object_steal_data
(
G_OBJECT
(
widget
),
GSTROKE_SIGNALS
);
g_clear_pointer
(
&
hash_table
,
g_hash_table_destroy
);
metrics
=
(
struct
gstroke_metrics
*
)
g_object_steal_data
(
G_OBJECT
(
widget
),
GSTROKE_METRICS
);
g_free
(
metrics
);
}
static
gboolean
gstroke_draw_cb
(
GtkWidget
*
widget
,
cairo_t
*
cr
,
G_GNUC_UNUSED
gpointer
user_data
)
{
struct
gstroke_metrics
*
metrics
=
(
struct
gstroke_metrics
*
)
g_object_get_data
(
G_OBJECT
(
widget
),
GSTROKE_METRICS
);
GSList
*
iter
=
NULL
;
p_point
point
;
if
(
last_mouse_position
.
invalid
)
{
return
FALSE
;
}
if
(
!
metrics
)
{
return
FALSE
;
}
iter
=
metrics
->
pointList
;
if
(
!
iter
)
{
return
FALSE
;
}
cairo_save
(
cr
);
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
);
point
=
(
p_point
)
iter
->
data
;
iter
=
iter
->
next
;
cairo_move_to
(
cr
,
point
->
x
,
point
->
y
);
while
(
iter
)
{
point
=
(
p_point
)
iter
->
data
;
iter
=
iter
->
next
;
cairo_line_to
(
cr
,
point
->
x
,
point
->
y
);
}
cairo_stroke
(
cr
);
cairo_restore
(
cr
);
return
FALSE
;
}