+2006-08-22 [colin] 2.4.0cvs73
+
+ * src/folder.c
+ Set folder's mtime after writing its
+ cache
+ * src/folderview.c
+ Add some timing
+ * src/procmsg.c
+ Don't do useless stuff if we don't
+ thread by subject
+ * src/summaryview.c
+ Add some timing, don't deselect prior
+ to selecting (gtksctree does it itself),
+ remove crash avoidance hacks as it's been
+ properly fixed since a while
+ * src/common/utils.c
+ Optimize to_human_readable(): _() is slow,
+ do it only once, and avoid %f format for KB
+ (the most common in a summaryview)
+ * src/gtk/gtksctree.c
+ Don't uselessly freeze/thaw (fixes flicker
+ on next unread and friends), reduce number
+ of g_list_nth/g_list_position where possible
+ * src/gtk/gtkutils.c
+ * src/gtk/gtkutils.h
+ Reduce number of g_list_nth/g_list_position
+ where possible.
+ All of this makes loading as 70k folder 2.1
+ seconds instead of 3.2 (with hot FS caches).
+ (1.3 seconds without Date and Size columns...)
+
2006-08-22 [paul] 2.4.0cvs72
wrap documents and do some items from mones' MANUAL-TODO:
( cvs diff -u -r 1.1.2.5 -r 1.1.2.6 manual/Makefile.am; cvs diff -u -r 1.60.2.61 -r 1.60.2.62 src/addressbook.c; cvs diff -u -r 1.3.2.42 -r 1.3.2.43 src/prefs_themes.c; cvs diff -u -r 1.5.2.37 -r 1.5.2.38 src/gtk/gtkutils.c; cvs diff -u -r 1.5.2.32 -r 1.5.2.33 src/gtk/pluginwindow.c; cvs diff -u -r 1.1.2.12 -r 1.1.2.13 src/plugins/pgpcore/prefs_gpg.c; cvs diff -u -r 1.1.2.26 -r 1.1.2.27 src/plugins/pgpcore/sgpgme.c; ) > 2.4.0cvs70.patchset
( cvs diff -u -r 1.5.2.33 -r 1.5.2.34 src/gtk/pluginwindow.c; ) > 2.4.0cvs71.patchset
( cvs diff -u -r 1.1.2.6 -r 1.1.2.7 manual/account.xml; cvs diff -u -r 1.1.2.9 -r 1.1.2.10 manual/faq.xml; cvs diff -u -r 1.1.2.8 -r 1.1.2.9 manual/handling.xml; ) > 2.4.0cvs72.patchset
+( cvs diff -u -r 1.213.2.106 -r 1.213.2.107 src/folder.c; cvs diff -u -r 1.207.2.112 -r 1.207.2.113 src/folderview.c; cvs diff -u -r 1.150.2.73 -r 1.150.2.74 src/procmsg.c; cvs diff -u -r 1.395.2.230 -r 1.395.2.231 src/summaryview.c; cvs diff -u -r 1.36.2.75 -r 1.36.2.76 src/common/utils.c; cvs diff -u -r 1.1.4.21 -r 1.1.4.22 src/gtk/gtksctree.c; cvs diff -u -r 1.5.2.38 -r 1.5.2.39 src/gtk/gtkutils.c; cvs diff -u -r 1.4.2.23 -r 1.4.2.24 src/gtk/gtkutils.h; ) > 2.4.0cvs73.patchset
MICRO_VERSION=0
INTERFACE_AGE=0
BINARY_AGE=0
-EXTRA_VERSION=72
+EXTRA_VERSION=73
EXTRA_RELEASE=
EXTRA_GTK2_VERSION=
return itos_buf(nstr, n);
}
+#define divide(num,divisor,i,d) \
+{ \
+ register int tmp; \
+ i = num/divisor; \
+ tmp = i*divisor; \
+ d = num-tmp; \
+ if (d > 1000) d /= 1000; \
+ else if (d > 100) d /= 100; \
+ else if (d > 10) d /= 10; \
+}
+
gchar *to_human_readable(off_t size)
{
static gchar str[14];
-
- if (size < 1024)
- g_snprintf(str, sizeof(str), _("%dB"), (gint)size);
- else if (size >> 10 < 1024)
- g_snprintf(str, sizeof(str), _("%.1fKB"), (gfloat)size / (1 << 10));
- else if (size >> 20 < 1024)
- g_snprintf(str, sizeof(str), _("%.2fMB"), (gfloat)size / (1 << 20));
- else
- g_snprintf(str, sizeof(str), _("%.2fGB"), (gfloat)size / (1 << 30));
-
- return str;
+ static gchar *b_format = NULL, *kb_format = NULL,
+ *mb_format = NULL, *gb_format = NULL;
+ register int t = 0, r = 0;
+ if (b_format == NULL) {
+ b_format = _("%dB");
+ kb_format = _("%d.%dKB");
+ mb_format = _("%.2fMB");
+ gb_format = _("%.2fGB");
+ }
+
+ if (size < 1024) {
+ g_snprintf(str, sizeof(str), b_format, (gint)size);
+ return str;
+ } else if (size >> 10 < 1024) {
+ divide(size, (1 << 10), t, r);
+ g_snprintf(str, sizeof(str), kb_format, t, r);
+ return str;
+ } else if (size >> 20 < 1024) {
+ g_snprintf(str, sizeof(str), mb_format, (gfloat)size / (1 << 20));
+ return str;
+ } else {
+ g_snprintf(str, sizeof(str), gb_format, (gfloat)size / (1 << 30));
+ return str;
+ }
}
/* strcmp with NULL-checking */
}
}
+ if (FOLDER_TYPE(item->folder) == F_MH)
+ item->mtime = time(NULL);
+
g_free(cache_file);
g_free(mark_file);
}
#include "filtering.h"
#include "quicksearch.h"
#include "manual.h"
+#include "timing.h"
#define COL_FOLDER_WIDTH 150
#define COL_NUM_WIDTH 32
FolderItem *item;
gchar *buf;
int res = 0;
-
+ START_TIMING("--- folderview_selected");
folderview->selected = row;
if (folderview->opened == row) {
folderview->open_folder = FALSE;
+ END_TIMING();
return;
}
gtkut_ctree_set_focus_row(ctree, folderview->opened);
gtk_ctree_select(ctree, folderview->opened);
}
+ END_TIMING();
return;
}
- if (!folderview->open_folder) return;
-
+ if (!folderview->open_folder) {
+ END_TIMING();
+ return;
+ }
item = gtk_ctree_node_get_row_data(ctree, row);
- if (!item || item->no_select) return;
+ if (!item || item->no_select) {
+ END_TIMING();
+ return;
+ }
can_select = FALSE;
folderview->open_folder = FALSE;
can_select = TRUE;
-
+ END_TIMING();
return;
} else if (res == -2) {
PostponedSelectData *data = g_new0(PostponedSelectData, 1);
folderview->open_folder = FALSE;
can_select = TRUE;
g_timeout_add(500, postpone_select, data);
+ END_TIMING();
return;
}
folderview->open_folder = FALSE;
can_select = TRUE;
+ END_TIMING();
}
static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
}
/* Handles row selection according to the specified modifier state */
+/* in certain cases, we arrive here from a function knowing the GtkCTreeNode, and having
+ * already slowly found row using g_list_position. In which case, _node will be non-NULL
+ * to avoid this function having to slowly find it with g_list_nth. */
static void
-select_row (GtkSCTree *sctree, gint row, gint col, guint state)
+select_row (GtkSCTree *sctree, gint row, gint col, guint state, GtkCTreeNode *_node)
{
gboolean range, additive;
g_return_if_fail (sctree != NULL);
(GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) &&
(GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE);
- gtk_clist_freeze (GTK_CLIST (sctree));
+ /* heavy GUI updates will be done only if we're selecting a range.
+ * additive selection is ctrl-click, where the user is the slow factor.
+ * So we only freeze the list if selecting a range (potentially thousands
+ * of lines. */
+ if (range)
+ gtk_clist_freeze (GTK_CLIST (sctree));
GTK_CLIST(sctree)->focus_row = row;
if (!additive) {
- sctree->selecting_range = TRUE;
+ /* if this selection isn't additive, we have to unselect what
+ * is selected. Here, heavy GUI updates can occur if we have
+ * a big selection. See if more than one line is selected, in
+ * which case, freeze, else don't. */
+
+ gboolean should_freeze = FALSE;
+ if (GTK_CLIST(sctree)->selection
+ && GTK_CLIST(sctree)->selection->next) {
+ should_freeze = TRUE;
+ sctree->selecting_range = TRUE;
+ gtk_clist_freeze (GTK_CLIST (sctree));
+ }
+
gtk_clist_unselect_all (GTK_CLIST (sctree));
- sctree->selecting_range = FALSE;
+
+ if (should_freeze) {
+ gtk_clist_thaw (GTK_CLIST (sctree));
+ sctree->selecting_range = FALSE;
+ }
}
if (!range) {
GtkCTreeNode *node;
- node = gtk_ctree_node_nth (GTK_CTREE(sctree), row);
+ node = _node ? _node : gtk_ctree_node_nth (GTK_CTREE(sctree), row);
/*No need to manage overlapped list*/
if (additive) {
} else
select_range (sctree, row);
- gtk_clist_thaw (GTK_CLIST (sctree));
+ if (range)
+ gtk_clist_thaw (GTK_CLIST (sctree));
}
/* Our handler for button_press events. We override all of GtkCList's broken
sctree->dnd_select_pending_state = event->state;
sctree->dnd_select_pending_row = row;
} else {
- select_row (sctree, row, col, event->state);
+ select_row (sctree, row, col, event->state, NULL);
}
} else {
sctree->selecting_range = TRUE;
/* Emit *_popup_menu signal*/
if (on_row) {
if (!row_is_selected(sctree,row))
- select_row (sctree, row, col, 0);
+ select_row (sctree, row, col, 0, NULL);
g_signal_emit (G_OBJECT (sctree),
sctree_signals[ROW_POPUP_MENU],
0, event);
if (on_row) {
if (sctree->dnd_select_pending) {
- select_row (sctree, row, col, sctree->dnd_select_pending_state);
+ select_row (sctree, row, col, sctree->dnd_select_pending_state, NULL);
sctree->dnd_select_pending = FALSE;
sctree->dnd_select_pending_state = 0;
}
select_row (sctree,
sctree->dnd_select_pending_row,
-1,
- sctree->dnd_select_pending_state);
+ sctree->dnd_select_pending_state,
+ NULL);
sctree->dnd_select_pending = FALSE;
sctree->dnd_select_pending_state = 0;
{
select_row(sctree,
g_list_position(GTK_CLIST(sctree)->row_list, (GList *)node),
- -1, 0);
+ -1, 0, node);
}
void gtk_sctree_select_with_state (GtkSCTree *sctree, GtkCTreeNode *node, int state)
{
select_row(sctree,
g_list_position(GTK_CLIST(sctree)->row_list, (GList *)node),
- -1, state);
+ -1, state, node);
}
void gtk_sctree_unselect_all (GtkSCTree *sctree)
#define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \
((clist)->row_height + CELL_SPACING))
-void gtkut_ctree_node_move_if_on_the_edge(GtkCTree *ctree, GtkCTreeNode *node)
+void gtkut_ctree_node_move_if_on_the_edge(GtkCTree *ctree, GtkCTreeNode *node, gint _row)
{
GtkCList *clist = GTK_CLIST(ctree);
gint row;
g_return_if_fail(ctree != NULL);
g_return_if_fail(node != NULL);
- row = g_list_position(clist->row_list, (GList *)node);
+ row = (_row != -1 ? _row : g_list_position(clist->row_list, (GList *)node));
+
if (row < 0 || row >= clist->rows || clist->row_height == 0) return;
row_visibility = gtk_clist_row_is_visible(clist, row);
prev_row_visibility = gtk_clist_row_is_visible(clist, row - 1);
void gtkut_ctree_node_move_if_on_the_edge
(GtkCTree *ctree,
- GtkCTreeNode *node);
+ GtkCTreeNode *node,
+ gint _row);
gint gtkut_ctree_get_nth_from_node (GtkCTree *ctree,
GtkCTreeNode *node);
GtkCTreeNode *gtkut_ctree_node_next (GtkCTree *ctree,
START_TIMING("procmsg_get_thread_tree");
root = g_node_new(NULL);
msgid_table = g_hash_table_new(g_str_hash, g_str_equal);
- subject_relation = g_relation_new(2);
- g_relation_index(subject_relation, 0, g_str_hash, g_str_equal);
+
+ if (prefs_common.thread_by_subject) {
+ subject_relation = g_relation_new(2);
+ g_relation_index(subject_relation, 0, g_str_hash, g_str_equal);
+ }
for (; mlist != NULL; mlist = mlist->next) {
msginfo = (MsgInfo *)mlist->data;
END_TIMING();
}
- g_relation_destroy(subject_relation);
+ if (prefs_common.thread_by_subject)
+ g_relation_destroy(subject_relation);
+
g_hash_table_destroy(msgid_table);
END_TIMING();
return root;
if (!summaryview->mainwin)
return FALSE;
-
+START_TIMING("--------- summary_show");
summaryview->last_displayed = NULL;
summary_switch_from_to(summaryview, item);
} else {
summary_unlock(summaryview);
inc_unlock();
+ END_TIMING();
return FALSE;
}
if (changed || !quicksearch_is_active(summaryview->quicksearch))
summaryview->folderview,
summaryview->folder_item);
main_window_cursor_normal(summaryview->mainwin);
- }
+ }
+ END_TIMING();
return TRUE;
}
g_free(buf);
summary_unlock(summaryview);
inc_unlock();
summary_show(summaryview, summaryview->folder_item);
+ END_TIMING();
return FALSE;
}
g_slist_free(mlist);
main_window_cursor_normal(summaryview->mainwin);
summary_unlock(summaryview);
inc_unlock();
-
+ END_TIMING();
return TRUE;
}
GTK_EVENTS_FLUSH();
summary_unlock(summaryview);
gtk_widget_grab_focus(GTK_WIDGET(ctree));
- if (GTK_CTREE_ROW(node) == NULL) {
- g_warning("crash avoidance hack 1\n");
- return;
- }
- if (((GtkCListRow *)(GTK_CTREE_ROW(node)))->state < GTK_STATE_NORMAL
- || ((GtkCListRow *)(GTK_CTREE_ROW(node)))->state > GTK_STATE_INSENSITIVE) {
- g_warning("crash avoidance hack 2\n");
- return;
- }
gtk_ctree_node_moveto(ctree, node, 0, 0.5, 0);
}
- summary_unselect_all(summaryview);
if (display_msg && summaryview->displayed == node)
summaryview->displayed = NULL;
summaryview->display_msg = display_msg;
else
text[col_pos[S_COL_NUMBER]] = "";
+ /* slow! */
if (summaryview->col_state[summaryview->col_pos[S_COL_SIZE]].visible)
text[col_pos[S_COL_SIZE]] = to_human_readable(msginfo->size);
else
else
text[col_pos[S_COL_SCORE]] = "";
+ /* slow! */
if (summaryview->col_state[summaryview->col_pos[S_COL_DATE]].visible) {
if (msginfo->date_t) {
procheader_date_get_localtime(date_modified,
val = messageview_show(msgview, msginfo, all_headers);
if (GTK_CLIST(msgview->mimeview->ctree)->row_list == NULL)
gtk_widget_grab_focus(summaryview->ctree);
- gtkut_ctree_node_move_if_on_the_edge(ctree, row);
+ gtkut_ctree_node_move_if_on_the_edge(ctree, row,
+ GTK_CLIST(summaryview->ctree)->focus_row);
}
if (val == 0 && MSG_IS_UNREAD(msginfo->flags)) {