summaryrefslogtreecommitdiff
path: root/platform/gl/gl-main.c
diff options
context:
space:
mode:
Diffstat (limited to 'platform/gl/gl-main.c')
-rw-r--r--platform/gl/gl-main.c213
1 files changed, 212 insertions, 1 deletions
diff --git a/platform/gl/gl-main.c b/platform/gl/gl-main.c
index dcb97c21..fad822fa 100644
--- a/platform/gl/gl-main.c
+++ b/platform/gl/gl-main.c
@@ -5,12 +5,15 @@
#include <stdlib.h>
#include <stdio.h>
+#include "mujs.h"
+
#ifndef PATH_MAX
#define PATH_MAX 2048
#endif
#ifndef _WIN32
#include <unistd.h> /* for fork and exec */
+char *realpath(const char *path, char *resolved_path); /* in gl-file.c */
#endif
#ifdef __APPLE__
@@ -143,6 +146,203 @@ static int future_count = 0;
static struct mark future[256];
static struct mark marks[10];
+static char *get_history_filename(void)
+{
+ static char history_path[PATH_MAX];
+ static int once = 0;
+ if (!once)
+ {
+ char *home = getenv("HOME");
+ if (!home)
+ home = getenv("USERPROFILE");
+ if (!home)
+ home = "/tmp";
+ fz_snprintf(history_path, sizeof history_path, "%s/.mupdf.history", home);
+ fz_cleanname(history_path);
+ once = 1;
+ }
+ return history_path;
+}
+
+static void read_history_file_as_json(js_State *J)
+{
+ fz_buffer *buf = NULL;
+ const char *json = "{}";
+
+ fz_var(buf);
+
+ if (fz_file_exists(ctx, get_history_filename()))
+ {
+ fz_try(ctx)
+ {
+ buf = fz_read_file(ctx, get_history_filename());
+ json = fz_string_from_buffer(ctx, buf);
+ }
+ fz_catch(ctx)
+ ;
+ }
+
+ js_getglobal(J, "JSON");
+ js_getproperty(J, -1, "parse");
+ js_pushnull(J);
+ js_pushstring(J, json);
+ if (js_pcall(J, 1))
+ {
+ fz_warn(ctx, "Can't parse history file: %s", js_trystring(J, -1, "error"));
+ js_pop(J, 1);
+ js_newobject(J);
+ }
+ else
+ {
+ js_rot2pop1(J);
+ }
+
+ fz_drop_buffer(ctx, buf);
+}
+
+static void load_history(void)
+{
+ js_State *J;
+ char absname[PATH_MAX];
+ int i, n;
+
+ if (!realpath(filename, absname))
+ return;
+
+ J = js_newstate(NULL, NULL, 0);
+
+ read_history_file_as_json(J);
+
+ if (js_hasproperty(J, -1, absname))
+ {
+ if (js_hasproperty(J, -1, "current"))
+ {
+ currentpage = js_tryinteger(J, -1, 1) - 1;
+ js_pop(J, 1);
+ }
+
+ if (js_hasproperty(J, -1, "history"))
+ {
+ if (js_isarray(J, -1))
+ {
+ history_count = fz_clampi(js_getlength(J, -1), 0, nelem(history));
+ for (i = 0; i < history_count; ++i)
+ {
+ js_getindex(J, -1, i);
+ history[i].page = js_tryinteger(J, -1, 1) - 1;
+ js_pop(J, 1);
+ }
+ }
+ js_pop(J, 1);
+ }
+
+ if (js_hasproperty(J, -1, "future"))
+ {
+ if (js_isarray(J, -1))
+ {
+ future_count = fz_clampi(js_getlength(J, -1), 0, nelem(future));
+ for (i = 0; i < future_count; ++i)
+ {
+ js_getindex(J, -1, i);
+ future[i].page = js_tryinteger(J, -1, 1) - 1;
+ js_pop(J, 1);
+ }
+ }
+ js_pop(J, 1);
+ }
+
+ if (js_hasproperty(J, -1, "marks"))
+ {
+ if (js_isarray(J, -1))
+ {
+ n = fz_clampi(js_getlength(J, -1), 0, nelem(marks));
+ for (i = 0; i < n; ++i)
+ {
+ js_getindex(J, -1, i);
+ marks[i].page = js_tryinteger(J, -1, 1) - 1;
+ js_pop(J, 1);
+ }
+ }
+ js_pop(J, 1);
+ }
+ }
+
+ js_freestate(J);
+}
+
+static void save_history(void)
+{
+ js_State *J;
+ char absname[PATH_MAX];
+ fz_output *out = NULL;
+ const char *json;
+ int i;
+
+ fz_var(out);
+
+ if (!realpath(filename, absname))
+ return;
+
+ J = js_newstate(NULL, NULL, 0);
+
+ read_history_file_as_json(J);
+
+ js_newobject(J);
+ {
+ js_pushnumber(J, currentpage+1);
+ js_setproperty(J, -2, "current");
+
+ js_newarray(J);
+ for (i = 0; i < history_count; ++i)
+ {
+ js_pushnumber(J, history[i].page+1);
+ js_setindex(J, -2, i);
+ }
+ js_setproperty(J, -2, "history");
+
+ js_newarray(J);
+ for (i = 0; i < future_count; ++i)
+ {
+ js_pushnumber(J, future[i].page+1);
+ js_setindex(J, -2, i);
+ }
+ js_setproperty(J, -2, "future");
+
+ js_newarray(J);
+ for (i = 0; i < nelem(marks); ++i)
+ {
+ js_pushnumber(J, marks[i].page+1);
+ js_setindex(J, -2, i);
+ }
+ js_setproperty(J, -2, "marks");
+ }
+ js_setproperty(J, -2, absname);
+
+ js_getglobal(J, "JSON");
+ js_getproperty(J, -1, "stringify");
+ js_pushnull(J);
+ js_copy(J, -4);
+ js_pushnull(J);
+ js_pushnumber(J, 0);
+ js_call(J, 3);
+ js_rot2pop1(J);
+ json = js_tostring(J, -1);
+
+ fz_try(ctx)
+ {
+ out = fz_new_output_with_path(ctx, get_history_filename(), 0);
+ fz_write_string(ctx, out, json);
+ fz_write_byte(ctx, out, '\n');
+ fz_close_output(ctx, out);
+ }
+ fz_always(ctx)
+ fz_drop_output(ctx, out);
+ fz_catch(ctx)
+ fz_warn(ctx, "Can't write history file.");
+
+ js_freestate(J);
+}
+
static int search_active = 0;
static struct input search_input = { { 0 }, 0 };
static char *search_needle = 0;
@@ -160,7 +360,11 @@ static void error_dialog(void)
ui_label("%C %s", 0x1f4a3, error_message); /* BOMB */
ui_layout(B, NONE, S, 2, 2);
if (ui_button("Quit") || ui.key == KEY_ENTER || ui.key == KEY_ESCAPE || ui.key == 'q')
+ {
+ if (doc)
+ save_history();
exit(1);
+ }
ui_dialog_end();
}
void ui_show_error_dialog(const char *fmt, ...)
@@ -290,6 +494,8 @@ static void restore_mark(struct mark mark)
static void push_history(void)
{
+ if (history_count > 0 && history[history_count-1].page == currentpage)
+ return;
if (history_count + 1 >= nelem(history))
{
memmove(history, history + 1, sizeof *history * (nelem(history) - 1));
@@ -656,11 +862,13 @@ static void load_document(void)
}
anchor = NULL;
+ load_history();
currentpage = fz_clampi(currentpage, 0, fz_count_pages(ctx, doc) - 1);
}
void reload(void)
{
+ save_history();
load_document();
if (doc)
{
@@ -778,7 +986,10 @@ static void clear_search(void)
static void do_app(void)
{
if (ui.key == KEY_F4 && ui.mod == GLUT_ACTIVE_ALT)
+ {
+ save_history();
glutLeaveMainLoop();
+ }
if (ui.down || ui.middle || ui.right || ui.key)
showinfo = showhelp = 0;
@@ -795,7 +1006,7 @@ static void do_app(void)
case 'F': showform = !showform; break;
case 'i': showinfo = !showinfo; break;
case 'r': reload(); break;
- case 'q': glutLeaveMainLoop(); break;
+ case 'q': save_history(); glutLeaveMainLoop(); break;
case 'I': currentinvert = !currentinvert; break;
case 'f': toggle_fullscreen(); break;