4747
nautilus_icon_container_search_position_func (NautilusIconContainer *container,
4748
GtkWidget *search_dialog)
4751
gint cont_x, cont_y;
4752
gint cont_width, cont_height;
4753
GdkWindow *cont_window;
4755
GtkRequisition requisition;
4757
GdkRectangle monitor;
4760
cont_window = gtk_widget_get_window (GTK_WIDGET (container));
4761
screen = gdk_window_get_screen (cont_window);
4763
monitor_num = gdk_screen_get_monitor_at_window (screen, cont_window);
4764
gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
4766
gtk_widget_realize (search_dialog);
4768
gdk_window_get_origin (cont_window, &cont_x, &cont_y);
4769
cont_width = gdk_window_get_width (cont_window);
4770
cont_height = gdk_window_get_height (cont_window);
4772
gtk_widget_get_preferred_size (search_dialog, &requisition, NULL);
4774
if (cont_x + cont_width > gdk_screen_get_width (screen)) {
4775
x = gdk_screen_get_width (screen) - requisition.width;
4776
} else if (cont_x + cont_width - requisition.width < 0) {
4779
x = cont_x + cont_width - requisition.width;
4782
if (cont_y + cont_height + requisition.height > gdk_screen_get_height (screen)) {
4783
y = gdk_screen_get_height (screen) - requisition.height;
4784
} else if (cont_y + cont_height < 0) { /* isn't really possible ... */
4787
y = cont_y + cont_height;
4790
gdk_window_move (gtk_widget_get_window (search_dialog), x, y);
4793
/* Cut and paste from gtkwindow.c */
4795
send_focus_change (GtkWidget *widget, gboolean in)
4799
fevent = gdk_event_new (GDK_FOCUS_CHANGE);
4801
g_object_ref (widget);
4802
((GdkEventFocus *) fevent)->in = in;
4804
gtk_widget_send_focus_change (widget, fevent);
4806
fevent->focus_change.type = GDK_FOCUS_CHANGE;
4807
fevent->focus_change.window = g_object_ref (gtk_widget_get_window (widget));
4808
fevent->focus_change.in = in;
4810
gtk_widget_event (widget, fevent);
4812
g_object_notify (G_OBJECT (widget), "has-focus");
4814
g_object_unref (widget);
4815
gdk_event_free (fevent);
4819
nautilus_icon_container_search_dialog_hide (GtkWidget *search_dialog,
4820
NautilusIconContainer *container)
4822
if (container->details->search_entry_changed_id) {
4823
g_signal_handler_disconnect (container->details->search_entry,
4824
container->details->search_entry_changed_id);
4825
container->details->search_entry_changed_id = 0;
4828
remove_search_entry_timeout (container);
4830
/* send focus-in event */
4831
send_focus_change (GTK_WIDGET (container->details->search_entry), FALSE);
4832
gtk_widget_hide (search_dialog);
4833
gtk_entry_set_text (GTK_ENTRY (container->details->search_entry), "");
4837
nautilus_icon_container_search_entry_flush_timeout (gpointer data)
4839
NautilusIconContainer *container = data;
4841
container->details->typeselect_flush_timeout = 0;
4842
nautilus_icon_container_search_dialog_hide (container->details->search_window, container);
4848
add_search_entry_timeout (NautilusIconContainer *container)
4850
container->details->typeselect_flush_timeout =
4851
g_timeout_add_seconds (NAUTILUS_ICON_CONTAINER_SEARCH_DIALOG_TIMEOUT,
4852
nautilus_icon_container_search_entry_flush_timeout,
4857
remove_search_entry_timeout (NautilusIconContainer *container)
4859
if (container->details->typeselect_flush_timeout) {
4860
g_source_remove (container->details->typeselect_flush_timeout);
4861
container->details->typeselect_flush_timeout = 0;
4866
reset_search_entry_timeout (NautilusIconContainer *container)
4868
remove_search_entry_timeout (container);
4869
add_search_entry_timeout (container);
4872
/* Because we're visible but offscreen, we just set a flag in the preedit
4876
nautilus_icon_container_search_preedit_changed (GtkEntry *entry,
4878
NautilusIconContainer *container)
4880
container->details->imcontext_changed = 1;
4881
reset_search_entry_timeout (container);
4885
nautilus_icon_container_search_activate (GtkEntry *entry,
4886
NautilusIconContainer *container)
4888
nautilus_icon_container_search_dialog_hide (container->details->search_window,
4891
activate_selected_items (container);
4895
nautilus_icon_container_search_delete_event (GtkWidget *widget,
4897
NautilusIconContainer *container)
4899
nautilus_icon_container_search_dialog_hide (widget, container);
4905
nautilus_icon_container_search_button_press_event (GtkWidget *widget,
4906
GdkEventButton *event,
4907
NautilusIconContainer *container)
4909
nautilus_icon_container_search_dialog_hide (widget, container);
4911
if (event->window == gtk_layout_get_bin_window (GTK_LAYOUT (container))) {
4912
button_press_event (GTK_WIDGET (container), event);
4919
nautilus_icon_container_search_entry_button_press_event (GtkWidget *widget,
4920
GdkEventButton *event,
4921
NautilusIconContainer *container)
4923
reset_search_entry_timeout (container);
4929
nautilus_icon_container_search_populate_popup (GtkEntry *entry,
4931
NautilusIconContainer *container)
4933
remove_search_entry_timeout (container);
4934
g_signal_connect_swapped (menu, "hide",
4935
G_CALLBACK (add_search_entry_timeout), container);
4939
4673
nautilus_icon_container_get_icon_text (NautilusIconContainer *container,
4940
4674
NautilusIconData *data,
4941
4675
char **editable_text,
4953
4687
static gboolean
4954
nautilus_icon_container_search_iter (NautilusIconContainer *container,
4955
const char *key, gint n)
4961
char *normalized_key, *case_normalized_key;
4962
char *normalized_name, *case_normalized_name;
4964
g_assert (key != NULL);
4967
normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
4968
if (!normalized_key) {
4971
case_normalized_key = g_utf8_casefold (normalized_key, -1);
4972
g_free (normalized_key);
4973
if (!case_normalized_key) {
4980
for (p = container->details->icons; p != NULL && count != n; p = p->next) {
4982
nautilus_icon_container_get_icon_text (container, icon->data, &name,
4985
/* This can happen if a key event is handled really early while
4986
* loading the icon container, before the items have all been
4993
normalized_name = g_utf8_normalize (name, -1, G_NORMALIZE_ALL);
4994
if (!normalized_name) {
4997
case_normalized_name = g_utf8_casefold (normalized_name, -1);
4998
g_free (normalized_name);
4999
if (!case_normalized_name) {
5003
if (strncmp (case_normalized_key, case_normalized_name,
5004
strlen (case_normalized_key)) == 0) {
5008
g_free (case_normalized_name);
5013
g_free (case_normalized_key);
5016
if (select_one_unselect_others (container, icon)) {
5017
g_signal_emit (container, signals[SELECTION_CHANGED], 0);
5019
schedule_keyboard_icon_reveal (container, icon);
5028
nautilus_icon_container_search_move (GtkWidget *window,
5029
NautilusIconContainer *container,
5036
text = gtk_entry_get_text (GTK_ENTRY (container->details->search_entry));
5038
g_assert (text != NULL);
5040
if (container->details->selected_iter == 0) {
5044
if (up && container->details->selected_iter == 1) {
5048
len = strlen (text);
5055
unselect_all (container);
5057
ret = nautilus_icon_container_search_iter (container, text,
5058
up?((container->details->selected_iter) - 1):((container->details->selected_iter + 1)));
5062
container->details->selected_iter += up?(-1):(1);
5064
/* return to old iter */
5065
nautilus_icon_container_search_iter (container, text,
5066
container->details->selected_iter);
5071
nautilus_icon_container_search_scroll_event (GtkWidget *widget,
5072
GdkEventScroll *event,
5073
NautilusIconContainer *container)
5075
gboolean retval = FALSE;
5077
if (event->direction == GDK_SCROLL_UP) {
5078
nautilus_icon_container_search_move (widget, container, TRUE);
5080
} else if (event->direction == GDK_SCROLL_DOWN) {
5081
nautilus_icon_container_search_move (widget, container, FALSE);
5085
reset_search_entry_timeout (container);
5091
nautilus_icon_container_search_key_press_event (GtkWidget *widget,
5093
NautilusIconContainer *container)
5095
gboolean retval = FALSE;
5097
g_assert (GTK_IS_WIDGET (widget));
5098
g_assert (NAUTILUS_IS_ICON_CONTAINER (container));
5100
/* close window and cancel the search */
5101
if (event->keyval == GDK_KEY_Escape || event->keyval == GDK_KEY_Tab) {
5102
nautilus_icon_container_search_dialog_hide (widget, container);
5106
/* close window and activate alternate */
5107
if (event->keyval == GDK_KEY_Return && event->state & GDK_SHIFT_MASK) {
5108
nautilus_icon_container_search_dialog_hide (widget,
5111
activate_selected_items_alternate (container, NULL);
5115
/* select previous matching iter */
5116
if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up) {
5117
nautilus_icon_container_search_move (widget, container, TRUE);
5121
if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == (GDK_CONTROL_MASK | GDK_SHIFT_MASK))
5122
&& (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G)) {
5123
nautilus_icon_container_search_move (widget, container, TRUE);
5127
/* select next matching iter */
5128
if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down) {
5129
nautilus_icon_container_search_move (widget, container, FALSE);
5133
if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == GDK_CONTROL_MASK)
5134
&& (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G)) {
5135
nautilus_icon_container_search_move (widget, container, FALSE);
5139
reset_search_entry_timeout (container);
5145
nautilus_icon_container_search_init (GtkWidget *entry,
5146
NautilusIconContainer *container)
5152
g_assert (GTK_IS_ENTRY (entry));
5153
g_assert (NAUTILUS_IS_ICON_CONTAINER (container));
5155
text = gtk_entry_get_text (GTK_ENTRY (entry));
5156
len = strlen (text);
5159
unselect_all (container);
5160
reset_search_entry_timeout (container);
5166
ret = nautilus_icon_container_search_iter (container, text, 1);
5169
container->details->selected_iter = 1;
5174
nautilus_icon_container_ensure_interactive_directory (NautilusIconContainer *container)
5176
GtkWidget *frame, *vbox;
5178
if (container->details->search_window != NULL) {
5182
container->details->search_window = gtk_window_new (GTK_WINDOW_POPUP);
5184
gtk_window_set_modal (GTK_WINDOW (container->details->search_window), TRUE);
5185
gtk_window_set_type_hint (GTK_WINDOW (container->details->search_window),
5186
GDK_WINDOW_TYPE_HINT_COMBO);
5188
g_signal_connect (container->details->search_window, "delete_event",
5189
G_CALLBACK (nautilus_icon_container_search_delete_event),
5191
g_signal_connect (container->details->search_window, "key_press_event",
5192
G_CALLBACK (nautilus_icon_container_search_key_press_event),
5194
g_signal_connect (container->details->search_window, "button_press_event",
5195
G_CALLBACK (nautilus_icon_container_search_button_press_event),
5197
g_signal_connect (container->details->search_window, "scroll_event",
5198
G_CALLBACK (nautilus_icon_container_search_scroll_event),
5201
frame = gtk_frame_new (NULL);
5202
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
5203
gtk_widget_show (frame);
5204
gtk_container_add (GTK_CONTAINER (container->details->search_window), frame);
5206
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
5207
gtk_widget_show (vbox);
5208
gtk_container_add (GTK_CONTAINER (frame), vbox);
5209
gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
5212
container->details->search_entry = gtk_entry_new ();
5213
gtk_widget_show (container->details->search_entry);
5214
g_signal_connect (container->details->search_entry, "populate-popup",
5215
G_CALLBACK (nautilus_icon_container_search_populate_popup),
5217
g_signal_connect (container->details->search_entry, "activate",
5218
G_CALLBACK (nautilus_icon_container_search_activate),
5220
g_signal_connect (container->details->search_entry, "preedit-changed",
5221
G_CALLBACK (nautilus_icon_container_search_preedit_changed),
5223
g_signal_connect (container->details->search_entry, "button-press-event",
5224
G_CALLBACK (nautilus_icon_container_search_entry_button_press_event),
5226
gtk_container_add (GTK_CONTAINER (vbox), container->details->search_entry);
5228
gtk_widget_realize (container->details->search_entry);
5231
/* Pops up the interactive search entry. If keybinding is TRUE then the user
5232
* started this by typing the start_interactive_search keybinding. Otherwise, it came from
5235
nautilus_icon_container_start_interactive_search (NautilusIconContainer *container)
5237
/* We only start interactive search if we have focus. If one of our
5238
* children have focus, we don't want to start the search.
5240
GtkWidgetClass *entry_parent_class;
5242
if (container->details->search_window != NULL &&
5243
gtk_widget_get_visible (container->details->search_window)) {
5247
if (!gtk_widget_has_focus (GTK_WIDGET (container))) {
5251
nautilus_icon_container_ensure_interactive_directory (container);
5254
nautilus_icon_container_search_position_func (container, container->details->search_window);
5255
gtk_widget_show (container->details->search_window);
5256
if (container->details->search_entry_changed_id == 0) {
5257
container->details->search_entry_changed_id =
5258
g_signal_connect (container->details->search_entry, "changed",
5259
G_CALLBACK (nautilus_icon_container_search_init),
5263
/* Grab focus will select all the text. We don't want that to happen, so we
5264
* call the parent instance and bypass the selection change. This is probably
5265
* really non-kosher. */
5266
entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (container->details->search_entry));
5267
(entry_parent_class->grab_focus) (container->details->search_entry);
5269
/* send focus-in event */
5270
send_focus_change (container->details->search_entry, TRUE);
5272
/* search first matching iter */
5273
nautilus_icon_container_search_init (container->details->search_entry, container);
5279
4688
handle_popups (NautilusIconContainer *container,
5280
4689
GdkEventKey *event,
5281
4690
const char *signal)
5431
4827
if (!handled) {
5432
4828
handled = GTK_WIDGET_CLASS (nautilus_icon_container_parent_class)->key_press_event (widget, event);
5435
/* We pass the event to the search_entry. If its text changes, then we
5436
* start the typeahead find capabilities.
5437
* Copied from NautilusIconContainer */
5439
event->keyval != GDK_KEY_slash /* don't steal slash key event, used for "go to" */ &&
5440
event->keyval != GDK_KEY_BackSpace &&
5441
event->keyval != GDK_KEY_Delete) {
5442
GdkEvent *new_event;
5445
const char *new_text;
5448
gboolean text_modified;
5449
gulong popup_menu_id;
5451
nautilus_icon_container_ensure_interactive_directory (container);
5453
/* Make a copy of the current text */
5454
old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (container->details->search_entry)));
5455
new_event = gdk_event_copy ((GdkEvent *) event);
5456
window = ((GdkEventKey *) new_event)->window;
5457
((GdkEventKey *) new_event)->window = gtk_widget_get_window (container->details->search_entry);
5458
gtk_widget_realize (container->details->search_window);
5460
popup_menu_id = g_signal_connect (container->details->search_entry,
5461
"popup_menu", G_CALLBACK (gtk_true), NULL);
5463
/* Move the entry off screen */
5464
screen = gtk_widget_get_screen (GTK_WIDGET (container));
5465
gtk_window_move (GTK_WINDOW (container->details->search_window),
5466
gdk_screen_get_width (screen) + 1,
5467
gdk_screen_get_height (screen) + 1);
5468
gtk_widget_show (container->details->search_window);
5470
/* Send the event to the window. If the preedit_changed signal is emitted
5471
* during this event, we will set priv->imcontext_changed */
5472
container->details->imcontext_changed = FALSE;
5473
retval = gtk_widget_event (container->details->search_entry, new_event);
5474
gtk_widget_hide (container->details->search_window);
5476
g_signal_handler_disconnect (container->details->search_entry,
5479
/* We check to make sure that the entry tried to handle the text, and that
5480
* the text has changed. */
5481
new_text = gtk_entry_get_text (GTK_ENTRY (container->details->search_entry));
5482
text_modified = strcmp (old_text, new_text) != 0;
5484
if (container->details->imcontext_changed || /* we're in a preedit */
5485
(retval && text_modified)) { /* ...or the text was modified */
5486
if (nautilus_icon_container_start_interactive_search (container)) {
5487
gtk_widget_grab_focus (GTK_WIDGET (container));
5490
gtk_entry_set_text (GTK_ENTRY (container->details->search_entry), "");
5495
((GdkEventKey *) new_event)->window = window;
5496
gdk_event_free (new_event);
5499
4831
return handled;