2
* This file is part of LaTeXila.
4
* Copyright Ā© 2009, 2010 SĆ©bastien Wilmet
6
* LaTeXila is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
11
* LaTeXila is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with LaTeXila. If not, see <http://www.gnu.org/licenses/>.
25
#include "callbacks.h"
27
#include "file_browser.h"
31
#include "templates.h"
32
#include "latex_output_filter.h"
35
static gboolean option_version (const gchar *option_name, const gchar *value,
36
gpointer data, GError **error);
37
static void init_main_window (void);
38
static void init_side_pane (void);
39
static void init_source_view (GtkWidget *vbox_source_view);
40
static void init_go_to_line (GtkWidget *vbox_source_view);
41
static void init_find (GtkWidget *vbox_source_view);
42
static void init_replace (GtkWidget *vbox_source_view);
43
static void init_statusbar (GtkWidget *main_vbox);
45
latexila_t latexila = {NULL};
48
option_version (const gchar *option_name, const gchar *value, gpointer data,
51
print_info ("%s %s", PROGRAM_NAME, PROGRAM_VERSION);
52
print_info ("\tGTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
54
print_info ("\tGLib %d.%d.%d", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
56
print_info ("\tGtkSourceView %s", GTKSOURCEVIEW_VERSION);
60
print_info ("\t%s GTK+ %s %d.%d.%d (%s %d.%d.%d)",
61
_("using"), _("version"),
62
gtk_major_version, gtk_minor_version, gtk_micro_version,
63
_("compiled against version"),
64
GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION);
66
print_info ("\t%s GLib %s %d.%d.%d (%s %d.%d.%d)",
67
_("using"), _("version"),
68
glib_major_version, glib_minor_version, glib_micro_version,
69
_("compiled against version"),
70
GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
78
init_main_window (void)
80
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
81
latexila.main_window = GTK_WINDOW (window);
82
g_signal_connect (G_OBJECT (window), "delete_event",
83
G_CALLBACK (cb_delete_event), NULL);
84
gtk_window_set_title (GTK_WINDOW (window), PROGRAM_NAME);
85
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
86
gtk_window_set_default_size (GTK_WINDOW (window),
87
latexila.prefs.window_width, latexila.prefs.window_height);
90
GList *list_icons = NULL;
94
DATA_DIR "/images/logo/icon16.png",
95
DATA_DIR "/images/logo/icon22.png",
96
DATA_DIR "/images/logo/icon24.png",
97
DATA_DIR "/images/logo/icon32.png",
98
DATA_DIR "/images/logo/icon48.png",
101
guint nb_icons = G_N_ELEMENTS (filenames);
103
for (int i = 0 ; i < nb_icons ; i++)
105
// TODO check memory leaks here
106
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (filenames[i], &error);
109
print_warning ("%s", error->message);
110
g_error_free (error);
115
list_icons = g_list_append (list_icons, pixbuf);
118
gtk_window_set_default_icon_list (list_icons);
120
// Gtk have a copy of the GList and adds a ref to every icon
121
g_list_foreach (list_icons, (GFunc) g_object_unref, NULL);
122
g_list_free (list_icons);
124
if (latexila.prefs.window_maximised)
125
gtk_window_maximize (GTK_WINDOW (window));
129
init_side_pane (void)
131
GtkWidget *side_pane_notebook = gtk_notebook_new ();
132
latexila.side_pane = side_pane_notebook;
133
gtk_notebook_set_scrollable (GTK_NOTEBOOK (side_pane_notebook), TRUE);
134
gtk_paned_add1 (latexila.main_hpaned, side_pane_notebook);
138
GtkWidget *vbox_symbols = gtk_vbox_new (FALSE, 0);
139
latexila.symbols.vbox = vbox_symbols;
141
GtkWidget *tab_label = gtk_hbox_new (FALSE, 3);
142
GtkWidget *label = gtk_label_new (_("Symbols"));
143
GtkWidget *image = gtk_image_new_from_file (DATA_DIR "/images/greek/01.png");
144
gtk_box_pack_start (GTK_BOX (tab_label), image, FALSE, FALSE, 0);
145
gtk_box_pack_start (GTK_BOX (tab_label), label, TRUE, TRUE, 0);
146
gtk_widget_show_all (tab_label);
148
gtk_notebook_append_page (GTK_NOTEBOOK (side_pane_notebook), vbox_symbols,
155
GtkWidget *vbox_file_browser = gtk_vbox_new (FALSE, 0);
157
GtkWidget *tab_label = gtk_hbox_new (FALSE, 3);
158
GtkWidget *label = gtk_label_new (_("File Browser"));
159
GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_OPEN,
161
gtk_box_pack_start (GTK_BOX (tab_label), image, FALSE, FALSE, 0);
162
gtk_box_pack_start (GTK_BOX (tab_label), label, TRUE, TRUE, 0);
163
gtk_widget_show_all (tab_label);
165
gtk_notebook_append_page (GTK_NOTEBOOK (side_pane_notebook),
166
vbox_file_browser, tab_label);
167
init_file_browser (vbox_file_browser);
172
init_source_view (GtkWidget *vbox_source_view)
174
GtkWidget *notebook = gtk_notebook_new ();
175
latexila.notebook = GTK_NOTEBOOK (notebook);
176
gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
177
g_signal_connect (G_OBJECT (notebook), "switch-page",
178
G_CALLBACK (cb_page_change), NULL);
179
g_signal_connect (G_OBJECT (notebook), "page-reordered",
180
G_CALLBACK (cb_page_reordered), NULL);
181
gtk_box_pack_start (GTK_BOX (vbox_source_view), notebook, TRUE, TRUE, 0);
185
init_go_to_line (GtkWidget *vbox_source_view)
187
GtkWidget *go_to_line = gtk_hbox_new (FALSE, 3);
188
latexila.under_source_view.go_to_line = go_to_line;
189
gtk_box_pack_start (GTK_BOX (vbox_source_view), go_to_line, FALSE, FALSE, 0);
191
GtkWidget *close_button = gtk_button_new ();
192
gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
193
GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_CLOSE,
195
gtk_container_add (GTK_CONTAINER (close_button), image);
196
g_signal_connect (G_OBJECT (close_button), "clicked",
197
G_CALLBACK (cb_close_go_to_line), NULL);
198
gtk_box_pack_start (GTK_BOX (go_to_line), close_button, FALSE, FALSE, 0);
200
GtkWidget *label = gtk_label_new (_("Go to Line:"));
201
gtk_box_pack_start (GTK_BOX (go_to_line), label, FALSE, FALSE, 2);
203
GtkWidget *entry_go_to_line = gtk_entry_new ();
204
latexila.under_source_view.go_to_line_entry = entry_go_to_line;
205
gtk_entry_set_icon_from_stock (GTK_ENTRY (entry_go_to_line),
206
GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_JUMP_TO);
207
gtk_widget_set_tooltip_text (entry_go_to_line,
208
_("Line you want to move the cursor to"));
209
g_signal_connect (G_OBJECT (entry_go_to_line), "activate",
210
G_CALLBACK (cb_go_to_line_entry), NULL);
211
gtk_box_pack_start (GTK_BOX (go_to_line), entry_go_to_line, FALSE, FALSE, 0);
215
init_find (GtkWidget *vbox_source_view)
217
GtkWidget *find = gtk_hbox_new (FALSE, 3);
218
latexila.under_source_view.find = find;
219
gtk_box_pack_start (GTK_BOX (vbox_source_view), find, FALSE, FALSE, 0);
221
GtkWidget *close_button = gtk_button_new ();
222
gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
223
GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
224
gtk_container_add (GTK_CONTAINER (close_button), image);
225
g_signal_connect (G_OBJECT (close_button), "clicked",
226
G_CALLBACK (cb_close_find), NULL);
227
gtk_box_pack_start (GTK_BOX (find), close_button, FALSE, FALSE, 0);
229
GtkWidget *label = gtk_label_new (_("Find:"));
230
gtk_box_pack_start (GTK_BOX (find), label, FALSE, FALSE, 2);
232
GtkWidget *find_entry = gtk_entry_new ();
233
latexila.under_source_view.find_entry = find_entry;
234
g_signal_connect (G_OBJECT (find_entry), "activate",
235
G_CALLBACK (cb_find_entry), NULL);
236
gtk_box_pack_start (GTK_BOX (find), find_entry, FALSE, FALSE, 0);
238
GtkWidget *previous_button = gtk_button_new_with_label (_("Previous"));
239
image = gtk_image_new_from_stock (GTK_STOCK_GO_BACK, GTK_ICON_SIZE_MENU);
240
gtk_button_set_image (GTK_BUTTON (previous_button), image);
241
gtk_button_set_relief (GTK_BUTTON (previous_button), GTK_RELIEF_NONE);
242
g_signal_connect (G_OBJECT (previous_button), "clicked",
243
G_CALLBACK (cb_find_previous), NULL);
244
gtk_box_pack_start (GTK_BOX (find), previous_button, FALSE, FALSE, 0);
246
GtkWidget *next_button = gtk_button_new_with_label (_("Next"));
247
image = gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_MENU);
248
gtk_button_set_image (GTK_BUTTON (next_button), image);
249
gtk_button_set_relief (GTK_BUTTON (next_button), GTK_RELIEF_NONE);
250
g_signal_connect (G_OBJECT (next_button), "clicked",
251
G_CALLBACK (cb_find_next), NULL);
252
gtk_box_pack_start (GTK_BOX (find), next_button, FALSE, FALSE, 0);
254
GtkWidget *match_case = gtk_check_button_new_with_label (_("Match case"));
255
latexila.under_source_view.find_match_case = match_case;
256
gtk_box_pack_start (GTK_BOX (find), match_case, FALSE, FALSE, 0);
260
init_replace (GtkWidget *vbox_source_view)
262
GtkWidget *replace = gtk_hbox_new (FALSE, 3);
263
latexila.under_source_view.replace = replace;
264
gtk_box_pack_start (GTK_BOX (vbox_source_view), replace, FALSE, FALSE, 0);
266
// see the result to understand ;)
267
GtkWidget *vbox = gtk_vbox_new (FALSE, 2);
268
GtkWidget *hbox1 = gtk_hbox_new (FALSE, 3);
269
GtkWidget *hbox2 = gtk_hbox_new (FALSE, 3);
270
gtk_box_pack_start (GTK_BOX (vbox), hbox1, FALSE, FALSE, 0);
271
gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 0);
273
// left: close button
274
GtkWidget *close_button = gtk_button_new ();
275
gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
276
GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_CLOSE,
278
gtk_container_add (GTK_CONTAINER (close_button), image);
279
g_signal_connect (G_OBJECT (close_button), "clicked",
280
G_CALLBACK (cb_close_replace), NULL);
281
gtk_box_pack_start (GTK_BOX (replace), close_button, FALSE, FALSE, 0);
283
// right: the two hbox
284
gtk_box_pack_start (GTK_BOX (replace), vbox, FALSE, FALSE, 0);
287
GtkWidget *label = gtk_label_new (_("Search for:"));
288
gtk_box_pack_start (GTK_BOX (hbox1), label, FALSE, FALSE, 0);
290
GtkWidget *replace_entry_search = gtk_entry_new ();
291
latexila.under_source_view.replace_entry_search = replace_entry_search;
292
gtk_box_pack_start (GTK_BOX (hbox1), replace_entry_search, FALSE, FALSE, 5);
294
label = gtk_label_new (_("Replace with:"));
295
gtk_box_pack_start (GTK_BOX (hbox1), label, FALSE, FALSE, 0);
297
GtkWidget *replace_entry_replace = gtk_entry_new ();
298
latexila.under_source_view.replace_entry_replace = replace_entry_replace;
299
gtk_box_pack_start (GTK_BOX (hbox1), replace_entry_replace, FALSE, FALSE, 5);
301
GtkWidget *match_case = gtk_check_button_new_with_label (_("Match case"));
302
latexila.under_source_view.replace_match_case = match_case;
303
gtk_box_pack_start (GTK_BOX (hbox1), match_case, FALSE, FALSE, 0);
306
GtkWidget *button_replace_all = gtk_button_new_with_label (_("Replace All"));
307
gtk_button_set_relief (GTK_BUTTON (button_replace_all), GTK_RELIEF_NONE);
308
g_signal_connect (G_OBJECT (button_replace_all), "clicked",
309
G_CALLBACK (cb_replace_replace_all), NULL);
310
gtk_box_pack_start (GTK_BOX (hbox2), button_replace_all, FALSE, FALSE, 0);
312
GtkWidget *button_replace = gtk_button_new_with_label (_("Replace"));
313
latexila.under_source_view.replace_button = button_replace;
314
image = gtk_image_new_from_stock (GTK_STOCK_FIND_AND_REPLACE, GTK_ICON_SIZE_MENU);
315
gtk_button_set_image (GTK_BUTTON (button_replace), image);
316
gtk_button_set_relief (GTK_BUTTON (button_replace), GTK_RELIEF_NONE);
317
// we can not make a replace before finding the first occurence
318
gtk_widget_set_sensitive (button_replace, FALSE);
319
g_signal_connect (G_OBJECT (button_replace), "clicked",
320
G_CALLBACK (cb_replace_replace), NULL);
321
gtk_box_pack_start (GTK_BOX (hbox2), button_replace, FALSE, FALSE, 0);
323
GtkWidget *button_find = gtk_button_new_from_stock (GTK_STOCK_FIND);
324
gtk_button_set_relief (GTK_BUTTON (button_find), GTK_RELIEF_NONE);
325
g_signal_connect (G_OBJECT (button_find), "clicked",
326
G_CALLBACK (cb_replace_find), NULL);
327
gtk_box_pack_start (GTK_BOX (hbox2), button_find, FALSE, FALSE, 0);
331
init_statusbar (GtkWidget *main_vbox)
333
GtkWidget *statusbar = gtk_statusbar_new ();
334
latexila.statusbar = GTK_STATUSBAR (statusbar);
335
gtk_box_pack_start (GTK_BOX (main_vbox), statusbar, FALSE, FALSE, 0);
337
GtkWidget *cursor_position_statusbar = gtk_statusbar_new ();
338
latexila.cursor_position = GTK_STATUSBAR (cursor_position_statusbar);
339
gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (cursor_position_statusbar),
341
gtk_widget_set_size_request (cursor_position_statusbar, 150, -1);
342
gtk_box_pack_end (GTK_BOX (statusbar), cursor_position_statusbar,
347
main (int argc, char *argv[])
349
GError *error = NULL;
352
gchar *latexila_nls_package = NULL;
354
#ifdef LATEXILA_NLS_ENABLED
355
setlocale (LC_ALL, "");
356
bindtextdomain (LATEXILA_NLS_PACKAGE, LATEXILA_NLS_LOCALEDIR);
357
bind_textdomain_codeset (LATEXILA_NLS_PACKAGE, "UTF-8");
358
textdomain (LATEXILA_NLS_PACKAGE);
359
latexila_nls_package = LATEXILA_NLS_PACKAGE;
362
/* command line options */
363
gboolean option_new_document = FALSE;
365
GOptionEntry options[] = {
366
{ "version", 'v', G_OPTION_FLAG_IN_MAIN | G_OPTION_FLAG_NO_ARG,
367
G_OPTION_ARG_CALLBACK, (gpointer) option_version,
368
N_("Display version informations"), NULL },
369
{ "new-document", 'n', G_OPTION_FLAG_IN_MAIN | G_OPTION_FLAG_NO_ARG,
370
G_OPTION_ARG_NONE, &option_new_document,
371
N_("Create new document"), NULL },
375
GOptionContext *context = g_option_context_new (NULL);
376
g_option_context_add_group (context, gtk_get_option_group (TRUE));
377
g_option_context_add_main_entries (context, options, latexila_nls_package);
379
// TODO with valgrind there are a lot of memory leaks with this, can we do
381
gboolean tmp = g_option_context_parse (context, &argc, &argv, &error);
382
g_option_context_free (context);
385
print_error ("option parsing failed: %s\n", error->message);
386
g_error_free (error);
390
gtk_init_with_args (&argc, &argv, NULL, options, latexila_nls_package,
394
print_error ("%s", error->message);
395
g_error_free (error);
400
load_preferences (&latexila.prefs);
403
// make the close buttons in tabs smaller
404
// we use gtk_widget_set_name (widget, "my-close-button") to apply this
406
gtk_rc_parse_string (
407
"style \"my-button-style\"\n"
409
" GtkWidget::focus-padding = 0\n"
410
" GtkWidget::focus-line-width = 0\n"
414
"widget \"*.my-close-button\" style \"my-button-style\"");
419
/* menubar and toolbar */
420
GtkWidget *main_vbox = gtk_vbox_new (FALSE, 0);
421
gtk_container_add (GTK_CONTAINER (latexila.main_window), main_vbox);
423
// init_ui() will set log_toolbar so we can pass it to init_log_zone()
424
GtkWidget *log_toolbar;
426
init_ui (main_vbox, &log_toolbar);
429
* left: side pane (symbol tables and the file browser)
430
* right: the source view and the log zone
432
GtkWidget *main_hpaned = gtk_hpaned_new ();
433
latexila.main_hpaned = GTK_PANED (main_hpaned);
434
gtk_paned_set_position (GTK_PANED (main_hpaned),
435
latexila.prefs.main_hpaned_pos);
436
gtk_box_pack_start (GTK_BOX (main_vbox), main_hpaned, TRUE, TRUE, 0);
442
* top: source view, go to line, search and replace
445
GtkWidget *vpaned = gtk_vpaned_new ();
446
latexila.vpaned = GTK_PANED (vpaned);
447
gtk_paned_set_position (GTK_PANED (vpaned), latexila.prefs.vpaned_pos);
448
gtk_paned_add2 (GTK_PANED (main_hpaned), vpaned);
450
// vbox_source_view contains the source view, go to line, search and replace
451
GtkWidget *vbox_source_view = gtk_vbox_new (FALSE, 2);
452
gtk_paned_add1 (GTK_PANED (vpaned), vbox_source_view);
454
init_source_view (vbox_source_view);
455
init_go_to_line (vbox_source_view);
456
init_find (vbox_source_view);
457
init_replace (vbox_source_view);
461
// left: action history
463
GtkWidget *hpaned = gtk_hpaned_new ();
464
latexila.log_hpaned = GTK_PANED (hpaned);
465
gtk_paned_set_position (GTK_PANED (hpaned), latexila.prefs.log_hpaned_pos);
466
gtk_paned_add2 (GTK_PANED (vpaned), hpaned);
468
init_log_zone (latexila.log_hpaned, log_toolbar);
470
/* init various things */
471
init_statusbar (main_vbox);
473
latex_output_filter_init ();
475
/* show the window */
476
gtk_widget_show_all (GTK_WIDGET (latexila.main_window));
478
if (! latexila.prefs.show_side_pane)
479
gtk_widget_hide (latexila.side_pane);
481
if (! latexila.prefs.show_edit_toolbar)
482
gtk_widget_hide (latexila.edit_toolbar);
484
gtk_widget_hide (latexila.under_source_view.go_to_line);
485
gtk_widget_hide (latexila.under_source_view.find);
486
gtk_widget_hide (latexila.under_source_view.replace);
488
gtk_notebook_set_current_page (GTK_NOTEBOOK (latexila.side_pane),
489
latexila.prefs.side_pane_page);
491
/* reopen files on startup */
492
gchar ** list_opened_docs = (gchar **) latexila.prefs.list_opened_docs->pdata;
493
for (int i = 0 ; i < latexila.prefs.list_opened_docs->len ; i++)
495
if (latexila.prefs.reopen_files_on_startup)
496
open_new_document_without_uri (list_opened_docs[i]);
498
// in all cases we must free the string
499
g_free (list_opened_docs[i]);
501
g_ptr_array_free (latexila.prefs.list_opened_docs, TRUE);
502
latexila.prefs.list_opened_docs = g_ptr_array_new ();
504
// go to the first file
505
gtk_notebook_set_current_page (latexila.notebook, 0);
507
/* open documents given in arguments */
508
for (int i = 1 ; i < argc ; i++)
511
if (g_path_is_absolute (argv[i]))
512
path = g_strdup (argv[i]);
515
gchar *current_dir = g_get_current_dir ();
516
path = g_build_filename (current_dir, argv[i], NULL);
517
g_free (current_dir);
520
open_new_document_without_uri (path);
524
/* if --new-document option is used */
525
if (option_new_document)
528
/* timeout for saving files every X minutes */
529
if (latexila.prefs.auto_save)
530
latexila.auto_save_timeout = g_timeout_add_seconds (
531
60 * latexila.prefs.auto_save_interval,
532
(GSourceFunc) auto_save_files, NULL);
534
latexila.auto_save_timeout = 0;