void update_created_files( gpointer key, gpointer data, gpointer user_data ) { VFSDir* dir = (VFSDir*)data; GSList* l; char* full_path; VFSFileInfo* file; GList* ll; if ( dir->created_files ) { g_mutex_lock( dir->mutex ); for ( l = dir->created_files; l; l = l->next ) { if ( !( ll = vfs_dir_find_file( dir, (char*)l->data, NULL ) ) ) { // file is not in dir file_list full_path = g_build_filename( dir->path, (char*)l->data, NULL ); file = vfs_file_info_new(); if ( vfs_file_info_get( file, full_path, NULL ) ) { // add new file to dir file_list vfs_file_info_load_special_info( file, full_path ); dir->file_list = g_list_prepend( dir->file_list, vfs_file_info_ref( file ) ); ++dir->n_files; g_signal_emit( dir, signals[ FILE_CREATED_SIGNAL ], 0, file ); } // else file doesn't exist in filesystem vfs_file_info_unref( file ); g_free( full_path ); } else { // file already exists in dir file_list file = vfs_file_info_ref( (VFSFileInfo*)ll->data ); if ( update_file_info( dir, file ) ) { g_signal_emit( dir, signals[ FILE_CHANGED_SIGNAL ], 0, file ); vfs_file_info_unref( file ); } // else was deleted, signaled, and unrefed in update_file_info } g_free( (char*)l->data ); // free file_name string } g_slist_free( dir->created_files ); dir->created_files = NULL; g_mutex_unlock( dir->mutex ); } }
void ptk_file_list_set_dir( PtkFileList* list, VFSDir* dir ) { GList* l; if( list->dir == dir ) return; if ( list->dir ) { if( list->max_thumbnail > 0 ) { /* cancel all possible pending requests */ vfs_thumbnail_loader_cancel_all_requests( list->dir, list->big_thumbnail ); } g_list_foreach( list->files, (GFunc)vfs_file_info_unref, NULL ); g_list_free( list->files ); g_signal_handlers_disconnect_by_func( list->dir, _ptk_file_list_file_created, list ); g_signal_handlers_disconnect_by_func( list->dir, ptk_file_list_file_deleted, list ); g_signal_handlers_disconnect_by_func( list->dir, _ptk_file_list_file_changed, list ); g_signal_handlers_disconnect_by_func( list->dir, on_thumbnail_loaded, list ); g_object_unref( list->dir ); } list->dir = dir; list->files = NULL; list->n_files = 0; if( ! dir ) return; g_object_ref( list->dir ); g_signal_connect( list->dir, "file-created", G_CALLBACK(_ptk_file_list_file_created), list ); g_signal_connect( list->dir, "file-deleted", G_CALLBACK(ptk_file_list_file_deleted), list ); g_signal_connect( list->dir, "file-changed", G_CALLBACK(_ptk_file_list_file_changed), list ); if( dir && dir->file_list ) { for( l = dir->file_list; l; l = l->next ) { if( list->show_hidden || ((VFSFileInfo*)l->data)->disp_name[0] != '.' ) { list->files = g_list_prepend( list->files, vfs_file_info_ref( (VFSFileInfo*)l->data) ); ++list->n_files; } } } }
void vfs_dir_emit_file_changed( VFSDir* dir, const char* file_name, VFSFileInfo* file, gboolean force ) { GList* l; //printf("vfs_dir_emit_file_changed dir=%s file_name=%s avoid=%s\n", dir->path, file_name, dir->avoid_changes ? "TRUE" : "FALSE" ); if ( !force && dir->avoid_changes ) return; if ( G_UNLIKELY( 0 == strcmp(file_name, dir->path) ) ) { // Special Case: The directory itself was changed g_signal_emit( dir, signals[ FILE_CHANGED_SIGNAL ], 0, NULL ); return; } g_mutex_lock( dir->mutex ); l = vfs_dir_find_file( dir, file_name, file ); if ( G_LIKELY( l ) ) { file = vfs_file_info_ref( ( VFSFileInfo* ) l->data ); if( !g_slist_find( dir->changed_files, file ) ) { if ( force ) { dir->changed_files = g_slist_prepend( dir->changed_files, file ); if ( 0 == change_notify_timeout ) { change_notify_timeout = g_timeout_add_full( G_PRIORITY_LOW, 100, notify_file_change, NULL, NULL ); } } else if( G_LIKELY( update_file_info( dir, file ) ) ) // update file info the first time { dir->changed_files = g_slist_prepend( dir->changed_files, file ); if ( 0 == change_notify_timeout ) { change_notify_timeout = g_timeout_add_full( G_PRIORITY_LOW, 500, notify_file_change, NULL, NULL ); } g_signal_emit( dir, signals[ FILE_CHANGED_SIGNAL ], 0, file ); } } else vfs_file_info_unref( file ); } g_mutex_unlock( dir->mutex ); }
void vfs_thumbnail_loader_request( VFSDir* dir, VFSFileInfo* file, gboolean is_big ) { VFSThumbnailLoader* loader; ThumbnailRequest* req; gboolean new_task = FALSE; GList* l; /* g_debug( "request thumbnail: %s, is_big: %d", file->name, is_big ); */ if( G_UNLIKELY( ! dir->thumbnail_loader ) ) { dir->thumbnail_loader = vfs_thumbnail_loader_new( dir ); new_task = TRUE; } loader = dir->thumbnail_loader; if( G_UNLIKELY( ! loader->task ) ) { loader->task = vfs_async_task_new( (VFSAsyncFunc)thumbnail_loader_thread, loader ); new_task = TRUE; } vfs_async_task_lock( loader->task ); /* Check if the request is already scheduled */ for( l = loader->queue->head; l; l = l->next ) { req = (ThumbnailRequest*)l->data; /* If file with the same name is already in our queue */ if( req->file == file || 0 == strcmp( req->file->name, file->name ) ) break; } if( l ) { req = (ThumbnailRequest*)l->data; } else { req = g_slice_new0( ThumbnailRequest ); req->file = vfs_file_info_ref(file); g_queue_push_tail( dir->thumbnail_loader->queue, req ); } ++req->n_requests[ is_big ? LOAD_BIG_THUMBNAIL : LOAD_SMALL_THUMBNAIL ]; vfs_async_task_unlock( loader->task ); if( new_task ) vfs_async_task_execute( loader->task ); }
gboolean on_dir_tree_view_button_press( GtkWidget* view, GdkEventButton* evt, PtkFileBrowser* browser ) { if ( evt->type == GDK_BUTTON_PRESS && evt->button == 3 ) { GtkTreeModel * model; GtkTreePath* tree_path; GtkTreeIter it; model = gtk_tree_view_get_model( GTK_TREE_VIEW( view ) ); if ( gtk_tree_view_get_path_at_pos( GTK_TREE_VIEW( view ), evt->x, evt->y, &tree_path, NULL, NULL, NULL ) ) { if ( gtk_tree_model_get_iter( model, &it, tree_path ) ) { VFSFileInfo * file; gtk_tree_model_get( model, &it, COL_DIR_TREE_INFO, &file, -1 ); if ( file ) { GtkWidget * popup; char* file_path; GList* sel_files; char* dir_name; file_path = ptk_dir_view_get_dir_path( model, &it ); sel_files = g_list_prepend( NULL, vfs_file_info_ref(file) ); dir_name = g_path_get_dirname( file_path ); popup = ptk_file_menu_new( file_path, file, dir_name, sel_files, browser ); g_free( dir_name ); g_free( file_path ); gtk_menu_popup( GTK_MENU( popup ), NULL, NULL, NULL, NULL, 3, evt->time ); vfs_file_info_unref( file ); } } gtk_tree_path_free( tree_path ); } } return FALSE; }
void ptk_file_list_file_created( VFSDir* dir, VFSFileInfo* file, PtkFileList* list ) { GList* l; GtkTreeIter it; GtkTreePath* path; VFSFileInfo* file2; if( ! list->show_hidden && vfs_file_info_get_name(file)[0] == '.' ) return; for( l = list->files; l; l = l->next ) { file2 = (VFSFileInfo*)l->data; if( G_UNLIKELY( file == file2 || ptk_file_list_compare( file2, file, list ) == 0 ) ) { /* The file is already in the list */ return; } if( ptk_file_list_compare( file2, file, list ) > 0 ) { break; } } list->files = g_list_insert_before( list->files, l, vfs_file_info_ref( file ) ); ++list->n_files; if( l ) l = l->prev; else l = g_list_last( list->files ); it.stamp = list->stamp; it.user_data = l; it.user_data2 = file; path = gtk_tree_path_new_from_indices( g_list_index(list->files, l->data), -1 ); gtk_tree_model_row_inserted( GTK_TREE_MODEL(list), path, &it ); gtk_tree_path_free( path ); }
void vfs_dir_emit_thumbnail_loaded( VFSDir* dir, VFSFileInfo* file ) { GList* l; g_mutex_lock( dir->mutex ); l = vfs_dir_find_file( dir, file->name, file ); if( l ) { g_assert( file == (VFSFileInfo*)l->data ); file = vfs_file_info_ref( (VFSFileInfo*)l->data ); } else file = NULL; g_mutex_unlock( dir->mutex ); if ( G_LIKELY( file ) ) { g_signal_emit( dir, signals[ THUMBNAIL_LOADED_SIGNAL ], 0, file ); vfs_file_info_unref( file ); } }
void vfs_dir_emit_file_deleted( VFSDir* dir, const char* file_name, VFSFileInfo* file ) { GList* l; VFSFileInfo* file_found; if( G_UNLIKELY( 0 == strcmp(file_name, dir->path) ) ) { /* Special Case: The directory itself was deleted... */ file = NULL; /* clear the whole list */ g_mutex_lock( dir->mutex ); g_list_foreach( dir->file_list, (GFunc)vfs_file_info_unref, NULL ); g_list_free( dir->file_list ); dir->file_list = NULL; g_mutex_unlock( dir->mutex ); g_signal_emit( dir, signals[ FILE_DELETED_SIGNAL ], 0, file ); return; } l = vfs_dir_find_file( dir, file_name, file ); if ( G_LIKELY( l ) ) { file_found = vfs_file_info_ref( ( VFSFileInfo* ) l->data ); if( !g_slist_find( dir->changed_files, file_found ) ) { dir->changed_files = g_slist_prepend( dir->changed_files, file_found ); if ( 0 == change_notify_timeout ) { change_notify_timeout = g_timeout_add_full( G_PRIORITY_LOW, 200, notify_file_change, NULL, NULL ); } } else vfs_file_info_unref( file_found ); } }
void update_changed_files( gpointer key, gpointer data, gpointer user_data ) { VFSDir* dir = (VFSDir*)data; GSList* l; VFSFileInfo* file; if ( dir->changed_files ) { g_mutex_lock( dir->mutex ); for ( l = dir->changed_files; l; l = l->next ) { file = vfs_file_info_ref( ( VFSFileInfo* ) l->data ); /// if ( update_file_info( dir, file ) ) { g_signal_emit( dir, signals[ FILE_CHANGED_SIGNAL ], 0, file ); vfs_file_info_unref( file ); } // else was deleted, signaled, and unrefed in update_file_info } g_slist_free( dir->changed_files ); dir->changed_files = NULL; g_mutex_unlock( dir->mutex ); } }
gpointer thumbnail_loader_thread( VFSAsyncTask* task, VFSThumbnailLoader* loader ) { ThumbnailRequest* req; int i; gboolean load_big, need_update; while( G_LIKELY( ! vfs_async_task_is_cancelled(task) )) { vfs_async_task_lock( task ); req = (ThumbnailRequest*)g_queue_pop_head( loader->queue ); vfs_async_task_unlock( task ); if( G_UNLIKELY( ! req ) ) break; /* g_debug("pop: %s", req->file->name); */ /* Only we have the reference. That means, no body is using the file */ if( req->file->n_ref == 1 ) { thumbnail_request_free( req ); continue; } need_update = FALSE; for ( i = 0; i < 2; ++i ) { if ( 0 == req->n_requests[ i ] ) continue; load_big = ( i == LOAD_BIG_THUMBNAIL ); if ( ! vfs_file_info_is_thumbnail_loaded( req->file, load_big ) ) { char* full_path; full_path = g_build_filename( loader->dir->path, vfs_file_info_get_name( req->file ), NULL ); vfs_file_info_load_thumbnail( req->file, full_path, load_big ); g_free( full_path ); /* Slow down for displaying. */ g_usleep(G_USEC_PER_SEC/1000); /* g_debug( "thumbnail loaded: %s", req->file ); */ } need_update = TRUE; } if( ! vfs_async_task_is_cancelled(task) && need_update ) { vfs_async_task_lock( task ); g_queue_push_tail( loader->update_queue, vfs_file_info_ref(req->file) ); if( 0 == loader->idle_handler) loader->idle_handler = g_idle_add_full( G_PRIORITY_LOW, (GSourceFunc) on_thumbnail_idle, loader, NULL ); vfs_async_task_unlock( task ); } /* g_debug( "NEED_UPDATE: %d", need_update ); */ thumbnail_request_free( req ); } if( vfs_async_task_is_cancelled(task) ) { /* g_debug( "THREAD CANCELLED!!!" ); */ vfs_async_task_lock( task ); if( loader->idle_handler) { g_source_remove( loader->idle_handler ); loader->idle_handler = 0; } vfs_async_task_unlock( task ); } else { if( 0 == loader->idle_handler) { /* g_debug( "ADD IDLE HANDLER BEFORE THREAD ENDING" ); */ loader->idle_handler = g_idle_add_full( G_PRIORITY_LOW, (GSourceFunc) on_thumbnail_idle, loader, NULL ); } } /* g_debug("THREAD ENDED!"); */ return NULL; }
static void on_open_files( GtkAction* action, FindFile* data ) { GtkTreeModel* model; GtkTreeSelection* sel; GtkTreeIter it; GList *row, *rows, *sel_files; GHashTable* hash; GtkWidget* w; VFSFileInfo* fi; gboolean open_files_has_dir = FALSE; //sfm PtkFileBrowser* file_browser = NULL; //sfm gboolean open_files = TRUE; if ( action ) open_files = (0 == strcmp( gtk_action_get_name(action), "OpenAction") ); sel = gtk_tree_view_get_selection( GTK_TREE_VIEW( data->result_view ) ); rows = gtk_tree_selection_get_selected_rows( sel, &model ); if( ! rows ) return; //sfm this frees list when new value inserted - caused segfault //hash = g_hash_table_new_full( g_str_hash, g_str_equal, (GDestroyNotify)g_free, open_files ? (GDestroyNotify)vfs_file_info_list_free : NULL ); hash = g_hash_table_new_full( g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL ); for( row = rows; row; row = row->next ) { char* dir; GtkTreePath* tp = (GtkTreePath*)row->data; if( gtk_tree_model_get_iter( model, &it, tp ) ) { if( open_files ) /* open files */ gtk_tree_model_get( model, &it, COL_INFO, &fi, COL_DIR, &dir, -1 ); else /* open containing folders */ gtk_tree_model_get( model, &it, COL_DIR, &dir, -1 ); if( open_files ) { GList *l; l = g_hash_table_lookup( hash, dir ); l = g_list_prepend( l, vfs_file_info_ref(fi) ); g_hash_table_insert( hash, dir, l ); //sfm caused segfault with destroy function if ( vfs_file_info_is_dir( fi ) ) //sfm open_files_has_dir = TRUE; } else { if( g_hash_table_lookup( hash, dir ) ) g_free( dir ); g_hash_table_insert( hash, dir, NULL ); } } gtk_tree_path_free( tp ); } g_list_free( rows ); if( open_files ) { if ( open_files_has_dir ) { w = GTK_WIDGET( fm_main_window_get_last_active() ); if( ! w ) { w = fm_main_window_new(); gtk_window_set_default_size( GTK_WINDOW( w ), app_settings.width, app_settings.height ); } gtk_window_present( (GtkWindow*)w ); file_browser = (PtkFileBrowser*)fm_main_window_get_current_file_browser( (FMMainWindow*)w ); } g_hash_table_foreach_steal( hash, (GHRFunc)open_file, file_browser ); } else { w = GTK_WIDGET( fm_main_window_get_last_active() ); if( ! w ) { w = fm_main_window_new(); gtk_window_set_default_size( GTK_WINDOW( w ), app_settings.width, app_settings.height ); } g_hash_table_foreach( hash, (GHFunc)open_dir, w ); gtk_window_present( (GtkWindow*)w ); } g_hash_table_destroy( hash ); }
void ptk_file_list_file_created( VFSDir* dir, VFSFileInfo* file, PtkFileList* list ) { GList* l, *ll = NULL; GtkTreeIter it; GtkTreePath* path; VFSFileInfo* file2; if( ! list->show_hidden && vfs_file_info_get_name(file)[0] == '.' ) return; gboolean is_desktop = vfs_file_info_is_desktop_entry( file ); //sfm gboolean is_desktop2; for( l = list->files; l; l = l->next ) { file2 = (VFSFileInfo*)l->data; if( G_UNLIKELY( file == file2 ) ) { /* The file is already in the list */ return; } is_desktop2 = vfs_file_info_is_desktop_entry( file2 ); if ( is_desktop || is_desktop2 ) { // at least one is a desktop file, need to compare filenames if ( file->name && file2->name ) { if ( !strcmp( file->name, file2->name ) ) return; } } else if ( ptk_file_list_compare( file2, file, list ) == 0 ) { // disp_name matches ? // ptk_file_list_compare may return 0 on differing display names // if case-insensitive - need to compare filenames if ( list->sort_natural && list->sort_case ) return; else if ( !strcmp( file->name, file2->name ) ) return; } if ( !ll && ptk_file_list_compare( file2, file, list ) > 0 ) { if ( !is_desktop && !is_desktop2 ) break; else ll = l; // store insertion location based on disp_name } } if ( ll ) l = ll; list->files = g_list_insert_before( list->files, l, vfs_file_info_ref( file ) ); ++list->n_files; if( l ) l = l->prev; else l = g_list_last( list->files ); it.stamp = list->stamp; it.user_data = l; it.user_data2 = file; path = gtk_tree_path_new_from_indices( g_list_index(list->files, l->data), -1 ); gtk_tree_model_row_inserted( GTK_TREE_MODEL(list), path, &it ); gtk_tree_path_free( path ); }
void ptk_file_list_get_value ( GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value ) { GList* l; PtkFileList* list = PTK_FILE_LIST(tree_model); VFSFileInfo* info; GdkPixbuf* icon; g_return_if_fail (PTK_IS_FILE_LIST (tree_model)); g_return_if_fail (iter != NULL); g_return_if_fail (column < G_N_ELEMENTS(column_types) ); g_value_init (value, column_types[column] ); l = (GList*) iter->user_data; g_return_if_fail ( l != NULL ); info = (VFSFileInfo*)iter->user_data2; switch(column) { case COL_FILE_BIG_ICON: icon = NULL; /* special file can use special icons saved as thumbnails*/ if( list->max_thumbnail > vfs_file_info_get_size( info ) && info->flags == VFS_FILE_INFO_NONE ) icon = vfs_file_info_get_big_thumbnail( info ); if( ! icon ) icon = vfs_file_info_get_big_icon( info ); if( icon ) { g_value_set_object( value, icon ); g_object_unref( icon ); } break; case COL_FILE_SMALL_ICON: icon = NULL; /* special file can use special icons saved as thumbnails*/ if( list->max_thumbnail > vfs_file_info_get_size( info ) ) icon = vfs_file_info_get_small_thumbnail( info ); if( !icon ) icon = vfs_file_info_get_small_icon( info ); if( icon ) { g_value_set_object( value, icon ); g_object_unref( icon ); } break; case COL_FILE_NAME: g_value_set_string( value, vfs_file_info_get_disp_name(info) ); break; case COL_FILE_SIZE: if ( S_ISDIR( info->mode ) || ( S_ISLNK( info->mode ) && 0 == strcmp( vfs_mime_type_get_type( info->mime_type ), XDG_MIME_TYPE_DIRECTORY ) ) ) g_value_set_string( value, NULL ); else g_value_set_string( value, vfs_file_info_get_disp_size(info) ); break; case COL_FILE_DESC: g_value_set_string( value, vfs_file_info_get_mime_type_desc( info ) ); break; case COL_FILE_PERM: g_value_set_string( value, vfs_file_info_get_disp_perm(info) ); break; case COL_FILE_OWNER: g_value_set_string( value, vfs_file_info_get_disp_owner(info) ); break; case COL_FILE_MTIME: g_value_set_string( value, vfs_file_info_get_disp_mtime(info) ); break; case COL_FILE_INFO: g_value_set_pointer( value, vfs_file_info_ref( info ) ); break; } }
gboolean on_dir_tree_view_key_press( GtkWidget* view, GdkEventKey* evt, PtkFileBrowser* browser ) { VFSFileInfo* file; GtkTreeModel *model; GtkTreeIter iter; GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); if(!gtk_tree_selection_get_selected(select, &model, &iter)) return FALSE; int keymod = ( evt->state & ( GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK | GDK_SUPER_MASK | GDK_HYPER_MASK | GDK_META_MASK ) ); GtkTreePath *path = gtk_tree_model_get_path(model, &iter); switch( evt->keyval ) { case GDK_KEY_Left: if(gtk_tree_view_row_expanded(GTK_TREE_VIEW(view), path)) { gtk_tree_view_collapse_row(GTK_TREE_VIEW(view), path); } else if(gtk_tree_path_up(path)) { gtk_tree_selection_select_path(select, path); gtk_tree_view_set_cursor(GTK_TREE_VIEW(view), path, NULL, FALSE); } else { gtk_tree_path_free( path ); return FALSE; } break; case GDK_KEY_Right: if(!gtk_tree_view_row_expanded(GTK_TREE_VIEW(view), path)) { gtk_tree_view_expand_row(GTK_TREE_VIEW(view), path, FALSE); } else { gtk_tree_path_down(path); gtk_tree_selection_select_path(select, path); gtk_tree_view_set_cursor(GTK_TREE_VIEW(view), path, NULL, FALSE); } break; case GDK_KEY_F10: case GDK_KEY_Menu: if ( evt->keyval == GDK_KEY_F10 && keymod != GDK_SHIFT_MASK ) { gtk_tree_path_free( path ); return FALSE; } gtk_tree_model_get( gtk_tree_view_get_model( GTK_TREE_VIEW( view ) ), &iter, COL_DIR_TREE_INFO, &file, -1 ); if ( file ) { GtkWidget * popup; char* file_path; GList* sel_files; char* dir_name; file_path = ptk_dir_view_get_dir_path( gtk_tree_view_get_model( GTK_TREE_VIEW( view ) ), &iter ); sel_files = g_list_prepend( NULL, vfs_file_info_ref(file) ); dir_name = g_path_get_dirname( file_path ); popup = ptk_file_menu_new( NULL, browser, file_path, file, dir_name, sel_files ); g_free( dir_name ); g_free( file_path ); if ( popup ) gtk_menu_popup( GTK_MENU( popup ), NULL, NULL, NULL, NULL, 3, evt->time ); vfs_file_info_unref( file ); } break; default: gtk_tree_path_free( path ); return FALSE; } gtk_tree_path_free( path ); return TRUE; }
gboolean on_dir_tree_view_button_press( GtkWidget* view, GdkEventButton* evt, PtkFileBrowser* browser ) { GtkTreeModel* model; GtkTreePath* tree_path; GtkTreeViewColumn* tree_col; GtkTreeIter it; if ( evt->type == GDK_BUTTON_PRESS && ( evt->button == 1 || evt->button == 3 ) ) { // middle click 2 handled in ptk-file-browser.c on_dir_tree_button_press model = gtk_tree_view_get_model( GTK_TREE_VIEW( view ) ); if ( gtk_tree_view_get_path_at_pos( GTK_TREE_VIEW( view ), evt->x, evt->y, &tree_path, &tree_col, NULL, NULL ) ) { if ( gtk_tree_model_get_iter( model, &it, tree_path ) ) { gtk_tree_view_set_cursor( GTK_TREE_VIEW( view ), tree_path, tree_col, FALSE ); gtk_tree_view_row_activated( GTK_TREE_VIEW( view ), tree_path, tree_col ); if ( evt->button == 3 ) { // right click VFSFileInfo * file; gtk_tree_model_get( model, &it, COL_DIR_TREE_INFO, &file, -1 ); if ( file ) { GtkWidget * popup; char* file_path; GList* sel_files; char* dir_name; file_path = ptk_dir_view_get_dir_path( model, &it ); sel_files = g_list_prepend( NULL, vfs_file_info_ref(file) ); dir_name = g_path_get_dirname( file_path ); /* FIXME: New|Tab Here and New|File etc work on the * wrong location because dir_name is really incorrect. * But if set to cur dir it breaks Copy, etc. */ popup = ptk_file_menu_new( NULL, browser, file_path, file, dir_name, sel_files ); g_free( dir_name ); g_free( file_path ); if ( popup ) gtk_menu_popup( GTK_MENU( popup ), NULL, NULL, NULL, NULL, 3, evt->time ); vfs_file_info_unref( file ); gtk_tree_path_free( tree_path ); return TRUE; } } } gtk_tree_path_free( tree_path ); } } else if ( evt->type == GDK_2BUTTON_PRESS && evt->button == 1 ) { // double click - expand/collapse if ( gtk_tree_view_get_path_at_pos( GTK_TREE_VIEW( view ), evt->x, evt->y, &tree_path, NULL, NULL, NULL ) ) { if ( gtk_tree_view_row_expanded( GTK_TREE_VIEW( view ), tree_path ) ) gtk_tree_view_collapse_row( GTK_TREE_VIEW( view ), tree_path ); else gtk_tree_view_expand_row( GTK_TREE_VIEW( view ), tree_path, FALSE ); gtk_tree_path_free( tree_path ); return TRUE; } } return FALSE; }