static void filename_cell_data_func (GtkTreeViewColumn *column, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, FMListView *view) { char *text; char *color; GdkRGBA rgba; GtkTreePath *path, *hover_path; PangoUnderline underline; gtk_tree_model_get (model, iter, FM_LIST_MODEL_FILENAME, &text, -1); gtk_tree_model_get (model, iter, FM_LIST_MODEL_COLOR, &color, -1); if (color != NULL) { gdk_rgba_parse (&rgba, color); //rgba.alpha = 0.85; } /*if (color) { GList *lrenderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT(column)); GList *l; for (l=lrenderers; l != NULL; l=l->next) g_object_set(l->data, "cell-background", color, NULL); g_list_free (lrenderers); } g_free (color);*/ underline = PANGO_UNDERLINE_NONE; if (exo_tree_view_get_single_click (EXO_TREE_VIEW (view->tree))) { path = gtk_tree_model_get_path (model, iter); hover_path = exo_tree_view_get_hover_path (EXO_TREE_VIEW (view->tree)); if (hover_path == NULL || gtk_tree_path_compare (path, hover_path)) { underline = PANGO_UNDERLINE_NONE; } else { underline = PANGO_UNDERLINE_SINGLE; } gtk_tree_path_free (path); } g_object_set (G_OBJECT (renderer), "text", text, "underline", underline, //"cell-background", color, "cell-background-rgba", &rgba, NULL); g_free (text); }
static void fm_list_view_init (FMListView *view) { view->details = g_new0 (FMListViewDetails, 1); view->details->selection = NULL; create_and_set_up_tree_view (view); g_settings_bind (settings, "single-click", EXO_TREE_VIEW (view->tree), "single-click", 0); g_settings_bind (settings, "single-click-timeout", EXO_TREE_VIEW (view->tree), "single-click-timeout", 0); g_settings_bind (marlin_list_view_settings, "zoom-level", view, "zoom-level", 0); }
static gboolean exo_tree_view_move_cursor (GtkTreeView *view, GtkMovementStep step, gint count) { ExoTreeView *tree_view = EXO_TREE_VIEW (view); /* be sure to cancel any pending single-click timeout */ if (G_UNLIKELY (tree_view->priv->single_click_timeout_id >= 0)) g_source_remove (tree_view->priv->single_click_timeout_id); /* release and reset the hover path (if any) */ if (tree_view->priv->hover_path != NULL) { gtk_tree_path_free (tree_view->priv->hover_path); tree_view->priv->hover_path = NULL; } /* reset the cursor for the tree view internal window */ if (gtk_widget_get_realized (GTK_WIDGET (tree_view))) gdk_window_set_cursor (gtk_tree_view_get_bin_window (GTK_TREE_VIEW (tree_view)), NULL); /* call the parent's handler */ return (*GTK_TREE_VIEW_CLASS (exo_tree_view_parent_class)->move_cursor) (view, step, count); }
static gboolean exo_tree_view_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event) { ExoTreeView *tree_view = EXO_TREE_VIEW (widget); /* be sure to cancel any pending single-click timeout */ if (G_UNLIKELY (tree_view->priv->single_click_timeout_id >= 0)) g_source_remove (tree_view->priv->single_click_timeout_id); /* release and reset the hover path (if any) */ if (tree_view->priv->hover_path != NULL) { gtk_tree_path_free (tree_view->priv->hover_path); tree_view->priv->hover_path = NULL; } /* reset the cursor for the tree view internal window */ if (gtk_widget_get_realized (GTK_WIDGET (tree_view))) gdk_window_set_cursor (gtk_tree_view_get_bin_window (GTK_TREE_VIEW (tree_view)), NULL); /* the next button-release-event should not activate */ tree_view->priv->button_release_activates = FALSE; /* call the parent's leave notify handler */ return (*GTK_WIDGET_CLASS (exo_tree_view_parent_class)->leave_notify_event) (widget, event); }
static void exo_tree_view_drag_begin (GtkWidget *widget, GdkDragContext *context) { ExoTreeView *tree_view = EXO_TREE_VIEW (widget); /* the next button-release-event should not activate */ tree_view->priv->button_release_activates = FALSE; /* call the parent's drag begin handler */ (*GTK_WIDGET_CLASS (exo_tree_view_parent_class)->drag_begin) (widget, context); }
static void exo_tree_view_finalize (GObject *object) { ExoTreeView *tree_view = EXO_TREE_VIEW (object); /* be sure to cancel any single-click timeout */ if (G_UNLIKELY (tree_view->priv->single_click_timeout_id >= 0)) g_source_remove (tree_view->priv->single_click_timeout_id); /* be sure to release the hover path */ if (G_UNLIKELY (tree_view->priv->hover_path == NULL)) gtk_tree_path_free (tree_view->priv->hover_path); (*G_OBJECT_CLASS (exo_tree_view_parent_class)->finalize) (object); }
static void exo_tree_view_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ExoTreeView *tree_view = EXO_TREE_VIEW (object); switch (prop_id) { case PROP_SINGLE_CLICK: exo_tree_view_set_single_click (tree_view, g_value_get_boolean (value)); break; case PROP_SINGLE_CLICK_TIMEOUT: exo_tree_view_set_single_click_timeout (tree_view, g_value_get_uint (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
gboolean on_btn_pressed(GtkWidget* view, GdkEventButton* evt, FmFolderView* fv) { GList* sels; FmFolderViewClickType type = 0; GtkTreePath* tp; if(!fv->model) return FALSE; /* FIXME: handle single click activation */ if( evt->type == GDK_BUTTON_PRESS ) { /* special handling for ExoIconView */ if(evt->button != 1) { if(fv->mode==FM_FV_ICON_VIEW || fv->mode==FM_FV_COMPACT_VIEW || fv->mode==FM_FV_THUMBNAIL_VIEW) { /* select the item on right click for ExoIconView */ if(exo_icon_view_get_item_at_pos(EXO_ICON_VIEW(view), evt->x, evt->y, &tp, NULL)) { /* if the hit item is not currently selected */ if(!exo_icon_view_path_is_selected(EXO_ICON_VIEW(view), tp)) { sels = exo_icon_view_get_selected_items((const struct ExoIconView *)(const struct ExoIconView *)view); if( sels ) /* if there are selected items */ { exo_icon_view_unselect_all(EXO_ICON_VIEW(view)); /* unselect all items */ g_list_foreach(sels, (GFunc)gtk_tree_path_free, NULL); g_list_free(sels); } exo_icon_view_select_path(EXO_ICON_VIEW(view), tp); exo_icon_view_set_cursor(EXO_ICON_VIEW(view), tp, NULL, FALSE); } gtk_tree_path_free(tp); } } else if( fv->mode == FM_FV_LIST_VIEW && evt->window == gtk_tree_view_get_bin_window(GTK_TREE_VIEW(view))) { /* special handling for ExoTreeView */ /* Fix #2986834: MAJOR PROBLEM: Deletes Wrong File Frequently. */ GtkTreeViewColumn* col; if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view), evt->x, evt->y, &tp, &col, NULL, NULL)) { GtkTreeSelection* tree_sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); if(!gtk_tree_selection_path_is_selected(tree_sel, tp)) { gtk_tree_selection_unselect_all(tree_sel); if(col == exo_tree_view_get_activable_column(EXO_TREE_VIEW(view))) { gtk_tree_selection_select_path(tree_sel, tp); gtk_tree_view_set_cursor(GTK_TREE_VIEW(view), tp, NULL, FALSE); } } gtk_tree_path_free(tp); } } } if(evt->button == 2) /* middle click */ type = FM_FV_MIDDLE_CLICK; else if(evt->button == 3) /* right click */ type = FM_FV_CONTEXT_MENU; } if( type != FM_FV_CLICK_NONE ) { sels = fm_folder_view_get_selected_tree_paths(fv); if( sels || type == FM_FV_CONTEXT_MENU ) { item_clicked(fv, sels ? sels->data : NULL, type); if(sels) { g_list_foreach(sels, (GFunc)gtk_tree_path_free, NULL); g_list_free(sels); } } } return FALSE; }
void fm_find_files( const char** search_dirs ) { FindFile* data = g_slice_new0(FindFile); GtkTreeIter it; GtkTreeViewColumn* col; GtkWidget *add_folder_btn, *remove_folder_btn, *img; GtkBuilder* builder = _gtk_builder_new_from_file( PACKAGE_UI_DIR "/find-files.ui", NULL ); data->win = (GtkWidget*)gtk_builder_get_object( builder, "win" ); g_object_set_data_full( G_OBJECT( data->win ), "find-files", data, (GDestroyNotify)free_data ); GdkPixbuf* icon = NULL; GtkIconTheme* theme = gtk_icon_theme_get_default(); if ( theme ) icon = gtk_icon_theme_load_icon( theme, "spacefm-find", 48, 0, NULL ); if ( icon ) { gtk_window_set_icon( GTK_WINDOW( data->win ), icon ); g_object_unref( icon ); } else gtk_window_set_icon_name( GTK_WINDOW( data->win ), GTK_STOCK_FIND ); /* search criteria pane */ data->search_criteria = (GtkWidget*)gtk_builder_get_object( builder, "search_criteria" ); data->fn_pattern = (GtkWidget*)gtk_builder_get_object( builder, "fn_pattern" ); data->fn_pattern_entry = gtk_bin_get_child( GTK_BIN( data->fn_pattern ) ); data->fn_case_sensitive = (GtkWidget*)gtk_builder_get_object( builder, "fn_case_sensitive" ); gtk_entry_set_activates_default( (GtkEntry*)data->fn_pattern_entry, TRUE ); /* file content */ data->fc_pattern = (GtkWidget*)gtk_builder_get_object( builder, "fc_pattern" ); data->fc_case_sensitive = (GtkWidget*)gtk_builder_get_object( builder, "fc_case_sensitive" ); data->fc_use_regexp = (GtkWidget*)gtk_builder_get_object( builder, "fc_use_regexp" ); /* advanced options */ data->search_hidden = (GtkWidget*)gtk_builder_get_object( builder, "search_hidden" ); /* size & date */ data->use_size_lower = (GtkWidget*)gtk_builder_get_object( builder, "use_size_lower" ); data->use_size_upper = (GtkWidget*)gtk_builder_get_object( builder, "use_size_upper" ); data->size_lower = (GtkWidget*)gtk_builder_get_object( builder, "size_lower" ); data->size_upper = (GtkWidget*)gtk_builder_get_object( builder, "size_upper" ); data->size_lower_unit = (GtkWidget*)gtk_builder_get_object( builder, "size_lower_unit" ); data->size_upper_unit = (GtkWidget*)gtk_builder_get_object( builder, "size_upper_unit" ); g_signal_connect( data->use_size_lower, "toggled", G_CALLBACK( on_use_size_lower_toggled ), data ); g_signal_connect( data->use_size_upper, "toggled", G_CALLBACK( on_use_size_upper_toggled ), data ); on_use_size_lower_toggled( data->use_size_lower, data ); on_use_size_upper_toggled( data->use_size_upper, data ); data->date_limit = (GtkWidget*)gtk_builder_get_object( builder, "date_limit" ); data->date1 = (GtkWidget*)gtk_builder_get_object( builder, "date1" ); data->date2 = (GtkWidget*)gtk_builder_get_object( builder, "date2" ); g_signal_connect( data->date_limit, "changed", G_CALLBACK( on_date_limit_changed ), data ); /* file types */ data->all_files = (GtkWidget*)gtk_builder_get_object( builder, "all_files" ); data->text_files = (GtkWidget*)gtk_builder_get_object( builder, "text_files" ); data->img_files = (GtkWidget*)gtk_builder_get_object( builder, "img_files" ); data->audio_files = (GtkWidget*)gtk_builder_get_object( builder, "audio_files" ); data->video_files = (GtkWidget*)gtk_builder_get_object( builder, "video_files" ); /* places */ data->places_list = gtk_list_store_new( 1, G_TYPE_STRING ); data->places_view = (GtkWidget*)gtk_builder_get_object( builder, "places_view" ); add_folder_btn = (GtkWidget*)gtk_builder_get_object( builder, "add_folder_btn" ); remove_folder_btn = (GtkWidget*)gtk_builder_get_object( builder, "remove_folder_btn" ); data->include_sub = (GtkWidget*)gtk_builder_get_object( builder, "include_sub" ); if( search_dirs ) { const char** dir; for( dir = search_dirs; *dir; ++dir ) { if( g_file_test( *dir, G_FILE_TEST_IS_DIR ) ) gtk_list_store_insert_with_values( data->places_list, &it, 0, 0, *dir, -1 ); } } gtk_tree_view_set_model( (GtkTreeView*)data->places_view, (GtkTreeModel*)data->places_list ); g_object_unref( data->places_list ); col = gtk_tree_view_column_new_with_attributes(NULL, gtk_cell_renderer_text_new(), "text", 0, NULL ); gtk_tree_view_append_column( (GtkTreeView*)data->places_view, col ); g_signal_connect(add_folder_btn, "clicked", G_CALLBACK( on_add_search_folder ), data ); g_signal_connect(remove_folder_btn, "clicked", G_CALLBACK( on_remove_search_folder ), data ); /* search result pane */ data->search_result = (GtkWidget*)gtk_builder_get_object( builder, "search_result" ); /* replace the problematic GtkTreeView with ExoTreeView */ data->result_view = exo_tree_view_new(); if( app_settings.single_click ) { exo_tree_view_set_single_click( EXO_TREE_VIEW( data->result_view ), TRUE ); exo_tree_view_set_single_click_timeout( EXO_TREE_VIEW( data->result_view ), SINGLE_CLICK_TIMEOUT ); } gtk_widget_show( data->result_view ); gtk_container_add( (GtkContainer*)gtk_builder_get_object(builder, "result_scroll"), data->result_view ); init_search_result( data ); g_signal_connect(data->result_view, "button-press-event", G_CALLBACK( on_view_button_press ), data ); /* buttons */ data->start_btn = (GtkWidget*)gtk_builder_get_object( builder, "start_btn" ); data->stop_btn = (GtkWidget*)gtk_builder_get_object( builder, "stop_btn" ); data->again_btn = (GtkWidget*)gtk_builder_get_object( builder, "again_btn" ); img = gtk_image_new_from_icon_name( GTK_STOCK_REFRESH, GTK_ICON_SIZE_BUTTON ); gtk_button_set_image( (GtkButton*)data->again_btn, img ); g_signal_connect(data->start_btn, "clicked", G_CALLBACK( on_start_search ), data ); g_signal_connect(data->stop_btn, "clicked", G_CALLBACK( on_stop_search ), data ); g_signal_connect(data->again_btn, "clicked", G_CALLBACK( on_search_again ), data ); gtk_entry_set_text( (GtkEntry*)data->fn_pattern_entry, "*" ); gtk_editable_select_region( (GtkEditable*)data->fn_pattern_entry, 0, -1 ); gtk_combo_box_set_active( (GtkComboBox*)data->size_lower_unit, 1 ); gtk_spin_button_set_range( (GtkSpinButton*)data->size_lower, 0, G_MAXINT ); gtk_combo_box_set_active( (GtkComboBox*)data->size_upper_unit, 2 ); gtk_spin_button_set_range( (GtkSpinButton*)data->size_upper, 0, G_MAXINT ); gtk_combo_box_set_active( (GtkComboBox*)data->date_limit, 0 ); g_signal_connect( data->win, "delete-event", G_CALLBACK(gtk_widget_destroy), NULL ); pcmanfm_ref(); g_signal_connect( data->win, "destroy", G_CALLBACK(pcmanfm_unref), NULL ); int width = xset_get_int( "main_search", "x" ); int height = xset_get_int( "main_search", "y" ); if ( width && height ) gtk_window_set_default_size( GTK_WINDOW( data->win ), width, height ); gtk_widget_show( data->win ); }
static void exo_tree_view_single_click_timeout_destroy (gpointer user_data) { EXO_TREE_VIEW (user_data)->priv->single_click_timeout_id = -1; }
static gboolean exo_tree_view_single_click_timeout (gpointer user_data) { GtkTreeViewColumn *cursor_column; GtkTreeSelection *selection; GtkTreeModel *model; GtkTreePath *cursor_path; GtkTreeIter iter; ExoTreeView *tree_view = EXO_TREE_VIEW (user_data); gboolean hover_path_selected; GList *rows; GList *lp; //GDK_THREADS_ENTER (); //sfm not needed because called from g_idle? /* verify that we are in single-click mode, have focus and a hover path */ if (gtk_widget_has_focus (GTK_WIDGET (tree_view)) && tree_view->priv->single_click && tree_view->priv->hover_path != NULL) { /* transform the hover_path to a tree iterator */ model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)); if (model != NULL && gtk_tree_model_get_iter (model, &iter, tree_view->priv->hover_path)) { /* determine the current cursor path/column */ gtk_tree_view_get_cursor (GTK_TREE_VIEW (tree_view), &cursor_path, &cursor_column); /* be sure the row is fully visible */ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (tree_view), tree_view->priv->hover_path, 0, //sfm was cursor_column - caused horizontal scroll FALSE, 0.0f, 0.0f); /* determine the selection and change it appropriately */ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); if (gtk_tree_selection_get_mode (selection) == GTK_SELECTION_NONE) { /* just place the cursor on the row */ gtk_tree_view_set_cursor (GTK_TREE_VIEW (tree_view), tree_view->priv->hover_path, cursor_column, FALSE); } else if ((tree_view->priv->single_click_timeout_state & GDK_SHIFT_MASK) != 0 && gtk_tree_selection_get_mode (selection) == GTK_SELECTION_MULTIPLE) { /* check if the item is not already selected (otherwise do nothing) */ if (!gtk_tree_selection_path_is_selected (selection, tree_view->priv->hover_path)) { /* unselect all previously selected items */ gtk_tree_selection_unselect_all (selection); /* since we cannot access the anchor of a GtkTreeView, we * use the cursor instead which is usually the same row. */ if (G_UNLIKELY (cursor_path == NULL)) { /* place the cursor on the new row */ gtk_tree_view_set_cursor (GTK_TREE_VIEW (tree_view), tree_view->priv->hover_path, cursor_column, FALSE); } else { /* select all between the cursor and the current row */ gtk_tree_selection_select_range (selection, tree_view->priv->hover_path, cursor_path); } } } else { /* remember the previously selected rows as set_cursor() clears the selection */ rows = gtk_tree_selection_get_selected_rows (selection, NULL); /* check if the hover path is selected (as it will be selected after the set_cursor() call) */ hover_path_selected = gtk_tree_selection_path_is_selected (selection, tree_view->priv->hover_path); /* place the cursor on the hover row */ gtk_tree_view_set_cursor (GTK_TREE_VIEW (tree_view), tree_view->priv->hover_path, cursor_column, FALSE); /* restore the previous selection */ for (lp = rows; lp != NULL; lp = lp->next) { gtk_tree_selection_select_path (selection, lp->data); gtk_tree_path_free (lp->data); } g_list_free (rows); /* check what to do */ if ((gtk_tree_selection_get_mode (selection) == GTK_SELECTION_MULTIPLE || (gtk_tree_selection_get_mode (selection) == GTK_SELECTION_SINGLE && hover_path_selected)) && (tree_view->priv->single_click_timeout_state & GDK_CONTROL_MASK) != 0) { /* toggle the selection state of the row */ if (G_UNLIKELY (hover_path_selected)) gtk_tree_selection_unselect_path (selection, tree_view->priv->hover_path); else gtk_tree_selection_select_path (selection, tree_view->priv->hover_path); } else if (G_UNLIKELY (!hover_path_selected)) { /* unselect all other rows */ gtk_tree_selection_unselect_all (selection); /* select only the hover row */ gtk_tree_selection_select_path (selection, tree_view->priv->hover_path); } } /* cleanup */ if (G_LIKELY (cursor_path != NULL)) gtk_tree_path_free (cursor_path); } } //GDK_THREADS_LEAVE (); return FALSE; }
static gboolean exo_tree_view_motion_notify_event (GtkWidget *widget, GdkEventMotion *event) { ExoTreeView *tree_view = EXO_TREE_VIEW (widget); GtkTreePath *path; GdkCursor *cursor; GtkTreeViewColumn *column; /* check if the event occurred on the tree view internal window and we are in single-click mode */ if (event->window == gtk_tree_view_get_bin_window (GTK_TREE_VIEW (tree_view)) && tree_view->priv->single_click) { /* check if we're doing a rubberband selection right now (which means DnD is blocked) */ if (G_UNLIKELY (tree_view->priv->button_release_unblocks_dnd)) { /* we're doing a rubberband selection, so don't activate anything */ tree_view->priv->button_release_activates = FALSE; /* also be sure to reset the cursor */ gdk_window_set_cursor (event->window, NULL); } else { /* determine the path at the event coordinates */ if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (tree_view), event->x, event->y, &path, &column, NULL, NULL)) path = NULL; /* determine if the column is activable */ if( tree_view->priv->activable_column && column != tree_view->priv->activable_column ) { if(path) { gtk_tree_path_free(path); path = NULL; } } /* check if we have a new path */ if ((path == NULL && tree_view->priv->hover_path != NULL) || (path != NULL && tree_view->priv->hover_path == NULL) || (path != NULL && tree_view->priv->hover_path != NULL && gtk_tree_path_compare (path, tree_view->priv->hover_path) != 0)) { /* release the previous hover path */ if (tree_view->priv->hover_path != NULL) gtk_tree_path_free (tree_view->priv->hover_path); /* setup the new path */ tree_view->priv->hover_path = path; /* check if we're over a row right now */ if (G_LIKELY (path != NULL)) { /* setup the hand cursor to indicate that the row at the pointer can be activated with a single click */ cursor = gdk_cursor_new (GDK_HAND2); gdk_window_set_cursor (event->window, cursor); gdk_cursor_unref (cursor); } else { /* reset the cursor to its default */ gdk_window_set_cursor (event->window, NULL); } /* check if autoselection is enabled and the pointer is over a row */ if (G_LIKELY (tree_view->priv->single_click_timeout > 0 && tree_view->priv->hover_path != NULL)) { /* cancel any previous single-click timeout */ if (G_LIKELY (tree_view->priv->single_click_timeout_id >= 0)) g_source_remove (tree_view->priv->single_click_timeout_id); /* remember the current event state */ tree_view->priv->single_click_timeout_state = event->state; /* schedule a new single-click timeout */ tree_view->priv->single_click_timeout_id = g_timeout_add_full (G_PRIORITY_LOW, tree_view->priv->single_click_timeout, exo_tree_view_single_click_timeout, tree_view, exo_tree_view_single_click_timeout_destroy); } } else { /* release the path resources */ if (path != NULL) gtk_tree_path_free (path); } } } /* call the parent's motion notify handler */ return (*GTK_WIDGET_CLASS (exo_tree_view_parent_class)->motion_notify_event) (widget, event); }
static gboolean exo_tree_view_button_release_event (GtkWidget *widget, GdkEventButton *event) { GtkTreeViewColumn *column; GtkTreeSelection *selection; GtkTreePath *path; ExoTreeView *tree_view = EXO_TREE_VIEW (widget); /* verify that the release event is for the internal tree view window */ if (G_LIKELY (event->window == gtk_tree_view_get_bin_window (GTK_TREE_VIEW (tree_view)))) { /* check if we're in single-click mode and the button-release-event should emit a "row-activate" */ if (G_UNLIKELY (tree_view->priv->single_click && tree_view->priv->button_release_activates)) { /* reset the "release-activates" flag */ tree_view->priv->button_release_activates = FALSE; /* determine the path to the row that should be activated */ if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (tree_view), event->x, event->y, &path, &column, NULL, NULL)) { /* emit row-activated for the determined row */ if( ! tree_view->priv->activable_column || tree_view->priv->activable_column == column ) gtk_tree_view_row_activated (GTK_TREE_VIEW (tree_view), path, column); /* cleanup */ gtk_tree_path_free (path); } } else if ((event->state & gtk_accelerator_get_default_mod_mask ()) == 0 && !tree_view->priv->button_release_unblocks_dnd) { /* determine the path on which the button was released and select only this row, this way * the user is still able to alter the selection easily if all rows are selected. */ if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (tree_view), event->x, event->y, &path, &column, NULL, NULL)) { /* check if the path is selected */ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); if (gtk_tree_selection_path_is_selected (selection, path)) { /* unselect all rows */ gtk_tree_selection_unselect_all (selection); /* select the row and place the cursor on it */ gtk_tree_view_set_cursor (GTK_TREE_VIEW (tree_view), path, column, FALSE); } /* cleanup */ gtk_tree_path_free (path); } } } /* check if we need to re-enable drag and drop */ if (G_LIKELY (tree_view->priv->button_release_unblocks_dnd)) { gpointer drag_data = g_object_get_data (G_OBJECT (tree_view), I_("gtk-site-data")); if (G_LIKELY (drag_data != NULL)) { g_signal_handlers_unblock_matched (G_OBJECT (tree_view), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, drag_data); } tree_view->priv->button_release_unblocks_dnd = FALSE; } /* check if we need to re-enable rubberbanding */ if (G_UNLIKELY (tree_view->priv->button_release_enables_rubber_banding)) { gtk_tree_view_set_rubber_banding (GTK_TREE_VIEW (tree_view), TRUE); tree_view->priv->button_release_enables_rubber_banding = FALSE; } /* call the parent's button release handler */ return (*GTK_WIDGET_CLASS (exo_tree_view_parent_class)->button_release_event) (widget, event); }
static gboolean exo_tree_view_button_press_event (GtkWidget *widget, GdkEventButton *event) { GtkTreeSelection *selection; ExoTreeView *tree_view = EXO_TREE_VIEW (widget); GtkTreePath *path = NULL; gboolean result; GList *selected_paths = NULL; GList *lp; GtkTreeViewColumn* col; gboolean treat_as_blank = FALSE; /* by default we won't emit "row-activated" on button-release-events */ tree_view->priv->button_release_activates = FALSE; /* grab the tree selection */ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); /* be sure to cancel any pending single-click timeout */ if (G_UNLIKELY (tree_view->priv->single_click_timeout_id >= 0)) g_source_remove (tree_view->priv->single_click_timeout_id); /* check if the button press was on the internal tree view window */ if (G_LIKELY (event->window == gtk_tree_view_get_bin_window (GTK_TREE_VIEW (tree_view)))) { /* determine the path at the event coordinates */ if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (tree_view), event->x, event->y, &path, &col, NULL, NULL)) path = NULL; if( tree_view->priv->activable_column && col != tree_view->priv->activable_column ) { treat_as_blank = TRUE; if( path ) { gtk_tree_path_free( path ); path = NULL; } gtk_tree_selection_unselect_all (selection); } /* we unselect all selected items if the user clicks on an empty * area of the tree view and no modifier key is active. */ if (path == NULL && (event->state & gtk_accelerator_get_default_mod_mask ()) == 0) gtk_tree_selection_unselect_all (selection); /* completely ignore double-clicks in single-click mode */ if (tree_view->priv->single_click && event->type == GDK_2BUTTON_PRESS) { /* make sure we ignore the GDK_BUTTON_RELEASE * event for this GDK_2BUTTON_PRESS event. */ gtk_tree_path_free (path); return TRUE; } /* check if the next button-release-event should activate the selected row (single click support) */ tree_view->priv->button_release_activates = (tree_view->priv->single_click && event->type == GDK_BUTTON_PRESS && event->button == 1 && (event->state & gtk_accelerator_get_default_mod_mask ()) == 0); } /* unfortunately GtkTreeView will unselect rows except the clicked one, * which makes dragging from a GtkTreeView problematic. That's why we * remember the selected paths here and restore them later. */ if (event->type == GDK_BUTTON_PRESS && (event->state & gtk_accelerator_get_default_mod_mask ()) == 0 && path != NULL && gtk_tree_selection_path_is_selected (selection, path)) { /* if no custom select function is set, we simply use exo_noop_false here, * to tell the tree view that it may not alter the selection. */ //MOD disabled exo_noop_false due to GTK 2.20 bug https://bugzilla.gnome.org/show_bug.cgi?id=612802 /* if (G_LIKELY (selection->user_func == NULL)) gtk_tree_selection_set_select_function (selection, (GtkTreeSelectionFunc) exo_noop_false, NULL, NULL); else */ selected_paths = gtk_tree_selection_get_selected_rows (selection, NULL); } /* Rubberbanding in GtkTreeView 2.9.0 and above is rather buggy, unfortunately, and * doesn't interact properly with GTKs own DnD mechanism. So we need to block all * dragging here when pressing the mouse button on a not yet selected row if * rubberbanding is active, or disable rubberbanding when starting a drag. */ if (gtk_tree_selection_get_mode (selection) == GTK_SELECTION_MULTIPLE && gtk_tree_view_get_rubber_banding (GTK_TREE_VIEW (tree_view)) && event->button == 1 && event->type == GDK_BUTTON_PRESS) { /* check if clicked on empty area or on a not yet selected row */ if (G_LIKELY (path == NULL || !gtk_tree_selection_path_is_selected (selection, path))) { /* need to disable drag and drop because we're rubberbanding now */ gpointer drag_data = g_object_get_data (G_OBJECT (tree_view), I_("gtk-site-data")); if (G_LIKELY (drag_data != NULL)) { g_signal_handlers_block_matched (G_OBJECT (tree_view), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, drag_data); } /* remember to re-enable drag and drop later */ tree_view->priv->button_release_unblocks_dnd = TRUE; } else { /* need to disable rubberbanding because we're dragging now */ gtk_tree_view_set_rubber_banding (GTK_TREE_VIEW (tree_view), FALSE); /* remember to re-enable rubberbanding later */ tree_view->priv->button_release_enables_rubber_banding = TRUE; } } /* call the parent's button press handler */ result = (*GTK_WIDGET_CLASS (exo_tree_view_parent_class)->button_press_event) (widget, event); if( treat_as_blank ) gtk_tree_selection_unselect_all( selection ); /* restore previous selection if the path is still selected */ if (event->type == GDK_BUTTON_PRESS && (event->state & gtk_accelerator_get_default_mod_mask ()) == 0 && path != NULL && gtk_tree_selection_path_is_selected (selection, path)) { /* check if we have to restore paths */ if (G_LIKELY (gtk_tree_selection_get_select_function (selection) == (GtkTreeSelectionFunc) exo_noop_false)) { /* just reset the select function (previously set to exo_noop_false), * there's no clean way to do this, so what the heck. */ gtk_tree_selection_set_select_function (selection, NULL, NULL, NULL); } else { /* select all previously selected paths */ for (lp = selected_paths; lp != NULL; lp = lp->next) gtk_tree_selection_select_path (selection, lp->data); } } /* release the path (if any) */ if (G_LIKELY (path != NULL)) gtk_tree_path_free (path); /* release the selected paths list */ g_list_foreach (selected_paths, (GFunc) gtk_tree_path_free, NULL); g_list_free (selected_paths); return result; }