zathura.c 17.5 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

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

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

17
#include "bookmarks.h"
Moritz Lipp's avatar
Moritz Lipp committed
18
19
#include "callbacks.h"
#include "config.h"
20
#include "database.h"
21
#include "document.h"
Moritz Lipp's avatar
Moritz Lipp committed
22
#include "shortcuts.h"
Moritz Lipp's avatar
Moritz Lipp committed
23
#include "zathura.h"
Moritz Lipp's avatar
Moritz Lipp committed
24
#include "utils.h"
Sebastian Ramacher's avatar
Sebastian Ramacher committed
25
#include "render.h"
Moritz Lipp's avatar
Moritz Lipp committed
26

Moritz Lipp's avatar
Update    
Moritz Lipp committed
27
28
29
30
31
32
33
typedef struct zathura_document_info_s
{
  zathura_t* zathura;
  const char* path;
  const char* password;
} zathura_document_info_t;

34
static gboolean document_info_open(gpointer data);
Moritz Lipp's avatar
Moritz Lipp committed
35

Moritz Lipp's avatar
Moritz Lipp committed
36
/* function implementation */
Moritz Lipp's avatar
Moritz Lipp committed
37
38
zathura_t*
zathura_init(int argc, char* argv[])
39
{
Sebastian Ramacher's avatar
Sebastian Ramacher committed
40
41
42
  /* parse command line options */
  GdkNativeWindow embed = 0;
  gchar* config_dir = NULL, *data_dir = NULL, *plugin_path = NULL;
43
  bool forkback = false;
44
  GOptionEntry entries[] =
Sebastian Ramacher's avatar
Sebastian Ramacher committed
45
46
47
48
49
  {
    { "reparent",    'e', 0, G_OPTION_ARG_INT,      &embed,       "Reparents to window specified by xid",       "xid"  },
    { "config-dir",  'c', 0, G_OPTION_ARG_FILENAME, &config_dir,  "Path to the config directory",               "path" },
    { "data-dir",    'd', 0, G_OPTION_ARG_FILENAME, &data_dir,    "Path to the data directory",                 "path" },
    { "plugins-dir", 'p', 0, G_OPTION_ARG_STRING,   &plugin_path, "Path to the directories containing plugins", "path" },
50
    { "fork",        '\0', 0, G_OPTION_ARG_NONE,    &forkback,    "Fork into the background"                  , NULL },
51
    { NULL, '\0', 0, 0, NULL, NULL, NULL }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
52
53
54
55
56
57
58
59
60
61
62
  };

  GOptionContext* context = g_option_context_new(" [file] [password]");
  g_option_context_add_main_entries(context, entries, NULL);

  GError* error = NULL;
  if (!g_option_context_parse(context, &argc, &argv, &error))
  {
    printf("Error parsing command line arguments: %s\n", error->message);
    g_option_context_free(context);
    g_error_free(error);
63
    return NULL;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
64
65
66
  }
  g_option_context_free(context);

67
68
69
70
71
72
73
74
75
76
77
78
79
  /* Fork into the background if the user really wants to ... */
  if (forkback == true)
  {
    int pid = fork();
    if (pid > 0) { /* parent */
      exit(0);
    } else if (pid < 0) { /* error */
      printf("Error: couldn't fork.");
    }

    setsid();
  }

80
  zathura_t* zathura = g_malloc0(sizeof(zathura_t));
81
82

  /* plugins */
83
  zathura->plugins.plugins = girara_list_new2(
Sebastian Ramacher's avatar
Sebastian Ramacher committed
84
      (girara_free_function_t)zathura_document_plugin_free);
85
86
  zathura->plugins.path    = girara_list_new2(g_free);
  zathura->plugins.type_plugin_mapping = girara_list_new2(
Sebastian Ramacher's avatar
Sebastian Ramacher committed
87
      (girara_free_function_t)zathura_type_plugin_mapping_free);
88

Sebastian Ramacher's avatar
Sebastian Ramacher committed
89
90
91
92
93
94
95
96
97
98
99
100
  if (config_dir) {
    zathura->config.config_dir = g_strdup(config_dir);
  } else {
    gchar* path = girara_get_xdg_path(XDG_CONFIG);
    zathura->config.config_dir = g_build_filename(path, "zathura", NULL);
    g_free(path);
  }

  if (data_dir) {
    zathura->config.data_dir = g_strdup(config_dir);
  } else {
    gchar* path = girara_get_xdg_path(XDG_DATA);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
101
    zathura->config.data_dir = g_build_filename(path, "zathura", NULL);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
102
103
104
    g_free(path);
  }

105
106
107
108
  /* create zathura (config/data) directory */
  g_mkdir_with_parents(zathura->config.config_dir, 0771);
  g_mkdir_with_parents(zathura->config.data_dir,   0771);

Sebastian Ramacher's avatar
Sebastian Ramacher committed
109
  if (plugin_path) {
110
111
112
    girara_list_t* paths = girara_split_path_array(plugin_path);
    girara_list_merge(zathura->plugins.path, paths);
    girara_list_free(paths);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
113
  } else {
114
#ifdef ZATHURA_PLUGINDIR
115
116
117
    girara_list_t* paths = girara_split_path_array(ZATHURA_PLUGINDIR);
    girara_list_merge(zathura->plugins.path, paths);
    girara_list_free(paths);
118
#endif
Sebastian Ramacher's avatar
Sebastian Ramacher committed
119
120
  }

121
  /* UI */
Moritz Lipp's avatar
Moritz Lipp committed
122
  if ((zathura->ui.session = girara_session_create()) == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
123
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
124
  }
125

Moritz Lipp's avatar
Moritz Lipp committed
126
  zathura->ui.session->global.data  = zathura;
Moritz Lipp's avatar
Moritz Lipp committed
127
128
129
  zathura->ui.statusbar.file        = NULL;
  zathura->ui.statusbar.buffer      = NULL;
  zathura->ui.statusbar.page_number = NULL;
130
  zathura->ui.page_widget             = NULL;
Moritz Lipp's avatar
Moritz Lipp committed
131
  zathura->ui.index                 = NULL;
132

Moritz Lipp's avatar
Moritz Lipp committed
133
  /* print settings */
134
135
136
  zathura->print.settings   = NULL;
  zathura->print.page_setup = NULL;

Moritz Lipp's avatar
Moritz Lipp committed
137
138
139
  /* global settings */
  zathura->global.recolor = false;

140
141
142
  /* load plugins */
  zathura_document_plugins_load(zathura);

143
144
145
  /* configuration */
  config_load_default(zathura);

146
147
148
149
150
151
152
153
154
155
156
157
158
  /* load global configuration files */
  girara_list_t* config_dirs = girara_split_path_array(girara_get_xdg_path(XDG_CONFIG_DIRS));
  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);

  config_load_file(zathura, GLOBAL_RC);

159
160
161
  /* load local configuration files */
  char* configuration_file = g_build_filename(zathura->config.config_dir, ZATHURA_RC, NULL);
  config_load_file(zathura, configuration_file);
162
  g_free(configuration_file);
163
164
165

  /* initialize girara */
  zathura->ui.session->gtk.embed = embed;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
166
  if (girara_session_init(zathura->ui.session, "zathura") == false) {
167
168
169
170
    goto error_out;
  }

  /* girara events */
Moritz Lipp's avatar
Moritz Lipp committed
171
  zathura->ui.session->events.buffer_changed = cb_buffer_changed;
172

173
  /* page view */
174
175
  zathura->ui.page_widget = gtk_table_new(0, 0, TRUE);
  if (!zathura->ui.page_widget) {
176
177
178
    goto error_free;
  }

179
180
  g_signal_connect(G_OBJECT(zathura->ui.session->gtk.view), "size-allocate", G_CALLBACK(cb_view_resized), zathura);

Moritz Lipp's avatar
Moritz Lipp committed
181
182
183
184
185
186
  /* 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);

187
  /* page view alignment */
188
189
  zathura->ui.page_widget_alignment = gtk_alignment_new(0.5, 0.5, 0, 0);
  if (!zathura->ui.page_widget_alignment) {
190
191
    goto error_free;
  }
192
  gtk_container_add(GTK_CONTAINER(zathura->ui.page_widget_alignment), zathura->ui.page_widget);
193

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

196
  /* statusbar */
Moritz Lipp's avatar
Moritz Lipp committed
197
198
  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
199
    goto error_free;
Moritz Lipp's avatar
Moritz Lipp committed
200
201
  }

Moritz Lipp's avatar
Moritz Lipp committed
202
203
  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
204
    goto error_free;
Moritz Lipp's avatar
Moritz Lipp committed
205
206
  }

Moritz Lipp's avatar
Moritz Lipp committed
207
208
  zathura->ui.statusbar.page_number = girara_statusbar_item_add(zathura->ui.session, FALSE, FALSE, FALSE, NULL);
  if (!zathura->ui.statusbar.page_number) {
Moritz Lipp's avatar
Moritz Lipp committed
209
    goto error_free;
Moritz Lipp's avatar
Moritz Lipp committed
210
211
  }

Moritz Lipp's avatar
Moritz Lipp committed
212
  girara_statusbar_item_set_text(zathura->ui.session, zathura->ui.statusbar.file, "[No Name]");
Moritz Lipp's avatar
Moritz Lipp committed
213

Moritz Lipp's avatar
Moritz Lipp committed
214
  /* signals */
Moritz Lipp's avatar
Moritz Lipp committed
215
  g_signal_connect(G_OBJECT(zathura->ui.session->gtk.window), "destroy", G_CALLBACK(cb_destroy), NULL);
216

Moritz Lipp's avatar
Moritz Lipp committed
217
  /* save page padding */
218
219
  zathura->global.page_padding = 1;
  girara_setting_get(zathura->ui.session, "page-padding", &zathura->global.page_padding);
Moritz Lipp's avatar
Moritz Lipp committed
220

221
222
  gtk_table_set_row_spacings(GTK_TABLE(zathura->ui.page_widget), zathura->global.page_padding);
  gtk_table_set_col_spacings(GTK_TABLE(zathura->ui.page_widget), zathura->global.page_padding);
Moritz Lipp's avatar
Moritz Lipp committed
223

Moritz Lipp's avatar
Moritz Lipp committed
224
  /* parse colors */
225
226
  char* string_value = NULL;
  girara_setting_get(zathura->ui.session, "recolor-darkcolor", &string_value);
Moritz Lipp's avatar
Moritz Lipp committed
227
228
  if (string_value != NULL) {
    gdk_color_parse(string_value, &(zathura->ui.colors.recolor_dark_color));
229
    g_free(string_value);
Moritz Lipp's avatar
Moritz Lipp committed
230
231
  }

232
233
  string_value = NULL;
  girara_setting_get(zathura->ui.session, "recolor-lightcolor", &string_value);
Moritz Lipp's avatar
Moritz Lipp committed
234
235
  if (string_value != NULL) {
    gdk_color_parse(string_value, &(zathura->ui.colors.recolor_light_color));
236
    g_free(string_value);
Moritz Lipp's avatar
Moritz Lipp committed
237
238
  }

239
240
  string_value = NULL;
  girara_setting_get(zathura->ui.session, "highlight-color", &string_value);
Moritz Lipp's avatar
Moritz Lipp committed
241
242
243
244
245
  if (string_value != NULL) {
    gdk_color_parse(string_value, &(zathura->ui.colors.highlight_color));
    g_free(string_value);
  }

246
  /* database */
247
  zathura->database = zathura_db_init(zathura->config.data_dir);
248
  if (zathura->database == NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
249
    girara_error("Unable to initialize database. Bookmarks won't be available.");
250
251
  }

252
  /* bookmarks */
253
  zathura->bookmarks.bookmarks = girara_sorted_list_new2((girara_compare_function_t) zathura_bookmarks_compare,
254
    (girara_free_function_t) zathura_bookmark_free);
255

Moritz Lipp's avatar
Moritz Lipp committed
256
  /* open document if passed */
Moritz Lipp's avatar
Update    
Moritz Lipp committed
257
  if (argc > 1) {
258
    zathura_document_info_t* document_info = g_malloc0(sizeof(zathura_document_info_t));
Moritz Lipp's avatar
Update    
Moritz Lipp committed
259

260
261
262
263
    document_info->zathura  = zathura;
    document_info->path     = argv[1];
    document_info->password = (argc >= 2) ? argv[2] : NULL;
    g_idle_add(document_info_open, document_info);
Moritz Lipp's avatar
Update    
Moritz Lipp committed
264
265
  }

Moritz Lipp's avatar
Moritz Lipp committed
266
  return zathura;
Moritz Lipp's avatar
Moritz Lipp committed
267
268
269

error_free:

270
271
  if (zathura->ui.page_widget) {
    g_object_unref(zathura->ui.page_widget);
272
273
  }

274
275
  if (zathura->ui.page_widget_alignment) {
    g_object_unref(zathura->ui.page_widget_alignment);
276
  }
Moritz Lipp's avatar
Moritz Lipp committed
277
278
279

error_out:

280
  zathura_free(zathura);
Moritz Lipp's avatar
Moritz Lipp committed
281

Moritz Lipp's avatar
Moritz Lipp committed
282
283
284
285
286
287
288
289
290
291
  return NULL;
}

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

292
293
  document_close(zathura);

Moritz Lipp's avatar
Moritz Lipp committed
294
295
296
297
  if (zathura->ui.session != NULL) {
    girara_session_destroy(zathura->ui.session);
  }

298
299
300
301
302
303
  /* stdin support */
  if (zathura->stdin_support.file != NULL) {
    g_unlink(zathura->stdin_support.file);
    g_free(zathura->stdin_support.file);
  }

304
305
306
  /* bookmarks */
  girara_list_free(zathura->bookmarks.bookmarks);

307
308
309
  /* database */
  zathura_db_free(zathura->database);

310
  /* free print settings */
311
312
313
314
315
316
317
  if(zathura->print.settings != NULL) {
    g_object_unref(zathura->print.settings);
  }

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

Moritz Lipp's avatar
Moritz Lipp committed
319
  /* free registered plugins */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
320
  girara_list_free(zathura->plugins.plugins);
321
322
323
324
325
  girara_list_free(zathura->plugins.path);

  /* free config variables */
  g_free(zathura->config.config_dir);
  g_free(zathura->config.data_dir);
Moritz Lipp's avatar
Moritz Lipp committed
326

327
  g_free(zathura);
328
329
}

330
331
332
333
334
335
336
337
338
339
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);
  if (handle == -1)
  {
340
341
342
343
    if (error != NULL) {
      girara_error("Can not create temporary file: %s", error->message);
      g_error_free(error);
    }
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
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
    return NULL;
  }

  // read from stdin and dump to temporary file
  int stdinfno = fileno(stdin);
  if (stdinfno == -1)
  {
    girara_error("Can not read from stdin.");
    close(handle);
    g_unlink(file);
    g_free(file);
    return NULL;
  }

  char buffer[BUFSIZ];
  ssize_t count = 0;
  while ((count = read(stdinfno, buffer, BUFSIZ)) > 0)
  {
    if (write(handle, buffer, count) != count)
    {
      girara_error("Can not write to temporary file: %s", file);
      close(handle);
      g_unlink(file);
      g_free(file);
      return NULL;
    }
  }
  close(handle);

  if (count != 0)
  {
    girara_error("Can not read from stdin.");
    g_unlink(file);
    g_free(file);
    return NULL;
  }

  return file;
}

384
static gboolean
Moritz Lipp's avatar
Update    
Moritz Lipp committed
385
386
387
388
389
document_info_open(gpointer data)
{
  zathura_document_info_t* document_info = data;
  g_return_val_if_fail(document_info != NULL, FALSE);

390
  if (document_info->zathura != NULL && document_info->path != NULL) {
391
392
393
394
395
396
    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,
            "Could not read file from stdin and write it to a temporary file.");
397
398
      } else {
        document_info->zathura->stdin_support.file = g_strdup(file);
399
400
401
402
403
404
405
406
407
      }
    } 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
Update    
Moritz Lipp committed
408
409
  }

410
  g_free(document_info);
Moritz Lipp's avatar
Update    
Moritz Lipp committed
411
  return FALSE;
412
413
}

Moritz Lipp's avatar
Moritz Lipp committed
414
bool
Moritz Lipp's avatar
Moritz Lipp committed
415
document_open(zathura_t* zathura, const char* path, const char* password)
Moritz Lipp's avatar
Moritz Lipp committed
416
{
Moritz Lipp's avatar
Moritz Lipp committed
417
  if (!path) {
418
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
419
420
  }

Sebastian Ramacher's avatar
Sebastian Ramacher committed
421
  zathura_document_t* document = zathura_document_open(zathura, path, password);
Moritz Lipp's avatar
Moritz Lipp committed
422

Moritz Lipp's avatar
Moritz Lipp committed
423
  if (!document) {
424
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
425
426
  }

Moritz Lipp's avatar
Moritz Lipp committed
427
  zathura->document = document;
Moritz Lipp's avatar
Moritz Lipp committed
428

429
  /* view mode */
430
431
  int pages_per_row = 1;
  girara_setting_get(zathura->ui.session, "pages-per-row", &pages_per_row);
432
  page_widget_set_mode(zathura, pages_per_row);
Moritz Lipp's avatar
Moritz Lipp committed
433

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

Moritz Lipp's avatar
Moritz Lipp committed
436
  /* threads */
Moritz Lipp's avatar
Moritz Lipp committed
437
  zathura->sync.render_thread = render_init(zathura);
Moritz Lipp's avatar
Moritz Lipp committed
438

Moritz Lipp's avatar
Moritz Lipp committed
439
  if (!zathura->sync.render_thread) {
Moritz Lipp's avatar
Moritz Lipp committed
440
441
442
    goto error_free;
  }

Moritz Lipp's avatar
Moritz Lipp committed
443
  /* create blank pages */
444
  for (unsigned int page_id = 0; page_id < document->number_of_pages; page_id++) {
Moritz Lipp's avatar
Moritz Lipp committed
445
    zathura_page_t* page = document->pages[page_id];
446
    gtk_widget_realize(page->drawing_area);
447
  }
Moritz Lipp's avatar
Moritz Lipp committed
448

449
450
451
452
453
  /* bookmarks */
  if (!zathura_bookmarks_load(zathura, zathura->document->file_path)) {
    girara_warning("Failed to load bookmarks for %s.\n", zathura->document->file_path);
  }

Pavel Borzenkov's avatar
Pavel Borzenkov committed
454
  page_set_delayed(zathura, document->current_page_number - 1);
455
  cb_view_vadjustment_value_changed(NULL, zathura);
456

Moritz Lipp's avatar
Moritz Lipp committed
457
  return true;
458
459
460
461
462
463
464
465

error_free:

  zathura_document_free(document);

error_out:

  return false;
Moritz Lipp's avatar
Moritz Lipp committed
466
467
}

468
469
470
471
472
473
474
475
476
477
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);
  if (!overwrite && g_file_test(file_path, G_FILE_TEST_EXISTS))
  {
478
    girara_error("File already exists: %s. Use :write! to overwrite it.", file_path);
479
    g_free(file_path);
480
481
482
483
484
485
486
487
    return false;
  }

  bool res = zathura_document_save_as(zathura->document, file_path);
  g_free(file_path);
  return res;
}

Pavel Borzenkov's avatar
Pavel Borzenkov committed
488
489
490
491
492
493
494
static void
remove_page_from_table(GtkWidget* page, gpointer permanent)
{
  if (!permanent) {
    g_object_ref(G_OBJECT(page));
  }

495
  gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(page)), page);
Pavel Borzenkov's avatar
Pavel Borzenkov committed
496
497
}

Moritz Lipp's avatar
Moritz Lipp committed
498
bool
Moritz Lipp's avatar
Moritz Lipp committed
499
document_close(zathura_t* zathura)
Moritz Lipp's avatar
Moritz Lipp committed
500
{
Moritz Lipp's avatar
Moritz Lipp committed
501
  if (!zathura->document) {
Moritz Lipp's avatar
Moritz Lipp committed
502
503
504
    return false;
  }

Sebastian Ramacher's avatar
Sebastian Ramacher committed
505
  /* store last seen page */
506
  zathura_db_set_fileinfo(zathura->database, zathura->document->file_path, zathura->document->current_page_number,
Sebastian Ramacher's avatar
Sebastian Ramacher committed
507
508
      /* zathura->document->offset TODO */ 0, zathura->document->scale,
      zathura->document->rotate);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
509

Pavel Borzenkov's avatar
Pavel Borzenkov committed
510
511
512
  render_free(zathura->sync.render_thread);
  zathura->sync.render_thread = NULL;

513
  gtk_container_foreach(GTK_CONTAINER(zathura->ui.page_widget), remove_page_from_table, (gpointer)1);
Moritz Lipp's avatar
Moritz Lipp committed
514

Moritz Lipp's avatar
Moritz Lipp committed
515
  zathura_document_free(zathura->document);
Pavel Borzenkov's avatar
Pavel Borzenkov committed
516
517
  zathura->document = NULL;

518
  gtk_widget_hide(zathura->ui.page_widget);
519
520
521
522
523
524

  statusbar_page_number_update(zathura);

  if (zathura->ui.session != NULL && zathura->ui.statusbar.file != NULL) {
    girara_statusbar_item_set_text(zathura->ui.session, zathura->ui.statusbar.file, "[No name]");
  }
Moritz Lipp's avatar
Moritz Lipp committed
525
526
527
528

  return true;
}

Sebastian Ramacher's avatar
Sebastian Ramacher committed
529
530
typedef struct page_set_delayed_s
{
531
532
533
534
535
  zathura_t* zathura;
  unsigned int page;
} page_set_delayed_t;

static gboolean
Sebastian Ramacher's avatar
Sebastian Ramacher committed
536
537
page_set_delayed_impl(gpointer data)
{
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
  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)
{
  if (zathura == NULL || zathura->document == NULL || zathura->document->pages == NULL ||
      page_id >= zathura->document->number_of_pages) {
    return false;
  }

  page_set_delayed_t* p = g_malloc(sizeof(page_set_delayed_t));
  p->zathura = zathura;
  p->page = page_id;
  g_idle_add(page_set_delayed_impl, p);
  return true;
}

Moritz Lipp's avatar
Moritz Lipp committed
560
bool
Moritz Lipp's avatar
Moritz Lipp committed
561
page_set(zathura_t* zathura, unsigned int page_id)
Moritz Lipp's avatar
Moritz Lipp committed
562
{
563
  if (zathura == NULL || zathura->document == NULL || zathura->document->pages == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
564
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
565
566
  }

Moritz Lipp's avatar
Moritz Lipp committed
567
  if (page_id >= zathura->document->number_of_pages) {
Moritz Lipp's avatar
Moritz Lipp committed
568
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
569
570
  }

571
  /* render page */
Moritz Lipp's avatar
Moritz Lipp committed
572
  zathura_page_t* page = zathura->document->pages[page_id];
Moritz Lipp's avatar
Moritz Lipp committed
573

Moritz Lipp's avatar
Moritz Lipp committed
574
  if (!page) {
575
576
577
    goto error_out;
  }

578
579
  page_offset_t offset;
  page_calculate_offset(page, &offset);
Moritz Lipp's avatar
Moritz Lipp committed
580

Moritz Lipp's avatar
Moritz Lipp committed
581
  GtkAdjustment* view_vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
Moritz Lipp's avatar
Moritz Lipp committed
582
  GtkAdjustment* view_hadjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
583
584
  set_adjustment(view_hadjustment, offset.x);
  set_adjustment(view_vadjustment, offset.y);
585

Moritz Lipp's avatar
Moritz Lipp committed
586
  return true;
Moritz Lipp's avatar
Moritz Lipp committed
587
588
589
590

error_out:

  return false;
Moritz Lipp's avatar
Moritz Lipp committed
591
592
}

593
594
595
596
597
598
599
void
statusbar_page_number_update(zathura_t* zathura)
{
  if (zathura == NULL || zathura->ui.statusbar.page_number == NULL) {
    return;
  }

600
601
602
603
604
605
606
  if (zathura->document != NULL) {
    char* page_number_text = g_strdup_printf("[%d/%d]", zathura->document->current_page_number + 1, zathura->document->number_of_pages);
    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, "");
  }
607
608
}

609
void
610
page_widget_set_mode(zathura_t* zathura, unsigned int pages_per_row)
611
{
Moritz Lipp's avatar
Moritz Lipp committed
612
613
614
615
616
  /* show at least one page */
  if (pages_per_row == 0) {
    pages_per_row = 1;
  }

617
618
619
620
  if (zathura->document == NULL) {
    return;
  }

621
  gtk_container_foreach(GTK_CONTAINER(zathura->ui.page_widget), remove_page_from_table, (gpointer)0);
622

623
  gtk_table_resize(GTK_TABLE(zathura->ui.page_widget), ceil(zathura->document->number_of_pages / pages_per_row), pages_per_row);
Moritz Lipp's avatar
Moritz Lipp committed
624
  for (unsigned int i = 0; i < zathura->document->number_of_pages; i++)
625
  {
626
627
    int x = i % pages_per_row;
    int y = i / pages_per_row;
628
    gtk_table_attach(GTK_TABLE(zathura->ui.page_widget), zathura->document->pages[i]->drawing_area, x, x + 1, y, y + 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
629
630
  }

631
  gtk_widget_show_all(zathura->ui.page_widget);
632
}