1 /******************************* LICENCE **************************************
2 * Any code in this file may be redistributed or modified under the terms of
3 * the GNU General Public Licence as published by the Free Software
4 * Foundation; version 2 of the licence.
5 ****************************** END LICENCE ***********************************/
6
7 /******************************************************************************
8 * Author:
9 * Andrew Smith, http://littlesvr.ca/misc/contactandrew.php
10 *
11 * Contributors:
12 *
13 ******************************************************************************/
14
15 #include <gtk/gtk.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <dirent.h>
19 #include <sys/stat.h>
20 #include <stdbool.h>
21 #include <errno.h>
22 #include <libintl.h>
23
24 #include "isomaster.h"
25
26 extern AppSettings GBLappSettings;
27 extern char* GBLuserHomeDir;
28
29 extern GtkWidget* GBLmainWindow;
30
31 extern GtkWidget* GBLfsCurrentDirField;
32 extern GtkWidget* GBLfsTreeView;
33 extern GtkListStore* GBLfsListStore;
34 extern char* GBLfsCurrentDir;
35
36 extern GdkPixbuf* GBLdirPixbuf;
37 extern GdkPixbuf* GBLfilePixbuf;
38 //~ extern GdkPixbuf* GBLsymlinkPixbuf;
39
40 extern bool GBLisoChangesProbable;
41
42 extern int errno;
43
44 /* the column for the filename in the fs pane */
45 static GtkTreeViewColumn* GBLfilenameFsColumn;
46
acceptFsPathCbk(GtkEntry * entry,gpointer user_data)47 void acceptFsPathCbk(GtkEntry *entry, gpointer user_data)
48 {
49 const char* newPath;
50 char* newPathTerminated;
51
52 newPath = gtk_entry_get_text(entry);
53
54 if(newPath[strlen(newPath) - 1] == '/')
55 {
56 changeFsDirectory((char*)newPath);
57 }
58 else
59 {
60 newPathTerminated = malloc(strlen(newPath) + 2);
61 if(newPathTerminated == NULL)
62 fatalError("newPathTerminated = malloc(strlen(newPath) + 2) failed");
63
64 strcpy(newPathTerminated, newPath);
65 strcat(newPathTerminated, "/");
66
67 changeFsDirectory(newPathTerminated);
68
69 free(newPathTerminated);
70 }
71 }
72
buildFsBrowser(GtkWidget * boxToPackInto)73 void buildFsBrowser(GtkWidget* boxToPackInto)
74 {
75 GtkWidget* scrolledWindow;
76 GtkTreeSelection *selection;
77 GtkCellRenderer* renderer;
78 GtkTreeViewColumn* column;
79
80 GBLfsListStore = gtk_list_store_new(NUM_COLUMNS,
81 GDK_TYPE_PIXBUF, /* icon */
82 G_TYPE_STRING, /* name */
83 G_TYPE_UINT64, /* size */
84 G_TYPE_UINT /* file type */
85 );
86
87 scrolledWindow = gtk_scrolled_window_new(NULL, NULL);
88 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledWindow),
89 GTK_POLICY_AUTOMATIC,
90 GTK_POLICY_AUTOMATIC);
91 gtk_box_pack_start(GTK_BOX(boxToPackInto), scrolledWindow, TRUE, TRUE, 0);
92 gtk_widget_show(scrolledWindow);
93
94 /* view widget */
95 GBLfsTreeView = gtk_tree_view_new_with_model(GTK_TREE_MODEL(GBLfsListStore));
96 gtk_tree_view_set_search_column(GTK_TREE_VIEW(GBLfsTreeView), COLUMN_FILENAME);
97 g_object_unref(GBLfsListStore); /* destroy model automatically with view */
98 gtk_container_add(GTK_CONTAINER(scrolledWindow), GBLfsTreeView);
99 g_signal_connect(GBLfsTreeView, "row-activated", (GCallback)fsRowDblClickCbk, NULL);
100 g_signal_connect(GBLfsTreeView, "select-cursor-parent", (GCallback)fsGoUpDirTreeCbk, NULL);
101 /* The problem with this is that i get a popup menu before the row is selected.
102 * if i do a connect_after the handler never gets called. So no right-click menu. */
103 g_signal_connect(GBLfsTreeView, "button-press-event", (GCallback)fsButtonPressedCbk, NULL);
104 g_signal_connect(GBLfsTreeView, "button-release-event", (GCallback)fsButtonReleasedCbk, NULL);
105 gtk_widget_show(GBLfsTreeView);
106
107 /* this won't be enabled until gtk allows me to drag a multiple selection */
108 //~ GtkTargetEntry targetEntry;
109 //~ targetEntry.target = "text/plain";
110 //~ targetEntry.flags = 0;
111 //~ targetEntry.info = 0;
112 //~ gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(GBLfsTreeView), GDK_BUTTON1_MASK,
113 //~ &targetEntry, 1, GDK_ACTION_COPY);
114
115 /* enable multi-line selection */
116 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLfsTreeView));
117 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
118
119 /* filename column */
120 GBLfilenameFsColumn = gtk_tree_view_column_new();
121 gtk_tree_view_column_set_title(GBLfilenameFsColumn, _("Name"));
122 gtk_tree_view_column_set_resizable(GBLfilenameFsColumn, TRUE);
123
124 renderer = gtk_cell_renderer_pixbuf_new();
125 gtk_tree_view_column_pack_start(GBLfilenameFsColumn, renderer, FALSE);
126 gtk_tree_view_column_add_attribute(GBLfilenameFsColumn, renderer, "pixbuf", COLUMN_ICON);
127
128 renderer = gtk_cell_renderer_text_new();
129 gtk_tree_view_column_pack_start(GBLfilenameFsColumn, renderer, TRUE);
130 gtk_tree_view_column_add_attribute(GBLfilenameFsColumn, renderer, "text", COLUMN_FILENAME);
131
132 gtk_tree_view_column_set_sort_column_id(GBLfilenameFsColumn, COLUMN_FILENAME);
133 gtk_tree_view_column_set_expand(GBLfilenameFsColumn, TRUE);
134 gtk_tree_view_append_column(GTK_TREE_VIEW(GBLfsTreeView), GBLfilenameFsColumn);
135
136 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(GBLfsListStore), COLUMN_FILENAME,
137 sortByName, NULL, NULL);
138
139 /* size column */
140 column = gtk_tree_view_column_new();
141 renderer = gtk_cell_renderer_text_new();
142 gtk_tree_view_column_set_title(column, _("Size"));
143 gtk_tree_view_column_pack_start(column, renderer, FALSE);
144 gtk_tree_view_column_add_attribute(column, renderer, "text", COLUMN_SIZE);
145 gtk_tree_view_column_set_cell_data_func(column, renderer, sizeCellDataFunc64, NULL, NULL);
146 gtk_tree_view_column_set_sort_column_id(column, COLUMN_SIZE);
147 gtk_tree_view_append_column(GTK_TREE_VIEW(GBLfsTreeView), column);
148
149 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(GBLfsListStore), COLUMN_SIZE,
150 sortBySize, NULL, NULL);
151
152 /* set default sort */
153 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(GBLfsListStore),
154 GBLappSettings.fsSortColumnId,
155 GBLappSettings.fsSortDirection);
156
157 GBLdirPixbuf = NULL;
158 GBLfilePixbuf = NULL;
159
160 #if GTK_MINOR_VERSION >= 6
161 GtkIconSet* iconSet;
162 GtkIconSize* iconSizes = NULL;
163 int numIconSizes;
164 GtkIconSize iconSize;
165
166 /* CREATE pixbuf for directory */
167 iconSet = gtk_icon_factory_lookup_default(GTK_STOCK_DIRECTORY);
168 if(iconSet != NULL)
169 {
170 gtk_icon_set_get_sizes(iconSet, &iconSizes, &numIconSizes);
171 iconSize = iconSizes[0];
172 g_free(iconSizes);
173 //!! figure out proper size and resisze if necessary, see gtk-demo->stock->create_model()
174 GBLdirPixbuf = gtk_widget_render_icon(GBLfsTreeView, GTK_STOCK_DIRECTORY, iconSize, NULL);
175 }
176 /* END CREATE pixbuf for directory */
177
178 /* CREATE pixbuf for file */
179 iconSet = gtk_icon_factory_lookup_default(GTK_STOCK_FILE);
180 if(iconSet != NULL)
181 {
182 gtk_icon_set_get_sizes(iconSet, &iconSizes, &numIconSizes);
183 iconSize = iconSizes[0];
184 g_free(iconSizes);
185 //!! figure out proper size and resisze if necessary, see gtk-demo->stock->create_model()
186 GBLfilePixbuf = gtk_widget_render_icon(GBLfsTreeView, GTK_STOCK_FILE, iconSize, NULL);
187 }
188 /* END CREATE pixbuf for file */
189 #endif
190
191 if(GBLappSettings.fsCurrentDir != NULL)
192 {
193 bool rc;
194
195 rc = changeFsDirectory(GBLappSettings.fsCurrentDir);
196 if(rc == false)
197 /* GBLuserHomeDir has just been set and tested a moment ago in findHomeDir() */
198 changeFsDirectory(GBLuserHomeDir);
199 }
200 else
201 changeFsDirectory(GBLuserHomeDir);
202 }
203
buildFsLocator(GtkWidget * boxToPackInto)204 void buildFsLocator(GtkWidget* boxToPackInto)
205 {
206 GBLfsCurrentDirField = gtk_entry_new();
207 g_signal_connect(GBLfsCurrentDirField, "activate", (GCallback)acceptFsPathCbk, NULL);
208 gtk_box_pack_start(GTK_BOX(boxToPackInto), GBLfsCurrentDirField, FALSE, FALSE, 0);
209 gtk_widget_show(GBLfsCurrentDirField);
210 }
211
changeFsDirectory(const char * newDirStr)212 bool changeFsDirectory(const char* newDirStr)
213 {
214 DIR* newDir;
215 struct dirent* nextItem; /* for contents of the directory */
216 char* nextItemPathAndName; /* for use with stat() */
217 GtkTreeIter listIterator;
218 int rc;
219 GtkTreeModel* model;
220 GtkWidget* warningDialog;
221
222 newDir = opendir(newDirStr);
223 if(newDir == NULL)
224 {
225 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
226 GTK_DIALOG_DESTROY_WITH_PARENT,
227 GTK_MESSAGE_ERROR,
228 GTK_BUTTONS_CLOSE,
229 _("Failed to open directory '%s', error %d"),
230 newDirStr,
231 errno);
232 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
233 gtk_dialog_run(GTK_DIALOG(warningDialog));
234 gtk_widget_destroy(warningDialog);
235
236 return false;
237 }
238
239 /* for improved performance disconnect the model from tree view before udating it */
240 model = gtk_tree_view_get_model(GTK_TREE_VIEW(GBLfsTreeView));
241 g_object_ref(model);
242 gtk_tree_view_set_model(GTK_TREE_VIEW(GBLfsTreeView), NULL);
243
244 /* this is the only way to disable sorting (for a huge performance boost) */
245 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(GBLfsListStore), COLUMN_FILENAME,
246 sortVoid, NULL, NULL);
247 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(GBLfsListStore), COLUMN_SIZE,
248 sortVoid, NULL, NULL);
249
250 gtk_list_store_clear(GBLfsListStore);
251
252 #if GTK_MINOR_VERSION >= 8
253 /* to make sure width of filename column isn't bigger than needed (need gtk 2.8) */
254 gtk_tree_view_column_queue_resize(GBLfilenameFsColumn);
255 #endif
256
257 nextItemPathAndName = (char*)malloc(strlen(newDirStr) + 257);
258 if(nextItemPathAndName == NULL)
259 fatalError("changeFsDirectory(): malloc(strlen(newDirStr) + 257) failed");
260
261 /* it may be possible but in any case very unlikely that readdir() will fail
262 * if it does, it returns NULL (same as end of dir) */
263 while( (nextItem = readdir(newDir)) != NULL )
264 {
265 /* skip current and parent directory */
266 if(strcmp(nextItem->d_name, ".") == 0 || strcmp(nextItem->d_name, "..") == 0)
267 continue;
268
269 if(nextItem->d_name[0] == '.' && !GBLappSettings.showHiddenFilesFs)
270 /* skip hidden files/dirs */
271 continue;
272
273 /* mind 256 is assumed in the malloc below */
274 if(strlen(nextItem->d_name) > 256)
275 {
276 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
277 GTK_DIALOG_DESTROY_WITH_PARENT,
278 GTK_MESSAGE_ERROR,
279 GTK_BUTTONS_CLOSE,
280 _("Skipping directory entry because "
281 "cannot handle filename longer than 256 chars"));
282 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
283 gtk_dialog_run(GTK_DIALOG(warningDialog));
284 gtk_widget_destroy(warningDialog);
285 continue;
286 }
287
288 strcpy(nextItemPathAndName, newDirStr);
289 strcat(nextItemPathAndName, nextItem->d_name);
290
291 struct stat nextItemInfo;
292 rc = lstat(nextItemPathAndName, &nextItemInfo);
293 if(rc == -1)
294 {
295 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
296 GTK_DIALOG_DESTROY_WITH_PARENT,
297 GTK_MESSAGE_ERROR,
298 GTK_BUTTONS_CLOSE,
299 _("Skipping directory entry because "
300 "stat(%s) failed with %d"),
301 nextItemPathAndName,
302 errno);
303 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
304 gtk_dialog_run(GTK_DIALOG(warningDialog));
305 gtk_widget_destroy(warningDialog);
306 continue;
307 }
308
309 if(IS_DIR(nextItemInfo.st_mode))
310 /* directory */
311 {
312 gtk_list_store_append(GBLfsListStore, &listIterator);
313 gtk_list_store_set(GBLfsListStore, &listIterator,
314 COLUMN_ICON, GBLdirPixbuf,
315 COLUMN_FILENAME, nextItem->d_name,
316 //COLUMN_FILENAME, g_filename_to_utf8(nextItem->d_name, -1, 0, 0, 0),
317 //COLUMN_FILENAME, g_locale_to_utf8(nextItem->d_name, -1, 0, 0, 0),
318 COLUMN_SIZE, 0LL,
319 COLUMN_HIDDEN_TYPE, FILE_TYPE_DIRECTORY,
320 -1);
321 }
322 else if(IS_REG_FILE(nextItemInfo.st_mode))
323 /* regular file */
324 {
325 gtk_list_store_append(GBLfsListStore, &listIterator);
326 gtk_list_store_set(GBLfsListStore, &listIterator,
327 COLUMN_ICON, GBLfilePixbuf,
328 COLUMN_FILENAME, nextItem->d_name,
329 //COLUMN_FILENAME, g_filename_to_utf8(nextItem->d_name, -1, 0, 0, 0),
330 //COLUMN_FILENAME, g_locale_to_utf8(nextItem->d_name, -1, 0, 0, 0),
331 COLUMN_SIZE, nextItemInfo.st_size,
332 COLUMN_HIDDEN_TYPE, FILE_TYPE_REGULAR,
333 -1);
334 }
335 else if(IS_SYMLINK(nextItemInfo.st_mode))
336 /* symbolic link */
337 {
338 gtk_list_store_append(GBLfsListStore, &listIterator);
339 gtk_list_store_set(GBLfsListStore, &listIterator,
340 COLUMN_ICON, GBLfilePixbuf,
341 COLUMN_FILENAME, nextItem->d_name,
342 COLUMN_SIZE, 0LL,
343 COLUMN_HIDDEN_TYPE, FILE_TYPE_SYMLINK,
344 -1);
345 }
346 /* else fancy file, ignore it */
347
348 } /* while (dir contents) */
349
350 free(nextItemPathAndName);
351
352 closedir(newDir);
353
354 /* reconnect the model and view now */
355 gtk_tree_view_set_model(GTK_TREE_VIEW(GBLfsTreeView), model);
356 g_object_unref(model);
357
358 /* reenable sorting */
359 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(GBLfsListStore), COLUMN_FILENAME,
360 sortByName, NULL, NULL);
361 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(GBLfsListStore), COLUMN_SIZE,
362 sortBySize, NULL, NULL);
363
364 /* set current directory string */
365 if(GBLfsCurrentDir != NULL)
366 free(GBLfsCurrentDir);
367 GBLfsCurrentDir = (char*)malloc(strlen(newDirStr) + 1);
368 if(GBLfsCurrentDir == NULL)
369 fatalError("changeFsDirectory(): malloc(strlen(newDirStr) + 1) failed");
370 strcpy(GBLfsCurrentDir, newDirStr);
371
372 /* update the location field with the path and name */
373 gtk_entry_set_text(GTK_ENTRY(GBLfsCurrentDirField), GBLfsCurrentDir);
374
375 return true;
376 }
377
378 /******************************************************************************
379 * fsButtonPressedCbk()
380 * Make sure that a right-click on the view doesn't send the signal to the
381 * widget. If it did, a selection of multiple rows would be lost.
382 * I have a feeling someone did this shit in GTK just to piss on users */
fsButtonPressedCbk(GtkWidget * fsView,GdkEventButton * event,gpointer user_data)383 gboolean fsButtonPressedCbk(GtkWidget* fsView, GdkEventButton* event, gpointer user_data)
384 {
385 if(event->type == GDK_BUTTON_PRESS && event->button == 3)
386 {
387 /* Stop event propagation */
388 /*!! Would be nice if I could only stop event propagation if click was on
389 * the selection, I have to look into how that may be done, if at all */
390 return TRUE;
391 }
392
393 return FALSE;
394 }
395
396 /******************************************************************************
397 * fsButtonReleasedCbk()
398 * Show context menu if releasing the right mouse button */
fsButtonReleasedCbk(GtkWidget * fsView,GdkEventButton * event,gpointer user_data)399 gboolean fsButtonReleasedCbk(GtkWidget* fsView, GdkEventButton* event, gpointer user_data)
400 {
401 if(event->type == GDK_BUTTON_RELEASE && event->button == 3)
402 {
403 showFsContextMenu(fsView, event);
404 }
405
406 return FALSE;
407 }
408
409 /* this is called from a button and via a treeview event so don't use the parameters */
fsGoUpDirTreeCbk(GtkButton * button,gpointer data)410 void fsGoUpDirTreeCbk(GtkButton *button, gpointer data)
411 {
412 int count;
413 bool done;
414 char* newCurrentDir;
415
416 /* do nothing if already at root */
417 if(GBLfsCurrentDir[0] == '/' && GBLfsCurrentDir[1] == '\0')
418 return;
419
420 /* need to allocate a new string because changeFsDirectory() uses it
421 * to copy from after freeing GBLfsCurrentDir */
422 newCurrentDir = (char*)malloc(strlen(GBLfsCurrentDir) + 1);
423 if(newCurrentDir == NULL)
424 fatalError("fsGoUpDirTree(): malloc(strlen(GBLfsCurrentDir) + 1) failed");
425 strcpy(newCurrentDir, GBLfsCurrentDir);
426
427 /* look for the second last slash */
428 done = false;
429 for(count = strlen(newCurrentDir) - 1; !done; count--)
430 {
431 if(newCurrentDir[count - 1] == '/')
432 /* truncate the string */
433 {
434 newCurrentDir[count] = '\0';
435 changeFsDirectory(newCurrentDir);
436 done = true;
437 }
438 }
439
440 free(newCurrentDir);
441 }
442
fsRowDblClickCbk(GtkTreeView * treeview,GtkTreePath * path,GtkTreeViewColumn * col,gpointer data)443 void fsRowDblClickCbk(GtkTreeView* treeview, GtkTreePath* path,
444 GtkTreeViewColumn* col, gpointer data)
445 {
446 GtkTreeModel* model;
447 GtkTreeIter iterator;
448 char* name;
449 char* selectedPathAndName;
450 int fileType;
451 GtkWidget* warningDialog;
452
453 model = gtk_tree_view_get_model(treeview);
454
455 if(gtk_tree_model_get_iter(model, &iterator, path) == FALSE)
456 {
457 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
458 GTK_DIALOG_DESTROY_WITH_PARENT,
459 GTK_MESSAGE_ERROR,
460 GTK_BUTTONS_CLOSE,
461 "GUI Error: 'fsRowDblClicked(): "
462 "gtk_tree_model_get_iter() failed'");
463 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
464 gtk_dialog_run(GTK_DIALOG(warningDialog));
465 gtk_widget_destroy(warningDialog);
466 return;
467 }
468
469 gtk_tree_model_get(model, &iterator, COLUMN_FILENAME, &name, -1);
470
471 /* 2 in case i need to append a '/' */
472 selectedPathAndName = (char*)malloc(strlen(GBLfsCurrentDir) + strlen(name) + 2);
473 if(selectedPathAndName == NULL)
474 fatalError("fsRowDblClicked(): malloc(strlen(GBLfsCurrentDir) + strlen(name) + 2) failed");
475
476 strcpy(selectedPathAndName, GBLfsCurrentDir);
477 strcat(selectedPathAndName, name);
478
479 gtk_tree_model_get(model, &iterator, COLUMN_HIDDEN_TYPE, &fileType, -1);
480 if(fileType == FILE_TYPE_DIRECTORY)
481 /* change directory */
482 {
483 strcat(selectedPathAndName, "/");
484 changeFsDirectory(selectedPathAndName);
485 }
486 else if(fileType == FILE_TYPE_SYMLINK)
487 /* if it's a symlink to a dir, change directory */
488 {
489 struct stat statStruct;
490 int rc;
491
492 rc = stat(selectedPathAndName, &statStruct);
493 if( rc == 0 && (statStruct.st_mode & S_IFDIR) )
494 {
495 strcat(selectedPathAndName, "/");
496 changeFsDirectory(selectedPathAndName);
497 }
498 }
499 else if(fileType == FILE_TYPE_REGULAR)
500 /* if it's an image, open it */
501 {
502 int strLen = strlen(name);
503
504 if( (name[strLen - 4] == '.' &&
505 (name[strLen - 3] == 'i' || name[strLen - 3] == 'I') &&
506 (name[strLen - 2] == 's' || name[strLen - 2] == 'S') &&
507 (name[strLen - 1] == 'o' || name[strLen - 1] == 'O'))
508 ||
509 (name[strLen - 4] == '.' &&
510 (name[strLen - 3] == 'n' || name[strLen - 3] == 'N') &&
511 (name[strLen - 2] == 'r' || name[strLen - 2] == 'R') &&
512 (name[strLen - 1] == 'g' || name[strLen - 1] == 'G'))
513 ||
514 (name[strLen - 4] == '.' &&
515 (name[strLen - 3] == 'm' || name[strLen - 3] == 'M') &&
516 (name[strLen - 2] == 'd' || name[strLen - 2] == 'D') &&
517 (name[strLen - 1] == 'f' || name[strLen - 1] == 'F')) )
518 {
519 if( !GBLisoChangesProbable || confirmCloseIso() )
520 {
521 openIso(selectedPathAndName);
522 }
523 }
524 }
525
526
527 free(selectedPathAndName);
528 g_free(name);
529 }
530
refreshFsView(void)531 void refreshFsView(void)
532 {
533 char* fsCurrentDir; /* for changeFsDirectory() */
534
535 fsCurrentDir = malloc(strlen(GBLfsCurrentDir) + 1);
536 if(fsCurrentDir == NULL)
537 fatalError("refreshFsView(): malloc(strlen(GBLfsCurrentDir) + 1) failed");
538 strcpy(fsCurrentDir, GBLfsCurrentDir);
539
540 /* remember scroll position */
541 GdkRectangle visibleRect;
542 gtk_tree_view_get_visible_rect(GTK_TREE_VIEW(GBLfsTreeView), &visibleRect);
543
544 changeFsDirectory(fsCurrentDir);
545
546 /* need the -1 because if i call this function with the same coordinates that
547 * the view already has, the position is set to 0. think it's a gtk bug. */
548 gtk_tree_view_scroll_to_point(GTK_TREE_VIEW(GBLfsTreeView), visibleRect.x - 1, visibleRect.y - 1);
549
550 free(fsCurrentDir);
551 }
552
showFsContextMenu(GtkWidget * fsView,GdkEventButton * event)553 void showFsContextMenu(GtkWidget* fsView, GdkEventButton* event)
554 {
555 GtkWidget* menu;
556 GtkWidget* menuItem;
557 GtkTreeSelection* selection;
558 gint numSelectedRows;
559 GtkAccelGroup* accelGroup;
560
561 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLfsTreeView));
562
563 numSelectedRows = gtk_tree_selection_count_selected_rows(selection);
564 if(numSelectedRows == 0)
565 return;
566
567 /* have this here just so that the shortcut keys show in the context menu */
568 accelGroup = gtk_accel_group_new();
569 gtk_window_add_accel_group(GTK_WINDOW(GBLmainWindow), accelGroup);
570
571 menu = gtk_menu_new();
572 gtk_menu_set_accel_group(GTK_MENU(menu), accelGroup);
573 /*
574 menuItem = gtk_image_menu_item_new_with_label(_("Rename"));
575 g_signal_connect(menuItem, "activate",
576 (GCallback)renameSelectedBtnCbk, NULL);
577 gtk_menu_item_set_accel_path(GTK_MENU_ITEM(menuItem), "<ISOMaster>/Contextmenu/Rename");
578 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuItem);
579 gtk_widget_show_all(menu);
580 if(numSelectedRows > 1)
581 gtk_widget_set_sensitive(menuItem, FALSE);
582 */
583 menuItem = gtk_image_menu_item_new_with_label(_("View"));
584 g_signal_connect(menuItem, "activate",
585 (GCallback)viewSelectedBtnCbk, NULL);
586 gtk_menu_item_set_accel_path(GTK_MENU_ITEM(menuItem), "<ISOMaster>/Contextmenu/View");
587 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuItem);
588 gtk_widget_show_all(menu);
589
590 menuItem = gtk_image_menu_item_new_with_label(_("Edit"));
591 g_signal_connect(menuItem, "activate",
592 (GCallback)editSelectedBtnCbk, NULL);
593 gtk_menu_item_set_accel_path(GTK_MENU_ITEM(menuItem), "<ISOMaster>/Contextmenu/Edit");
594 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuItem);
595 gtk_widget_show_all(menu);
596 /*
597 menuItem = gtk_image_menu_item_new_with_label(_("Change permissions"));
598 g_signal_connect(menuItem, "activate",
599 (GCallback)changePermissionsBtnCbk, NULL);
600 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuItem);
601 gtk_widget_show_all(menu);
602 if(numSelectedRows > 1)
603 gtk_widget_set_sensitive(menuItem, FALSE);
604 */
605 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
606 event->button, gdk_event_get_time((GdkEvent*)event));
607 }
608
showHiddenCbk(GtkButton * button,gpointer data)609 void showHiddenCbk(GtkButton *button, gpointer data)
610 {
611 GBLappSettings.showHiddenFilesFs = !GBLappSettings.showHiddenFilesFs;
612
613 /* refresh fs view */
614 refreshFsView();
615 }
616