talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

folderview.c (81259B)


      1 /*
      2  * Claws Mail -- a GTK based, lightweight, and fast e-mail client
      3  * Copyright (C) 1999-2025 the Claws Mail team and Hiroyuki Yamamoto
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation; either version 3 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License
     16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
     17  */
     18 
     19 #include "defs.h"
     20 
     21 #include <glib.h>
     22 #include <glib/gi18n.h>
     23 #include <gdk/gdkkeysyms.h>
     24 #include <gtk/gtk.h>
     25 #include <stdio.h>
     26 #include <string.h>
     27 #include <stdlib.h>
     28 
     29 #include "main.h"
     30 #include "mainwindow.h"
     31 #include "folderview.h"
     32 #include "summaryview.h"
     33 #include "inputdialog.h"
     34 #include "manage_window.h"
     35 #include "alertpanel.h"
     36 #include "menu.h"
     37 #include "stock_pixmap.h"
     38 #include "procmsg.h"
     39 #include "utils.h"
     40 #include "gtkutils.h"
     41 #include "prefs_common.h"
     42 #include "prefs_account.h"
     43 #include "prefs_folder_item.h"
     44 #include "account.h"
     45 #include "folder.h"
     46 #include "foldersel.h"
     47 #include "inc.h"
     48 #include "statusbar.h"
     49 #include "hooks.h"
     50 #include "folderutils.h"
     51 #include "prefs_folder_column.h"
     52 #include "manual.h"
     53 #include "log.h"
     54 #include "gtkcmctree.h"
     55 
     56 #define COL_FOLDER_WIDTH	150
     57 #define COL_NUM_WIDTH		32
     58 
     59 static GList *folderview_list = NULL;
     60 
     61 static GtkStyle *bold_style;
     62 
     63 static GdkPixbuf *inboxxpm;
     64 static GdkPixbuf *inboxhrmxpm;
     65 static GdkPixbuf *inboxopenxpm;
     66 static GdkPixbuf *inboxopenhrmxpm;
     67 static GdkPixbuf *outboxxpm;
     68 static GdkPixbuf *outboxhrmxpm;
     69 static GdkPixbuf *outboxopenxpm;
     70 static GdkPixbuf *outboxopenhrmxpm;
     71 static GdkPixbuf *folderxpm;
     72 static GdkPixbuf *folderhrmxpm;
     73 static GdkPixbuf *folderopenxpm;
     74 static GdkPixbuf *folderopenhrmxpm;
     75 static GdkPixbuf *trashopenxpm;
     76 static GdkPixbuf *trashopenhrmxpm;
     77 static GdkPixbuf *trashxpm;
     78 static GdkPixbuf *trashhrmxpm;
     79 static GdkPixbuf *queuexpm;
     80 static GdkPixbuf *queuehrmxpm;
     81 static GdkPixbuf *queueopenxpm;
     82 static GdkPixbuf *queueopenhrmxpm;
     83 static GdkPixbuf *draftsxpm;
     84 static GdkPixbuf *draftsopenxpm;
     85 static GdkPixbuf *foldersubsxpm;
     86 static GdkPixbuf *foldersubsopenxpm;
     87 static GdkPixbuf *foldernoselectxpm;
     88 static GdkPixbuf *foldernoselectopenxpm;
     89 
     90 static GdkPixbuf *m_inboxxpm;
     91 static GdkPixbuf *m_inboxhrmxpm;
     92 static GdkPixbuf *m_inboxopenxpm;
     93 static GdkPixbuf *m_inboxopenhrmxpm;
     94 static GdkPixbuf *m_outboxxpm;
     95 static GdkPixbuf *m_outboxhrmxpm;
     96 static GdkPixbuf *m_outboxopenxpm;
     97 static GdkPixbuf *m_outboxopenhrmxpm;
     98 static GdkPixbuf *m_folderxpm;
     99 static GdkPixbuf *m_folderhrmxpm;
    100 static GdkPixbuf *m_folderopenxpm;
    101 static GdkPixbuf *m_folderopenhrmxpm;
    102 static GdkPixbuf *m_trashopenxpm;
    103 static GdkPixbuf *m_trashopenhrmxpm;
    104 static GdkPixbuf *m_trashxpm;
    105 static GdkPixbuf *m_trashhrmxpm;
    106 static GdkPixbuf *m_queuexpm;
    107 static GdkPixbuf *m_queuehrmxpm;
    108 static GdkPixbuf *m_queueopenxpm;
    109 static GdkPixbuf *m_queueopenhrmxpm;
    110 static GdkPixbuf *m_draftsxpm;
    111 static GdkPixbuf *m_draftsopenxpm;
    112 static GdkPixbuf *m_foldersubsxpm;
    113 static GdkPixbuf *m_foldernoselectxpm;
    114 
    115 static GdkPixbuf *newxpm;
    116 static GdkPixbuf *unreadxpm;
    117 static GdkPixbuf *readxpm;
    118 
    119 static void folderview_select_node	 (FolderView	*folderview,
    120 					  GtkCMCTreeNode	*node);
    121 static void folderview_set_folders	 (FolderView	*folderview);
    122 static void folderview_sort_folders	 (FolderView	*folderview,
    123 					  GtkCMCTreeNode	*root,
    124 					  Folder	*folder);
    125 static void folderview_append_folder	 (FolderView	*folderview,
    126 					  Folder	*folder);
    127 static void folderview_update_node	 (FolderView	*folderview,
    128 					  GtkCMCTreeNode	*node);
    129 
    130 static gint folderview_clist_compare	(GtkCMCList	*clist,
    131 					 gconstpointer	 ptr1,
    132 					 gconstpointer	 ptr2);
    133 
    134 /* callback functions */
    135 static gboolean folderview_button_pressed	(GtkWidget	*ctree,
    136 						 GdkEventButton	*event,
    137 						 FolderView	*folderview);
    138 static gboolean folderview_button_released	(GtkWidget	*ctree,
    139 						 GdkEventButton	*event,
    140 						 FolderView	*folderview);
    141 static gboolean folderview_key_pressed	(GtkWidget	*widget,
    142 					 GdkEventKey	*event,
    143 					 FolderView	*folderview);
    144 static void folderview_selected		(GtkCMCTree	*ctree,
    145 					 GtkCMCTreeNode	*row,
    146 					 gint		 column,
    147 					 FolderView	*folderview);
    148 static void folderview_tree_expanded	(GtkCMCTree	*ctree,
    149 					 GtkCMCTreeNode	*node,
    150 					 FolderView	*folderview);
    151 static void folderview_tree_collapsed	(GtkCMCTree	*ctree,
    152 					 GtkCMCTreeNode	*node,
    153 					 FolderView	*folderview);
    154 static void folderview_popup_close	(GtkMenuShell	*menu_shell,
    155 					 FolderView	*folderview);
    156 static void folderview_col_resized	(GtkCMCList	*clist,
    157 					 gint		 column,
    158 					 gint		 width,
    159 					 FolderView	*folderview);
    160 
    161 static void mark_all_read_unread_handler	(GtkAction	*action,
    162 					 gpointer	 data,
    163 					 gboolean	 recursive,
    164 					 gboolean	 read);
    165 
    166 static void mark_all_read_cb            (GtkAction 	*action,
    167 					 gpointer	 data);
    168 static void mark_all_unread_cb            (GtkAction 	*action,
    169 					 gpointer	 data);
    170 static void mark_all_read_recursive_cb  (GtkAction 	*action,
    171 					 gpointer	 data);
    172 static void mark_all_unread_recursive_cb  (GtkAction 	*action,
    173 					 gpointer	 data);
    174 
    175 static void folderview_empty_trash_cb	(GtkAction 	*action,
    176 					 gpointer	 data);
    177 
    178 static void folderview_send_queue_cb	(GtkAction 	*action,
    179 					 gpointer	 data);
    180 
    181 static void folderview_startup_folder_cb(GtkAction	*action,
    182 					 gpointer	 data);
    183 
    184 static void folderview_property_cb	(GtkAction 	*action,
    185 					 gpointer	 data);
    186 
    187 static void folderview_create_folder_node       (FolderView       *folderview,
    188 					  FolderItem       *item);
    189 static gboolean folderview_update_folder	 (gpointer 	    source,
    190 					  gpointer 	    userdata);
    191 static gboolean folderview_update_item_claws	 (gpointer 	    source,
    192 					  gpointer	    data);
    193 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
    194 				GdkEventButton *event);
    195 static void folderview_header_set_displayed_columns_cb(GtkAction *gaction,
    196 		gpointer data);
    197 static gboolean folderview_header_button_pressed(GtkWidget *widget,
    198 		GdkEvent *_event,
    199 		gpointer user_data);
    200 
    201 GHashTable *folderview_popups;
    202 
    203 static GtkActionEntry folderview_common_popup_entries[] =
    204 {
    205 	{"FolderViewPopup",                  NULL, "FolderViewPopup", NULL, NULL , NULL},
    206 	{"FolderViewPopup/MarkAllRead",      NULL, N_("Mark all re_ad"), NULL, NULL, G_CALLBACK(mark_all_read_cb) },
    207 	{"FolderViewPopup/MarkAllUnread",    NULL, N_("Mark all u_nread"), NULL, NULL, G_CALLBACK(mark_all_unread_cb) },
    208 	{"FolderViewPopup/MarkAllReadRec",   NULL, N_("Mark all read recursi_vely"), NULL, NULL, G_CALLBACK(mark_all_read_recursive_cb) },
    209 	{"FolderViewPopup/MarkAllUnreadRec", NULL, N_("Mark all unread recursi_vely"), NULL, NULL, G_CALLBACK(mark_all_unread_recursive_cb) },
    210 	{"FolderViewPopup/---",              NULL, "---", NULL, NULL , NULL},
    211 	{"FolderViewPopup/OpenFolder",       NULL, N_("Open on start-up"), NULL, NULL, G_CALLBACK(folderview_startup_folder_cb) },
    212 	{"FolderViewPopup/Properties",       NULL, N_("_Properties..."), NULL, NULL, G_CALLBACK(folderview_property_cb) },
    213 	{"FolderViewPopup/EmptyTrash",       NULL, N_("Empty _trash..."), NULL, NULL, G_CALLBACK(folderview_empty_trash_cb) },
    214 	{"FolderViewPopup/SendQueue",        NULL, N_("Send _queue..."), NULL, NULL, G_CALLBACK(folderview_send_queue_cb) },
    215 
    216 };
    217 
    218 static GtkActionEntry folderview_header_popup_entries[] =
    219 {
    220 	{"FolderViewHeaderPopup",                     NULL, "FolderViewHeaderPopup", NULL, NULL, NULL },
    221 	{"FolderViewHeaderPopup/SetDisplayedColumns", NULL, N_("Set Displayed columns"), NULL, NULL, G_CALLBACK(folderview_header_set_displayed_columns_cb) }
    222 };
    223 
    224 void folderview_initialize(void)
    225 {
    226 	FolderViewPopup *fpopup;
    227 
    228 	fpopup = g_new0(FolderViewPopup, 1);
    229 
    230 	fpopup->klass = "common";
    231 	fpopup->path = "<CommonFolder>";
    232 	fpopup->entries = folderview_common_popup_entries;
    233 	fpopup->n_entries = G_N_ELEMENTS(folderview_common_popup_entries);
    234 	fpopup->set_sensitivity = NULL;
    235 
    236 	folderview_popups = g_hash_table_new(g_str_hash, g_str_equal);
    237 	g_hash_table_insert(folderview_popups, "common", fpopup);
    238 }
    239 
    240 static GtkActionGroup *create_action_group(FolderView *folderview, FolderViewPopup *fpopup)
    241 {
    242 	FolderViewPopup *fpopup_common;
    243 	GtkActionGroup *action_group;
    244 
    245 	action_group = cm_menu_create_action_group(
    246 				fpopup->path,
    247 				fpopup->entries, fpopup->n_entries,
    248 				(gpointer)folderview);
    249 
    250 	if (fpopup->toggle_entries)
    251 		gtk_action_group_add_toggle_actions(action_group, fpopup->toggle_entries,
    252 				fpopup->n_toggle_entries,
    253 				(gpointer)folderview);
    254 	if (fpopup->radio_entries)
    255 		gtk_action_group_add_radio_actions(action_group, fpopup->radio_entries,
    256 				fpopup->n_radio_entries, fpopup->radio_default,
    257 				G_CALLBACK(fpopup->radio_callback),
    258 				(gpointer)folderview);
    259 
    260 	fpopup_common = g_hash_table_lookup(folderview_popups, "common");
    261 	if (fpopup_common != fpopup) {
    262 		gtk_action_group_add_actions(action_group, fpopup_common->entries,
    263 				fpopup_common->n_entries,
    264 				(gpointer)folderview);
    265 		if (fpopup_common->toggle_entries)
    266 			gtk_action_group_add_toggle_actions(action_group, fpopup_common->toggle_entries,
    267 					fpopup_common->n_toggle_entries,
    268 					(gpointer)folderview);
    269 		if (fpopup_common->radio_entries)
    270 			gtk_action_group_add_radio_actions(action_group, fpopup_common->radio_entries,
    271 					fpopup_common->n_radio_entries, fpopup_common->radio_default,
    272 					G_CALLBACK(fpopup_common->radio_callback),
    273 					(gpointer)folderview);
    274 	}
    275 
    276 	return action_group;
    277 }
    278 
    279 static void create_action_groups(gpointer key, gpointer value, gpointer data)
    280 {
    281 	FolderView *folderview = data;
    282 	FolderViewPopup *fpopup = value;
    283 	GtkActionGroup *group;
    284 
    285 	group = create_action_group(folderview, fpopup);
    286 	g_hash_table_insert(folderview->popups, fpopup->klass, group);
    287 }
    288 
    289 static void folderview_column_set_titles(FolderView *folderview)
    290 {
    291 	GtkWidget *ctree = folderview->ctree;
    292 	GtkWidget *label_folder;
    293 	GtkWidget *label_new;
    294 	GtkWidget *label_unread;
    295 	GtkWidget *label_total;
    296 	GtkWidget *hbox_folder;
    297 	GtkWidget *hbox_new;
    298 	GtkWidget *hbox_unread;
    299 	GtkWidget *hbox_total;
    300 	gint *col_pos = folderview->col_pos;
    301 
    302 	debug_print("setting titles...\n");
    303 	gtk_widget_realize(folderview->ctree);
    304 	gtk_widget_show_all(folderview->scrolledwin);
    305 
    306 	/* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
    307 	 * instead text (text overflows making them unreadable and ugly) */
    308 	stock_pixbuf_gdk(STOCK_PIXMAP_NEW, &newxpm);
    309 	stock_pixbuf_gdk(STOCK_PIXMAP_UNREAD, &unreadxpm);
    310 	stock_pixbuf_gdk(STOCK_PIXMAP_READ, &readxpm);
    311 
    312 	label_folder = gtk_label_new(_("Folder"));
    313 	label_new = gtk_image_new_from_pixbuf(newxpm);
    314 	label_unread = gtk_image_new_from_pixbuf(unreadxpm);
    315 	label_total = gtk_image_new_from_pixbuf(readxpm);
    316 
    317 	gtk_cmclist_column_titles_active(GTK_CMCLIST(ctree));
    318 
    319 	hbox_folder = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
    320 	hbox_new = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
    321 	hbox_unread = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
    322 	hbox_total = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
    323 
    324 	/* left justified */
    325 	gtk_box_pack_start(GTK_BOX(hbox_folder), label_folder, TRUE, TRUE, 0);
    326 	gtk_widget_set_halign(label_folder, GTK_ALIGN_START);
    327 	gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
    328 	gtk_widget_set_halign(label_new, GTK_ALIGN_END);
    329 	gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
    330 	gtk_widget_set_halign(label_unread, GTK_ALIGN_END);
    331 	gtk_box_pack_start(GTK_BOX(hbox_total), label_total, TRUE, TRUE, 0);
    332 	gtk_widget_set_halign(label_total, GTK_ALIGN_END);
    333 
    334 	gtk_widget_show_all(hbox_folder);
    335 	gtk_widget_show_all(hbox_new);
    336 	gtk_widget_show_all(hbox_unread);
    337 	gtk_widget_show_all(hbox_total);
    338 
    339 	gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree),col_pos[F_COL_FOLDER],hbox_folder);
    340 	gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree),col_pos[F_COL_NEW],hbox_new);
    341 	gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree),col_pos[F_COL_UNREAD],hbox_unread);
    342 	gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree),col_pos[F_COL_TOTAL],hbox_total);
    343 
    344 	gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_NEW], _("New"));
    345 	gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_UNREAD], _("Unread"));
    346 	gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_TOTAL], _("Total"));
    347 }
    348 
    349 static gboolean folderview_popup_menu(GtkWidget *widget, gpointer data)
    350 {
    351 	FolderView *folderview = (FolderView *)data;
    352 	GdkEventButton event;
    353 	if (folderview_get_selected_item(folderview) == NULL)
    354 		return FALSE;
    355 
    356 	event.button = 3;
    357 	event.time = gtk_get_current_event_time();
    358 
    359 	folderview_set_sens_and_popup_menu(folderview, -1,
    360 				&event);
    361 
    362 	return TRUE;
    363 }
    364 
    365 
    366 static GtkWidget *folderview_ctree_create(FolderView *folderview)
    367 {
    368 	GtkWidget *ctree;
    369 	gint *col_pos;
    370 	FolderColumnState *col_state;
    371 	FolderColumnType type;
    372 	gchar *titles[N_FOLDER_COLS];
    373 	gint i;
    374 	GtkWidget *scrolledwin = folderview->scrolledwin;
    375 
    376 	debug_print("creating tree...\n");
    377 	memset(titles, 0, sizeof(titles));
    378 
    379 	col_state = prefs_folder_column_get_config();
    380 	memset(titles, 0, sizeof(titles));
    381 
    382 	col_pos = folderview->col_pos;
    383 
    384 	for (i = 0; i < N_FOLDER_COLS; i++) {
    385 		folderview->col_state[i] = col_state[i];
    386 		type = col_state[i].type;
    387 		col_pos[type] = i;
    388 	}
    389 
    390 	titles[col_pos[F_COL_FOLDER]] = _("Folder");
    391 	titles[col_pos[F_COL_NEW]]    = _("New");
    392 	titles[col_pos[F_COL_UNREAD]] = _("Unread");
    393 	/* TRANSLATORS: This in Number sign in American style */
    394 	titles[col_pos[F_COL_TOTAL]]  = _("#");
    395 
    396 	ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, col_pos[F_COL_FOLDER],
    397 					   titles);
    398 
    399 	gtk_widget_set_name(GTK_WIDGET(ctree), "folderview_sctree");
    400 
    401 	if (prefs_common.show_col_headers == FALSE)
    402 		gtk_cmclist_column_titles_hide(GTK_CMCLIST(ctree));
    403 
    404 
    405 	gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
    406 	gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree), col_pos[F_COL_NEW],
    407 					   GTK_JUSTIFY_RIGHT);
    408 	gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree),
    409 					   col_pos[F_COL_UNREAD],
    410 					   GTK_JUSTIFY_RIGHT);
    411 	gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree),
    412 					   col_pos[F_COL_TOTAL],
    413 					   GTK_JUSTIFY_RIGHT);
    414 	gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
    415 			     GTK_CMCTREE_EXPANDER_TRIANGLE);
    416 
    417 	gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
    418 	gtk_sctree_set_recursive_expand(GTK_SCTREE(ctree), FALSE);
    419 
    420 	gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
    421 	gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree), folderview_clist_compare);
    422 
    423 	/* don't let title buttons take key focus */
    424 	for (i = 0; i < N_FOLDER_COLS; i++) {
    425 		gtk_widget_set_can_focus(GTK_CMCLIST(ctree)->column[i].button, FALSE);
    426 		gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), col_pos[i],
    427 				   prefs_common.folder_col_size[i]);
    428 		gtk_cmclist_set_column_visibility
    429 			(GTK_CMCLIST(ctree), i, col_state[i].visible);
    430 
    431 		g_signal_connect(G_OBJECT(GTK_CMCLIST(ctree)->column[i].button),
    432 					"button-press-event",
    433 					G_CALLBACK(folderview_header_button_pressed),
    434 					folderview);
    435 	}
    436 
    437 	g_signal_connect(G_OBJECT(ctree), "key_press_event",
    438 			 G_CALLBACK(folderview_key_pressed),
    439 			 folderview);
    440 	g_signal_connect(G_OBJECT(ctree), "button_press_event",
    441 			 G_CALLBACK(folderview_button_pressed),
    442 			 folderview);
    443 	g_signal_connect(G_OBJECT(ctree), "popup-menu",
    444 			 G_CALLBACK(folderview_popup_menu), folderview);
    445 	g_signal_connect(G_OBJECT(ctree), "button_release_event",
    446 			 G_CALLBACK(folderview_button_released),
    447 			 folderview);
    448 	g_signal_connect(G_OBJECT(ctree), "tree_select_row",
    449 			 G_CALLBACK(folderview_selected), folderview);
    450 
    451 	g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
    452 			       G_CALLBACK(folderview_tree_expanded),
    453 			       folderview);
    454 	g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
    455 			       G_CALLBACK(folderview_tree_collapsed),
    456 			       folderview);
    457 
    458 	g_signal_connect(G_OBJECT(ctree), "resize_column",
    459 			 G_CALLBACK(folderview_col_resized),
    460 			 folderview);
    461 
    462 	gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
    463 
    464 	return ctree;
    465 }
    466 
    467 void folderview_set_column_order(FolderView *folderview)
    468 {
    469 	GtkWidget *ctree = folderview->ctree;
    470 	FolderItem *item = folderview_get_selected_item(folderview);
    471 	FolderItem *sel_item = NULL, *op_item = NULL;
    472 	GtkWidget *scrolledwin = folderview->scrolledwin;
    473 
    474 	if (folderview->selected)
    475 		sel_item = folderview_get_selected_item(folderview);
    476 	if (folderview->opened)
    477 		op_item = folderview_get_opened_item(folderview);
    478 
    479 	debug_print("recreating tree...\n");
    480 	gtk_widget_destroy(folderview->ctree);
    481 
    482 
    483 	folderview->ctree = ctree = folderview_ctree_create(folderview);
    484 	gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
    485 					    GTK_CMCLIST(ctree)->hadjustment);
    486 	gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
    487 					    GTK_CMCLIST(ctree)->vadjustment);
    488 	gtk_widget_show(ctree);
    489 
    490 	if (sel_item)
    491 		folderview->selected = gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree), NULL, sel_item);
    492 	if (op_item)
    493 		folderview->opened = gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree), NULL, op_item);
    494 
    495 	folderview_set(folderview);
    496 	folderview_column_set_titles(folderview);
    497 
    498 	folderview_select(folderview,item);
    499 }
    500 
    501 FolderView *folderview_create(MainWindow *mainwin)
    502 {
    503 	FolderView *folderview;
    504 	GtkWidget *scrolledwin;
    505 	GtkWidget *ctree;
    506 
    507 	debug_print("Creating folder view...\n");
    508 	folderview = g_new0(FolderView, 1);
    509 
    510 	scrolledwin = gtk_scrolled_window_new(NULL, NULL);
    511 	gtk_widget_set_name(GTK_WIDGET(scrolledwin), "folderview");
    512 	gtk_scrolled_window_set_policy
    513 		(GTK_SCROLLED_WINDOW(scrolledwin),
    514 		 GTK_POLICY_AUTOMATIC,
    515 		 prefs_common.folderview_vscrollbar_policy);
    516 
    517 	folderview->scrolledwin  = scrolledwin;
    518 	ctree = folderview_ctree_create(folderview);
    519 	gtk_cmclist_set_row_height(GTK_CMCLIST(ctree), 0);
    520 
    521 	/* create popup factories */
    522 	folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
    523 	g_hash_table_foreach(folderview_popups, create_action_groups, folderview);
    524 
    525 	gtk_action_group_add_actions(mainwin->action_group,
    526 			folderview_header_popup_entries,
    527 			G_N_ELEMENTS(folderview_header_popup_entries),
    528 			(gpointer)folderview);
    529 
    530 	MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus", "FolderViewHeaderPopup", "FolderViewHeaderPopup", GTK_UI_MANAGER_MENU)
    531 	MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/FolderViewHeaderPopup", "SetDisplayedColumns", "FolderViewHeaderPopup/SetDisplayedColumns", GTK_UI_MANAGER_MENUITEM)
    532 
    533 	folderview->headerpopupmenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
    534 				gtk_ui_manager_get_widget(mainwin->ui_manager,
    535 					"/Menus/FolderViewHeaderPopup") ));
    536 
    537 	folderview->ctree        = ctree;
    538 
    539 	folderview->folder_update_callback_id =
    540 		hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
    541 	folderview->folder_item_update_callback_id =
    542 		hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
    543 
    544 	gtk_widget_show_all(scrolledwin);
    545 
    546 	folderview_list = g_list_append(folderview_list, folderview);
    547 	return folderview;
    548 }
    549 
    550 void folderview_init(FolderView *folderview)
    551 {
    552 	stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm);
    553 	stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm);
    554 	stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm);
    555 	stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm);
    556 	stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm);
    557 	stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm);
    558 	stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm);
    559 	stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm);
    560 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
    561 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm);
    562 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
    563 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm);
    564 	stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm);
    565 	stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm);
    566 	stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE, &trashxpm);
    567 	stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm);
    568 	stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm);
    569 	stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm);
    570 	stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm);
    571 	stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm);
    572 	stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm);
    573 	stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm);
    574 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_OPEN, &foldersubsopenxpm);
    575 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_CLOSE, &foldersubsxpm);
    576 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_OPEN, &foldernoselectopenxpm);
    577 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_CLOSE, &foldernoselectxpm);
    578 
    579 	stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm);
    580 	stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm);
    581 	stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm);
    582 	stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm);
    583 	stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm);
    584 	stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm);
    585 	stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm);
    586 	stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm);
    587 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm);
    588 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm);
    589 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm);
    590 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm);
    591 	stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm);
    592 	stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm);
    593 	stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm);
    594 	stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm);
    595 	stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm);
    596 	stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm);
    597 	stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm);
    598 	stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm);
    599 	stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm);
    600 	stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm);
    601 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_CLOSE_MARK, &m_foldersubsxpm);
    602 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_CLOSE_MARK, &m_foldernoselectxpm);
    603 }
    604 
    605 static gboolean folderview_defer_set(gpointer data)
    606 {
    607 	FolderView *folderview = (FolderView *)data;
    608 	MainWindow *mainwin = folderview->mainwin;
    609 
    610 	if (!mainwin)
    611 		return FALSE;
    612 	if (mainwin->lock_count)
    613 		return TRUE;
    614 
    615 	debug_print("doing deferred folderview_set now\n");
    616 	folderview_set(folderview);
    617 
    618 	folderview->deferred_refresh_id = 0;
    619 	return FALSE;
    620 }
    621 
    622 void folderview_set(FolderView *folderview)
    623 {
    624 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
    625 	MainWindow *mainwin = folderview->mainwin;
    626 	FolderItem *sel_item = NULL, *op_item = NULL;
    627 
    628 	if (!mainwin)
    629 		return;
    630 
    631 	if (mainwin->lock_count) {
    632 		if (folderview->deferred_refresh_id == 0)
    633 			folderview->deferred_refresh_id =
    634 				g_timeout_add(500, folderview_defer_set, folderview);
    635 		debug_print("deferred folderview_set\n");
    636 		return;
    637 	}
    638 
    639 	inc_lock();
    640 	debug_print("Setting folder info...\n");
    641 	STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
    642 
    643 	main_window_cursor_wait(mainwin);
    644 
    645 	if (folderview->selected)
    646 		sel_item = folderview_get_selected_item(folderview);
    647 	if (folderview->opened)
    648 		op_item = folderview_get_opened_item(folderview);
    649 
    650 	folderview->selected = NULL;
    651 	folderview->opened = NULL;
    652 
    653 	gtk_cmclist_freeze(GTK_CMCLIST(ctree));
    654 	gtk_cmclist_clear(GTK_CMCLIST(ctree));
    655 
    656 	folderview_set_folders(folderview);
    657 
    658 	if (sel_item)
    659 		folderview->selected = gtk_cmctree_find_by_row_data(ctree, NULL, sel_item);
    660 	if (op_item)
    661 		folderview->opened = gtk_cmctree_find_by_row_data(ctree, NULL, op_item);
    662 
    663 	gtk_cmclist_thaw(GTK_CMCLIST(ctree));
    664 	main_window_cursor_normal(mainwin);
    665 	STATUSBAR_POP(mainwin);
    666 	inc_unlock();
    667 }
    668 
    669 void folderview_set_all(void)
    670 {
    671 	GList *list;
    672 
    673 	for (list = folderview_list; list != NULL; list = list->next)
    674 		folderview_set((FolderView *)list->data);
    675 }
    676 
    677 void folderview_select(FolderView *folderview, FolderItem *item)
    678 {
    679 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
    680 	GtkCMCTreeNode *node;
    681 	GtkCMCTreeNode *old_selected = folderview->selected;
    682 
    683 	if (!item) return;
    684 
    685 	node = gtk_cmctree_find_by_row_data(ctree, NULL, item);
    686 	if (node) folderview_select_node(folderview, node);
    687 
    688 	if (old_selected != node)
    689 		folder_update_op_count();
    690 }
    691 
    692 static void mark_all_read_cb(GtkAction *action, gpointer data)
    693 {
    694 	mark_all_read_unread_handler(action, data, FALSE, TRUE);
    695 }
    696 
    697 static void mark_all_unread_cb(GtkAction *action, gpointer data)
    698 {
    699 	mark_all_read_unread_handler(action, data, FALSE, FALSE);
    700 }
    701 
    702 static void mark_all_read_recursive_cb(GtkAction *action, gpointer data)
    703 {
    704 	mark_all_read_unread_handler(action, data, TRUE, TRUE);
    705 }
    706 
    707 static void mark_all_unread_recursive_cb(GtkAction *action, gpointer data)
    708 {
    709 	mark_all_read_unread_handler(action, data, TRUE, FALSE);
    710 }
    711 
    712 static void mark_all_read_unread_handler(GtkAction *action, gpointer data,
    713 						gboolean recursive, gboolean read)
    714 {
    715 	FolderView *folderview = (FolderView *)data;
    716 	FolderItem *item;
    717 	AlertValue val;
    718 	gchar *message;
    719 	gchar *title;
    720 
    721 	item = folderview_get_selected_item(folderview);
    722 	if (item == NULL)
    723 		return;
    724 
    725 	if (read) {
    726 		title = _("Mark all as read");
    727 		message = recursive? _("Do you really want to mark all mails in this "
    728 							"folder and its subfolders as read?") :
    729 							_("Do you really want to mark all mails in this "
    730 							"folder as read?");
    731 	} else {
    732 		title = _("Mark all as unread");
    733 		message = recursive? _("Do you really want to mark all mails in this "
    734 							"folder and its subfolders as unread?") :
    735 							_("Do you really want to mark all mails in this "
    736 							"folder as unread?");
    737 	}
    738 	if (prefs_common.ask_mark_all_read) {
    739 		val = alertpanel_full(title, message,
    740 				      NULL, _("_No"), NULL, _("_Yes"), NULL, NULL,
    741 				      ALERTFOCUS_FIRST, TRUE, NULL, ALERT_QUESTION);
    742 
    743 		if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
    744 			return;
    745 		else if (val & G_ALERTDISABLE)
    746 			prefs_common.ask_mark_all_read = FALSE;
    747 	}
    748 
    749 	folder_item_update_freeze();
    750 	if (folderview->summaryview->folder_item != item && !recursive)
    751 		summary_lock(folderview->summaryview);
    752 	else
    753 		summary_freeze(folderview->summaryview);
    754 
    755 	if (read) {
    756 		if (recursive)
    757 			folderutils_mark_all_read_recursive(item, TRUE);
    758 		else {
    759 			folderutils_mark_all_read(item, TRUE);
    760 		}
    761 	} else {
    762 		if (recursive)
    763 			folderutils_mark_all_read_recursive(item, FALSE);
    764 		else {
    765 			folderutils_mark_all_read(item, FALSE);
    766 		}
    767 	}
    768 	if (folderview->summaryview->folder_item != item && !recursive)
    769 		summary_unlock(folderview->summaryview);
    770 	else
    771 		summary_thaw(folderview->summaryview);
    772 	folder_item_update_thaw();
    773 }
    774 
    775 static void folderview_select_node(FolderView *folderview, GtkCMCTreeNode *node)
    776 {
    777 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
    778 
    779 	cm_return_if_fail(node != NULL);
    780 
    781 	if (folderview->open_folder) {
    782 		return;
    783 	}
    784 
    785 	gtk_cmclist_freeze(GTK_CMCLIST(ctree));
    786 	gtkut_ctree_expand_parent_all(ctree, node);
    787 
    788 	folderview->open_folder = TRUE;
    789 	gtkut_ctree_set_focus_row(ctree, node);
    790 	gtk_cmctree_select(ctree, node);
    791 	gtk_cmclist_thaw(GTK_CMCLIST(ctree));
    792 	if ((folderview->summaryview->folder_item &&
    793 	    folderview->summaryview->folder_item->total_msgs > 0))
    794 		summary_select_node(folderview->summaryview,
    795 				    folderview->summaryview->selected, OPEN_SELECTED_ON_FOLDER_OPEN);
    796 	else
    797 		gtk_widget_grab_focus(folderview->ctree);
    798 }
    799 
    800 void folderview_unselect(FolderView *folderview)
    801 {
    802 	if (folderview->opened && !GTK_CMCTREE_ROW(folderview->opened)->children)
    803 		gtk_cmctree_collapse
    804 			(GTK_CMCTREE(folderview->ctree), folderview->opened);
    805 
    806 	folderview->selected = folderview->opened = NULL;
    807 }
    808 
    809 static GtkCMCTreeNode *folderview_find_next_with_flag(GtkCMCTree *ctree,
    810 						      GtkCMCTreeNode *node,
    811 						      MsgPermFlags flag)
    812 {
    813 	FolderItem *item;
    814 
    815 	if (node)
    816 		node = gtkut_ctree_node_next(ctree, node);
    817 	else
    818 		node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
    819 
    820 	for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
    821 		item = gtk_cmctree_node_get_row_data(ctree, node);
    822 		if (!item)
    823 			continue;
    824 		if (item->stype == F_TRASH || item->stype == F_DRAFT)
    825 			continue;
    826 		switch (flag) {
    827 		case MSG_UNREAD:
    828 			if((item->unread_msgs > 0) && (!item->prefs || !item->prefs->skip_on_goto_unread_or_new))
    829 				return node;
    830 			break;
    831 		case MSG_NEW:
    832 			if((item->new_msgs > 0) && (!item->prefs || !item->prefs->skip_on_goto_unread_or_new))
    833 				return node;
    834 			break;
    835 		case MSG_MARKED:
    836 			if(item->marked_msgs > 0)
    837 				return node;
    838 			break;
    839 		default:
    840 			if(item->total_msgs > 0)
    841 				return node;
    842 			break;
    843 		}
    844 	}
    845 
    846 	return NULL;
    847 }
    848 
    849 void folderview_select_next_with_flag(FolderView *folderview,
    850 				      MsgPermFlags flag)
    851 {
    852 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
    853 	GtkCMCTreeNode *node = NULL;
    854 	EntryAction last_summary_select_prio = prefs_common.summary_select_prio[0];
    855 
    856 	switch (flag) {
    857 	case MSG_UNREAD:
    858 		prefs_common.summary_select_prio[0] = ACTION_OLDEST_UNREAD;
    859 		break;
    860 	case MSG_NEW:
    861 		prefs_common.summary_select_prio[0] = ACTION_OLDEST_NEW;
    862 		break;
    863 	case MSG_MARKED:
    864 		prefs_common.summary_select_prio[0] = ACTION_OLDEST_MARKED;
    865 		break;
    866 	default:
    867 		prefs_common.summary_select_prio[0] = ACTION_OLDEST_LIST;
    868 		break;
    869 	}
    870 
    871 	node = folderview_find_next_with_flag(ctree, folderview->opened, flag);
    872 	if (node != NULL) {
    873 		folderview_select_node(folderview, node);
    874 		goto out;
    875 	}
    876 
    877 	if (!folderview->opened ||
    878 	    folderview->opened == GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list)) {
    879 		goto out;
    880 	}
    881 
    882 	/* search again from the first node */
    883 	node = folderview_find_next_with_flag(ctree, NULL, flag);
    884 	if (node != NULL)
    885 		folderview_select_node(folderview, node);
    886 
    887 out:
    888 	prefs_common.summary_select_prio[0] = last_summary_select_prio;
    889 }
    890 
    891 FolderItem *folderview_get_selected_item(FolderView *folderview)
    892 {
    893 	g_return_val_if_fail(folderview != NULL, NULL);
    894 	g_return_val_if_fail(folderview->ctree != NULL, NULL);
    895 
    896 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
    897 
    898 	if (!folderview->selected) return NULL;
    899 	return gtk_cmctree_node_get_row_data(ctree, folderview->selected);
    900 }
    901 
    902 FolderItem *folderview_get_opened_item(FolderView *folderview)
    903 {
    904 	g_return_val_if_fail(folderview != NULL, NULL);
    905 	g_return_val_if_fail(folderview->ctree != NULL, NULL);
    906 
    907 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
    908 
    909 	if (!folderview->opened) return NULL;
    910 	return gtk_cmctree_node_get_row_data(ctree, folderview->opened);
    911 }
    912 
    913 static void folderview_set_folders(FolderView *folderview)
    914 {
    915 	GList *list;
    916 	list = folder_get_list();
    917 
    918 	for (; list != NULL; list = list->next) {
    919 		folderview_append_folder(folderview, FOLDER(list->data));
    920 	}
    921 }
    922 
    923 static gchar *get_scan_str(FolderItem *item)
    924 {
    925 	if (item->path)
    926 		return g_strdup_printf(_("Scanning folder %s/%s..."),
    927 				      item->folder->name, item->path);
    928 	else
    929 		return g_strdup_printf(_("Scanning folder %s..."),
    930 				      item->folder->name);
    931 }
    932 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
    933 				      gpointer data)
    934 {
    935 	GList *list;
    936 	for (list = folderview_list; list != NULL; list = list->next) {
    937 		FolderView *folderview = (FolderView *)list->data;
    938 		MainWindow *mainwin = folderview->mainwin;
    939 		gchar *str = get_scan_str(item);
    940 
    941 		STATUSBAR_PUSH(mainwin, str);
    942 		STATUSBAR_POP(mainwin);
    943 		g_free(str);
    944 	}
    945 }
    946 
    947 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
    948 {
    949 	GtkWidget *window;
    950 	MainWindow *mainwin = mainwindow_get_mainwindow();
    951 	FolderView *folderview = NULL;
    952 	GtkAdjustment *pos = NULL;
    953 	gint height = 0;
    954 
    955 	cm_return_if_fail(folder != NULL);
    956 
    957 	if (!folder->klass->scan_tree) return;
    958 
    959 	if (rebuild &&
    960 	    alertpanel_full(_("Rebuild folder tree"),
    961 	    		 _("Rebuilding the folder tree will remove "
    962 			   "local caches. Do you want to continue?"),
    963 		       	 NULL, _("_No"), NULL, _("_Yes"), NULL, NULL,
    964 			 ALERTFOCUS_FIRST, FALSE, NULL, ALERT_WARNING)
    965 		!= G_ALERTALTERNATE) {
    966 		return;
    967 	}
    968 
    969 	inc_lock();
    970 	if (rebuild)
    971 		window = label_window_create(_("Rebuilding folder tree..."));
    972 	else
    973 		window = label_window_create(_("Scanning folder tree..."));
    974 
    975 	if (mainwin)
    976 		folderview = mainwin->folderview;
    977 
    978 	if (folderview) {
    979 		pos = gtk_scrolled_window_get_vadjustment(
    980 					GTK_SCROLLED_WINDOW(folderview->scrolledwin));
    981 		height = gtk_adjustment_get_value(pos);
    982 	}
    983 
    984 	folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
    985 	folder_scan_tree(folder, rebuild);
    986 	folder_set_ui_func(folder, NULL, NULL);
    987 
    988 	folderview_set_all();
    989 
    990 	if (folderview) {
    991 		pos = gtk_scrolled_window_get_vadjustment(
    992 					GTK_SCROLLED_WINDOW(folderview->scrolledwin));
    993 		gtk_adjustment_set_value(pos, height);
    994 	}
    995 	label_window_destroy(window);
    996 	inc_unlock();
    997 }
    998 
    999 /** folderview_check_new()
   1000  *  Scan and update the folder and return the
   1001  *  count the number of new messages since last check.
   1002  *  \param folder the folder to check for new messages
   1003  *  \return the number of new messages since last check
   1004  */
   1005 gint folderview_check_new(Folder *folder)
   1006 {
   1007 	GList *list;
   1008 	FolderItem *item;
   1009 	FolderView *folderview;
   1010 	GtkCMCTree *ctree;
   1011 	GtkCMCTreeNode *node;
   1012 	gint new_msgs = 0;
   1013 	gint former_new_msgs = 0;
   1014 	gint former_new = 0, former_unread = 0, former_total;
   1015 
   1016 	for (list = folderview_list; list != NULL; list = list->next) {
   1017 		folderview = (FolderView *)list->data;
   1018 		ctree = GTK_CMCTREE(folderview->ctree);
   1019 		folderview->scanning_folder = folder;
   1020 		inc_lock();
   1021 		main_window_lock(folderview->mainwin);
   1022 
   1023 		for (node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
   1024 		     node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
   1025 			gchar *str = NULL;
   1026 			item = gtk_cmctree_node_get_row_data(ctree, node);
   1027 			if (!item || !item->path || !item->folder) continue;
   1028 			if (item->no_select) continue;
   1029 			if (folder && folder != item->folder) continue;
   1030 			if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
   1031 			if (!item->prefs->newmailcheck) continue;
   1032 			if (item->scanning != ITEM_NOT_SCANNING) {
   1033 				debug_print("skipping %s, scanning\n",
   1034 					item->path ? item->path : item->name);
   1035 				continue;
   1036 			}
   1037 
   1038 			str = get_scan_str(item);
   1039 
   1040 			STATUSBAR_PUSH(folderview->mainwin, str);
   1041 			GTK_EVENTS_FLUSH();
   1042 			g_free(str);
   1043 
   1044 			folderview_scan_tree_func(item->folder, item, NULL);
   1045 			former_new    = item->new_msgs;
   1046 			former_unread = item->unread_msgs;
   1047 			former_total  = item->total_msgs;
   1048 
   1049 			if (item->folder->klass->scan_required &&
   1050 			    (item->folder->klass->scan_required(item->folder, item) ||
   1051 			     item->folder->inbox == item ||
   1052 			     item->opened == TRUE )) {
   1053 				if (folder_item_scan(item) < 0) {
   1054 					if (folder) {
   1055 						if (FOLDER_TYPE(item->folder) == F_NEWS || FOLDER_IS_LOCAL(folder)) {
   1056 							log_error(LOG_PROTOCOL, _("Couldn't scan folder %s\n"),
   1057 								item->path ? item->path:item->name);
   1058 							STATUSBAR_POP(folderview->mainwin);
   1059 							continue;
   1060 						} else if (!FOLDER_IS_LOCAL(folder)) {
   1061 							STATUSBAR_POP(folderview->mainwin);
   1062 							break;
   1063 						}
   1064 					}
   1065 				}
   1066 			} else if (!item->folder->klass->scan_required) {
   1067 				if (folder_item_scan(item) < 0) {
   1068 					if (folder && !FOLDER_IS_LOCAL(folder)) {
   1069 						STATUSBAR_POP(folderview->mainwin);
   1070 						break;
   1071 					}
   1072 				}
   1073 			}
   1074 			if (former_new    != item->new_msgs ||
   1075 			    former_unread != item->unread_msgs ||
   1076 			    former_total  != item->total_msgs)
   1077 				folderview_update_node(folderview, node);
   1078 
   1079 			new_msgs += item->new_msgs;
   1080 			former_new_msgs += former_new;
   1081 			STATUSBAR_POP(folderview->mainwin);
   1082 		}
   1083 		folderview->scanning_folder = NULL;
   1084 		main_window_unlock(folderview->mainwin);
   1085 		inc_unlock();
   1086 	}
   1087 
   1088 	folder_write_list();
   1089 	/* Number of new messages since last check is the just the difference
   1090 	 * between former_new_msgs and new_msgs. If new_msgs is less than
   1091 	 * former_new_msgs, that would mean another session accessed the folder
   1092 	 * and the result is not well defined.
   1093 	 */
   1094 	new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
   1095 	return new_msgs;
   1096 }
   1097 
   1098 void folderview_check_new_all(void)
   1099 {
   1100 	GList *list;
   1101 	GtkWidget *window;
   1102 	FolderView *folderview;
   1103 
   1104 	folderview = (FolderView *)folderview_list->data;
   1105 
   1106 	inc_lock();
   1107 	main_window_lock(folderview->mainwin);
   1108 	window = label_window_create
   1109 		(_("Checking for new messages in all folders..."));
   1110 
   1111 	list = folder_get_list();
   1112 	for (; list != NULL; list = list->next) {
   1113 		Folder *folder = list->data;
   1114 
   1115 		folderview_check_new(folder);
   1116 	}
   1117 
   1118 	folder_write_list();
   1119 	folderview_set_all();
   1120 
   1121 	label_window_destroy(window);
   1122 	main_window_unlock(folderview->mainwin);
   1123 	inc_unlock();
   1124 }
   1125 
   1126 static gboolean folderview_have_children_sub(FolderView *folderview,
   1127 					     FolderItem *item,
   1128 					     gboolean in_sub)
   1129 {
   1130 	GNode *node = NULL;
   1131 
   1132 	if (!item || !item->folder || !item->folder->node)
   1133 		return FALSE;
   1134 
   1135 	node = item->folder->node;
   1136 
   1137 	node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
   1138 	node = node->children;
   1139 
   1140 	if (in_sub && item->total_msgs > 0) {
   1141 		return TRUE;
   1142 	}
   1143 
   1144 	while (node != NULL) {
   1145 		if (node && node->data) {
   1146 			FolderItem *next_item = (FolderItem*) node->data;
   1147 			node = node->next;
   1148 			if (folderview_have_children_sub(folderview,
   1149 							 next_item, TRUE))
   1150 				return TRUE;
   1151 		}
   1152 	}
   1153 
   1154 	return FALSE;
   1155 }
   1156 
   1157 static gboolean folderview_have_children(FolderView *folderview,
   1158 					 FolderItem *item)
   1159 {
   1160 	return folderview_have_children_sub(folderview, item, FALSE);
   1161 }
   1162 
   1163 static gboolean folderview_have_new_children_sub(FolderView *folderview,
   1164 						 FolderItem *item,
   1165 						 gboolean in_sub)
   1166 {
   1167 	GNode *node = NULL;
   1168 
   1169 	if (!item || !item->folder || !item->folder->node)
   1170 		return FALSE;
   1171 
   1172 	node = item->folder->node;
   1173 
   1174 	node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
   1175 	node = node->children;
   1176 
   1177 	if (in_sub &&
   1178 	    (item->new_msgs > 0 ||
   1179 	    (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
   1180 		return TRUE;
   1181 	}
   1182 
   1183 	while (node != NULL) {
   1184 		if (node && node->data) {
   1185 			FolderItem *next_item = (FolderItem*) node->data;
   1186 			node = node->next;
   1187 			if (folderview_have_new_children_sub(folderview,
   1188 							     next_item, TRUE))
   1189 				return TRUE;
   1190 		}
   1191 	}
   1192 
   1193 	return FALSE;
   1194 }
   1195 
   1196 static gboolean folderview_have_new_children(FolderView *folderview,
   1197 					     FolderItem *item)
   1198 {
   1199 	return folderview_have_new_children_sub(folderview, item, FALSE);
   1200 }
   1201 
   1202 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
   1203 						    FolderItem *item,
   1204 						    gboolean in_sub)
   1205 {
   1206 	GNode *node = NULL;
   1207 
   1208 	if (!item || !item->folder || !item->folder->node)
   1209 		return FALSE;
   1210 
   1211 	node = item->folder->node;
   1212 
   1213 	node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
   1214 	node = node->children;
   1215 
   1216 	if (in_sub &&
   1217 	    (item->unread_msgs > 0 ||
   1218 	    (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
   1219 		return TRUE;
   1220 	}
   1221 
   1222 	while (node != NULL) {
   1223 		if (node && node->data) {
   1224 			FolderItem *next_item = (FolderItem*) node->data;
   1225 			node = node->next;
   1226 			if (folderview_have_unread_children_sub(folderview,
   1227 							        next_item,
   1228 								TRUE))
   1229 				return TRUE;
   1230 		}
   1231 	}
   1232 
   1233 	return FALSE;
   1234 }
   1235 
   1236 static gboolean folderview_have_unread_children(FolderView *folderview,
   1237 						FolderItem *item)
   1238 {
   1239 	return folderview_have_unread_children_sub(folderview, item, FALSE);
   1240 }
   1241 
   1242 static gboolean folderview_have_read_children_sub(FolderView *folderview,
   1243 						    FolderItem *item,
   1244 						    gboolean in_sub)
   1245 {
   1246 	GNode *node = NULL;
   1247 
   1248 	if (!item || !item->folder || !item->folder->node) {
   1249 		return FALSE;
   1250 	}
   1251 
   1252 	node = item->folder->node;
   1253 
   1254 	node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
   1255 	node = node->children;
   1256 
   1257 	if (in_sub &&
   1258 	    (((item->total_msgs > 0) &&
   1259 		(item->unread_msgs != (item->total_msgs - item->ignored_msgs))))) {
   1260 		return TRUE;
   1261 	}
   1262 
   1263 	while (node != NULL) {
   1264 		if (node && node->data) {
   1265 			FolderItem *next_item = (FolderItem*) node->data;
   1266 			node = node->next;
   1267 			if (folderview_have_read_children_sub(folderview,
   1268 							        next_item,
   1269 								TRUE)) {
   1270 				return TRUE;
   1271 			}
   1272 		}
   1273 	}
   1274 
   1275 	return FALSE;
   1276 }
   1277 
   1278 static gboolean folderview_have_read_children(FolderView *folderview,
   1279 						FolderItem *item)
   1280 {
   1281 	return folderview_have_read_children_sub(folderview, item, FALSE);
   1282 }
   1283 
   1284 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
   1285 						      FolderItem *item,
   1286 						      gboolean in_sub)
   1287 {
   1288 	GNode *node = NULL;
   1289 
   1290 	if (!item || !item->folder || !item->folder->node)
   1291 		return FALSE;
   1292 
   1293 	node = item->folder->node;
   1294 
   1295 	node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
   1296 	node = node->children;
   1297 
   1298 	if (in_sub && item->search_match){
   1299 		return TRUE;
   1300 	}
   1301 
   1302 	while (node != NULL) {
   1303 		if (node && node->data) {
   1304 			FolderItem *next_item = (FolderItem*) node->data;
   1305 			node = node->next;
   1306 			if (folderview_have_matching_children_sub(folderview,
   1307 							          next_item,
   1308 								  TRUE))
   1309 				return TRUE;
   1310 		}
   1311 	}
   1312 
   1313 	return FALSE;
   1314 }
   1315 
   1316 static gboolean folderview_have_matching_children(FolderView *folderview,
   1317 						  FolderItem *item)
   1318 {
   1319 	return folderview_have_matching_children_sub(folderview, item, FALSE);
   1320 }
   1321 
   1322 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
   1323 						    FolderItem *item,
   1324 						    gboolean in_sub)
   1325 {
   1326 	GNode *node = NULL;
   1327 
   1328 	if (!item || !item->folder || !item->folder->node)
   1329 		return FALSE;
   1330 
   1331 	node = item->folder->node;
   1332 
   1333 	node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
   1334 	node = node->children;
   1335 
   1336 	if (item->marked_msgs != 0) {
   1337 		return TRUE;
   1338 	}
   1339 
   1340 	while (node != NULL) {
   1341 		if (node && node->data) {
   1342 			FolderItem *next_item = (FolderItem*) node->data;
   1343 			node = node->next;
   1344 			if (folderview_have_marked_children_sub(folderview,
   1345 							        next_item, TRUE))
   1346 				return TRUE;
   1347 		}
   1348 	}
   1349 
   1350 	return FALSE;
   1351 }
   1352 
   1353 static gboolean folderview_have_marked_children(FolderView *folderview,
   1354 					     FolderItem *item)
   1355 {
   1356 	return folderview_have_marked_children_sub(folderview, item, FALSE);
   1357 }
   1358 
   1359 static void folderview_update_node(FolderView *folderview, GtkCMCTreeNode *node)
   1360 {
   1361 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
   1362 	GtkStyle *style = NULL, *prev_style;
   1363 	FolderItem *item;
   1364 	GdkPixbuf *xpm, *openxpm;
   1365 	static GdkPixbuf *searchicon;
   1366 	gboolean mark = FALSE;
   1367 	gchar *name;
   1368 	gchar *str;
   1369 	gboolean add_unread_mark;
   1370 	gboolean add_sub_match_mark;
   1371 	gboolean use_bold, use_color;
   1372 	gint *col_pos = folderview->col_pos;
   1373 	SpecialFolderItemType stype;
   1374 
   1375 	item = gtk_cmctree_node_get_row_data(ctree, node);
   1376 	cm_return_if_fail(item != NULL);
   1377 
   1378 	if (!GTK_CMCTREE_ROW(node)->expanded)
   1379 		mark = folderview_have_marked_children(folderview, item);
   1380 	else
   1381 		mark = (item->marked_msgs != 0);
   1382 
   1383 	stype = item->stype;
   1384 	if (stype == F_NORMAL) {
   1385 		if (folder_has_parent_of_type(item, F_TRASH))
   1386 			stype = F_TRASH;
   1387 		else if (folder_has_parent_of_type(item, F_DRAFT))
   1388 			stype = F_DRAFT;
   1389 		else if (folder_has_parent_of_type(item, F_OUTBOX))
   1390 			stype = F_OUTBOX;
   1391 		else if (folder_has_parent_of_type(item, F_QUEUE))
   1392 			stype = F_QUEUE;
   1393 	}
   1394 	switch (stype) {
   1395 	case F_INBOX:
   1396 		if (item->hide_read_msgs || item->hide_read_threads) {
   1397 			xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
   1398 			openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
   1399 		} else {
   1400 			xpm = mark?m_inboxxpm:inboxxpm;
   1401 			openxpm = mark?m_inboxopenxpm:inboxopenxpm;
   1402 		}
   1403 		break;
   1404 	case F_OUTBOX:
   1405 		if (item->hide_read_msgs || item->hide_read_threads) {
   1406 			xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
   1407 			openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
   1408 		} else {
   1409 			xpm = mark?m_outboxxpm:outboxxpm;
   1410 			openxpm = mark?m_outboxopenxpm:outboxopenxpm;
   1411 		}
   1412 		break;
   1413 	case F_QUEUE:
   1414 		if (item->hide_read_msgs || item->hide_read_threads) {
   1415 			xpm = mark?m_queuehrmxpm:queuehrmxpm;
   1416 			openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
   1417 		} else {
   1418 			xpm = mark?m_queuexpm:queuexpm;
   1419 			openxpm = mark?m_queueopenxpm:queueopenxpm;
   1420 		}
   1421 		break;
   1422 	case F_TRASH:
   1423 		if (item->hide_read_msgs || item->hide_read_threads) {
   1424 			xpm = mark?m_trashhrmxpm:trashhrmxpm;
   1425 			openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
   1426 		} else {
   1427 			xpm = mark?m_trashxpm:trashxpm;
   1428 			openxpm = mark?m_trashopenxpm:trashopenxpm;
   1429 		}
   1430 		break;
   1431 	case F_DRAFT:
   1432 		xpm = mark?m_draftsxpm:draftsxpm;
   1433 		openxpm = mark?m_draftsopenxpm:draftsopenxpm;
   1434 		break;
   1435 	default:
   1436 		if (!item->path &&
   1437 		    FOLDER_TYPE(item->folder) == F_IMAP &&
   1438 		    item->folder->account->imap_subsonly) {
   1439 			xpm = mark?m_foldersubsxpm:foldersubsxpm;
   1440 			openxpm = foldersubsopenxpm;
   1441 		} else if (item->no_select) {
   1442 			xpm = mark?m_foldernoselectxpm:foldernoselectxpm;
   1443 			openxpm = foldernoselectopenxpm;
   1444 		} else if (item->hide_read_msgs || item->hide_read_threads) {
   1445 			xpm = mark?m_folderhrmxpm:folderhrmxpm;
   1446 			openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
   1447 		} else {
   1448 			xpm = mark?m_folderxpm:folderxpm;
   1449 			openxpm = mark?m_folderopenxpm:folderopenxpm;
   1450 		}
   1451 	}
   1452 
   1453 	name = folder_item_get_name(item);
   1454 
   1455 	if (!GTK_CMCTREE_ROW(node)->expanded) {
   1456 		add_unread_mark = folderview_have_unread_children(
   1457 					folderview, item);
   1458 		add_sub_match_mark = folderview_have_matching_children(
   1459 					folderview, item);
   1460 	} else {
   1461 		add_unread_mark = FALSE;
   1462 		add_sub_match_mark = FALSE;
   1463 	}
   1464 
   1465 	if (item->search_match) {
   1466 		if (!searchicon) {
   1467 			stock_pixbuf_gdk(STOCK_PIXMAP_QUICKSEARCH,
   1468 			 &searchicon);
   1469 		}
   1470 		xpm = openxpm = searchicon;
   1471 	}
   1472 
   1473 	str = NULL;
   1474 	if (prefs_common.display_folder_unread) {
   1475 		if (folder_has_parent_of_type(item, F_QUEUE)) {
   1476 			/* only total_msgs matters here */
   1477 			if (item->total_msgs > 0) {
   1478 				/* show total number (should be equal to the unread number)
   1479 				   and signs if any */
   1480 				str = g_strdup_printf("%s (%d%s%s)",
   1481 							name, item->total_msgs,
   1482 							(add_unread_mark || add_sub_match_mark) ? "+" : "",
   1483 							(item->unreadmarked_msgs > 0) ? "!" : "");
   1484 			}
   1485 		} else {
   1486 			if (prefs_common.display_folder_unread == 1) {
   1487 				if (item->unread_msgs > 0) {
   1488 					/* show unread number and signs */
   1489 					str = g_strdup_printf("%s (%d%s%s)",
   1490 								name, item->unread_msgs,
   1491 								(add_unread_mark || add_sub_match_mark) ? "+" : "",
   1492 								(item->unreadmarked_msgs > 0) ? "!" : "");
   1493 				}
   1494 			} else {
   1495 				if (item->total_msgs > 0) {
   1496 					/* show unread number, total number and signs if any */
   1497 					str = g_strdup_printf("%s (%d/%d%s%s)",
   1498 								name, item->unread_msgs, item->total_msgs,
   1499 								(add_unread_mark || add_sub_match_mark) ? "+" : "",
   1500 								(item->unreadmarked_msgs > 0) ? "!" : "");
   1501 				}
   1502 			}
   1503 		}
   1504 		if ((str == NULL) &&
   1505 			(add_unread_mark || add_sub_match_mark || (item->unreadmarked_msgs > 0))) {
   1506 			/* no unread/total numbers, but at least one sign */
   1507 			str = g_strdup_printf("%s (%s%s)",
   1508 						name,
   1509 						(add_unread_mark || add_sub_match_mark) ? "+" : "",
   1510 						(item->unreadmarked_msgs > 0) ? "!" : "");
   1511 		}
   1512 	}
   1513 	if (str == NULL) {
   1514 		/* last fallback, folder name only or with +! sign */
   1515 		if (item->unreadmarked_msgs > 0 && add_sub_match_mark) {
   1516 			str = g_strdup_printf("%s%s",
   1517 						name, " (+!)");
   1518 		} else if (item->unreadmarked_msgs > 0) {
   1519 			str = g_strdup_printf("%s%s",
   1520 						name, " (!)");
   1521 		} else if (add_sub_match_mark) {
   1522 			str = g_strdup_printf("%s%s",
   1523 						name, " (+)");
   1524 		} else {
   1525 			str = g_strdup_printf("%s", name);
   1526 		}
   1527 	}
   1528 	gtk_cmctree_set_node_info(ctree, node, str, FOLDER_SPACING,
   1529 				xpm, openxpm,
   1530 				FALSE, GTK_CMCTREE_ROW(node)->expanded);
   1531 	g_free(str);
   1532 	g_free(name);
   1533 
   1534 	if (!folder_item_parent(item)) {
   1535 		gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_NEW],    "-");
   1536 		gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
   1537 		gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL],  "-");
   1538 	} else {
   1539 		gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_NEW],    item->new_msgs    > 0 ? itos(item->new_msgs)    : prefs_common.zero_replacement);
   1540 		gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], item->unread_msgs > 0 ? itos(item->unread_msgs) : prefs_common.zero_replacement);
   1541 		gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL],  item->total_msgs  > 0 ? itos(item->total_msgs)  : prefs_common.zero_replacement);
   1542 	}
   1543 
   1544 	if (folder_has_parent_of_type(item, F_OUTBOX) ||
   1545 	    folder_has_parent_of_type(item, F_TRASH)) {
   1546 		use_bold = use_color = FALSE;
   1547 	} else if (folder_has_parent_of_type(item, F_QUEUE)) {
   1548 		GSList *list = folder_item_get_msg_list(item);
   1549 		GSList *cur;
   1550 		use_bold = use_color = FALSE;
   1551 		for (cur = list; cur; cur = cur->next) {
   1552 			MsgInfo *msginfo = (MsgInfo *)cur->data;
   1553 			if (!MSG_IS_DELETED(msginfo->flags)) {
   1554 				/* highlight queue folder if there are any messages */
   1555 				use_bold = use_color = TRUE;
   1556 				break;
   1557 			}
   1558 		}
   1559 		if (!GTK_CMCTREE_ROW(node)->expanded &&
   1560 		    use_bold == FALSE &&
   1561 		    folderview_have_children(folderview, item))
   1562 			use_bold = use_color = TRUE;
   1563 		procmsg_msg_list_free(list);
   1564 	} else {
   1565 		/* if unread messages exist or target folder is set, print with bold font */
   1566 		use_bold = (item->unread_msgs > 0 || item->new_msgs > 0 || item->op_count > 0)
   1567 				|| add_unread_mark;
   1568 		/* if new messages exist, print with colored letter */
   1569 		use_color =
   1570 			(item->new_msgs > 0) ||
   1571 			(add_unread_mark &&
   1572 			 folderview_have_new_children(folderview, item));
   1573 	}
   1574 
   1575 	gtk_cmctree_node_set_foreground(ctree, node, NULL);
   1576 
   1577 	if (use_bold) {
   1578 		style = bold_style;
   1579 		if (item->op_count > 0)
   1580 			gtk_cmctree_node_set_foreground(ctree, node, &folderview->color_op);
   1581 		else if (use_color)
   1582 			gtk_cmctree_node_set_foreground(ctree, node, &folderview->color_new);
   1583 	} else if (use_color)
   1584 		gtk_cmctree_node_set_foreground(ctree, node, &folderview->color_new);
   1585 	else if (item->op_count > 0)
   1586 		gtk_cmctree_node_set_foreground(ctree, node, &folderview->color_op);
   1587 
   1588 	gtk_cmctree_node_set_row_style(ctree, node, style);
   1589 
   1590 	prev_style = gtk_cmctree_node_get_row_style(ctree, node);
   1591 	if (prev_style) {
   1592 		GtkStyle *ctree_style = gtk_widget_get_style(GTK_WIDGET(ctree));
   1593 
   1594 		style = gtk_style_copy(prev_style);
   1595 		style->text[GTK_STATE_NORMAL] = ctree_style->text[GTK_STATE_NORMAL];
   1596 		style->text[GTK_STATE_SELECTED] = ctree_style->text[GTK_STATE_SELECTED];
   1597 		gtk_cmctree_node_set_row_style(ctree, node, style);
   1598 		g_object_unref(style);
   1599 	}
   1600 
   1601 	if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
   1602 		folderview_update_node(folderview, node);
   1603 }
   1604 
   1605 static gboolean folderview_update_item_claws(gpointer source, gpointer data)
   1606 {
   1607 	FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
   1608 	FolderView *folderview = (FolderView *)data;
   1609 	GtkCMCTree *ctree;
   1610 	GtkCMCTreeNode *node;
   1611 	cm_return_val_if_fail(update_info != NULL, TRUE);
   1612 	cm_return_val_if_fail(update_info->item != NULL, TRUE);
   1613 	cm_return_val_if_fail(folderview != NULL, FALSE);
   1614 
   1615     	ctree = GTK_CMCTREE(folderview->ctree);
   1616 
   1617 	node = gtk_cmctree_find_by_row_data(ctree, NULL, update_info->item);
   1618 
   1619 	if (node) {
   1620 		if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
   1621 			folderview_update_node(folderview, node);
   1622 
   1623 		if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) &&
   1624 		     update_info->item == folderview->summaryview->folder_item &&
   1625 		     update_info->item != NULL)
   1626 			summary_show(folderview->summaryview, update_info->item, FALSE);
   1627 	}
   1628 
   1629 	return FALSE;
   1630 }
   1631 
   1632 static gboolean folderview_gnode_func(GtkCMCTree *ctree, guint depth,
   1633 				      GNode *gnode, GtkCMCTreeNode *cnode,
   1634 				      gpointer data)
   1635 {
   1636 	FolderView *folderview = (FolderView *)data;
   1637 	FolderItem *item = FOLDER_ITEM(gnode->data);
   1638 
   1639 	cm_return_val_if_fail(item != NULL, FALSE);
   1640 
   1641 	gtk_cmctree_node_set_row_data(ctree, cnode, item);
   1642 	folderview_update_node(folderview, cnode);
   1643 
   1644 	return TRUE;
   1645 }
   1646 
   1647 static void folderview_expand_func(GtkCMCTree *ctree, GtkCMCTreeNode *node,
   1648 				   gpointer data)
   1649 {
   1650 	FolderView *folderview = (FolderView *)data;
   1651 	FolderItem *item;
   1652 
   1653 	if (GTK_CMCTREE_ROW(node)->children) {
   1654 		item = gtk_cmctree_node_get_row_data(ctree, node);
   1655 		cm_return_if_fail(item != NULL);
   1656 
   1657 		if (!item->collapsed)
   1658 			gtk_cmctree_expand(ctree, node);
   1659 		else
   1660 			folderview_update_node(folderview, node);
   1661 	}
   1662 }
   1663 
   1664 static void set_special_folder(GtkCMCTree *ctree, FolderItem *item,
   1665 			       GtkCMCTreeNode *root, GtkCMCTreeNode **prev)
   1666 {
   1667 	if (item) {
   1668 		GtkCMCTreeNode *node, *parent, *sibling;
   1669 
   1670 		node = gtk_cmctree_find_by_row_data(ctree, root, item);
   1671 		if (!node)
   1672 			g_warning("%s not found", item->path);
   1673 		else {
   1674 			parent = GTK_CMCTREE_ROW(node)->parent;
   1675 			if (*prev && parent == GTK_CMCTREE_ROW(*prev)->parent)
   1676 				sibling = GTK_CMCTREE_ROW(*prev)->sibling;
   1677 			else
   1678 				sibling = GTK_CMCTREE_ROW(parent)->children;
   1679 			while (sibling) {
   1680 				FolderItem *tmp;
   1681 
   1682 				tmp = gtk_cmctree_node_get_row_data
   1683 					(ctree, sibling);
   1684 				if (tmp && tmp->stype != F_NORMAL)
   1685 					sibling = GTK_CMCTREE_ROW(sibling)->sibling;
   1686 				else
   1687 					break;
   1688 			}
   1689 			if (node != sibling)
   1690 				gtk_cmctree_move(ctree, node, parent, sibling);
   1691 		}
   1692 
   1693 		*prev = node;
   1694 	}
   1695 }
   1696 
   1697 static void folderview_sort_folders(FolderView *folderview, GtkCMCTreeNode *root,
   1698 				    Folder *folder)
   1699 {
   1700 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
   1701 	GtkCMCTreeNode *prev = NULL;
   1702 
   1703 	gtk_cmclist_freeze(GTK_CMCLIST(ctree));
   1704 	gtk_sctree_sort_recursive(ctree, root);
   1705 	if (root && GTK_CMCTREE_ROW(root)->parent) {
   1706 		gtk_cmclist_thaw(GTK_CMCLIST(ctree));
   1707 		return;
   1708 	}
   1709 	set_special_folder(ctree, folder->inbox, root, &prev);
   1710 	set_special_folder(ctree, folder->outbox, root, &prev);
   1711 	set_special_folder(ctree, folder->draft, root, &prev);
   1712 	set_special_folder(ctree, folder->queue, root, &prev);
   1713 	set_special_folder(ctree, folder->trash, root, &prev);
   1714 	gtk_cmclist_thaw(GTK_CMCLIST(ctree));
   1715 }
   1716 
   1717 static void folderview_append_folder(FolderView *folderview, Folder *folder)
   1718 {
   1719 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
   1720 	GtkCMCTreeNode *root;
   1721 
   1722 	cm_return_if_fail(folder != NULL);
   1723 
   1724 	root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
   1725 				      folderview_gnode_func, folderview);
   1726 	gtk_cmctree_pre_recursive(ctree, root, folderview_expand_func,
   1727 				folderview);
   1728 	folderview_sort_folders(folderview, root, folder);
   1729 }
   1730 
   1731 /* callback functions */
   1732 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
   1733 				GdkEventButton *event)
   1734 {
   1735 	FolderItem *item;
   1736 	Folder *folder;
   1737 	FolderViewPopup *fpopup;
   1738 	GtkActionGroup *action_group;
   1739 	GtkWidget *popup;
   1740 	FolderItem *special_trash = NULL, *special_queue = NULL;
   1741 	PrefsAccount *ac;
   1742 	GtkUIManager *ui_manager = gtk_ui_manager_new();
   1743 
   1744 	if (folderview->ui_manager)
   1745 		g_object_unref(folderview->ui_manager);
   1746 
   1747 	folderview->ui_manager = ui_manager;
   1748 	item = folderview_get_selected_item(folderview);
   1749 
   1750 	cm_return_if_fail(item != NULL);
   1751 	cm_return_if_fail(item->folder != NULL);
   1752 	folder = item->folder;
   1753 
   1754 	fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
   1755 
   1756 	if (fpopup != NULL)
   1757 		action_group = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
   1758 	else {
   1759 		fpopup = g_hash_table_lookup(folderview_popups, "common");
   1760 		action_group = g_hash_table_lookup(folderview->popups, "common");
   1761 	}
   1762 
   1763 	gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
   1764 	MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popup", "Popup", GTK_UI_MANAGER_MENUBAR)
   1765 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup", "FolderViewPopup", "FolderViewPopup", GTK_UI_MANAGER_MENU)
   1766 
   1767 	if (fpopup->add_menuitems)
   1768 		fpopup->add_menuitems(ui_manager, item);
   1769 
   1770 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MarkAllRead", "FolderViewPopup/MarkAllRead", GTK_UI_MANAGER_MENUITEM)
   1771 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MarkAllUnread", "FolderViewPopup/MarkAllUnread", GTK_UI_MANAGER_MENUITEM)
   1772 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MarkAllReadRec", "FolderViewPopup/MarkAllReadRec", GTK_UI_MANAGER_MENUITEM)
   1773 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MarkAllUnreadRec", "FolderViewPopup/MarkAllUnreadRec", GTK_UI_MANAGER_MENUITEM)
   1774 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "Separator1", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
   1775 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "OpenFolder", "FolderViewPopup/OpenFolder", GTK_UI_MANAGER_MENUITEM)
   1776 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "Properties", "FolderViewPopup/Properties", GTK_UI_MANAGER_MENUITEM)
   1777 
   1778 	if (fpopup->set_sensitivity != NULL)
   1779 		fpopup->set_sensitivity(ui_manager, item);
   1780 
   1781 	if (NULL != (ac = account_find_from_item(item))) {
   1782 		special_trash = account_get_special_folder(ac, F_TRASH);
   1783 		special_queue = account_get_special_folder(ac, F_QUEUE);
   1784 	}
   1785 
   1786 	if ((item == folder->trash || item == special_trash
   1787 	     || folder_has_parent_of_type(item, F_TRASH))) {
   1788 		MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorTrash", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
   1789 		MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "EmptyTrash", "FolderViewPopup/EmptyTrash", GTK_UI_MANAGER_MENUITEM)
   1790 	}
   1791 
   1792 	if ((item == folder->queue || item == special_queue
   1793 	     || folder_has_parent_of_type(item, F_QUEUE))) {
   1794 		MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorQueue", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
   1795 		MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SendQueue", "FolderViewPopup/SendQueue", GTK_UI_MANAGER_MENUITEM)
   1796 	}
   1797 
   1798 #define SET_SENS(name, sens) \
   1799 	cm_menu_set_sensitive_full(ui_manager, "Popup/"name, sens)
   1800 
   1801 	SET_SENS("FolderViewPopup/MarkAllRead", item->unread_msgs > 0);
   1802 	SET_SENS("FolderViewPopup/MarkAllUnread", (item->total_msgs > 0) &&
   1803 		(item->unread_msgs != (item->total_msgs - item->ignored_msgs)));
   1804 	SET_SENS("FolderViewPopup/MarkAllReadRec", folderview_have_unread_children(folderview,item));
   1805 	SET_SENS("FolderViewPopup/MarkAllUnreadRec", folderview_have_read_children(folderview,item));
   1806 	SET_SENS("FolderViewPopup/Properties", TRUE);
   1807 
   1808 	if (item->node->parent != NULL) {
   1809 		gchar *id = folder_item_get_identifier(item);
   1810 		SET_SENS("FolderViewPopup/OpenFolder", !prefs_common.goto_folder_on_startup
   1811 			|| strcmp(id, prefs_common.startup_folder));
   1812 		g_free(id);
   1813 	}
   1814 
   1815 	if (item == folder->trash || item == special_trash
   1816 	    || folder_has_parent_of_type(item, F_TRASH)) {
   1817 		GSList *msglist = folder_item_get_msg_list(item);
   1818 		SET_SENS("FolderViewPopup/EmptyTrash", msglist != NULL);
   1819 		procmsg_msg_list_free(msglist);
   1820 	}
   1821 	if (item == folder->queue || item == special_queue
   1822 	    || folder_has_parent_of_type(item, F_QUEUE)) {
   1823 		GSList *msglist = folder_item_get_msg_list(item);
   1824 		SET_SENS("FolderViewPopup/SendQueue", msglist != NULL);
   1825 		procmsg_msg_list_free(msglist);
   1826 	}
   1827 #undef SET_SENS
   1828 
   1829 	popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
   1830 			gtk_ui_manager_get_widget(ui_manager, "/Popup/FolderViewPopup")) );
   1831         g_signal_connect(G_OBJECT(popup), "selection_done",
   1832                          G_CALLBACK(folderview_popup_close),
   1833                          folderview);
   1834 	gtk_menu_popup_at_pointer(GTK_MENU(popup), NULL);
   1835 }
   1836 
   1837 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
   1838 					  FolderView *folderview)
   1839 {
   1840 	GtkCMCList *clist = GTK_CMCLIST(ctree);
   1841 	gint prev_row = -1, row = -1, column = -1;
   1842 
   1843 	if (!event) return FALSE;
   1844 	if (event->window != clist->clist_window) return FALSE;
   1845 
   1846 	if (event->button == 1 || event->button == 2) {
   1847 		if (!gtk_sctree_is_hot_spot (GTK_SCTREE(clist), event->x, event->y))
   1848 			folderview->open_folder = TRUE;
   1849 
   1850 	        if (event->type == GDK_2BUTTON_PRESS) {
   1851 			if (clist->selection) {
   1852 				GtkCMCTreeNode *node;
   1853 
   1854 				node = GTK_CMCTREE_NODE(clist->selection->data);
   1855 				if (node) {
   1856 					gtk_cmctree_toggle_expansion(
   1857 						GTK_CMCTREE(ctree),
   1858 						node);
   1859 					folderview->open_folder = FALSE;
   1860 				}
   1861 			}
   1862 		}
   1863 		return FALSE;
   1864 	}
   1865 
   1866 	if (event->button == 2 || event->button == 3) {
   1867 		/* right clicked */
   1868 		if (clist->selection) {
   1869 			GtkCMCTreeNode *node;
   1870 
   1871 			node = GTK_CMCTREE_NODE(clist->selection->data);
   1872 			if (node)
   1873 				prev_row = gtkut_ctree_get_nth_from_node
   1874 					(GTK_CMCTREE(ctree), node);
   1875 		}
   1876 
   1877 		if (!gtk_cmclist_get_selection_info(clist, event->x, event->y,
   1878 						  &row, &column))
   1879 			return FALSE;
   1880 		if (prev_row != row) {
   1881 			gtk_cmclist_unselect_all(clist);
   1882 			if (event->button == 2)
   1883 				folderview_select_node
   1884 					(folderview,
   1885 					 gtk_cmctree_node_nth(GTK_CMCTREE(ctree),
   1886 					 		    row));
   1887 			else
   1888 				gtk_cmclist_select_row(clist, row, column);
   1889 		}
   1890 	}
   1891 
   1892 	if (event->button != 3) return FALSE;
   1893 
   1894 	folderview_set_sens_and_popup_menu(folderview, row, event);
   1895 	return FALSE;
   1896 }
   1897 
   1898 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
   1899 					   FolderView *folderview)
   1900 {
   1901 	int row = -1, column = -1;
   1902 
   1903 	if (!event) return FALSE;
   1904 
   1905 	if (!gtk_cmclist_get_selection_info(GTK_CMCLIST(ctree), event->x, event->y,
   1906 					  &row, &column))
   1907 		return FALSE;
   1908 	if (event->button == 1 && folderview->open_folder == FALSE &&
   1909 	    folderview->opened != NULL) {
   1910 		gtkut_ctree_set_focus_row(GTK_CMCTREE(ctree),
   1911 					  folderview->opened);
   1912 		gtk_cmctree_select(GTK_CMCTREE(ctree), folderview->opened);
   1913 	}
   1914 
   1915 	return FALSE;
   1916 }
   1917 
   1918 #define BREAK_ON_MODIFIER_KEY() \
   1919 	if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
   1920 
   1921 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
   1922 				       FolderView *folderview)
   1923 {
   1924 	GtkCMCTreeNode *node;
   1925 	FolderItem *item;
   1926 
   1927 	if (!event) return FALSE;
   1928 
   1929 	switch (event->keyval) {
   1930 	case GDK_KEY_Right:
   1931 		if (folderview->selected) {
   1932 			if (GTK_CMCTREE_ROW(folderview->selected)->children != NULL
   1933 					&& !GTK_CMCTREE_ROW(folderview->selected)->expanded)
   1934 				gtk_cmctree_expand(GTK_CMCTREE(folderview->ctree),
   1935 						folderview->selected);
   1936 			else
   1937 				folderview_select_node(folderview,
   1938 						       folderview->selected);
   1939 		}
   1940 		break;
   1941 	case GDK_KEY_Return:
   1942 	case GDK_KEY_KP_Enter:
   1943 		if (folderview->selected)
   1944 			folderview_select_node(folderview, folderview->selected);
   1945 		break;
   1946 	case GDK_KEY_space:
   1947 		BREAK_ON_MODIFIER_KEY();
   1948 		if (folderview->selected) {
   1949 			if (folderview->opened == folderview->selected &&
   1950 			    (!folderview->summaryview->folder_item ||
   1951 			     folderview->summaryview->folder_item->total_msgs == 0))
   1952 				folderview_select_next_with_flag(folderview, MSG_UNREAD);
   1953 			else
   1954 				folderview_select_node(folderview,
   1955 						       folderview->selected);
   1956 		}
   1957 		break;
   1958 	case GDK_KEY_Left:
   1959 		if (folderview->selected) {
   1960 			/* If the folder is expanded and can be collapsed, do that... */
   1961 			if (GTK_CMCTREE_ROW(folderview->selected)->expanded &&
   1962 					GTK_CMCTREE_ROW(folderview->selected)->children != NULL) {
   1963 				gtk_cmctree_collapse(GTK_CMCTREE(folderview->ctree),
   1964 						folderview->selected);
   1965 			} else {
   1966 				/* ...otherwise, move cursor to its parent node. */
   1967 				if ((item = gtk_cmctree_node_get_row_data(GTK_CMCTREE(folderview->ctree),
   1968 						folderview->selected))) {
   1969 					if ((node = gtk_cmctree_find_by_row_data(GTK_CMCTREE(folderview->ctree),
   1970 							NULL, folder_item_parent(item)))) {
   1971 						gtk_sctree_select(GTK_SCTREE(folderview->ctree), node);
   1972 						if (!gtk_cmctree_node_is_visible(GTK_CMCTREE(folderview->ctree), node))
   1973 							gtk_cmctree_node_moveto(GTK_CMCTREE(folderview->ctree),
   1974 									node, -1, 0, 0);
   1975 					}
   1976 				}
   1977 			}
   1978 		}
   1979 		break;
   1980 	case GDK_KEY_Home:
   1981 	case GDK_KEY_End:
   1982 		if (event->keyval == GDK_KEY_Home)
   1983 			node = gtk_cmctree_node_nth(GTK_CMCTREE(folderview->ctree), 0);
   1984 		else
   1985 			node = gtk_cmctree_last(GTK_CMCTREE(folderview->ctree),
   1986 					gtk_cmctree_node_nth(GTK_CMCTREE(folderview->ctree), 0));
   1987 
   1988 		gtk_sctree_select(GTK_SCTREE(folderview->ctree), node);
   1989 
   1990 		if (!gtk_cmctree_node_is_visible(GTK_CMCTREE(folderview->ctree), node))
   1991 			gtk_cmctree_node_moveto(GTK_CMCTREE(folderview->ctree),
   1992 					node, -1, 0, 0);
   1993 		break;
   1994 	default:
   1995 		break;
   1996 	}
   1997 
   1998 	return FALSE;
   1999 }
   2000 
   2001 typedef struct _PostponedSelectData
   2002 {
   2003 	GtkCMCTree *ctree;
   2004 	GtkCMCTreeNode *row;
   2005 	gint column;
   2006 	FolderView *folderview;
   2007 } PostponedSelectData;
   2008 
   2009 static gboolean postpone_select(void *data)
   2010 {
   2011 	PostponedSelectData *psdata = (PostponedSelectData *)data;
   2012 	debug_print("trying again\n");
   2013 
   2014 	psdata->folderview->postpone_select_id = 0;
   2015 	psdata->folderview->open_folder = TRUE;
   2016 	main_window_cursor_normal(psdata->folderview->mainwin);
   2017 	STATUSBAR_POP(psdata->folderview->mainwin);
   2018 	folderview_selected(psdata->ctree, psdata->row,
   2019 			    psdata->column, psdata->folderview);
   2020 	g_free(psdata);
   2021 	return FALSE;
   2022 }
   2023 
   2024 void folderview_close_opened(FolderView *folderview, gboolean dirty)
   2025 {
   2026 	if (folderview->opened) {
   2027 		if (dirty) {
   2028 			folderview->opened = NULL;
   2029 			return;
   2030 		}
   2031 
   2032 		FolderItem *olditem =
   2033 			gtk_cmctree_node_get_row_data(GTK_CMCTREE(folderview->ctree),
   2034 						      folderview->opened);
   2035 		if (olditem) {
   2036 			gchar *buf = g_strdup_printf(_("Closing folder %s..."),
   2037 				olditem->path ? olditem->path:olditem->name);
   2038 			/* will be null if we just moved the previously opened folder */
   2039 			STATUSBAR_PUSH(folderview->mainwin, buf);
   2040 			main_window_cursor_wait(folderview->mainwin);
   2041 			g_free(buf);
   2042 			summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
   2043 			summary_show(folderview->summaryview, NULL, FALSE);
   2044 			folder_item_close(olditem);
   2045 			main_window_cursor_normal(folderview->mainwin);
   2046 			STATUSBAR_POP(folderview->mainwin);
   2047 			if (olditem->folder->klass->item_closed)
   2048 				olditem->folder->klass->item_closed(olditem);
   2049 
   2050 		}
   2051 	}
   2052 
   2053 	if (folderview->opened &&
   2054 	    !GTK_CMCTREE_ROW(folderview->opened)->children)
   2055 		gtk_cmctree_collapse(GTK_CMCTREE(folderview->ctree), folderview->opened);
   2056 
   2057 	folderview->opened = NULL;
   2058 }
   2059 static void folderview_selected(GtkCMCTree *ctree, GtkCMCTreeNode *row,
   2060 				gint column, FolderView *folderview)
   2061 {
   2062 	GdkDisplay *display;
   2063 	GdkSeat    *seat;
   2064 	GdkDevice  *device;
   2065 	static gboolean can_select = TRUE;	/* exclusive lock */
   2066 	gboolean opened;
   2067 	FolderItem *item;
   2068 	int res = 0;
   2069 	GtkCMCTreeNode *old_opened = folderview->opened;
   2070 	folderview->selected = row;
   2071 
   2072 	display = gdk_display_get_default();
   2073 	seat = gdk_display_get_default_seat(display);
   2074 	device = gdk_seat_get_pointer(seat);
   2075 
   2076 	debug_print("newly selected %p, opened %p\n", folderview->selected,
   2077 			folderview->opened);
   2078 	if (folderview->opened == row) {
   2079 		folderview->open_folder = FALSE;
   2080 		return;
   2081 	}
   2082 
   2083 	item = gtk_cmctree_node_get_row_data(ctree, row);
   2084 	if (!item) {
   2085 		folderview->open_folder = FALSE;
   2086 		return;
   2087 	}
   2088 
   2089 	if (!can_select || summary_is_locked(folderview->summaryview)) {
   2090 		if (folderview->opened) {
   2091 			gtkut_ctree_set_focus_row(ctree, folderview->opened);
   2092 			gtk_cmctree_select(ctree, folderview->opened);
   2093 		}
   2094 		folderview->open_folder = FALSE;
   2095 		return;
   2096 	}
   2097 
   2098 	if (!folderview->open_folder) {
   2099 		return;
   2100 	}
   2101 
   2102 	can_select = FALSE;
   2103 
   2104 	/* Save cache for old folder */
   2105 	/* We don't want to lose all caches if app crashes */
   2106 	/* Resets folderview->opened to NULL */
   2107 	folderview_close_opened(folderview, FALSE);
   2108 
   2109 	/* CLAWS: set compose button type: news folder items
   2110 	 * always have a news folder as parent */
   2111 	if (item->folder)
   2112 		toolbar_set_compose_button
   2113 			(folderview->mainwin->toolbar,
   2114 			 FOLDER_TYPE(item->folder) == F_NEWS ?
   2115 			 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
   2116 
   2117 	if (item->path)
   2118 		debug_print("Folder %s is selected\n", item->path);
   2119 
   2120 	if (!GTK_CMCTREE_ROW(row)->children)
   2121 		gtk_cmctree_expand(ctree, row);
   2122 
   2123 	/* ungrab the mouse event */
   2124 	if (gtk_widget_has_grab(GTK_WIDGET(ctree))) {
   2125 		gtk_grab_remove(GTK_WIDGET(ctree));
   2126 		if (gdk_display_device_is_grabbed(display, device))
   2127 			gdk_seat_ungrab(seat);
   2128 	}
   2129 
   2130 	if (item->path) {
   2131 		gchar *buf;
   2132 		buf = g_strdup_printf(_("Opening folder %s..."), item->path);
   2133 		debug_print("%s\n", buf);
   2134 		STATUSBAR_PUSH(folderview->mainwin, buf);
   2135 		g_free(buf);
   2136 	}
   2137 
   2138 	main_window_cursor_wait(folderview->mainwin);
   2139 
   2140 	if (folderview->scanning_folder == item->folder) {
   2141 		res = -2;
   2142 	} else {
   2143 		res = folder_item_open(item);
   2144 	}
   2145 
   2146 	if (res == -1 && item->no_select == FALSE) {
   2147 		main_window_cursor_normal(folderview->mainwin);
   2148 		STATUSBAR_POP(folderview->mainwin);
   2149 
   2150 		alertpanel_error(_("Folder could not be opened."));
   2151 
   2152 		folderview->open_folder = FALSE;
   2153 		can_select = TRUE;
   2154 		return;
   2155         } else if (res == -2 && item->no_select == FALSE) {
   2156 		PostponedSelectData *data = g_new0(PostponedSelectData, 1);
   2157 		data->ctree = ctree;
   2158 		data->row = row;
   2159 		data->column = column;
   2160 		data->folderview = folderview;
   2161 		debug_print("postponing open of %s till end of scan\n",
   2162 			item->path ? item->path:item->name);
   2163 		folderview->open_folder = FALSE;
   2164 		can_select = TRUE;
   2165 		if (folderview->postpone_select_id != 0)
   2166 			g_source_remove(folderview->postpone_select_id);
   2167 		folderview->postpone_select_id = g_timeout_add(500, postpone_select, data);
   2168 		return;
   2169 	}
   2170 
   2171 	main_window_cursor_normal(folderview->mainwin);
   2172 
   2173 	/* Show messages */
   2174 	summary_set_prefs_from_folderitem(folderview->summaryview, item);
   2175 	opened = summary_show(folderview->summaryview, item, FALSE);
   2176 
   2177 	folder_clean_cache_memory(item);
   2178 
   2179 	if (!opened) {
   2180 		gtkut_ctree_set_focus_row(ctree, old_opened);
   2181 		gtk_cmctree_select(ctree, old_opened);
   2182 		folderview->opened = old_opened;
   2183 	} else {
   2184 		folderview->opened = row;
   2185 		if (gtk_cmctree_node_is_visible(ctree, row)
   2186 		    != GTK_VISIBILITY_FULL)
   2187 			gtk_cmctree_node_moveto(ctree, row, -1, 0.5, 0);
   2188 	}
   2189 
   2190 	STATUSBAR_POP(folderview->mainwin);
   2191 
   2192 	folderview->open_folder = FALSE;
   2193 	can_select = TRUE;
   2194 }
   2195 
   2196 static void folderview_tree_expanded(GtkCMCTree *ctree, GtkCMCTreeNode *node,
   2197 				     FolderView *folderview)
   2198 {
   2199 	FolderItem *item;
   2200 
   2201 	item = gtk_cmctree_node_get_row_data(ctree, node);
   2202 	cm_return_if_fail(item != NULL);
   2203 	item->collapsed = FALSE;
   2204 	folderview_update_node(folderview, node);
   2205 }
   2206 
   2207 static void folderview_tree_collapsed(GtkCMCTree *ctree, GtkCMCTreeNode *node,
   2208 				      FolderView *folderview)
   2209 {
   2210 	FolderItem *item;
   2211 
   2212 	item = gtk_cmctree_node_get_row_data(ctree, node);
   2213 	cm_return_if_fail(item != NULL);
   2214 	item->collapsed = TRUE;
   2215 	folderview_update_node(folderview, node);
   2216 }
   2217 
   2218 static void folderview_popup_close(GtkMenuShell *menu_shell,
   2219 				   FolderView *folderview)
   2220 {
   2221 	if (!folderview->opened) return;
   2222 
   2223 	gtk_cmctree_select(GTK_CMCTREE(folderview->ctree), folderview->opened);
   2224 }
   2225 
   2226 static void folderview_col_resized(GtkCMCList *clist, gint column, gint width,
   2227 				   FolderView *folderview)
   2228 {
   2229 	FolderColumnType type = folderview->col_state[column].type;
   2230 
   2231 	prefs_common.folder_col_size[type] = width;
   2232 }
   2233 
   2234 static void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
   2235 {
   2236 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
   2237 	gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
   2238 	GtkCMCTreeNode *node, *parent_node;
   2239 	gint *col_pos = folderview->col_pos;
   2240 	FolderItemUpdateData hookdata;
   2241 
   2242 	parent_node = gtk_cmctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
   2243 	if (parent_node == NULL)
   2244 		return;
   2245 
   2246 	gtk_cmclist_freeze(GTK_CMCLIST(ctree));
   2247 
   2248 	text[col_pos[F_COL_FOLDER]] = item->name;
   2249 	node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
   2250 				     FOLDER_SPACING,
   2251 				     folderxpm,
   2252 				     folderopenxpm,
   2253 				     FALSE, FALSE);
   2254 	gtk_cmctree_expand(ctree, parent_node);
   2255 	gtk_cmctree_node_set_row_data(ctree, node, item);
   2256 	folderview_sort_folders(folderview, parent_node, item->folder);
   2257 
   2258 	hookdata.item = item;
   2259 	hookdata.update_flags = F_ITEM_UPDATE_NAME;
   2260 	hookdata.msg = NULL;
   2261 	hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
   2262 
   2263 	gtk_cmclist_thaw(GTK_CMCLIST(ctree));
   2264 }
   2265 
   2266 static void folderview_empty_trash_cb(GtkAction *action, gpointer data)
   2267 {
   2268 	FolderView *folderview = (FolderView *)data;
   2269 	FolderItem *item;
   2270 	GSList *mlist = NULL;
   2271 	GSList *cur = NULL;
   2272 	FolderItem *special_trash = NULL;
   2273 	PrefsAccount *ac;
   2274 
   2275 	if (!folderview->selected) return;
   2276 	item = folderview_get_selected_item(folderview);
   2277 	cm_return_if_fail(item != NULL);
   2278 	cm_return_if_fail(item->folder != NULL);
   2279 
   2280 	if (NULL != (ac = account_find_from_item(item)))
   2281 		special_trash = account_get_special_folder(ac, F_TRASH);
   2282 
   2283 	if (item != item->folder->trash && item != special_trash
   2284 	&&  !folder_has_parent_of_type(item, F_TRASH)) return;
   2285 
   2286 	if (prefs_common.ask_on_clean) {
   2287 		if (alertpanel(_("Empty trash"),
   2288 			       _("Delete all messages in trash?"),
   2289 			       NULL, _("_Cancel"), NULL, _("_Empty trash"), NULL, NULL,
   2290 				ALERTFOCUS_SECOND) != G_ALERTALTERNATE)
   2291 			return;
   2292 	}
   2293 
   2294 	mlist = folder_item_get_msg_list(item);
   2295 
   2296 	for (cur = mlist ; cur != NULL ; cur = cur->next) {
   2297 		MsgInfo * msginfo = (MsgInfo *) cur->data;
   2298 		if (MSG_IS_LOCKED(msginfo->flags))
   2299 			continue;
   2300 	}
   2301 	procmsg_msg_list_free(mlist);
   2302 
   2303 	folder_item_remove_all_msg(item);
   2304 }
   2305 
   2306 static void folderview_send_queue_cb(GtkAction *action, gpointer data)
   2307 {
   2308 	FolderView *folderview = (FolderView *)data;
   2309 	FolderItem *item;
   2310 	FolderItem *special_queue = NULL;
   2311 	PrefsAccount *ac;
   2312 	gchar *errstr = NULL;
   2313 
   2314 	if (!folderview->selected) return;
   2315 	item = folderview_get_selected_item(folderview);
   2316 	cm_return_if_fail(item != NULL);
   2317 	cm_return_if_fail(item->folder != NULL);
   2318 
   2319 	if (NULL != (ac = account_find_from_item(item)))
   2320 		special_queue = account_get_special_folder(ac, F_QUEUE);
   2321 
   2322 	if (item != item->folder->queue && item != special_queue
   2323 	&&  !folder_has_parent_of_type(item, F_QUEUE)) return;
   2324 
   2325 	if (procmsg_queue_is_empty(item))
   2326 		return;
   2327 
   2328 	if (prefs_common.work_offline)
   2329 		if (alertpanel(_("Offline warning"),
   2330 			       _("You're working offline. Override?"),
   2331 			       NULL, _("_No"), NULL, _("_Yes"),
   2332 			       NULL, NULL, ALERTFOCUS_FIRST) != G_ALERTALTERNATE)
   2333 		return;
   2334 
   2335 	/* ask for confirmation before sending queued messages only
   2336 	   in online mode and if there is at least one message queued
   2337 	   in any of the folder queue
   2338 	*/
   2339 	if (prefs_common.confirm_send_queued_messages) {
   2340 		if (!prefs_common.work_offline) {
   2341 			if (alertpanel(_("Send queued messages"),
   2342 			    	   _("Send all queued messages?"),
   2343 			    	   NULL, _("_Cancel"), NULL, _("_Send"),
   2344 				   NULL, NULL, ALERTFOCUS_FIRST) != G_ALERTALTERNATE)
   2345 				return;
   2346 		}
   2347 	}
   2348 
   2349 	if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
   2350 		if (!errstr)
   2351 			alertpanel_error_log(_("Some errors occurred while "
   2352 					   "sending queued messages."));
   2353 		else {
   2354 			alertpanel_error_log(_("Some errors occurred "
   2355 					"while sending queued messages:\n%s"), errstr);
   2356 			g_free(errstr);
   2357 		}
   2358 	}
   2359 }
   2360 
   2361 static void folderview_startup_folder_cb(GtkAction *action, gpointer data)
   2362 {
   2363 	FolderView *folderview = (FolderView *)data;
   2364 	FolderItem *item;
   2365 
   2366 	if (!folderview->selected) return;
   2367 
   2368 	item = folderview_get_selected_item(folderview);
   2369 
   2370 	prefs_common.startup_folder = folder_item_get_identifier(item);
   2371 	prefs_common.goto_folder_on_startup = prefs_common.startup_folder? TRUE : FALSE;
   2372 }
   2373 
   2374 static void folderview_property_cb(GtkAction *action, gpointer data)
   2375 {
   2376 	FolderView *folderview = (FolderView *)data;
   2377 	FolderItem *item;
   2378 
   2379 	if (!folderview->selected) return;
   2380 
   2381 	item = folderview_get_selected_item(folderview);
   2382 	cm_return_if_fail(item != NULL);
   2383 	cm_return_if_fail(item->folder != NULL);
   2384 
   2385 	prefs_folder_item_open(item);
   2386 }
   2387 
   2388 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
   2389 		            FolderItem *to_folder, gboolean copy)
   2390 {
   2391 	FolderItem *new_folder = NULL;
   2392 	gchar *buf;
   2393 	gint status;
   2394 
   2395 	cm_return_if_fail(folderview != NULL);
   2396 	cm_return_if_fail(from_folder != NULL);
   2397 	cm_return_if_fail(to_folder != NULL);
   2398 
   2399 	if (prefs_common.warn_dnd) {
   2400 		buf = g_strdup_printf(copy ? _("Do you really want to copy folder '%s' in '%s'?"):
   2401 					     _("Do you really want to make folder '%s' a subfolder of '%s'?"),
   2402 					from_folder->name, to_folder->name);
   2403 		status = alertpanel_full(copy ? _("Copy folder"):_("Move folder"), buf,
   2404 				       	 NULL, _("_No"), NULL, _("_Yes"), NULL, NULL,
   2405 					 ALERTFOCUS_FIRST, TRUE, NULL, ALERT_QUESTION);
   2406 		g_free(buf);
   2407 
   2408 		if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
   2409 			return;
   2410 		else if (status & G_ALERTDISABLE)
   2411 			prefs_common.warn_dnd = FALSE;
   2412 	}
   2413 
   2414 	buf = g_strdup_printf(copy ? _("Copying %s to %s..."):_("Moving %s to %s..."),
   2415 				from_folder->name, to_folder->name);
   2416 	STATUSBAR_PUSH(folderview->mainwin, buf);
   2417 	g_free(buf);
   2418 	summary_clear_all(folderview->summaryview);
   2419 	folderview->opened = NULL;
   2420 	folderview->selected = NULL;
   2421 	gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
   2422 	inc_lock();
   2423 	main_window_cursor_wait(folderview->mainwin);
   2424 
   2425 	statusbar_verbosity_set(FALSE);
   2426 	folder_item_update_freeze();
   2427 	gtk_cmclist_freeze(GTK_CMCLIST(folderview->ctree));
   2428 	if ((status = folder_item_move_to(from_folder, to_folder, &new_folder, copy)) == F_MOVE_OK) {
   2429 		statusbar_verbosity_set(FALSE);
   2430 		main_window_cursor_normal(folderview->mainwin);
   2431 		STATUSBAR_POP(folderview->mainwin);
   2432 		folder_item_update_thaw();
   2433 		folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
   2434 
   2435 		folderview_sort_folders(folderview,
   2436 			gtk_cmctree_find_by_row_data(GTK_CMCTREE(folderview->ctree),
   2437 				NULL, to_folder), new_folder->folder);
   2438 		folderview_select(folderview, new_folder);
   2439 		gtk_cmclist_thaw(GTK_CMCLIST(folderview->ctree));
   2440 	} else {
   2441 		statusbar_verbosity_set(FALSE);
   2442 		main_window_cursor_normal(folderview->mainwin);
   2443 		STATUSBAR_POP(folderview->mainwin);
   2444 		gtk_cmclist_thaw(GTK_CMCLIST(folderview->ctree));
   2445 		folder_item_update_thaw();
   2446 		switch (status) {
   2447 		case F_MOVE_FAILED_DEST_IS_PARENT:
   2448 			alertpanel_error(_("Source and destination are the same."));
   2449 			break;
   2450 		case F_MOVE_FAILED_DEST_IS_CHILD:
   2451 			alertpanel_error(copy ? _("Can't copy a folder to one of its children."):
   2452 						_("Can't move a folder to one of its children."));
   2453 			break;
   2454 		case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
   2455 			alertpanel_error(_("A folder cannot be moved between different mailboxes."));
   2456 			break;
   2457 		default:
   2458 			alertpanel_error(copy ? _("Copy failed!"):_("Move failed!"));
   2459 			break;
   2460 		}
   2461 	}
   2462 	inc_unlock();
   2463 	gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
   2464 }
   2465 
   2466 static gint folderview_clist_compare(GtkCMCList *clist,
   2467 				     gconstpointer ptr1, gconstpointer ptr2)
   2468 {
   2469 	FolderItem *item1 = ((GtkCMCListRow *)ptr1)->data;
   2470 	FolderItem *item2 = ((GtkCMCListRow *)ptr2)->data;
   2471 
   2472 	if (item1->order > 0 && item2->order > 0)  // if we have an order item, use it
   2473 	{
   2474 		return item1->order - item2->order;
   2475 	}
   2476 
   2477 	// if only one folder has an order it comes first
   2478 	if (item1->order > 0)
   2479 	{
   2480 		return -1;
   2481 	}
   2482 	if (item2->order > 0)
   2483 	{
   2484 		return 1;
   2485 	}
   2486 
   2487 	if (!item1->name)
   2488 		return (item2->name != NULL);
   2489 	if (!item2->name)
   2490 		return -1;
   2491 
   2492 	return g_utf8_collate(item1->name, item2->name);
   2493 }
   2494 
   2495 static gboolean folderview_update_folder(gpointer source, gpointer userdata)
   2496 {
   2497 	FolderUpdateData *hookdata;
   2498 	FolderView *folderview;
   2499 	GtkWidget *ctree;
   2500 
   2501 	hookdata = source;
   2502 	folderview = (FolderView *) userdata;
   2503 	cm_return_val_if_fail(hookdata != NULL, FALSE);
   2504 	cm_return_val_if_fail(folderview != NULL, FALSE);
   2505 
   2506 	ctree = folderview->ctree;
   2507 	cm_return_val_if_fail(ctree != NULL, FALSE);
   2508 
   2509 	if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
   2510 		folderview_create_folder_node(folderview, hookdata->item);
   2511 	else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
   2512 		GtkCMCTreeNode *node = gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree),
   2513 				NULL, folder_item_parent(hookdata->item));
   2514 		folderview_sort_folders(folderview, node, hookdata->folder);
   2515 	} else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
   2516 		GtkCMCTreeNode *node;
   2517 
   2518 		node = gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree), NULL, hookdata->item);
   2519 		if (node != NULL) {
   2520 			gtk_cmctree_remove_node(GTK_CMCTREE(ctree), node);
   2521 			if (folderview->selected == node)
   2522 				folderview->selected = NULL;
   2523 			if (folderview->opened == node)
   2524 				folderview->opened = NULL;
   2525 		}
   2526 	} else if (hookdata->update_flags & FOLDER_MOVE_FOLDERITEM) {
   2527 		/* do nothing, it's done by the ADD and REMOVE) */
   2528 	} else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
   2529 		folderview_set(folderview);
   2530 
   2531 	return FALSE;
   2532 }
   2533 
   2534 static gboolean folderview_dnd_scroll_cb(gpointer data)
   2535 {
   2536 	FolderView *folderview = (FolderView *)data;
   2537 	GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
   2538 				GTK_SCROLLED_WINDOW(folderview->scrolledwin));
   2539 	gint new_val = (int)gtk_adjustment_get_value(pos) + folderview->scroll_value;
   2540 	gint max = (int)gtk_adjustment_get_upper(pos) -
   2541                (int)gtk_adjustment_get_page_size(pos);
   2542 
   2543 	if (folderview->scroll_value == 0) {
   2544 		folderview->scroll_timeout_id = 0;
   2545 		return FALSE;
   2546 	}
   2547 
   2548 	if (folderview->scroll_value > 0 && new_val > max) {
   2549 		new_val = max;
   2550 	} else if (folderview->scroll_value < 0 && new_val < 0) {
   2551 		new_val = 0;
   2552 	}
   2553 	gtk_adjustment_set_value(pos, new_val);
   2554 
   2555 	return TRUE;
   2556 }
   2557 
   2558 static void free_info(gpointer stuff, gpointer data) { g_free(stuff); }
   2559 
   2560 void folderview_remove_item(FolderView *folderview, FolderItem *item)
   2561 {
   2562 	g_return_if_fail(folderview != NULL);
   2563 	g_return_if_fail(item != NULL);
   2564 
   2565 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
   2566 	g_return_if_fail(ctree != NULL);
   2567 
   2568 	GtkCMCTreeNode *node =
   2569 		gtk_cmctree_find_by_row_data(ctree, NULL, item);
   2570 	g_return_if_fail(node != NULL);
   2571 
   2572 	gtk_cmctree_remove_node(ctree, node);
   2573 }
   2574 
   2575 void folderview_freeze(FolderView *folderview)
   2576 {
   2577 	if (folderview)
   2578 		gtk_cmclist_freeze(GTK_CMCLIST(folderview->ctree));
   2579 }
   2580 
   2581 void folderview_thaw(FolderView *folderview)
   2582 {
   2583 	if (folderview)
   2584 		gtk_cmclist_thaw(GTK_CMCLIST(folderview->ctree));
   2585 }
   2586 
   2587 void folderview_grab_focus(FolderView *folderview)
   2588 {
   2589 	 if (folderview)
   2590 		 gtk_widget_grab_focus(folderview->ctree);
   2591 }
   2592 
   2593 static void folderview_header_set_displayed_columns_cb(GtkAction *gaction,
   2594 		gpointer data)
   2595 {
   2596 	prefs_folder_column_open();
   2597 }
   2598 
   2599 static gboolean folderview_header_button_pressed(GtkWidget *widget,
   2600 		GdkEvent *_event,
   2601 		gpointer user_data)
   2602 {
   2603 	GdkEventButton *event = (GdkEventButton *)_event;
   2604 	FolderView *folderview = (FolderView *)user_data;
   2605 
   2606 	cm_return_val_if_fail(folderview != NULL, FALSE);
   2607 
   2608 	/* Only handle single button presses. */
   2609 	if (event->type == GDK_2BUTTON_PRESS ||
   2610 			event->type == GDK_3BUTTON_PRESS)
   2611 		return FALSE;
   2612 
   2613 	/* Handle right-click for context menu */
   2614 	if (event->button == 3) {
   2615 		gtk_menu_popup_at_pointer(GTK_MENU(folderview->headerpopupmenu), NULL);
   2616 		return TRUE;
   2617 	}
   2618 
   2619 	return FALSE;
   2620 }