From 0d91cd758ba37276fdf09f819b14af61c6489174 Mon Sep 17 00:00:00 2001 From: Archisman Panigrahi Date: Tue, 21 Jul 2026 14:51:46 -0400 Subject: [PATCH 1/7] checkbox implemented except in list view --- libnemo-private/nemo-icon-canvas-item.c | 114 ++++++++++++++++++++++++ libnemo-private/nemo-icon-canvas-item.h | 3 + libnemo-private/nemo-icon-container.c | 45 ++++++++++ 3 files changed, 162 insertions(+) diff --git a/libnemo-private/nemo-icon-canvas-item.c b/libnemo-private/nemo-icon-canvas-item.c index 665f78f156..113d2d3bf3 100644 --- a/libnemo-private/nemo-icon-canvas-item.c +++ b/libnemo-private/nemo-icon-canvas-item.c @@ -51,6 +51,8 @@ /* gap between bottom of icon and start of text box */ #define LABEL_OFFSET_BESIDES 3 #define LABEL_LINE_SPACING 0 +#define SELECTION_CHECKBOX_SIZE 12 +#define SELECTION_CHECKBOX_MARGIN 2 /* special text height handling @@ -174,6 +176,9 @@ static void draw_pixbuf (GdkPixbuf cairo_t *cr, int x, int y); +static void draw_selection_checkbox (NemoIconCanvasItem *item, + cairo_t *cr, + EelIRect icon_rect); static PangoLayout *get_label_layout (PangoLayout **layout, NemoIconCanvasItem *item, const char *text); @@ -1288,6 +1293,88 @@ draw_pixbuf (GdkPixbuf *pixbuf, cairo_restore (cr); } +static void +draw_selection_checkbox (NemoIconCanvasItem *icon_item, + cairo_t *cr, + EelIRect icon_rect) +{ + GtkWidget *widget; + GtkStyleContext *context; + GdkRGBA border_color; + GdkRGBA fill_color; + GdkRGBA check_color; + double pixels_per_unit; + double checkbox_size; + double inset; + double checkbox_x; + double checkbox_y; + double check_x0; + double check_y0; + double check_x1; + double check_y1; + double check_x2; + double check_y2; + gboolean selected; + + widget = GTK_WIDGET (EEL_CANVAS_ITEM (icon_item)->canvas); + context = gtk_widget_get_style_context (widget); + pixels_per_unit = EEL_CANVAS_ITEM (icon_item)->canvas->pixels_per_unit; + checkbox_size = SELECTION_CHECKBOX_SIZE / pixels_per_unit; + checkbox_x = icon_rect.x0 + (SELECTION_CHECKBOX_MARGIN / pixels_per_unit); + checkbox_y = icon_rect.y0 + (SELECTION_CHECKBOX_MARGIN / pixels_per_unit); + selected = icon_item->details->is_highlighted_for_selection; + inset = MAX (1.0, 1.0 / pixels_per_unit); + + gtk_style_context_get_border_color (context, + selected ? GTK_STATE_FLAG_SELECTED : GTK_STATE_FLAG_NORMAL, + &border_color); + gtk_style_context_get_background_color (context, + selected ? GTK_STATE_FLAG_SELECTED : GTK_STATE_FLAG_NORMAL, + &fill_color); + gtk_style_context_get_color (context, + selected ? GTK_STATE_FLAG_SELECTED : GTK_STATE_FLAG_NORMAL, + &check_color); + + gtk_style_context_save (context); + gtk_style_context_set_state (context, + selected ? GTK_STATE_FLAG_SELECTED : GTK_STATE_FLAG_NORMAL); + + gdk_cairo_set_source_rgba (cr, &fill_color); + cairo_rectangle (cr, + checkbox_x, + checkbox_y, + checkbox_size, + checkbox_size); + cairo_fill_preserve (cr); + + gdk_cairo_set_source_rgba (cr, &border_color); + cairo_set_line_width (cr, inset); + cairo_stroke (cr); + + if (selected) { + double tick_width; + + tick_width = MAX (1.0, 2.0 / pixels_per_unit); + cairo_set_line_width (cr, tick_width); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + gdk_cairo_set_source_rgba (cr, &check_color); + + check_x0 = checkbox_x + checkbox_size * 0.22; + check_y0 = checkbox_y + checkbox_size * 0.55; + check_x1 = checkbox_x + checkbox_size * 0.42; + check_y1 = checkbox_y + checkbox_size * 0.72; + check_x2 = checkbox_x + checkbox_size * 0.78; + check_y2 = checkbox_y + checkbox_size * 0.30; + + cairo_move_to (cr, check_x0, check_y0); + cairo_line_to (cr, check_x1, check_y1); + cairo_line_to (cr, check_x2, check_y2); + cairo_stroke (cr); + } + + gtk_style_context_restore (context); +} + /* shared code to highlight or dim the passed-in pixbuf */ static cairo_surface_t * real_map_surface (NemoIconCanvasItem *icon_item) @@ -1387,6 +1474,8 @@ nemo_icon_canvas_item_draw (EelCanvasItem *item, icon_rect.x0, icon_rect.y0); cairo_surface_destroy (temp_surface); + draw_selection_checkbox (icon_item, cr, icon_rect); + /* Draw stretching handles (if necessary). */ draw_stretch_handles (icon_item, cr, &icon_rect); @@ -1988,6 +2077,31 @@ nemo_icon_canvas_item_hit_test_rectangle (NemoIconCanvasItem *item, EelIRect can return hit_test (item, canvas_rect); } +gboolean +nemo_icon_canvas_item_hit_test_selection_checkbox (NemoIconCanvasItem *item, + gdouble world_x, + gdouble world_y) +{ + EelDRect icon_rect; + double pixels_per_unit; + double checkbox_size; + double checkbox_x; + double checkbox_y; + + g_return_val_if_fail (NEMO_IS_ICON_CANVAS_ITEM (item), FALSE); + + icon_rect = nemo_icon_canvas_item_get_icon_rectangle (item); + pixels_per_unit = EEL_CANVAS_ITEM (item)->canvas->pixels_per_unit; + checkbox_size = SELECTION_CHECKBOX_SIZE / pixels_per_unit; + checkbox_x = icon_rect.x0 + (SELECTION_CHECKBOX_MARGIN / pixels_per_unit); + checkbox_y = icon_rect.y0 + (SELECTION_CHECKBOX_MARGIN / pixels_per_unit); + + return world_x >= checkbox_x && + world_x <= checkbox_x + checkbox_size && + world_y >= checkbox_y && + world_y <= checkbox_y + checkbox_size; +} + const char * nemo_icon_canvas_item_get_editable_text (NemoIconCanvasItem *icon_item) { diff --git a/libnemo-private/nemo-icon-canvas-item.h b/libnemo-private/nemo-icon-canvas-item.h index 7a6c083b4f..8314271e8e 100644 --- a/libnemo-private/nemo-icon-canvas-item.h +++ b/libnemo-private/nemo-icon-canvas-item.h @@ -74,6 +74,9 @@ void nemo_icon_canvas_item_set_emblems (NemoIconCanvasItem GList *emblem_pixbufs); void nemo_icon_canvas_item_set_show_stretch_handles (NemoIconCanvasItem *item, gboolean show_stretch_handles); +gboolean nemo_icon_canvas_item_hit_test_selection_checkbox (NemoIconCanvasItem *item, + gdouble world_x, + gdouble world_y); double nemo_icon_canvas_item_get_max_text_width (NemoIconCanvasItem *item); const char *nemo_icon_canvas_item_get_editable_text (NemoIconCanvasItem *icon_item); void nemo_icon_canvas_item_set_renaming (NemoIconCanvasItem *icon_item, diff --git a/libnemo-private/nemo-icon-container.c b/libnemo-private/nemo-icon-container.c index b24d3da2b1..9327ec41dc 100644 --- a/libnemo-private/nemo-icon-container.c +++ b/libnemo-private/nemo-icon-container.c @@ -5220,6 +5220,44 @@ handle_icon_button_press (NemoIconContainer *container, return TRUE; } +static gboolean +clicked_on_selection_checkbox (NemoIconContainer *container, + NemoIcon *icon, + GdkEventButton *event) +{ + double raw_x; + double raw_y; + double world_x; + double world_y; + EelDRect icon_rect; + double pixels_per_unit; + double checkbox_size; + double checkbox_x; + double checkbox_y; + + g_return_val_if_fail (NEMO_IS_ICON_CONTAINER (container), FALSE); + g_return_val_if_fail (icon != NULL, FALSE); + + raw_x = event->x; + raw_y = event->y; + eel_canvas_window_to_world (EEL_CANVAS (container), event->x, event->y, + &world_x, &world_y); + if (nemo_icon_canvas_item_hit_test_selection_checkbox (icon->item, world_x, world_y)) { + return TRUE; + } + + icon_rect = nemo_icon_canvas_item_get_icon_rectangle (icon->item); + pixels_per_unit = EEL_CANVAS (container)->pixels_per_unit; + checkbox_size = 12 / pixels_per_unit; + checkbox_x = icon_rect.x0 + (2 / pixels_per_unit); + checkbox_y = icon_rect.y0 + (2 / pixels_per_unit); + + return raw_x >= checkbox_x && + raw_x <= checkbox_x + checkbox_size && + raw_y >= checkbox_y && + raw_y <= checkbox_y + checkbox_size; +} + static int item_event_callback (EelCanvasItem *item, GdkEvent *event, @@ -5234,6 +5272,13 @@ item_event_callback (EelCanvasItem *item, g_assert (icon != NULL); if (event->type == GDK_BUTTON_PRESS) { + if (clicked_on_selection_checkbox (container, icon, &event->button)) { + icon_toggle_selected (container, icon); + g_signal_emit (container, + signals[SELECTION_CHANGED], 0); + return TRUE; + } + if (handle_icon_button_press (container, icon, &event->button)) { /* Stop the event from being passed along further. Returning * TRUE ain't enough. From 6d69aa779af96433b5364beeeb7b1d0564b42f1d Mon Sep 17 00:00:00 2001 From: Archisman Panigrahi Date: Tue, 21 Jul 2026 14:56:46 -0400 Subject: [PATCH 2/7] Checkbox in list view --- src/nemo-list-view.c | 122 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/src/nemo-list-view.c b/src/nemo-list-view.c index f027d22b49..2842ce3460 100644 --- a/src/nemo-list-view.c +++ b/src/nemo-list-view.c @@ -76,6 +76,7 @@ struct NemoListViewDetails { GtkTreeViewColumn *file_name_column; int file_name_column_num; + GtkCellRendererToggle *selection_toggle_cell; GtkCellRendererPixbuf *pixbuf_cell; GtkCellRendererText *file_name_cell; GList *cells; @@ -187,6 +188,14 @@ static void set_columns_settings_from_metadata_and_preferences (NemoListView * static void queue_update_visible_icons (NemoListView *view, gint delay); static NemoZoomLevel nemo_list_view_get_zoom_level (NemoView *view); static void prioritize_visible_files (NemoListView *view); +static void selection_toggle_cell_data_func (GtkTreeViewColumn *column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data); +static void selection_toggle_toggled_callback (GtkCellRendererToggle *cell, + gchar *path_str, + gpointer data); G_DEFINE_TYPE (NemoListView, nemo_list_view, NEMO_TYPE_VIEW); @@ -431,6 +440,85 @@ button_event_modifies_selection (GdkEventButton *event) return (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) != 0; } +static gboolean +clicked_on_selection_toggle (NemoListView *view, + GtkTreePath *path, + GdkEventButton *event) +{ + GtkTreeViewColumn *column; + int x_col_offset; + int x_cell_offset; + int width; + int start_x; + GtkTreePath *event_path = NULL; + + if (!gtk_tree_view_get_path_at_pos (view->details->tree_view, + event->x, event->y, + &event_path, &column, NULL, NULL)) { + return FALSE; + } + + if (path != NULL && gtk_tree_path_compare (path, event_path) != 0) { + gtk_tree_path_free (event_path); + return FALSE; + } + + gtk_tree_path_free (event_path); + + if (column != view->details->file_name_column) { + return FALSE; + } + + gtk_tree_view_column_cell_get_position (view->details->file_name_column, + GTK_CELL_RENDERER (view->details->selection_toggle_cell), + &x_cell_offset, &width); + x_col_offset = gtk_tree_view_column_get_x_offset (view->details->file_name_column); + start_x = x_col_offset + x_cell_offset; + + return event->x >= start_x && event->x <= start_x + width; +} + +static void +selection_toggle_cell_data_func (GtkTreeViewColumn *column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + NemoListView *view = NEMO_LIST_VIEW (data); + GtkTreePath *path; + gboolean active; + + path = gtk_tree_model_get_path (model, iter); + active = gtk_tree_selection_path_is_selected (gtk_tree_view_get_selection (view->details->tree_view), path); + g_object_set (cell, + "active", active, + "activatable", TRUE, + NULL); + gtk_tree_path_free (path); +} + +static void +selection_toggle_toggled_callback (GtkCellRendererToggle *cell, + gchar *path_str, + gpointer data) +{ + NemoListView *view = NEMO_LIST_VIEW (data); + GtkTreePath *path; + GtkTreeSelection *selection; + + path = gtk_tree_path_new_from_string (path_str); + selection = gtk_tree_view_get_selection (view->details->tree_view); + + if (gtk_tree_selection_path_is_selected (selection, path)) { + gtk_tree_selection_unselect_path (selection, path); + } else { + gtk_tree_selection_select_path (selection, path); + } + + gtk_tree_path_free (path); +} + static void nemo_list_view_did_not_drag (NemoListView *view, GdkEventButton *event) @@ -1148,6 +1236,19 @@ button_press_callback (GtkWidget *widget, GdkEventButton *event, gpointer callba call_parent = TRUE; if (gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y, &path, NULL, NULL, NULL)) { + if (view->details->selection_toggle_cell != NULL && + clicked_on_selection_toggle (view, path, event) && + (event->button == 1 || event->button == 2)) { + GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view); + if (gtk_tree_selection_path_is_selected (selection, path)) { + gtk_tree_selection_unselect_path (selection, path); + } else { + gtk_tree_selection_select_path (selection, path); + } + gtk_tree_path_free (path); + return GDK_EVENT_STOP; + } + if (g_settings_get_boolean (nemo_list_view_preferences, NEMO_PREFERENCES_LIST_VIEW_ENABLE_EXPANSION)) { gtk_widget_style_get (widget, @@ -2710,6 +2811,7 @@ create_and_set_up_tree_view (NemoListView *view) * has the icon in it.*/ if (!strcmp (name, "name")) { /* Create the file name column */ + GtkCellRendererToggle *toggle_cell; cell = gtk_cell_renderer_pixbuf_new (); view->details->pixbuf_cell = (GtkCellRendererPixbuf *)cell; @@ -2741,6 +2843,26 @@ create_and_set_up_tree_view (NemoListView *view) gtk_tree_view_column_set_reorderable (view->details->file_name_column, TRUE); gtk_tree_view_column_set_expand (view->details->file_name_column, TRUE); + toggle_cell = GTK_CELL_RENDERER_TOGGLE (gtk_cell_renderer_toggle_new ()); + view->details->selection_toggle_cell = toggle_cell; + g_object_set (toggle_cell, + "xpad", 0, + "ypad", 0, + "activatable", TRUE, + NULL); + gtk_tree_view_column_pack_start (view->details->file_name_column, + GTK_CELL_RENDERER (toggle_cell), + FALSE); + gtk_tree_view_column_set_cell_data_func (view->details->file_name_column, + GTK_CELL_RENDERER (toggle_cell), + selection_toggle_cell_data_func, + view, + NULL); + g_signal_connect (toggle_cell, + "toggled", + G_CALLBACK (selection_toggle_toggled_callback), + view); + gtk_tree_view_column_pack_start (view->details->file_name_column, cell, FALSE); gtk_tree_view_column_set_attributes (view->details->file_name_column, cell, From 3c6096bd445160ca3507eb6dd19bb769f64810bf Mon Sep 17 00:00:00 2001 From: Archisman Panigrahi Date: Tue, 21 Jul 2026 14:59:45 -0400 Subject: [PATCH 3/7] make checkbox appear on hover except for list view --- libnemo-private/nemo-icon-canvas-item.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libnemo-private/nemo-icon-canvas-item.c b/libnemo-private/nemo-icon-canvas-item.c index 113d2d3bf3..b7cf87bbcc 100644 --- a/libnemo-private/nemo-icon-canvas-item.c +++ b/libnemo-private/nemo-icon-canvas-item.c @@ -1316,6 +1316,10 @@ draw_selection_checkbox (NemoIconCanvasItem *icon_item, double check_y2; gboolean selected; + if (!icon_item->details->is_prelit) { + return; + } + widget = GTK_WIDGET (EEL_CANVAS_ITEM (icon_item)->canvas); context = gtk_widget_get_style_context (widget); pixels_per_unit = EEL_CANVAS_ITEM (icon_item)->canvas->pixels_per_unit; From d2e86aea18cda3cabe3bebeb1fb7ed5126ef388d Mon Sep 17 00:00:00 2001 From: Archisman Panigrahi Date: Tue, 21 Jul 2026 15:09:54 -0400 Subject: [PATCH 4/7] settings for item selection checkboxes --- .../nemo-file-management-properties.glade | 26 +++++++++++++++---- libnemo-private/nemo-global-preferences.h | 1 + libnemo-private/nemo-icon-canvas-item.c | 14 ++++++++++ libnemo-private/nemo-icon-container.c | 7 +++++ libnemo-private/org.nemo.gschema.xml | 5 ++++ src/nemo-file-management-properties.c | 5 ++++ 6 files changed, 53 insertions(+), 5 deletions(-) diff --git a/gresources/nemo-file-management-properties.glade b/gresources/nemo-file-management-properties.glade index 7bb4fffbec..3a2f540e42 100644 --- a/gresources/nemo-file-management-properties.glade +++ b/gresources/nemo-file-management-properties.glade @@ -1207,6 +1207,22 @@ along with . If not, see . 0 + + + Enable item selection checkboxes + True + True + False + True + 0 + True + + + False + False + 1 + + Ignore per-folder view preferences @@ -1220,7 +1236,7 @@ along with . If not, see . False False - 1 + 2 @@ -1236,7 +1252,7 @@ along with . If not, see . False False - 2 + 3 @@ -1253,7 +1269,7 @@ along with . If not, see . False False 3 - 3 + 4 @@ -1270,7 +1286,7 @@ along with . If not, see . False False 3 - 4 + 5 @@ -1286,7 +1302,7 @@ along with . If not, see . False False - 5 + 6 diff --git a/libnemo-private/nemo-global-preferences.h b/libnemo-private/nemo-global-preferences.h index 91f404854e..b7e1f0d4c2 100644 --- a/libnemo-private/nemo-global-preferences.h +++ b/libnemo-private/nemo-global-preferences.h @@ -145,6 +145,7 @@ typedef enum #define NEMO_PREFERENCES_START_WITH_DUAL_PANE "start-with-dual-pane" #define NEMO_PREFERENCES_RESTORE_TABS_ON_STARTUP "restore-tabs-on-startup" +#define NEMO_PREFERENCES_SHOW_SELECTION_CHECKBOXES "show-selection-checkboxes" #define NEMO_PREFERENCES_IGNORE_VIEW_METADATA "ignore-view-metadata" #define NEMO_PREFERENCES_SHOW_BOOKMARKS_IN_TO_MENUS "show-bookmarks-in-to-menus" #define NEMO_PREFERENCES_SHOW_PLACES_IN_TO_MENUS "show-places-in-to-menus" diff --git a/libnemo-private/nemo-icon-canvas-item.c b/libnemo-private/nemo-icon-canvas-item.c index b7cf87bbcc..f81d12c8ef 100644 --- a/libnemo-private/nemo-icon-canvas-item.c +++ b/libnemo-private/nemo-icon-canvas-item.c @@ -1315,6 +1315,13 @@ draw_selection_checkbox (NemoIconCanvasItem *icon_item, double check_x2; double check_y2; gboolean selected; + gboolean show_selection_checkboxes; + + show_selection_checkboxes = g_settings_get_boolean (nemo_preferences, + NEMO_PREFERENCES_SHOW_SELECTION_CHECKBOXES); + if (!show_selection_checkboxes) { + return; + } if (!icon_item->details->is_prelit) { return; @@ -2091,9 +2098,16 @@ nemo_icon_canvas_item_hit_test_selection_checkbox (NemoIconCanvasItem *item, double checkbox_size; double checkbox_x; double checkbox_y; + gboolean show_selection_checkboxes; g_return_val_if_fail (NEMO_IS_ICON_CANVAS_ITEM (item), FALSE); + show_selection_checkboxes = g_settings_get_boolean (nemo_preferences, + NEMO_PREFERENCES_SHOW_SELECTION_CHECKBOXES); + if (!show_selection_checkboxes) { + return FALSE; + } + icon_rect = nemo_icon_canvas_item_get_icon_rectangle (item); pixels_per_unit = EEL_CANVAS_ITEM (item)->canvas->pixels_per_unit; checkbox_size = SELECTION_CHECKBOX_SIZE / pixels_per_unit; diff --git a/libnemo-private/nemo-icon-container.c b/libnemo-private/nemo-icon-container.c index 9327ec41dc..78cedd0c7b 100644 --- a/libnemo-private/nemo-icon-container.c +++ b/libnemo-private/nemo-icon-container.c @@ -5225,6 +5225,7 @@ clicked_on_selection_checkbox (NemoIconContainer *container, NemoIcon *icon, GdkEventButton *event) { + gboolean show_selection_checkboxes; double raw_x; double raw_y; double world_x; @@ -5238,6 +5239,12 @@ clicked_on_selection_checkbox (NemoIconContainer *container, g_return_val_if_fail (NEMO_IS_ICON_CONTAINER (container), FALSE); g_return_val_if_fail (icon != NULL, FALSE); + show_selection_checkboxes = g_settings_get_boolean (nemo_preferences, + NEMO_PREFERENCES_SHOW_SELECTION_CHECKBOXES); + if (!show_selection_checkboxes) { + return FALSE; + } + raw_x = event->x; raw_y = event->y; eel_canvas_window_to_world (EEL_CANVAS (container), event->x, event->y, diff --git a/libnemo-private/org.nemo.gschema.xml b/libnemo-private/org.nemo.gschema.xml index abc2814d44..12b0e02561 100644 --- a/libnemo-private/org.nemo.gschema.xml +++ b/libnemo-private/org.nemo.gschema.xml @@ -351,6 +351,11 @@ Restore the previous window tabs on startup If set to true, Nemo will restore the last saved window tab state when launched without explicit locations. + + true + Enable item selection checkboxes + If set to true, Nemo will show clickable checkboxes on hovered items in icon and compact views, and beside all items in list view to make mouse-only multi-selection easier. + false Whether to ignore folder metadata for view zoom levels and layouts diff --git a/src/nemo-file-management-properties.c b/src/nemo-file-management-properties.c index 1566a467fd..8610a527d7 100644 --- a/src/nemo-file-management-properties.c +++ b/src/nemo-file-management-properties.c @@ -101,6 +101,7 @@ #define NEMO_FILE_MANAGEMENT_PROPERTIES_START_WITH_DUAL_PANE_WIDGET "start_with_dual_pane_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_RESTORE_TABS_ON_STARTUP_WIDGET "restore_tabs_on_startup_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_IGNORE_VIEW_METADATA_WIDGET "ignore_view_metadata_checkbutton" +#define NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_SELECTION_CHECKBOXES_WIDGET "show_selection_checkboxes_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_BOOKMARKS_IN_TO_MENUS_WIDGET "bookmarks_in_to_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_PLACES_IN_TO_MENUS_WIDGET "places_in_to_checkbutton" #define NEMO_FILE_MANAGEMENT_PROPERTIES_INHERIT_SHOW_THUMBNAILS_WIDGET "inherit_show_thumbnails_checkbutton" @@ -1076,6 +1077,10 @@ nemo_file_management_properties_dialog_setup (GtkBuilder *builder, NEMO_FILE_MANAGEMENT_PROPERTIES_IGNORE_VIEW_METADATA_WIDGET, NEMO_PREFERENCES_IGNORE_VIEW_METADATA); + bind_builder_bool (builder, nemo_preferences, + NEMO_FILE_MANAGEMENT_PROPERTIES_SHOW_SELECTION_CHECKBOXES_WIDGET, + NEMO_PREFERENCES_SHOW_SELECTION_CHECKBOXES); + bind_builder_bool (builder, nemo_preferences, NEMO_FILE_MANAGEMENT_PROPERTIES_BOOKMARKS_IN_TO_MENUS_WIDGET, NEMO_PREFERENCES_SHOW_BOOKMARKS_IN_TO_MENUS); From 834b1aa4d4bc9e2f1c125d573fc10f8dfb2b19fe Mon Sep 17 00:00:00 2001 From: Archisman Panigrahi Date: Tue, 21 Jul 2026 15:43:18 -0400 Subject: [PATCH 5/7] Fix checkmark size when zooming in/out Switch to symbolic icon --- libnemo-private/nemo-icon-canvas-item.c | 139 ++++++++++++------------ 1 file changed, 71 insertions(+), 68 deletions(-) diff --git a/libnemo-private/nemo-icon-canvas-item.c b/libnemo-private/nemo-icon-canvas-item.c index f81d12c8ef..2e660f99c9 100644 --- a/libnemo-private/nemo-icon-canvas-item.c +++ b/libnemo-private/nemo-icon-canvas-item.c @@ -51,7 +51,6 @@ /* gap between bottom of icon and start of text box */ #define LABEL_OFFSET_BESIDES 3 #define LABEL_LINE_SPACING 0 -#define SELECTION_CHECKBOX_SIZE 12 #define SELECTION_CHECKBOX_MARGIN 2 @@ -179,6 +178,9 @@ static void draw_pixbuf (GdkPixbuf static void draw_selection_checkbox (NemoIconCanvasItem *item, cairo_t *cr, EelIRect icon_rect); +static double get_selection_checkbox_size (GtkWidget *widget); +static GdkPixbuf *get_selection_checkbox_pixbuf (GtkWidget *widget, + gboolean selected); static PangoLayout *get_label_layout (PangoLayout **layout, NemoIconCanvasItem *item, const char *text); @@ -1293,29 +1295,73 @@ draw_pixbuf (GdkPixbuf *pixbuf, cairo_restore (cr); } +static double +get_selection_checkbox_size (GtkWidget *widget) +{ + int width = 0; + int height = 0; + + if (gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (widget), + GTK_ICON_SIZE_MENU, + &width, + &height)) { + return MAX (width, height); + } + + return 16.0; +} + +static GdkPixbuf * +get_selection_checkbox_pixbuf (GtkWidget *widget, + gboolean selected) +{ + GtkIconTheme *icon_theme; + GtkStyleContext *context; + GtkIconInfo *icon_info; + GdkRGBA fg_color; + GdkPixbuf *pixbuf; + int icon_size; + const char *icon_name; + GError *error = NULL; + gboolean was_symbolic = FALSE; + + context = gtk_widget_get_style_context (widget); + icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget)); + icon_size = (int) get_selection_checkbox_size (widget); + icon_name = selected ? "checkbox-checked-symbolic" : "checkbox-symbolic"; + + icon_info = gtk_icon_theme_lookup_icon (icon_theme, + icon_name, + icon_size, + GTK_ICON_LOOKUP_FORCE_SIZE); + if (icon_info == NULL) { + return NULL; + } + + gtk_style_context_get_color (context, GTK_STATE_FLAG_SELECTED, &fg_color); + pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info, + context, + &was_symbolic, + &error); + g_object_unref (icon_info); + + if (pixbuf == NULL) { + g_clear_error (&error); + } + + return pixbuf; +} + static void draw_selection_checkbox (NemoIconCanvasItem *icon_item, cairo_t *cr, EelIRect icon_rect) { GtkWidget *widget; - GtkStyleContext *context; - GdkRGBA border_color; - GdkRGBA fill_color; - GdkRGBA check_color; double pixels_per_unit; - double checkbox_size; - double inset; - double checkbox_x; - double checkbox_y; - double check_x0; - double check_y0; - double check_x1; - double check_y1; - double check_x2; - double check_y2; gboolean selected; gboolean show_selection_checkboxes; + GdkPixbuf *checkbox_pixbuf; show_selection_checkboxes = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_SELECTION_CHECKBOXES); @@ -1328,62 +1374,19 @@ draw_selection_checkbox (NemoIconCanvasItem *icon_item, } widget = GTK_WIDGET (EEL_CANVAS_ITEM (icon_item)->canvas); - context = gtk_widget_get_style_context (widget); pixels_per_unit = EEL_CANVAS_ITEM (icon_item)->canvas->pixels_per_unit; - checkbox_size = SELECTION_CHECKBOX_SIZE / pixels_per_unit; - checkbox_x = icon_rect.x0 + (SELECTION_CHECKBOX_MARGIN / pixels_per_unit); - checkbox_y = icon_rect.y0 + (SELECTION_CHECKBOX_MARGIN / pixels_per_unit); selected = icon_item->details->is_highlighted_for_selection; - inset = MAX (1.0, 1.0 / pixels_per_unit); - - gtk_style_context_get_border_color (context, - selected ? GTK_STATE_FLAG_SELECTED : GTK_STATE_FLAG_NORMAL, - &border_color); - gtk_style_context_get_background_color (context, - selected ? GTK_STATE_FLAG_SELECTED : GTK_STATE_FLAG_NORMAL, - &fill_color); - gtk_style_context_get_color (context, - selected ? GTK_STATE_FLAG_SELECTED : GTK_STATE_FLAG_NORMAL, - &check_color); - - gtk_style_context_save (context); - gtk_style_context_set_state (context, - selected ? GTK_STATE_FLAG_SELECTED : GTK_STATE_FLAG_NORMAL); - - gdk_cairo_set_source_rgba (cr, &fill_color); - cairo_rectangle (cr, - checkbox_x, - checkbox_y, - checkbox_size, - checkbox_size); - cairo_fill_preserve (cr); - - gdk_cairo_set_source_rgba (cr, &border_color); - cairo_set_line_width (cr, inset); - cairo_stroke (cr); - - if (selected) { - double tick_width; - - tick_width = MAX (1.0, 2.0 / pixels_per_unit); - cairo_set_line_width (cr, tick_width); - cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); - gdk_cairo_set_source_rgba (cr, &check_color); - - check_x0 = checkbox_x + checkbox_size * 0.22; - check_y0 = checkbox_y + checkbox_size * 0.55; - check_x1 = checkbox_x + checkbox_size * 0.42; - check_y1 = checkbox_y + checkbox_size * 0.72; - check_x2 = checkbox_x + checkbox_size * 0.78; - check_y2 = checkbox_y + checkbox_size * 0.30; - - cairo_move_to (cr, check_x0, check_y0); - cairo_line_to (cr, check_x1, check_y1); - cairo_line_to (cr, check_x2, check_y2); - cairo_stroke (cr); + checkbox_pixbuf = get_selection_checkbox_pixbuf (widget, selected); + if (checkbox_pixbuf == NULL) { + return; } - gtk_style_context_restore (context); + draw_pixbuf (checkbox_pixbuf, + cr, + icon_rect.x0 + (SELECTION_CHECKBOX_MARGIN / pixels_per_unit), + icon_rect.y0 + (SELECTION_CHECKBOX_MARGIN / pixels_per_unit)); + g_object_unref (checkbox_pixbuf); + } /* shared code to highlight or dim the passed-in pixbuf */ @@ -2110,7 +2113,7 @@ nemo_icon_canvas_item_hit_test_selection_checkbox (NemoIconCanvasItem *item, icon_rect = nemo_icon_canvas_item_get_icon_rectangle (item); pixels_per_unit = EEL_CANVAS_ITEM (item)->canvas->pixels_per_unit; - checkbox_size = SELECTION_CHECKBOX_SIZE / pixels_per_unit; + checkbox_size = get_selection_checkbox_size (GTK_WIDGET (EEL_CANVAS_ITEM (item)->canvas)) / pixels_per_unit; checkbox_x = icon_rect.x0 + (SELECTION_CHECKBOX_MARGIN / pixels_per_unit); checkbox_y = icon_rect.y0 + (SELECTION_CHECKBOX_MARGIN / pixels_per_unit); From aac56a66dc9554219e2e9bac665b8d3114b5ea66 Mon Sep 17 00:00:00 2001 From: Archisman Panigrahi Date: Tue, 21 Jul 2026 22:00:14 -0400 Subject: [PATCH 6/7] keep showing checkmark for selected icons --- libnemo-private/nemo-icon-canvas-item.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libnemo-private/nemo-icon-canvas-item.c b/libnemo-private/nemo-icon-canvas-item.c index 2e660f99c9..e7adbb8443 100644 --- a/libnemo-private/nemo-icon-canvas-item.c +++ b/libnemo-private/nemo-icon-canvas-item.c @@ -1369,13 +1369,13 @@ draw_selection_checkbox (NemoIconCanvasItem *icon_item, return; } - if (!icon_item->details->is_prelit) { + selected = icon_item->details->is_highlighted_for_selection; + if (!icon_item->details->is_prelit && !selected) { return; } widget = GTK_WIDGET (EEL_CANVAS_ITEM (icon_item)->canvas); pixels_per_unit = EEL_CANVAS_ITEM (icon_item)->canvas->pixels_per_unit; - selected = icon_item->details->is_highlighted_for_selection; checkbox_pixbuf = get_selection_checkbox_pixbuf (widget, selected); if (checkbox_pixbuf == NULL) { return; From fe9a2e51931dcd4dd3826b02aaf90e26578721dc Mon Sep 17 00:00:00 2001 From: Archisman Panigrahi Date: Wed, 22 Jul 2026 10:23:27 -0400 Subject: [PATCH 7/7] Do not turn checkbox feature on by default --- libnemo-private/org.nemo.gschema.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libnemo-private/org.nemo.gschema.xml b/libnemo-private/org.nemo.gschema.xml index 12b0e02561..24b7e8d674 100644 --- a/libnemo-private/org.nemo.gschema.xml +++ b/libnemo-private/org.nemo.gschema.xml @@ -352,7 +352,7 @@ If set to true, Nemo will restore the last saved window tab state when launched without explicit locations. - true + false Enable item selection checkboxes If set to true, Nemo will show clickable checkboxes on hovered items in icon and compact views, and beside all items in list view to make mouse-only multi-selection easier.