summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor.andersson@artifex.com>2018-09-21 22:55:25 +0200
committerTor Andersson <tor.andersson@artifex.com>2018-09-25 14:39:17 +0200
commita35b410b1e9c2773cf6ae59c2f9b34fe9b908750 (patch)
treea0bcbdf53e7bf4e2fa71a84f63c83e2f9fd0a01c
parentebd1ae69dc462b30a42d76dd17e2f7b8b24b1f2e (diff)
downloadmupdf-a35b410b1e9c2773cf6ae59c2f9b34fe9b908750.tar.xz
gl: Save history and bookmarks in ~/.mupdf.history.
Use MuJS to parse/write JSON object.
-rw-r--r--Makefile2
-rw-r--r--platform/gl/gl-main.c213
-rw-r--r--platform/win32/mupdf-gl.vcproj24
3 files changed, 225 insertions, 14 deletions
diff --git a/Makefile b/Makefile
index 0eebda0f..37fc48e6 100644
--- a/Makefile
+++ b/Makefile
@@ -90,7 +90,7 @@ $(OUT)/platform/x11/curl/%.o : platform/x11/%.c
$(CC_CMD) -Wall $(X11_CFLAGS) $(CURL_CFLAGS) -DHAVE_CURL
$(OUT)/platform/gl/%.o : platform/gl/%.c
- $(CC_CMD) -Wall $(GLUT_CFLAGS)
+ $(CC_CMD) -Wall $(THIRD_CFLAGS) $(GLUT_CFLAGS)
ifeq ($(HAVE_OBJCOPY),yes)
$(OUT)/source/fitz/noto.o : source/fitz/noto.c
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;
diff --git a/platform/win32/mupdf-gl.vcproj b/platform/win32/mupdf-gl.vcproj
index 3f48e261..c5229cce 100644
--- a/platform/win32/mupdf-gl.vcproj
+++ b/platform/win32/mupdf-gl.vcproj
@@ -43,7 +43,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
- AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
+ AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\mujs;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
PreprocessorDefinitions="FREEGLUT_LIB_PRAGMAS=0;FREEGLUT_STATIC;WIN32;_DEBUG"
MinimalRebuild="true"
BasicRuntimeChecks="3"
@@ -121,7 +121,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
- AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
+ AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\mujs;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
PreprocessorDefinitions="FREEGLUT_LIB_PRAGMAS=0;FREEGLUT_STATIC;WIN64;_DEBUG"
MinimalRebuild="true"
BasicRuntimeChecks="3"
@@ -198,7 +198,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
- AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
+ AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\mujs;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
PreprocessorDefinitions="FREEGLUT_LIB_PRAGMAS=0;FREEGLUT_STATIC;WIN32;_DEBUG;MEMENTO"
MinimalRebuild="true"
BasicRuntimeChecks="3"
@@ -273,7 +273,7 @@
/>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
+ AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\mujs;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
PreprocessorDefinitions="FREEGLUT_LIB_PRAGMAS=0;FREEGLUT_STATIC;WIN64;_DEBUG;MEMENTO=1"
RuntimeLibrary="1"
/>
@@ -340,7 +340,7 @@
/>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
+ AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\mujs;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
PreprocessorDefinitions="FREEGLUT_LIB_PRAGMAS=0;FREEGLUT_STATIC;WIN32;NDEBUG"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
@@ -419,7 +419,7 @@
/>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
+ AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\mujs;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
PreprocessorDefinitions="FREEGLUT_LIB_PRAGMAS=0;FREEGLUT_STATIC;WIN64;NDEBUG"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
@@ -496,7 +496,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
- AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
+ AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\mujs;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
PreprocessorDefinitions="FREEGLUT_LIB_PRAGMAS=0;FREEGLUT_STATIC;WIN32;_DEBUG;MEMENTO"
MinimalRebuild="true"
BasicRuntimeChecks="3"
@@ -572,7 +572,7 @@
/>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
+ AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\mujs;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
PreprocessorDefinitions="FREEGLUT_LIB_PRAGMAS=0;FREEGLUT_STATIC;"
RuntimeLibrary="1"
/>
@@ -640,7 +640,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
- AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
+ AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\mujs;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
PreprocessorDefinitions="FREEGLUT_LIB_PRAGMAS=0;FREEGLUT_STATIC;WIN32;_DEBUG"
MinimalRebuild="true"
BasicRuntimeChecks="3"
@@ -718,7 +718,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
- AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
+ AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\mujs;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
PreprocessorDefinitions="FREEGLUT_LIB_PRAGMAS=0;FREEGLUT_STATIC;WIN64;_DEBUG"
MinimalRebuild="true"
BasicRuntimeChecks="3"
@@ -795,7 +795,7 @@
/>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
+ AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\mujs;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
PreprocessorDefinitions="FREEGLUT_LIB_PRAGMAS=0;FREEGLUT_STATIC;WIN32;NDEBUG"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
@@ -874,7 +874,7 @@
/>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
+ AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\mujs;..\..\thirdparty\freeglut\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include"
PreprocessorDefinitions="FREEGLUT_LIB_PRAGMAS=0;FREEGLUT_STATIC;WIN64;NDEBUG"
RuntimeLibrary="0"
UsePrecompiledHeader="0"