* Claudio Saavedra <csaavedra@igalia.com>
*/
-#include <config.h>
-#include <string.h>
-
-#include <gtk/gtk.h>
-#include <gdk/gdkkeysyms.h>
-
-#include <libempathy/empathy-utils.h>
-
+#include "config.h"
#include "empathy-live-search.h"
-#include "empathy-gtk-marshal.h"
+
+#include "empathy-utils.h"
G_DEFINE_TYPE (EmpathyLiveSearch, empathy_live_search, GTK_TYPE_HBOX)
static guint signals[LAST_SIGNAL];
-static void live_search_hook_widget_destroy_cb (GtkObject *object,
+static void live_search_hook_widget_destroy_cb (GtkWidget *object,
gpointer user_data);
/**
{
gunichar retval = 0;
GUnicodeType utype;
- gunichar *decomp;
- gsize dlen;
utype = g_unichar_type (ch);
case G_UNICODE_SPACE_SEPARATOR:
default:
ch = g_unichar_tolower (ch);
- decomp = g_unicode_canonical_decomposition (ch, &dlen);
- if (decomp != NULL)
- {
- retval = decomp[0];
- g_free (decomp);
- }
+ g_unichar_fully_decompose (ch, FALSE, &retval, 1);
}
return retval;
}
}
-static GPtrArray *
-strip_utf8_string (const gchar *string)
+GPtrArray *
+empathy_live_search_strip_utf8_string (const gchar *string)
{
GPtrArray *word_array = NULL;
GString *word = NULL;
return FALSE;
}
-static gboolean
-live_search_match_words (const gchar *string,
+gboolean
+empathy_live_search_match_words (const gchar *string,
GPtrArray *words)
{
guint i;
return TRUE;
}
+static gboolean
+fire_key_navigation_sig (EmpathyLiveSearch *self,
+ GdkEventKey *event)
+{
+ gboolean ret;
+
+ g_signal_emit (self, signals[KEYNAV], 0, event, &ret);
+ return ret;
+}
+
static gboolean
live_search_entry_key_pressed_cb (GtkEntry *entry,
GdkEventKey *event,
gpointer user_data)
{
EmpathyLiveSearch *self = EMPATHY_LIVE_SEARCH (user_data);
- gboolean ret;
/* if esc key pressed, hide the search */
- if (event->keyval == GDK_Escape)
+ if (event->keyval == GDK_KEY_Escape)
{
gtk_widget_hide (GTK_WIDGET (self));
return TRUE;
}
/* emit key navigation signal, so other widgets can respond to it properly */
- if (event->keyval == GDK_Up || event->keyval == GDK_Down
- || event->keyval == GDK_Left || event->keyval == GDK_Right)
+ if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down
+ || event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_Page_Down
+ || event->keyval == GDK_KEY_Menu)
{
- g_signal_emit (self, signals[KEYNAV], 0, event, &ret);
- return ret;
+ return fire_key_navigation_sig (self, event);
}
+ if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_End ||
+ event->keyval == GDK_KEY_space)
+ {
+ /* If the live search is visible, the entry should catch the Home/End
+ * and space events */
+ if (!gtk_widget_get_visible (GTK_WIDGET (self)))
+ {
+ return fire_key_navigation_sig (self, event);
+ }
+ }
+
return FALSE;
}
if (priv->stripped_words != NULL)
g_ptr_array_unref (priv->stripped_words);
- priv->stripped_words = strip_utf8_string (text);
+ priv->stripped_words = empathy_live_search_strip_utf8_string (text);
g_object_notify (G_OBJECT (self), "text");
}
/* dont forward this event to the entry, else the event is consumed by the
* entry and does not close the window */
if (!gtk_widget_get_visible (GTK_WIDGET (self)) &&
- event->keyval == GDK_Escape)
+ event->keyval == GDK_KEY_Escape)
return FALSE;
/* do not show the search if CTRL and/or ALT are pressed with a key
* this is needed, because otherwise the CTRL + F accel would not work,
* because the entry consumes it */
if (event->state & (GDK_MOD1_MASK | GDK_CONTROL_MASK) ||
- event->keyval == GDK_Control_L ||
- event->keyval == GDK_Control_R)
+ event->keyval == GDK_KEY_Control_L ||
+ event->keyval == GDK_KEY_Control_R)
return FALSE;
- /* dont forward the up and down arrow keys to the entry, they are needed for
- * navigation in the treeview and are not needed in the search entry */
- if (event->keyval == GDK_Up || event->keyval == GDK_Down)
+ /* dont forward the up/down and Page Up/Down arrow keys to the entry,
+ * they are needed for navigation in the treeview and are not needed in
+ * the search entry */
+ if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down ||
+ event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_Page_Down ||
+ event->keyval == GDK_KEY_Menu)
return FALSE;
+ if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_End ||
+ event->keyval == GDK_KEY_space)
+ {
+ /* Home/End and space keys have to be forwarded to the entry only if
+ * the live search is visible (to move the cursor inside the entry). */
+ if (!gtk_widget_get_visible (GTK_WIDGET (self)))
+ return FALSE;
+ }
+
+ /* Don't forward shift keys events as focusing the search entry would
+ * cancel an in-progress editing on a cell renderer (like when renaming a
+ * group). There is no point focusing it anyway as we don't display the
+ * search entry when only a shift key is pressed. */
+ if (event->keyval == GDK_KEY_Shift_L ||
+ event->keyval == GDK_KEY_Shift_R)
+ return FALSE;
+
/* realize the widget if it is not realized yet */
gtk_widget_realize (priv->search_entry);
if (!gtk_widget_has_focus (priv->search_entry))
}
static void
-live_search_hook_widget_destroy_cb (GtkObject *object,
+live_search_hook_widget_destroy_cb (GtkWidget *object,
gpointer user_data)
{
EmpathyLiveSearch *self = EMPATHY_LIVE_SEARCH (user_data);
}
static void
-live_search_hide (GtkWidget *widget)
+live_search_unmap (GtkWidget *widget)
{
EmpathyLiveSearch *self = EMPATHY_LIVE_SEARCH (widget);
EmpathyLiveSearchPriv *priv = GET_PRIV (self);
- GTK_WIDGET_CLASS (empathy_live_search_parent_class)->hide (widget);
+ GTK_WIDGET_CLASS (empathy_live_search_parent_class)->unmap (widget);
+
+ /* unmap can happen if a parent gets hidden, in that case we want to hide
+ * the live search as well, so when it gets mapped again, the live search
+ * won't be shown. */
+ gtk_widget_hide (widget);
gtk_entry_set_text (GTK_ENTRY (priv->search_entry), "");
- gtk_widget_grab_focus (priv->hook_widget);
+
+ if (priv->hook_widget != NULL)
+ gtk_widget_grab_focus (priv->hook_widget);
}
static void
object_class->get_property = live_search_get_property;
object_class->set_property = live_search_set_property;
- widget_class->hide = live_search_hide;
+ widget_class->unmap = live_search_unmap;
widget_class->show = live_search_show;
widget_class->grab_focus = live_search_grab_focus;
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
+ g_cclosure_marshal_generic,
G_TYPE_NONE, 0);
signals[KEYNAV] = g_signal_new ("key-navigation",
G_SIGNAL_RUN_LAST,
0,
g_signal_accumulator_true_handled, NULL,
- _empathy_gtk_marshal_BOOLEAN__BOXED,
+ g_cclosure_marshal_generic,
G_TYPE_BOOLEAN, 1, GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
param_spec = g_param_spec_object ("hook-widget", "Live Search Hook Widget",
priv = GET_PRIV (self);
- return live_search_match_words (string, priv->stripped_words);
+ return empathy_live_search_match_words (string, priv->stripped_words);
}
gboolean
GPtrArray *words;
gboolean match;
- words = strip_utf8_string (prefix);
- match = live_search_match_words (string, words);
+ words = empathy_live_search_strip_utf8_string (prefix);
+ match = empathy_live_search_match_words (string, words);
if (words != NULL)
g_ptr_array_unref (words);
return match;
}
+GPtrArray *
+empathy_live_search_get_words (EmpathyLiveSearch *self)
+{
+ EmpathyLiveSearchPriv *priv = GET_PRIV (self);
+
+ return priv->stripped_words;
+}