callbacks.c 16 KB
Newer Older
Moritz Lipp's avatar
Moritz Lipp committed
1
/* See LICENSE file for license and copyright information */
2

3 4 5
#include <girara/statusbar.h>
#include <girara/session.h>
#include <girara/settings.h>
Sebastian Ramacher's avatar
Sebastian Ramacher committed
6
#include <girara/utils.h>
7
#include <stdlib.h>
8
#include <gtk/gtk.h>
9
#include <string.h>
10
#include <glib/gi18n.h>
11
#include <math.h>
12

Sebastian Ramacher's avatar
Sebastian Ramacher committed
13
#include "callbacks.h"
Moritz Lipp's avatar
Moritz Lipp committed
14
#include "links.h"
15
#include "zathura.h"
Moritz Lipp's avatar
Moritz Lipp committed
16
#include "render.h"
17
#include "document.h"
18
#include "utils.h"
Sebastian Ramacher's avatar
Sebastian Ramacher committed
19
#include "shortcuts.h"
20
#include "page-widget.h"
Moritz Lipp's avatar
Moritz Lipp committed
21
#include "page.h"
22
#include "adjustment.h"
23 24

gboolean
25
cb_destroy(GtkWidget* UNUSED(widget), zathura_t* zathura)
26
{
27
  if (zathura != NULL && zathura->document != NULL) {
28
    document_close(zathura, false);
29 30
  }

31
  gtk_main_quit();
32 33
  return TRUE;
}
34 35

void
36
cb_buffer_changed(girara_session_t* session)
37 38
{
  g_return_if_fail(session != NULL);
Moritz Lipp's avatar
Moritz Lipp committed
39 40 41
  g_return_if_fail(session->global.data != NULL);

  zathura_t* zathura = session->global.data;
42 43

  char* buffer = girara_buffer_get(session);
Moritz Lipp's avatar
Moritz Lipp committed
44
  if (buffer != NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
45
    girara_statusbar_item_set_text(session, zathura->ui.statusbar.buffer, buffer);
46
    free(buffer);
Moritz Lipp's avatar
Moritz Lipp committed
47
  } else {
Moritz Lipp's avatar
Moritz Lipp committed
48
    girara_statusbar_item_set_text(session, zathura->ui.statusbar.buffer, "");
49
  }
50
}
51

52
static void
53 54
update_visible_pages(zathura_t* zathura)
{
55
  const unsigned int number_of_pages = zathura_document_get_number_of_pages(zathura->document);
56 57 58

  for (unsigned int page_id = 0; page_id < number_of_pages; page_id++) {
    zathura_page_t* page = zathura_document_get_page(zathura->document, page_id);
59
    GtkWidget* page_widget = zathura_page_get_widget(zathura, page);
60
    ZathuraPage* zathura_page_widget = ZATHURA_PAGE(page_widget);
61

62 63
    if (page_is_visible(zathura->document, page_id) == true) {
      /* make page visible */
64
      if (zathura_page_get_visibility(page) == false) {
65
        zathura_page_set_visibility(page, true);
66
        zathura_page_widget_update_view_time(zathura_page_widget);
67
        zathura_renderer_page_cache_add(zathura->sync.render_thread, zathura_page_get_index(page));
68
      }
69

70
    } else {
71
      /* make page invisible */
72 73 74 75
      if (zathura_page_get_visibility(page) == true) {
        zathura_page_set_visibility(page, false);
        /* If a page becomes invisible, abort the render request. */
        zathura_page_widget_abort_render_request(zathura_page_widget);
76
      }
77

78
      /* reset current search result */
79 80 81
      girara_list_t* results = NULL;
      g_object_get(page_widget, "search-results", &results, NULL);
      if (results != NULL) {
82
        g_object_set(page_widget, "search-current", 0, NULL);
83
      }
84 85
    }
  }
86 87 88 89 90 91 92 93 94 95
}

void
cb_view_hadjustment_value_changed(GtkAdjustment* adjustment, gpointer data)
{
  zathura_t* zathura = data;
  if (zathura == NULL || zathura->document == NULL) {
    return;
  }

96 97 98 99 100
  /* Do nothing in index mode */
  if (girara_mode_get(zathura->ui.session) == zathura->modes.index) {
    return;
  }

101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
  update_visible_pages(zathura);

  double position_x = zathura_adjustment_get_ratio(adjustment);
  double position_y = zathura_document_get_position_y(zathura->document);
  unsigned int page_id = position_to_page_number(zathura->document, position_x, position_y);

  zathura_document_set_position_x(zathura->document, position_x);
  zathura_document_set_position_y(zathura->document, position_y);
  zathura_document_set_current_page_number(zathura->document, page_id);

  statusbar_page_number_update(zathura);
}

void
cb_view_vadjustment_value_changed(GtkAdjustment* adjustment, gpointer data)
{
  zathura_t* zathura = data;
  if (zathura == NULL || zathura->document == NULL) {
    return;
  }

122 123 124 125 126
  /* Do nothing in index mode */
  if (girara_mode_get(zathura->ui.session) == zathura->modes.index) {
    return;
  }

127 128 129 130 131 132 133 134 135
  update_visible_pages(zathura);

  double position_x = zathura_document_get_position_x(zathura->document);
  double position_y = zathura_adjustment_get_ratio(adjustment);
  unsigned int page_id = position_to_page_number(zathura->document, position_x, position_y);

  zathura_document_set_position_x(zathura->document, position_x);
  zathura_document_set_position_y(zathura->document, position_y);
  zathura_document_set_current_page_number(zathura->document, page_id);
136 137

  statusbar_page_number_update(zathura);
138
}
139

140 141 142 143 144 145 146 147 148
void
cb_view_hadjustment_changed(GtkAdjustment* adjustment, gpointer data)
{
  zathura_t* zathura = data;
  g_return_if_fail(zathura != NULL);

  zathura_adjust_mode_t adjust_mode =
    zathura_document_get_adjust_mode(zathura->document);

149 150 151 152 153
  /* Do nothing in index mode */
  if (girara_mode_get(zathura->ui.session) == zathura->modes.index) {
    return;
  }

154 155 156
  /* Don't scroll we're focusing the inputbar. */
  if (adjust_mode == ZATHURA_ADJUST_INPUTBAR) {
    return;
157
  }
158 159 160 161 162 163 164 165

  /* save the viewport size */
  unsigned int view_width = (unsigned int)floor(gtk_adjustment_get_page_size(adjustment));
  zathura_document_set_viewport_width(zathura->document, view_width);

  /* reset the adjustment, in case bounds have changed */
  double ratio = zathura_document_get_position_x(zathura->document);
  zathura_adjustment_set_value_from_ratio(adjustment, ratio);
166 167 168 169 170 171 172 173
}

void
cb_view_vadjustment_changed(GtkAdjustment* adjustment, gpointer data)
{
  zathura_t* zathura = data;
  g_return_if_fail(zathura != NULL);

174 175 176
  zathura_adjust_mode_t adjust_mode =
    zathura_document_get_adjust_mode(zathura->document);

177 178 179 180 181
  /* Do nothing in index mode */
  if (girara_mode_get(zathura->ui.session) == zathura->modes.index) {
    return;
  }

182
  /* Don't scroll we're focusing the inputbar. */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
183
  if (adjust_mode == ZATHURA_ADJUST_INPUTBAR) {
184
    return;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
185
  }
186

187 188 189 190 191 192
  /* save the viewport size */
  unsigned int view_height = (unsigned int)floor(gtk_adjustment_get_page_size(adjustment));
  zathura_document_set_viewport_height(zathura->document, view_height);

  /* reset the adjustment, in case bounds have changed */
  double ratio = zathura_document_get_position_y(zathura->document);
193 194 195
  zathura_adjustment_set_value_from_ratio(adjustment, ratio);
}

196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
void
cb_refresh_view(GtkWidget* GIRARA_UNUSED(view), gpointer data)
{
  zathura_t* zathura = data;
  if (zathura == NULL || zathura->document == NULL) {
    return;
  }

  unsigned int page_id = zathura_document_get_current_page_number(zathura->document);
  zathura_page_t* page = zathura_document_get_page(zathura->document, page_id);
  if (page == NULL) {
    return;
  }

  GtkAdjustment* vadj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
  GtkAdjustment* hadj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));

  double position_x = zathura_document_get_position_x(zathura->document);
  double position_y = zathura_document_get_position_y(zathura->document);

  zathura_adjustment_set_value_from_ratio(vadj, position_y);
  zathura_adjustment_set_value_from_ratio(hadj, position_x);

  statusbar_page_number_update(zathura);
}

222
void
223
cb_page_layout_value_changed(girara_session_t* session, const char* UNUSED(name), girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data))
224
{
225
  g_return_if_fail(value != NULL);
226 227 228
  g_return_if_fail(session != NULL);
  g_return_if_fail(session->global.data != NULL);
  zathura_t* zathura = session->global.data;
229

230 231 232 233
  if (zathura->document == NULL) {
    /* no document has been openend yet */
    return;
  }
234

235 236
  unsigned int pages_per_row = 1;
  girara_setting_get(session, "pages-per-row", &pages_per_row);
237

238 239 240
  unsigned int first_page_column = 1;
  girara_setting_get(session, "first-page-column", &first_page_column);

241
  unsigned int page_padding = 1;
242
  girara_setting_get(zathura->ui.session, "page-padding", &page_padding);
243 244 245

  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);
246
}
247 248

void
249
cb_index_row_activated(GtkTreeView* tree_view, GtkTreePath* path,
Moritz Lipp's avatar
Moritz Lipp committed
250
                       GtkTreeViewColumn* UNUSED(column), void* data)
251
{
Sebastian Ramacher's avatar
Sebastian Ramacher committed
252
  zathura_t* zathura = data;
253 254 255 256 257 258 259 260 261
  if (tree_view == NULL || zathura == NULL || zathura->ui.session == NULL) {
    return;
  }

  GtkTreeModel  *model;
  GtkTreeIter   iter;

  g_object_get(tree_view, "model", &model, NULL);

Moritz Lipp's avatar
Moritz Lipp committed
262
  if(gtk_tree_model_get_iter(model, &iter, path)) {
263
    zathura_index_element_t* index_element;
264
    gtk_tree_model_get(model, &iter, 2, &index_element, -1);
265 266 267 268 269

    if (index_element == NULL) {
      return;
    }

Moritz Lipp's avatar
Moritz Lipp committed
270
    sc_toggle_index(zathura->ui.session, NULL, NULL, 0);
271
    zathura_link_evaluate(zathura, index_element->link);
272 273 274 275
  }

  g_object_unref(model);
}
276

277 278 279 280 281 282 283 284 285
typedef enum zathura_link_action_e
{
  ZATHURA_LINK_ACTION_FOLLOW,
  ZATHURA_LINK_ACTION_DISPLAY
} zathura_link_action_t;

static bool
handle_link(GtkEntry* entry, girara_session_t* session,
            zathura_link_action_t action)
286 287 288 289 290
{
  g_return_val_if_fail(session != NULL, FALSE);
  g_return_val_if_fail(session->global.data != NULL, FALSE);

  zathura_t* zathura = session->global.data;
Moritz Lipp's avatar
Moritz Lipp committed
291
  bool eval = true;
292 293

  char* input = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
Moritz Lipp's avatar
Moritz Lipp committed
294 295
  if (input == NULL || strlen(input) == 0) {
    eval = false;
296 297
  }

Moritz Lipp's avatar
Moritz Lipp committed
298 299 300 301
  int index = 0;
  if (eval == true) {
    index = atoi(input);
    if (index == 0 && g_strcmp0(input, "0") != 0) {
302
      girara_notify(session, GIRARA_WARNING, _("Invalid input '%s' given."), input);
Moritz Lipp's avatar
Moritz Lipp committed
303 304 305
      eval = false;
    }
    index = index - 1;
306 307 308 309
  }

  /* set pages to draw links */
  bool invalid_index = true;
310 311 312
  unsigned int number_of_pages = zathura_document_get_number_of_pages(zathura->document);
  for (unsigned int page_id = 0; page_id < number_of_pages; page_id++) {
    zathura_page_t* page = zathura_document_get_page(zathura->document, page_id);
Moritz Lipp's avatar
Moritz Lipp committed
313
    if (page == NULL || zathura_page_get_visibility(page) == false) {
314 315 316
      continue;
    }

317
    GtkWidget* page_widget = zathura_page_get_widget(zathura, page);
Moritz Lipp's avatar
Moritz Lipp committed
318
    g_object_set(page_widget, "draw-links", FALSE, NULL);
319

Moritz Lipp's avatar
Moritz Lipp committed
320
    if (eval == true) {
Moritz Lipp's avatar
Moritz Lipp committed
321
      zathura_link_t* link = zathura_page_widget_link_get(ZATHURA_PAGE(page_widget), index);
322

Moritz Lipp's avatar
Moritz Lipp committed
323 324
      if (link != NULL) {
        invalid_index = false;
325 326 327 328 329 330 331 332
        switch (action) {
          case ZATHURA_LINK_ACTION_FOLLOW:
            zathura_link_evaluate(zathura, link);
            break;
          case ZATHURA_LINK_ACTION_DISPLAY:
            zathura_link_display(zathura, link);
            break;
        }
333 334 335 336
      }
    }
  }

Moritz Lipp's avatar
Moritz Lipp committed
337
  if (eval == true && invalid_index == true) {
338
    girara_notify(session, GIRARA_WARNING, _("Invalid index '%s' given."), input);
339 340 341 342
  }

  g_free(input);

Moritz Lipp's avatar
Moritz Lipp committed
343
  return (eval == TRUE) ? TRUE : FALSE;
344
}
345

346 347 348 349 350 351 352 353 354 355 356 357
bool
cb_sc_follow(GtkEntry* entry, girara_session_t* session)
{
  return handle_link(entry, session, ZATHURA_LINK_ACTION_FOLLOW);
}

bool
cb_sc_display_link(GtkEntry* entry, girara_session_t* session)
{
  return handle_link(entry, session, ZATHURA_LINK_ACTION_DISPLAY);
}

358 359 360 361 362 363 364
static gboolean
file_monitor_reload(void* data)
{
  sc_reload((girara_session_t*) data, NULL, NULL, 0);
  return FALSE;
}

365 366 367 368 369 370 371
void
cb_file_monitor(GFileMonitor* monitor, GFile* file, GFile* UNUSED(other_file), GFileMonitorEvent event, girara_session_t* session)
{
  g_return_if_fail(monitor  != NULL);
  g_return_if_fail(file     != NULL);
  g_return_if_fail(session  != NULL);

372 373 374
  switch (event) {
    case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
    case G_FILE_MONITOR_EVENT_CREATED:
375
      g_main_context_invoke(NULL, file_monitor_reload, session);
376 377 378
      break;
    default:
      return;
379 380
  }
}
381

382 383 384 385
static gboolean
password_dialog(gpointer data)
{
  zathura_password_dialog_info_t* dialog = data;
Moritz Lipp's avatar
Moritz Lipp committed
386

387
  if (dialog != NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
388
    girara_dialog(
Moritz Lipp's avatar
Moritz Lipp committed
389 390 391 392 393 394 395
      dialog->zathura->ui.session,
      "Incorrect password. Enter password:",
      true,
      NULL,
      (girara_callback_inputbar_activate_t) cb_password_dialog,
      dialog
    );
396
  }
Moritz Lipp's avatar
Moritz Lipp committed
397

398 399 400
  return FALSE;
}

401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
bool
cb_password_dialog(GtkEntry* entry, zathura_password_dialog_info_t* dialog)
{
  if (entry == NULL || dialog == NULL) {
    goto error_ret;
  }

  if (dialog->path == NULL) {
    free(dialog);
    goto error_ret;
  }

  if (dialog->zathura == NULL) {
    goto error_free;
  }

  char* input = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);

  /* no or empty password: ask again */
  if (input == NULL || strlen(input) == 0) {
    if (input != NULL) {
      g_free(input);
    }

425
    gdk_threads_add_idle(password_dialog, dialog);
426 427 428 429
    return false;
  }

  /* try to open document again */
430 431
  if (document_open(dialog->zathura, dialog->path, input,
                    ZATHURA_PAGE_NUMBER_UNSPECIFIED) == false) {
432
    gdk_threads_add_idle(password_dialog, dialog);
433 434 435 436
  } else {
    g_free(dialog->path);
    free(dialog);
  }
437 438 439 440 441 442 443

  g_free(input);

  return true;

error_free:

Moritz Lipp's avatar
Moritz Lipp committed
444 445
  g_free(dialog->path);
  free(dialog);
446 447 448 449 450

error_ret:

  return false;
}
451 452

bool
453
cb_view_resized(GtkWidget* UNUSED(widget), GtkAllocation* UNUSED(allocation), zathura_t* zathura)
454 455 456 457 458
{
  if (zathura == NULL || zathura->document == NULL) {
    return false;
  }

459 460
  /* adjust the scale according to settings. If nothing needs to be resized,
     it does not trigger the resize event.
461

462 463 464 465
     The right viewport size is already in the document object, due to a
     previous call to adjustment_changed. We don't want to use the allocation in
     here, because we would have to subtract scrollbars, etc. */
  adjust_view(zathura);
466 467

  return false;
468
}
Moritz Lipp's avatar
Moritz Lipp committed
469 470 471

void
cb_setting_recolor_change(girara_session_t* session, const char* name,
Moritz Lipp's avatar
Moritz Lipp committed
472
                          girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data))
Moritz Lipp's avatar
Moritz Lipp committed
473 474 475 476 477 478 479
{
  g_return_if_fail(value != NULL);
  g_return_if_fail(session != NULL);
  g_return_if_fail(session->global.data != NULL);
  g_return_if_fail(name != NULL);
  zathura_t* zathura = session->global.data;

480
  const bool bool_value = *((bool*) value);
Moritz Lipp's avatar
Moritz Lipp committed
481

482 483 484
  if (zathura->sync.render_thread != NULL && zathura_renderer_recolor_enabled(zathura->sync.render_thread) != bool_value) {
     zathura_renderer_enable_recolor(zathura->sync.render_thread, bool_value);
     render_all(zathura);
Moritz Lipp's avatar
Moritz Lipp committed
485 486
  }
}
Moritz Lipp's avatar
Moritz Lipp committed
487

488 489
void
cb_setting_recolor_keep_hue_change(girara_session_t* session, const char* name,
Moritz Lipp's avatar
Moritz Lipp committed
490
                                   girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data))
491 492 493 494 495 496 497
{
  g_return_if_fail(value != NULL);
  g_return_if_fail(session != NULL);
  g_return_if_fail(session->global.data != NULL);
  g_return_if_fail(name != NULL);
  zathura_t* zathura = session->global.data;

498
  const bool bool_value = *((bool*) value);
499

500 501 502
  if (zathura->sync.render_thread != NULL && zathura_renderer_recolor_hue_enabled(zathura->sync.render_thread) != bool_value) {
     zathura_renderer_enable_recolor_hue(zathura->sync.render_thread, bool_value);
     render_all(zathura);
503 504 505 506
  }
}


Moritz Lipp's avatar
Moritz Lipp committed
507 508 509 510 511 512 513 514 515 516 517 518 519 520
bool
cb_unknown_command(girara_session_t* session, const char* input)
{
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  g_return_val_if_fail(input != NULL, false);

  zathura_t* zathura = session->global.data;

  if (zathura->document == NULL) {
    return false;
  }

  /* check for number */
521 522
  const size_t size = strlen(input);
  for (size_t i = 0; i < size; i++) {
Moritz Lipp's avatar
Moritz Lipp committed
523 524 525 526 527
    if (g_ascii_isdigit(input[i]) == FALSE) {
      return false;
    }
  }

528
  zathura_jumplist_add(zathura);
Moritz Lipp's avatar
Moritz Lipp committed
529
  page_set(zathura, atoi(input) - 1);
530
  zathura_jumplist_add(zathura);
Moritz Lipp's avatar
Moritz Lipp committed
531 532 533

  return true;
}
534 535 536 537 538 539 540 541 542

void
cb_page_widget_text_selected(ZathuraPage* page, const char* text, void* data)
{
  g_return_if_fail(page != NULL);
  g_return_if_fail(text != NULL);
  g_return_if_fail(data != NULL);

  zathura_t* zathura = data;
543 544 545 546 547
  girara_mode_t mode = girara_mode_get(zathura->ui.session);
  if (mode != zathura->modes.normal && mode != zathura->modes.fullscreen) {
    return;
  }

548 549 550 551 552 553 554
  GdkAtom* selection = get_selection(zathura);

  /* copy to clipboard */
  if (selection != NULL) {
    gtk_clipboard_set_text(gtk_clipboard_get(*selection), text, -1);

    char* stripped_text = g_strdelimit(g_strdup(text), "\n\t\r\n", ' ');
555 556
    char* escaped_text = g_markup_printf_escaped(
        _("Copied selected text to clipboard: %s"), stripped_text);
557
    g_free(stripped_text);
558

559
    girara_notify(zathura->ui.session, GIRARA_INFO, "%s", escaped_text);
560
    g_free(escaped_text);
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
  }

  g_free(selection);
}

void
cb_page_widget_image_selected(ZathuraPage* page, GdkPixbuf* pixbuf, void* data)
{
  g_return_if_fail(page != NULL);
  g_return_if_fail(pixbuf != NULL);
  g_return_if_fail(data != NULL);

  zathura_t* zathura = data;
  GdkAtom* selection = get_selection(zathura);

  if (selection != NULL) {
    gtk_clipboard_set_image(gtk_clipboard_get(*selection), pixbuf);
  }

  g_free(selection);
}