No issues found
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /*
4 * Nautilus
5 *
6 * Copyright (C) 2000 Eazel, Inc.
7 *
8 * Nautilus is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * Nautilus 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 GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program; see the file COPYING. If not,
20 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
22 *
23 * Author: Maciej Stachowiak <mjs@eazel.com>
24 * Ettore Perazzoli <ettore@gnu.org>
25 * Michael Meeks <michael@nuclecu.unam.mx>
26 * Andy Hertzfeld <andy@eazel.com>
27 *
28 */
29
30 /* nautilus-location-bar.c - Location bar for Nautilus
31 */
32
33 #include <config.h>
34 #include "nautilus-location-entry.h"
35
36 #include "nautilus-application.h"
37 #include "nautilus-window-private.h"
38 #include "nautilus-window.h"
39 #include <gtk/gtk.h>
40 #include <gdk/gdkkeysyms.h>
41 #include <glib/gi18n.h>
42 #include <gio/gio.h>
43 #include <libnautilus-private/nautilus-file-utilities.h>
44 #include <libnautilus-private/nautilus-entry.h>
45 #include <libnautilus-private/nautilus-clipboard.h>
46 #include <eel/eel-stock-dialogs.h>
47 #include <eel/eel-string.h>
48 #include <eel/eel-vfs-extensions.h>
49 #include <stdio.h>
50 #include <string.h>
51
52 #define NAUTILUS_DND_URI_LIST_TYPE "text/uri-list"
53 #define NAUTILUS_DND_TEXT_PLAIN_TYPE "text/plain"
54
55 enum {
56 NAUTILUS_DND_URI_LIST,
57 NAUTILUS_DND_TEXT_PLAIN,
58 NAUTILUS_DND_NTARGETS
59 };
60
61 static const GtkTargetEntry drag_types [] = {
62 { NAUTILUS_DND_URI_LIST_TYPE, 0, NAUTILUS_DND_URI_LIST },
63 { NAUTILUS_DND_TEXT_PLAIN_TYPE, 0, NAUTILUS_DND_TEXT_PLAIN },
64 };
65
66 static const GtkTargetEntry drop_types [] = {
67 { NAUTILUS_DND_URI_LIST_TYPE, 0, NAUTILUS_DND_URI_LIST },
68 { NAUTILUS_DND_TEXT_PLAIN_TYPE, 0, NAUTILUS_DND_TEXT_PLAIN },
69 };
70
71 struct NautilusLocationEntryDetails {
72 char *current_directory;
73 GFilenameCompleter *completer;
74
75 guint idle_id;
76
77 char *last_uri;
78
79 gboolean has_special_text;
80 gboolean setting_special_text;
81 gchar *special_text;
82 NautilusLocationEntryAction secondary_action;
83 };
84
85 enum {
86 CANCEL,
87 LOCATION_CHANGED,
88 LAST_SIGNAL
89 };
90
91 static guint signals[LAST_SIGNAL];
92
93 G_DEFINE_TYPE (NautilusLocationEntry, nautilus_location_entry, NAUTILUS_TYPE_ENTRY);
94
95 void
96 nautilus_location_entry_focus (NautilusLocationEntry *entry)
97 {
98 /* Put the keyboard focus in the text field when switching to this mode,
99 * and select all text for easy overtyping
100 */
101 gtk_widget_grab_focus (GTK_WIDGET (entry));
102 nautilus_entry_select_all (NAUTILUS_ENTRY (entry));
103 }
104
105 static GFile *
106 nautilus_location_entry_get_location (NautilusLocationEntry *entry)
107 {
108 char *user_location;
109 GFile *location;
110
111 user_location = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
112 location = g_file_parse_name (user_location);
113 g_free (user_location);
114
115 return location;
116 }
117
118 static void
119 emit_location_changed (NautilusLocationEntry *entry)
120 {
121 GFile *location;
122
123 location = nautilus_location_entry_get_location (entry);
124 g_signal_emit (entry, signals[LOCATION_CHANGED], 0, location);
125 g_object_unref (location);
126 }
127
128 static void
129 nautilus_location_entry_update_action (NautilusLocationEntry *entry)
130 {
131 const char *current_text;
132 GFile *location;
133 GFile *last_location;
134
135 if (entry->details->last_uri == NULL){
136 nautilus_location_entry_set_secondary_action (entry,
137 NAUTILUS_LOCATION_ENTRY_ACTION_GOTO);
138 return;
139 }
140
141 current_text = gtk_entry_get_text (GTK_ENTRY (entry));
142 location = g_file_parse_name (current_text);
143 last_location = g_file_parse_name (entry->details->last_uri);
144
145 if (g_file_equal (last_location, location)) {
146 nautilus_location_entry_set_secondary_action (entry,
147 NAUTILUS_LOCATION_ENTRY_ACTION_CLEAR);
148 } else {
149 nautilus_location_entry_set_secondary_action (entry,
150 NAUTILUS_LOCATION_ENTRY_ACTION_GOTO);
151 }
152
153 g_object_unref (location);
154 g_object_unref (last_location);
155 }
156
157 static int
158 get_editable_number_of_chars (GtkEditable *editable)
159 {
160 char *text;
161 int length;
162
163 text = gtk_editable_get_chars (editable, 0, -1);
164 length = g_utf8_strlen (text, -1);
165 g_free (text);
166 return length;
167 }
168
169 static void
170 set_position_and_selection_to_end (GtkEditable *editable)
171 {
172 int end;
173
174 end = get_editable_number_of_chars (editable);
175 gtk_editable_select_region (editable, end, end);
176 gtk_editable_set_position (editable, end);
177 }
178
179 static void
180 nautilus_location_entry_update_current_uri (NautilusLocationEntry *entry,
181 const char *uri)
182 {
183 g_free (entry->details->current_directory);
184 entry->details->current_directory = g_strdup (uri);
185
186 nautilus_entry_set_text (NAUTILUS_ENTRY (entry), uri);
187 set_position_and_selection_to_end (GTK_EDITABLE (entry));
188 }
189
190 void
191 nautilus_location_entry_set_uri (NautilusLocationEntry *entry,
192 const char *uri)
193 {
194 char *formatted_uri;
195 GFile *file;
196
197 g_assert (uri != NULL);
198
199 /* Note: This is called in reaction to external changes, and
200 * thus should not emit the LOCATION_CHANGED signal. */
201
202 if (eel_uri_is_search (uri)) {
203 nautilus_location_entry_set_special_text (entry,
204 "");
205 } else {
206 file = g_file_new_for_uri (uri);
207 formatted_uri = g_file_get_parse_name (file);
208 g_object_unref (file);
209 nautilus_location_entry_update_current_uri (entry,
210 formatted_uri);
211 g_free (formatted_uri);
212 }
213
214 /* remember the original uri for later comparison */
215
216 if (entry->details->last_uri != uri) {
217 g_free (entry->details->last_uri);
218 entry->details->last_uri = g_strdup (uri);
219 }
220
221 nautilus_location_entry_update_action (entry);
222 }
223
224 static void
225 drag_data_received_callback (GtkWidget *widget,
226 GdkDragContext *context,
227 int x,
228 int y,
229 GtkSelectionData *data,
230 guint info,
231 guint32 time,
232 gpointer callback_data)
233 {
234 char **names;
235 NautilusApplication *application;
236 int name_count;
237 NautilusWindow *new_window;
238 GtkWidget *window;
239 GdkScreen *screen;
240 gboolean new_windows_for_extras;
241 char *prompt;
242 char *detail;
243 GFile *location;
244 NautilusLocationEntry *self = NAUTILUS_LOCATION_ENTRY (widget);
245
246 g_assert (data != NULL);
247 g_assert (callback_data == NULL);
248
249 names = g_uri_list_extract_uris ((const gchar *) gtk_selection_data_get_data (data));
250
251 if (names == NULL || *names == NULL) {
252 g_warning ("No D&D URI's");
253 gtk_drag_finish (context, FALSE, FALSE, time);
254 return;
255 }
256
257 window = gtk_widget_get_toplevel (widget);
258 new_windows_for_extras = FALSE;
259 /* Ask user if they really want to open multiple windows
260 * for multiple dropped URIs. This is likely to have been
261 * a mistake.
262 */
263 name_count = g_strv_length (names);
264 if (name_count > 1) {
265 prompt = g_strdup_printf (ngettext("Do you want to view %d location?",
266 "Do you want to view %d locations?",
267 name_count),
268 name_count);
269 detail = g_strdup_printf (ngettext("This will open %d separate window.",
270 "This will open %d separate windows.",
271 name_count),
272 name_count);
273 /* eel_run_simple_dialog should really take in pairs
274 * like gtk_dialog_new_with_buttons() does. */
275 new_windows_for_extras = eel_run_simple_dialog (GTK_WIDGET (window),
276 TRUE,
277 GTK_MESSAGE_QUESTION,
278 prompt,
279 detail,
280 GTK_STOCK_CANCEL, GTK_STOCK_OK,
281 NULL) != 0 /* GNOME_OK */;
282
283 g_free (prompt);
284 g_free (detail);
285
286 if (!new_windows_for_extras) {
287 gtk_drag_finish (context, FALSE, FALSE, time);
288 return;
289 }
290 }
291
292 nautilus_location_entry_set_uri (self, names[0]);
293 emit_location_changed (self);
294
295 if (new_windows_for_extras) {
296 int i;
297
298 application = NAUTILUS_APPLICATION (g_application_get_default ());
299 screen = gtk_window_get_screen (GTK_WINDOW (window));
300
301 for (i = 1; names[i] != NULL; ++i) {
302 new_window = nautilus_application_create_window (application, screen);
303 location = g_file_new_for_uri (names[i]);
304 nautilus_window_go_to (new_window, location);
305 g_object_unref (location);
306 }
307 }
308
309 g_strfreev (names);
310
311 gtk_drag_finish (context, TRUE, FALSE, time);
312 }
313
314 static void
315 drag_data_get_callback (GtkWidget *widget,
316 GdkDragContext *context,
317 GtkSelectionData *selection_data,
318 guint info,
319 guint32 time,
320 gpointer callback_data)
321 {
322 NautilusLocationEntry *self;
323 GFile *location;
324 gchar *uri;
325
326 g_assert (selection_data != NULL);
327 self = callback_data;
328
329 location = nautilus_location_entry_get_location (self);
330 uri = g_file_get_uri (location);
331
332 switch (info) {
333 case NAUTILUS_DND_URI_LIST:
334 case NAUTILUS_DND_TEXT_PLAIN:
335 gtk_selection_data_set (selection_data,
336 gtk_selection_data_get_target (selection_data),
337 8, (guchar *) uri,
338 strlen (uri));
339 break;
340 default:
341 g_assert_not_reached ();
342 }
343 g_free (uri);
344 g_object_unref (location);
345 }
346
347 /* routine that performs the tab expansion. Extract the directory name and
348 incomplete basename, then iterate through the directory trying to complete it. If we
349 find something, add it to the entry */
350
351 static gboolean
352 try_to_expand_path (gpointer callback_data)
353 {
354 NautilusLocationEntry *entry;
355 GtkEditable *editable;
356 char *suffix, *user_location, *absolute_location, *uri_scheme;
357 int user_location_length, pos;
358
359 entry = NAUTILUS_LOCATION_ENTRY (callback_data);
360 editable = GTK_EDITABLE (entry);
361 user_location = gtk_editable_get_chars (editable, 0, -1);
362 user_location_length = g_utf8_strlen (user_location, -1);
363 entry->details->idle_id = 0;
364
365 uri_scheme = g_uri_parse_scheme (user_location);
366
367 if (!g_path_is_absolute (user_location) && uri_scheme == NULL && user_location[0] != '~') {
368 absolute_location = g_build_filename (entry->details->current_directory, user_location, NULL);
369 suffix = g_filename_completer_get_completion_suffix (entry->details->completer,
370 absolute_location);
371 g_free (absolute_location);
372 } else {
373 suffix = g_filename_completer_get_completion_suffix (entry->details->completer,
374 user_location);
375 }
376
377 g_free (user_location);
378 g_free (uri_scheme);
379
380 /* if we've got something, add it to the entry */
381 if (suffix != NULL) {
382 pos = user_location_length;
383 gtk_editable_insert_text (editable,
384 suffix, -1, &pos);
385 pos = user_location_length;
386 gtk_editable_select_region (editable, pos, -1);
387
388 g_free (suffix);
389 }
390
391 return FALSE;
392 }
393
394 /* Until we have a more elegant solution, this is how we figure out if
395 * the GtkEntry inserted characters, assuming that the return value is
396 * TRUE indicating that the GtkEntry consumed the key event for some
397 * reason. This is a clone of code from GtkEntry.
398 */
399 static gboolean
400 entry_would_have_inserted_characters (const GdkEventKey *event)
401 {
402 switch (event->keyval) {
403 case GDK_KEY_BackSpace:
404 case GDK_KEY_Clear:
405 case GDK_KEY_Insert:
406 case GDK_KEY_Delete:
407 case GDK_KEY_Home:
408 case GDK_KEY_End:
409 case GDK_KEY_KP_Home:
410 case GDK_KEY_KP_End:
411 case GDK_KEY_Left:
412 case GDK_KEY_Right:
413 case GDK_KEY_KP_Left:
414 case GDK_KEY_KP_Right:
415 case GDK_KEY_Return:
416 return FALSE;
417 default:
418 if (event->keyval >= 0x20 && event->keyval <= 0xFF) {
419 if ((event->state & GDK_CONTROL_MASK) != 0) {
420 return FALSE;
421 }
422 if ((event->state & GDK_MOD1_MASK) != 0) {
423 return FALSE;
424 }
425 }
426 return event->length > 0;
427 }
428 }
429
430 static gboolean
431 position_and_selection_are_at_end (GtkEditable *editable)
432 {
433 int end;
434 int start_sel, end_sel;
435
436 end = get_editable_number_of_chars (editable);
437 if (gtk_editable_get_selection_bounds (editable, &start_sel, &end_sel)) {
438 if (start_sel != end || end_sel != end) {
439 return FALSE;
440 }
441 }
442 return gtk_editable_get_position (editable) == end;
443 }
444
445 static void
446 got_completion_data_callback (GFilenameCompleter *completer,
447 NautilusLocationEntry *entry)
448 {
449 if (entry->details->idle_id) {
450 g_source_remove (entry->details->idle_id);
451 entry->details->idle_id = 0;
452 }
453 try_to_expand_path (entry);
454 }
455
456 static void
457 editable_event_after_callback (GtkEntry *entry,
458 GdkEvent *event,
459 NautilusLocationEntry *location_entry)
460 {
461 GtkEditable *editable;
462 GdkEventKey *keyevent;
463
464 if (event->type != GDK_KEY_PRESS) {
465 return;
466 }
467
468 editable = GTK_EDITABLE (entry);
469 keyevent = (GdkEventKey *)event;
470
471 /* After typing the right arrow key we move the selection to
472 * the end, if we have a valid selection - since this is most
473 * likely an auto-completion. We ignore shift / control since
474 * they can validly be used to extend the selection.
475 */
476 if ((keyevent->keyval == GDK_KEY_Right || keyevent->keyval == GDK_KEY_End) &&
477 !(keyevent->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) &&
478 gtk_editable_get_selection_bounds (editable, NULL, NULL)) {
479 set_position_and_selection_to_end (editable);
480 }
481
482 /* Only do expanding when we are typing at the end of the
483 * text. Do the expand at idle time to avoid slowing down
484 * typing when the directory is large. Only trigger the expand
485 * when we type a key that would have inserted characters.
486 */
487 if (position_and_selection_are_at_end (editable)) {
488 if (entry_would_have_inserted_characters (keyevent)) {
489 if (location_entry->details->idle_id == 0) {
490 location_entry->details->idle_id = g_idle_add (try_to_expand_path, location_entry);
491 }
492 }
493 } else {
494 /* FIXME: Also might be good to do this when you click
495 * to change the position or selection.
496 */
497 if (location_entry->details->idle_id != 0) {
498 g_source_remove (location_entry->details->idle_id);
499 location_entry->details->idle_id = 0;
500 }
501 }
502 }
503
504 static void
505 finalize (GObject *object)
506 {
507 NautilusLocationEntry *entry;
508
509 entry = NAUTILUS_LOCATION_ENTRY (object);
510
511 g_object_unref (entry->details->completer);
512 g_free (entry->details->special_text);
513
514 g_free (entry->details->last_uri);
515 entry->details->last_uri = NULL;
516
517 G_OBJECT_CLASS (nautilus_location_entry_parent_class)->finalize (object);
518 }
519
520 static void
521 destroy (GtkWidget *object)
522 {
523 NautilusLocationEntry *entry;
524
525 entry = NAUTILUS_LOCATION_ENTRY (object);
526
527 /* cancel the pending idle call, if any */
528 if (entry->details->idle_id != 0) {
529 g_source_remove (entry->details->idle_id);
530 entry->details->idle_id = 0;
531 }
532
533 g_free (entry->details->current_directory);
534 entry->details->current_directory = NULL;
535
536 GTK_WIDGET_CLASS (nautilus_location_entry_parent_class)->destroy (object);
537 }
538
539 static void
540 nautilus_location_entry_text_changed (NautilusLocationEntry *entry,
541 GParamSpec *pspec)
542 {
543 if (entry->details->setting_special_text) {
544 return;
545 }
546
547 entry->details->has_special_text = FALSE;
548 }
549
550 static void
551 nautilus_location_entry_icon_release (GtkEntry *gentry,
552 GtkEntryIconPosition position,
553 GdkEvent *event,
554 gpointer unused)
555 {
556 switch (NAUTILUS_LOCATION_ENTRY (gentry)->details->secondary_action) {
557 case NAUTILUS_LOCATION_ENTRY_ACTION_GOTO:
558 g_signal_emit_by_name (gentry, "activate", gentry);
559 break;
560 case NAUTILUS_LOCATION_ENTRY_ACTION_CLEAR:
561 gtk_entry_set_text (gentry, "");
562 break;
563 default:
564 g_assert_not_reached ();
565 }
566 }
567
568 static gboolean
569 nautilus_location_entry_focus_in (GtkWidget *widget,
570 GdkEventFocus *event)
571 {
572 NautilusLocationEntry *entry = NAUTILUS_LOCATION_ENTRY (widget);
573
574 if (entry->details->has_special_text) {
575 entry->details->setting_special_text = TRUE;
576 gtk_entry_set_text (GTK_ENTRY (entry), "");
577 entry->details->setting_special_text = FALSE;
578 }
579
580 return GTK_WIDGET_CLASS (nautilus_location_entry_parent_class)->focus_in_event (widget, event);
581 }
582
583 static void
584 nautilus_location_entry_activate (GtkEntry *entry)
585 {
586 NautilusLocationEntry *loc_entry;
587 const gchar *entry_text;
588 gchar *full_path, *uri_scheme = NULL;
589
590 loc_entry = NAUTILUS_LOCATION_ENTRY (entry);
591 entry_text = gtk_entry_get_text (entry);
592
593 if (entry_text != NULL && *entry_text != '\0') {
594 uri_scheme = g_uri_parse_scheme (entry_text);
595
596 if (!g_path_is_absolute (entry_text) && uri_scheme == NULL && entry_text[0] != '~') {
597 /* Fix non absolute paths */
598 full_path = g_build_filename (loc_entry->details->current_directory, entry_text, NULL);
599 gtk_entry_set_text (entry, full_path);
600 g_free (full_path);
601 }
602
603 g_free (uri_scheme);
604 }
605
606 GTK_ENTRY_CLASS (nautilus_location_entry_parent_class)->activate (entry);
607 }
608
609 static void
610 nautilus_location_entry_cancel (NautilusLocationEntry *entry)
611 {
612 char *last_uri;
613
614 last_uri = entry->details->last_uri;
615 nautilus_location_entry_set_uri (entry, last_uri);
616 }
617
618 static void
619 nautilus_location_entry_class_init (NautilusLocationEntryClass *class)
620 {
621 GtkWidgetClass *widget_class;
622 GObjectClass *gobject_class;
623 GtkEntryClass *entry_class;
624 GtkBindingSet *binding_set;
625
626 widget_class = GTK_WIDGET_CLASS (class);
627 widget_class->focus_in_event = nautilus_location_entry_focus_in;
628 widget_class->destroy = destroy;
629
630 gobject_class = G_OBJECT_CLASS (class);
631 gobject_class->finalize = finalize;
632
633 entry_class = GTK_ENTRY_CLASS (class);
634 entry_class->activate = nautilus_location_entry_activate;
635
636 class->cancel = nautilus_location_entry_cancel;
637
638 signals[CANCEL] = g_signal_new
639 ("cancel",
640 G_TYPE_FROM_CLASS (class),
641 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
642 G_STRUCT_OFFSET (NautilusLocationEntryClass,
643 cancel),
644 NULL, NULL,
645 g_cclosure_marshal_VOID__VOID,
646 G_TYPE_NONE, 0);
647
648 signals[LOCATION_CHANGED] = g_signal_new
649 ("location-changed",
650 G_TYPE_FROM_CLASS (class),
651 G_SIGNAL_RUN_LAST, 0,
652 NULL, NULL,
653 g_cclosure_marshal_generic,
654 G_TYPE_NONE, 1, G_TYPE_OBJECT);
655
656 binding_set = gtk_binding_set_by_class (class);
657 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0, "cancel", 0);
658
659 g_type_class_add_private (class, sizeof (NautilusLocationEntryDetails));
660 }
661
662 void
663 nautilus_location_entry_set_secondary_action (NautilusLocationEntry *entry,
664 NautilusLocationEntryAction secondary_action)
665 {
666 if (entry->details->secondary_action == secondary_action) {
667 return;
668 }
669 switch (secondary_action) {
670 case NAUTILUS_LOCATION_ENTRY_ACTION_CLEAR:
671 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry),
672 GTK_ENTRY_ICON_SECONDARY,
673 "edit-clear-symbolic");
674 break;
675 case NAUTILUS_LOCATION_ENTRY_ACTION_GOTO:
676 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry),
677 GTK_ENTRY_ICON_SECONDARY,
678 "go-next-symbolic");
679 break;
680 default:
681 g_assert_not_reached ();
682 }
683 entry->details->secondary_action = secondary_action;
684 }
685
686 static void
687 editable_activate_callback (GtkEntry *entry,
688 gpointer user_data)
689 {
690 NautilusLocationEntry *self = user_data;
691 const char *entry_text;
692
693 entry_text = gtk_entry_get_text (entry);
694 if (entry_text != NULL && *entry_text != '\0') {
695 emit_location_changed (self);
696 }
697 }
698
699 static void
700 editable_changed_callback (GtkEntry *entry,
701 gpointer user_data)
702 {
703 nautilus_location_entry_update_action (NAUTILUS_LOCATION_ENTRY (entry));
704 }
705
706 static void
707 nautilus_location_entry_init (NautilusLocationEntry *entry)
708 {
709 GtkTargetList *targetlist;
710
711 entry->details = G_TYPE_INSTANCE_GET_PRIVATE (entry, NAUTILUS_TYPE_LOCATION_ENTRY,
712 NautilusLocationEntryDetails);
713
714 entry->details->completer = g_filename_completer_new ();
715 g_filename_completer_set_dirs_only (entry->details->completer, TRUE);
716
717 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry), GTK_ENTRY_ICON_PRIMARY, "folder-symbolic");
718 gtk_entry_set_icon_activatable (GTK_ENTRY (entry), GTK_ENTRY_ICON_PRIMARY, FALSE);
719 targetlist = gtk_target_list_new (drag_types, G_N_ELEMENTS (drag_types));
720 gtk_entry_set_icon_drag_source (GTK_ENTRY (entry), GTK_ENTRY_ICON_PRIMARY, targetlist, GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
721 gtk_target_list_unref (targetlist);
722
723 nautilus_location_entry_set_secondary_action (entry,
724 NAUTILUS_LOCATION_ENTRY_ACTION_CLEAR);
725
726 nautilus_entry_set_special_tab_handling (NAUTILUS_ENTRY (entry), TRUE);
727
728 g_signal_connect (entry, "event_after",
729 G_CALLBACK (editable_event_after_callback), entry);
730
731 g_signal_connect (entry, "notify::text",
732 G_CALLBACK (nautilus_location_entry_text_changed), NULL);
733
734 g_signal_connect (entry, "icon-release",
735 G_CALLBACK (nautilus_location_entry_icon_release), NULL);
736
737 g_signal_connect (entry->details->completer, "got_completion_data",
738 G_CALLBACK (got_completion_data_callback), entry);
739
740 /* Drag source */
741 g_signal_connect_object (entry, "drag_data_get",
742 G_CALLBACK (drag_data_get_callback), entry, 0);
743
744 /* Drag dest. */
745 gtk_drag_dest_set (GTK_WIDGET (entry),
746 GTK_DEST_DEFAULT_ALL,
747 drop_types, G_N_ELEMENTS (drop_types),
748 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
749 g_signal_connect (entry, "drag_data_received",
750 G_CALLBACK (drag_data_received_callback), NULL);
751
752 g_signal_connect_object (entry, "activate",
753 G_CALLBACK (editable_activate_callback), entry, G_CONNECT_AFTER);
754 g_signal_connect_object (entry, "changed",
755 G_CALLBACK (editable_changed_callback), entry, 0);
756 }
757
758 GtkWidget *
759 nautilus_location_entry_new (void)
760 {
761 GtkWidget *entry;
762
763 entry = gtk_widget_new (NAUTILUS_TYPE_LOCATION_ENTRY, NULL);
764
765 return entry;
766 }
767
768 void
769 nautilus_location_entry_set_special_text (NautilusLocationEntry *entry,
770 const char *special_text)
771 {
772 entry->details->has_special_text = TRUE;
773
774 g_free (entry->details->special_text);
775 entry->details->special_text = g_strdup (special_text);
776
777 entry->details->setting_special_text = TRUE;
778 gtk_entry_set_text (GTK_ENTRY (entry), special_text);
779 entry->details->setting_special_text = FALSE;
780 }