* podcast/rb-podcast-manager.c: (rb_podcast_manager_add_post): add
[rhythmbox.git] / widgets / rb-search-entry.c
blobd779ac81af8d162860f0d8f278c09074f085d48e
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3 * arch-tag: Implementation of search entry widget
5 * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
6 * Copyright (C) 2003 Colin Walters <walters@verbum.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <config.h>
26 #include <string.h>
28 #include <glib/gi18n.h>
29 #include <gtk/gtk.h>
30 #include "libsexy/sexy-icon-entry.h"
32 #include "rb-search-entry.h"
34 static void rb_search_entry_class_init (RBSearchEntryClass *klass);
35 static void rb_search_entry_init (RBSearchEntry *entry);
36 static void rb_search_entry_finalize (GObject *object);
37 static gboolean rb_search_entry_timeout_cb (RBSearchEntry *entry);
38 static void rb_search_entry_changed_cb (GtkEditable *editable,
39 RBSearchEntry *entry);
40 static void rb_search_entry_activate_cb (GtkEntry *gtkentry,
41 RBSearchEntry *entry);
42 static gboolean rb_search_entry_focus_out_event_cb (GtkWidget *widget,
43 GdkEventFocus *event,
44 RBSearchEntry *entry);
46 struct RBSearchEntryPrivate
48 GtkWidget *entry;
50 gboolean clearing;
52 guint timeout;
54 gboolean is_a11y_theme;
57 G_DEFINE_TYPE (RBSearchEntry, rb_search_entry, GTK_TYPE_HBOX)
58 #define RB_SEARCH_ENTRY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_SEARCH_ENTRY, RBSearchEntryPrivate))
60 enum
62 SEARCH,
63 ACTIVATE,
64 LAST_SIGNAL
67 static guint rb_search_entry_signals[LAST_SIGNAL] = { 0 };
69 static void
70 rb_search_entry_class_init (RBSearchEntryClass *klass)
72 GObjectClass *object_class = G_OBJECT_CLASS (klass);
74 object_class->finalize = rb_search_entry_finalize;
76 rb_search_entry_signals[SEARCH] =
77 g_signal_new ("search",
78 G_OBJECT_CLASS_TYPE (object_class),
79 G_SIGNAL_RUN_LAST,
80 G_STRUCT_OFFSET (RBSearchEntryClass, search),
81 NULL, NULL,
82 g_cclosure_marshal_VOID__STRING,
83 G_TYPE_NONE,
85 G_TYPE_STRING);
86 rb_search_entry_signals[ACTIVATE] =
87 g_signal_new ("activate",
88 G_OBJECT_CLASS_TYPE (object_class),
89 G_SIGNAL_RUN_LAST,
90 G_STRUCT_OFFSET (RBSearchEntryClass, activate),
91 NULL, NULL,
92 g_cclosure_marshal_VOID__VOID,
93 G_TYPE_NONE,
94 0);
96 g_type_class_add_private (klass, sizeof (RBSearchEntryPrivate));
99 static void
100 rb_search_entry_init (RBSearchEntry *entry)
102 GtkWidget *label;
103 GtkSettings *settings;
104 char *theme;
106 entry->priv = RB_SEARCH_ENTRY_GET_PRIVATE (entry);
108 settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (entry)));
109 g_object_get (settings, "gtk-theme-name", &theme, NULL);
110 entry->priv->is_a11y_theme = strncmp (theme, "HighContrast", strlen ("HighContrast")) == 0 ||
111 strncmp (theme, "LowContrast", strlen ("LowContrast")) == 0;
112 g_free (theme);
114 /* this string can only be so long, or there wont be a search entry :) */
115 label = gtk_label_new_with_mnemonic (_("_Search:"));
116 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT);
117 gtk_box_pack_start (GTK_BOX (entry), label, FALSE, TRUE, 0);
119 entry->priv->entry = sexy_icon_entry_new ();
120 sexy_icon_entry_add_clear_button (SEXY_ICON_ENTRY (entry->priv->entry));
122 gtk_label_set_mnemonic_widget (GTK_LABEL (label),
123 entry->priv->entry);
125 gtk_box_pack_start (GTK_BOX (entry), entry->priv->entry, TRUE, TRUE, 0);
127 g_signal_connect_object (G_OBJECT (entry->priv->entry),
128 "changed",
129 G_CALLBACK (rb_search_entry_changed_cb),
130 entry, 0);
131 g_signal_connect_object (G_OBJECT (entry->priv->entry),
132 "focus_out_event",
133 G_CALLBACK (rb_search_entry_focus_out_event_cb),
134 entry, 0);
135 g_signal_connect_object (G_OBJECT (entry->priv->entry),
136 "activate",
137 G_CALLBACK (rb_search_entry_activate_cb),
138 entry, 0);
141 static void
142 rb_search_entry_finalize (GObject *object)
144 RBSearchEntry *entry;
146 g_return_if_fail (object != NULL);
147 g_return_if_fail (RB_IS_SEARCH_ENTRY (object));
149 entry = RB_SEARCH_ENTRY (object);
151 g_return_if_fail (entry->priv != NULL);
153 G_OBJECT_CLASS (rb_search_entry_parent_class)->finalize (object);
156 RBSearchEntry *
157 rb_search_entry_new (void)
159 RBSearchEntry *entry;
161 entry = RB_SEARCH_ENTRY (g_object_new (RB_TYPE_SEARCH_ENTRY,
162 "spacing", 5,
163 NULL));
165 g_return_val_if_fail (entry->priv != NULL, NULL);
167 return entry;
170 void
171 rb_search_entry_clear (RBSearchEntry *entry)
173 if (entry->priv->timeout != 0) {
174 g_source_remove (entry->priv->timeout);
175 entry->priv->timeout = 0;
178 entry->priv->clearing = TRUE;
180 gtk_entry_set_text (GTK_ENTRY (entry->priv->entry), "");
182 entry->priv->clearing = FALSE;
185 void
186 rb_search_entry_set_text (RBSearchEntry *entry, const char *text)
188 gtk_entry_set_text (GTK_ENTRY (entry->priv->entry),
189 text ? text : "");
192 static void
193 rb_search_entry_check_style (RBSearchEntry *entry)
195 /*GdkColor fg_colour;*/
196 GdkColor bg_colour;
197 static const GdkColor fallback_bg_colour = { 0, 0xf7f7, 0xf7f7, 0xbebe }; /* yellow-ish */
198 const gchar* text;
200 if (entry->priv->is_a11y_theme)
201 return;
203 /*fg_colour = GTK_WIDGET(entry)->style->text[GTK_STATE_NORMAL];*/
204 bg_colour = fallback_bg_colour;
206 text = gtk_entry_get_text (GTK_ENTRY (entry->priv->entry));
207 if (text && *text) {
208 /*gtk_widget_modify_text (entry->priv->entry, GTK_STATE_NORMAL, &fg_colour);*/
209 gtk_widget_modify_base (entry->priv->entry, GTK_STATE_NORMAL, &bg_colour);
210 } else {
211 /*gtk_widget_modify_text (entry->priv->entry, GTK_STATE_NORMAL, NULL);*/
212 gtk_widget_modify_base (entry->priv->entry, GTK_STATE_NORMAL, NULL);
215 gtk_widget_queue_draw (GTK_WIDGET (entry));
218 static void
219 rb_search_entry_changed_cb (GtkEditable *editable,
220 RBSearchEntry *entry)
222 rb_search_entry_check_style (entry);
224 if (entry->priv->clearing == TRUE)
225 return;
227 if (entry->priv->timeout != 0) {
228 g_source_remove (entry->priv->timeout);
229 entry->priv->timeout = 0;
232 /* emit it now if we're clearing the entry */
233 if (gtk_entry_get_text (GTK_ENTRY (entry->priv->entry)))
234 entry->priv->timeout = g_timeout_add (300, (GSourceFunc) rb_search_entry_timeout_cb, entry);
235 else
236 rb_search_entry_timeout_cb (entry);
239 static gboolean
240 rb_search_entry_timeout_cb (RBSearchEntry *entry)
242 gdk_threads_enter ();
244 g_signal_emit (G_OBJECT (entry), rb_search_entry_signals[SEARCH], 0,
245 gtk_entry_get_text (GTK_ENTRY (entry->priv->entry)));
246 entry->priv->timeout = 0;
248 gdk_threads_leave ();
250 return FALSE;
253 static gboolean
254 rb_search_entry_focus_out_event_cb (GtkWidget *widget,
255 GdkEventFocus *event,
256 RBSearchEntry *entry)
258 if (entry->priv->timeout == 0)
259 return FALSE;
261 g_source_remove (entry->priv->timeout);
262 entry->priv->timeout = 0;
264 g_signal_emit (G_OBJECT (entry), rb_search_entry_signals[SEARCH], 0,
265 gtk_entry_get_text (GTK_ENTRY (entry->priv->entry)));
267 return FALSE;
270 gboolean
271 rb_search_entry_searching(RBSearchEntry *entry)
273 return strcmp ("", gtk_entry_get_text (GTK_ENTRY (entry->priv->entry))) != 0;
276 static void
277 rb_search_entry_activate_cb (GtkEntry *gtkentry,
278 RBSearchEntry *entry)
280 g_signal_emit (G_OBJECT (entry), rb_search_entry_signals[ACTIVATE], 0);
283 void
284 rb_search_entry_grab_focus (RBSearchEntry *entry)
286 gtk_widget_grab_focus (GTK_WIDGET (entry->priv->entry));