zathura.c 17.1 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>
Moritz Lipp's avatar
Moritz Lipp committed
8

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

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

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

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

Moritz Lipp's avatar
Moritz Lipp committed
35
/* function implementation */
Moritz Lipp's avatar
Moritz Lipp committed
36
37
zathura_t*
zathura_init(int argc, char* argv[])
38
{
Sebastian Ramacher's avatar
Sebastian Ramacher committed
39
40
41
  /* parse command line options */
  GdkNativeWindow embed = 0;
  gchar* config_dir = NULL, *data_dir = NULL, *plugin_path = NULL;
42
  GOptionEntry entries[] =
Sebastian Ramacher's avatar
Sebastian Ramacher committed
43
44
45
46
47
  {
    { "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" },
48
    { NULL, '\0', 0, 0, NULL, NULL, NULL }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
49
50
51
52
53
54
55
56
57
58
59
  };

  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);
60
    return NULL;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
61
62
63
  }
  g_option_context_free(context);

64
  zathura_t* zathura = g_malloc0(sizeof(zathura_t));
65
66

  /* plugins */
67
  zathura->plugins.plugins = girara_list_new2(
Sebastian Ramacher's avatar
Sebastian Ramacher committed
68
      (girara_free_function_t)zathura_document_plugin_free);
69
70
  zathura->plugins.path    = girara_list_new2(g_free);
  zathura->plugins.type_plugin_mapping = girara_list_new2(
Sebastian Ramacher's avatar
Sebastian Ramacher committed
71
      (girara_free_function_t)zathura_type_plugin_mapping_free);
72

Sebastian Ramacher's avatar
Sebastian Ramacher committed
73
74
75
76
77
78
79
80
81
82
83
84
  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
85
    zathura->config.data_dir = g_build_filename(path, "zathura", NULL);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
86
87
88
    g_free(path);
  }

89
90
91
92
  /* 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
93
  if (plugin_path) {
94
95
96
    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
97
  } else {
98
#ifdef ZATHURA_PLUGINDIR
99
100
101
    girara_list_t* paths = girara_split_path_array(ZATHURA_PLUGINDIR);
    girara_list_merge(zathura->plugins.path, paths);
    girara_list_free(paths);
102
#endif
Sebastian Ramacher's avatar
Sebastian Ramacher committed
103
104
  }

105
  /* UI */
Moritz Lipp's avatar
Moritz Lipp committed
106
  if ((zathura->ui.session = girara_session_create()) == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
107
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
108
  }
109

Moritz Lipp's avatar
Moritz Lipp committed
110
  zathura->ui.session->global.data  = zathura;
Moritz Lipp's avatar
Moritz Lipp committed
111
112
113
114
115
  zathura->ui.statusbar.file        = NULL;
  zathura->ui.statusbar.buffer      = NULL;
  zathura->ui.statusbar.page_number = NULL;
  zathura->ui.page_view             = NULL;
  zathura->ui.index                 = NULL;
116

Moritz Lipp's avatar
Moritz Lipp committed
117
  /* print settings */
118
119
120
  zathura->print.settings   = NULL;
  zathura->print.page_setup = NULL;

Moritz Lipp's avatar
Moritz Lipp committed
121
122
123
  /* global settings */
  zathura->global.recolor = false;

124
125
126
  /* load plugins */
  zathura_document_plugins_load(zathura);

127
128
129
  /* configuration */
  config_load_default(zathura);

130
131
132
133
134
135
136
137
138
139
140
141
142
  /* 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);

143
144
145
  /* load local configuration files */
  char* configuration_file = g_build_filename(zathura->config.config_dir, ZATHURA_RC, NULL);
  config_load_file(zathura, configuration_file);
146
  g_free(configuration_file);
147
148
149

  /* initialize girara */
  zathura->ui.session->gtk.embed = embed;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
150
  if (girara_session_init(zathura->ui.session, "zathura") == false) {
151
152
153
154
155
156
    goto error_out;
  }

  /* girara events */
  zathura->ui.session->events.buffer_changed = buffer_changed;

157
  /* page view */
158
  zathura->ui.page_view = gtk_table_new(0, 0, TRUE);
Moritz Lipp's avatar
Moritz Lipp committed
159
  if (!zathura->ui.page_view) {
160
161
162
    goto error_free;
  }

Moritz Lipp's avatar
Moritz Lipp committed
163
164
165
166
167
168
  /* 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);

169
170
171
172
173
174
175
  /* page view alignment */
  zathura->ui.page_view_alignment = gtk_alignment_new(0.5, 0.5, 0, 0);
  if (!zathura->ui.page_view_alignment) {
    goto error_free;
  }
  gtk_container_add(GTK_CONTAINER(zathura->ui.page_view_alignment), zathura->ui.page_view);

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

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

Moritz Lipp's avatar
Moritz Lipp committed
184
185
  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
186
    goto error_free;
Moritz Lipp's avatar
Moritz Lipp committed
187
188
  }

Moritz Lipp's avatar
Moritz Lipp committed
189
190
  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
191
    goto error_free;
Moritz Lipp's avatar
Moritz Lipp committed
192
193
  }

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

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

Moritz Lipp's avatar
Moritz Lipp committed
199
  /* save page padding */
Moritz Lipp's avatar
Moritz Lipp committed
200
  int* page_padding = girara_setting_get(zathura->ui.session, "page-padding");
Moritz Lipp's avatar
Moritz Lipp committed
201
  zathura->global.page_padding = (page_padding) ? *page_padding : 1;
202
  g_free(page_padding);
Moritz Lipp's avatar
Moritz Lipp committed
203

Moritz Lipp's avatar
Moritz Lipp committed
204
205
206
  gtk_table_set_row_spacings(GTK_TABLE(zathura->ui.page_view), zathura->global.page_padding);
  gtk_table_set_col_spacings(GTK_TABLE(zathura->ui.page_view), zathura->global.page_padding);

Moritz Lipp's avatar
Moritz Lipp committed
207
  /* parse colors */
Moritz Lipp's avatar
Moritz Lipp committed
208
  char* string_value = girara_setting_get(zathura->ui.session, "recolor-darkcolor");
Moritz Lipp's avatar
Moritz Lipp committed
209
210
  if (string_value != NULL) {
    gdk_color_parse(string_value, &(zathura->ui.colors.recolor_dark_color));
211
    g_free(string_value);
Moritz Lipp's avatar
Moritz Lipp committed
212
213
  }

Moritz Lipp's avatar
Moritz Lipp committed
214
  string_value = girara_setting_get(zathura->ui.session, "recolor-lightcolor");
Moritz Lipp's avatar
Moritz Lipp committed
215
216
  if (string_value != NULL) {
    gdk_color_parse(string_value, &(zathura->ui.colors.recolor_light_color));
217
    g_free(string_value);
Moritz Lipp's avatar
Moritz Lipp committed
218
219
  }

220
  /* database */
221
  zathura->database = zathura_db_init(zathura->config.data_dir);
222
  if (zathura->database == NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
223
    girara_error("Unable to initialize database. Bookmarks won't be available.");
224
225
  }

226
  /* bookmarks */
227
  zathura->bookmarks.bookmarks = girara_sorted_list_new2((girara_compare_function_t) zathura_bookmarks_compare,
228
    (girara_free_function_t) zathura_bookmark_free);
229

Moritz Lipp's avatar
Moritz Lipp committed
230
  /* open document if passed */
Moritz Lipp's avatar
Update    
Moritz Lipp committed
231
  if (argc > 1) {
232
    zathura_document_info_t* document_info = g_malloc0(sizeof(zathura_document_info_t));
Moritz Lipp's avatar
Update    
Moritz Lipp committed
233

234
235
236
237
    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
238
239
  }

Moritz Lipp's avatar
Moritz Lipp committed
240
  return zathura;
Moritz Lipp's avatar
Moritz Lipp committed
241
242
243

error_free:

Moritz Lipp's avatar
Moritz Lipp committed
244
245
  if (zathura->ui.page_view) {
    g_object_unref(zathura->ui.page_view);
246
247
  }

248
249
250
  if (zathura->ui.page_view_alignment) {
    g_object_unref(zathura->ui.page_view_alignment);
  }
Moritz Lipp's avatar
Moritz Lipp committed
251
252
253

error_out:

254
  zathura_free(zathura);
Moritz Lipp's avatar
Moritz Lipp committed
255

Moritz Lipp's avatar
Moritz Lipp committed
256
257
258
259
260
261
262
263
264
265
  return NULL;
}

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

266
267
  document_close(zathura);

Moritz Lipp's avatar
Moritz Lipp committed
268
269
270
271
  if (zathura->ui.session != NULL) {
    girara_session_destroy(zathura->ui.session);
  }

272
273
274
275
276
277
  /* stdin support */
  if (zathura->stdin_support.file != NULL) {
    g_unlink(zathura->stdin_support.file);
    g_free(zathura->stdin_support.file);
  }

278
279
280
  /* bookmarks */
  girara_list_free(zathura->bookmarks.bookmarks);

281
282
283
  /* database */
  zathura_db_free(zathura->database);

284
  /* free print settings */
285
286
287
288
289
290
291
  if(zathura->print.settings != NULL) {
    g_object_unref(zathura->print.settings);
  }

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

Moritz Lipp's avatar
Moritz Lipp committed
293
  /* free registered plugins */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
294
  girara_list_free(zathura->plugins.plugins);
295
296
297
298
299
  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
300

301
  g_free(zathura);
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
347
348
349
350
351
352
353
354
355
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)
  {
    girara_error("Can not create temporary file: %s", error->message);
    g_error_free(error);
    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;
}

356
static gboolean
Moritz Lipp's avatar
Update    
Moritz Lipp committed
357
358
359
360
361
document_info_open(gpointer data)
{
  zathura_document_info_t* document_info = data;
  g_return_val_if_fail(document_info != NULL, FALSE);

362
  if (document_info->zathura != NULL && document_info->path != NULL) {
363
364
365
366
367
368
    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.");
369
370
      } else {
        document_info->zathura->stdin_support.file = g_strdup(file);
371
372
373
374
375
376
377
378
379
      }
    } 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
380
381
  }

382
  g_free(document_info);
Moritz Lipp's avatar
Update    
Moritz Lipp committed
383
  return FALSE;
384
385
}

Moritz Lipp's avatar
Moritz Lipp committed
386
bool
Moritz Lipp's avatar
Moritz Lipp committed
387
document_open(zathura_t* zathura, const char* path, const char* password)
Moritz Lipp's avatar
Moritz Lipp committed
388
{
Moritz Lipp's avatar
Moritz Lipp committed
389
  if (!path) {
390
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
391
392
  }

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

Moritz Lipp's avatar
Moritz Lipp committed
395
  if (!document) {
396
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
397
398
  }

Moritz Lipp's avatar
Moritz Lipp committed
399
  zathura->document = document;
Moritz Lipp's avatar
Moritz Lipp committed
400

401
  /* view mode */
Moritz Lipp's avatar
Moritz Lipp committed
402
  int* value = girara_setting_get(zathura->ui.session, "pages-per-row");
403
  int pages_per_row = (value) ? *value : 1;
404
  g_free(value);
Moritz Lipp's avatar
Moritz Lipp committed
405
  page_view_set_mode(zathura, pages_per_row);
Moritz Lipp's avatar
Moritz Lipp committed
406

407
  girara_set_view(zathura->ui.session, zathura->ui.page_view_alignment);
Moritz Lipp's avatar
Moritz Lipp committed
408

Moritz Lipp's avatar
Moritz Lipp committed
409
  /* threads */
Moritz Lipp's avatar
Moritz Lipp committed
410
  zathura->sync.render_thread = render_init(zathura);
Moritz Lipp's avatar
Moritz Lipp committed
411

Moritz Lipp's avatar
Moritz Lipp committed
412
  if (!zathura->sync.render_thread) {
Moritz Lipp's avatar
Moritz Lipp committed
413
414
415
    goto error_free;
  }

Moritz Lipp's avatar
Moritz Lipp committed
416
  /* create blank pages */
417
  for (unsigned int page_id = 0; page_id < document->number_of_pages; page_id++) {
Moritz Lipp's avatar
Moritz Lipp committed
418
419
    zathura_page_t* page = document->pages[page_id];
    gtk_widget_realize(page->event_box);
420
  }
Moritz Lipp's avatar
Moritz Lipp committed
421

422
423
424
425
426
  /* 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
427
  page_set_delayed(zathura, document->current_page_number - 1);
428

Moritz Lipp's avatar
Moritz Lipp committed
429
  return true;
430
431
432
433
434
435
436
437

error_free:

  zathura_document_free(document);

error_out:

  return false;
Moritz Lipp's avatar
Moritz Lipp committed
438
439
}

440
441
442
443
444
445
446
447
448
449
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))
  {
450
    girara_error("File already exists: %s. Use :write! to overwrite it.", file_path);
451
    g_free(file_path);
452
453
454
455
456
457
458
459
    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
460
461
462
463
464
465
466
467
468
469
static void
remove_page_from_table(GtkWidget* page, gpointer permanent)
{
  if (!permanent) {
    g_object_ref(G_OBJECT(page));
  }

  gtk_container_remove(GTK_CONTAINER(page->parent), page);
}

Moritz Lipp's avatar
Moritz Lipp committed
470
bool
Moritz Lipp's avatar
Moritz Lipp committed
471
document_close(zathura_t* zathura)
Moritz Lipp's avatar
Moritz Lipp committed
472
{
Moritz Lipp's avatar
Moritz Lipp committed
473
  if (!zathura->document) {
Moritz Lipp's avatar
Moritz Lipp committed
474
475
476
    return false;
  }

Sebastian Ramacher's avatar
Sebastian Ramacher committed
477
  /* store last seen page */
478
  zathura_db_set_fileinfo(zathura->database, zathura->document->file_path, zathura->document->current_page_number + 1,
Sebastian Ramacher's avatar
Sebastian Ramacher committed
479
480
      /* zathura->document->offset TODO */ 0, zathura->document->scale);

Pavel Borzenkov's avatar
Pavel Borzenkov committed
481
482
483
484
  render_free(zathura->sync.render_thread);
  zathura->sync.render_thread = NULL;

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

Moritz Lipp's avatar
Moritz Lipp committed
486
  zathura_document_free(zathura->document);
Pavel Borzenkov's avatar
Pavel Borzenkov committed
487
488
  zathura->document = NULL;

489
490
491
492
493
494
495
  gtk_widget_hide(zathura->ui.page_view);

  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
496
497
498
499

  return true;
}

Sebastian Ramacher's avatar
Sebastian Ramacher committed
500
501
typedef struct page_set_delayed_s
{
502
503
504
505
506
  zathura_t* zathura;
  unsigned int page;
} page_set_delayed_t;

static gboolean
Sebastian Ramacher's avatar
Sebastian Ramacher committed
507
508
page_set_delayed_impl(gpointer data)
{
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
  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
531
bool
Moritz Lipp's avatar
Moritz Lipp committed
532
page_set(zathura_t* zathura, unsigned int page_id)
Moritz Lipp's avatar
Moritz Lipp committed
533
{
534
  if (zathura == NULL || zathura->document == NULL || zathura->document->pages == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
535
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
536
537
  }

Moritz Lipp's avatar
Moritz Lipp committed
538
  if (page_id >= zathura->document->number_of_pages) {
Moritz Lipp's avatar
Moritz Lipp committed
539
    goto error_out;
Moritz Lipp's avatar
Moritz Lipp committed
540
541
  }

542
  /* render page */
Moritz Lipp's avatar
Moritz Lipp committed
543
  zathura_page_t* page = zathura->document->pages[page_id];
Moritz Lipp's avatar
Moritz Lipp committed
544

Moritz Lipp's avatar
Moritz Lipp committed
545
  if (!page) {
546
547
548
    goto error_out;
  }

Moritz Lipp's avatar
Moritz Lipp committed
549
550
551
552
553
  page_offset_t* offset = page_calculate_offset(page);
  if (offset == NULL) {
    goto error_out;
  }

Moritz Lipp's avatar
Moritz Lipp committed
554
  GtkAdjustment* view_vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
Moritz Lipp's avatar
Moritz Lipp committed
555
556
557
  GtkAdjustment* view_hadjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
  gtk_adjustment_set_value(view_hadjustment, offset->x);
  gtk_adjustment_set_value(view_vadjustment, offset->y);
558
559

  /* update page number */
Moritz Lipp's avatar
Moritz Lipp committed
560
  zathura->document->current_page_number = page_id;
561
  statusbar_page_number_update(zathura);
Moritz Lipp's avatar
Moritz Lipp committed
562
563

  return true;
Moritz Lipp's avatar
Moritz Lipp committed
564
565
566
567

error_out:

  return false;
Moritz Lipp's avatar
Moritz Lipp committed
568
569
}

570
571
572
573
574
575
576
void
statusbar_page_number_update(zathura_t* zathura)
{
  if (zathura == NULL || zathura->ui.statusbar.page_number == NULL) {
    return;
  }

577
578
579
580
581
582
583
  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, "");
  }
584
585
}

586
void
Moritz Lipp's avatar
Moritz Lipp committed
587
page_view_set_mode(zathura_t* zathura, unsigned int pages_per_row)
588
{
Moritz Lipp's avatar
Moritz Lipp committed
589
590
591
592
593
  /* show at least one page */
  if (pages_per_row == 0) {
    pages_per_row = 1;
  }

594
595
596
597
  if (zathura->document == NULL) {
    return;
  }

Pavel Borzenkov's avatar
Pavel Borzenkov committed
598
  gtk_container_foreach(GTK_CONTAINER(zathura->ui.page_view), remove_page_from_table, (gpointer)0);
599

600
  gtk_table_resize(GTK_TABLE(zathura->ui.page_view), zathura->document->number_of_pages / pages_per_row + 1, pages_per_row);
Moritz Lipp's avatar
Moritz Lipp committed
601
  for (unsigned int i = 0; i < zathura->document->number_of_pages; i++)
602
  {
603
604
    int x = i % pages_per_row;
    int y = i / pages_per_row;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
605
    gtk_table_attach(GTK_TABLE(zathura->ui.page_view), zathura->document->pages[i]->event_box, x, x + 1, y, y + 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
606
607
  }

Moritz Lipp's avatar
Moritz Lipp committed
608
  gtk_widget_show_all(zathura->ui.page_view);
609
610
}

Moritz Lipp's avatar
Moritz Lipp committed
611
/* main function */
612
int main(int argc, char* argv[])
Moritz Lipp's avatar
Moritz Lipp committed
613
{
614
615
  g_thread_init(NULL);
  gdk_threads_init();
Moritz Lipp's avatar
Moritz Lipp committed
616
617
  gtk_init(&argc, &argv);

Moritz Lipp's avatar
Moritz Lipp committed
618
619
  zathura_t* zathura = zathura_init(argc, argv);
  if (zathura == NULL) {
Pavel Borzenkov's avatar
Pavel Borzenkov committed
620
    printf("error: could not initialize zathura\n");
Moritz Lipp's avatar
Moritz Lipp committed
621
622
    return -1;
  }
Moritz Lipp's avatar
Moritz Lipp committed
623

Moritz Lipp's avatar
Moritz Lipp committed
624
625
626
  gdk_threads_enter();
  gtk_main();
  gdk_threads_leave();
627

Moritz Lipp's avatar
Moritz Lipp committed
628
629
  zathura_free(zathura);

Moritz Lipp's avatar
Moritz Lipp committed
630
631
  return 0;
}
632