dbus-interface.c 21.1 KB
Newer Older
1
2
/* See LICENSE file for license and copyright information */

Sebastian Ramacher's avatar
Sebastian Ramacher committed
3
#include "dbus-interface.h"
4
#include "dbus-interface-definitions.h"
5
6
7
8
#include "synctex.h"
#include "macros.h"
#include "zathura.h"
#include "document.h"
9
#include "utils.h"
10
#include "adjustment.h"
11

12
#include <girara/session.h>
13
#include <girara/utils.h>
Sebastian Ramacher's avatar
Sebastian Ramacher committed
14
#include <girara/settings.h>
15
16
#include <gio/gio.h>
#include <sys/types.h>
17
#include <string.h>
18
19
#include <unistd.h>

Sebastian Ramacher's avatar
Sebastian Ramacher committed
20
G_DEFINE_TYPE(ZathuraDbus, zathura_dbus, G_TYPE_OBJECT)
21
22
23

/* template for bus name */
static const char DBUS_NAME_TEMPLATE[] = "org.pwmt.zathura.PID-%d";
24
/* object path */
25
static const char DBUS_OBJPATH[] = "/org/pwmt/zathura";
26
/* interface name */
27
static const char DBUS_INTERFACE[] = "org.pwmt.zathura";
28
29
30
31
32
33
34
35
36
37

typedef struct private_s {
  zathura_t* zathura;
  GDBusNodeInfo* introspection_data;
  GDBusConnection* connection;
  guint owner_id;
  guint registration_id;
} private_t;

#define GET_PRIVATE(obj) \
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
38
  (G_TYPE_INSTANCE_GET_PRIVATE((obj), ZATHURA_TYPE_DBUS, private_t))
39
40
41
42
43
44

static const GDBusInterfaceVTable interface_vtable;

static void
finalize(GObject* object)
{
Sebastian Ramacher's avatar
Sebastian Ramacher committed
45
46
  ZathuraDbus* dbus = ZATHURA_DBUS(object);
  private_t* priv   = GET_PRIVATE(dbus);
47
48
49
50
51
52
53
54
55
56
57
58
59

  if (priv->connection != NULL && priv->registration_id > 0) {
    g_dbus_connection_unregister_object(priv->connection, priv->registration_id);
  }

  if (priv->owner_id > 0) {
    g_bus_unown_name(priv->owner_id);
  }

  if (priv->introspection_data != NULL) {
    g_dbus_node_info_unref(priv->introspection_data);
  }

Sebastian Ramacher's avatar
Sebastian Ramacher committed
60
  G_OBJECT_CLASS(zathura_dbus_parent_class)->finalize(object);
61
62
63
}

static void
Sebastian Ramacher's avatar
Sebastian Ramacher committed
64
zathura_dbus_class_init(ZathuraDbusClass* class)
65
66
67
68
69
70
71
72
73
74
{
  /* add private members */
  g_type_class_add_private(class, sizeof(private_t));

  /* overwrite methods */
  GObjectClass* object_class = G_OBJECT_CLASS(class);
  object_class->finalize     = finalize;
}

static void
Sebastian Ramacher's avatar
Sebastian Ramacher committed
75
zathura_dbus_init(ZathuraDbus* dbus)
76
{
Sebastian Ramacher's avatar
Sebastian Ramacher committed
77
  private_t* priv          = GET_PRIVATE(dbus);
78
79
80
81
82
83
84
  priv->zathura            = NULL;
  priv->introspection_data = NULL;
  priv->connection         = NULL;
  priv->owner_id           = 0;
  priv->registration_id    = 0;
}

85
86
87
88
89
90
91
92
93
static void
gdbus_connection_closed(GDBusConnection* UNUSED(connection),
    gboolean UNUSED(remote_peer_vanished), GError* error, void* UNUSED(data))
{
  if (error != NULL) {
    girara_debug("D-Bus connection closed: %s", error->message);
  }
}

94
95
96
97
98
static void
bus_acquired(GDBusConnection* connection, const gchar* name, void* data)
{
  girara_debug("Bus acquired at '%s'.", name);

99
100
101
102
  /* register callback for GDBusConnection's closed signal */
  g_signal_connect(G_OBJECT(connection), "closed",
                   G_CALLBACK(gdbus_connection_closed), NULL);

Sebastian Ramacher's avatar
Sebastian Ramacher committed
103
104
  ZathuraDbus* dbus = data;
  private_t* priv   = GET_PRIVATE(dbus);
105
106

  GError* error = NULL;
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
107
108
  priv->registration_id = g_dbus_connection_register_object(
      connection, DBUS_OBJPATH, priv->introspection_data->interfaces[0],
109
110
111
      &interface_vtable, dbus, NULL, &error);
  if (priv->registration_id == 0) {
    girara_warning("Failed to register object on D-Bus connection: %s",
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
112
                   error->message);
113
114
115
116
117
118
119
120
121
    g_error_free(error);
    return;
  }

  priv->connection = connection;
}

static void
name_acquired(GDBusConnection* UNUSED(connection), const gchar* name,
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
122
              void* UNUSED(data))
123
124
125
126
127
128
{
  girara_debug("Acquired '%s' on session bus.", name);
}

static void
name_lost(GDBusConnection* UNUSED(connection), const gchar* name,
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
129
          void* UNUSED(data))
130
131
{
  girara_debug("Lost connection or failed to acquire '%s' on session bus.",
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
132
               name);
133
134
}

Sebastian Ramacher's avatar
Sebastian Ramacher committed
135
136
ZathuraDbus*
zathura_dbus_new(zathura_t* zathura)
137
{
Sebastian Ramacher's avatar
Sebastian Ramacher committed
138
  GObject* obj = g_object_new(ZATHURA_TYPE_DBUS, NULL);
139
140
141
142
  if (obj == NULL) {
    return NULL;
  }

Sebastian Ramacher's avatar
Sebastian Ramacher committed
143
144
145
  ZathuraDbus* dbus = ZATHURA_DBUS(obj);
  private_t* priv   = GET_PRIVATE(dbus);
  priv->zathura     = zathura;
146
147

  GError* error = NULL;
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
148
149
  priv->introspection_data = g_dbus_node_info_new_for_xml(DBUS_INTERFACE_XML,
                                                          &error);
150
151
152
153
154
155
156
157
  if (priv->introspection_data == NULL) {
    girara_warning("Failed to parse introspection data: %s", error->message);
    g_error_free(error);
    g_object_unref(obj);
    return NULL;
  }

  char* well_known_name = g_strdup_printf(DBUS_NAME_TEMPLATE, getpid());
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
158
159
160
  priv->owner_id = g_bus_own_name(G_BUS_TYPE_SESSION, well_known_name,
                                  G_BUS_NAME_OWNER_FLAGS_NONE, bus_acquired,
                                  name_acquired, name_lost, dbus, NULL);
161
162
  g_free(well_known_name);

Sebastian Ramacher's avatar
Sebastian Ramacher committed
163
  return dbus;
164
165
}

Sebastian Ramacher's avatar
Sebastian Ramacher committed
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
void
zathura_dbus_edit(ZathuraDbus* edit, unsigned int page, unsigned int x, unsigned int y) {
  private_t* priv = GET_PRIVATE(edit);

  const char* filename = zathura_document_get_path(priv->zathura->document);

  char* input_file = NULL;
  unsigned int line = 0;
  unsigned int column = 0;

  if (synctex_get_input_line_column(filename, page, x, y, &input_file, &line,
        &column) == false) {
    return;
  }

  GError* error = NULL;
  g_dbus_connection_emit_signal(priv->connection, NULL, DBUS_OBJPATH,
    DBUS_INTERFACE, "Edit", g_variant_new("(suu)", input_file, x, y), &error);

  g_free(input_file);

  if (error != NULL) {
    girara_debug("Failed to emit 'Edit' signal: %s", error->message);
    g_error_free(error);
  }
}

193
194
/* D-Bus handler */

195
196
197
198
199
200
201
static void
highlight_rects(zathura_t* zathura, unsigned int page,
                girara_list_t** rectangles)
{
  const unsigned int number_of_pages = zathura_document_get_number_of_pages(zathura->document);

  for (unsigned int p = 0; p != number_of_pages; ++p) {
202
    GObject* widget = G_OBJECT(zathura->pages[p]);
203
204

    g_object_set(widget, "draw-links", FALSE, "search-results", rectangles[p],
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
205
                 NULL);
206
207
208
209
210
211
    if (p == page) {
      g_object_set(widget, "search-current", 0, NULL);
    }
  }

  document_draw_search_results(zathura, true);
212

213
214
  girara_list_t* rect_list = rectangles[page];
  if (rect_list == NULL || girara_list_size(rect_list) == 0) {
215
    girara_debug("No rectangles for the given page. Jumping to page %u.", page);
216
    page_set(zathura, page);
217
218
219
    return;
  }

220
221
222
  bool search_hadjust = true;
  girara_setting_get(zathura->ui.session, "search-hadjust", &search_hadjust);

223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  /* compute the position of the center of the page */
  double pos_x = 0;
  double pos_y = 0;
  page_number_to_position(zathura->document, page, 0.5, 0.5, &pos_x, &pos_y);

  /* correction to center the current result                          */
  /* NOTE: rectangle is in viewport units, already scaled and rotated */
  unsigned int cell_height = 0;
  unsigned int cell_width = 0;
  zathura_document_get_cell_size(zathura->document, &cell_height, &cell_width);

  unsigned int doc_height = 0;
  unsigned int doc_width = 0;
  zathura_document_get_document_size(zathura->document, &doc_height, &doc_width);

238
239
  /* Need to adjust rectangle to page scale and orientation */
  zathura_page_t* doc_page = zathura_document_get_page(zathura->document, page);
240
241
  zathura_rectangle_t* rect = girara_list_nth(rect_list, 0);
  if (rect == NULL) {
242
    girara_debug("List of rectangles is broken. Jumping to page %u.", page);
243
244
245
246
    page_set(zathura, page);
    return;
  }

247
248
  zathura_rectangle_t rectangle = recalc_rectangle(doc_page, *rect);

249
250
251
252
253
254
  /* compute the center of the rectangle, which will be aligned to the center
     of the viewport */
  double center_x = (rectangle.x1 + rectangle.x2) / 2;
  double center_y = (rectangle.y1 + rectangle.y2) / 2;

  pos_y += (center_y - (double)cell_height/2) / (double)doc_height;
255
256
257
  if (search_hadjust == true) {
    pos_x += (center_x - (double)cell_width/2) / (double)doc_width;
  }
258
259

  /* move to position */
260
  girara_debug("Jumping to page %u position (%f, %f).", page, pos_x, pos_y);
261
262
263
  zathura_jumplist_add(zathura);
  position_set(zathura, pos_x, pos_y);
  zathura_jumplist_add(zathura);
264
265
}

266
267
static void
handle_method_call(GDBusConnection* UNUSED(connection),
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
268
269
270
271
                   const gchar* UNUSED(sender), const gchar* object_path,
                   const gchar* interface_name, const gchar* method_name,
                   GVariant* parameters, GDBusMethodInvocation* invocation,
                   void* data)
272
{
Sebastian Ramacher's avatar
Sebastian Ramacher committed
273
274
  ZathuraDbus* dbus = data;
  private_t* priv   = GET_PRIVATE(dbus);
275

276
277
278
279
280
281
282
283
284
285
286
287
  girara_debug("Handling call '%s.%s' on '%s'.", interface_name, method_name,
               object_path);

  /* methods that work without open document */
  if (g_strcmp0(method_name, "OpenDocument") == 0) {
    gchar* filename = NULL;
    gchar* password = NULL;
    gint page = ZATHURA_PAGE_NUMBER_UNSPECIFIED;
    g_variant_get(parameters, "(ssi)", &filename, &password, &page);

    document_close(priv->zathura, false);
    const bool ret = document_open(priv->zathura, filename,
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
288
289
                                   strlen(password) > 0 ? password : NULL,
                                   page);
290
291
292
293
294
295
296
297
    g_free(filename);
    g_free(password);

    GVariant* result = g_variant_new("(b)", ret);
    g_dbus_method_invocation_return_value(invocation, result);
    return;
  } else if (g_strcmp0(method_name, "CloseDocument") == 0) {
    const bool ret = document_close(priv->zathura, false);
298

299
300
301
302
    GVariant* result = g_variant_new("(b)", ret);
    g_dbus_method_invocation_return_value(invocation, result);
    return;
  }
303

304
305
  if (priv->zathura->document == NULL) {
    g_dbus_method_invocation_return_dbus_error(invocation,
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
306
307
                                               "org.pwmt.zathura.NoOpenDocumen",
                                               "No document has been opened.");
308
309
310
311
312
313
314
    return;
  }

  const unsigned int number_of_pages = zathura_document_get_number_of_pages(priv->zathura->document);

  /* methods that require an open document */
  if (g_strcmp0(method_name, "GotoPage") == 0) {
315
316
    guint page = 0;
    g_variant_get(parameters, "(u)", &page);
317
318

    bool ret = true;
319
    if (page >= number_of_pages) {
320
321
      ret = false;
    } else {
322
      page_set(priv->zathura, page);
323
324
325
326
327
    }

    GVariant* result = g_variant_new("(b)", ret);
    g_dbus_method_invocation_return_value(invocation, result);
  } else if (g_strcmp0(method_name, "HighlightRects") == 0) {
328
    guint page = 0;
329
    GVariantIter* iter = NULL;
330
    GVariantIter* secondary_iter = NULL;
331
    g_variant_get(parameters, "(ua(dddd)a(udddd))", &page, &iter,
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
332
                  &secondary_iter);
333

334
    if (page >= number_of_pages) {
335
      girara_debug("Got invalid page number.");
336
      GVariant* result = g_variant_new("(b)", false);
337
338
      g_variant_iter_free(iter);
      g_variant_iter_free(secondary_iter);
339
      g_dbus_method_invocation_return_value(invocation, result);
340
      return;
341
342
343
    }

    /* get rectangles */
344
345
    girara_list_t** rectangles = g_try_malloc0(number_of_pages * sizeof(girara_list_t*));
    if (rectangles == NULL) {
346
347
348
349
350
      g_variant_iter_free(iter);
      g_variant_iter_free(secondary_iter);
      g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR,
                                            G_DBUS_ERROR_NO_MEMORY,
                                            "Failed to allocate memory.");
351
352
353
      return;
    }

354
    rectangles[page] = girara_list_new2(g_free);
355
356
357
358
359
360
361
362
363
    if (rectangles[page] == NULL) {
      g_free(rectangles);
      g_variant_iter_free(iter);
      g_variant_iter_free(secondary_iter);
      g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR,
                                            G_DBUS_ERROR_NO_MEMORY,
                                            "Failed to allocate memory.");
      return;
    }
364

Sebastian Ramacher's avatar
Sebastian Ramacher committed
365
    zathura_rectangle_t temp_rect = { 0, 0, 0, 0 };
366
    while (g_variant_iter_loop(iter, "(dddd)", &temp_rect.x1, &temp_rect.x2,
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
367
                               &temp_rect.y1, &temp_rect.y2)) {
368
369
      zathura_rectangle_t* rect = g_try_malloc0(sizeof(zathura_rectangle_t));
      if (rect == NULL) {
370
371
372
373
374
375
376
377
        g_variant_iter_free(iter);
        g_variant_iter_free(secondary_iter);
        girara_list_free(rectangles[page]);
        g_free(rectangles);
        g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR,
                                              G_DBUS_ERROR_NO_MEMORY,
                                              "Failed to allocate memory.");
        return;
378
      }
379

380
      *rect = temp_rect;
381
      girara_list_append(rectangles[page], rect);
382
383
384
    }
    g_variant_iter_free(iter);

385
    /* get secondary rectangles */
386
387
    guint temp_page = 0;
    while (g_variant_iter_loop(secondary_iter, "(udddd)", &temp_page,
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
388
389
                               &temp_rect.x1, &temp_rect.x2, &temp_rect.y1,
                               &temp_rect.y2)) {
390
      if (temp_page >= number_of_pages) {
391
        /* error out here? */
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
392
        girara_debug("Got invalid page number.");
393
394
395
396
397
398
        continue;
      }

      if (rectangles[temp_page] == NULL) {
        rectangles[temp_page] = girara_list_new2(g_free);
      }
399

400
      zathura_rectangle_t* rect = g_try_malloc0(sizeof(zathura_rectangle_t));
401
402
403
404
405
406
407
408
409
410
411
      if (rect == NULL || rectangles[temp_page] == NULL) {
        g_variant_iter_free(secondary_iter);
        for (unsigned int p = 0; p != number_of_pages; ++p) {
          girara_list_free(rectangles[p]);
        }
        g_free(rectangles);
        g_free(rect);
        g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR,
                                              G_DBUS_ERROR_NO_MEMORY,
                                              "Failed to allocate memory.");
        return;
412
      }
413

414
      *rect = temp_rect;
415
416
417
418
      girara_list_append(rectangles[temp_page], rect);
    }
    g_variant_iter_free(secondary_iter);

419
    highlight_rects(priv->zathura, page, rectangles);
420
    g_free(rectangles);
421
422
423

    GVariant* result = g_variant_new("(b)", true);
    g_dbus_method_invocation_return_value(invocation, result);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
  } else if (g_strcmp0(method_name, "SynctexView") == 0) {
    gchar* input_file = NULL;
    guint line = 0;
    guint column = 0;
    g_variant_get(parameters, "(suu)", &input_file, &line, &column);

    unsigned int page = 0;
    girara_list_t* secondary_rects = NULL;
    girara_list_t* rectangles = synctex_rectangles_from_position(
      zathura_document_get_path(priv->zathura->document), input_file, line,
      column, &page, &secondary_rects);
    g_free(input_file);

    if (rectangles == NULL) {
      GVariant* result = g_variant_new("(b)", false);
      g_dbus_method_invocation_return_value(invocation, result);
      return;
    }

    girara_list_t** all_rectangles = g_try_malloc0(number_of_pages * sizeof(girara_list_t*));
    for (unsigned int p = 0; p != number_of_pages; ++p) {
      if (p == page) {
        all_rectangles[p] = rectangles;
      } else {
        all_rectangles[p] = girara_list_new2(g_free);
      }
    }

    if (secondary_rects != NULL) {
      GIRARA_LIST_FOREACH(secondary_rects, synctex_page_rect_t*, iter, rect)
        zathura_rectangle_t* newrect = g_try_malloc0(sizeof(zathura_rectangle_t));
        *newrect = rect->rect;
        girara_list_append(all_rectangles[rect->page], newrect);
      GIRARA_LIST_FOREACH_END(secondary_rects, synctex_page_rect_t*, iter, rect);
    }

    highlight_rects(priv->zathura, page, all_rectangles);

    girara_list_free(secondary_rects);
    g_free(all_rectangles);

    GVariant* result = g_variant_new("(b)", true);
    g_dbus_method_invocation_return_value(invocation, result);

468
469
470
471
472
  }
}

static GVariant*
handle_get_property(GDBusConnection* UNUSED(connection),
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
473
474
475
476
                    const gchar* UNUSED(sender),
                    const gchar* UNUSED(object_path),
                    const gchar* UNUSED(interface_name),
                    const gchar* property_name, GError** error, void* data)
477
{
Sebastian Ramacher's avatar
Sebastian Ramacher committed
478
479
  ZathuraDbus* dbus = data;
  private_t* priv   = GET_PRIVATE(dbus);
480

481
482
483
484
485
  if (priv->zathura->document == NULL) {
    g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "No document open.");
    return NULL;
  }

486
  if (g_strcmp0(property_name, "filename") == 0) {
487
488
489
490
491
    return g_variant_new_string(zathura_document_get_path(priv->zathura->document));
  } else if (g_strcmp0(property_name, "pagenumber") == 0) {
    return g_variant_new_uint32(zathura_document_get_current_page_number(priv->zathura->document));
  } else if (g_strcmp0(property_name, "numberofpages") == 0) {
    return g_variant_new_uint32(zathura_document_get_number_of_pages(priv->zathura->document));
492
493
494
495
496
497
498
499
500
501
502
503
  }

  return NULL;
}

static const GDBusInterfaceVTable interface_vtable =
{
  .method_call  = handle_method_call,
  .get_property = handle_get_property,
  .set_property = NULL
};

504
505
static const unsigned int TIMEOUT = 3000;

506
507
static bool
call_hightlight_rects(GDBusConnection* connection, const char* filename,
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
508
509
                      const char* name, unsigned int page,
                      girara_list_t* rectangles, girara_list_t* secondary_rects)
510
511
{
  GError* error       = NULL;
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
512
513
514
515
  GVariant* vfilename = g_dbus_connection_call_sync(
      connection, name, DBUS_OBJPATH, "org.freedesktop.DBus.Properties", "Get",
      g_variant_new("(ss)", DBUS_INTERFACE, "filename"), G_VARIANT_TYPE("(v)"),
      G_DBUS_CALL_FLAGS_NONE, TIMEOUT, NULL, &error);
516
517
  if (vfilename == NULL) {
    girara_error("Failed to query 'filename' property from '%s': %s",
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
518
                  name, error->message);
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
    g_error_free(error);
    return false;
  }

  GVariant* tmp = NULL;
  g_variant_get(vfilename, "(v)", &tmp);
  gchar* remote_filename = g_variant_dup_string(tmp, NULL);
  girara_debug("Filename from '%s': %s", name, remote_filename);
  g_variant_unref(tmp);
  g_variant_unref(vfilename);

  if (g_strcmp0(filename, remote_filename) != 0) {
    g_free(remote_filename);
    return false;
  }

  g_free(remote_filename);

  GVariantBuilder* builder = g_variant_builder_new(G_VARIANT_TYPE("a(dddd)"));
  if (rectangles != NULL) {
    GIRARA_LIST_FOREACH(rectangles, zathura_rectangle_t*, iter, rect)
      g_variant_builder_add(builder, "(dddd)", rect->x1, rect->x2, rect->y1,
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
541
                            rect->y2);
542
543
544
545
546
547
548
    GIRARA_LIST_FOREACH_END(rectangles, zathura_rectangle_t*, iter, rect);
  }

  GVariantBuilder* second_builder = g_variant_builder_new(G_VARIANT_TYPE("a(udddd)"));
  if (secondary_rects != NULL) {
    GIRARA_LIST_FOREACH(secondary_rects, synctex_page_rect_t*, iter, rect)
      g_variant_builder_add(second_builder, "(udddd)", rect->page,
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
549
550
                            rect->rect.x1, rect->rect.x2, rect->rect.y1,
                            rect->rect.y2);
551
552
553
    GIRARA_LIST_FOREACH_END(secondary_rects, synctex_page_rect_t*, iter, rect);
  }

Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
554
555
556
557
  GVariant* ret = g_dbus_connection_call_sync(
      connection, name, DBUS_OBJPATH, DBUS_INTERFACE, "HighlightRects",
      g_variant_new("(ua(dddd)a(udddd))", page, builder, second_builder),
      G_VARIANT_TYPE("(b)"), G_DBUS_CALL_FLAGS_NONE, TIMEOUT, NULL, &error);
558
559
560
561
562
563
564
565
566
567
568
569
  g_variant_builder_unref(builder);
  if (ret == NULL) {
    girara_error("Failed to run HighlightRects on '%s': %s", name,
                 error->message);
    g_error_free(error);
    return false;
  }

  g_variant_unref(ret);
  return true;
}

570
bool
571
zathura_dbus_goto_page_and_highlight(const char* filename, unsigned int page,
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
572
573
                                     girara_list_t* rectangles,
                                     girara_list_t* secondary_rects, pid_t hint)
574
{
575
  if (filename == NULL) {
576
577
578
579
    return false;
  }

  GError* error = NULL;
580
581
  GDBusConnection* connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL,
                                               &error);
582
  if (connection == NULL) {
583
    girara_error("Could not connect to session bus: %s", error->message);
584
585
586
587
    g_error_free(error);
    return false;
  }

588
589
590
  if (hint != -1) {
    char* well_known_name = g_strdup_printf(DBUS_NAME_TEMPLATE, hint);
    const bool ret = call_hightlight_rects(connection, filename,
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
591
592
                                           well_known_name, page, rectangles,
                                           secondary_rects);
593
594
595
596
    g_free(well_known_name);
    return ret;
  }

Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
597
598
599
600
  GVariant* vnames = g_dbus_connection_call_sync(
      connection, "org.freedesktop.DBus", "/org/freedesktop/DBus",
      "org.freedesktop.DBus", "ListNames", NULL, G_VARIANT_TYPE("(as)"),
      G_DBUS_CALL_FLAGS_NONE, TIMEOUT, NULL, &error);
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
  if (vnames == NULL) {
    girara_error("Could not list available names: %s", error->message);
    g_error_free(error);
    g_object_unref(connection);
    return false;
  }

  GVariantIter* iter = NULL;
  g_variant_get(vnames, "(as)", &iter);

  gchar* name = NULL;
  bool found_one = false;
  while (g_variant_iter_loop(iter, "s", &name) == TRUE) {
    if (g_str_has_prefix(name, "org.pwmt.zathura.PID") == FALSE) {
      continue;
    }
    girara_debug("Found name: %s", name);

619
    if (call_hightlight_rects(connection, filename, name, page, rectangles,
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
620
                              secondary_rects) == true) {
621
      found_one = true;
622
623
624
625
    }
  }
  g_variant_iter_free(iter);
  g_variant_unref(vnames);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
626
  g_object_unref(connection);
627
628
629
630

  return found_one;
}

631
bool
632
633
zathura_dbus_synctex_position(const char* filename, const char* input_file,
                              int line, int column, pid_t hint)
634
{
635
  if (filename == NULL || input_file == NULL) {
636
637
638
    return false;
  }

639
  unsigned int page = 0;
640
  girara_list_t* secondary_rects = NULL;
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
641
  girara_list_t* rectangles = synctex_rectangles_from_position(
642
      filename, input_file, line, column, &page, &secondary_rects);
643
644
645
646
  if (rectangles == NULL) {
    return false;
  }

647
  const bool ret = zathura_dbus_goto_page_and_highlight(filename, page,
Sebastian Ramacher's avatar
CS    
Sebastian Ramacher committed
648
649
                                                        rectangles,
                                                        secondary_rects, hint);
650
  girara_list_free(rectangles);
651
  girara_list_free(secondary_rects);
652
653
  return ret;
}