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