mirror of https://github.com/MidnightCommander/mc
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:
parent
b473577525
commit
cff5925598
|
@ -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 *********************************************************/
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue