gboolean on_thumbnail_idle( VFSThumbnailLoader* loader ) { VFSFileInfo* file; /* g_debug( "ENTER ON_THUMBNAIL_IDLE" ); */ vfs_async_task_lock( loader->task ); while( ( file = (VFSFileInfo*)g_queue_pop_head(loader->update_queue) ) ) { GDK_THREADS_ENTER(); vfs_dir_emit_thumbnail_loaded( loader->dir, file ); vfs_file_info_unref( file ); GDK_THREADS_LEAVE(); } loader->idle_handler = 0; vfs_async_task_unlock( loader->task ); if( vfs_async_task_is_finished( loader->task ) ) { /* g_debug( "FREE LOADER IN IDLE HANDLER" ); */ loader->dir->thumbnail_loader = NULL; vfs_thumbnail_loader_free(loader); } /* g_debug( "LEAVE ON_THUMBNAIL_IDLE" ); */ return FALSE; }
void vfs_thumbnail_loader_cancel_all_requests( VFSDir* dir, gboolean is_big ) { GList* l; VFSThumbnailLoader* loader; ThumbnailRequest* req; if( G_UNLIKELY( (loader=dir->thumbnail_loader) ) ) { vfs_async_task_lock( loader->task ); /* g_debug( "TRY TO CANCEL REQUESTS!!" ); */ for( l = loader->queue->head; l; ) { req = (ThumbnailRequest*)l->data; --req->n_requests[ is_big ? LOAD_BIG_THUMBNAIL : LOAD_SMALL_THUMBNAIL ]; if( req->n_requests[0] <= 0 && req->n_requests[1] <= 0 ) /* nobody needs this */ { GList* next = l->next; g_queue_delete_link( loader->queue, l ); l = next; } else l = l->next; } if( g_queue_get_length( loader->queue ) == 0 ) { /* g_debug( "FREE LOADER IN vfs_thumbnail_loader_cancel_all_requests!" ); */ vfs_async_task_unlock( loader->task ); loader->dir->thumbnail_loader = NULL; /* FIXME: added idle_handler = 0 to prevent idle_handler being * removed in vfs_thumbnail_loader_free - BUT causes a segfault * in vfs_async_task_lock ?? * If source is removed here or in vfs_thumbnail_loader_free * it causes a "GLib-CRITICAL **: Source ID N was not found when * attempting to remove it" warning. Such a source ID is always * the one added in thumbnail_loader_thread at the "add2" comment. */ //loader->idle_handler = 0; vfs_thumbnail_loader_free( loader ); return; } vfs_async_task_unlock( loader->task ); } }
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 ); }
void vfs_thumbnail_loader_cancel_all_requests( VFSDir* dir, gboolean is_big ) { GList* l; VFSThumbnailLoader* loader; ThumbnailRequest* req; if( G_UNLIKELY( (loader=dir->thumbnail_loader) ) ) { vfs_async_task_lock( loader->task ); /* g_debug( "TRY TO CANCEL REQUESTS!!" ); */ for( l = loader->queue->head; l; ) { req = (ThumbnailRequest*)l->data; --req->n_requests[ is_big ? LOAD_BIG_THUMBNAIL : LOAD_SMALL_THUMBNAIL ]; if( req->n_requests[0] <= 0 && req->n_requests[1] <= 0 ) /* nobody needs this */ { GList* next = l->next; g_queue_delete_link( loader->queue, l ); l = next; } else l = l->next; } if( g_queue_get_length( loader->queue ) == 0 ) { /* g_debug( "FREE LOADER IN vfs_thumbnail_loader_cancel_all_requests!" ); */ vfs_async_task_unlock( loader->task ); loader->dir->thumbnail_loader = NULL; vfs_thumbnail_loader_free( loader ); return; } vfs_async_task_unlock( loader->task ); } }
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; }