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

3
#include <girara/utils.h>
4
#include <girara/settings.h>
5
6
7
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <limits.h>
Moritz Lipp's avatar
Moritz Lipp committed
8
#include <locale.h>
9
10
11
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Moritz Lipp's avatar
Moritz Lipp committed
12
13

#include "zathura.h"
14
#include "utils.h"
Sebastian Ramacher's avatar
Sebastian Ramacher committed
15
#include "dbus-interface.h"
16
#ifdef WITH_SYNCTEX
17
#include "synctex.h"
18
#endif
Moritz Lipp's avatar
Moritz Lipp committed
19
20

/* main function */
21
22
int
main(int argc, char* argv[])
Moritz Lipp's avatar
Moritz Lipp committed
23
{
24
  /* init locale */
25
26
27
28
29
  setlocale(LC_ALL, "");
  bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
  bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
  textdomain(GETTEXT_PACKAGE);

30
  /* init gtk */
31
#if !GTK_CHECK_VERSION(3, 6, 0)
Moritz Lipp's avatar
Moritz Lipp committed
32
  gdk_threads_init();
33
#endif
Moritz Lipp's avatar
Moritz Lipp committed
34
35
  gtk_init(&argc, &argv);

36
37
38
  /* parse command line arguments */
  gchar* config_dir     = NULL;
  gchar* data_dir       = NULL;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
39
  gchar* cache_dir      = NULL;
40
41
42
  gchar* plugin_path    = NULL;
  gchar* loglevel       = NULL;
  gchar* password       = NULL;
43
#ifdef WITH_SYNCTEX
44
  gchar* synctex_editor = NULL;
45
  gchar* synctex_fwd    = NULL;
46
#endif
Sebastian Ramacher's avatar
Sebastian Ramacher committed
47
  gchar* mode           = NULL;
48
49
  bool forkback         = false;
  bool print_version    = false;
50
  int page_number       = ZATHURA_PAGE_NUMBER_UNSPECIFIED;
51
#ifdef WITH_SYNCTEX
52
  int synctex_pid       = -1;
53
#endif
54
#ifdef GDK_WINDOWING_X11
Sebastian Ramacher's avatar
Sebastian Ramacher committed
55
  Window embed          = 0;
56
#endif
57
58

  GOptionEntry entries[] = {
59
#ifdef GDK_WINDOWING_X11
60
    { "reparent",               'e',  0, G_OPTION_ARG_INT,      &embed,          _("Reparents to window specified by xid"),              "xid"  },
61
#endif
62
63
    { "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" },
Sebastian Ramacher's avatar
Sebastian Ramacher committed
64
    { "cache-dir",              '\0', 0, G_OPTION_ARG_FILENAME, &cache_dir,      _("Path to the cache directory"),                       "path"},
65
66
67
68
69
70
    { "plugins-dir",            'p',  0, G_OPTION_ARG_STRING,   &plugin_path,    _("Path to the directories containing plugins"),        "path" },
    { "fork",                   '\0', 0, G_OPTION_ARG_NONE,     &forkback,       _("Fork into the background"),                          NULL },
    { "password",               'w',  0, G_OPTION_ARG_STRING,   &password,       _("Document password"),                                 "password" },
    { "page",                   'P',  0, G_OPTION_ARG_INT,      &page_number,    _("Page number to go to"),                              "number" },
    { "debug",                  'l',  0, G_OPTION_ARG_STRING,   &loglevel,       _("Log level (debug, info, warning, error)"),           "level" },
    { "version",                'v',  0, G_OPTION_ARG_NONE,     &print_version,  _("Print version information"),                         NULL },
71
#ifdef WITH_SYNCTEX
72
    { "synctex-editor-command", 'x',  0, G_OPTION_ARG_STRING,   &synctex_editor, _("Synctex editor (forwarded to the synctex command)"), "cmd" },
Sebastian Ramacher's avatar
Sebastian Ramacher committed
73
    { "synctex-forward",        '\0', 0, G_OPTION_ARG_STRING,   &synctex_fwd,    _("Move to given synctex position"),                    "position" },
74
    { "synctex-pid",            '\0', 0, G_OPTION_ARG_INT,      &synctex_pid,    _("Highlight given position in the given process"),     "pid" },
75
#endif
Sebastian Ramacher's avatar
Sebastian Ramacher committed
76
    { "mode",                   '\0', 0, G_OPTION_ARG_STRING,   &mode,           _("Start in a non-default mode"),                       "mode" },
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
    { NULL, '\0', 0, 0, NULL, NULL, NULL }
  };

  GOptionContext* context = g_option_context_new(" [file1] [file2] [...]");
  g_option_context_add_main_entries(context, entries, NULL);

  GError* error = NULL;
  if (g_option_context_parse(context, &argc, &argv, &error) == false) {
    girara_error("Error parsing command line arguments: %s\n", error->message);
    g_option_context_free(context);
    g_error_free(error);

    return -1;
  }
  g_option_context_free(context);

Sebastian Ramacher's avatar
Sebastian Ramacher committed
93
94
95
96
97
98
99
100
101
  /* Set log level. */
  if (loglevel == NULL || g_strcmp0(loglevel, "info") == 0) {
    girara_set_debug_level(GIRARA_INFO);
  } else if (g_strcmp0(loglevel, "warning") == 0) {
    girara_set_debug_level(GIRARA_WARNING);
  } else if (g_strcmp0(loglevel, "error") == 0) {
    girara_set_debug_level(GIRARA_ERROR);
  }

102
#ifdef WITH_SYNCTEX
Sebastian Ramacher's avatar
Sebastian Ramacher committed
103
  /* handle synctex forward synchronization */
104
105
  if (synctex_fwd != NULL) {
    if (argc != 2) {
106
      girara_error("Too many arguments or missing filename while running with --synctex-forward");
107
108
109
      return -1;
    }

110
111
112
113
114
115
116
117
    GFile* file = g_file_new_for_commandline_arg(argv[1]);
    if (file == NULL) {
      girara_error("Unable to handle argument '%s'.", argv[1]);
      return -1;
    }

    char* real_path = g_file_get_path(file);
    g_object_unref(file);
118
    if (real_path == NULL) {
119
      girara_error("Failed to determine path for '%s'", argv[1]);
120
121
122
      return -1;
    }

123
124
125
126
    int line = 0;
    int column = 0;
    char* input_file = NULL;
    if (synctex_parse_input(synctex_fwd, &input_file, &line, &column) == false) {
127
      girara_error("Failed to parse argument to --synctex-forward.");
128
      g_free(real_path);
129
130
131
      return -1;
    }

132
133
134
    const int ret = zathura_dbus_synctex_position(real_path, input_file, line, column, synctex_pid);
    g_free(input_file);
    g_free(real_path);
135

136
137
138
139
140
141
142
    if (ret == -1) {
      /* D-Bus or SyncTeX failed */
      girara_error("Got no usable data from SyncTeX or D-Bus failed in some way.");
      return -1;
    } else if (ret == 1) {
      /* Found a instance */
      return 0;
143
    }
144

145
    girara_debug("No instance found. Starting new one.");
146
  }
147
#endif
148

Sebastian Ramacher's avatar
Sebastian Ramacher committed
149
150
151
152
153
  /* check mode */
  if (mode != NULL && g_strcmp0(mode, "presentation") != 0 && g_strcmp0(mode, "fullscreen") != 0) {
    girara_error("Invalid argument for --mode: %s", mode);
    return -1;
  }
154

155
156
  /* Fork into the background if the user really wants to ... */
  if (forkback == true) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
157
    const pid_t pid = fork();
158
    if (pid > 0) { /* parent */
159
      return 0;
160
161
162
163
164
165
166
    } else if (pid < 0) { /* error */
      girara_error("Couldn't fork.");
    }

    setsid();
  }

167
168
169
170
171
172
  /* create zathura session */
  zathura_t* zathura = zathura_create();
  if (zathura == NULL) {
    return -1;
  }

173
#ifdef GDK_WINDOWING_X11
174
  zathura_set_xid(zathura, embed);
175
#endif
176
177
  zathura_set_config_dir(zathura, config_dir);
  zathura_set_data_dir(zathura, data_dir);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
178
  zathura_set_cache_dir(zathura, cache_dir);
179
180
181
182
  zathura_set_plugin_dir(zathura, plugin_path);
  zathura_set_argv(zathura, argv);

  /* Init zathura */
183
  if (zathura_init(zathura) == false) {
184
185
186
187
188
    girara_error("Could not initialize zathura.");
    zathura_free(zathura);
    return -1;
  }

189
#ifdef WITH_SYNCTEX
190
191
192
  if (synctex_editor != NULL) {
    girara_setting_set(zathura->ui.session, "synctex-editor-command", synctex_editor);
  }
193
#endif
Moritz Lipp's avatar
Moritz Lipp committed
194

195
196
197
198
199
  /* Print version */
  if (print_version == true) {
    char* string = zathura_get_version_string(zathura, false);
    if (string != NULL) {
      fprintf(stdout, "%s\n", string);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
200
      g_free(string);
201
202
203
204
205
206
207
208
    }
    zathura_free(zathura);

    return 0;
  }

  /* open document if passed */
  if (argc > 1) {
209
210
    if (page_number > 0)
      --page_number;
211
#ifdef WITH_SYNCTEX
212
    document_open_idle(zathura, argv[1], password, page_number, mode, synctex_fwd);
213
214
215
#else
    document_open_idle(zathura, argv[1], password, page_number, mode, NULL);
#endif
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
  }
  if (argc > 2) {
    char* new_argv[2 * sizeof(entries) / sizeof(GOptionEntry) + 3] = {
      NULL
    };

    size_t idx = 0;
    new_argv[idx++] = g_strdup(zathura->global.arguments[0]);

    /* pass arguments to new process */
    if (config_dir != NULL) {
      new_argv[idx++] = g_strdup("--config-dir");
      new_argv[idx++] = g_strdup(config_dir);
    }
    if (data_dir != NULL) {
      new_argv[idx++] = g_strdup("--data-dir");
      new_argv[idx++] = g_strdup(data_dir);
    }
    if (cache_dir != NULL) {
      new_argv[idx++] = g_strdup("--cache-dir");
      new_argv[idx++] = g_strdup(cache_dir);
    }
    if (plugin_path != NULL) {
      new_argv[idx++] = g_strdup("--plugins-dir");
      new_argv[idx++] = g_strdup(plugin_path);
    }
    /* no need to pass fork */
    if (password != NULL) {
      new_argv[idx++] = g_strdup("--password");
      new_argv[idx++] = g_strdup(password);
    }
    if (page_number != ZATHURA_PAGE_NUMBER_UNSPECIFIED) {
      new_argv[idx++] = g_strdup("--page");
      new_argv[idx++] = g_strdup_printf("%d", page_number);
    }
    if (loglevel != NULL) {
      new_argv[idx++] = g_strdup("--debug");
      new_argv[idx++] = g_strdup(loglevel);
    }
255
#ifdef WITH_SYNCTEX
256
257
258
259
260
261
262
263
    if (synctex_editor != NULL) {
      new_argv[idx++] = g_strdup("--synctex-editor-command");
      new_argv[idx++] = g_strdup(synctex_editor);
    }
    if (synctex_fwd != NULL) {
      new_argv[idx++] = g_strdup("--synctex-forward");
      new_argv[idx++] = g_strdup(synctex_fwd);
    }
264
#endif
265
266
267
268
269
    /* no need to pass synctex-pid */
    if (mode != NULL) {
      new_argv[idx++] = g_strdup("--mode");
      new_argv[idx++] = g_strdup(mode);
    }
270
271
272

    /* open additional files */
    for (int i = 2; i < argc; i++) {
273
274
      g_free(new_argv[idx]);
      new_argv[idx] = g_strdup(argv[i]);
275
276
277

      g_spawn_async(NULL, new_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL);
    }
278
279
280
281

    for (size_t s = 0; s <= idx; ++s) {
      g_free(new_argv[s]);
    }
282
283
284
  }

  /* run zathura */
285
#if !GTK_CHECK_VERSION(3, 6, 0)
Moritz Lipp's avatar
Moritz Lipp committed
286
  gdk_threads_enter();
287
#endif
Moritz Lipp's avatar
Moritz Lipp committed
288
  gtk_main();
289
#if !GTK_CHECK_VERSION(3, 6, 0)
Moritz Lipp's avatar
Moritz Lipp committed
290
  gdk_threads_leave();
291
#endif
Moritz Lipp's avatar
Moritz Lipp committed
292

293
  /* free zathura */
Moritz Lipp's avatar
Moritz Lipp committed
294
295
296
297
  zathura_free(zathura);

  return 0;
}