aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Trowbridge <trow@ximian.com>2001-04-20 16:15:24 +0800
committerJon Trowbridge <trow@src.gnome.org>2001-04-20 16:15:24 +0800
commit7221bd79c2c61f5c66f35ffcf0f471f85bdb6ac7 (patch)
tree5f890cfefd04a8ec0c32aabdaebdf83801164876
parent4ab57773ab02e3460e8b34897662fe4eb66c7ad7 (diff)
downloadgsoc2013-evolution-7221bd79c2c61f5c66f35ffcf0f471f85bdb6ac7.tar.gz
gsoc2013-evolution-7221bd79c2c61f5c66f35ffcf0f471f85bdb6ac7.tar.zst
gsoc2013-evolution-7221bd79c2c61f5c66f35ffcf0f471f85bdb6ac7.zip
Limit total matches, for better performance on slow machines. It is
2001-04-20 Jon Trowbridge <trow@ximian.com> * gal/e-text/e-completion-test.c: Limit total matches, for better performance on slow machines. It is supposed to be a test, so correctness of the completion operations isn't really a priority... * gal/e-text/e-completion-view.c (e_completion_view_construct): Set GTK_CAN_FOCUS flag. * gal/e-text/e-entry.c (e_entry_show_popup): Evil! Evil! Unclean! Unclean! Manually check if the pointer is in the area where the popup is going to appear, and if it is, warp the pointer out of the way. After days of fucking around, this horrible hack is the only way that I've been able to figure out to keep the focus from being taken away from the entry and ending up somewhere strange when the popup pops up. (The main problem is with the case of focus-follows-cursor --- click-to-focus works fine. Sawfish idiocincracies may also be causing problems, but I don't want to unjustly accuse the WM of anything, as tempting and appealing as that can be.) (key_press_cb): Proxy for forwarding the popup's key press events to the entry. (key_release_cb): Proxy for forwarding the popup's key release events to the entry. These proxies should be enough to take care of my focus problems. Unfortunately, they aren't, and the pointer-warping-focus-horror is required for reasons that I don't fully understand. * gal/e-text/e-text.c (_get_xy_from_position): Made _get_xy_from_position return a boolean. It returns TRUE if the computation was successful (and if valid data is now in *xp and *yp), FALSE otherwise. Make sure that text->lines is not NULL, and return FALSE if it is. (_get_position): Test that _get_xy_from_position returns TRUE before using the values in x and y. (_get_position): Test that _get_xy_from_position returns TRUE before using the values in x and y. Garbage values being returned in passed-in pointers created a race condition where you could hang an EText if you deleted the entire contents of the buffer really quickly. svn path=/trunk/; revision=9468
-rw-r--r--widgets/text/e-completion-test.c17
-rw-r--r--widgets/text/e-completion-view.c6
-rw-r--r--widgets/text/e-entry.c80
-rw-r--r--widgets/text/e-text.c24
4 files changed, 98 insertions, 29 deletions
diff --git a/widgets/text/e-completion-test.c b/widgets/text/e-completion-test.c
index 626842cb51..8550e9a10f 100644
--- a/widgets/text/e-completion-test.c
+++ b/widgets/text/e-completion-test.c
@@ -6,7 +6,7 @@
#include "e-completion.h"
#include "e-entry.h"
-#define TIMEOUT 50
+#define TIMEOUT 10
/* Dictionary Lookup test */
@@ -59,7 +59,7 @@ find_word (const gchar *str)
a = m;
else
return m;
- };
+ }
return b;
}
@@ -71,6 +71,7 @@ struct {
gint current;
gint len;
gint limit;
+ gint count;
} dict_info;
static guint dict_tag = 0;
@@ -88,15 +89,19 @@ dict_check (gpointer ptr)
}
i = dict_info.current;
- while (limit > 0 && i < word_count && g_strncasecmp (dict_info.txt, word_array[i], dict_info.len) == 0) {
+ while (limit > 0
+ && i < word_count
+ && dict_info.count < 50
+ && g_strncasecmp (dict_info.txt, word_array[i], dict_info.len) == 0) {
e_completion_found_match_full (dict_info.complete, word_array[i],
dict_info.len / (double)strlen (word_array[i]),
NULL, NULL);
++i;
--limit;
+ ++dict_info.count;
}
dict_info.current = i;
- dict_info.limit = MIN (dict_info.limit*2, 200);
+ dict_info.limit = MIN (dict_info.limit*2, 400);
if (limit != 0) {
dict_tag = 0;
@@ -125,10 +130,10 @@ begin_dict_search (ECompletion *complete, const gchar *txt, gint pos, gint limit
dict_info.start = -1;
dict_info.current = -1;
dict_info.len = len;
- dict_info.limit = 20;
+ dict_info.limit = 100;
+ dict_info.count = 0;
dict_tag = gtk_timeout_add (TIMEOUT, dict_check, NULL);
} else {
- g_message ("halting");
e_completion_end_search (complete);
}
}
diff --git a/widgets/text/e-completion-view.c b/widgets/text/e-completion-view.c
index 825e7c5e11..2ffb19f3e3 100644
--- a/widgets/text/e-completion-view.c
+++ b/widgets/text/e-completion-view.c
@@ -150,6 +150,7 @@ e_completion_view_class_init (ECompletionViewClass *klass)
gtk_object_class_add_signals (object_class, e_completion_view_signals, E_COMPLETION_VIEW_LAST_SIGNAL);
object_class->destroy = e_completion_view_destroy;
+
widget_class->key_press_event = e_completion_view_local_key_press_handler;
}
@@ -306,7 +307,7 @@ e_completion_view_key_press_handler (GtkWidget *w, GdkEventKey *key_event, gpoin
ECompletionView *cv = E_COMPLETION_VIEW (user_data);
gint dir = 0;
gboolean key_handled = TRUE;
-
+
/* Start up a completion.*/
if (cv->complete_key && key_event->keyval == cv->complete_key && !cv->editable) {
gtk_signal_emit (GTK_OBJECT (cv), e_completion_view_signals[E_COMPLETION_VIEW_BROWSE], NULL);
@@ -380,6 +381,7 @@ e_completion_view_key_press_handler (GtkWidget *w, GdkEventKey *key_event, gpoin
gtk_signal_emit (GTK_OBJECT (cv), e_completion_view_signals[E_COMPLETION_VIEW_UNBROWSE]);
stop_emission:
+
if (key_handled)
gtk_signal_emit_stop_by_name (GTK_OBJECT (w), "key_press_event");
@@ -518,6 +520,8 @@ e_completion_view_construct (ECompletionView *cv, ECompletion *completion)
/* Make sure we don't call construct twice. */
g_return_if_fail (cv->completion == NULL);
+ GTK_WIDGET_SET_FLAGS (GTK_WIDGET (cv), GTK_CAN_FOCUS);
+
cv->completion = completion;
gtk_object_ref (GTK_OBJECT (completion));
diff --git a/widgets/text/e-entry.c b/widgets/text/e-entry.c
index 4ab21be725..b84e622de6 100644
--- a/widgets/text/e-entry.c
+++ b/widgets/text/e-entry.c
@@ -49,6 +49,12 @@
#include "e-text.h"
#include "e-entry.h"
+#define EVIL_POINTER_WARPING_HACK
+
+#ifdef EVIL_POINTER_WARPING_HACK
+#include <gdk/gdkx.h>
+#endif
+
#define MIN_ENTRY_WIDTH 150
#define INNER_BORDER 2
@@ -457,13 +463,13 @@ e_entry_show_popup (EEntry *entry, gboolean visible)
if (visible) {
GtkAllocation *dim = &(GTK_WIDGET (entry)->allocation);
- gint x, y, fudge;
+ gint x, y, xo, yo, fudge;
const GdkEventMask grab_mask = (GdkEventMask)GDK_BUTTON_PRESS_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON_RELEASE_MASK;
/* Figure out where to put our popup. */
- gdk_window_get_origin (GTK_WIDGET (entry)->window, &x, &y);
- x += dim->x;
- y += dim->height + dim->y;
+ gdk_window_get_origin (GTK_WIDGET (entry)->window, &xo, &yo);
+ x = xo + dim->x;
+ y = yo + dim->height + dim->y;
/* Put our popup slightly to the right and up, to try to give a visual cue that this popup
is tied to this entry. Otherwise one-row popups can sort of "blend" with an entry
@@ -475,16 +481,41 @@ e_entry_show_popup (EEntry *entry, gboolean visible)
gtk_widget_set_uposition (pop, x, y);
e_completion_view_set_width (E_COMPLETION_VIEW (entry->priv->completion_view), dim->width);
+#ifdef EVIL_POINTER_WARPING_HACK
+ /*
+ I should have learned by now to listen to Havoc...
+ http://developer.gnome.org/doc/GGAD/faqs.html
+ */
+
+ if (! entry->priv->popup_is_visible) {
+ GdkWindow *gwin = GTK_WIDGET (entry)->window;
+ gint xx, yy;
+ gdk_window_get_pointer (gwin, &xx, &yy, NULL);
+ xx += xo;
+ yy += yo;
+
+ /* If we are inside the "zone of death" where the popup will appear, warp the pointer to safety.
+ This is a horrible thing to do. */
+ if (y <= yy && yy < yy + dim->height && x <= xx && xx < xx + dim->width) {
+ XWarpPointer (GDK_WINDOW_XDISPLAY (gwin), None, GDK_WINDOW_XWINDOW (gwin),
+ 0, 0, 0, 0,
+ xx - xo, (y-1) - yo);
+ }
+ }
+#endif
+
gtk_widget_show (pop);
if (! entry->priv->ptr_grab) {
- entry->priv->ptr_grab = gdk_pointer_grab (GTK_WIDGET (entry->priv->completion_view)->window, TRUE,
- grab_mask, NULL, NULL, GDK_CURRENT_TIME);
- if (entry->priv->ptr_grab)
- gtk_grab_add (GTK_WIDGET (entry->priv->completion_view));
+ entry->priv->ptr_grab = (0 == gdk_pointer_grab (GTK_WIDGET (entry->priv->completion_view)->window, TRUE,
+ grab_mask, NULL, NULL, GDK_CURRENT_TIME));
+ if (entry->priv->ptr_grab) {
+ gtk_grab_add (GTK_WIDGET (entry->priv->completion_view));
+ }
}
-
+
+
} else {
gtk_widget_hide (pop);
@@ -497,8 +528,6 @@ e_entry_show_popup (EEntry *entry, gboolean visible)
entry->priv->ptr_grab = FALSE;
entry->priv->last_completion_pos = -1;
-
-
}
e_completion_view_set_editable (E_COMPLETION_VIEW (entry->priv->completion_view), visible);
@@ -668,6 +697,24 @@ button_press_cb (GtkWidget *w, GdkEvent *ev, gpointer user_data)
unbrowse_cb (E_COMPLETION_VIEW (w), entry);
}
+static gint
+key_press_cb (GtkWidget *w, GdkEventKey *ev, gpointer user_data)
+{
+ gint rv = 0;
+ /* Forward signal */
+ gtk_signal_emit_by_name (GTK_OBJECT (user_data), "key_press_event", ev, &rv);
+ return rv;
+}
+
+static gint
+key_release_cb (GtkWidget *w, GdkEventKey *ev, gpointer user_data)
+{
+ gint rv = 0;
+ /* Forward signal */
+ gtk_signal_emit_by_name (GTK_OBJECT (user_data), "key_release_event", ev, &rv);
+ return rv;
+}
+
void
e_entry_enable_completion_full (EEntry *entry, ECompletion *completion, gint delay, EEntryCompletionHandler handler)
{
@@ -725,7 +772,16 @@ e_entry_enable_completion_full (EEntry *entry, ECompletion *completion, gint del
entry);
entry->priv->completion_view_popup = gtk_window_new (GTK_WINDOW_POPUP);
-
+
+ gtk_signal_connect (GTK_OBJECT (entry->priv->completion_view_popup),
+ "key_press_event",
+ GTK_SIGNAL_FUNC (key_press_cb),
+ entry->canvas);
+ gtk_signal_connect (GTK_OBJECT (entry->priv->completion_view_popup),
+ "key_release_event",
+ GTK_SIGNAL_FUNC (key_release_cb),
+ entry->canvas);
+
gtk_object_ref (GTK_OBJECT (entry->priv->completion_view_popup));
gtk_object_sink (GTK_OBJECT (entry->priv->completion_view_popup));
gtk_window_set_policy (GTK_WINDOW (entry->priv->completion_view_popup), FALSE, TRUE, FALSE);
diff --git a/widgets/text/e-text.c b/widgets/text/e-text.c
index ceb09ab25d..e9b6e3272f 100644
--- a/widgets/text/e-text.c
+++ b/widgets/text/e-text.c
@@ -2471,12 +2471,10 @@ e_text_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double
*y2 = *y1 + height;
}
-static void
+static gboolean
_get_xy_from_position (EText *text, gint position, gint *xp, gint *yp)
{
- if ( !text->lines )
- return;
- if (xp || yp) {
+ if (text->lines && (xp || yp)) {
struct line *lines = NULL;
int x, y;
double xd, yd;
@@ -2506,7 +2504,11 @@ _get_xy_from_position (EText *text, gint position, gint *xp, gint *yp)
*xp = x;
if (yp)
*yp = y;
+
+ return TRUE;
}
+
+ return FALSE;
}
static gint
@@ -3312,15 +3314,17 @@ _get_position(EText *text, ETextEventProcessorCommand *command)
break;
case E_TEP_FORWARD_LINE:
- _get_xy_from_position(text, text->selection_end, &x, &y);
- y += e_font_height (text->font);
- new_pos = _get_position_from_xy(text, x, y);
+ if (_get_xy_from_position(text, text->selection_end, &x, &y)) {
+ y += e_font_height (text->font);
+ new_pos = _get_position_from_xy(text, x, y);
+ }
break;
case E_TEP_BACKWARD_LINE:
- _get_xy_from_position(text, text->selection_end, &x, &y);
- y -= e_font_height (text->font);
- new_pos = _get_position_from_xy(text, x, y);
+ if (_get_xy_from_position(text, text->selection_end, &x, &y)) {
+ y -= e_font_height (text->font);
+ new_pos = _get_position_from_xy(text, x, y);
+ }
break;
case E_TEP_SELECT_WORD: