zathura.c 32.7 KB
Newer Older
1 2
/* See LICENSE file for license and copyright information */

3
#define _BSD_SOURCE
Sebastian Ramacher's avatar
Sebastian Ramacher committed
4
#define _XOPEN_SOURCE 700
5

6
#include <errno.h>
Moritz Lipp's avatar
Moritz Lipp committed
7
#include <stdlib.h>
Pavel Borzenkov's avatar
Pavel Borzenkov committed
8
#include <unistd.h>
9
#include <math.h>
Moritz Lipp's avatar
Moritz Lipp committed
10

11 12 13 14 15
#include <girara/datastructures.h>
#include <girara/utils.h>
#include <girara/session.h>
#include <girara/statusbar.h>
#include <girara/settings.h>
16
#include <glib/gstdio.h>
17
#include <glib/gi18n.h>
18

19
#include "bookmarks.h"
Moritz Lipp's avatar
Moritz Lipp committed
20 21
#include "callbacks.h"
#include "config.h"
22 23 24 25
#ifdef WITH_SQLITE
#include "database-sqlite.h"
#endif
#include "database-plain.h"
26
#include "document.h"
Moritz Lipp's avatar
Moritz Lipp committed
27
#include "shortcuts.h"
Moritz Lipp's avatar
Moritz Lipp committed
28
#include "zathura.h"
Moritz Lipp's avatar
Moritz Lipp committed
29
#include "utils.h"
Moritz Lipp's avatar
Moritz Lipp committed
30
#include "marks.h"
Sebastian Ramacher's avatar
Sebastian Ramacher committed
31
#include "render.h"
Moritz Lipp's avatar
Moritz Lipp committed
32
#include "page.h"
33
#include "page-widget.h"
34
#include "plugin.h"
Moritz Lipp's avatar
Moritz Lipp committed
35

Moritz Lipp's avatar
Moritz Lipp committed
36
typedef struct zathura_document_info_s {
Moritz Lipp's avatar
Moritz Lipp committed
37 38 39 40 41
  zathura_t* zathura;
  const char* path;
  const char* password;
} zathura_document_info_t;

Moritz Lipp's avatar
Moritz Lipp committed
42
typedef struct page_set_delayed_s {
43 44 45 46
  zathura_t* zathura;
  unsigned int page;
} page_set_delayed_t;

Moritz Lipp's avatar
Moritz Lipp committed
47
typedef struct position_set_delayed_s {
48
  zathura_t* zathura;
Moritz Lipp's avatar
Moritz Lipp committed
49 50
  double position_x;
  double position_y;
51 52
} position_set_delayed_t;

53
static gboolean document_info_open(gpointer data);
54
static gboolean purge_pages(gpointer data);
Moritz Lipp's avatar
Moritz Lipp committed
55

Moritz Lipp's avatar
Moritz Lipp committed
56
/* function implementation */
Moritz Lipp's avatar
Moritz Lipp committed
57
zathura_t*
58
zathura_create(void)
59
{
60
  zathura_t* zathura = g_malloc0(sizeof(zathura_t));
61

62 63 64
  /* global settings */
  zathura->global.recolor            = false;
  zathura->global.update_page_number = true;
65
  zathura->global.search_direction = FORWARD;
66

67
  /* plugins */
Moritz Lipp's avatar
Moritz Lipp committed
68 69
  zathura->plugins.manager = zathura_plugin_manager_new();
  if (zathura->plugins.manager == NULL) {
70
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
71
  }
72

73 74 75
  /* UI */
  if ((zathura->ui.session = girara_session_create()) == NULL) {
    goto error_out;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
76 77
  }

78 79 80 81 82 83 84 85 86 87
  zathura->ui.session->global.data = zathura;

  return zathura;

error_out:

  zathura_free(zathura);

  return NULL;
}
Sebastian Ramacher's avatar
Sebastian Ramacher committed
88

89 90 91 92 93
bool
zathura_init(zathura_t* zathura)
{
  if (zathura == NULL) {
    return false;
94 95
  }

96
  /* create zathura (config/data) directory */
97 98 99 100 101 102 103
  if (g_mkdir_with_parents(zathura->config.config_dir, 0771) == -1) {
    girara_error("Could not create '%s': %s", zathura->config.config_dir, strerror(errno));
  }

  if (g_mkdir_with_parents(zathura->config.data_dir, 0771) == -1) {
    girara_error("Could not create '%s': %s", zathura->config.data_dir, strerror(errno));
  }
104

105 106 107
  /* load plugins */
  zathura_plugin_manager_load(zathura->plugins.manager);

108 109 110
  /* configuration */
  config_load_default(zathura);

111
  /* load global configuration files */
Moritz Lipp's avatar
Moritz Lipp committed
112 113
  char* config_path = girara_get_xdg_path(XDG_CONFIG_DIRS);
  girara_list_t* config_dirs = girara_split_path_array(config_path);
114 115 116 117 118 119 120 121
  ssize_t size = girara_list_size(config_dirs) - 1;
  for (; size >= 0; --size) {
    const char* dir = girara_list_nth(config_dirs, size);
    char* file = g_build_filename(dir, ZATHURA_RC, NULL);
    config_load_file(zathura, file);
    g_free(file);
  }
  girara_list_free(config_dirs);
Moritz Lipp's avatar
Moritz Lipp committed
122
  g_free(config_path);
123 124 125

  config_load_file(zathura, GLOBAL_RC);

126 127 128
  /* load local configuration files */
  char* configuration_file = g_build_filename(zathura->config.config_dir, ZATHURA_RC, NULL);
  config_load_file(zathura, configuration_file);
129
  g_free(configuration_file);
130

131
  /* UI */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
132
  if (girara_session_init(zathura->ui.session, "zathura") == false) {
Moritz Lipp's avatar
Moritz Lipp committed
133
    goto error_free;
134 135 136
  }

  /* girara events */
Moritz Lipp's avatar
Moritz Lipp committed
137 138
  zathura->ui.session->events.buffer_changed  = cb_buffer_changed;
  zathura->ui.session->events.unknown_command = cb_unknown_command;
139

140
  /* page view */
141 142
#if (GTK_MAJOR_VERSION == 3)
  zathura->ui.page_widget = gtk_grid_new();
143 144
  gtk_grid_set_row_homogeneous(GTK_GRID(zathura->ui.page_widget), TRUE);
  gtk_grid_set_column_homogeneous(GTK_GRID(zathura->ui.page_widget), TRUE);
145
#else
146
  zathura->ui.page_widget = gtk_table_new(0, 0, TRUE);
147
#endif
Moritz Lipp's avatar
Moritz Lipp committed
148
  if (zathura->ui.page_widget == NULL) {
149 150 151
    goto error_free;
  }

152
  g_signal_connect(G_OBJECT(zathura->ui.session->gtk.window), "size-allocate", G_CALLBACK(cb_view_resized), zathura);
153

Moritz Lipp's avatar
Moritz Lipp committed
154 155 156 157 158 159
  /* callbacks */
  GtkAdjustment* view_vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
  g_signal_connect(G_OBJECT(view_vadjustment), "value-changed", G_CALLBACK(cb_view_vadjustment_value_changed), zathura);
  GtkAdjustment* view_hadjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
  g_signal_connect(G_OBJECT(view_hadjustment), "value-changed", G_CALLBACK(cb_view_vadjustment_value_changed), zathura);

160
  /* page view alignment */
161
  zathura->ui.page_widget_alignment = gtk_alignment_new(0.5, 0.5, 0, 0);
Moritz Lipp's avatar
Moritz Lipp committed
162
  if (zathura->ui.page_widget_alignment == NULL) {
163 164
    goto error_free;
  }
165
  gtk_container_add(GTK_CONTAINER(zathura->ui.page_widget_alignment), zathura->ui.page_widget);
166

167 168 169 170 171 172 173 174
#if (GTK_MAJOR_VERSION == 3)
  gtk_widget_set_hexpand_set(zathura->ui.page_widget_alignment, TRUE);
  gtk_widget_set_hexpand(zathura->ui.page_widget_alignment, FALSE);
  gtk_widget_set_vexpand_set(zathura->ui.page_widget_alignment, TRUE);
  gtk_widget_set_vexpand(zathura->ui.page_widget_alignment, FALSE);
#endif


175
  gtk_widget_show(zathura->ui.page_widget);
Moritz Lipp's avatar
Moritz Lipp committed
176

177
  /* statusbar */
Moritz Lipp's avatar
Moritz Lipp committed
178 179
  zathura->ui.statusbar.file = girara_statusbar_item_add(zathura->ui.session, TRUE, TRUE, TRUE, NULL);
  if (zathura->ui.statusbar.file == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
180
    goto error_free;
Moritz Lipp's avatar
Moritz Lipp committed
181 182
  }

Moritz Lipp's avatar
Moritz Lipp committed
183 184
  zathura->ui.statusbar.buffer = girara_statusbar_item_add(zathura->ui.session, FALSE, FALSE, FALSE, NULL);
  if (zathura->ui.statusbar.buffer == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
185
    goto error_free;
Moritz Lipp's avatar
Moritz Lipp committed
186 187
  }

Moritz Lipp's avatar
Moritz Lipp committed
188
  zathura->ui.statusbar.page_number = girara_statusbar_item_add(zathura->ui.session, FALSE, FALSE, FALSE, NULL);
Moritz Lipp's avatar
Moritz Lipp committed
189
  if (zathura->ui.statusbar.page_number == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
190
    goto error_free;
Moritz Lipp's avatar
Moritz Lipp committed
191 192
  }

Sebastian Ramacher's avatar
Sebastian Ramacher committed
193
  girara_statusbar_item_set_text(zathura->ui.session, zathura->ui.statusbar.file, _("[No name]"));
Moritz Lipp's avatar
Moritz Lipp committed
194

Moritz Lipp's avatar
Moritz Lipp committed
195
  /* signals */
196
  g_signal_connect(G_OBJECT(zathura->ui.session->gtk.window), "destroy", G_CALLBACK(cb_destroy), zathura);
197

198 199 200
  /* set page padding */
  int page_padding = 1;
  girara_setting_get(zathura->ui.session, "page-padding", &page_padding);
Moritz Lipp's avatar
Moritz Lipp committed
201

202 203 204 205
#if (GTK_MAJOR_VERSION == 3)
  gtk_grid_set_row_spacing(GTK_GRID(zathura->ui.page_widget), page_padding);
  gtk_grid_set_column_spacing(GTK_GRID(zathura->ui.page_widget), page_padding);
#else
206 207
  gtk_table_set_row_spacings(GTK_TABLE(zathura->ui.page_widget), page_padding);
  gtk_table_set_col_spacings(GTK_TABLE(zathura->ui.page_widget), page_padding);
208
#endif
Moritz Lipp's avatar
Moritz Lipp committed
209

210
  /* database */
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
  char* database = NULL;
  girara_setting_get(zathura->ui.session, "database", &database);

  if (g_strcmp0(database, "plain") == 0) {
    girara_info("Using plain database backend.");
    zathura->database = zathura_plaindatabase_new(zathura->config.data_dir);
#ifdef WITH_SQLITE
  } else if (g_strcmp0(database, "sqlite") == 0) {
    girara_info("Using sqlite database backend.");
    char* tmp = g_build_filename(zathura->config.data_dir, "bookmarks.sqlite", NULL);
    zathura->database = zathura_sqldatabase_new(tmp);
    g_free(tmp);
#endif
  } else {
    girara_error("Database backend '%s' is not supported.", database);
  }
  g_free(database);

229
  if (zathura->database == NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
230
    girara_error("Unable to initialize database. Bookmarks won't be available.");
231 232
  }

233
  /* bookmarks */
234
  zathura->bookmarks.bookmarks = girara_sorted_list_new2((girara_compare_function_t) zathura_bookmarks_compare,
Moritz Lipp's avatar
Moritz Lipp committed
235
                                 (girara_free_function_t) zathura_bookmark_free);
236

237 238 239 240 241
  /* add even to purge old pages */
  int interval = 30;
  girara_setting_get(zathura->ui.session, "page-store-interval", &interval);
  g_timeout_add_seconds(interval, purge_pages, zathura);

242 243 244 245 246 247 248 249 250 251
  /* jumplist */

  zathura->jumplist.max_size = 20;
  girara_setting_get(zathura->ui.session, "jumplist-size", &(zathura->jumplist.max_size));

  zathura->jumplist.list = girara_list_new2(g_free);
  zathura->jumplist.size = 0;
  zathura->jumplist.cur = NULL;
  zathura_jumplist_append_jump(zathura);
  zathura->jumplist.cur = girara_list_iterator(zathura->jumplist.list);
252
  return true;
Moritz Lipp's avatar
Moritz Lipp committed
253 254 255

error_free:

Moritz Lipp's avatar
Moritz Lipp committed
256
  if (zathura->ui.page_widget != NULL) {
257
    g_object_unref(zathura->ui.page_widget);
258 259
  }

Moritz Lipp's avatar
Moritz Lipp committed
260
  if (zathura->ui.page_widget_alignment != NULL) {
261
    g_object_unref(zathura->ui.page_widget_alignment);
262
  }
Moritz Lipp's avatar
Moritz Lipp committed
263

264
  return false;
Moritz Lipp's avatar
Moritz Lipp committed
265 266 267 268 269 270 271 272 273
}

void
zathura_free(zathura_t* zathura)
{
  if (zathura == NULL) {
    return;
  }

Moritz Lipp's avatar
Moritz Lipp committed
274
  document_close(zathura, false);
275

Moritz Lipp's avatar
Moritz Lipp committed
276 277 278 279
  if (zathura->ui.session != NULL) {
    girara_session_destroy(zathura->ui.session);
  }

280 281 282 283 284 285
  /* stdin support */
  if (zathura->stdin_support.file != NULL) {
    g_unlink(zathura->stdin_support.file);
    g_free(zathura->stdin_support.file);
  }

286 287 288
  /* bookmarks */
  girara_list_free(zathura->bookmarks.bookmarks);

289 290 291
  /* database */
  zathura_db_free(zathura->database);

292
  /* free print settings */
Moritz Lipp's avatar
Moritz Lipp committed
293
  if (zathura->print.settings != NULL) {
294 295 296 297 298 299
    g_object_unref(zathura->print.settings);
  }

  if (zathura->print.page_setup != NULL) {
    g_object_unref(zathura->print.page_setup);
  }
300

Moritz Lipp's avatar
Moritz Lipp committed
301
  /* free registered plugins */
Moritz Lipp's avatar
Moritz Lipp committed
302
  zathura_plugin_manager_free(zathura->plugins.manager);
303 304 305 306

  /* free config variables */
  g_free(zathura->config.config_dir);
  g_free(zathura->config.data_dir);
307

308 309 310 311 312 313 314 315 316
  /* free jumplist */
  if (zathura->jumplist.list != NULL) {
    girara_list_free(zathura->jumplist.list);
  }

  if (zathura->jumplist.cur != NULL) {
    girara_list_iterator_free(zathura->jumplist.cur);
  }

317
  g_free(zathura);
318 319
}

320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
void
#if (GTK_MAJOR_VERSION == 2)
zathura_set_xid(zathura_t* zathura, GdkNativeWindow xid)
#else
zathura_set_xid(zathura_t* zathura, Window xid)
#endif
{
  g_return_if_fail(zathura != NULL);

  zathura->ui.session->gtk.embed = xid;
}

void
zathura_set_config_dir(zathura_t* zathura, const char* dir)
{
  g_return_if_fail(zathura != NULL);

  if (dir != NULL) {
    zathura->config.config_dir = g_strdup(dir);
  } else {
    gchar* path = girara_get_xdg_path(XDG_CONFIG);
    zathura->config.config_dir = g_build_filename(path, "zathura", NULL);
    g_free(path);
  }
}

void
zathura_set_data_dir(zathura_t* zathura, const char* dir)
{
  if (dir != NULL) {
    zathura->config.data_dir = g_strdup(dir);
  } else {
    gchar* path = girara_get_xdg_path(XDG_DATA);
    zathura->config.data_dir = g_build_filename(path, "zathura", NULL);
    g_free(path);
  }

  g_return_if_fail(zathura != NULL);
}

void
zathura_set_plugin_dir(zathura_t* zathura, const char* dir)
{
  g_return_if_fail(zathura != NULL);
  g_return_if_fail(zathura->plugins.manager != NULL);

  if (dir != NULL) {
    girara_list_t* paths = girara_split_path_array(dir);
    GIRARA_LIST_FOREACH(paths, char*, iter, path)
Moritz Lipp's avatar
Moritz Lipp committed
369
    zathura_plugin_manager_add_dir(zathura->plugins.manager, path);
370 371 372 373 374 375
    GIRARA_LIST_FOREACH_END(paths, char*, iter, path);
    girara_list_free(paths);
  } else {
#ifdef ZATHURA_PLUGINDIR
    girara_list_t* paths = girara_split_path_array(ZATHURA_PLUGINDIR);
    GIRARA_LIST_FOREACH(paths, char*, iter, path)
Moritz Lipp's avatar
Moritz Lipp committed
376
    zathura_plugin_manager_add_dir(zathura->plugins.manager, path);
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
    GIRARA_LIST_FOREACH_END(paths, char*, iter, path);
    girara_list_free(paths);
#endif
  }

}

void
zathura_set_synctex_editor_command(zathura_t* zathura, const char* command)
{
  g_return_if_fail(zathura != NULL);

  if (zathura->synctex.editor != NULL) {
    g_free(zathura->synctex.editor);
  }

  if (command != NULL) {
    zathura->synctex.editor = g_strdup(command);
  } else {
    zathura->synctex.editor = NULL;
  }
}

Moritz Lipp's avatar
Moritz Lipp committed
400
void
401
zathura_set_synctex(zathura_t* zathura, bool value)
Moritz Lipp's avatar
Moritz Lipp committed
402 403 404 405 406 407 408
{
  g_return_if_fail(zathura != NULL);
  g_return_if_fail(zathura->ui.session != NULL);

  girara_setting_set(zathura->ui.session, "synctex", &value);
}

409 410 411 412 413 414 415 416
void
zathura_set_argv(zathura_t* zathura, char** argv)
{
  g_return_if_fail(zathura != NULL);

  zathura->global.arguments = argv;
}

417 418 419 420 421 422 423 424
static gchar*
prepare_document_open_from_stdin(zathura_t* zathura)
{
  g_return_val_if_fail(zathura, NULL);

  GError* error = NULL;
  gchar* file = NULL;
  gint handle = g_file_open_tmp("zathura.stdin.XXXXXX", &file, &error);
Moritz Lipp's avatar
Moritz Lipp committed
425
  if (handle == -1) {
426 427 428 429
    if (error != NULL) {
      girara_error("Can not create temporary file: %s", error->message);
      g_error_free(error);
    }
430 431 432 433 434
    return NULL;
  }

  // read from stdin and dump to temporary file
  int stdinfno = fileno(stdin);
Moritz Lipp's avatar
Moritz Lipp committed
435
  if (stdinfno == -1) {
436 437 438 439 440 441 442 443 444
    girara_error("Can not read from stdin.");
    close(handle);
    g_unlink(file);
    g_free(file);
    return NULL;
  }

  char buffer[BUFSIZ];
  ssize_t count = 0;
Moritz Lipp's avatar
Moritz Lipp committed
445 446
  while ((count = read(stdinfno, buffer, BUFSIZ)) > 0) {
    if (write(handle, buffer, count) != count) {
447 448 449 450 451 452 453
      girara_error("Can not write to temporary file: %s", file);
      close(handle);
      g_unlink(file);
      g_free(file);
      return NULL;
    }
  }
Moritz Lipp's avatar
Moritz Lipp committed
454

455 456
  close(handle);

Moritz Lipp's avatar
Moritz Lipp committed
457
  if (count != 0) {
458 459 460 461 462 463 464 465 466
    girara_error("Can not read from stdin.");
    g_unlink(file);
    g_free(file);
    return NULL;
  }

  return file;
}

467
static gboolean
Moritz Lipp's avatar
Moritz Lipp committed
468 469 470 471 472
document_info_open(gpointer data)
{
  zathura_document_info_t* document_info = data;
  g_return_val_if_fail(document_info != NULL, FALSE);

473
  if (document_info->zathura != NULL && document_info->path != NULL) {
474 475 476 477 478
    char* file = NULL;
    if (g_strcmp0(document_info->path, "-") == 0) {
      file = prepare_document_open_from_stdin(document_info->zathura);
      if (file == NULL) {
        girara_notify(document_info->zathura->ui.session, GIRARA_ERROR,
Moritz Lipp's avatar
Moritz Lipp committed
479
                      "Could not read file from stdin and write it to a temporary file.");
480 481
      } else {
        document_info->zathura->stdin_support.file = g_strdup(file);
482 483 484 485 486 487 488 489 490
      }
    } else {
      file = g_strdup(document_info->path);
    }

    if (file != NULL) {
      document_open(document_info->zathura, file, document_info->password);
      g_free(file);
    }
Moritz Lipp's avatar
Moritz Lipp committed
491 492
  }

493
  g_free(document_info);
Moritz Lipp's avatar
Moritz Lipp committed
494
  return FALSE;
495 496
}

Moritz Lipp's avatar
Moritz Lipp committed
497
bool
Moritz Lipp's avatar
Moritz Lipp committed
498
document_open(zathura_t* zathura, const char* path, const char* password)
Moritz Lipp's avatar
Moritz Lipp committed
499
{
500
  if (zathura == NULL || zathura->plugins.manager == NULL || path == NULL) {
501
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
502 503
  }

504 505
  zathura_error_t error = ZATHURA_ERROR_OK;
  zathura_document_t* document = zathura_document_open(zathura->plugins.manager, path, password, &error);
Moritz Lipp's avatar
Moritz Lipp committed
506

Moritz Lipp's avatar
Moritz Lipp committed
507
  if (document == NULL) {
508 509 510 511 512 513 514 515
    if (error == ZATHURA_ERROR_INVALID_PASSWORD) {
      zathura_password_dialog_info_t* password_dialog_info = malloc(sizeof(zathura_password_dialog_info_t));
      if (password_dialog_info != NULL) {
        password_dialog_info->zathura = zathura;

        if (path != NULL) {
          password_dialog_info->path = g_strdup(path);
          girara_dialog(zathura->ui.session, "Enter password:", true, NULL,
Moritz Lipp's avatar
Moritz Lipp committed
516
                        (girara_callback_inputbar_activate_t) cb_password_dialog, password_dialog_info);
517 518 519 520 521 522 523
          goto error_out;
        } else {
          free(password_dialog_info);
        }
      }
      goto error_out;
    }
524
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
525 526
  }

527 528
  const char* file_path        = zathura_document_get_path(document);
  unsigned int number_of_pages = zathura_document_get_number_of_pages(document);
529 530

  /* read history file */
531
  zathura_fileinfo_t file_info = { 0, 0, 1, 0, 0, 0, 0, 0 };
532
  bool known_file = zathura_db_get_fileinfo(zathura->database, file_path, &file_info);
533

Moritz Lipp's avatar
Moritz Lipp committed
534
  /* set page offset */
535
  zathura_document_set_page_offset(document, file_info.page_offset);
536

537
  /* check for valid scale value */
538
  if (file_info.scale <= FLT_EPSILON) {
539 540
    girara_warning("document info: '%s' has non positive scale", file_path);
    zathura_document_set_scale(document, 1);
541
  } else {
542
    zathura_document_set_scale(document, file_info.scale);
543 544 545
  }

  /* check current page number */
546
  if (file_info.current_page > number_of_pages) {
547 548
    girara_warning("document info: '%s' has an invalid page number", file_path);
    zathura_document_set_current_page_number(document, 0);
549
  } else {
550
    zathura_document_set_current_page_number(document, file_info.current_page);
551 552 553
  }

  /* check for valid rotation */
554
  if (file_info.rotation % 90 != 0) {
555 556 557
    girara_warning("document info: '%s' has an invalid rotation", file_path);
    zathura_document_set_rotation(document, 0);
  } else {
558
    zathura_document_set_rotation(document, file_info.rotation % 360);
559 560 561 562 563 564 565 566 567 568 569
  }

  /* jump to first page if setting enabled */
  bool always_first_page = false;
  girara_setting_get(zathura->ui.session, "open-first-page", &always_first_page);
  if (always_first_page == true) {
    zathura_document_set_current_page_number(document, 0);
  }

  /* apply open adjustment */
  char* adjust_open = "best-fit";
570
  if (known_file == false && girara_setting_get(zathura->ui.session, "adjust-open", &(adjust_open)) == true) {
571 572 573 574 575 576 577 578
    if (g_strcmp0(adjust_open, "best-fit") == 0) {
      zathura_document_set_adjust_mode(document, ZATHURA_ADJUST_BESTFIT);
    } else if (g_strcmp0(adjust_open, "width") == 0) {
      zathura_document_set_adjust_mode(document, ZATHURA_ADJUST_WIDTH);
    } else {
      zathura_document_set_adjust_mode(document, ZATHURA_ADJUST_NONE);
    }
    g_free(adjust_open);
579 580
  } else {
    zathura_document_set_adjust_mode(document, ZATHURA_ADJUST_NONE);
581 582 583 584 585
  }

  /* update statusbar */
  girara_statusbar_item_set_text(zathura->ui.session, zathura->ui.statusbar.file, file_path);

Moritz Lipp's avatar
Moritz Lipp committed
586
  /* install file monitor */
587
  gchar* file_uri = g_filename_to_uri(file_path, NULL, NULL);
Moritz Lipp's avatar
Moritz Lipp committed
588 589 590 591 592
  if (file_uri == NULL) {
    goto error_free;
  }

  if (zathura->file_monitor.file == NULL) {
593 594 595 596
    zathura->file_monitor.file = g_file_new_for_uri(file_uri);
    if (zathura->file_monitor.file == NULL) {
      goto error_free;
    }
Moritz Lipp's avatar
Moritz Lipp committed
597 598 599
  }

  if (zathura->file_monitor.monitor == NULL) {
600 601 602 603 604
    zathura->file_monitor.monitor = g_file_monitor_file(zathura->file_monitor.file, G_FILE_MONITOR_NONE, NULL, NULL);
    if (zathura->file_monitor.monitor == NULL) {
      goto error_free;
    }
    g_signal_connect(G_OBJECT(zathura->file_monitor.monitor), "changed", G_CALLBACK(cb_file_monitor), zathura->ui.session);
Moritz Lipp's avatar
Moritz Lipp committed
605 606 607
  }

  if (zathura->file_monitor.file_path == NULL) {
608
    zathura->file_monitor.file_path = g_strdup(file_path);
609 610 611
    if (zathura->file_monitor.file_path == NULL) {
      goto error_free;
    }
Moritz Lipp's avatar
Moritz Lipp committed
612 613
  }

614
  if (password != NULL) {
615
    g_free(zathura->file_monitor.password);
616
    zathura->file_monitor.password = g_strdup(password);
Moritz Lipp's avatar
Moritz Lipp committed
617 618 619 620 621
    if (zathura->file_monitor.password == NULL) {
      goto error_free;
    }
  }

Moritz Lipp's avatar
Moritz Lipp committed
622 623 624 625 626 627
  /* create marks list */
  zathura->global.marks = girara_list_new2((girara_free_function_t) mark_free);
  if (zathura->global.marks == NULL) {
    goto error_free;
  }

Moritz Lipp's avatar
Moritz Lipp committed
628
  zathura->document = document;
Moritz Lipp's avatar
Moritz Lipp committed
629

630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
  /* create blank pages */
  zathura->pages = calloc(number_of_pages, sizeof(GtkWidget*));
  if (zathura->pages == NULL) {
    goto error_free;
  }

  for (unsigned int page_id = 0; page_id < number_of_pages; page_id++) {
    zathura_page_t* page = zathura_document_get_page(document, page_id);
    if (page == NULL) {
      goto error_free;
    }

    GtkWidget* page_widget = zathura_page_widget_new(zathura, page);
    if (page_widget == NULL) {
      goto error_free;
    }

    zathura->pages[page_id] = page_widget;

    /* set widget size */
    unsigned int page_height = 0;
    unsigned int page_width  = 0;
    page_calc_height_width(page, &page_height, &page_width, true);

    gtk_widget_set_size_request(page_widget, page_width, page_height);
  }

657
  /* view mode */
658
  int pages_per_row = 1;
659
  int first_page_column = 1;
660 661 662 663 664
  if (file_info.pages_per_row > 0) {
    pages_per_row = file_info.pages_per_row;
  } else {
    girara_setting_get(zathura->ui.session, "pages-per-row", &pages_per_row);
  }
Moritz Lipp's avatar
Moritz Lipp committed
665

666 667 668 669 670 671
  if (file_info.first_page_column > 0) {
    first_page_column = file_info.first_page_column;
  } else {
    girara_setting_get(zathura->ui.session, "first-page-column", &first_page_column);
  }

Moritz Lipp's avatar
Moritz Lipp committed
672
  girara_setting_set(zathura->ui.session, "pages-per-row", &pages_per_row);
673 674
  girara_setting_set(zathura->ui.session, "first-page-column", &first_page_column);
  page_widget_set_mode(zathura, pages_per_row, first_page_column);
Moritz Lipp's avatar
Moritz Lipp committed
675

676
  girara_set_view(zathura->ui.session, zathura->ui.page_widget_alignment);
Moritz Lipp's avatar
Moritz Lipp committed
677

Moritz Lipp's avatar
Moritz Lipp committed
678
  /* threads */
Moritz Lipp's avatar
Moritz Lipp committed
679
  zathura->sync.render_thread = render_init(zathura);
Moritz Lipp's avatar
Moritz Lipp committed
680

Moritz Lipp's avatar
Moritz Lipp committed
681
  if (zathura->sync.render_thread == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
682 683 684
    goto error_free;
  }

685
  for (unsigned int page_id = 0; page_id < number_of_pages; page_id++) {
686
    gtk_widget_realize(zathura->pages[page_id]);
687
  }
Moritz Lipp's avatar
Moritz Lipp committed
688

689
  /* bookmarks */
690
  zathura_bookmarks_load(zathura, file_path);
691

Moritz Lipp's avatar
Moritz Lipp committed
692
  /* update title */
693 694 695 696 697 698 699 700 701
  bool basename_only = false;
  girara_setting_get(zathura->ui.session, "window-title-basename", &basename_only);
  if (basename_only == false) {
    girara_set_window_title(zathura->ui.session, file_path);
  } else {
    char* tmp = g_path_get_basename(file_path);
    girara_set_window_title(zathura->ui.session, tmp);
    g_free(tmp);
  }
Moritz Lipp's avatar
Moritz Lipp committed
702

703
  g_free(file_uri);
Moritz Lipp's avatar
Moritz Lipp committed
704

705
  /* adjust window */
706
  girara_argument_t argument = { zathura_document_get_adjust_mode(document), NULL };
707 708
  sc_adjust_window(zathura->ui.session, &argument, NULL, 0);

709 710
  /* set position */
  if (file_info.position_x != 0 || file_info.position_y != 0) {
Moritz Lipp's avatar
Moritz Lipp committed
711
    position_set_delayed(zathura, file_info.position_x, file_info.position_y);
712 713 714 715 716
  } else {
    page_set_delayed(zathura, zathura_document_get_current_page_number(document));
    cb_view_vadjustment_value_changed(NULL, zathura);
  }

Moritz Lipp's avatar
Moritz Lipp committed
717
  return true;
718 719 720

error_free:

Moritz Lipp's avatar
Moritz Lipp committed
721 722 723 724
  if (file_uri != NULL) {
    g_free(file_uri);
  }

725 726 727 728 729
  zathura_document_free(document);

error_out:

  return false;
Moritz Lipp's avatar
Moritz Lipp committed
730 731
}

732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
void
document_open_idle(zathura_t* zathura, const char* path, const char* password)
{
  if (zathura == NULL || path == NULL) {
    return;
  }

  zathura_document_info_t* document_info = g_malloc0(sizeof(zathura_document_info_t));

  document_info->zathura  = zathura;
  document_info->path     = path;
  document_info->password = password;

  gdk_threads_add_idle(document_info_open, document_info);
}

748 749 750 751 752 753 754 755
bool
document_save(zathura_t* zathura, const char* path, bool overwrite)
{
  g_return_val_if_fail(zathura, false);
  g_return_val_if_fail(zathura->document, false);
  g_return_val_if_fail(path, false);

  gchar* file_path = girara_fix_path(path);
Moritz Lipp's avatar
Moritz Lipp committed
756
  if ((overwrite == false) && g_file_test(file_path, G_FILE_TEST_EXISTS)) {
757
    girara_error("File already exists: %s. Use :write! to overwrite it.", file_path);
758
    g_free(file_path);
759 760 761
    return false;
  }

762
  zathura_error_t error = zathura_document_save_as(zathura->document, file_path);
763
  g_free(file_path);
764

765
  return (error == ZATHURA_ERROR_OK) ? true : false;
766 767
}

Pavel Borzenkov's avatar
Pavel Borzenkov committed
768 769 770
static void
remove_page_from_table(GtkWidget* page, gpointer permanent)
{
Moritz Lipp's avatar
Moritz Lipp committed
771
  if (permanent == false) {
Pavel Borzenkov's avatar
Pavel Borzenkov committed
772 773 774
    g_object_ref(G_OBJECT(page));
  }

775
  gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(page)), page);
Pavel Borzenkov's avatar
Pavel Borzenkov committed
776 777
}

Moritz Lipp's avatar
Moritz Lipp committed
778
bool
Moritz Lipp's avatar
Moritz Lipp committed
779
document_close(zathura_t* zathura, bool keep_monitor)
Moritz Lipp's avatar
Moritz Lipp committed
780
{
Moritz Lipp's avatar
Moritz Lipp committed
781
  if (zathura == NULL || zathura->document == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
782 783 784
    return false;
  }

Moritz Lipp's avatar
Moritz Lipp committed
785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808
  /* remove monitor */
  if (keep_monitor == false) {
    if (zathura->file_monitor.monitor != NULL) {
      g_file_monitor_cancel(zathura->file_monitor.monitor);
      g_object_unref(zathura->file_monitor.monitor);
      zathura->file_monitor.monitor = NULL;
    }

    if (zathura->file_monitor.file != NULL) {
      g_object_unref(zathura->file_monitor.file);
      zathura->file_monitor.file = NULL;
    }

    if (zathura->file_monitor.file_path != NULL) {
      g_free(zathura->file_monitor.file_path);
      zathura->file_monitor.file_path = NULL;
    }

    if (zathura->file_monitor.password != NULL) {
      g_free(zathura->file_monitor.password);
      zathura->file_monitor.password = NULL;
    }
  }

Moritz Lipp's avatar
Moritz Lipp committed
809 810 811 812 813 814
  /* remove marks */
  if (zathura->global.marks != NULL) {
    girara_list_free(zathura->global.marks);
    zathura->global.marks = NULL;
  }

815 816
  /* store file information */
  const char* path = zathura_document_get_path(zathura->document);
817

818
  zathura_fileinfo_t file_info = { 0, 0, 1, 0, 1, 1, 0, 0 };
819 820 821 822 823
  file_info.current_page = zathura_document_get_current_page_number(zathura->document);
  file_info.page_offset  = zathura_document_get_page_offset(zathura->document);
  file_info.scale        = zathura_document_get_scale(zathura->document);
  file_info.rotation     = zathura_document_get_rotation(zathura->document);

824
  girara_setting_get(zathura->ui.session, "pages-per-row", &(file_info.pages_per_row));
825
  girara_setting_get(zathura->ui.session, "first-page-column", &(file_info.first_page_column));
826 827 828 829 830 831 832 833 834 835

  /* get position */
  GtkScrolledWindow *window = GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view);
  GtkAdjustment* vadjustment = gtk_scrolled_window_get_vadjustment(window);
  GtkAdjustment* hadjustment = gtk_scrolled_window_get_hadjustment(window);

  file_info.position_x = gtk_adjustment_get_value(hadjustment);
  file_info.position_y = gtk_adjustment_get_value(vadjustment);

  /* save file info */
836
  zathura_db_set_fileinfo(zathura->database, path, &file_info);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
837

838
  /* release render thread */
Pavel Borzenkov's avatar
Pavel Borzenkov committed
839 840 841
  render_free(zathura->sync.render_thread);
  zathura->sync.render_thread = NULL;

842
  /* remove widgets */
843
  gtk_container_foreach(GTK_CONTAINER(zathura->ui.page_widget), remove_page_from_table, (gpointer) 1);
Moritz Lipp's avatar
Moritz Lipp committed
844 845 846
  for (unsigned int i = 0; i < zathura_document_get_number_of_pages(zathura->document); i++) {
    g_object_unref(zathura->pages[i]);
  }
847 848
  free(zathura->pages);
  zathura->pages = NULL;
Moritz Lipp's avatar
Moritz Lipp committed
849

850
  /* remove document */
Moritz Lipp's avatar
Moritz Lipp committed
851
  zathura_document_free(zathura->document);
Pavel Borzenkov's avatar
Pavel Borzenkov committed
852 853
  zathura->document = NULL;

854 855 856 857 858 859
  /* remove index */
  if (zathura->ui.index != NULL) {
    g_object_ref_sink(zathura->ui.index);
    zathura->ui.index = NULL;
  }

860
  gtk_widget_hide(zathura->ui.page_widget);
861 862 863 864

  statusbar_page_number_update(zathura);

  if (zathura->ui.session != NULL && zathura->ui.statusbar.file != NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
865
    girara_statusbar_item_set_text(zathura->ui.session, zathura->ui.statusbar.file, _("[No name]"));
866
  }
Moritz Lipp's avatar
Moritz Lipp committed
867

Moritz Lipp's avatar
Moritz Lipp committed
868 869 870
  /* update title */
  girara_set_window_title(zathura->ui.session, "zathura");

Moritz Lipp's avatar
Moritz Lipp committed
871 872 873
  return true;
}

874
static gboolean
Sebastian Ramacher's avatar
Sebastian Ramacher committed
875 876
page_set_delayed_impl(gpointer data)
{
877 878 879 880 881 882 883 884 885 886
  page_set_delayed_t* p = data;
  page_set(p->zathura, p->page);

  g_free(p);
  return FALSE;
}

bool
page_set_delayed(zathura_t* zathura, unsigned int page_id)
{
887 888
  if (zathura == NULL || zathura->document == NULL ||
      (page_id >= zathura_document_get_number_of_pages(zathura->document))) {
889 890 891 892 893 894
    return false;
  }

  page_set_delayed_t* p = g_malloc(sizeof(page_set_delayed_t));
  p->zathura = zathura;
  p->page = page_id;
895
  gdk_threads_add_idle(page_set_delayed_impl, p);
896 897 898
  return true;
}

Moritz Lipp's avatar
Moritz Lipp committed
899
bool
Moritz Lipp's avatar
Moritz Lipp committed
900
page_set(zathura_t* zathura, unsigned int page_id)
Moritz Lipp's avatar
Moritz Lipp committed
901
{
902
  if (zathura == NULL || zathura->document == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
903
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
904 905
  }

906
  /* render page */
907
  zathura_page_t* page = zathura_document_get_page(zathura->document, page_id);
Moritz Lipp's avatar
Moritz Lipp committed
908

Moritz Lipp's avatar
Moritz Lipp committed
909
  if (page == NULL) {
910 911 912
    goto error_out;
  }

913
  zathura_document_set_current_page_number(zathura->document, page_id);
914
  zathura->global.update_page_number = false;
915

916
  page_offset_t offset;
917
  page_calculate_offset(zathura, page, &offset);
Moritz Lipp's avatar
Moritz Lipp committed
918

Moritz Lipp's avatar
Moritz Lipp committed
919
  GtkAdjustment* view_vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
Moritz Lipp's avatar
Moritz Lipp committed
920
  GtkAdjustment* view_hadjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
921 922
  set_adjustment(view_hadjustment, offset.x);
  set_adjustment(view_vadjustment, offset.y);
923

Moritz Lipp's avatar
Moritz Lipp committed
924 925
  statusbar_page_number_update(zathura);

Moritz Lipp's avatar
Moritz Lipp committed
926
  return true;
Moritz Lipp's avatar
Moritz Lipp committed
927 928 929 930

error_out:

  return false;
Moritz Lipp's avatar
Moritz Lipp committed
931 932
}

933 934 935 936 937 938 939
void
statusbar_page_number_update(zathura_t* zathura)
{
  if (zathura == NULL || zathura->ui.statusbar.page_number == NULL) {
    return;
  }

940 941 942
  unsigned int number_of_pages     = zathura_document_get_number_of_pages(zathura->document);
  unsigned int current_page_number = zathura_document_get_current_page_number(zathura->document);

943
  if (zathura->document != NULL) {
944
    char* page_number_text = g_strdup_printf("[%d/%d]", current_page_number + 1, number_of_pages);
945 946 947 948 949
    girara_statusbar_item_set_text(zathura->ui.session, zathura->ui.statusbar.page_number, page_number_text);
    g_free(page_number_text);
  } else {
    girara_statusbar_item_set_text(zathura->ui.session, zathura->ui.statusbar.page_number, "");
  }
950 951
}

952
void
953
page_widget_set_mode(zathura_t* zathura, unsigned int pages_per_row, unsigned int first_page_column)
954
{
Moritz Lipp's avatar
Moritz Lipp committed
955 956 957 958 959
  /* show at least one page */
  if (pages_per_row == 0) {
    pages_per_row = 1;
  }

Moritz Lipp's avatar
Moritz Lipp committed
960 961 962 963
  /* ensure: 0 < first_page_column <= pages_per_row */
  if (first_page_column < 1) {
    first_page_column = 1;
  }
964

Moritz Lipp's avatar
Moritz Lipp committed
965 966 967
  if (first_page_column > pages_per_row) {
    first_page_column = ((first_page_column - 1) % pages_per_row) + 1;
  }
968

969 970 971 972
  if (zathura->document == NULL) {
    return;
  }

973
  gtk_container_foreach(GTK_CONTAINER(zathura->ui.page_widget), remove_page_from_table, (gpointer)0);
974

975
  unsigned int number_of_pages     = zathura_document_get_number_of_pages(zathura->document);
976 977
#if (GTK_MAJOR_VERSION == 3)
#else
978
  gtk_table_resize(GTK_TABLE(zathura->ui.page_widget), ceil((number_of_pages + first_page_column - 1) / pages_per_row), pages_per_row);
979 980 981
#endif

  for (unsigned int i = 0; i < number_of_pages; i++) {
982 983
    int x = (i + first_page_column - 1) % pages_per_row;
    int y = (i + first_page_column - 1) / pages_per_row;
Moritz Lipp's avatar
Moritz Lipp committed
984

985
    zathura_page_t* page   = zathura_document_get_page(zathura->document, i);
986
    GtkWidget* page_widget = zathura_page_get_widget(zathura, page);
987 988 989
#if (GTK_MAJOR_VERSION == 3)
    gtk_grid_attach(GTK_GRID(zathura->ui.page_widget), page_widget, x, y, 1, 1);
#else
Moritz Lipp's avatar
Moritz Lipp committed
990
    gtk_table_attach(GTK_TABLE(zathura->ui.page_widget), page_widget, x, x + 1, y, y + 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
991
#endif
992 993
  }

994
  gtk_widget_show_all(zathura->ui.page_widget);
995
}
996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010

static
gboolean purge_pages(gpointer data)
{
  zathura_t* zathura = data;
  if (zathura == NULL || zathura->document == NULL) {
    return TRUE;
  }

  int threshold = 0;
  girara_setting_get(zathura->ui.session, "page-store-threshold", &threshold);
  if (threshold <= 0) {
    return TRUE;
  }

Sebastian Ramacher's avatar
Sebastian Ramacher committed
1011
  girara_debug("purging pages ...");
1012 1013 1014
  unsigned int number_of_pages = zathura_document_get_number_of_pages(zathura->document);
  for (unsigned int page_id = 0; page_id < number_of_pages; page_id++) {
    zathura_page_t* page   = zathura_document_get_page(zathura->document, page_id);
1015
    GtkWidget* page_widget = zathura_page_get_widget(zathura, page);
Moritz Lipp's avatar
Moritz Lipp committed
1016
    zathura_page_widget_purge_unused(ZATHURA_PAGE(page_widget), threshold);
1017 1018 1019
  }
  return TRUE;
}
1020 1021

static gboolean
Moritz Lipp's avatar
Moritz Lipp committed
1022
position_set_delayed_impl(gpointer data)
1023 1024 1025 1026 1027 1028 1029
{
  position_set_delayed_t* p = (position_set_delayed_t*) data;

  GtkScrolledWindow *window = GTK_SCROLLED_WINDOW(p->zathura->ui.session->gtk.view);
  GtkAdjustment* vadjustment = gtk_scrolled_window_get_vadjustment(window);
  GtkAdjustment* hadjustment = gtk_scrolled_window_get_hadjustment(window);

1030 1031
  set_adjustment(hadjustment, p->position_x);
  set_adjustment(vadjustment, p->position_y);
1032

Moritz Lipp's avatar
Moritz Lipp committed
1033 1034
  g_free(p);

1035 1036
  return FALSE;
}
Moritz Lipp's avatar
Moritz Lipp committed
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048

bool
position_set_delayed(zathura_t* zathura, double position_x, double position_y)
{
  position_set_delayed_t* p = g_malloc0(sizeof(position_set_delayed_t));

  p->zathura    = zathura;
  p->position_x = position_x;
  p->position_y = position_y;

  gdk_threads_add_idle(position_set_delayed_impl, p);

Moritz Lipp's avatar
Moritz Lipp committed
1049
  return FALSE;
Moritz Lipp's avatar
Moritz Lipp committed
1050
}
1051 1052 1053


zathura_jump_t*
Moritz Lipp's avatar
Moritz Lipp committed
1054 1055
zathura_jumplist_current(zathura_t* zathura)
{
1056 1057 1058 1059 1060 1061 1062 1063
  if (zathura->jumplist.cur != NULL) {
    return girara_list_iterator_data(zathura->jumplist.cur);
  } else {
    return NULL;
  }
}

void
Moritz Lipp's avatar
Moritz Lipp committed
1064 1065
zathura_jumplist_forward(zathura_t* zathura)
{
1066 1067 1068 1069 1070 1071
  if (girara_list_iterator_has_next(zathura->jumplist.cur)) {
    girara_list_iterator_next(zathura->jumplist.cur);
  }
}

void
Moritz Lipp's avatar
Moritz Lipp committed
1072 1073
zathura_jumplist_backward(zathura_t* zathura)
{
1074 1075 1076 1077 1078 1079
  if (girara_list_iterator_has_previous(zathura->jumplist.cur)) {
    girara_list_iterator_previous(zathura->jumplist.cur);
  }
}

void
Moritz Lipp's avatar
Moritz Lipp committed
1080 1081
zathura_jumplist_append_jump(zathura_t* zathura)
{
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
  zathura_jump_t *jump = g_malloc(sizeof(zathura_jump_t));
  if (jump != NULL) {
    jump->page = 0;
    jump->x = 0;
    jump->y = 0;

    /* remove right tail after current */
    if (zathura->jumplist.cur != NULL) {
      girara_list_iterator_t *it = girara_list_iterator_copy(zathura->jumplist.cur);
      girara_list_iterator_next(it);
      while (girara_list_iterator_is_valid(it)) {
        girara_list_iterator_remove(it);
        zathura->jumplist.size = zathura->jumplist.size - 1;
      }
      g_free(it);
    }

    /* trim from beginning until max_size */
    girara_list_iterator_t *it = girara_list_iterator(zathura->jumplist.list);
    while (zathura->jumplist.size >= zathura->jumplist.max_size && girara_list_iterator_is_valid(it)) {
      girara_list_iterator_remove(it);
      zathura->jumplist.size = zathura->jumplist.size - 1;
    }
    g_free(it);

    girara_list_append(zathura->jumplist.list, jump);
    zathura->jumplist.size = zathura->jumplist.size + 1;
  }
}

void
Moritz Lipp's avatar
Moritz Lipp committed
1113 1114
zathura_jumplist_add(zathura_t* zathura)
{
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129
  if (zathura->jumplist.list != NULL) {
    unsigned int pagenum = zathura_document_get_current_page_number(zathura->document);
    zathura_jump_t* cur = zathura_jumplist_current(zathura);
    if (cur && cur->page == pagenum) {
      return;
    }

    zathura_jumplist_append_jump(zathura);
    girara_list_iterator_next(zathura->jumplist.cur);
    zathura_jumplist_save(zathura);
  }
}


void
Moritz Lipp's avatar
Moritz Lipp committed
1130 1131
zathura_jumplist_save(zathura_t* zathura)
{
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
  zathura_jump_t* cur = zathura_jumplist_current(zathura);

  unsigned int pagenum = zathura_document_get_current_page_number(zathura->document);

  if (cur) {
    /* get position */
    GtkAdjustment* view_vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
    GtkAdjustment* view_hadjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));

    cur->page = pagenum;
1142 1143
    cur->x = gtk_adjustment_get_value(view_hadjustment) / zathura_document_get_scale(zathura->document);
    cur->y = gtk_adjustment_get_value(view_vadjustment) / zathura_document_get_scale(zathura->document);;
1144 1145
  }
}