1 /* gdict-app.c - main application class
2 *
3 * This file is part of GNOME Dictionary
4 *
5 * Copyright (C) 2005 Emmanuele Bassi
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <math.h>
27 #include <sys/stat.h>
28
29 #include <gtk/gtk.h>
30 #include <glib.h>
31 #include <glib/gi18n.h>
32
33 #include "gdict-common.h"
34 #include "gdict-about.h"
35 #include "gdict-pref-dialog.h"
36 #include "gdict-app.h"
37
38 G_DEFINE_TYPE (GdictApp, gdict_app, GTK_TYPE_APPLICATION)
39
40 static GOptionEntry gdict_app_goptions[] = {
41 {
42 "look-up", 0,
43 0,
44 G_OPTION_ARG_STRING_ARRAY, NULL,
45 N_("Words to look up"), N_("WORD")
46 },
47 {
48 "match", 0,
49 0,
50 G_OPTION_ARG_STRING_ARRAY, NULL,
51 N_("Words to match"), N_("WORD")
52 },
53 {
54 "source", 's',
55 0,
56 G_OPTION_ARG_STRING, NULL,
57 N_("Dictionary source to use"), N_("NAME")
58 },
59 {
60 "database", 'D',
61 0,
62 G_OPTION_ARG_STRING, NULL,
63 N_("Database to use"), N_("NAME")
64 },
65 {
66 "strategy", 'S',
67 0,
68 G_OPTION_ARG_STRING, NULL,
69 N_("Strategy to use"), N_("NAME")
70 },
71 {
72 G_OPTION_REMAINING, 0, 0,
73 G_OPTION_ARG_STRING_ARRAY, NULL,
74 N_("Words to look up"), N_("WORDS")
75 },
76 { NULL },
77 };
78
79 static void
gdict_app_cmd_new(GSimpleAction * action,GVariant * parameter,gpointer user_data)80 gdict_app_cmd_new (GSimpleAction *action,
81 GVariant *parameter,
82 gpointer user_data)
83 {
84 GdictApp *app = user_data;
85 GtkWidget *window = gdict_window_new (GDICT_WINDOW_ACTION_CLEAR,
86 GTK_APPLICATION (app),
87 app->loader,
88 NULL, NULL, NULL,
89 NULL);
90
91 gtk_widget_show (window);
92 }
93
94 static void
gdict_app_cmd_preferences(GSimpleAction * action,GVariant * parameter,gpointer user_data)95 gdict_app_cmd_preferences (GSimpleAction *action,
96 GVariant *parameter,
97 gpointer user_data)
98 {
99 GtkApplication *app = user_data;
100 GdictWindow *window;
101
102 g_assert (GTK_IS_APPLICATION (app));
103
104 window = GDICT_WINDOW (gtk_application_get_windows (app)->data);
105 gdict_show_pref_dialog (GTK_WIDGET (window),
106 _("Dictionary Preferences"),
107 window->loader);
108 }
109
110 static void
gdict_app_cmd_help(GSimpleAction * action,GVariant * parameter,gpointer user_data)111 gdict_app_cmd_help (GSimpleAction *action,
112 GVariant *parameter,
113 gpointer user_data)
114 {
115 GtkApplication *app = user_data;
116 GdictWindow *window;
117 GError *err = NULL;
118
119 g_return_if_fail (GTK_IS_APPLICATION (app));
120
121 window = GDICT_WINDOW (gtk_application_get_windows (app)->data);
122
123 #if GTK_CHECK_VERSION (3, 22, 0)
124 gtk_show_uri_on_window (GTK_WINDOW (window),
125 "help:gnome-dictionary",
126 gtk_get_current_event_time (),
127 &err);
128 #else
129 gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (window)),
130 "help:gnome-dictionary",
131 gtk_get_current_event_time (), &err);
132 #endif
133
134 if (err)
135 {
136 gdict_show_gerror_dialog (GTK_WINDOW (window),
137 _("There was an error while displaying help"),
138 err);
139 g_error_free (err);
140 }
141 }
142
143 static void
gdict_app_cmd_about(GSimpleAction * action,GVariant * parameter,gpointer user_data)144 gdict_app_cmd_about (GSimpleAction *action,
145 GVariant *parameter,
146 gpointer user_data)
147 {
148 GtkApplication *app = user_data;
149 GdictWindow *window;
150
151 g_assert (GTK_IS_APPLICATION (app));
152
153 window = GDICT_WINDOW (gtk_application_get_windows (app)->data);
154 gdict_show_about_dialog (GTK_WIDGET (window));
155 }
156
157 static void
gdict_app_cmd_quit(GSimpleAction * action,GVariant * parameter,gpointer user_data)158 gdict_app_cmd_quit (GSimpleAction *action,
159 GVariant *parameter,
160 gpointer user_data)
161 {
162 GtkApplication *app = user_data;
163 GList *windows;
164
165 g_assert (GTK_IS_APPLICATION (app));
166
167 windows = gtk_application_get_windows (app);
168 g_list_foreach (windows, (GFunc)gtk_widget_destroy, NULL);
169 }
170
171 static void
gdict_app_cmd_close(GSimpleAction * action,GVariant * variant,gpointer user_data)172 gdict_app_cmd_close (GSimpleAction *action,
173 GVariant *variant,
174 gpointer user_data)
175 {
176 GtkApplication *app = user_data;
177 GList *windows;
178
179 windows = gtk_application_get_windows (app);
180
181 if (windows != NULL)
182 gtk_window_close (windows->data);
183 }
184
185 static const GActionEntry app_entries[] =
186 {
187 { "new", gdict_app_cmd_new, NULL, NULL, NULL },
188 { "preferences", gdict_app_cmd_preferences, NULL, NULL, NULL },
189 { "help", gdict_app_cmd_help, NULL, NULL, NULL },
190 { "about", gdict_app_cmd_about, NULL, NULL, NULL },
191 { "quit", gdict_app_cmd_quit, NULL, NULL, NULL },
192 { "close", gdict_app_cmd_close, NULL, NULL, NULL }
193 };
194
195 static void
gdict_app_dispose(GObject * object)196 gdict_app_dispose (GObject *object)
197 {
198 GdictApp *app = GDICT_APP (object);
199
200 g_clear_object (&app->loader);
201
202 G_OBJECT_CLASS (gdict_app_parent_class)->dispose (object);
203 }
204
205 static gchar **
strv_concat(gchar ** strv1,gchar ** strv2)206 strv_concat (gchar **strv1, gchar **strv2)
207 {
208 gchar **tmp;
209 guint len1, len2;
210 gint i;
211
212 len1 = g_strv_length (strv1);
213 len2 = g_strv_length (strv2);
214 tmp = g_realloc (strv1, len1 + len2 + 1);
215 for (i = 0; i < len2; i++)
216 tmp[len1 + i] = (gchar *)strv2[i];
217 tmp[len1 + len2] = NULL;
218
219 return tmp;
220 }
221
222 static int
gdict_app_command_line(GApplication * application,GApplicationCommandLine * cmd_line)223 gdict_app_command_line (GApplication *application,
224 GApplicationCommandLine *cmd_line)
225 {
226 GdictApp *app = GDICT_APP (application);
227 gsize words_len, i;
228 GVariantDict *options;
229 gchar **gdict_lookup_words = NULL;
230 gchar **gdict_match_words = NULL;
231 gchar **remaining = NULL;
232 const gchar *gdict_source_name = NULL;
233 const gchar *gdict_database_name = NULL;
234 const gchar *gdict_strategy_name = NULL;
235
236 options = g_application_command_line_get_options_dict (cmd_line);
237
238 g_variant_dict_lookup (options, "look-up", "^as", &gdict_lookup_words);
239 g_variant_dict_lookup (options, "match", "^as", &gdict_match_words);
240 g_variant_dict_lookup (options, "source", "&s", &gdict_source_name);
241 g_variant_dict_lookup (options, "database", "&s", &gdict_database_name);
242 g_variant_dict_lookup (options, "strategy", "&s", &gdict_strategy_name);
243 g_variant_dict_lookup (options, G_OPTION_REMAINING, "^as", &remaining);
244
245 if (remaining != NULL)
246 {
247 if (gdict_match_words != NULL)
248 {
249 gchar **tmp;
250 tmp = strv_concat (gdict_match_words, remaining);
251 g_strfreev (gdict_match_words);
252 g_strfreev (remaining);
253 gdict_match_words = tmp;
254 }
255 else
256 {
257 gdict_match_words = remaining;
258 }
259 remaining = NULL;
260 }
261
262 if (gdict_lookup_words == NULL &&
263 gdict_match_words == NULL)
264 {
265 GtkWidget *window = gdict_window_new (GDICT_WINDOW_ACTION_CLEAR,
266 GTK_APPLICATION (application),
267 app->loader,
268 gdict_source_name,
269 gdict_database_name,
270 gdict_strategy_name,
271 NULL);
272 gtk_widget_show (window);
273
274 goto out;
275 }
276
277 if (gdict_lookup_words != NULL)
278 words_len = g_strv_length (gdict_lookup_words);
279 else
280 words_len = 0;
281
282 for (i = 0; i < words_len; i++)
283 {
284 const gchar *word = gdict_lookup_words[i];
285 GtkWidget *window;
286
287 window = gdict_window_new (GDICT_WINDOW_ACTION_LOOKUP,
288 GTK_APPLICATION (application),
289 app->loader,
290 gdict_source_name,
291 gdict_database_name,
292 gdict_strategy_name,
293 word);
294
295 gtk_widget_show (window);
296 }
297
298 if (gdict_match_words != NULL)
299 words_len = g_strv_length (gdict_match_words);
300 else
301 words_len = 0;
302
303 for (i = 0; i < words_len; i++)
304 {
305 const gchar *word = gdict_match_words[i];
306 GtkWidget *window;
307
308 window = gdict_window_new (GDICT_WINDOW_ACTION_MATCH,
309 GTK_APPLICATION (application),
310 app->loader,
311 gdict_source_name,
312 gdict_database_name,
313 gdict_strategy_name,
314 word);
315
316 gtk_widget_show (window);
317 }
318
319 out:
320 g_strfreev (gdict_lookup_words);
321 g_strfreev (gdict_match_words);
322
323 return 0;
324 }
325
326 static void
gdict_app_activate(GApplication * application)327 gdict_app_activate (GApplication *application)
328 {
329 GdictApp *app = GDICT_APP (application);
330 GtkWidget *window = gdict_window_new (GDICT_WINDOW_ACTION_CLEAR,
331 GTK_APPLICATION (application),
332 app->loader,
333 NULL, NULL, NULL,
334 NULL);
335
336 gtk_widget_show (window);
337 }
338
339 static void
gdict_app_startup(GApplication * application)340 gdict_app_startup (GApplication *application)
341 {
342 static const gchar *action_accels[] =
343 {
344 /* Win shortcuts */
345 "win.save-as", "<Primary>s", NULL,
346 "win.preview", "<Primary><Shift>p", NULL ,
347 "win.print", "<Primary>p", NULL,
348 "win.find", "<Primary>f", NULL,
349 "win.previous-def", "Page_Up", NULL,
350 "win.next-def", "Page_Down", NULL,
351 "win.first-def", "Home", NULL,
352 "win.last-def", "End", NULL,
353 "win.view-sidebar", "F9", NULL,
354 "win.view-speller", "<Primary>t", NULL,
355 "win.view-source", "<Primary>d", NULL,
356 "win.view-strat", "<Primary>r", NULL,
357 "win.lookup", "<Primary>l", NULL,
358 "win.escape", "Escape", NULL,
359 "win.help-overlay-ui", "<Primary>question", NULL,
360 /* App shortcuts */
361 "app.new", "<Primary>n", NULL,
362 "app.preferences", "<Primary>comma", NULL,
363 "app.help", "F1", NULL,
364 "app.close", "<Primary>w", NULL,
365 "app.quit", "<Primary>q", NULL,
366 NULL /* Terminating NULL */
367 };
368
369 g_set_application_name (_("Dictionary"));
370
371 G_APPLICATION_CLASS (gdict_app_parent_class)->startup (application);
372
373 g_action_map_add_action_entries (G_ACTION_MAP (application), app_entries,
374 G_N_ELEMENTS (app_entries), application);
375
376 GtkApplication *gtk_app = GTK_APPLICATION (application);
377 for (const char **it = action_accels;
378 it[0] != NULL;
379 it += g_strv_length ((char **) it) + 1)
380 {
381 gtk_application_set_accels_for_action (gtk_app, it[0], &it[1]);
382 }
383 }
384
385 static void
gdict_app_class_init(GdictAppClass * klass)386 gdict_app_class_init (GdictAppClass *klass)
387 {
388 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
389 GApplicationClass *application_class = G_APPLICATION_CLASS (klass);
390
391 gobject_class->dispose = gdict_app_dispose;
392
393 application_class->startup = gdict_app_startup;
394 application_class->activate = gdict_app_activate;
395 application_class->command_line = gdict_app_command_line;
396 }
397
398 static void
gdict_app_init(GdictApp * app)399 gdict_app_init (GdictApp *app)
400 {
401 char *loader_path;
402
403 /* add user's path for fetching dictionary sources */
404 app->loader = gdict_source_loader_new ();
405 loader_path = gdict_get_config_dir ();
406 gdict_source_loader_add_search_path (app->loader, loader_path);
407 g_free (loader_path);
408
409 /* Add the command line options */
410 g_application_add_main_option_entries (G_APPLICATION (app), gdict_app_goptions);
411
412 /* Set main application icon */
413 gtk_window_set_default_icon_name (APPLICATION_ID);
414 }
415
416 GApplication *
gdict_app_new(void)417 gdict_app_new (void)
418 {
419 return g_object_new (gdict_app_get_type (),
420 "application-id", APPLICATION_ID,
421 "resource-base-path", "/org/gnome/Dictionary",
422 "flags", G_APPLICATION_HANDLES_COMMAND_LINE,
423 NULL);
424 }
425