Mercurial > geeqie.yaz
annotate src/ui_tabcomp.c @ 1562:4c8c041c8f5b
fixed writting metadata behavior at exit
author | nadvornik |
---|---|
date | Thu, 23 Apr 2009 21:15:14 +0000 |
parents | 89dedc61b1bd |
children |
rev | line source |
---|---|
9 | 1 /* |
2 * (SLIK) SimpLIstic sKin functions | |
69
31759d770628
Fri Oct 13 10:27:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
12
diff
changeset
|
3 * (C) 2006 John Ellis |
1284 | 4 * Copyright (C) 2008 - 2009 The Geeqie Team |
9 | 5 * |
6 * Author: John Ellis | |
7 * | |
8 * This software is released under the GNU General Public License (GNU GPL). | |
9 * Please read the included file COPYING for more information. | |
10 * This software comes with no warranty of any kind, use at your own risk! | |
11 */ | |
12 | |
13 #ifdef HAVE_CONFIG_H | |
14 # include "config.h" | |
15 #endif | |
16 #include "intl.h" | |
17 | |
18 #include <stdio.h> | |
19 #include <stdlib.h> | |
20 #include <string.h> | |
21 #include <unistd.h> | |
22 #include <sys/types.h> | |
23 #include <dirent.h> | |
24 | |
25 #include <gdk/gdk.h> | |
26 #include <gtk/gtk.h> | |
27 #include <gdk-pixbuf/gdk-pixbuf.h> | |
28 | |
281 | 29 #include "main.h" |
9 | 30 #include "ui_tabcomp.h" |
31 | |
902 | 32 #include "history_list.h" |
1022
9962b24b6b43
Move miscellaneous functions to their own files (new misc.[ch]).
zas_
parents:
991
diff
changeset
|
33 #include "misc.h" /* expand_tilde() */ |
9 | 34 #include "ui_fileops.h" |
35 #include "ui_spinner.h" | |
36 #include "ui_utildlg.h" | |
37 | |
38 #include <gdk/gdkkeysyms.h> /* for key values */ | |
39 | |
40 | |
41 /* define this to enable a pop-up menu that shows possible matches | |
42 * #define TAB_COMPLETION_ENABLE_POPUP_MENU | |
43 */ | |
44 #define TAB_COMPLETION_ENABLE_POPUP_MENU 1 | |
1388
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
45 #define TAB_COMP_POPUP_MAX 1000 |
9 | 46 |
47 #ifdef TAB_COMPLETION_ENABLE_POPUP_MENU | |
48 #include "ui_menu.h" | |
49 #endif | |
50 | |
51 | |
52 /* ---------------------------------------------------------------- | |
53 Tab completion routines, can be connected to any gtkentry widget | |
54 using the tab_completion_add_to_entry() function. | |
726 | 55 Use remove_trailing_slash() to strip the trailing G_DIR_SEPARATOR. |
9 | 56 ----------------------------------------------------------------*/ |
57 | |
58 typedef struct _TabCompData TabCompData; | |
59 struct _TabCompData | |
60 { | |
61 GtkWidget *entry; | |
62 gchar *dir_path; | |
63 GList *file_list; | |
64 void (*enter_func)(const gchar *, gpointer); | |
65 void (*tab_func)(const gchar *, gpointer); | |
1167
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
66 void (*tab_append_func)(const gchar *, gpointer, gint); |
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
67 |
9 | 68 gpointer enter_data; |
69 gpointer tab_data; | |
1167
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
70 gpointer tab_append_data; |
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
71 |
9 | 72 GtkWidget *combo; |
1448 | 73 gboolean has_history; |
9 | 74 gchar *history_key; |
75 gint history_levels; | |
76 | |
77 FileDialog *fd; | |
78 gchar *fd_title; | |
1448 | 79 gboolean fd_folders_only; |
9 | 80 GtkWidget *fd_button; |
1388
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
81 |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
82 guint choices; |
9 | 83 }; |
84 | |
85 | |
86 static void tab_completion_select_show(TabCompData *td); | |
1388
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
87 static gint tab_completion_do(TabCompData *td); |
9 | 88 |
89 static void tab_completion_free_list(TabCompData *td) | |
90 { | |
91 GList *list; | |
92 | |
93 g_free(td->dir_path); | |
94 td->dir_path = NULL; | |
95 | |
96 list = td->file_list; | |
97 | |
516 | 98 while (list) |
9 | 99 { |
100 g_free(list->data); | |
101 list = list->next; | |
102 } | |
103 | |
104 g_list_free(td->file_list); | |
105 td->file_list = NULL; | |
106 } | |
107 | |
108 static void tab_completion_read_dir(TabCompData *td, const gchar *path) | |
109 { | |
442 | 110 DIR *dp; |
111 struct dirent *dir; | |
112 GList *list = NULL; | |
9 | 113 gchar *pathl; |
114 | |
115 tab_completion_free_list(td); | |
116 | |
117 pathl = path_from_utf8(path); | |
442 | 118 dp = opendir(pathl); |
9 | 119 if (!dp) |
442 | 120 { |
121 /* dir not found */ | |
1385
b4e6fee484f7
Fix utf8/locale conversion warning: the path passed to isdir() is not in UTF8 (if local fs is not in UFT8) so do not use it (isdir() uses stat_utf8() which calls path_from_utf8()).
zas_
parents:
1382
diff
changeset
|
122 g_free(pathl); |
442 | 123 return; |
124 } | |
125 while ((dir = readdir(dp)) != NULL) | |
126 { | |
69
31759d770628
Fri Oct 13 10:27:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
12
diff
changeset
|
127 gchar *name = dir->d_name; |
31759d770628
Fri Oct 13 10:27:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
12
diff
changeset
|
128 if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0) |
31759d770628
Fri Oct 13 10:27:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
12
diff
changeset
|
129 { |
1385
b4e6fee484f7
Fix utf8/locale conversion warning: the path passed to isdir() is not in UTF8 (if local fs is not in UFT8) so do not use it (isdir() uses stat_utf8() which calls path_from_utf8()).
zas_
parents:
1382
diff
changeset
|
130 gchar *abspath = g_build_filename(pathl, name, NULL); |
1370
0011d6859ec5
Add a directory separator at the end of names in tab completion list to indicate directories.
zas_
parents:
1365
diff
changeset
|
131 |
1385
b4e6fee484f7
Fix utf8/locale conversion warning: the path passed to isdir() is not in UTF8 (if local fs is not in UFT8) so do not use it (isdir() uses stat_utf8() which calls path_from_utf8()).
zas_
parents:
1382
diff
changeset
|
132 if (g_file_test(abspath, G_FILE_TEST_IS_DIR)) |
1370
0011d6859ec5
Add a directory separator at the end of names in tab completion list to indicate directories.
zas_
parents:
1365
diff
changeset
|
133 { |
0011d6859ec5
Add a directory separator at the end of names in tab completion list to indicate directories.
zas_
parents:
1365
diff
changeset
|
134 gchar *dname = g_strconcat(name, G_DIR_SEPARATOR_S, NULL); |
0011d6859ec5
Add a directory separator at the end of names in tab completion list to indicate directories.
zas_
parents:
1365
diff
changeset
|
135 list = g_list_prepend(list, path_to_utf8(dname)); |
1371 | 136 g_free(dname); |
1370
0011d6859ec5
Add a directory separator at the end of names in tab completion list to indicate directories.
zas_
parents:
1365
diff
changeset
|
137 } |
0011d6859ec5
Add a directory separator at the end of names in tab completion list to indicate directories.
zas_
parents:
1365
diff
changeset
|
138 else |
0011d6859ec5
Add a directory separator at the end of names in tab completion list to indicate directories.
zas_
parents:
1365
diff
changeset
|
139 { |
0011d6859ec5
Add a directory separator at the end of names in tab completion list to indicate directories.
zas_
parents:
1365
diff
changeset
|
140 list = g_list_prepend(list, path_to_utf8(name)); |
0011d6859ec5
Add a directory separator at the end of names in tab completion list to indicate directories.
zas_
parents:
1365
diff
changeset
|
141 } |
0011d6859ec5
Add a directory separator at the end of names in tab completion list to indicate directories.
zas_
parents:
1365
diff
changeset
|
142 g_free(abspath); |
69
31759d770628
Fri Oct 13 10:27:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
12
diff
changeset
|
143 } |
9 | 144 } |
442 | 145 closedir(dp); |
9 | 146 |
147 td->dir_path = g_strdup(path); | |
148 td->file_list = list; | |
1385
b4e6fee484f7
Fix utf8/locale conversion warning: the path passed to isdir() is not in UTF8 (if local fs is not in UFT8) so do not use it (isdir() uses stat_utf8() which calls path_from_utf8()).
zas_
parents:
1382
diff
changeset
|
149 g_free(pathl); |
9 | 150 } |
151 | |
152 static void tab_completion_destroy(GtkWidget *widget, gpointer data) | |
153 { | |
154 TabCompData *td = data; | |
155 | |
156 tab_completion_free_list(td); | |
157 g_free(td->history_key); | |
158 | |
159 if (td->fd) file_dialog_close(td->fd); | |
160 g_free(td->fd_title); | |
161 | |
162 g_free(td); | |
163 } | |
164 | |
991 | 165 static gchar *tab_completion_get_text(TabCompData *td) |
9 | 166 { |
167 gchar *text; | |
168 | |
169 text = g_strdup(gtk_entry_get_text(GTK_ENTRY(td->entry))); | |
170 | |
171 if (text[0] == '~') | |
172 { | |
173 gchar *t = text; | |
720
d8a88f279aca
Use expand_tilde() instead of simple concatenation, it allows correct expansion
zas_
parents:
673
diff
changeset
|
174 text = expand_tilde(text); |
9 | 175 g_free(t); |
176 } | |
177 | |
991 | 178 return text; |
179 } | |
180 | |
1448 | 181 static gboolean tab_completion_emit_enter_signal(TabCompData *td) |
991 | 182 { |
183 gchar *text; | |
184 if (!td->enter_func) return FALSE; | |
185 | |
186 text = tab_completion_get_text(td); | |
9 | 187 td->enter_func(text, td->enter_data); |
188 g_free(text); | |
189 | |
190 return TRUE; | |
191 } | |
192 | |
193 static void tab_completion_emit_tab_signal(TabCompData *td) | |
194 { | |
195 gchar *text; | |
196 if (!td->tab_func) return; | |
197 | |
991 | 198 text = tab_completion_get_text(td); |
9 | 199 td->tab_func(text, td->tab_data); |
200 g_free(text); | |
201 } | |
202 | |
203 #ifdef TAB_COMPLETION_ENABLE_POPUP_MENU | |
1388
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
204 void tab_completion_iter_menu_items(GtkWidget *widget, gpointer data) |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
205 { |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
206 TabCompData *td = data; |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
207 GtkWidget *child; |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
208 |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
209 if (!GTK_WIDGET_VISIBLE(widget)) return; |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
210 |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
211 child = gtk_bin_get_child(GTK_BIN(widget)); |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
212 if (GTK_IS_LABEL(child)) { |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
213 const gchar *text = gtk_label_get_text(GTK_LABEL(child)); |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
214 const gchar *entry_text = gtk_entry_get_text(GTK_ENTRY(td->entry)); |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
215 const gchar *prefix = filename_from_path(entry_text); |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
216 guint prefix_len = strlen(prefix); |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
217 |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
218 if (strlen(text) < prefix_len || strncmp(text, prefix, prefix_len)) |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
219 { |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
220 /* Hide menu items not matching */ |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
221 gtk_widget_hide(widget); |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
222 } |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
223 else |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
224 { |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
225 /* Count how many choices are left in the menu */ |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
226 td->choices++; |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
227 } |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
228 } |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
229 } |
9 | 230 |
1448 | 231 static gboolean tab_completion_popup_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) |
9 | 232 { |
233 TabCompData *td = data; | |
234 | |
235 if (event->keyval == GDK_Tab || | |
236 event->keyval == GDK_BackSpace || | |
237 (event->keyval >= 0x20 && event->keyval <= 0xFF) ) | |
238 { | |
239 if (event->keyval >= 0x20 && event->keyval <= 0xFF) | |
240 { | |
241 gchar buf[2]; | |
242 gint p = -1; | |
243 | |
244 buf[0] = event->keyval; | |
245 buf[1] = '\0'; | |
246 gtk_editable_insert_text(GTK_EDITABLE(td->entry), buf, 1, &p); | |
247 gtk_editable_set_position(GTK_EDITABLE(td->entry), -1); | |
1388
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
248 |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
249 /* Reduce the number of entries in the menu */ |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
250 td->choices = 0; |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
251 gtk_container_foreach(GTK_CONTAINER(widget), tab_completion_iter_menu_items, (gpointer) td); |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
252 if (td->choices > 1) return TRUE; /* multiple choices */ |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
253 if (td->choices > 0) tab_completion_do(td); /* one choice */ |
9 | 254 } |
1388
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
255 |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
256 /* close the menu */ |
9 | 257 gtk_menu_popdown(GTK_MENU(widget)); |
258 /* doing this does not emit the "selection done" signal, unref it ourselves */ | |
1043 | 259 #if GTK_CHECK_VERSION(2,12,0) |
260 g_object_unref(widget); | |
261 #else | |
9 | 262 gtk_widget_unref(widget); |
1043 | 263 #endif |
9 | 264 return TRUE; |
265 } | |
266 | |
267 return FALSE; | |
268 } | |
269 | |
270 static void tab_completion_popup_cb(GtkWidget *widget, gpointer data) | |
271 { | |
272 gchar *name = data; | |
273 TabCompData *td; | |
274 gchar *buf; | |
275 | |
276 td = g_object_get_data(G_OBJECT(widget), "tab_completion_data"); | |
277 if (!td) return; | |
278 | |
721
b736a2e3129b
tab_completion_popup_cb(): use g_build_filename() and simplify code.
zas_
parents:
720
diff
changeset
|
279 buf = g_build_filename(td->dir_path, name, NULL); |
9 | 280 gtk_entry_set_text(GTK_ENTRY(td->entry), buf); |
281 gtk_editable_set_position(GTK_EDITABLE(td->entry), strlen(buf)); | |
282 g_free(buf); | |
283 | |
284 tab_completion_emit_tab_signal(td); | |
285 } | |
286 | |
287 static void tab_completion_popup_pos_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data) | |
288 { | |
289 TabCompData *td = data; | |
290 gint height; | |
291 PangoLayout *layout; | |
292 PangoRectangle strong_pos, weak_pos; | |
293 gint length; | |
294 gint xoffset, yoffset; | |
12
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
295 GtkRequisition req; |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
296 GdkScreen *screen; |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
297 gint monitor_num; |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
298 GdkRectangle monitor; |
9 | 299 |
300 gdk_window_get_origin(td->entry->window, x, y); | |
301 | |
12
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
302 screen = gtk_widget_get_screen(GTK_WIDGET(menu)); |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
303 monitor_num = gdk_screen_get_monitor_at_window(screen, td->entry->window); |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
304 gdk_screen_get_monitor_geometry(screen, monitor_num, &monitor); |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
305 |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
306 gtk_widget_size_request(GTK_WIDGET(menu), &req); |
9 | 307 |
308 length = strlen(gtk_entry_get_text(GTK_ENTRY(td->entry))); | |
309 gtk_entry_get_layout_offsets(GTK_ENTRY(td->entry), &xoffset, &yoffset); | |
310 | |
311 layout = gtk_entry_get_layout(GTK_ENTRY(td->entry)); | |
312 pango_layout_get_cursor_pos(layout, length, &strong_pos, &weak_pos); | |
12
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
313 |
9 | 314 *x += strong_pos.x / PANGO_SCALE + xoffset; |
12
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
315 |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
316 height = MIN(td->entry->requisition.height, td->entry->allocation.height); |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
317 |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
318 if (req.height > monitor.y + monitor.height - *y - height && |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
319 *y - monitor.y > monitor.y + monitor.height - *y) |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
320 { |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
321 height = MIN(*y - monitor.y, req.height); |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
322 gtk_widget_set_size_request(GTK_WIDGET(menu), -1, height); |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
323 *y -= height; |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
324 } |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
325 else |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
326 { |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
327 *y += height; |
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
328 } |
9 | 329 } |
330 | |
331 static void tab_completion_popup_list(TabCompData *td, GList *list) | |
332 { | |
333 GtkWidget *menu; | |
334 GList *work; | |
335 GdkEvent *event; | |
336 guint32 etime; | |
337 gint ebutton; | |
338 gint count = 0; | |
339 | |
340 if (!list) return; | |
341 | |
342 #if 0 | |
343 /* | |
344 * well, the menu would be too long anyway... | |
345 * (listing /dev causes gtk+ window allocation errors, -> too big a window) | |
346 * this is why menu popups are disabled, this really should be a popup scrollable listview. | |
347 */ | |
348 if (g_list_length(list) > 200) return; | |
349 #endif | |
350 | |
351 menu = popup_menu_short_lived(); | |
352 | |
353 work = list; | |
354 while (work && count < TAB_COMP_POPUP_MAX) | |
355 { | |
356 gchar *name = work->data; | |
357 GtkWidget *item; | |
358 | |
359 item = menu_item_add_simple(menu, name, G_CALLBACK(tab_completion_popup_cb), name); | |
360 g_object_set_data(G_OBJECT(item), "tab_completion_data", td); | |
361 | |
362 work = work->next; | |
363 count++; | |
364 } | |
365 | |
366 g_signal_connect(G_OBJECT(menu), "key_press_event", | |
367 G_CALLBACK(tab_completion_popup_key_press), td); | |
368 | |
369 /* peek at the current event to get the time, etc. */ | |
370 event = gtk_get_current_event(); | |
371 | |
372 if (event && event->type == GDK_BUTTON_RELEASE) | |
373 { | |
374 ebutton = event->button.button; | |
375 } | |
376 else | |
377 { | |
378 ebutton = 0; | |
379 } | |
380 | |
381 if (event) | |
382 { | |
383 etime = gdk_event_get_time(event); | |
384 gdk_event_free(event); | |
385 } | |
386 else | |
387 { | |
388 etime = 0; | |
389 } | |
390 | |
391 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, | |
392 tab_completion_popup_pos_cb, td, ebutton, etime); | |
393 } | |
394 | |
395 #ifndef CASE_SORT | |
396 #define CASE_SORT strcmp | |
397 #endif | |
398 | |
399 static gint simple_sort(gconstpointer a, gconstpointer b) | |
400 { | |
442 | 401 return CASE_SORT((gchar *)a, (gchar *)b); |
9 | 402 } |
403 | |
404 #endif | |
405 | |
1448 | 406 static gboolean tab_completion_do(TabCompData *td) |
9 | 407 { |
408 const gchar *entry_text = gtk_entry_get_text(GTK_ENTRY(td->entry)); | |
409 const gchar *entry_file; | |
410 gchar *entry_dir; | |
411 gchar *ptr; | |
1437 | 412 gboolean home_exp = FALSE; |
9 | 413 |
1388
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
414 if (entry_text[0] == '\0') |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
415 { |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
416 entry_dir = g_strdup(G_DIR_SEPARATOR_S); /* FIXME: root directory win32 */ |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
417 gtk_entry_set_text(GTK_ENTRY(td->entry), entry_dir); |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
418 gtk_editable_set_position(GTK_EDITABLE(td->entry), strlen(entry_dir)); |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
419 g_free(entry_dir); |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
420 return FALSE; |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
421 } |
2496a345c452
Try to improve tab completion: when a key is pressed while tab completion menu is shown, the number of entries is reduced, dhowing all matching entries but the menu is no more closed after each key pressure. Number of possible entries in this menu was increased from 500 to 1000. Pressing TAB when path entry is empty now adds / (root directory).
zas_
parents:
1385
diff
changeset
|
422 |
9 | 423 /* home dir expansion */ |
424 if (entry_text[0] == '~') | |
425 { | |
720
d8a88f279aca
Use expand_tilde() instead of simple concatenation, it allows correct expansion
zas_
parents:
673
diff
changeset
|
426 entry_dir = expand_tilde(entry_text); |
9 | 427 home_exp = TRUE; |
428 } | |
429 else | |
430 { | |
431 entry_dir = g_strdup(entry_text); | |
432 } | |
433 | |
434 if (isfile(entry_dir)) | |
435 { | |
436 if (home_exp) | |
437 { | |
438 gtk_entry_set_text(GTK_ENTRY(td->entry), entry_dir); | |
439 gtk_editable_set_position(GTK_EDITABLE(td->entry), strlen(entry_dir)); | |
440 } | |
441 g_free(entry_dir); | |
442 return home_exp; | |
443 } | |
722
9a145206ec2c
tab_completion_do(): use g_build_filename(), G_DIR_SEPARATOR, G_DIR_SEPARATOR_S.
zas_
parents:
721
diff
changeset
|
444 |
1382
31a747f9d268
Fix tab completion when entering "/et[TAB]" it was changed to "et", this is fixed.
zas_
parents:
1371
diff
changeset
|
445 entry_file = filename_from_path(entry_text); |
31a747f9d268
Fix tab completion when entering "/et[TAB]" it was changed to "et", this is fixed.
zas_
parents:
1371
diff
changeset
|
446 |
9 | 447 if (isdir(entry_dir) && strcmp(entry_file, ".") != 0 && strcmp(entry_file, "..") != 0) |
448 { | |
449 ptr = entry_dir + strlen(entry_dir) - 1; | |
722
9a145206ec2c
tab_completion_do(): use g_build_filename(), G_DIR_SEPARATOR, G_DIR_SEPARATOR_S.
zas_
parents:
721
diff
changeset
|
450 if (ptr[0] == G_DIR_SEPARATOR) |
9 | 451 { |
452 if (home_exp) | |
453 { | |
454 gtk_entry_set_text(GTK_ENTRY(td->entry), entry_dir); | |
455 gtk_editable_set_position(GTK_EDITABLE(td->entry), strlen(entry_dir)); | |
456 } | |
457 | |
458 tab_completion_read_dir(td, entry_dir); | |
459 td->file_list = g_list_sort(td->file_list, simple_sort); | |
460 if (td->file_list && !td->file_list->next) | |
461 { | |
462 gchar *buf; | |
463 const gchar *file; | |
464 | |
465 file = td->file_list->data; | |
722
9a145206ec2c
tab_completion_do(): use g_build_filename(), G_DIR_SEPARATOR, G_DIR_SEPARATOR_S.
zas_
parents:
721
diff
changeset
|
466 buf = g_build_filename(entry_dir, file, NULL); |
9 | 467 if (isdir(buf)) |
468 { | |
722
9a145206ec2c
tab_completion_do(): use g_build_filename(), G_DIR_SEPARATOR, G_DIR_SEPARATOR_S.
zas_
parents:
721
diff
changeset
|
469 gchar *tmp = g_strconcat(buf, G_DIR_SEPARATOR_S, NULL); |
9 | 470 g_free(buf); |
722
9a145206ec2c
tab_completion_do(): use g_build_filename(), G_DIR_SEPARATOR, G_DIR_SEPARATOR_S.
zas_
parents:
721
diff
changeset
|
471 buf = tmp; |
9 | 472 } |
473 gtk_entry_set_text(GTK_ENTRY(td->entry), buf); | |
474 gtk_editable_set_position(GTK_EDITABLE(td->entry), strlen(buf)); | |
475 g_free(buf); | |
476 } | |
477 | |
478 #ifdef TAB_COMPLETION_ENABLE_POPUP_MENU | |
479 | |
480 else | |
481 { | |
482 tab_completion_popup_list(td, td->file_list); | |
483 } | |
484 #endif | |
485 | |
486 g_free(entry_dir); | |
487 return home_exp; | |
488 } | |
489 else | |
490 { | |
722
9a145206ec2c
tab_completion_do(): use g_build_filename(), G_DIR_SEPARATOR, G_DIR_SEPARATOR_S.
zas_
parents:
721
diff
changeset
|
491 gchar *buf = g_strconcat(entry_dir, G_DIR_SEPARATOR_S, NULL); |
9 | 492 gtk_entry_set_text(GTK_ENTRY(td->entry), buf); |
493 gtk_editable_set_position(GTK_EDITABLE(td->entry), strlen(buf)); | |
494 g_free(buf); | |
495 g_free(entry_dir); | |
496 return TRUE; | |
497 } | |
498 } | |
499 | |
500 ptr = (gchar *)filename_from_path(entry_dir); | |
501 if (ptr > entry_dir) ptr--; | |
502 ptr[0] = '\0'; | |
1382
31a747f9d268
Fix tab completion when entering "/et[TAB]" it was changed to "et", this is fixed.
zas_
parents:
1371
diff
changeset
|
503 |
9 | 504 if (strlen(entry_dir) == 0) |
505 { | |
506 g_free(entry_dir); | |
722
9a145206ec2c
tab_completion_do(): use g_build_filename(), G_DIR_SEPARATOR, G_DIR_SEPARATOR_S.
zas_
parents:
721
diff
changeset
|
507 entry_dir = g_strdup(G_DIR_SEPARATOR_S); /* FIXME: win32 */ |
9 | 508 } |
509 | |
510 if (isdir(entry_dir)) | |
511 { | |
512 GList *list; | |
513 GList *poss = NULL; | |
514 gint l = strlen(entry_file); | |
515 | |
516 if (!td->dir_path || !td->file_list || strcmp(td->dir_path, entry_dir) != 0) | |
517 { | |
518 tab_completion_read_dir(td, entry_dir); | |
519 } | |
520 | |
521 list = td->file_list; | |
516 | 522 while (list) |
9 | 523 { |
524 gchar *file = list->data; | |
525 if (strncmp(entry_file, file, l) == 0) | |
526 { | |
527 poss = g_list_prepend(poss, file); | |
528 } | |
529 list = list->next; | |
530 } | |
531 | |
532 if (poss) | |
533 { | |
534 if (!poss->next) | |
535 { | |
536 gchar *file = poss->data; | |
537 gchar *buf; | |
538 | |
722
9a145206ec2c
tab_completion_do(): use g_build_filename(), G_DIR_SEPARATOR, G_DIR_SEPARATOR_S.
zas_
parents:
721
diff
changeset
|
539 buf = g_build_filename(entry_dir, file, NULL); |
9 | 540 gtk_entry_set_text(GTK_ENTRY(td->entry), buf); |
541 gtk_editable_set_position(GTK_EDITABLE(td->entry), strlen(buf)); | |
542 g_free(buf); | |
543 g_list_free(poss); | |
544 g_free(entry_dir); | |
545 return TRUE; | |
546 } | |
547 else | |
548 { | |
734
e6ebae313d46
Fix up some types, make some signed vs unsigned warnings quiet.
zas_
parents:
726
diff
changeset
|
549 gsize c = strlen(entry_file); |
1437 | 550 gboolean done = FALSE; |
9 | 551 gchar *test_file = poss->data; |
552 | |
553 while (!done) | |
554 { | |
555 list = poss; | |
556 if (!list) done = TRUE; | |
516 | 557 while (list && !done) |
9 | 558 { |
559 gchar *file = list->data; | |
560 if (strlen(file) < c || strncmp(test_file, file, c) != 0) | |
561 { | |
562 done = TRUE; | |
563 } | |
564 list = list->next; | |
565 } | |
566 c++; | |
567 } | |
568 c -= 2; | |
569 if (c > 0) | |
570 { | |
571 gchar *file; | |
572 gchar *buf; | |
573 file = g_strdup(test_file); | |
574 file[c] = '\0'; | |
722
9a145206ec2c
tab_completion_do(): use g_build_filename(), G_DIR_SEPARATOR, G_DIR_SEPARATOR_S.
zas_
parents:
721
diff
changeset
|
575 buf = g_build_filename(entry_dir, file, NULL); |
9 | 576 gtk_entry_set_text(GTK_ENTRY(td->entry), buf); |
577 gtk_editable_set_position(GTK_EDITABLE(td->entry), strlen(buf)); | |
578 | |
579 #ifdef TAB_COMPLETION_ENABLE_POPUP_MENU | |
580 | |
581 poss = g_list_sort(poss, simple_sort); | |
582 tab_completion_popup_list(td, poss); | |
583 | |
584 #endif | |
585 | |
586 g_free(file); | |
587 g_free(buf); | |
588 g_list_free(poss); | |
589 g_free(entry_dir); | |
590 return TRUE; | |
591 } | |
592 } | |
593 g_list_free(poss); | |
594 } | |
595 } | |
596 | |
597 g_free(entry_dir); | |
598 | |
599 return FALSE; | |
600 } | |
601 | |
1448 | 602 static gboolean tab_completion_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data) |
9 | 603 { |
604 TabCompData *td = data; | |
1437 | 605 gboolean stop_signal = FALSE; |
9 | 606 |
607 switch (event->keyval) | |
608 { | |
442 | 609 case GDK_Tab: |
9 | 610 if (!(event->state & GDK_CONTROL_MASK)) |
611 { | |
612 if (tab_completion_do(td)) | |
613 { | |
614 tab_completion_emit_tab_signal(td); | |
615 } | |
616 stop_signal = TRUE; | |
617 } | |
618 break; | |
619 case GDK_Return: case GDK_KP_Enter: | |
620 if (td->fd_button && | |
621 (event->state & GDK_CONTROL_MASK)) | |
622 { | |
623 tab_completion_select_show(td); | |
624 stop_signal = TRUE; | |
625 } | |
626 else if (tab_completion_emit_enter_signal(td)) | |
627 { | |
628 stop_signal = TRUE; | |
629 } | |
630 break; | |
631 default: | |
632 break; | |
633 } | |
634 | |
635 if (stop_signal) g_signal_stop_emission_by_name(G_OBJECT(widget), "key_press_event"); | |
636 | |
637 return (stop_signal); | |
638 } | |
639 | |
640 static void tab_completion_button_pressed(GtkWidget *widget, gpointer data) | |
641 { | |
642 TabCompData *td; | |
643 GtkWidget *entry = data; | |
644 | |
645 td = g_object_get_data(G_OBJECT(entry), "tab_completion_data"); | |
646 | |
647 if (!td) return; | |
648 | |
649 if (!GTK_WIDGET_HAS_FOCUS(entry)) | |
650 { | |
651 gtk_widget_grab_focus(entry); | |
652 } | |
653 | |
654 if (tab_completion_do(td)) | |
655 { | |
656 tab_completion_emit_tab_signal(td); | |
657 } | |
658 } | |
659 | |
660 static void tab_completion_button_size_allocate(GtkWidget *button, GtkAllocation *allocation, gpointer data) | |
661 { | |
662 GtkWidget *parent = data; | |
663 | |
664 if (allocation->height > parent->allocation.height) | |
665 { | |
666 GtkAllocation button_allocation; | |
667 | |
668 button_allocation = button->allocation; | |
669 button_allocation.height = parent->allocation.height; | |
670 button_allocation.y = parent->allocation.y + | |
671 (parent->allocation.height - parent->allocation.height) / 2; | |
672 gtk_widget_size_allocate(button, &button_allocation); | |
673 } | |
674 } | |
675 | |
676 static GtkWidget *tab_completion_create_complete_button(GtkWidget *entry, GtkWidget *parent) | |
677 { | |
678 GtkWidget *button; | |
679 GtkWidget *icon; | |
680 GdkPixbuf *pixbuf; | |
681 | |
682 button = gtk_button_new(); | |
683 GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_FOCUS); | |
684 g_signal_connect(G_OBJECT(button), "size_allocate", | |
685 G_CALLBACK(tab_completion_button_size_allocate), parent); | |
686 g_signal_connect(G_OBJECT(button), "clicked", | |
687 G_CALLBACK(tab_completion_button_pressed), entry); | |
688 | |
689 pixbuf = gdk_pixbuf_new_from_inline(-1, icon_tabcomp, FALSE, NULL); | |
690 icon = gtk_image_new_from_pixbuf(pixbuf); | |
1043 | 691 g_object_unref(pixbuf); |
692 | |
9 | 693 gtk_container_add(GTK_CONTAINER(button), icon); |
694 gtk_widget_show(icon); | |
695 | |
696 return button; | |
697 } | |
698 | |
699 /* | |
700 *---------------------------------------------------------------------------- | |
701 * public interface | |
702 *---------------------------------------------------------------------------- | |
703 */ | |
704 | |
705 GtkWidget *tab_completion_new_with_history(GtkWidget **entry, const gchar *text, | |
706 const gchar *history_key, gint max_levels, | |
707 void (*enter_func)(const gchar *, gpointer), gpointer data) | |
708 { | |
709 GtkWidget *box; | |
710 GtkWidget *combo; | |
711 GtkWidget *combo_entry; | |
712 GtkWidget *button; | |
713 GList *work; | |
714 TabCompData *td; | |
715 gint n = 0; | |
716 | |
717 box = gtk_hbox_new(FALSE, 0); | |
718 | |
719 combo = gtk_combo_box_entry_new_text(); | |
720 gtk_box_pack_start(GTK_BOX(box), combo, TRUE, TRUE, 0); | |
721 gtk_widget_show(combo); | |
722 | |
723 combo_entry = GTK_BIN(combo)->child; | |
724 #if 0 | |
725 gtk_combo_set_case_sensitive(GTK_COMBO(combo), TRUE); | |
726 gtk_combo_set_use_arrows(GTK_COMBO(combo), FALSE); | |
727 #endif | |
728 | |
729 button = tab_completion_create_complete_button(combo_entry, combo); | |
730 gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0); | |
731 gtk_widget_show(button); | |
732 | |
733 tab_completion_add_to_entry(combo_entry, enter_func, data); | |
734 | |
735 td = g_object_get_data(G_OBJECT(combo_entry), "tab_completion_data"); | |
736 if (!td) return NULL; /* this should never happen! */ | |
737 | |
738 td->combo = combo; | |
739 td->has_history = TRUE; | |
740 td->history_key = g_strdup(history_key); | |
741 td->history_levels = max_levels; | |
742 | |
743 work = history_list_get_by_key(td->history_key); | |
744 | |
745 work = history_list_get_by_key(history_key); | |
746 while (work) | |
747 { | |
748 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), (gchar *)work->data); | |
749 work = work->next; | |
750 n++; | |
751 } | |
752 | |
753 if (text) | |
754 { | |
755 gtk_entry_set_text(GTK_ENTRY(combo_entry), text); | |
756 } | |
757 else if (n > 0) | |
758 { | |
759 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0); | |
760 } | |
761 | |
762 if (entry) *entry = combo_entry; | |
763 return box; | |
764 } | |
765 | |
766 const gchar *tab_completion_set_to_last_history(GtkWidget *entry) | |
767 { | |
768 TabCompData *td = g_object_get_data(G_OBJECT(entry), "tab_completion_data"); | |
769 const gchar *buf; | |
770 | |
771 if (!td || !td->has_history) return NULL; | |
772 | |
773 buf = history_list_find_last_path_by_key(td->history_key); | |
774 if (buf) | |
775 { | |
776 gtk_entry_set_text(GTK_ENTRY(td->entry), buf); | |
777 } | |
778 | |
779 return buf; | |
780 } | |
781 | |
782 void tab_completion_append_to_history(GtkWidget *entry, const gchar *path) | |
783 { | |
784 TabCompData *td; | |
785 GtkTreeModel *store; | |
786 GList *work; | |
1167
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
787 gint n = 0; |
9 | 788 |
789 td = g_object_get_data(G_OBJECT(entry), "tab_completion_data"); | |
790 | |
791 if (!path) return; | |
792 | |
793 if (!td || !td->has_history) return; | |
794 | |
795 history_list_add_to_key(td->history_key, path, td->history_levels); | |
796 | |
797 gtk_combo_box_set_active(GTK_COMBO_BOX(td->combo), -1); | |
798 | |
799 store = gtk_combo_box_get_model(GTK_COMBO_BOX(td->combo)); | |
800 gtk_list_store_clear(GTK_LIST_STORE(store)); | |
801 | |
802 work = history_list_get_by_key(td->history_key); | |
803 while (work) | |
804 { | |
805 gtk_combo_box_append_text(GTK_COMBO_BOX(td->combo), (gchar *)work->data); | |
806 work = work->next; | |
1167
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
807 n++; |
9 | 808 } |
1167
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
809 |
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
810 if (td->tab_append_func) { |
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
811 td->tab_append_func(path, td->tab_append_data, n); |
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
812 } |
9 | 813 } |
814 | |
815 GtkWidget *tab_completion_new(GtkWidget **entry, const gchar *text, | |
816 void (*enter_func)(const gchar *, gpointer), gpointer data) | |
817 { | |
818 GtkWidget *hbox; | |
819 GtkWidget *button; | |
820 GtkWidget *newentry; | |
821 | |
822 hbox = gtk_hbox_new(FALSE, 0); | |
823 | |
824 newentry = gtk_entry_new(); | |
825 if (text) gtk_entry_set_text(GTK_ENTRY(newentry), text); | |
826 gtk_box_pack_start(GTK_BOX(hbox), newentry, TRUE, TRUE, 0); | |
827 gtk_widget_show(newentry); | |
828 | |
829 button = tab_completion_create_complete_button(newentry, newentry); | |
830 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); | |
831 gtk_widget_show(button); | |
832 | |
833 tab_completion_add_to_entry(newentry, enter_func, data); | |
834 | |
835 if (entry) *entry = newentry; | |
836 return hbox; | |
837 } | |
838 | |
839 void tab_completion_add_to_entry(GtkWidget *entry, void (*enter_func)(const gchar *, gpointer), gpointer data) | |
840 { | |
841 TabCompData *td; | |
842 if (!entry) | |
843 { | |
673
fbebf5cf4a55
Do not use printf() directly but use new wrapper function log_printf() instead.
zas_
parents:
516
diff
changeset
|
844 log_printf("Tab completion error: entry != NULL\n"); |
9 | 845 return; |
846 } | |
847 | |
848 td = g_new0(TabCompData, 1); | |
1365
249bf204004a
When g_new0() is used, drop redundant initializations to NULL, FALSE or 0.
zas_
parents:
1284
diff
changeset
|
849 |
9 | 850 td->entry = entry; |
851 td->enter_func = enter_func; | |
852 td->enter_data = data; | |
853 | |
854 g_object_set_data(G_OBJECT(td->entry), "tab_completion_data", td); | |
855 | |
856 g_signal_connect(G_OBJECT(entry), "key_press_event", | |
857 G_CALLBACK(tab_completion_key_pressed), td); | |
858 g_signal_connect(G_OBJECT(entry), "destroy", | |
859 G_CALLBACK(tab_completion_destroy), td); | |
860 } | |
861 | |
862 void tab_completion_add_tab_func(GtkWidget *entry, void (*tab_func)(const gchar *, gpointer), gpointer data) | |
863 { | |
864 TabCompData *td = g_object_get_data(G_OBJECT(entry), "tab_completion_data"); | |
865 | |
866 if (!td) return; | |
867 | |
868 td->tab_func = tab_func; | |
869 td->tab_data = data; | |
870 } | |
871 | |
1167
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
872 /* Add a callback function called when a new entry is appended to the list */ |
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
873 void tab_completion_add_append_func(GtkWidget *entry, void (*tab_append_func)(const gchar *, gpointer, gint), gpointer data) |
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
874 { |
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
875 TabCompData *td = g_object_get_data(G_OBJECT(entry), "tab_completion_data"); |
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
876 |
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
877 if (!td) return; |
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
878 |
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
879 td->tab_append_func = tab_append_func; |
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
880 td->tab_append_data = data; |
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
881 } |
e812b1a7adda
Add a back button in the toolbar: it allows to go back and forth between two directories. Experimental, please test and comment on ml.
zas_
parents:
1055
diff
changeset
|
882 |
9 | 883 gchar *remove_trailing_slash(const gchar *path) |
884 { | |
885 gint l; | |
260
249a9a6cd27f
Improve remove_trailing_slash() so it allocates no more than
zas_
parents:
254
diff
changeset
|
886 |
9 | 887 if (!path) return NULL; |
888 | |
260
249a9a6cd27f
Improve remove_trailing_slash() so it allocates no more than
zas_
parents:
254
diff
changeset
|
889 l = strlen(path); |
726 | 890 while (l > 1 && path[l - 1] == G_DIR_SEPARATOR) l--; |
9 | 891 |
260
249a9a6cd27f
Improve remove_trailing_slash() so it allocates no more than
zas_
parents:
254
diff
changeset
|
892 return g_strndup(path, l); |
9 | 893 } |
894 | |
895 static void tab_completion_select_cancel_cb(FileDialog *fd, gpointer data) | |
896 { | |
897 TabCompData *td = data; | |
898 | |
899 td->fd = NULL; | |
900 file_dialog_close(fd); | |
901 } | |
902 | |
903 static void tab_completion_select_ok_cb(FileDialog *fd, gpointer data) | |
904 { | |
905 TabCompData *td = data; | |
906 | |
907 gtk_entry_set_text(GTK_ENTRY(td->entry), gtk_entry_get_text(GTK_ENTRY(fd->entry))); | |
908 | |
909 tab_completion_select_cancel_cb(fd, data); | |
910 | |
911 tab_completion_emit_enter_signal(td); | |
912 } | |
913 | |
914 static void tab_completion_select_show(TabCompData *td) | |
915 { | |
916 const gchar *title; | |
917 const gchar *path; | |
918 | |
919 if (td->fd) | |
920 { | |
921 gtk_window_present(GTK_WINDOW(GENERIC_DIALOG(td->fd)->dialog)); | |
922 return; | |
923 } | |
924 | |
925 title = (td->fd_title) ? td->fd_title : _("Select path"); | |
1174
0bea79d87065
Drop useless wmclass stuff. Gtk will take care of it and as said in the documentation using gtk_window_set_wmclass() is sort of pointless.
zas_
parents:
1167
diff
changeset
|
926 td->fd = file_dialog_new(title, "select_path", td->entry, |
9 | 927 tab_completion_select_cancel_cb, td); |
928 file_dialog_add_button(td->fd, GTK_STOCK_OK, NULL, | |
929 tab_completion_select_ok_cb, TRUE); | |
930 | |
931 generic_dialog_add_message(GENERIC_DIALOG(td->fd), NULL, title, NULL); | |
932 | |
933 path = gtk_entry_get_text(GTK_ENTRY(td->entry)); | |
934 if (strlen(path) == 0) path = NULL; | |
935 if (td->fd_folders_only) | |
936 { | |
937 file_dialog_add_path_widgets(td->fd, NULL, path, td->history_key, NULL, NULL); | |
938 } | |
939 else | |
940 { | |
941 file_dialog_add_path_widgets(td->fd, NULL, path, td->history_key, "*", _("All files")); | |
942 } | |
943 | |
944 gtk_widget_show(GENERIC_DIALOG(td->fd)->dialog); | |
945 } | |
946 | |
947 static void tab_completion_select_pressed(GtkWidget *widget, gpointer data) | |
948 { | |
949 TabCompData *td = data; | |
950 | |
951 tab_completion_select_show(td); | |
952 } | |
953 | |
1448 | 954 void tab_completion_add_select_button(GtkWidget *entry, const gchar *title, gboolean folders_only) |
9 | 955 { |
956 TabCompData *td; | |
957 GtkWidget *parent; | |
958 GtkWidget *hbox; | |
959 | |
960 td = g_object_get_data(G_OBJECT(entry), "tab_completion_data"); | |
961 | |
962 if (!td) return; | |
963 | |
964 g_free(td->fd_title); | |
965 td->fd_title = g_strdup(title); | |
966 td->fd_folders_only = folders_only; | |
967 | |
968 if (td->fd_button) return; | |
969 | |
970 parent = (td->combo) ? td->combo : td->entry; | |
971 | |
972 hbox = gtk_widget_get_parent(parent); | |
973 if (!GTK_IS_BOX(hbox)) return; | |
974 | |
975 td->fd_button = gtk_button_new_with_label("..."); | |
976 g_signal_connect(G_OBJECT(td->fd_button), "size_allocate", | |
977 G_CALLBACK(tab_completion_button_size_allocate), parent); | |
978 g_signal_connect(G_OBJECT(td->fd_button), "clicked", | |
979 G_CALLBACK(tab_completion_select_pressed), td); | |
980 | |
981 gtk_box_pack_start(GTK_BOX(hbox), td->fd_button, FALSE, FALSE, 0); | |
982 | |
983 gtk_widget_show(td->fd_button); | |
984 } | |
1055
1646720364cf
Adding a vim modeline to all files - patch by Klaus Ethgen
nadvornik
parents:
1043
diff
changeset
|
985 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */ |