/* 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; }
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); } }
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); }
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; }
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); }
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); }
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)); } }
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); }
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); }
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; }
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); }
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); } }
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); } }
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)); }
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; }
static gboolean sep_func( GtkTreeModel* model, GtkTreeIter* it, gpointer data ) { return fm_places_model_iter_is_separator(FM_PLACES_MODEL(model), it); }
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; }
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); }
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); }
static void on_pane_icon_size_changed(FmConfig* cfg, gpointer user_data) { FmPlacesModel* model = FM_PLACES_MODEL(user_data); update_icons(model); }
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); }