From cff59255982d470b11a97408d7d3571b03b8401a Mon Sep 17 00:00:00 2001 From: Andrew Borodin Date: Mon, 2 May 2011 13:44:47 +0400 Subject: [PATCH] Optimization of history save. Formerly, each widget saved its history self in WIDGET_DESTROY stage. Thus, history file was read and written as many times as many widgets with history are in dialog. Now all widget histories are written to ${XDG_CACHE_HOME}/mc/history file at one time before dialog destruction. An ev_history_load_save_t event type is created to use new event engine to save histories. Signed-off-by: Andrew Borodin --- lib/event-types.h | 14 ++++++++++++-- lib/widget/dialog.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- lib/widget/dialog.h | 1 + lib/widget/history.c | 5 +++++ lib/widget/history.h | 2 ++ lib/widget/input.c | 39 +++++++++++++++++++++++++++++++++++---- src/filemanager/layout.c | 22 +++++++++++++++------- src/filemanager/panel.c | 34 +++++++++++++++++++++++++++++++--- 8 files changed, 145 insertions(+), 17 deletions(-) diff --git a/lib/event-types.h b/lib/event-types.h index c4c0b6911..6984e2326 100644 --- a/lib/event-types.h +++ b/lib/event-types.h @@ -7,16 +7,19 @@ /* Event groups for main modules */ #define MCEVENT_GROUP_CORE "Core" +#define MCEVENT_GROUP_DIALOG "Dialog" #define MCEVENT_GROUP_DIFFVIEWER "DiffViewer" #define MCEVENT_GROUP_EDITOR "Editor" #define MCEVENT_GROUP_FILEMANAGER "FileManager" #define MCEVENT_GROUP_VIEWER "Viewer" +/* Events */ +#define MCEVENT_HISTORY_SAVE "history_save" + /*** enums ***************************************************************************************/ /*** structures declarations (and typedefs of structures)*****************************************/ - /* MCEVENT_GROUP_CORE:vfs_timestamp */ struct vfs_class; typedef struct @@ -26,7 +29,6 @@ typedef struct gboolean ret; } ev_vfs_stamp_create_t; - /* MCEVENT_GROUP_CORE:vfs_print_message */ typedef struct { @@ -63,6 +65,14 @@ typedef struct } ret; } ev_background_parent_call_t; +/* MCEVENT_GROUP_DIALOG:history_save */ +struct mc_config_t; +struct Widget; +typedef struct +{ + struct mc_config_t *cfg; + struct Widget *receiver; /* NULL means broadcast message */ +} ev_history_load_save_t; /*** global variables defined in .c file *********************************************************/ diff --git a/lib/widget/dialog.c b/lib/widget/dialog.c index 70c7c4849..ef49660a7 100644 --- a/lib/widget/dialog.c +++ b/lib/widget/dialog.c @@ -24,10 +24,13 @@ #include #include +#include #include -#include #include #include +#include +#include +#include /* open() */ #include "lib/global.h" @@ -37,6 +40,7 @@ #include "lib/tty/key.h" #include "lib/strutil.h" #include "lib/widget.h" +#include "lib/fileloc.h" /* MC_HISTORY_FILE */ #include "lib/event.h" /* mc_event_raise() */ /*** global variables ****************************************************************************/ @@ -1154,6 +1158,8 @@ run_dlg (Dlg_head * h) void destroy_dlg (Dlg_head * h) { + /* if some widgets have history, save all history at one moment here */ + dlg_save_history (h); dlg_broadcast_msg (h, WIDGET_DESTROY, FALSE); g_list_foreach (h->widgets, (GFunc) g_free, NULL); g_list_free (h->widgets); @@ -1167,6 +1173,43 @@ destroy_dlg (Dlg_head * h) /* --------------------------------------------------------------------------------------------- */ +/** + * Write history to the ${XDG_CACHE_HOME}/mc/history file + */ +void +dlg_save_history (Dlg_head * h) +{ + char *profile; + int i; + + if (num_history_items_recorded == 0) /* this is how to disable */ + return; + + profile = g_build_filename (mc_config_get_cache_path (), MC_HISTORY_FILE, (char *) NULL); + i = open (profile, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); + if (i != -1) + close (i); + + /* Make sure the history is only readable by the user */ + if (chmod (profile, S_IRUSR | S_IWUSR) != -1 || errno == ENOENT) + { + ev_history_load_save_t event_data; + + event_data.cfg = mc_config_init (profile); + event_data.receiver = NULL; + + /* get all histories in dialog */ + mc_event_raise (h->event_group, MCEVENT_HISTORY_SAVE, &event_data); + + mc_config_save_file (event_data.cfg, NULL); + mc_config_deinit (event_data.cfg); + } + + g_free (profile); +} + +/* --------------------------------------------------------------------------------------------- */ + char * dlg_get_title (const Dlg_head * h, size_t len) { diff --git a/lib/widget/dialog.h b/lib/widget/dialog.h index 8f004286c..6c13212a2 100644 --- a/lib/widget/dialog.h +++ b/lib/widget/dialog.h @@ -190,6 +190,7 @@ int run_dlg (Dlg_head * d); void destroy_dlg (Dlg_head * h); void dlg_run_done (Dlg_head * h); +void dlg_save_history (Dlg_head * h); void dlg_process_event (Dlg_head * h, int key, Gpm_Event * event); char *dlg_get_title (const Dlg_head * h, size_t len); diff --git a/lib/widget/history.c b/lib/widget/history.c index 12bab639e..dc27ee118 100644 --- a/lib/widget/history.c +++ b/lib/widget/history.c @@ -214,6 +214,9 @@ history_save (struct mc_config_t * cfg, const char *name, GList * h) GString *buffer; int i; + if (name == NULL || *name == '\0' || h == NULL) + return; + /* go to end of list */ h = g_list_last (h); @@ -261,6 +264,7 @@ history_save (struct mc_config_t * cfg, const char *name, GList * h) /* --------------------------------------------------------------------------------------------- */ +#if 0 /** * Write the history to the ${XDG_CACHE_HOME}/mc/history file. */ @@ -296,6 +300,7 @@ history_put (const char *input_name, GList * h) g_free (profile); } +#endif /* --------------------------------------------------------------------------------------------- */ diff --git a/lib/widget/history.h b/lib/widget/history.h index 5b569c9ab..461995b36 100644 --- a/lib/widget/history.h +++ b/lib/widget/history.h @@ -24,8 +24,10 @@ extern int num_history_items_recorded; GList *history_get (const char *input_name); /* save history to the mc_config, but don't save config to file */ void history_save (struct mc_config_t * cfg, const char *name, GList * h); +#if 0 /* write history to the ${XDG_CACHE_HOME}/mc/history file */ void history_put (const char *input_name, GList * h); +#endif /* for repositioning of history dialog we should pass widget to this * function, as position of history dialog depends on widget's position */ char *history_show (GList ** history, Widget * widget); diff --git a/lib/widget/input.c b/lib/widget/input.c index e7f33b18b..48f4fa45a 100644 --- a/lib/widget/input.c +++ b/lib/widget/input.c @@ -758,6 +758,30 @@ input_execute_cmd (WInput * in, unsigned long command) /* --------------------------------------------------------------------------------------------- */ +/* "history_save" event handler */ +static gboolean +input_save_history (const gchar * event_group_name, const gchar * event_name, + gpointer init_data, gpointer data) +{ + WInput *in = (WInput *) init_data; + + (void) event_group_name; + (void) event_name; + + if (in->history != NULL && !in->is_password && (((Widget *) in)->owner->ret_value != B_CANCEL)) + { + ev_history_load_save_t *ev = (ev_history_load_save_t *) data; + + if (in->need_push) + push_history (in, in->buffer); + history_save (ev->cfg, in->history_name, in->history); + } + + return TRUE; +} + +/* --------------------------------------------------------------------------------------------- */ + static void input_destroy (WInput * in) { @@ -769,11 +793,10 @@ input_destroy (WInput * in) input_clean (in); + /* clean history */ if (in->history != NULL) { - if (!in->is_password && (((Widget *) in)->owner->ret_value != B_CANCEL)) - history_put (in->history_name, in->history); - + /* history is already saved before this moment */ in->history = g_list_first (in->history); g_list_foreach (in->history, (GFunc) g_free, NULL); g_list_free (in->history); @@ -903,6 +926,11 @@ input_callback (Widget * w, widget_msg_t msg, int parm) switch (msg) { + case WIDGET_INIT: + /* subscribe to "history_save" event */ + mc_event_add (w->owner->event_group, MCEVENT_HISTORY_SAVE, input_save_history, w, NULL); + return MSG_HANDLED; + case WIDGET_KEY: if (parm == XCTRL ('q')) { @@ -943,6 +971,8 @@ input_callback (Widget * w, widget_msg_t msg, int parm) return MSG_HANDLED; case WIDGET_DESTROY: + /* unsubscribe from "history_save" event */ + mc_event_del (w->owner->event_group, MCEVENT_HISTORY_SAVE, input_save_history, w); input_destroy (in); return MSG_HANDLED; @@ -1210,7 +1240,8 @@ input_disable_update (WInput * in) void input_clean (WInput * in) { - push_history (in, in->buffer); + if (in->need_push) + push_history (in, in->buffer); in->need_push = TRUE; in->buffer[0] = '\0'; in->point = 0; diff --git a/src/filemanager/layout.c b/src/filemanager/layout.c index 6f5e39cf0..3f03c620d 100644 --- a/src/filemanager/layout.c +++ b/src/filemanager/layout.c @@ -810,6 +810,7 @@ set_display_type (int num, panel_view_mode_t type) unsigned int the_other = 0; /* Index to the other panel */ const char *file_name = NULL; /* For Quick view */ Widget *new_widget = NULL, *old_widget = NULL; + panel_view_mode_t old_type; WPanel *the_other_panel = NULL; if (num >= MAX_VIEWS) @@ -837,15 +838,13 @@ set_display_type (int num, panel_view_mode_t type) cols = w->cols; lines = w->lines; old_widget = w; + old_type = panels[num].type; - if (panels[num].type == view_listing) + if (old_type == view_listing && panel->frame_size == frame_full && type != view_listing) { - if (panel->frame_size == frame_full && type != view_listing) - { - cols = COLS - first_panel_size; - if (num == 1) - x = first_panel_size; - } + cols = COLS - first_panel_size; + if (num == 1) + x = first_panel_size; } } @@ -897,7 +896,16 @@ set_display_type (int num, panel_view_mode_t type) /* We use replace to keep the circular list of the dialog in the */ /* same state. Maybe we could just kill it and then replace it */ if ((midnight_dlg != NULL) && (old_widget != NULL)) + { + if (old_widget == view_listing) + { + /* save and write directory history of panel + * ... and other histories of midnight_dlg */ + dlg_save_history (midnight_dlg); + } + dlg_replace_widget (old_widget, new_widget); + } if (type == view_listing) { diff --git a/src/filemanager/panel.c b/src/filemanager/panel.c index a4f62f474..24ee4be99 100644 --- a/src/filemanager/panel.c +++ b/src/filemanager/panel.c @@ -1187,6 +1187,28 @@ panel_save_name (WPanel * panel) /* --------------------------------------------------------------------------------------------- */ +/* "history_save" event handler */ +static gboolean +panel_save_history (const gchar * event_group_name, const gchar * event_name, + gpointer init_data, gpointer data) +{ + WPanel *p = (WPanel *) init_data; + + (void) event_group_name; + (void) event_name; + + if (p->dir_history != NULL) + { + ev_history_load_save_t *ev = (ev_history_load_save_t *) data; + + history_save (ev->cfg, p->hist_name, p->dir_history); + } + + return TRUE; +} + +/* --------------------------------------------------------------------------------------------- */ + static void panel_destroy (WPanel * p) { @@ -1203,11 +1225,10 @@ panel_destroy (WPanel * p) panel_clean_dir (p); - /* save and clean history */ + /* clean history */ if (p->dir_history != NULL) { - history_put (p->hist_name, p->dir_history); - + /* directory history is already saved before this moment */ p->dir_history = g_list_first (p->dir_history); g_list_foreach (p->dir_history, (GFunc) g_free, NULL); g_list_free (p->dir_history); @@ -2908,6 +2929,11 @@ panel_callback (Widget * w, widget_msg_t msg, int parm) switch (msg) { + case WIDGET_INIT: + /* subscribe to "history_save" event */ + mc_event_add (w->owner->event_group, MCEVENT_HISTORY_SAVE, panel_save_history, w, NULL); + return MSG_HANDLED; + case WIDGET_DRAW: /* Repaint everything, including frame and separator */ paint_frame (panel); /* including show_dir */ @@ -2956,6 +2982,8 @@ panel_callback (Widget * w, widget_msg_t msg, int parm) return panel_execute_cmd (panel, parm); case WIDGET_DESTROY: + /* unsubscribe from "history_save" event */ + mc_event_del (w->owner->event_group, MCEVENT_HISTORY_SAVE, panel_save_history, w); panel_destroy (panel); free_my_statfs (); return MSG_HANDLED; -- 2.11.4.GIT