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

📄 vfs-dir.c

📁 台湾人开发的Linux下的文件管理器
💻 C
📖 第 1 页 / 共 2 页
字号:
/**  C Implementation: vfs-dir** Description: Object used to present a directory*** Author: Hong Jen Yee (PCMan) <pcman.tw (AT) gmail.com>, (C) 2006** Copyright: See COPYING file that comes with this distribution**//*FIXME: The original multi-threading synchronization in this file is poor and       needs re-check.  Briefly speaking, it's totally in a mess.       If this works without any problems, you are really lucky.       If not, take it easy.  That's quite normal.        Finally, I found Thunar's thunar/thunar-thumbnail-generator.c, whose author       is Benedikt Meurer, and use it as a reference.  Now, the multi-threading       handling is learned from Thunar and re-written.*/#include "vfs-dir.h"#include "vfs-file-info.h"#include "glib-mem.h"#include <string.h>static void vfs_dir_class_init( VFSDirClass* klass );static void vfs_dir_init( VFSDir* dir );static void vfs_dir_finalize( GObject *obj );static void vfs_dir_set_property ( GObject *obj,                                   guint prop_id,                                   const GValue *value,                                   GParamSpec *pspec );static void vfs_dir_get_property ( GObject *obj,                                   guint prop_id,                                   GValue *value,                                   GParamSpec *pspec );static void vfs_dir_load( VFSDir* dir, const char* path );static gpointer vfs_dir_load_thread( VFSDir* dir );static void vfs_dir_file_created( VFSDir* dir, const VFSFileInfo* file );static void vfs_dir_file_deleted( VFSDir* dir, const VFSFileInfo* file );static void vfs_dir_file_changed( VFSDir* dir, const VFSFileInfo* file );static void vfs_dir_monitor_callback( VFSFileMonitor* fm,                                      VFSFileMonitorEvent event,                                      const char* file_name,                                      gpointer user_data );static gboolean vfs_dir_call_state_callback( VFSDir* dir );static gpointer load_thumbnail_thread( gpointer user_data );static gboolean on_thumbnail_idle( VFSDir* dir );static void on_mime_type_reload( gpointer user_data );enum {    FILE_CREATED_SIGNAL = 0,    FILE_DELETED_SIGNAL,    FILE_CHANGED_SIGNAL,    N_SIGNALS};static guint signals[ N_SIGNALS ] = { 0 };static GObjectClass *parent_class = NULL;static GHashTable* dir_hash = NULL;static int xdg_mime_cb_id = 0;static guint change_notify_timeout = 0;struct VFSDirStateCallbackEnt{    VFSDirStateCallback func;    gpointer user_data;    int stage;};enum{    LOAD_BIG_THUMBNAIL,    LOAD_SMALL_THUMBNAIL,    N_LOAD_TYPES};typedef struct _ThumbnailRequest{    int n_requests[ N_LOAD_TYPES ];    VFSFileInfo* file;}ThumbnailRequest;GType vfs_dir_get_type(){    static GType type = G_TYPE_INVALID;    if ( G_UNLIKELY ( type == G_TYPE_INVALID ) )    {        static const GTypeInfo info =            {                sizeof ( VFSDirClass ),                NULL,                NULL,                ( GClassInitFunc ) vfs_dir_class_init,                NULL,                NULL,                sizeof ( VFSDir ),                0,                ( GInstanceInitFunc ) vfs_dir_init,                NULL,            };        type = g_type_register_static ( G_TYPE_OBJECT, "VFSDir", &info, 0 );    }    return type;}void vfs_dir_class_init( VFSDirClass* klass ){    GObjectClass * object_class;    object_class = ( GObjectClass * ) klass;    parent_class = g_type_class_peek_parent ( klass );    object_class->set_property = vfs_dir_set_property;    object_class->get_property = vfs_dir_get_property;    object_class->finalize = vfs_dir_finalize;    /* signals */    klass->file_created = vfs_dir_file_created;    klass->file_deleted = vfs_dir_file_deleted;    klass->file_changed = vfs_dir_file_changed;    /*    * file-created is emitted when there is a new file created in the dir.    * The param is VFSFileInfo of the newly created file.    */    signals[ FILE_CREATED_SIGNAL ] =        g_signal_new ( "file-created",                       G_TYPE_FROM_CLASS ( klass ),                       G_SIGNAL_RUN_LAST,                       G_STRUCT_OFFSET ( VFSDirClass, file_created ),                       NULL, NULL,                       g_cclosure_marshal_VOID__POINTER,                       G_TYPE_NONE, 1, G_TYPE_POINTER );    /*    * file-deleted is emitted when there is a file deleted in the dir.    * The param is VFSFileInfo of the newly created file.    */    signals[ FILE_DELETED_SIGNAL ] =        g_signal_new ( "file-deleted",                       G_TYPE_FROM_CLASS ( klass ),                       G_SIGNAL_RUN_LAST,                       G_STRUCT_OFFSET ( VFSDirClass, file_deleted ),                       NULL, NULL,                       g_cclosure_marshal_VOID__POINTER,                       G_TYPE_NONE, 1, G_TYPE_POINTER );    /*    * file-changed is emitted when there is a file changed in the dir.    * The param is VFSFileInfo of the newly created file.    */    signals[ FILE_CHANGED_SIGNAL ] =        g_signal_new ( "file-changed",                       G_TYPE_FROM_CLASS ( klass ),                       G_SIGNAL_RUN_LAST,                       G_STRUCT_OFFSET ( VFSDirClass, file_changed ),                       NULL, NULL,                       g_cclosure_marshal_VOID__POINTER,                       G_TYPE_NONE, 1, G_TYPE_POINTER );}/* constructor */void vfs_dir_init( VFSDir* dir ){    dir->mutex = g_mutex_new();}/* destructor */static void vfs_dir_clear( VFSDir* dir ){    ThumbnailRequest * req;    GList* l;    if ( dir->monitor )    {        vfs_file_monitor_remove( dir->monitor,                                 vfs_dir_monitor_callback,                                 dir );    }    if ( dir->path )    {        g_hash_table_remove( dir_hash, dir->path );        /* There is no VFSDir instance */        if ( 0 == g_hash_table_size( dir_hash ) )        {            g_hash_table_destroy( dir_hash );            dir_hash = NULL;            xdg_mime_remove_callback( xdg_mime_cb_id );            xdg_mime_cb_id = 0;            if( change_notify_timeout )            {                g_source_remove( change_notify_timeout );                change_notify_timeout = 0;            }        }        g_free( dir->path );        g_free( dir->disp_path );    }    if ( dir->thumbnail_mutex )    {        g_mutex_lock( dir->thumbnail_mutex );        if ( dir->loaded_thumbnails )        {            for ( l = dir->loaded_thumbnails; l ;l = l->next )            {                req = l->data;                vfs_file_info_unref( req->file );                g_slice_free( ThumbnailRequest, req );            }            g_list_free( dir->loaded_thumbnails );            dir->loaded_thumbnails = NULL;        }        if ( dir->thumbnail_requests )        {            while ( req = ( ThumbnailRequest* ) g_queue_pop_head( dir->thumbnail_requests ) )            {                vfs_file_info_unref( req->file );                g_slice_free( ThumbnailRequest, req );            }            g_mutex_unlock( dir->thumbnail_mutex );            if ( dir->thumbnail_thread )            {                g_cond_wait( dir->thumbnail_cond, dir->thumbnail_mutex );            }            g_cond_free( dir->thumbnail_cond );            dir->thumbnail_cond = NULL;        }        else        {            g_mutex_unlock( dir->thumbnail_mutex );        }        if ( dir->thumbnail_idle )        {            g_source_remove( dir->thumbnail_idle );            dir->thumbnail_idle = 0;        }        g_mutex_free( dir->thumbnail_mutex );        dir->thumbnail_mutex = NULL;    }    if ( dir->file_list )    {        g_list_foreach( dir->file_list, ( GFunc ) vfs_file_info_unref, NULL );        g_list_free( dir->file_list );        dir->file_list = NULL;        dir->n_files = 0;    }    if( dir->changed_files )    {        g_slist_foreach( dir->changed_files, (GFunc)vfs_file_info_unref, NULL );        g_slist_free( dir->changed_files );         dir->changed_files = NULL;    }}void vfs_dir_finalize( GObject *obj ){    VFSDir * dir = VFS_DIR( obj );    do{}    while( g_source_remove_by_user_data( dir ) );    vfs_dir_clear( dir );    G_OBJECT_CLASS( parent_class ) ->finalize( obj );}void vfs_dir_get_property ( GObject *obj,                            guint prop_id,                            GValue *value,                            GParamSpec *pspec ){}void vfs_dir_set_property ( GObject *obj,                            guint prop_id,                            const GValue *value,                            GParamSpec *pspec ){}/* signal handlers */void vfs_dir_file_created( VFSDir* dir, const VFSFileInfo* file ){}void vfs_dir_file_deleted( VFSDir* dir, const VFSFileInfo* file ){}void vfs_dir_file_changed( VFSDir* dir, const VFSFileInfo* file ){}/* methods */VFSDir* vfs_dir_new(){    VFSDir * dir;    dir = ( VFSDir* ) g_object_new( VFS_TYPE_DIR, NULL );    return dir;}void vfs_dir_load( VFSDir* dir, const char* path ){    GSList * l;    struct VFSDirStateCallbackEnt* ent;    if ( path )    {        vfs_dir_clear( dir );        dir->path = g_strdup( path );        dir->disp_path = g_filename_display_name( path );        for ( l = dir->state_callback_list; l; l = l->next )        {            ent = ( struct VFSDirStateCallbackEnt* ) l->data;            ent->stage = 0;        }        dir->thread = g_thread_create( ( GThreadFunc ) vfs_dir_load_thread,                                       dir, FALSE, NULL );    }}static gboolean is_dir_desktop( const char* path ){    static int len_home_dir = 0;    static const char* home_dir;    gboolean is_desktop = FALSE;    if( G_UNLIKELY( 0 == len_home_dir ) )    {        home_dir = g_get_home_dir();        len_home_dir = strlen( home_dir );    }    if( 0 == strncmp( path, home_dir, len_home_dir) )    {        if( path[len_home_dir] == '/' &&            G_UNLIKELY(0 == strcmp(path+len_home_dir+1, "Desktop")))            return TRUE;    }    return FALSE;}gpointer vfs_dir_load_thread( VFSDir* dir ){    const gchar * file_name;    char* full_path;    GDir* dir_content;    VFSFileInfo* file;    GList* l;    gboolean is_desktop;    dir->file_listed = 0;    dir->load_complete = 0;    if ( dir->path )    {        /* Install file alteration monitor */        dir->monitor = vfs_file_monitor_add( dir->path,                                             vfs_dir_monitor_callback,                                             dir );        dir_content = g_dir_open( dir->path, 0, NULL );        if ( dir_content )        {            is_desktop = is_dir_desktop( dir->path );            while ( !dir->cancel && ( file_name = g_dir_read_name( dir_content ) ) )            {                full_path = g_build_filename( dir->path, file_name, NULL );                if ( !full_path )                    continue;                file = vfs_file_info_new();                if ( vfs_file_info_get( file, full_path, file_name ) )                {                    g_mutex_lock( dir->mutex );                    /* Special processing for desktop folder */                    if( G_UNLIKELY(is_desktop) )                        vfs_file_info_load_special_info( file, full_path );                    dir->file_list = g_list_prepend( dir->file_list, file );                    g_mutex_unlock( dir->mutex );                    ++dir->n_files;                }                else                {                    vfs_file_info_unref( file );                }                g_free( full_path );            }            g_dir_close( dir_content );        }        dir->file_listed = 1;        //        dir->load_notify = g_idle_add(        //                               ( GSourceFunc ) vfs_dir_call_state_callback, dir );        /* FIXME: load thumbnails and do some time-consuming tasks here */        dir->load_complete = 1;        dir->load_notify = g_idle_add(                               ( GSourceFunc ) vfs_dir_call_state_callback, dir );    }    return NULL;}gboolean vfs_dir_is_loading( VFSDir* dir ){    return dir->thread ? TRUE : FALSE;}void vfs_cancel_load( VFSDir* dir ){    dir->cancel = TRUE;    if ( dir->thread )    {        g_thread_join( dir->thread );        dir->thread = NULL;    }}GList* vfs_dir_find_file( VFSDir* dir, const char* file_name ){    GList * l;    VFSFileInfo* file;    for ( l = dir->file_list; l; l = l->next )    {        file = ( VFSFileInfo* ) l->data;        if ( file->name && 0 == strcmp( file->name, file_name ) )        {            return l;        }    }    return NULL;}static gboolean update_file_info( VFSDir* dir, VFSFileInfo* file ){    char* full_path;    char* file_name;    gboolean ret;    gboolean is_desktop = is_dir_desktop(dir->path);    /* FIXME: Dirty hack: steal the string to prevent memory allocation */    file_name = file->name;    if( file->name == file->disp_name )        file->disp_name = NULL;    file->name = NULL;    full_path = g_build_filename( dir->path, file_name, NULL );    if ( G_LIKELY( full_path ) )    {        if( G_LIKELY( vfs_file_info_get( file, full_path, file_name ) ) )        {            ret = TRUE;            if( G_UNLIKELY(is_desktop) )                vfs_file_info_load_special_info( file, full_path );        }        else /* The file doesn't exist */        {            GList* l;            l = g_list_find( dir->file_list, file );            if( G_UNLIKELY(l) )

⌨️ 快捷键说明

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