zathura.c 40.2 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 <girara/shortcuts.h>
17
#include <glib/gstdio.h>
18
#include <glib/gi18n.h>
19

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

Moritz Lipp's avatar
Moritz Lipp committed
39
typedef struct zathura_document_info_s {
Moritz Lipp's avatar
Moritz Lipp committed
40 41 42
  zathura_t* zathura;
  const char* path;
  const char* password;
43
  int page_number;
Moritz Lipp's avatar
Moritz Lipp committed
44 45
} zathura_document_info_t;

46

47
static gboolean document_info_open(gpointer data);
48 49 50
static void zathura_jumplist_reset_current(zathura_t* zathura);
static void zathura_jumplist_append_jump(zathura_t* zathura);
static void zathura_jumplist_save(zathura_t* zathura);
Moritz Lipp's avatar
Moritz Lipp committed
51

Moritz Lipp's avatar
Moritz Lipp committed
52
/* function implementation */
Moritz Lipp's avatar
Moritz Lipp committed
53
zathura_t*
54
zathura_create(void)
55
{
56
  zathura_t* zathura = g_malloc0(sizeof(zathura_t));
57

58
  /* global settings */
59
  zathura->global.search_direction = FORWARD;
60

61
  /* plugins */
Moritz Lipp's avatar
Moritz Lipp committed
62 63
  zathura->plugins.manager = zathura_plugin_manager_new();
  if (zathura->plugins.manager == NULL) {
64
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
65
  }
66

67 68 69
  /* UI */
  if ((zathura->ui.session = girara_session_create()) == NULL) {
    goto error_out;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
70 71
  }

72 73 74 75 76 77 78 79 80 81
  zathura->ui.session->global.data = zathura;

  return zathura;

error_out:

  zathura_free(zathura);

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

83 84 85 86 87
bool
zathura_init(zathura_t* zathura)
{
  if (zathura == NULL) {
    return false;
88 89
  }

90
  /* create zathura (config/data) directory */
91 92 93 94 95 96 97
  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));
  }
98

99 100 101
  /* load plugins */
  zathura_plugin_manager_load(zathura->plugins.manager);

102 103
  /* configuration */
  config_load_default(zathura);
104
  config_load_files(zathura);
105

106
  /* UI */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
107
  if (girara_session_init(zathura->ui.session, "zathura") == false) {
Moritz Lipp's avatar
Moritz Lipp committed
108
    goto error_free;
109 110 111
  }

  /* girara events */
Moritz Lipp's avatar
Moritz Lipp committed
112 113
  zathura->ui.session->events.buffer_changed  = cb_buffer_changed;
  zathura->ui.session->events.unknown_command = cb_unknown_command;
114

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
  /* zathura signals */
  zathura->signals.refresh_view = g_signal_new("refresh-view",
                                               GTK_TYPE_WIDGET,
                                               G_SIGNAL_RUN_LAST,
                                               0,
                                               NULL,
                                               NULL,
                                               g_cclosure_marshal_generic,
                                               G_TYPE_NONE,
                                               1,
                                               G_TYPE_POINTER);

  g_signal_connect(G_OBJECT(zathura->ui.session->gtk.view), "refresh-view",
                   G_CALLBACK(cb_refresh_view), zathura);

130
  /* page view */
131
  zathura->ui.page_widget = gtk_grid_new();
132 133
  gtk_grid_set_row_homogeneous(GTK_GRID(zathura->ui.page_widget), TRUE);
  gtk_grid_set_column_homogeneous(GTK_GRID(zathura->ui.page_widget), TRUE);
Moritz Lipp's avatar
Moritz Lipp committed
134
  if (zathura->ui.page_widget == NULL) {
135 136 137
    goto error_free;
  }

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

140
  GtkAdjustment* hadjustment = gtk_scrolled_window_get_hadjustment(
141
                 GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
142 143 144

  /* Connect hadjustment signals */
  g_signal_connect(G_OBJECT(hadjustment), "value-changed",
145
      G_CALLBACK(cb_view_hadjustment_value_changed), zathura);
146 147 148 149
  g_signal_connect(G_OBJECT(hadjustment), "changed",
      G_CALLBACK(cb_view_hadjustment_changed), zathura);

  GtkAdjustment* vadjustment = gtk_scrolled_window_get_vadjustment(
150
                 GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
151 152 153 154 155 156

  /* Connect vadjustment signals */
  g_signal_connect(G_OBJECT(vadjustment), "value-changed",
      G_CALLBACK(cb_view_vadjustment_value_changed), zathura);
  g_signal_connect(G_OBJECT(vadjustment), "changed",
      G_CALLBACK(cb_view_vadjustment_changed), zathura);
Moritz Lipp's avatar
Moritz Lipp committed
157

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

165 166 167 168 169
  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);

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

172
  /* statusbar */
Moritz Lipp's avatar
Moritz Lipp committed
173 174
  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
175
    goto error_free;
Moritz Lipp's avatar
Moritz Lipp committed
176 177
  }

Moritz Lipp's avatar
Moritz Lipp committed
178 179
  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
180
    goto error_free;
Moritz Lipp's avatar
Moritz Lipp committed
181 182
  }

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

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

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

193
  /* database */
194 195 196 197
  char* database = NULL;
  girara_setting_get(zathura->ui.session, "database", &database);

  if (g_strcmp0(database, "plain") == 0) {
198
    girara_debug("Using plain database backend.");
199 200 201
    zathura->database = zathura_plaindatabase_new(zathura->config.data_dir);
#ifdef WITH_SQLITE
  } else if (g_strcmp0(database, "sqlite") == 0) {
202
    girara_debug("Using sqlite database backend.");
203 204 205 206 207 208 209 210 211
    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);

212
  if (zathura->database == NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
213
    girara_error("Unable to initialize database. Bookmarks won't be available.");
214
  } else {
215
    g_object_set(zathura->ui.session->command_history, "io", zathura->database, NULL);
216 217
  }

218
  /* bookmarks */
219
  zathura->bookmarks.bookmarks = girara_sorted_list_new2((girara_compare_function_t) zathura_bookmarks_compare,
Moritz Lipp's avatar
Moritz Lipp committed
220
                                 (girara_free_function_t) zathura_bookmark_free);
221

222 223
  /* jumplist */

224 225
  int jumplist_size = 20;
  girara_setting_get(zathura->ui.session, "jumplist-size", &jumplist_size);
226

227 228
  zathura->jumplist.max_size = jumplist_size < 0 ? 0 : jumplist_size;
  zathura->jumplist.list = NULL;
229 230
  zathura->jumplist.size = 0;
  zathura->jumplist.cur = NULL;
231

232
  return true;
Moritz Lipp's avatar
Moritz Lipp committed
233 234 235

error_free:

Moritz Lipp's avatar
Moritz Lipp committed
236
  if (zathura->ui.page_widget != NULL) {
237
    g_object_unref(zathura->ui.page_widget);
238 239
  }

Moritz Lipp's avatar
Moritz Lipp committed
240
  if (zathura->ui.page_widget_alignment != NULL) {
241
    g_object_unref(zathura->ui.page_widget_alignment);
242
  }
Moritz Lipp's avatar
Moritz Lipp committed
243

244
  return false;
Moritz Lipp's avatar
Moritz Lipp committed
245 246 247 248 249 250 251 252 253
}

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

Moritz Lipp's avatar
Moritz Lipp committed
254
  document_close(zathura, false);
255

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

260 261 262 263 264 265
  /* stdin support */
  if (zathura->stdin_support.file != NULL) {
    g_unlink(zathura->stdin_support.file);
    g_free(zathura->stdin_support.file);
  }

266 267 268
  /* bookmarks */
  girara_list_free(zathura->bookmarks.bookmarks);

269
  /* database */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
270 271 272
  if (zathura->database != NULL) {
    g_object_unref(G_OBJECT(zathura->database));
  }
273

274
  /* free print settings */
Moritz Lipp's avatar
Moritz Lipp committed
275
  if (zathura->print.settings != NULL) {
276 277 278 279 280 281
    g_object_unref(zathura->print.settings);
  }

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

Moritz Lipp's avatar
Moritz Lipp committed
283
  /* free registered plugins */
Moritz Lipp's avatar
Moritz Lipp committed
284
  zathura_plugin_manager_free(zathura->plugins.manager);
285 286 287 288

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

290 291 292 293 294 295 296 297 298
  /* 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);
  }

299
  g_free(zathura);
300 301
}

302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 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
void
zathura_set_xid(zathura_t* zathura, Window xid)
{
  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
347
    zathura_plugin_manager_add_dir(zathura->plugins.manager, path);
348 349 350 351 352 353
    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
354
    zathura_plugin_manager_add_dir(zathura->plugins.manager, path);
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
    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
378
void
379
zathura_set_synctex(zathura_t* zathura, bool value)
Moritz Lipp's avatar
Moritz Lipp committed
380 381 382 383 384 385 386
{
  g_return_if_fail(zathura != NULL);
  g_return_if_fail(zathura->ui.session != NULL);

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

387 388 389 390 391 392 393 394
void
zathura_set_argv(zathura_t* zathura, char** argv)
{
  g_return_if_fail(zathura != NULL);

  zathura->global.arguments = argv;
}

395 396 397 398 399 400 401 402
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
403
  if (handle == -1) {
404 405 406 407
    if (error != NULL) {
      girara_error("Can not create temporary file: %s", error->message);
      g_error_free(error);
    }
408 409 410 411 412
    return NULL;
  }

  // read from stdin and dump to temporary file
  int stdinfno = fileno(stdin);
Moritz Lipp's avatar
Moritz Lipp committed
413
  if (stdinfno == -1) {
414 415 416 417 418 419 420 421 422
    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
423 424
  while ((count = read(stdinfno, buffer, BUFSIZ)) > 0) {
    if (write(handle, buffer, count) != count) {
425 426 427 428 429 430 431
      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
432

433 434
  close(handle);

Moritz Lipp's avatar
Moritz Lipp committed
435
  if (count != 0) {
436 437 438 439 440 441 442 443 444
    girara_error("Can not read from stdin.");
    g_unlink(file);
    g_free(file);
    return NULL;
  }

  return file;
}

445
static gboolean
Moritz Lipp's avatar
Moritz Lipp committed
446 447 448 449 450
document_info_open(gpointer data)
{
  zathura_document_info_t* document_info = data;
  g_return_val_if_fail(document_info != NULL, FALSE);

451
  if (document_info->zathura != NULL && document_info->path != NULL) {
452 453 454 455 456
    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,
457
                      _("Could not read file from stdin and write it to a temporary file."));
458 459
      } else {
        document_info->zathura->stdin_support.file = g_strdup(file);
460 461 462 463 464 465
      }
    } else {
      file = g_strdup(document_info->path);
    }

    if (file != NULL) {
466 467
      document_open(document_info->zathura, file, document_info->password,
                    document_info->page_number);
468 469
      g_free(file);
    }
Moritz Lipp's avatar
Moritz Lipp committed
470 471
  }

472
  g_free(document_info);
Moritz Lipp's avatar
Moritz Lipp committed
473
  return FALSE;
474 475
}

Moritz Lipp's avatar
Moritz Lipp committed
476
bool
477 478
document_open(zathura_t* zathura, const char* path, const char* password,
              int page_number)
Moritz Lipp's avatar
Moritz Lipp committed
479
{
480
  if (zathura == NULL || zathura->plugins.manager == NULL || path == NULL) {
481
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
482 483
  }

484
  gchar* file_uri = NULL;
485 486
  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
487

Moritz Lipp's avatar
Moritz Lipp committed
488
  if (document == NULL) {
489 490 491 492 493 494 495 496
    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
497
                        (girara_callback_inputbar_activate_t) cb_password_dialog, password_dialog_info);
498 499 500 501 502 503 504
          goto error_out;
        } else {
          free(password_dialog_info);
        }
      }
      goto error_out;
    }
Moritz Lipp's avatar
Moritz Lipp committed
505 506 507
    if (error == ZATHURA_ERROR_OK ) {
      girara_notify(zathura->ui.session, GIRARA_ERROR, _("Unsupported file type. Please install the necessary plugin."));
    }
508
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
509 510
  }

511 512
  const char* file_path        = zathura_document_get_path(document);
  unsigned int number_of_pages = zathura_document_get_number_of_pages(document);
513

514 515 516 517 518 519
  if (number_of_pages == 0) {
    girara_notify(zathura->ui.session, GIRARA_WARNING,
        _("Document does not contain any pages"));
    goto error_free;
  }

520
  /* read history file */
521 522 523 524 525 526 527 528 529 530 531
  zathura_fileinfo_t file_info = {
    .current_page = 0,
    .page_offset = 0,
    .scale = 1,
    .rotation = 0,
    .pages_per_row = 0,
    .first_page_column = 0,
    .position_x = 0,
    .position_y = 0
  };
  const bool known_file = zathura_db_get_fileinfo(zathura->database, file_path, &file_info);
532

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

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

  /* check current page number */
545 546 547 548 549 550
  /* if it wasn't specified on the command-line, get it from file_info */
  if (page_number == ZATHURA_PAGE_NUMBER_UNSPECIFIED)
    page_number = file_info.current_page;
  if (page_number < 0)
    page_number += number_of_pages;
  if ((unsigned)page_number > number_of_pages) {
551 552
    girara_warning("document info: '%s' has an invalid page number", file_path);
    zathura_document_set_current_page_number(document, 0);
553
  } else {
554
    zathura_document_set_current_page_number(document, page_number);
555 556 557
  }

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

  /* 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";
574
  if (known_file == false && girara_setting_get(zathura->ui.session, "adjust-open", &(adjust_open)) == true) {
575 576 577 578 579 580 581 582
    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);
583 584
  } else {
    zathura_document_set_adjust_mode(document, ZATHURA_ADJUST_NONE);
585 586
  }

587 588 589 590 591
  /* initialize bisect state */
  zathura->bisect.start = 0;
  zathura->bisect.last_jump = zathura_document_get_current_page_number(document);
  zathura->bisect.end = number_of_pages - 1;

592
  /* update statusbar */
593 594 595 596 597
  bool basename_only = false;
  girara_setting_get(zathura->ui.session, "statusbar-basename", &basename_only);
  if (basename_only == false) {
    girara_statusbar_item_set_text(zathura->ui.session, zathura->ui.statusbar.file, file_path);
  } else {
598
    girara_statusbar_item_set_text(zathura->ui.session, zathura->ui.statusbar.file, zathura_document_get_basename(document));
599
  }
600

Moritz Lipp's avatar
Moritz Lipp committed
601
  /* install file monitor */
602
  file_uri = g_filename_to_uri(file_path, NULL, NULL);
Moritz Lipp's avatar
Moritz Lipp committed
603 604 605 606 607
  if (file_uri == NULL) {
    goto error_free;
  }

  if (zathura->file_monitor.file == NULL) {
608 609 610 611
    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
612 613 614
  }

  if (zathura->file_monitor.monitor == NULL) {
615 616 617 618 619
    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
620 621 622
  }

  if (zathura->file_monitor.file_path == NULL) {
623
    zathura->file_monitor.file_path = g_strdup(file_path);
624 625 626
    if (zathura->file_monitor.file_path == NULL) {
      goto error_free;
    }
Moritz Lipp's avatar
Moritz Lipp committed
627 628
  }

629
  if (password != NULL) {
630
    g_free(zathura->file_monitor.password);
631
    zathura->file_monitor.password = g_strdup(password);
Moritz Lipp's avatar
Moritz Lipp committed
632 633 634 635 636
    if (zathura->file_monitor.password == NULL) {
      goto error_free;
    }
  }

Moritz Lipp's avatar
Moritz Lipp committed
637 638 639 640 641 642
  /* 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
643
  zathura->document = document;
Moritz Lipp's avatar
Moritz Lipp committed
644

645 646 647 648 649 650 651 652 653
  /* page cache size */
  int cache_size = 0;
  girara_setting_get(zathura->ui.session, "page-cache-size", &cache_size);
  if (cache_size <= 0) {
    girara_warning("page-cache-size is not positive, using %d instead",
        ZATHURA_PAGE_CACHE_DEFAULT_SIZE);
    cache_size = ZATHURA_PAGE_CACHE_DEFAULT_SIZE;
  }

654
  /* threads */
655
  zathura->sync.render_thread = zathura_renderer_new(cache_size);
656 657 658 659 660

  if (zathura->sync.render_thread == NULL) {
    goto error_free;
  }

Sebastian Ramacher's avatar
Sebastian Ramacher committed
661
  /* set up recolor info in ZathuraRenderer */
662 663 664 665 666 667 668 669 670
  char* recolor_dark = NULL;
  char* recolor_light = NULL;
  girara_setting_get(zathura->ui.session, "recolor-darkcolor", &recolor_dark);
  girara_setting_get(zathura->ui.session, "recolor-lightcolor", &recolor_light);
  zathura_renderer_set_recolor_colors_str(zathura->sync.render_thread,
      recolor_light, recolor_dark);
  g_free(recolor_dark);
  g_free(recolor_light);

671 672 673 674 675 676
  bool recolor = false;
  girara_setting_get(zathura->ui.session, "recolor", &recolor);
  zathura_renderer_enable_recolor(zathura->sync.render_thread, recolor);
  girara_setting_get(zathura->ui.session, "recolor-keephue", &recolor);
  zathura_renderer_enable_recolor_hue(zathura->sync.render_thread, recolor);

677 678 679 680 681 682
  /* get view port size */
  GtkAdjustment* hadjustment = gtk_scrolled_window_get_hadjustment(
                 GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
  GtkAdjustment* vadjustment = gtk_scrolled_window_get_vadjustment(
                 GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));

683
  const unsigned int view_width = (unsigned int)floor(gtk_adjustment_get_page_size(hadjustment));
684
  zathura_document_set_viewport_width(zathura->document, view_width);
685
  const unsigned int view_height = (unsigned int)floor(gtk_adjustment_get_page_size(vadjustment));
686 687
  zathura_document_set_viewport_height(zathura->document, view_height);

688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
  /* 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;

707 708 709
    g_signal_connect(G_OBJECT(page_widget), "text-selected",
        G_CALLBACK(cb_page_widget_text_selected), zathura);
    g_signal_connect(G_OBJECT(page_widget), "image-selected",
710
        G_CALLBACK(cb_page_widget_image_selected), zathura);
711 712
  }

713
  /* view mode */
714 715 716 717 718 719
  unsigned int pages_per_row = 1;
  unsigned int first_page_column = 1;
  unsigned int page_padding = 1;

  girara_setting_get(zathura->ui.session, "page-padding", &page_padding);

720 721 722 723 724
  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
725

726 727 728 729 730 731
  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
732
  girara_setting_set(zathura->ui.session, "pages-per-row", &pages_per_row);
733
  girara_setting_set(zathura->ui.session, "first-page-column", &first_page_column);
734 735 736

  page_widget_set_mode(zathura, page_padding, pages_per_row, first_page_column);
  zathura_document_set_page_layout(zathura->document, page_padding, pages_per_row, first_page_column);
Moritz Lipp's avatar
Moritz Lipp committed
737

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

Moritz Lipp's avatar
Moritz Lipp committed
740

741
  /* bookmarks */
742
  zathura_bookmarks_load(zathura, file_path);
743

744 745 746 747 748
  /* jumplist */
  if (zathura_jumplist_load(zathura, file_path) == false) {
    zathura->jumplist.list = girara_list_new2(g_free);
  }

Moritz Lipp's avatar
Moritz Lipp committed
749
  /* update title */
750
  basename_only = false;
751 752 753 754
  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 {
755
    girara_set_window_title(zathura->ui.session, zathura_document_get_basename(document));
756
  }
Moritz Lipp's avatar
Moritz Lipp committed
757

758
  g_free(file_uri);
Moritz Lipp's avatar
Moritz Lipp committed
759

760
  /* adjust_view */
761
  adjust_view(zathura);
762 763 764 765 766 767 768 769 770
  for (unsigned int page_id = 0; page_id < number_of_pages; page_id++) {
    /* set widget size */
    zathura_page_t* page = zathura_document_get_page(document, page_id);
    unsigned int page_height = 0;
    unsigned int page_width  = 0;

    /* adjust_view calls render_all in some cases and render_all calls
     * gtk_widget_set_size_request. To be sure that it's really called, do it
     * here once again. */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
771 772
    const double height = zathura_page_get_height(page);
    const double width = zathura_page_get_width(page);
773 774 775 776 777 778
    page_calc_height_width(zathura->document, height, width, &page_height, &page_width, true);
    gtk_widget_set_size_request(zathura->pages[page_id], page_width, page_height);

    /* show widget */
    gtk_widget_show(zathura->pages[page_id]);
  }
779

780
  /* Set page */
781
  page_set(zathura, zathura_document_get_current_page_number(document));
782 783

  /* Set position (only if restoring from history file) */
Sebastian Ramacher's avatar
CS  
Sebastian Ramacher committed
784 785 786
  if (file_info.current_page == zathura_document_get_current_page_number(document) &&
      (file_info.position_x != 0 || file_info.position_y != 0)) {
    position_set(zathura, file_info.position_x, file_info.position_y);
787 788
  }

789 790 791 792 793 794
  /* Start D-Bus service for synctex forward synchronization */
  bool synctex_dbus = true;
  girara_setting_get(zathura->ui.session, "synctex-dbus-service", &synctex_dbus);
  if (synctex_dbus == true) {
    zathura->synctex.dbus = zathura_synctex_dbus_new(zathura);
  }
795

Moritz Lipp's avatar
Moritz Lipp committed
796
  return true;
797 798 799

error_free:

Moritz Lipp's avatar
Moritz Lipp committed
800 801 802 803
  if (file_uri != NULL) {
    g_free(file_uri);
  }

804 805 806 807 808
  zathura_document_free(document);

error_out:

  return false;
Moritz Lipp's avatar
Moritz Lipp committed
809 810
}

811
void
812 813
document_open_idle(zathura_t* zathura, const char* path, const char* password,
                   int page_number)
814 815 816 817 818 819 820
{
  if (zathura == NULL || path == NULL) {
    return;
  }

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

821 822 823 824
  document_info->zathura     = zathura;
  document_info->path        = path;
  document_info->password    = password;
  document_info->page_number = page_number;
825 826 827 828

  gdk_threads_add_idle(document_info_open, document_info);
}

829 830 831 832 833 834 835 836
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);
837 838 839 840 841 842 843 844 845
  /* use current basename if path points to a directory  */
  if (g_file_test(file_path, G_FILE_TEST_IS_DIR) == TRUE) {
    char* basename = g_path_get_basename(zathura_document_get_path(zathura->document));
    char* tmp = file_path;
    file_path = g_strconcat(file_path, "/", basename, NULL);
    g_free(tmp);
    g_free(basename);
  }

Moritz Lipp's avatar
Moritz Lipp committed
846
  if ((overwrite == false) && g_file_test(file_path, G_FILE_TEST_EXISTS)) {
847
    girara_error("File already exists: %s. Use :write! to overwrite it.", file_path);
848
    g_free(file_path);
849 850 851
    return false;
  }

852
  zathura_error_t error = zathura_document_save_as(zathura->document, file_path);
853
  g_free(file_path);
854

855
  return (error == ZATHURA_ERROR_OK) ? true : false;
856 857
}

Pavel Borzenkov's avatar
Pavel Borzenkov committed
858 859 860
static void
remove_page_from_table(GtkWidget* page, gpointer permanent)
{
Moritz Lipp's avatar
Moritz Lipp committed
861
  if (permanent == false) {
Pavel Borzenkov's avatar
Pavel Borzenkov committed
862 863 864
    g_object_ref(G_OBJECT(page));
  }

865
  gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(page)), page);
Pavel Borzenkov's avatar
Pavel Borzenkov committed
866 867
}

Moritz Lipp's avatar
Moritz Lipp committed
868
bool
Moritz Lipp's avatar
Moritz Lipp committed
869
document_close(zathura_t* zathura, bool keep_monitor)
Moritz Lipp's avatar
Moritz Lipp committed
870
{
Moritz Lipp's avatar
Moritz Lipp committed
871
  if (zathura == NULL || zathura->document == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
872 873 874
    return false;
  }

875 876 877
  /* stop rendering */
  zathura_renderer_stop(zathura->sync.render_thread);

878 879 880 881 882 883
  /* stop D-Bus */
  if (zathura->synctex.dbus != NULL) {
    g_object_unref(zathura->synctex.dbus);
    zathura->synctex.dbus = NULL;
  }

Moritz Lipp's avatar
Moritz Lipp committed
884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
  /* 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
908 909 910 911 912 913
  /* remove marks */
  if (zathura->global.marks != NULL) {
    girara_list_free(zathura->global.marks);
    zathura->global.marks = NULL;
  }

914 915
  /* store file information */
  const char* path = zathura_document_get_path(zathura->document);
916

917
  zathura_fileinfo_t file_info = { 0, 0, 1, 0, 1, 1, 0, 0 };
918 919 920 921 922
  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);

923
  girara_setting_get(zathura->ui.session, "pages-per-row", &(file_info.pages_per_row));
924
  girara_setting_get(zathura->ui.session, "first-page-column", &(file_info.first_page_column));
925 926

  /* get position */
927 928
  file_info.position_x = zathura_document_get_position_x(zathura->document);
  file_info.position_y = zathura_document_get_position_y(zathura->document);
929 930

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

933 934 935 936 937 938 939 940
  /* save jumplist */
  zathura_db_save_jumplist(zathura->database, path, zathura->jumplist.list);
  girara_list_iterator_free(zathura->jumplist.cur);
  zathura->jumplist.cur = NULL;
  girara_list_free(zathura->jumplist.list);
  zathura->jumplist.list = NULL;
  zathura->jumplist.size = 0;

941
  /* release render thread */
942
  g_object_unref(zathura->sync.render_thread);
Pavel Borzenkov's avatar
Pavel Borzenkov committed
943 944
  zathura->sync.render_thread = NULL;

945
  /* remove widgets */
946
  gtk_container_foreach(GTK_CONTAINER(zathura->ui.page_widget), remove_page_from_table, (gpointer) 1);
Moritz Lipp's avatar
Moritz Lipp committed
947 948
  for (unsigned int i = 0; i < zathura_document_get_number_of_pages(zathura->document); i++) {
    g_object_unref(zathura->pages[i]);
949
    g_object_unref(zathura->pages[i]); // FIXME
Moritz Lipp's avatar
Moritz Lipp committed
950
  }
951 952
  free(zathura->pages);
  zathura->pages = NULL;
Moritz Lipp's avatar
Moritz Lipp committed
953

954
  /* remove document */
Moritz Lipp's avatar
Moritz Lipp committed
955
  zathura_document_free(zathura->document);
Pavel Borzenkov's avatar
Pavel Borzenkov committed
956 957
  zathura->document = NULL;

958 959 960 961 962 963
  /* remove index */
  if (zathura->ui.index != NULL) {
    g_object_ref_sink(zathura->ui.index);
    zathura->ui.index = NULL;
  }

964
  gtk_widget_hide(zathura->ui.page_widget);
965 966 967 968

  statusbar_page_number_update(zathura);

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

Moritz Lipp's avatar
Moritz Lipp committed
972 973 974
  /* update title */
  girara_set_window_title(zathura->ui.session, "zathura");

Moritz Lipp's avatar
Moritz Lipp committed
975 976 977 978
  return true;
}

bool
Moritz Lipp's avatar
Moritz Lipp committed
979
page_set(zathura_t* zathura, unsigned int page_id)
Moritz Lipp's avatar
Moritz Lipp committed
980
{
981
  if (zathura == NULL || zathura->document == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
982
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
983 984
  }

985
  zathura_page_t* page = zathura_document_get_page(zathura->document, page_id);
Moritz Lipp's avatar
Moritz Lipp committed
986
  if (page == NULL) {
987 988 989
    goto error_out;
  }

990
  zathura_document_set_current_page_number(zathura->document, page_id);
991

992 993
  /* negative position means auto */
  return position_set(zathura, -1, -1);
Moritz Lipp's avatar
Moritz Lipp committed
994 995 996

error_out:
  return false;
Moritz Lipp's avatar
Moritz Lipp committed
997 998
}

999 1000 1001 1002 1003 1004 1005
void
statusbar_page_number_update(zathura_t* zathura)
{
  if (zathura == NULL || zathura->ui.statusbar.page_number == NULL) {
    return;
  }

1006 1007 1008
  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);

1009
  if (zathura->document != NULL) {
1010
    char* page_number_text = g_strdup_printf("[%d/%d]", current_page_number + 1, number_of_pages);
1011
    girara_statusbar_item_set_text(zathura->ui.session, zathura->ui.statusbar.page_number, page_number_text);
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027

    bool page_number_in_window_title = false;
    girara_setting_get(zathura->ui.session, "window-title-page", &page_number_in_window_title);

    if (page_number_in_window_title == true) {
      bool basename_only = false;
      girara_setting_get(zathura->ui.session, "window-title-basename", &basename_only);
      char* title = g_strdup_printf("%s %s",
        (basename_only == true)
          ? zathura_document_get_basename(zathura->document)
          : zathura_document_get_path(zathura->document),
        page_number_text);
      girara_set_window_title(zathura->ui.session, title);
      g_free(title);
    }

1028 1029 1030 1031
    g_free(page_number_text);
  } else {
    girara_statusbar_item_set_text(zathura->ui.session, zathura->ui.statusbar.page_number, "");
  }
1032 1033
}

1034
void
1035 1036
page_widget_set_mode(zathura_t* zathura, unsigned int page_padding,
                     unsigned int pages_per_row, unsigned int first_page_column)
1037
{
Moritz Lipp's avatar
Moritz Lipp committed
1038 1039 1040 1041 1042
  /* show at least one page */
  if (pages_per_row == 0) {
    pages_per_row = 1;
  }

Moritz Lipp's avatar
Moritz Lipp committed
1043 1044 1045 1046 1047 1048 1049
  /* ensure: 0 < first_page_column <= pages_per_row */
  if (first_page_column < 1) {
    first_page_column = 1;
  }
  if (first_page_column > pages_per_row) {
    first_page_column = ((first_page_column - 1) % pages_per_row) + 1;
  }
1050

1051 1052 1053 1054
  if (zathura->document == NULL) {
    return;
  }

1055
  gtk_container_foreach(GTK_CONTAINER(zathura->ui.page_widget), remove_page_from_table, (gpointer)0);
1056

1057
  unsigned int number_of_pages     = zathura_document_get_number_of_pages(zathura->document);
1058 1059 1060 1061

  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);

1062
  for (unsigned int i = 0; i < number_of_pages; i++) {
1063 1064
    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
1065

1066
    zathura_page_t* page   = zathura_document_get_page(zathura->document, i);
1067
    GtkWidget* page_widget = zathura_page_get_widget(zathura, page);
1068
    gtk_grid_attach(GTK_GRID(zathura->ui.page_widget), page_widget, x, y, 1, 1);
1069 1070
  }

1071
  gtk_widget_show_all(zathura->ui.page_widget);
1072
}
1073

1074
bool
1075 1076
position_set(zathura_t* zathura, double position_x, double position_y)
{
1077 1078 1079
  if (zathura == NULL || zathura->document == NULL) {
    goto error_out;
  }
1080

1081 1082
  double comppos_x, comppos_y;
  unsigned int page_id = zathura_document_get_current_page_number(zathura->document);
1083

1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102
  /* xalign = 0.5: center horizontally (with the page, not the document) */
  /* yalign = 0.0: align page an viewport edges at the top               */
  page_number_to_position(zathura->document, page_id, 0.5, 0.0, &comppos_x, &comppos_y);

  /* automatic horizontal adjustment */
  zathura_adjust_mode_t adjust_mode = zathura_document_get_adjust_mode(zathura->document);

  /* negative position_x mean: use the computed value */
  if (position_x < 0) {
    position_x = comppos_x;
    bool zoom_center = false;
    girara_setting_get(zathura->ui.session, "zoom-center", &zoom_center);

    /* center horizontally */
    if (adjust_mode == ZATHURA_ADJUST_BESTFIT ||
      adjust_mode == ZATHURA_ADJUST_WIDTH ||
      zoom_center) {
        position_x = 0.5;
    }
1103 1104
  }

1105 1106
  if (position_y < 0) {
    position_y = comppos_y;
1107
  }
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119

  /* set the position */
  zathura_document_set_position_x(zathura->document, position_x);
  zathura_document_set_position_y(zathura->document, position_y);

  /* trigger a 'change' event for both adjustments */
  refresh_view(zathura);

  return true;

error_out:
  return false;
1120
}
1121

1122 1123 1124 1125 1126 1127 1128 1129 1130 1131

void
refresh_view(zathura_t* zathura) {
  g_return_if_fail(zathura != NULL);

  /* emit a custom refresh-view signal */
  g_signal_emit(zathura->ui.session->gtk.view, zathura->signals.refresh_view,
                0, zathura);
}

1132

1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
bool
adjust_view(zathura_t* zathura) {
    g_return_val_if_fail(zathura != NULL, false);

  if (zathura->ui.page_widget == NULL || zathura->document == NULL) {
    goto error_ret;
  }

  zathura_adjust_mode_t adjust_mode = zathura_document_get_adjust_mode(zathura->document);
  if (adjust_mode == ZATHURA_ADJUST_NONE) {
    /* there is nothing todo */
    goto error_ret;
  }

  unsigned int cell_height = 0, cell_width = 0;
  unsigned int document_height = 0, document_width = 0;
  unsigned int view_height = 0, view_width = 0;

  zathura_document_get_cell_size(zathura->document, &cell_height, &cell_width);
  zathura_document_get_document_size(zathura->document, &document_height, &document_width);
  zathura_document_get_viewport_size(zathura->document, &view_height, &view_width);

  if (view_height == 0 || view_width == 0 || cell_height == 0 || cell_width == 0) {
    goto error_ret;
  }