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 <aborodin@vmail.ru>
This commit is contained in:
Andrew Borodin 2011-05-02 13:44:47 +04:00
parent b473577525
commit cff5925598
8 changed files with 145 additions and 17 deletions

View File

@ -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 *********************************************************/

View File

@ -24,10 +24,13 @@
#include <config.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> /* 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)
{

View File

@ -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);

View File

@ -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
/* --------------------------------------------------------------------------------------------- */

View File

@ -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);

View File

@ -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;

View File

@ -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)
{

View File

@ -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;