예제 #1
0
/* Given a drop path retrieved by gtk_tree_view_get_dest_row_at_pos, this function
 * determines whether dropping a bookmark item at the specified path is allow.
 * If dropping is not allowed, this function tries to choose an alternative position
 * for the bookmark item and modified the tree path @tp passed into this function. */
static gboolean get_bookmark_drag_dest(FmPlacesView* view, GtkTreePath** tp, GtkTreeViewDropPosition* pos)
{
    gboolean ret = TRUE;
    if(*tp)
    {
        /* if the drop site is below the separator (in the bookmark area) */
        if(fm_places_model_path_is_bookmark(FM_PLACES_MODEL(model), *tp))
        {
            /* we cannot drop into a item */
            if(*pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
               *pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
                ret = FALSE;
            else
                ret = TRUE;
        }
        else /* the drop site is above the separator (in the places area containing volumes) */
        {
            const GtkTreePath* sep = fm_places_model_get_separator_path(FM_PLACES_MODEL(model));
            /* set drop site at the first bookmark item */
            gtk_tree_path_get_indices(*tp)[0] = gtk_tree_path_get_indices(sep)[0] + 1;
            *pos = GTK_TREE_VIEW_DROP_BEFORE;
            ret = TRUE;
        }
    }
    else
    {
        /* drop at end of the bookmarks list instead */
        *tp = gtk_tree_path_new_from_indices(gtk_tree_model_iter_n_children(GTK_TREE_MODEL(model), NULL) - 1, -1);
        *pos = GTK_TREE_VIEW_DROP_AFTER;
        ret = TRUE;
    }
    g_debug("path: %s", gtk_tree_path_to_string(*tp));
    return ret;
}
예제 #2
0
void on_mount_added(GVolumeMonitor* vm, GMount* mount, gpointer user_data)
{
    FmPlacesModel* model = FM_PLACES_MODEL(user_data);
    GVolume* vol = g_mount_get_volume(mount);
    if(vol)
    {
        FmPlaceItem *item;
        GtkTreeIter it;
        item = find_vol(model, vol, &it);
        if(item && item->type == FM_PLACES_ITEM_VOL && !item->fi->path)
        {
            GtkTreePath* tp;
            GFile* gf = g_mount_get_root(mount);
            FmPath* path = fm_path_new_for_gfile(gf);
            g_debug("mount path: %s", path->name);
            g_object_unref(gf);
            fm_file_info_set_path(item->fi, path);
            if(path)
                fm_path_unref(path);
            item->vol_mounted = TRUE;

            /* inform the view to update mount indicator */
            tp = gtk_tree_model_get_path(GTK_TREE_MODEL(model), &it);
            gtk_tree_model_row_changed(GTK_TREE_MODEL(model), tp, &it);
            gtk_tree_path_free(tp);
        }
        g_object_unref(vol);
    }
}
예제 #3
0
void on_vol_added(GVolumeMonitor* vm, GVolume* vol, gpointer user_data)
{
    FmPlacesModel* model = FM_PLACES_MODEL(user_data);
    g_debug("add vol: %p, uuid: %s, udi: %s", vol, g_volume_get_identifier(vol, "uuid"), g_volume_get_identifier(vol, "hal-udi"));
    add_vol(model, vol, NULL);
    update_sep_tp(model);
}
예제 #4
0
static gboolean update_trash_item(gpointer user_data)
{
    FmPlacesModel* model = FM_PLACES_MODEL(user_data);
    if(fm_config->use_trash)
    {
        GFile* gf = g_file_new_for_uri("trash:///");
        GFileInfo* inf = g_file_query_info(gf, G_FILE_ATTRIBUTE_TRASH_ITEM_COUNT, 0, NULL, NULL);
        g_object_unref(gf);
        if(inf)
        {
            FmIcon* icon;
            const char* icon_name;
            FmPlaceItem* item;
            GdkPixbuf* pix;
            guint32 n = g_file_info_get_attribute_uint32(inf, G_FILE_ATTRIBUTE_TRASH_ITEM_COUNT);
            g_object_unref(inf);
            icon_name = n > 0 ? "user-trash-full" : "user-trash";
            icon = fm_icon_from_name(icon_name);
            gtk_tree_model_get(GTK_TREE_MODEL(model), &model->trash_it, FM_PLACES_MODEL_COL_INFO, &item, -1);
            if(item->fi->icon)
                fm_icon_unref(item->fi->icon);
            item->fi->icon = icon;
            /* update the icon */
            pix = fm_icon_get_pixbuf(item->fi->icon, fm_config->pane_icon_size);
            gtk_list_store_set(GTK_LIST_STORE(model), &model->trash_it, FM_PLACES_MODEL_COL_ICON, pix, -1);
            g_object_unref(pix);
        }
    }
    return FALSE;
}
예제 #5
0
static void on_trash_changed(GFileMonitor *monitor, GFile *gf, GFile *other, GFileMonitorEvent evt, gpointer user_data)
{
    FmPlacesModel* model = FM_PLACES_MODEL(user_data);
    if(model->trash_idle)
        g_source_remove(model->trash_idle);
    model->trash_idle = g_idle_add((GSourceFunc)update_trash_item, model);
}
예제 #6
0
static void on_use_trash_changed(FmConfig* cfg, gpointer user_data)
{
    FmPlacesModel* model = FM_PLACES_MODEL(user_data);
    if(cfg->use_trash && model->trash_it.user_data == NULL)
        create_trash_item(model);
    else
    {
        FmPlaceItem *item;
        gtk_tree_model_get(GTK_TREE_MODEL(model), &model->trash_it, FM_PLACES_MODEL_COL_INFO, &item, -1);
        gtk_list_store_remove(GTK_LIST_STORE(model), &model->trash_it);
        model->trash_it.user_data = NULL;
        place_item_free(item);

        if(model->trash_monitor)
        {
            g_signal_handlers_disconnect_by_func(model->trash_monitor, on_trash_changed, model);
            g_object_unref(model->trash_monitor);
            model->trash_monitor = NULL;
        }
        if(model->trash_idle)
        {
            g_source_remove(model->trash_idle);
            model->trash_idle = 0;
        }
    }
    update_sep_tp(model);
}
예제 #7
0
static void on_file_info_job_finished(FmFileInfoJob* job, gpointer user_data)
{
    FmPlacesModel* model = FM_PLACES_MODEL(user_data);
    GList* l;
    GtkTreeIter it;
    FmPlaceItem* item;
    FmFileInfo* fi;

    /* g_debug("file info job finished"); */
    model->jobs = g_slist_remove(model->jobs, job);

    if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &it))
        return;

    if(fm_list_is_empty(job->file_infos))
        return;

    /* optimize for one file case */
    if(fm_list_get_length(job->file_infos) == 1)
    {
        fi = FM_FILE_INFO(fm_list_peek_head(job->file_infos));
        do {
            item = NULL;
            gtk_tree_model_get(GTK_TREE_MODEL(model), &it, FM_PLACES_MODEL_COL_INFO, &item, -1);
            if( item && item->fi && item->fi->path && fm_path_equal(item->fi->path, fi->path) )
            {
                fm_file_info_unref(item->fi);
                item->fi = fm_file_info_ref(fi);
                break;
            }
        }while(gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &it));
    }
    else
    {
        do {
            item = NULL;
            gtk_tree_model_get(GTK_TREE_MODEL(model), &it, FM_PLACES_MODEL_COL_INFO, &item, -1);
            if( item && item->fi && item->fi->path )
            {
                for(l = fm_list_peek_head_link(job->file_infos); l; l = l->next )
                {
                    fi = FM_FILE_INFO(l->data);
                    if(fm_path_equal(item->fi->path, fi->path))
                    {
                        fm_file_info_unref(item->fi);
                        item->fi = fm_file_info_ref(fi);
                        /* remove the file from list to speed up further loading.
                      * This won't cause problem since nobody else if using the list. */
                        fm_list_delete_link(job->file_infos, l);
                        break;
                    }
                }
            }
        }while(gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &it));
    }
}
예제 #8
0
void on_vol_changed(GVolumeMonitor* vm, GVolume* vol, gpointer user_data)
{
    FmPlacesModel* model = FM_PLACES_MODEL(user_data);
    FmPlaceItem* item;
    GtkTreeIter it;
    g_debug("vol-changed");
    item = find_vol(model, vol, &it);
    if(item)
        update_vol(model, item, &it, NULL);
}
예제 #9
0
static void fm_places_model_finalize(GObject *object)
{
    FmPlacesModel *self;
    GtkTreeIter it;

    g_return_if_fail(object != NULL);
    g_return_if_fail(FM_IS_PLACES_MODEL(object));

    self = FM_PLACES_MODEL(object);

    if(self->jobs)
    {
        GSList* l;
        for(l = self->jobs; l; l=l->next)
        {
            fm_job_cancel(FM_JOB(l->data));
            g_object_unref(l->data);
        }
        g_slist_free(self->jobs);
    }

    if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(self), &it))
    {
        do
        {
            FmPlaceItem* item;
            gtk_tree_model_get(GTK_TREE_MODEL(self), &it, FM_PLACES_MODEL_COL_INFO, &item, -1);
            if(G_LIKELY(item))
                place_item_free(item);
        }while(gtk_tree_model_iter_next(GTK_TREE_MODEL(self), &it));
    }

    gtk_tree_path_free(self->sep_tp);

    g_signal_handler_disconnect(gtk_icon_theme_get_default(), self->theme_change_handler);
    g_signal_handler_disconnect(fm_config, self->use_trash_change_handler);
    g_signal_handler_disconnect(fm_config, self->pane_icon_size_change_handler);

    g_signal_handlers_disconnect_by_func(self->vol_mon, on_vol_added, self);
    g_signal_handlers_disconnect_by_func(self->vol_mon, on_vol_removed, self);
    g_signal_handlers_disconnect_by_func(self->vol_mon, on_vol_changed, self);
    g_signal_handlers_disconnect_by_func(self->vol_mon, on_mount_added, self);
    g_object_unref(self->vol_mon);

    if(self->trash_monitor)
    {
        g_signal_handlers_disconnect_by_func(self->trash_monitor, on_trash_changed, self);
        g_object_unref(self->trash_monitor);
    }
    if(self->trash_idle)
        g_source_remove(self->trash_idle);

    G_OBJECT_CLASS(fm_places_model_parent_class)->finalize(object);
}
예제 #10
0
gboolean on_dnd_dest_files_dropped(FmDndDest* dd, GdkDragAction action,
                               int info_type, FmFileInfoList* files, FmPlacesView* view)
{
    FmPath* dest;
    GList* l;
    gboolean ret = FALSE;

    dest = fm_dnd_dest_get_dest_path(dd);
    /* g_debug("action= %d, %d files-dropped!, info_type: %d", action, fm_list_get_length(files), info_type); */

    if(!dest && action == GDK_ACTION_LINK) /* add bookmarks */
    {
        GtkTreePath* tp = view->dest_row;
        if(tp)
        {
            const GtkTreePath* sep = fm_places_model_get_separator_path(FM_PLACES_MODEL(model));
            int idx = gtk_tree_path_get_indices(tp)[0] - gtk_tree_path_get_indices(sep)[0];

            if(view->dest_pos == GTK_TREE_VIEW_DROP_BEFORE)
                --idx;
            for( l=fm_list_peek_head_link(files); l; l=l->next, ++idx )
            {
                FmBookmarkItem* item;
                FmFileInfo* fi = FM_FILE_INFO(l->data);
                if(fm_file_info_is_dir(fi))
                    item = fm_bookmarks_insert( FM_PLACES_MODEL(model)->bookmarks, fi->path, fi->disp_name, idx);
                /* we don't need to add item to places view. Later the bookmarks will be reloaded. */
            }
        }
        ret = TRUE;
    }

    if(view->dest_row)
    {
        gtk_tree_path_free(view->dest_row);
        view->dest_row = NULL;
    }
    return ret;
}
예제 #11
0
void fm_places_model_mount_indicator_cell_data_func(GtkCellLayout *cell_layout,
                                           GtkCellRenderer *render,
                                           GtkTreeModel *tree_model,
                                           GtkTreeIter *it,
                                           gpointer user_data)
{
    FmPlaceItem* item;
    GdkPixbuf* pix = NULL;
    gtk_tree_model_get(tree_model, it, FM_PLACES_MODEL_COL_INFO, &item, -1);
    if(item && item->vol_mounted)
        pix = FM_PLACES_MODEL(tree_model)->eject_icon;
    g_object_set(render, "pixbuf", pix, NULL);
}
예제 #12
0
void on_vol_removed(GVolumeMonitor* vm, GVolume* vol, gpointer user_data)
{
    FmPlacesModel* model = FM_PLACES_MODEL(user_data);
    FmPlaceItem* item;
    GtkTreeIter it;
    item = find_vol(model, vol, &it);
    /* g_debug("remove vol: %p, uuid: %s, udi: %s", vol, g_volume_get_identifier(vol, "uuid"), g_volume_get_identifier(vol, "hal-udi")); */
    if(item)
    {
        gtk_list_store_remove(GTK_LIST_STORE(model), &it);
        place_item_free(item);
        update_sep_tp(model);
    }
}
예제 #13
0
void on_rename_bm(GtkAction* act, gpointer user_data)
{
    FmPlaceItem* item = (FmPlaceItem*)user_data;
    /* FIXME: we need to set a proper parent window for the dialog */
    char* new_name = fm_get_user_input(NULL, _("Rename Bookmark Item"),
                                        _("Enter a new name:"), item->bm_item->name);
    if(new_name)
    {
        if(strcmp(new_name, item->bm_item->name))
        {
            fm_bookmarks_rename(FM_PLACES_MODEL(model)->bookmarks, item->bm_item, new_name);
        }
        g_free(new_name);
    }
}
예제 #14
0
static void on_bookmarks_changed(FmBookmarks* bm, gpointer user_data)
{
    FmPlacesModel* model = FM_PLACES_MODEL(user_data);
    FmFileInfoJob* job = fm_file_info_job_new(NULL, FM_FILE_INFO_JOB_FOLLOW_SYMLINK);
    GtkTreeIter it = model->sep_it;
    /* remove all old bookmarks */
    if(gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &it))
    {
        while(gtk_list_store_remove(GTK_LIST_STORE(model), &it))
            continue;
    }
    add_bookmarks(model, job);

    g_signal_connect(job, "finished", G_CALLBACK(on_file_info_job_finished), model);
    model->jobs = g_slist_prepend(model->jobs, job);
    fm_job_run_async(FM_JOB(job));
}
예제 #15
0
gboolean on_button_press(GtkWidget* widget, GdkEventButton* evt)
{
    FmPlacesView* view = FM_PLACES_VIEW(widget);
    GtkTreePath* tp;
    GtkTreeViewColumn* col;
    gboolean ret = GTK_WIDGET_CLASS(fm_places_view_parent_class)->button_press_event(widget, evt);
    int cell_x;

    gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view), evt->x, evt->y, &tp, &col, NULL, NULL);
    view->clicked_row = tp;
    if(tp)
    {
        switch(evt->button) /* middle click */
        {
        case 1: /* left click */
            break;
        case 2: /* middle click */
            activate_row(view, 2, tp);
            break;
        case 3: /* right click */
            {
                GtkTreeIter it;
                if(gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &it, tp)
                    && !fm_places_model_iter_is_separator(FM_PLACES_MODEL(model), &it) )
                {
                    FmPlaceItem* item;
                    GtkWidget* menu;
                    gtk_tree_model_get(GTK_TREE_MODEL(model), &it, FM_PLACES_MODEL_COL_INFO, &item, -1);
                    menu = place_item_get_menu(item);
                    if(menu)
                    {
                        gtk_menu_attach_to_widget(GTK_MENU(menu), widget, NULL);
                        gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, evt->time);
                    }
                }
            }
            break;
        }
    }
    return ret;
}
예제 #16
0
static gboolean sep_func( GtkTreeModel* model, GtkTreeIter* it, gpointer data )
{
    return fm_places_model_iter_is_separator(FM_PLACES_MODEL(model), it);
}
예제 #17
0
static gboolean on_drag_motion (GtkWidget *dest_widget,
                    GdkDragContext *drag_context, gint x, gint y, guint time)
{
    FmPlacesView* view = FM_PLACES_VIEW(dest_widget);
    /* fm_drag_context_has_target_name(drag_context, "GTK_TREE_MODEL_ROW"); */
    GdkAtom target;
    GtkTreeViewDropPosition pos;
    GtkTreePath* tp, *sep;
    gboolean ret = FALSE;
    GdkDragAction action = 0;

    target = gtk_drag_dest_find_target(dest_widget, drag_context, NULL);
    if(target == GDK_NONE)
        return FALSE;

    gtk_tree_view_get_dest_row_at_pos((GtkTreeView*)view, x, y, &tp, &pos);

    /* handle reordering bookmark items first */
    if(target == gdk_atom_intern_static_string("GTK_TREE_MODEL_ROW"))
    {
        /* bookmark item is being dragged */
        ret = get_bookmark_drag_dest(view, &tp, &pos);
        action = ret ? GDK_ACTION_MOVE : 0; /* bookmark items can only be moved */
    }
    /* try FmDndDest */
    else if(fm_dnd_dest_is_target_supported(view->dnd_dest, target))
    {
        /* the user is dragging files. get FmFileInfo of drop site. */
        if(pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE || pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER) /* drag into items */
        {
            FmPlaceItem* item = NULL;
            GtkTreeIter it;
            /* FIXME: handle adding bookmarks with Dnd */
            if(tp && gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &it, tp))
                gtk_tree_model_get(GTK_TREE_MODEL(model), &it, FM_PLACES_MODEL_COL_INFO, &item, -1);

            fm_dnd_dest_set_dest_file(view->dnd_dest, item && item->fi ? item->fi : NULL);
            action = fm_dnd_dest_get_default_action(view->dnd_dest, drag_context, target);
            ret = action != 0;
        }
        else /* drop between items, create bookmark items for dragged files */
        {
            if( (!tp || fm_places_model_path_is_bookmark(FM_PLACES_MODEL(model), tp))
               && get_bookmark_drag_dest(view, &tp, &pos)) /* tp is after separator */
            {
                action = GDK_ACTION_LINK;
                ret = TRUE;
            }
            else
            {
                action = 0;
                ret = FALSE;
            }
        }
    }
    gdk_drag_status(drag_context, action, time);

    if(ret)
        gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(view), tp, pos);
    else
        gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(view), NULL, 0);

    if(tp)
        gtk_tree_path_free(tp);

    return ret;
}
예제 #18
0
static gboolean row_draggable(GtkTreeDragSource* drag_source, GtkTreePath* tp)
{
    FmPlacesModel* model = FM_PLACES_MODEL(drag_source);
    return fm_places_model_path_is_bookmark(model, tp);
}
예제 #19
0
static void on_drag_data_received ( GtkWidget *dest_widget,
                GdkDragContext *drag_context, gint x, gint y,
                GtkSelectionData *sel_data, guint info, guint time)
{
    FmPlacesView* view = FM_PLACES_VIEW(dest_widget);
    GtkTreePath* dest_tp = NULL;
    GtkTreeViewDropPosition pos;

    gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(view), x, y, &dest_tp, &pos);
    switch(info)
    {
    case FM_DND_DEST_TARGET_BOOOKMARK:
        if(get_bookmark_drag_dest(view, &dest_tp, &pos)) /* got the drop position */
        {
            GtkTreePath* src_tp;
            /* get the source row */
            gboolean ret = gtk_tree_get_row_drag_data(sel_data, NULL, &src_tp);
            if(ret)
            {
                /* don't do anything if source and dest are the same row */
                if(G_UNLIKELY(gtk_tree_path_compare(src_tp, dest_tp) == 0))
                    ret = FALSE;
                else
                {
                    /* don't do anything if this is not a bookmark item */
                    if(!fm_places_model_path_is_bookmark(FM_PLACES_MODEL(model), src_tp))
                        ret = FALSE;
                }
                if(ret)
                {
                    GtkTreeIter src_it, dest_it;
                    FmPlaceItem* item = NULL;
                    ret = FALSE;
                    /* get the source bookmark item */
                    if(gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &src_it, src_tp))
                        gtk_tree_model_get(GTK_TREE_MODEL(model), &src_it, FM_PLACES_MODEL_COL_INFO, &item, -1);
                    if(item)
                    {
                        /* move it to destination position */
                        if(gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &dest_it, dest_tp))
                        {
                            int new_pos, sep_pos;
                            /* get index of the separator */
                            const GtkTreePath* sep_tp = fm_places_model_get_separator_path(FM_PLACES_MODEL(model));
                            sep_pos = gtk_tree_path_get_indices(sep_tp)[0];

                            if(pos == GTK_TREE_VIEW_DROP_BEFORE)
                                gtk_list_store_move_before(model, &src_it, &dest_it);
                            else
                                gtk_list_store_move_after(model, &src_it, &dest_it);
                            new_pos = gtk_tree_path_get_indices(dest_tp)[0] - sep_pos - 1;
                            /* reorder the bookmark item */
                            fm_bookmarks_reorder(FM_PLACES_MODEL(model)->bookmarks, item->bm_item, new_pos);
                            ret = TRUE;
                        }
                    }
                }
                gtk_tree_path_free(src_tp);
            }
            gtk_drag_finish(drag_context, ret, FALSE, time);
        }
        break;
    default:
        /* check if files are received. */
        fm_dnd_dest_drag_data_received(view->dnd_dest, drag_context, x, y, sel_data, info, time);
        break;
    }
    if(dest_tp)
        gtk_tree_path_free(dest_tp);
}
예제 #20
0
static void on_pane_icon_size_changed(FmConfig* cfg, gpointer user_data)
{
    FmPlacesModel* model = FM_PLACES_MODEL(user_data);
    update_icons(model);
}
예제 #21
0
void on_remove_bm(GtkAction* act, gpointer user_data)
{
    FmPlaceItem* item = (FmPlaceItem*)user_data;
    fm_bookmarks_remove(FM_PLACES_MODEL(model)->bookmarks, item->bm_item);
}