1 /* Copyright (C) 2004 Red Hat, Inc.
3 This library is free software; you can redistribute it and/or
4 modify it under the terms of the GNU Library General Public License as
5 published by the Free Software Foundation; either version 2 of the
6 License, or (at your option) any later version.
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
13 You should have received a copy of the GNU Library General Public
14 License along with the Gnome Library; see the file COPYING.LIB. If not,
15 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 Boston, MA 02111-1307, USA.
21 #include "eggfindbar.h"
23 #include <glib/gi18n.h>
24 #include <gtk/gtkhbox.h>
25 #include <gtk/gtkentry.h>
26 #include <gtk/gtkcheckbutton.h>
27 #include <gtk/gtkvseparator.h>
28 #include <gtk/gtkstock.h>
29 #include <gtk/gtklabel.h>
30 #include <gdk/gdkkeysyms.h>
31 #include <gtk/gtkbindings.h>
35 typedef struct _EggFindBarPrivate EggFindBarPrivate;
36 struct _EggFindBarPrivate
40 GtkWidget *close_button;
41 GtkWidget *find_entry;
42 GtkWidget *next_button;
43 GtkWidget *previous_button;
44 GtkWidget *case_button;
45 guint case_sensitive : 1;
48 #define EGG_FIND_BAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EGG_TYPE_FIND_BAR, EggFindBarPrivate))
58 static void egg_find_bar_finalize (GObject *object);
59 static void egg_find_bar_get_property (GObject *object,
63 static void egg_find_bar_set_property (GObject *object,
67 static void egg_find_bar_size_request (GtkWidget *widget,
68 GtkRequisition *requisition);
69 static void egg_find_bar_size_allocate (GtkWidget *widget,
70 GtkAllocation *allocation);
72 G_DEFINE_TYPE (EggFindBar, egg_find_bar, GTK_TYPE_BIN);
82 static guint find_bar_signals[LAST_SIGNAL] = { 0 };
85 egg_find_bar_class_init (EggFindBarClass *klass)
87 GObjectClass *object_class;
88 GtkWidgetClass *widget_class;
89 GtkBinClass *bin_class;
90 GtkBindingSet *binding_set;
92 object_class = (GObjectClass *)klass;
93 widget_class = (GtkWidgetClass *)klass;
94 bin_class = (GtkBinClass *)klass;
96 object_class->set_property = egg_find_bar_set_property;
97 object_class->get_property = egg_find_bar_get_property;
99 object_class->finalize = egg_find_bar_finalize;
101 widget_class->size_request = egg_find_bar_size_request;
102 widget_class->size_allocate = egg_find_bar_size_allocate;
104 find_bar_signals[NEXT] =
105 g_signal_new ("next",
106 G_OBJECT_CLASS_TYPE (object_class),
110 g_cclosure_marshal_VOID__VOID,
112 find_bar_signals[PREVIOUS] =
113 g_signal_new ("previous",
114 G_OBJECT_CLASS_TYPE (object_class),
118 g_cclosure_marshal_VOID__VOID,
120 find_bar_signals[CLOSE] =
121 g_signal_new ("close",
122 G_OBJECT_CLASS_TYPE (object_class),
123 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
126 g_cclosure_marshal_VOID__VOID,
130 * EggFindBar:search_string:
132 * The current string to search for. NULL or empty string
133 * both mean no current string.
136 g_object_class_install_property (object_class,
138 g_param_spec_string ("search_string",
140 _("The name of the string to be found"),
145 * EggFindBar:case_sensitive:
147 * TRUE for a case sensitive search.
150 g_object_class_install_property (object_class,
152 g_param_spec_boolean ("case_sensitive",
154 _("TRUE for a case sensitive search"),
158 /* Style properties */
159 gtk_widget_class_install_style_property (widget_class,
160 g_param_spec_boxed ("all_matches_color",
161 _("Highlight color"),
162 _("Color of highlight for all matches"),
166 gtk_widget_class_install_style_property (widget_class,
167 g_param_spec_boxed ("current_match_color",
169 _("Color of highlight for the current match"),
173 g_type_class_add_private (object_class, sizeof (EggFindBarPrivate));
175 binding_set = gtk_binding_set_by_class (klass);
177 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
182 egg_find_bar_emit_next (EggFindBar *find_bar)
184 g_signal_emit (find_bar, find_bar_signals[NEXT], 0);
188 egg_find_bar_emit_previous (EggFindBar *find_bar)
190 g_signal_emit (find_bar, find_bar_signals[PREVIOUS], 0);
194 egg_find_bar_emit_close (EggFindBar *find_bar)
196 g_signal_emit (find_bar, find_bar_signals[CLOSE], 0);
200 close_clicked_callback (GtkButton *button,
203 EggFindBar *find_bar = EGG_FIND_BAR (data);
205 egg_find_bar_emit_close (find_bar);
209 next_clicked_callback (GtkButton *button,
212 EggFindBar *find_bar = EGG_FIND_BAR (data);
214 egg_find_bar_emit_next (find_bar);
218 previous_clicked_callback (GtkButton *button,
221 EggFindBar *find_bar = EGG_FIND_BAR (data);
223 egg_find_bar_emit_previous (find_bar);
227 case_sensitive_toggled_callback (GtkCheckButton *button,
230 EggFindBar *find_bar = EGG_FIND_BAR (data);
232 egg_find_bar_set_case_sensitive (find_bar,
233 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)));
237 entry_activate_callback (GtkEntry *entry,
240 EggFindBar *find_bar = EGG_FIND_BAR (data);
242 egg_find_bar_emit_next (find_bar);
246 entry_changed_callback (GtkEntry *entry,
249 EggFindBar *find_bar = EGG_FIND_BAR (data);
252 /* paranoid strdup because set_search_string() sets
255 text = g_strdup (gtk_entry_get_text (entry));
257 egg_find_bar_set_search_string (find_bar, text);
263 egg_find_bar_init (EggFindBar *find_bar)
265 EggFindBarPrivate *priv;
267 GtkWidget *separator;
271 priv = EGG_FIND_BAR_GET_PRIVATE (find_bar);
272 find_bar->private_data = priv;
274 priv->search_string = NULL;
277 gtk_widget_push_composite_child ();
278 priv->hbox = gtk_hbox_new (FALSE, 6);
279 gtk_container_set_border_width (GTK_CONTAINER (priv->hbox), 3);
281 label = gtk_label_new_with_mnemonic (_("F_ind:"));
282 separator = gtk_vseparator_new ();
284 priv->close_button = gtk_button_new ();
285 gtk_button_set_relief (GTK_BUTTON (priv->close_button),
287 image = gtk_image_new_from_stock (GTK_STOCK_CLOSE,
288 GTK_ICON_SIZE_SMALL_TOOLBAR);
289 gtk_container_add (GTK_CONTAINER (priv->close_button), image);
291 priv->find_entry = gtk_entry_new ();
292 gtk_label_set_mnemonic_widget (GTK_LABEL (label), priv->find_entry);
294 priv->previous_button = gtk_button_new_from_stock (GTK_STOCK_GO_BACK);
295 priv->next_button = gtk_button_new_from_stock (GTK_STOCK_GO_FORWARD);
297 priv->case_button = gtk_check_button_new_with_mnemonic (_("C_ase Sensitive"));
299 gtk_box_pack_start (GTK_BOX (priv->hbox),
300 priv->close_button, FALSE, FALSE, 0);
301 gtk_box_pack_start (GTK_BOX (priv->hbox),
302 label, FALSE, FALSE, 0);
303 gtk_box_pack_start (GTK_BOX (priv->hbox),
304 priv->find_entry, FALSE, FALSE, 0);
305 gtk_box_pack_start (GTK_BOX (priv->hbox),
306 priv->previous_button, FALSE, FALSE, 0);
307 gtk_box_pack_start (GTK_BOX (priv->hbox),
308 priv->next_button, FALSE, FALSE, 0);
309 gtk_box_pack_start (GTK_BOX (priv->hbox),
310 separator, FALSE, FALSE, 0);
311 gtk_box_pack_start (GTK_BOX (priv->hbox),
312 priv->case_button, FALSE, FALSE, 0);
314 gtk_container_add (GTK_CONTAINER (find_bar), priv->hbox);
316 gtk_widget_show (priv->hbox);
317 gtk_widget_show (priv->close_button);
318 gtk_widget_show (priv->find_entry);
319 gtk_widget_show (priv->previous_button);
320 gtk_widget_show (priv->next_button);
321 gtk_widget_show (separator);
322 gtk_widget_show (label);
323 gtk_widget_show (image);
325 gtk_widget_pop_composite_child ();
327 gtk_widget_show_all (priv->hbox);
329 g_signal_connect (priv->close_button, "clicked",
330 G_CALLBACK (close_clicked_callback),
332 g_signal_connect (priv->find_entry, "changed",
333 G_CALLBACK (entry_changed_callback),
335 g_signal_connect (priv->find_entry, "activate",
336 G_CALLBACK (entry_activate_callback),
338 g_signal_connect (priv->next_button, "clicked",
339 G_CALLBACK (next_clicked_callback),
341 g_signal_connect (priv->previous_button, "clicked",
342 G_CALLBACK (previous_clicked_callback),
344 g_signal_connect (priv->case_button, "toggled",
345 G_CALLBACK (case_sensitive_toggled_callback),
350 egg_find_bar_finalize (GObject *object)
352 EggFindBar *find_bar = EGG_FIND_BAR (object);
353 EggFindBarPrivate *priv = (EggFindBarPrivate *)find_bar->private_data;
355 g_free (priv->search_string);
357 G_OBJECT_CLASS (egg_find_bar_parent_class)->finalize (object);
361 egg_find_bar_set_property (GObject *object,
366 EggFindBar *find_bar = EGG_FIND_BAR (object);
370 case PROP_SEARCH_STRING:
371 egg_find_bar_set_search_string (find_bar, g_value_get_string (value));
373 case PROP_CASE_SENSITIVE:
374 egg_find_bar_set_case_sensitive (find_bar, g_value_get_boolean (value));
377 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
383 egg_find_bar_get_property (GObject *object,
388 EggFindBar *find_bar = EGG_FIND_BAR (object);
389 EggFindBarPrivate *priv = (EggFindBarPrivate *)find_bar->private_data;
393 case PROP_SEARCH_STRING:
394 g_value_set_string (value, priv->search_string);
396 case PROP_CASE_SENSITIVE:
397 g_value_set_boolean (value, priv->case_sensitive);
400 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
406 egg_find_bar_size_request (GtkWidget *widget,
407 GtkRequisition *requisition)
409 GtkBin *bin = GTK_BIN (widget);
410 GtkRequisition child_requisition;
411 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
413 gtk_widget_size_request (bin->child, &child_requisition);
415 *requisition = child_requisition;
419 requisition->width = 0;
420 requisition->height = 0;
425 egg_find_bar_size_allocate (GtkWidget *widget,
426 GtkAllocation *allocation)
428 GtkBin *bin = GTK_BIN (widget);
430 widget->allocation = *allocation;
432 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
433 gtk_widget_size_allocate (bin->child, allocation);
439 * Creates a new #EggFindBar.
441 * Returns: a newly created #EggFindBar
446 egg_find_bar_new (void)
448 EggFindBar *find_bar;
450 find_bar = g_object_new (EGG_TYPE_FIND_BAR, NULL);
452 return GTK_WIDGET (find_bar);
456 * egg_find_bar_set_search_string:
458 * Sets the string that should be found/highlighted in the document.
459 * Empty string is converted to NULL.
464 egg_find_bar_set_search_string (EggFindBar *find_bar,
465 const char *search_string)
467 EggFindBarPrivate *priv;
469 g_return_if_fail (EGG_IS_FIND_BAR (find_bar));
471 priv = (EggFindBarPrivate *)find_bar->private_data;
473 g_object_freeze_notify (G_OBJECT (find_bar));
475 if (priv->search_string != search_string)
479 old = priv->search_string;
481 if (search_string && *search_string == '\0')
482 search_string = NULL;
484 /* Only update if the string has changed; setting the entry
485 * will emit changed on the entry which will re-enter
486 * this function, but we'll handle that fine with this
489 if ((old && search_string == NULL) ||
490 (old == NULL && search_string) ||
491 (old && search_string &&
492 strcmp (old, search_string) != 0))
494 priv->search_string = g_strdup (search_string);
497 gtk_entry_set_text (GTK_ENTRY (priv->find_entry),
498 priv->search_string ?
499 priv->search_string :
502 g_object_notify (G_OBJECT (find_bar),
507 g_object_thaw_notify (G_OBJECT (find_bar));
512 * egg_find_bar_get_search_string:
514 * Gets the string that should be found/highlighted in the document.
516 * Returns: the string
521 egg_find_bar_get_search_string (EggFindBar *find_bar)
523 EggFindBarPrivate *priv;
525 g_return_val_if_fail (EGG_IS_FIND_BAR (find_bar), NULL);
527 priv = (EggFindBarPrivate *)find_bar->private_data;
529 return priv->search_string;
533 * egg_find_bar_set_case_sensitive:
535 * Sets whether the search is case sensitive
540 egg_find_bar_set_case_sensitive (EggFindBar *find_bar,
541 gboolean case_sensitive)
543 EggFindBarPrivate *priv;
545 g_return_if_fail (EGG_IS_FIND_BAR (find_bar));
547 priv = (EggFindBarPrivate *)find_bar->private_data;
549 g_object_freeze_notify (G_OBJECT (find_bar));
551 case_sensitive = case_sensitive != FALSE;
553 if (priv->case_sensitive != case_sensitive)
555 priv->case_sensitive = case_sensitive;
557 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->case_button),
558 priv->case_sensitive);
560 g_object_notify (G_OBJECT (find_bar),
564 g_object_thaw_notify (G_OBJECT (find_bar));
568 * egg_find_bar_get_case_sensitive:
570 * Gets whether the search is case sensitive
572 * Returns: TRUE if it's case sensitive
577 egg_find_bar_get_case_sensitive (EggFindBar *find_bar)
579 EggFindBarPrivate *priv;
581 g_return_val_if_fail (EGG_IS_FIND_BAR (find_bar), FALSE);
583 priv = (EggFindBarPrivate *)find_bar->private_data;
585 return priv->case_sensitive;
589 get_style_color (EggFindBar *find_bar,
590 const char *style_prop_name,
593 GdkColor *style_color;
595 gtk_widget_ensure_style (GTK_WIDGET (find_bar));
596 gtk_widget_style_get (GTK_WIDGET (find_bar),
597 "color", &style_color, NULL);
600 *color = *style_color;
601 gdk_color_free (style_color);
606 * egg_find_bar_get_all_matches_color:
608 * Gets the color to use to highlight all the
614 egg_find_bar_get_all_matches_color (EggFindBar *find_bar,
617 GdkColor found_color = { 0, 0, 0, 0x0f0f };
619 get_style_color (find_bar, "all_matches_color", &found_color);
621 *color = found_color;
625 * egg_find_bar_get_current_match_color:
627 * Gets the color to use to highlight the match
628 * we're currently on.
633 egg_find_bar_get_current_match_color (EggFindBar *find_bar,
636 GdkColor found_color = { 0, 0, 0, 0xffff };
638 get_style_color (find_bar, "current_match_color", &found_color);
640 *color = found_color;
644 * egg_find_bar_grab_focus:
646 * Focuses the text entry in the find bar; currently GTK+ doesn't have
647 * a way to make this work on gtk_widget_grab_focus(find_bar).
652 egg_find_bar_grab_focus (EggFindBar *find_bar)
654 EggFindBarPrivate *priv;
656 g_return_if_fail (EGG_IS_FIND_BAR (find_bar));
658 priv = (EggFindBarPrivate *)find_bar->private_data;
660 gtk_widget_grab_focus (priv->find_entry);