[Eve] Improve session saving support.

Use a timer to periodically save the current state: which windows are open,
which tabs are open in which window, which one is focused, etc.  The
relevant entry in the eet file is updated.  This should provide a somewhat
crash-safe approach, which is way better than the previous version.

The timer is currently set to fire every 15s: testing should be performed to
ensure this won't impact performance too much.  Should this be a problem,
this interval might be a user-customized setting.

SVN revision: 52522
This commit is contained in:
Leandro Pereira 2010-09-20 22:14:07 +00:00
parent 98b62fa6e2
commit 9ee9f7523d
6 changed files with 226 additions and 77 deletions

View File

@ -751,6 +751,7 @@ on_view_load_progress(void *data, Evas_Object *view, void *event_info)
{
Evas_Object *chrome = data;
Evas_Object *ed = elm_layout_edje_get(chrome);
Session_Item *si;
double *progress = event_info;
Edje_Message_Float msg = { *progress };
@ -1094,6 +1095,12 @@ conf_updated(More_Menu_Config *mmc, void *new_value)
SET_PREF_TO_ALL_VIEWS(view_touch_interface_set, *((int*)new_value));
break;
}
case EVE_CONFIG_RESTORE_STATE:
/* This setting should be saved immediately, so that if the browser crashes before creating
the initial configuration (and the user chose to save/restore the session), he doesn't
loses the state when reopening the browser. */
config_save(config, NULL);
break;
case EVE_CONFIG_MOUSE_CURSOR:
{
EINA_LIST_FOREACH(app.windows, win_iter, win)
@ -1615,7 +1622,7 @@ on_action_addtab(void *data, Evas_Object *o __UNUSED__,
Evas_Object *ed = elm_layout_edje_get(chrome);
edje_object_signal_emit(ed, "tab,item,clicked", "");
tab_add(win, config_home_page_get(config));
tab_add(win, config_home_page_get(config), NULL);
}
static void
@ -1866,12 +1873,12 @@ tab_grid_state_get(const void *data __UNUSED__, Evas_Object *obj __UNUSED__, con
}
static void
tab_grid_del(const void *data, Evas_Object *obj)
tab_grid_del(const void *data __UNUSED__, Evas_Object *obj __UNUSED__)
{
}
Evas_Object *
chrome_add(Browser_Window *win, const char *url)
chrome_add(Browser_Window *win, const char *url, Session_Item *session_item)
{
Evas_Object *chrome = elm_layout_add(win->win);
Evas_Object *ed = elm_layout_edje_get(chrome);
@ -1895,6 +1902,17 @@ chrome_add(Browser_Window *win, const char *url)
goto error_view_create;
}
if (!session_item)
{
if (!(session_item = session_item_new(url, EINA_FALSE, 0, 0)))
{
CRITICAL("Could not create session object");
goto error_session_create;
}
session_window_tabs_add(win->session_window, session_item);
}
evas_object_data_set(chrome, "session", session_item);
evas_object_focus_set(view, 1);
elm_layout_content_set(chrome, "view", view);
@ -2000,6 +2018,9 @@ chrome_add(Browser_Window *win, const char *url)
chrome_config_apply(chrome);
return chrome;
error_session_create:
evas_object_del(view);
error_view_create:
evas_object_del(chrome);
return NULL;

View File

@ -51,8 +51,8 @@ struct _Fav {
struct _Session_Item {
const char * url;
unsigned char focused;
double scroll_x;
double scroll_y;
int scroll_x;
int scroll_y;
};
struct _Session_Window {
@ -803,8 +803,8 @@ _session_item_init(void)
EET_DATA_DESCRIPTOR_ADD_BASIC(_session_item_descriptor, Session_Item, "url", url, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(_session_item_descriptor, Session_Item, "focused", focused, EET_T_UCHAR);
EET_DATA_DESCRIPTOR_ADD_BASIC(_session_item_descriptor, Session_Item, "scroll_x", scroll_x, EET_T_DOUBLE);
EET_DATA_DESCRIPTOR_ADD_BASIC(_session_item_descriptor, Session_Item, "scroll_y", scroll_y, EET_T_DOUBLE);
EET_DATA_DESCRIPTOR_ADD_BASIC(_session_item_descriptor, Session_Item, "scroll_x", scroll_x, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(_session_item_descriptor, Session_Item, "scroll_y", scroll_y, EET_T_INT);
}
static inline void
@ -816,7 +816,7 @@ _session_item_shutdown(void)
}
Session_Item *
session_item_new(const char * url, unsigned char focused, double scroll_x, double scroll_y)
session_item_new(const char * url, unsigned char focused, int scroll_x, int scroll_y)
{
Session_Item *session_item = calloc(1, sizeof(Session_Item));
@ -867,27 +867,27 @@ session_item_focused_set(Session_Item *session_item, unsigned char focused)
session_item->focused = focused;
}
inline double
inline int
session_item_scroll_x_get(const Session_Item *session_item)
{
return session_item->scroll_x;
}
inline void
session_item_scroll_x_set(Session_Item *session_item, double scroll_x)
session_item_scroll_x_set(Session_Item *session_item, int scroll_x)
{
EINA_SAFETY_ON_NULL_RETURN(session_item);
session_item->scroll_x = scroll_x;
}
inline double
inline int
session_item_scroll_y_get(const Session_Item *session_item)
{
return session_item->scroll_y;
}
inline void
session_item_scroll_y_set(Session_Item *session_item, double scroll_y)
session_item_scroll_y_set(Session_Item *session_item, int scroll_y)
{
EINA_SAFETY_ON_NULL_RETURN(session_item);
session_item->scroll_y = scroll_y;

View File

@ -37,8 +37,8 @@ Fav {
Session_Item {
url : str;
focused : uchar;
scroll_x : double;
scroll_y : double;
scroll_x : int;
scroll_y : int;
}
Session_Window {

View File

@ -99,17 +99,17 @@ Fav *fav_load(const char *filename);
Eina_Bool fav_save(Fav *fav, const char *filename);
/* Session_Item */
Session_Item *session_item_new(const char * url, unsigned char focused, double scroll_x, double scroll_y);
Session_Item *session_item_new(const char * url, unsigned char focused, int scroll_x, int scroll_y);
void session_item_free(Session_Item *session_item);
void session_item_url_set(Session_Item *session_item, const char * url);
const char * session_item_url_get(const Session_Item *session_item);
void session_item_focused_set(Session_Item *session_item, unsigned char focused);
unsigned char session_item_focused_get(const Session_Item *session_item);
void session_item_scroll_x_set(Session_Item *session_item, double scroll_x);
double session_item_scroll_x_get(const Session_Item *session_item);
void session_item_scroll_y_set(Session_Item *session_item, double scroll_y);
double session_item_scroll_y_get(const Session_Item *session_item);
void session_item_scroll_x_set(Session_Item *session_item, int scroll_x);
int session_item_scroll_x_get(const Session_Item *session_item);
void session_item_scroll_y_set(Session_Item *session_item, int scroll_y);
int session_item_scroll_y_get(const Session_Item *session_item);
/* Session_Window */
Session_Window *session_window_new(Eina_List * tabs, unsigned char focused);

View File

@ -24,6 +24,7 @@ int _log_domain = -1;
Hist *hist = NULL;
Fav *fav = NULL;
Config *config = NULL;
Session *session = NULL;
App app;
struct Cursor {
@ -38,7 +39,7 @@ struct Eve_DBus_Request_Name_Response {
};
static void
del_win(App *app, Evas_Object *win)
win_del(App *app, Evas_Object *win)
{
Browser_Window *win_data;
Eina_List *l;
@ -48,6 +49,7 @@ del_win(App *app, Evas_Object *win)
evas_object_del(win);
app->windows = eina_list_remove(app->windows, win_data);
session_window_tabs_list_clear(win_data->session_window);
free(win_data);
if (!app->windows)
@ -57,7 +59,7 @@ del_win(App *app, Evas_Object *win)
static void
on_win_del_req(void *data, Evas_Object *win, void *event_info __UNUSED__)
{
del_win(data, win);
win_del(data, win);
}
void
@ -88,9 +90,9 @@ window_mouse_enabled_set(Evas_Object *win, Eina_Bool setting)
}
Eina_Bool
tab_add(Browser_Window *win, const char *url)
tab_add(Browser_Window *win, const char *url, Session_Item *session_item)
{
Evas_Object *chrome = chrome_add(win, url);
Evas_Object *chrome = chrome_add(win, url, session_item);
if (!chrome)
{
@ -170,15 +172,24 @@ Eina_Bool
tab_close_chrome(Browser_Window *win, Evas_Object *chrome)
{
Evas_Object *edje;
Session_Item *si;
EINA_SAFETY_ON_TRUE_RETURN_VAL(!win, EINA_FALSE);
EINA_SAFETY_ON_TRUE_RETURN_VAL(!chrome, EINA_FALSE);
if ((si = evas_object_data_get(chrome, "session")))
{
Eina_List *tabs = session_window_tabs_list_get(win->session_window);
tabs = eina_list_remove(tabs, si);
session_item_free(si);
session_window_tabs_list_set(win->session_window, tabs);
}
evas_object_del(chrome);
win->chromes = eina_list_remove(win->chromes, chrome);
if (!win->chromes)
{
del_win(win->app, win->win);
win_del(win->app, win->win);
return EINA_TRUE;
}
@ -204,7 +215,7 @@ tab_close_view(Browser_Window *win, Evas_Object *view)
}
static Browser_Window *
add_win(App *app, const char *url)
win_add(App *app, const char *url, Session_Window *session_window, Session_Item *session_item)
{
Browser_Window *win = malloc(sizeof(*win));
@ -222,6 +233,14 @@ add_win(App *app, const char *url)
win->list_history = NULL;
win->list_history_titles = NULL;
if (session_window)
win->session_window = session_window;
else
{
win->session_window = session_window_new(NULL, EINA_FALSE);
session_windows_add(session, win->session_window);
}
win->win = elm_win_add(NULL, "eve", ELM_WIN_BASIC);
if (!win->win)
{
@ -270,7 +289,7 @@ add_win(App *app, const char *url)
elm_win_resize_object_add(win->win, win->pager);
evas_object_show(win->pager);
if (!tab_add(win, url))
if (!tab_add(win, url, session_item))
goto error_tab_add;
app->windows = eina_list_append(app->windows, win);
@ -295,7 +314,7 @@ error_pager_create:
}
/**
* Creates a new window, without any url to load, calling add_win().
* Creates a new window, without any url to load, calling win_add().
*
* @return If a window was successfully created, it returns the correspondent view
* object.
@ -303,7 +322,7 @@ error_pager_create:
Evas_Object *
window_create(void)
{
Browser_Window *win = add_win(&app, NULL);
Browser_Window *win = win_add(&app, NULL, NULL, NULL);
if (!win)
return NULL;
@ -365,7 +384,7 @@ _cb_dbus_open_url(E_DBus_Object *obj __UNUSED__, DBusMessage *msg)
char *new_url;
dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &new_url, DBUS_TYPE_INVALID);
tab_add(win, new_url);
tab_add(win, new_url, NULL);
ecore_x_window_focus(elm_win_xwindow_get(win->win));
return dbus_message_new_method_return(msg);
@ -417,25 +436,142 @@ cleanup:
free(response);
}
static void
state_save(void)
static Eina_Bool
cb_session_save(void *data __UNUSED__)
{
Browser_Window *win;
Eina_List *win_iter;
Eina_List *chrome_iter, *win_iter;
Evas_Object *chrome;
Eina_Bool changed = EINA_FALSE;
Session_Item *si;
if (!config_restore_state_get(config)) return;
prefs_state_list_clear(prefs);
if (!config_restore_state_get(config)) goto end;
EINA_LIST_FOREACH(app.windows, win_iter, win)
{
Evas_Object *chrome;
Eina_List *chrome_iter;
EINA_LIST_FOREACH(win->chromes, chrome_iter, chrome)
{
Evas_Object *view = evas_object_data_get(chrome, "view");
prefs_state_add(prefs, prefs_opened_tab_new(ewk_view_uri_get(view)));
Evas_Object *frame = ewk_view_frame_main_get(view);
const Eina_Bool focused = chrome == win->current_chrome;
const char *url, *wk_url;
int sx, sy;
si = evas_object_data_get(chrome, "session");
if (!si)
{
WRN("chrome %p doesn't have a Session_Item, ignoring", chrome);
continue;
}
url = session_item_url_get(si);
wk_url = ewk_view_uri_get(view);
if ((url && wk_url && strcmp(url, wk_url)) || (wk_url && !url))
{
session_item_url_set(si, wk_url);
changed = EINA_TRUE;
}
ewk_frame_scroll_pos_get(frame, &sx, &sy);
if (session_item_scroll_x_get(si) != sx ||
session_item_scroll_y_get(si) != sy)
{
session_item_scroll_x_set(si, sx);
session_item_scroll_y_set(si, sy);
changed = EINA_TRUE;
}
if (session_item_focused_get(si) != focused)
{
session_item_focused_set(si, focused);
changed = EINA_TRUE;
}
}
}
if (changed)
session_save(session, NULL);
end:
return ECORE_CALLBACK_RENEW;
}
struct _Session_Restore_Scroll {
Evas_Object *frame;
int sx, sy, tries;
};
static Eina_Bool
cb_session_scroll_restore(void *data)
{
struct _Session_Restore_Scroll *srs = data;
if (--srs->tries && ewk_frame_scroll_set(srs->frame, srs->sx, srs->sy))
{
free(srs);
return ECORE_CALLBACK_CANCEL;
}
return ECORE_CALLBACK_RENEW;
}
static void
session_restore_delayed_scroll(Evas_Object *view, Session_Item *item)
{
struct _Session_Restore_Scroll *srs;
if ((srs = calloc(1, sizeof(*srs))))
{
srs->frame = ewk_view_frame_main_get(view);
srs->sx = session_item_scroll_x_get(item);
srs->sy = session_item_scroll_y_get(item);
srs->tries = 10;
ecore_timer_loop_add(1, cb_session_scroll_restore, srs);
}
}
static Eina_Bool
session_restore(void)
{
Eina_List *windows = session_windows_list_get(session);
Eina_List *window_iter;
Session_Window *window;
int n_tabs = 0;
EINA_LIST_FOREACH(windows, window_iter, window)
{
Evas_Object *frame, *focused_chrome;
Eina_List *items = session_window_tabs_list_get(window);
Eina_List *items_iter;
Browser_Window *win;
Session_Item *item;
if (!items) continue;
item = eina_list_data_get(items);
win = win_add(&app, session_item_url_get(item), window, item);
if (!win) continue;
focused_chrome = win->current_chrome;
session_restore_delayed_scroll(win->current_view, item);
n_tabs++;
EINA_LIST_FOREACH(items->next, items_iter, item)
{
if (!tab_add(win, session_item_url_get(item), item))
/*
* Silently ignoring this error is sub-optimal, but bugging the
* user doesn't look like a good alternative either.
*/
continue;
session_restore_delayed_scroll(win->current_view, item);
if (session_item_focused_get(item))
focused_chrome = win->current_chrome;
n_tabs++;
}
tab_focus_chrome(win, focused_chrome);
}
return !!n_tabs;
}
EAPI int
@ -453,6 +589,7 @@ elm_main(int argc, char **argv)
const char *user_agent_str;
E_DBus_Connection *conn;
size_t dirlen;
Ecore_Timer *session_save_timer;
Ecore_Getopt_Value values[] = {
ECORE_GETOPT_VALUE_BOOL(app.is_fullscreen),
@ -563,25 +700,10 @@ elm_main(int argc, char **argv)
basename[0] = '/';
basename++;
dirlen++;
eina_strlcpy(basename, "favorites.db", sizeof(path) - dirlen);
fav = fav_load(path);
if (!fav)
{
fav = fav_new(0);
fav_save(fav, path);
}
eina_strlcpy(basename, "history.db", sizeof(path) - dirlen);
hist = hist_load(path);
if (!hist)
{
hist = hist_new(0);
hist_save(hist, path);
}
eina_strlcpy(basename, "prefs.db", sizeof(path) - dirlen);
prefs = prefs_load(path);
if (!prefs)
eina_strlcpy(basename, "config.eet", sizeof(path) - dirlen);
config = config_load(path);
if (!config)
{
Eina_Bool enable_mouse_cursor, enable_touch_interface, enable_plugins;
@ -633,6 +755,23 @@ elm_main(int argc, char **argv)
}
}
session = session_load(path);
if (!session)
{
session = session_new(NULL);
if (!session_save(session, path))
{
r = -1;
goto end_session;
}
}
session_save_timer = ecore_timer_loop_add(15, cb_session_save, NULL);
if (!session_save_timer)
{
r = -1;
goto end;
}
#define BOOL_OPT(opt) \
if (disable_##opt != 0xff) \
{ \
@ -677,32 +816,15 @@ elm_main(int argc, char **argv)
e_dbus_request_name(conn, "mobi.profusion.eve", 0, _cb_dbus_request_name, response);
}
#if 0
if (prefs_restore_state_get(prefs) && prefs_state_count(config) > 0)
if (config_restore_state_get(config) && session_windows_count(session) > 0 && session_restore())
{
Eina_List *previous_state = prefs_state_list_get(prefs);
Eina_List *state_iter;
Prefs_Opened_Tab *tab = eina_list_data_get(previous_state);
Browser_Window *win;
if (!add_win(&app, prefs_opened_tab_address_get(tab)))
{
r = -1;
goto end;
}
win = eina_list_data_get(app.windows);
EINA_LIST_FOREACH(previous_state->next, state_iter, tab)
tab_add(win, prefs_opened_tab_address_get(tab));
/* session was restored successfully */
}
else
#else
if (!add_win(&app, url))
else if (!win_add(&app, url, NULL, NULL))
{
r = -1;
goto end;
}
#endif
elm_run();
end:
@ -715,7 +837,11 @@ end_hist:
fav_save(fav, NULL);
fav_free(fav);
end_fav:
cb_session_save(session);
session_free(session);
end_session:
if (conn) e_dbus_connection_close(conn);
if (session_save_timer) ecore_timer_del(session_save_timer);
eina_log_domain_unregister(_log_domain);
_log_domain = -1;

View File

@ -45,6 +45,8 @@ struct _Browser_Window
Evas_Object *current_chrome;
Evas_Object *current_view;
Session_Window *session_window;
unsigned int current_tab;
Eina_Bool creating_tab : 1;
@ -88,10 +90,10 @@ Ewk_Context_Menu * view_context_menu_get(Evas_Object *view);
void view_touch_interface_set(Evas_Object *view, Eina_Bool setting);
Eina_Bool view_touch_interface_get(const Evas_Object *view);
Evas_Object * chrome_add(Browser_Window *win, const char *url);
Evas_Object * chrome_add(Browser_Window *win, const char *url, Session_Item *session_item);
void chrome_focused_notify(Evas_Object *chrome);
Eina_Bool tab_add(Browser_Window *win, const char *url);
Eina_Bool tab_add(Browser_Window *win, const char *url, Session_Item *session_item);
Eina_Bool tab_focus_nth(Browser_Window *win, unsigned int n);
Eina_Bool tab_focus_chrome(Browser_Window *win, Evas_Object *chrome);
Eina_Bool tab_focus_next(Browser_Window *win);