⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vfs-dir.c

📁 台湾人开发的Linux下的文件管理器
💻 C
📖 第 1 页 / 共 2 页
字号:
            {                dir->file_list = g_list_delete_link( dir->file_list, l );                --dir->n_files;                if ( file )                {                    g_signal_emit( dir, signals[ FILE_DELETED_SIGNAL ], 0, file );                    vfs_file_info_unref( file );                }            }            ret = FALSE;        }        g_free( full_path );    }    g_free( file_name );    return ret;}static void update_changed_files( gpointer key, gpointer data,                                  gpointer user_data ){    VFSDir* dir = (VFSDir*)data;    GSList* l;    if( dir->changed_files )    {        for( l = dir->changed_files; l; l = l->next )        {            VFSFileInfo* file = l->data;            g_mutex_lock( dir->mutex );            update_file_info( dir, file );            g_mutex_unlock( dir->mutex );            vfs_file_info_unref( file );        }        g_slist_free( dir->changed_files );        dir->changed_files = NULL;    }}static gboolean notify_file_change( gpointer user_data ){    GDK_THREADS_ENTER();    g_hash_table_foreach( dir_hash, update_changed_files, NULL );    /* remove the timeout */    change_notify_timeout = 0;    GDK_THREADS_LEAVE();    return FALSE;}/* Callback function which will be called when monitored events happen */void vfs_dir_monitor_callback( VFSFileMonitor* fm,                               VFSFileMonitorEvent event,                               const char* file_name,                               gpointer user_data ){    char * full_path;    VFSDir* dir = ( VFSDir* ) user_data;    VFSFileInfo* file = NULL;    GList* l;    guint signal;    GDK_THREADS_ENTER();    g_mutex_lock( dir->mutex );    switch ( event )    {    case VFS_FILE_MONITOR_CREATE:        if ( ! vfs_dir_find_file( dir, file_name ) )        {            signal = FILE_CREATED_SIGNAL;            full_path = g_build_filename( dir->path, file_name, NULL );            if ( full_path )            {                file = vfs_file_info_new();                if ( vfs_file_info_get( file, full_path, NULL ) )                {                    gboolean is_desktop = is_dir_desktop(dir->path);                    if( G_UNLIKELY(is_desktop) )                        vfs_file_info_load_special_info( file, full_path );                    dir->file_list = g_list_prepend( dir->file_list, file );                    vfs_file_info_ref( file );                    ++dir->n_files;                }                else                {                    vfs_file_info_unref( file );                    file = NULL;                }                g_free( full_path );            }        }        break;    case VFS_FILE_MONITOR_DELETE:        l = vfs_dir_find_file( dir, file_name );        if ( l )        {            signal = FILE_DELETED_SIGNAL;            file = ( VFSFileInfo* ) l->data;            dir->file_list = g_list_delete_link( dir->file_list, l );            --dir->n_files;        }        break;    case VFS_FILE_MONITOR_CHANGE:        l = vfs_dir_find_file( dir, file_name );        if ( l )        {            signal = FILE_CHANGED_SIGNAL;            file = ( VFSFileInfo* ) l->data;            vfs_file_info_ref( file );            /*                NOTE: We should do some hack here not to fire "change" signal                      too often, or the GUI will need to be refreshed every                      second when the file is continuously changed.                      For example, when downloading a file this happens.                FIXME: Is there any better way to do this? Here's an idea:                       Maybe adding a timer with an interval of 5 sec or so.                       When the timeout handler called, it check if there is                       anyone request the timer to be alive. If it's true,                       the timeout stays alive, and will be called in the next                       5 seconds. The "change" signal only get fired when the file                       wasn't changed in the past 5 seconds, or we'll wait until                       the next time the handler called, and fire the signal if the                       file wasn't changed in the past 5 seconds.            */            if( ! g_slist_find( dir->changed_files, file ) )            {                /* update file info the first time */                if( G_LIKELY( update_file_info( dir, file ) ) )                {                    vfs_file_info_ref( file );                    dir->changed_files = g_slist_prepend( dir->changed_files, file );                    if( 0 == change_notify_timeout )                    {                        /* check every 5 seconds */                        change_notify_timeout = g_timeout_add_full( G_PRIORITY_LOW,                                                                    5000,                                                                    notify_file_change,                                                                    NULL, NULL );                    }                }            }        }        break;    }    g_mutex_unlock( dir->mutex );    if ( file )    {        g_signal_emit( dir, signals[ signal ], 0, file );        vfs_file_info_unref( file );    }    GDK_THREADS_LEAVE();}gboolean vfs_dir_call_state_callback( VFSDir* dir ){    GSList * l;    struct VFSDirStateCallbackEnt* ent;    gdk_threads_enter();    dir->load_notify = 0;    if ( dir->load_complete )    {        /* FIXME: g_thread_join( dir->thread ); Is this necessary? */        dir->thread = NULL;    }    if ( dir->file_listed )    {        for ( l = dir->state_callback_list; l; l = l->next )        {            ent = ( struct VFSDirStateCallbackEnt* ) l->data;            if ( ent->stage < 1 )            {                ent->func( dir, 1, ent->user_data );                ent->stage = 1;            }        }    }    if ( dir->load_complete )    {        for ( l = dir->state_callback_list; l; l = l->next )        {            ent = ( struct VFSDirStateCallbackEnt* ) l->data;            if ( ent->stage < 2 )            {                ent->func( dir, 2, ent->user_data );                ent->stage = 2;            }        }    }    gdk_threads_leave();    return FALSE;}void vfs_dir_add_state_callback( VFSDir* dir,                                 VFSDirStateCallback func,                                 gpointer user_data ){    struct VFSDirStateCallbackEnt * ent;    ent = g_slice_new( struct VFSDirStateCallbackEnt );    ent->func = func;    ent->user_data = user_data;    ent->stage = 0;    dir->state_callback_list = g_slist_prepend( dir->state_callback_list, ent );    if ( dir->file_listed )    {        /* The dir has been loaded */        /*if ( ! dir->load_notify )*/   /* FIXME: this seems to have problems? */        {            dir->load_notify = g_idle_add(                                   ( GSourceFunc ) vfs_dir_call_state_callback, dir );        }    }}void vfs_dir_remove_state_callback( VFSDir* dir,                                    VFSDirStateCallback func,                                    gpointer user_data ){    struct VFSDirStateCallbackEnt * ent;    GSList* prev;    GSList* l;    prev = NULL;    for ( l = dir->state_callback_list; l; l = l->next )    {        ent = ( struct VFSDirStateCallbackEnt* ) l->data;        if ( ent->func == func && ent->user_data == user_data )        {            if ( G_LIKELY( prev ) )                prev->next = l->next;            else    /* first item */                dir->state_callback_list = l->next;            g_slist_free_1( l );            g_slice_free( struct VFSDirStateCallbackEnt, ent );            break;        }        prev = l;    }}VFSDir* vfs_get_dir( const char* path ){    VFSDir * dir = NULL;    if ( !dir_hash )    {        dir_hash = g_hash_table_new( g_str_hash, g_str_equal );        xdg_mime_cb_id = xdg_mime_register_reload_callback(                             on_mime_type_reload, NULL, NULL );    }    else    {        dir = g_hash_table_lookup( dir_hash, path );    }    if ( dir )    {        vfs_dir_ref( dir );    }    else    {        dir = vfs_dir_new();        g_hash_table_insert( dir_hash, path, dir );        vfs_dir_load( dir, path );  /* asynchronous operation */    }    return dir;}gboolean on_thumbnail_idle( VFSDir* dir ){    GList * reqs, *l;    ThumbnailRequest* req;    g_mutex_lock( dir->thumbnail_mutex );    reqs = dir->loaded_thumbnails;    dir->loaded_thumbnails = NULL;    dir->thumbnail_idle = 0;    g_mutex_unlock( dir->thumbnail_mutex );    gdk_threads_enter();    for ( l = reqs; l ;l = l->next )    {        req = l->data;        g_signal_emit( dir, signals[ FILE_CHANGED_SIGNAL ], 0, req->file );        vfs_file_info_unref( req->file );        g_slice_free( ThumbnailRequest, req );    }    g_list_free( dir->loaded_thumbnails );    gdk_threads_leave();    return FALSE;}gpointer load_thumbnail_thread( gpointer user_data ){    VFSDir * dir = VFS_DIR( user_data );    ThumbnailRequest* req;    VFSFileInfo* file;    char* full_path;    int i;    gboolean load_big;    gboolean need_update;    while ( TRUE )    {        g_mutex_lock( dir->thumbnail_mutex );        req = ( ThumbnailRequest* ) g_queue_pop_head( dir->thumbnail_requests );        if ( G_UNLIKELY( ! req ) )        {            g_queue_free( dir->thumbnail_requests );            dir->thumbnail_requests = NULL;            g_mutex_unlock( dir->thumbnail_mutex );            dir->thumbnail_thread = NULL;            g_cond_signal( dir->thumbnail_cond );            break;        }        g_mutex_unlock( dir->thumbnail_mutex );        file = req->file;        need_update = FALSE;        for ( i = 0; i < 2; ++i )        {            if ( ! req->n_requests[ i ] )                continue;            load_big = ( i == LOAD_BIG_THUMBNAIL );            if ( ! vfs_file_info_is_thumbnail_loaded( file, load_big ) )            {                full_path = g_build_filename( dir->path,                                              vfs_file_info_get_name( file ),                                              NULL );                vfs_file_info_load_thumbnail( file, full_path, load_big );                g_free( full_path );            }            need_update = TRUE;        }        if ( need_update )        {            g_mutex_lock( dir->thumbnail_mutex );            dir->loaded_thumbnails = g_list_append( dir->loaded_thumbnails, req );            if ( ! dir->thumbnail_idle )            {                dir->thumbnail_idle = g_idle_add( ( GSourceFunc ) on_thumbnail_idle, dir );            }            g_mutex_unlock( dir->thumbnail_mutex );        }        g_thread_yield();    }    return NULL;}void vfs_dir_request_thumbnail( VFSDir* dir, VFSFileInfo* file, gboolean big ){    ThumbnailRequest * req;    GList* l;    if ( ! dir->thumbnail_mutex )    {        dir->thumbnail_mutex = g_mutex_new();        dir->thumbnail_cond = g_cond_new();    }    g_mutex_lock( dir->thumbnail_mutex );    if ( ! dir->thumbnail_requests )    {        dir->thumbnail_requests = g_queue_new();    }    for ( l = dir->thumbnail_requests->head; l; l = l->next )    {        req = ( ThumbnailRequest* ) l->data;        if ( req->file == file )        {            if ( big )                ++req->n_requests[ LOAD_BIG_THUMBNAIL ];            else                ++req->n_requests[ LOAD_SMALL_THUMBNAIL ];            g_mutex_unlock( dir->thumbnail_mutex );            return ;        }    }    req = g_slice_new0( ThumbnailRequest );    vfs_file_info_ref( file );    req->file = file;    if ( big )        ++req->n_requests[ LOAD_BIG_THUMBNAIL ];    else        ++req->n_requests[ LOAD_SMALL_THUMBNAIL ];    g_queue_push_tail( dir->thumbnail_requests, req );    if ( ! dir->thumbnail_thread )    {        dir->thumbnail_thread = g_thread_create_full(                                    load_thumbnail_thread, dir,                                    0, FALSE, FALSE, G_THREAD_PRIORITY_LOW, NULL );    }    g_mutex_unlock( dir->thumbnail_mutex );}void vfs_dir_cancel_thumbnail_request( VFSDir* dir, VFSFileInfo* file,                                       gboolean big ){    /* FIXME: This cannot work. :( */#if 0    ThumbnailRequest * req;    GList* l;    if ( ! dir->thumbnail_mutex || ! dir->thumbnail_requests )        return ;    g_mutex_lock( dir->thumbnail_mutex );    for ( l = dir->thumbnail_requests->head; l; l = l->next )    {        req = ( ThumbnailRequest* ) l->data;        if ( req->file == file )        {            if ( big )                --req->n_requests[ LOAD_BIG_THUMBNAIL ];            else                --req->n_requests[ LOAD_SMALL_THUMBNAIL ];            /* FIXME: remove the request if it doesn't load any thumbnail? */        }    }    g_mutex_unlock( dir->thumbnail_mutex );#endif}static void reload_mime_type( char* key, VFSDir* dir, gpointer user_data ){    GList* l;    VFSFileInfo* file;    char* full_path;    if( G_UNLIKELY( ! dir || ! dir->file_list ) )        return;    g_mutex_lock( dir->mutex );    for( l = dir->file_list; l; l = l->next )    {        file = (VFSFileInfo*)l->data;        full_path = g_build_filename( dir->path,                                      vfs_file_info_get_name( file ), NULL );        vfs_file_info_reload_mime_type( file, full_path );        g_free( full_path );    }    for( l = dir->file_list; l; l = l->next )    {        file = (VFSFileInfo*)l->data;        g_signal_emit( dir, signals[FILE_CHANGED_SIGNAL], 0, file );    }    g_mutex_unlock( dir->mutex );}static void on_mime_type_reload( gpointer user_data ){    if( ! dir_hash )        return;    GDK_THREADS_ENTER();    g_hash_table_foreach( dir_hash, (GHFunc)reload_mime_type, NULL );    GDK_THREADS_LEAVE();}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -