1 #define _DEFAULT_SOURCE
2 /*
3 * This is free software; you can redistribute it and/or modify it under
4 * the terms of the GNU Library General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU Library General Public
14 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
15 */
16 #include <fcntl.h>
17 #define _POSIX_SOURCE /* feature test macro for signal functions */
18 #define _XOPEN_SOURCE /* feature test macro for popen */
19
20 /*
21 * This message is shown in a modal dialog when tilda starts and there is a problem parsing the configuration file.
22 * Such problems can occur for example if the config file contains a key-value pair that is unknown to tilda. This
23 * can be the case if the user manually modified the configuration file or if a newer version of tilda was run and
24 * which saved some settings that are not known by older versions of tilda.
25 */
26 #define TILDA_CONFIG_PARSE_ERROR \
27 "<b>A problem occurred while parsing the config file.</b>\n\n" \
28 "This can happen if the tilda config contains a setting that is unknown to tilda. " \
29 "Tilda will now start with the default configuration."
30
31 /*
32 * This message is shown in a modal dialog when tilda starts and there is a any other problem with the configuration
33 * file except a parse error.
34 */
35 #define TILDA_CONFIG_OTHER_ERROR \
36 "<b>An unexpected error occurred while parsing the config file.</b>\n\n" \
37 "The default configuration will be used instead. This error can occur if the configuration file is corrupted" \
38 "or otherwise unreadable. Tilda will now start with a default configuration."
39
40
41 #include <tilda-config.h>
42
43 #include "debug.h"
44 #include "tilda.h"
45 #include "configsys.h"
46 #include "tilda_window.h"
47 #include "key_grabber.h" /* for pull */
48 #include "wizard.h"
49 #include "xerror.h"
50 #include "tomboykeybinder.h"
51 #include "tilda-keybinding.h"
52 #include "tilda-cli-options.h"
53
54 #include <sys/ioctl.h>
55 #include <sys/stat.h>
56 #include <sys/file.h>
57 #include <errno.h>
58 #include <dirent.h>
59 #include <errno.h>
60 #include <fcntl.h>
61 #include <string.h>
62 #include <unistd.h>
63 #include <stdlib.h>
64 #include <gtk/gtk.h>
65 #include <glib-object.h>
66 #include <glib.h>
67 #include <glib/gi18n.h>
68 #include <locale.h>
69 #include <stdio.h>
70 #include <signal.h>
71 #include <pwd.h>
72
73 #include <X11/Xlib.h>
74 #include <X11/Xlibint.h>
75
76 #include <vte/vte.h>
77 #include <glib/gstdio.h>
78
79 /**
80 * If lock->pid is 0 then the file is not opened exclusively. Instead flock() must be used to obtain a lock.
81 * Otherwise an exclusive lock file is created for the process.
82 */
create_lock_file(struct lock_info * lock)83 static gchar *create_lock_file (struct lock_info *lock)
84 {
85 DEBUG_FUNCTION ("create_lock_file");
86 DEBUG_ASSERT (lock != NULL);
87 DEBUG_ASSERT (lock->instance >= 0);
88 DEBUG_ASSERT (lock->pid >= 0);
89
90 gint ret;
91 gchar *lock_file_full;
92 gchar *lock_dir = g_build_filename (g_get_user_cache_dir (), "tilda", "locks", NULL);
93 gchar *lock_file = g_strdup_printf ("lock_%d_%d", lock->pid, lock->instance);
94
95 /* Make the ~/.cache/tilda/locks directory */
96 ret = g_mkdir_with_parents (lock_dir, S_IRUSR | S_IWUSR | S_IXUSR);
97
98 if (ret == -1)
99 goto mkdir_fail;
100
101 /* Create the full path to the lock file */
102 lock_file_full = g_build_filename (lock_dir, lock_file, NULL);
103
104 /* Create the lock file */
105 if(lock->pid == 0) {
106 ret = g_open(lock_file_full, O_CREAT, S_IRUSR | S_IWUSR);
107 } else {
108 ret = g_open(lock_file_full, O_WRONLY | O_CREAT | O_EXCL, 0);
109 }
110
111 if (ret == -1)
112 goto creat_fail;
113
114 lock->file_descriptor = ret;
115
116 g_free (lock_file);
117 g_free (lock_dir);
118
119 return lock_file_full;
120
121 /* Free memory and return NULL */
122 creat_fail:
123 g_free (lock_file_full);
124 mkdir_fail:
125 g_free (lock_file);
126 g_free (lock_dir);
127
128 return NULL;
129 }
130
131 /**
132 * Check if a filename corresponds to a valid lockfile. Note that this
133 * routine does NOT check whether it is a stale lock, however. This
134 * will return the lock file's corresponding pid, if it is a valid lock.
135 *
136 * @param filename the filename to check
137 * @return a new struct lock_info
138 *
139 * Success: struct lock_info will be filled in and non-NULL
140 * Failure: return NULL
141 */
islockfile(const gchar * filename)142 static struct lock_info *islockfile (const gchar *filename)
143 {
144 DEBUG_FUNCTION ("islockfile");
145 DEBUG_ASSERT (filename != NULL);
146
147 struct lock_info *lock;
148
149 lock = g_malloc (sizeof (struct lock_info));
150
151 if (lock == NULL)
152 return NULL;
153
154 #ifdef USE_GLIB_2_14
155 GRegex *regex;
156 GMatchInfo *match_info;
157 gboolean matched;
158 gchar *temp;
159
160 regex = g_regex_new ("^lock_(\d+)_(\d+)$", 0, 0, NULL);
161 matched = g_regex_match (regex, filename, 0, &match_info);
162
163 if (!matched)
164 {
165 g_free (lock);
166 lock = NULL;
167 goto nomatch;
168 }
169
170 /* Get the lock pid */
171 temp = g_match_info_fetch (match_info, 0);
172 lock->pid = atoi (temp);
173 g_free (temp);
174
175 /* Get the configuration number */
176 temp = g_match_info_fetch (match_info, 1);
177 lock->instance = atoi (temp);
178 g_free (temp);
179
180 nomatch:
181 if (match_info)
182 g_match_info_free (match_info);
183
184 g_regex_unref (regex);
185
186 return matched;
187
188 #else /* Glib version is <2.14 */
189
190 gboolean matches = g_str_has_prefix (filename, "lock_");
191 gboolean islock = FALSE;
192 gchar *pid_s, *instance_s;
193
194 if (matches) /* we are prefixed with "lock_" and are probably a lock */
195 {
196 pid_s = strstr (filename, "_");
197
198 if (pid_s) /* we have a valid pid */
199 {
200 /* Advance the pointer past the underscore */
201 pid_s++;
202
203 lock->pid = atoi (pid_s);
204 instance_s = strstr (pid_s, "_");
205
206 if (lock->pid > 0 && instance_s)
207 {
208 /* Advance the pointer past the underscore */
209 instance_s++;
210
211 /* Extract the instance number and store it */
212 lock->instance = atoi (instance_s);
213
214 /* we parsed everything, so yes, we were a lock */
215 islock = TRUE;
216 }
217 }
218 }
219
220 if (!islock)
221 {
222 g_free (lock);
223 lock = NULL;
224 }
225
226 return lock;
227 #endif
228 }
229
230 /**
231 * Gets a list of the pids in
232 */
getPids()233 static GSList *getPids() {
234 GSList *pids = NULL;
235 FILE *ps_output;
236 const gchar ps_command[] = "pgrep tilda";
237 gchar buf[16]; /* Really shouldn't need more than 6 */
238
239 if ((ps_output = popen (ps_command, "r")) == NULL) {
240 g_printerr (_("Unable to run command: `%s'\n"), ps_command);
241 return NULL;
242 }
243
244 /* The popen() succeeded, get all of the pids */
245 while (fgets (buf, sizeof(buf), ps_output) != NULL)
246 pids = g_slist_append (pids, GINT_TO_POINTER (atoi (buf)));
247
248 /* We've read all of the pids, exit */
249 pclose (ps_output);
250 return pids;
251 }
252
253 /**
254 * Remove stale lock files from the ~/.tilda/locks/ directory.
255 *
256 * Success: returns 0
257 * Failure: returns non-zero
258 */
remove_stale_lock_files()259 static gint remove_stale_lock_files ()
260 {
261 DEBUG_FUNCTION ("remove_stale_lock_files");
262
263 GSList *pids = getPids();
264 if(pids == NULL) {
265 return -1;
266 }
267
268 struct lock_info *lock;
269 gchar *lock_dir = g_build_filename (g_get_user_cache_dir (), "tilda", "locks", NULL);
270 gchar *remove_file;
271 gchar *filename;
272 GDir *dir;
273
274 /* if the lock dir does not exist then there are no stale lock files to remove. */
275 if (!g_file_test (lock_dir, G_FILE_TEST_EXISTS)) {
276 g_free (lock_dir);
277 return 0;
278 }
279
280 /* Open the lock directory for reading */
281 dir = g_dir_open (lock_dir, 0, NULL);
282
283 if (dir == NULL)
284 {
285 g_printerr (_("Unable to open lock directory: %s\n"), lock_dir);
286 g_free (lock_dir);
287 return -2;
288 }
289
290 /* For each possible lock file, check if it is a lock, and see if
291 * it matches one of the running tildas */
292 while ((filename = (gchar*) g_dir_read_name (dir)) != NULL)
293 {
294 lock = islockfile (filename);
295
296 if (lock && (g_slist_find (pids, GINT_TO_POINTER (lock->pid)) == NULL))
297 {
298 /* We have found a stale element */
299 remove_file = g_build_filename (lock_dir, filename, NULL);
300 g_remove (remove_file);
301 g_free (remove_file);
302 }
303
304 if (lock)
305 g_free (lock);
306 }
307
308 g_dir_close (dir);
309 g_free (lock_dir);
310 g_slist_free(pids);
311
312 return 0;
313 }
314
315 /**
316 * Set values in the config from command-line parameters
317 *
318 * @param cli_options pointer to a struct containing command-line options
319 */
setup_config_from_cli_options(tilda_cli_options * cli_options)320 static void setup_config_from_cli_options(tilda_cli_options *cli_options)
321 {
322 if (cli_options->background_color != NULL
323 && cli_options->background_color != config_getstr ("background_color")) {
324 config_setstr ("background_color", cli_options->background_color);
325
326 GdkRGBA col;
327 if (gdk_rgba_parse (&col, cli_options->background_color))
328 {
329 config_setint("back_red", GUINT16_FROM_FLOAT (col.red));
330 config_setint("back_green", GUINT16_FROM_FLOAT (col.green));
331 config_setint("back_blue", GUINT16_FROM_FLOAT (col.blue));
332 }
333
334 g_free(cli_options->background_color);
335 }
336 if (cli_options->command != NULL
337 && cli_options->command != config_getstr ("command"))
338 {
339 config_setbool ("run_command", TRUE);
340 config_setstr ("command", cli_options->command);
341 g_free(cli_options->command);
342 }
343 if (cli_options->font != NULL
344 && cli_options->font != config_getstr ("font")) {
345 config_setstr ("font", cli_options->font);
346 g_free(cli_options->font);
347 }
348
349 if (cli_options->back_alpha != 0
350 && cli_options->back_alpha != config_getint ("back_alpha"))
351 {
352 config_setbool ("enable_transparency", ~cli_options->back_alpha & 0xffff);
353 config_setint ("back_alpha", cli_options->back_alpha);
354 }
355
356 if (cli_options->working_dir != NULL
357 && cli_options->working_dir != config_getstr ("working_dir")) {
358 config_setstr ("working_dir", cli_options->working_dir);
359 g_free(cli_options->working_dir);
360 }
361
362 if (cli_options->lines != 0
363 && cli_options->lines != config_getint ("lines"))
364 config_setint ("lines", cli_options->lines);
365 if (cli_options->x_pos != 0
366 && cli_options->x_pos != config_getint ("x_pos"))
367 config_setint ("x_pos", cli_options->x_pos);
368 if (cli_options->y_pos != 0
369 && cli_options->y_pos != config_getint ("y_pos"))
370 config_setint ("y_pos", cli_options->y_pos);
371
372 if (cli_options->hidden != FALSE
373 && cli_options->hidden != config_getbool ("hidden"))
374 config_setbool ("hidden", cli_options->hidden);
375 if (cli_options->scrollbar != FALSE
376 && cli_options->scrollbar != config_getbool ("scrollbar"))
377 config_setbool ("scrollbar", cli_options->scrollbar);
378 }
379
380 /**
381 * Get a pointer to the config file name for this instance.
382 *
383 * NOTE: you MUST call free() on the returned value!!!
384 *
385 * @param tw the tilda_window structure corresponding to this instance
386 * @return a pointer to a string representation of the config file's name
387 */
get_config_file_name(gint instance)388 static gchar *get_config_file_name (gint instance)
389 {
390 DEBUG_FUNCTION ("get_config_file_name");
391 DEBUG_ASSERT (instance >= 0);
392
393 gchar *config_dir = g_build_filename (g_get_user_config_dir (), "tilda", NULL);
394
395 /* Make the ~/.config/tilda directory */
396 if (!g_file_test (config_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
397 g_print (_("Creating directory:'%s'\n"), config_dir);
398 g_mkdir_with_parents (config_dir, S_IRUSR | S_IWUSR | S_IXUSR);
399 }
400
401 gchar *config_file_prefix = g_build_filename (config_dir, "config_", NULL);
402 gchar *config_file;
403
404 config_file = g_strdup_printf ("%s%d", config_file_prefix, instance);
405 g_free (config_file_prefix);
406
407 /* resolve possible symlink pointing to a different location. */
408 gchar * resolved_config_file = realpath (config_file, NULL);
409
410 if (g_strcmp0 (config_file, resolved_config_file) != 0) {
411 g_debug ("Config file at '%s' points to '%s'", config_file, resolved_config_file);
412 }
413
414 if (resolved_config_file != NULL) {
415 g_free (config_file);
416 /* resolved_config_file must be freed with free(3) so we duplicate the
417 * string to ensure that what ever we return from this function can be
418 * freed with g_free(). */
419 config_file = g_strdup (resolved_config_file);
420 free (resolved_config_file);
421 }
422
423 return config_file;
424 }
425
_cmp_locks(gconstpointer a,gconstpointer b,gpointer userdata)426 static gint _cmp_locks(gconstpointer a, gconstpointer b, gpointer userdata) {
427 return GPOINTER_TO_INT (a) - GPOINTER_TO_INT (b);
428 }
429
430 /**
431 * get_instance_number ()
432 *
433 * Gets the next available tilda instance number. This will always pick the
434 * lowest non-running tilda available.
435 *
436 * Success: return next available instance number (>=0)
437 * Failure: return 0
438 */
get_instance_number()439 static gint get_instance_number ()
440 {
441 DEBUG_FUNCTION ("get_instance_number");
442
443 gchar *name;
444
445 GSequence *seq;
446 GSequenceIter *iter;
447 gint lowest_lock_instance = 0;
448 gint current_lock_instance;
449
450 GDir *dir;
451 struct lock_info *lock;
452 gchar *lock_dir = g_build_filename (g_get_user_cache_dir (), "tilda", "locks", NULL);
453
454 /* Open the lock directory */
455 dir = g_dir_open (lock_dir, 0, NULL);
456
457 /* Check for failure to open */
458 if (dir == NULL)
459 {
460 g_printerr (_("Unable to open lock directory: %s\n"), lock_dir);
461 g_free (lock_dir);
462 return 0;
463 }
464
465 /* Look through every file in the lock directory, and see if it is a lock file.
466 * If it is a lock file, insert it in a sorted sequence. */
467 seq = g_sequence_new(NULL);
468 while ((name = (gchar*)g_dir_read_name (dir)) != NULL)
469 {
470 lock = islockfile (name);
471
472 if (lock != NULL)
473 {
474 g_sequence_insert_sorted(seq, GINT_TO_POINTER(lock->instance), _cmp_locks, NULL);
475 g_free (lock);
476 }
477 }
478
479 g_dir_close (dir);
480 g_free (lock_dir);
481
482 /* We iterate the sorted sequence of lock instances to find the first (lowest) number *not* taken. */
483 for (iter = g_sequence_get_begin_iter(seq); !g_sequence_iter_is_end(iter); iter = g_sequence_iter_next(iter)) {
484 current_lock_instance = GPOINTER_TO_INT(g_sequence_get(iter));
485 if (lowest_lock_instance < current_lock_instance)
486 break;
487 else
488 lowest_lock_instance = current_lock_instance + 1;
489 }
490
491 g_sequence_free(seq);
492
493 return lowest_lock_instance;
494 }
495
termination_handler(G_GNUC_UNUSED gint signum)496 static void termination_handler (G_GNUC_UNUSED gint signum) {
497 DEBUG_FUNCTION ("termination_handler");
498 gtk_main_quit ();
499 }
500
501 /*
502 * This is to do the migration of config files from ~/.tilda to the
503 * XDG_*_HOME folders
504 */
migrate_config_files(char * old_config_path)505 static void migrate_config_files(char *old_config_path) {
506 gchar* old_lock_dir = g_build_filename(old_config_path, "locks", NULL);
507 gchar* new_lock_dir = g_build_filename(g_get_user_cache_dir (), "tilda", "locks", NULL);
508 gchar* new_config_dir = g_build_filename(g_get_user_config_dir (), "tilda", NULL);
509
510 if(!g_file_test(new_lock_dir, G_FILE_TEST_IS_DIR)) {
511 g_mkdir_with_parents(new_lock_dir, 0700);
512 }
513
514 //we basically need to move the files from old_config_path to config and cache
515 g_rename(old_lock_dir, new_lock_dir);
516 //we must move the config files after we have moved the locks directory, otherwise it gets moved aswell
517 g_rename(old_config_path, new_config_dir);
518 g_free(old_lock_dir);
519 g_free(new_lock_dir);
520 g_free(new_config_dir);
521 }
522
load_application_css()523 static void load_application_css () {
524 GtkCssProvider *provider;
525 const gchar* style;
526 GError *error;
527
528 provider = gtk_css_provider_new ();
529
530 gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
531 GTK_STYLE_PROVIDER (provider),
532 GTK_STYLE_PROVIDER_PRIORITY_USER);
533
534 style = "#search{background:#fff;}";
535 error = NULL;
536 gtk_css_provider_load_from_data (provider, style, -1, &error);
537
538 if (error) {
539 g_print ("Error %s\n", error->message);
540 g_error_free (error);
541 }
542 }
543
load_custom_css_file()544 static void load_custom_css_file () {
545 GtkCssProvider *provider;
546 GFile *file;
547 GError *error;
548 gchar *filename;
549
550 filename = g_build_filename (g_get_user_config_dir (),
551 "tilda", "style.css", NULL);
552
553 if (!g_file_test (filename, G_FILE_TEST_EXISTS))
554 return;
555
556 g_print (_("Found style.css in the user config directory, "
557 "applying user css style.\n"));
558
559 provider = gtk_css_provider_new ();
560
561 gtk_style_context_add_provider_for_screen (gdk_screen_get_default(),
562 GTK_STYLE_PROVIDER(provider),
563 GTK_STYLE_PROVIDER_PRIORITY_USER);
564
565
566 file = g_file_new_for_path (filename);
567 error = NULL;
568 gtk_css_provider_load_from_file (provider, file, &error);
569
570 if (error) {
571 g_print ("Error: %s", error->message);
572 g_error_free (error);
573 }
574
575 g_object_unref (file);
576 g_free (filename);
577 }
578
main(int argc,char * argv[])579 int main (int argc, char *argv[])
580 {
581 #ifdef DEBUG
582 /**
583 * This enables the tilda log domain while we are in debug mode. This
584 * is for convenience such that we do not need to start tilda with
585 * 'G_MESSAGES_DEBUG=tilda ./tilda' each time we start tilda.
586 */
587
588 g_setenv ("G_MESSAGES_DEBUG", "tilda", FALSE);
589 #endif
590
591 DEBUG_FUNCTION_MESSAGE ("main", "Using libvte version: %i.%i.%i",
592 VTE_MAJOR_VERSION, VTE_MINOR_VERSION, VTE_MICRO_VERSION);
593
594 /* Set supported backend to X11 */
595 gdk_set_allowed_backends ("x11");
596
597 tilda_window tw;
598 /* NULL set the tw pointers so we can get a clean exit on initialization failure */
599 memset(&tw, 0, sizeof(tilda_window));
600
601 struct sigaction sa;
602 struct lock_info lock;
603 gboolean need_wizard = FALSE;
604 gchar *config_file, *lock_file, *old_config_path;
605
606 /*
607 * Migration code to move old files to new XDG folders
608 */
609 old_config_path = g_build_filename(g_get_home_dir (), ".tilda", NULL);
610 if (g_file_test(old_config_path, G_FILE_TEST_IS_DIR)) {
611 g_print (_("Migrating old config path to XDG folders\n"));
612 migrate_config_files(old_config_path);
613 g_free(old_config_path);
614 }
615
616 /* Remove stale lock files */
617 remove_stale_lock_files ();
618
619 /* The global lock file is used to synchronize the start up of multiple simultaneously starting tilda processes.
620 * The processes will synchronize on a lock file named lock_0_0, such that the part of determining the instance
621 * number and creating the per process lock file (lock_<pid>_<instance>) is atomic. Without this it could
622 * happen, that a second tilda instance was trying to determine its instance number before the first instance
623 * had finished creating its lock file, this resulted in two processes with the same instance number and could lead
624 * to corruption of the config file.
625 * In order to test if this works the following shell command can be used: "tilda & tilda && fg", which causes
626 * two tilda processes to be started simultaneously. See:
627 *
628 * http://stackoverflow.com/questions/3004811/how-do-you-run-multiple-programs-from-a-bash-script
629 */
630 struct lock_info global_lock;
631 global_lock.instance = 0;
632 global_lock.pid = 0;
633 gchar *global_lock_file = NULL;
634
635 global_lock_file = create_lock_file(&global_lock);
636 if(global_lock_file == NULL) {
637 perror("Error creating global lock file");
638 return EXIT_FAILURE;
639 }
640 flock(global_lock.file_descriptor, LOCK_EX);
641
642 /* Start of atomic section. */
643 lock.pid = getpid ();
644 lock.instance = get_instance_number ();
645 lock_file = create_lock_file (&lock);
646
647 /* End of atomic section */
648
649 flock(global_lock.file_descriptor, LOCK_UN);
650 g_remove (global_lock_file);
651 close(lock.file_descriptor);
652 g_free(global_lock_file);
653
654
655 #if ENABLE_NLS
656 /* Gettext Initialization */
657 char* locale = setlocale (LC_ALL, "");
658 if(!locale) {
659 g_warning ("Could not setup locale.");
660 }
661 bindtextdomain (PACKAGE, LOCALEDIR);
662 bind_textdomain_codeset (PACKAGE, "UTF-8");
663 textdomain (PACKAGE);
664 #endif
665
666 config_file = NULL;
667
668 /* Parse the command line */
669 tilda_cli_options *cli_options = tilda_cli_options_new ();
670 need_wizard = tilda_cli_options_parse_options (cli_options, argc, argv, &config_file);
671
672 if (config_file) { // if there was a config file specified via cli
673 if (!g_file_test (config_file, G_FILE_TEST_EXISTS)) {
674 g_printerr (_("Specified config file '%s' does not exist. Reverting to default path.\n"),
675 config_file);
676 config_file = get_config_file_name (lock.instance);
677 }
678 } else { // if not, we look for the defaut config file
679 config_file = get_config_file_name (lock.instance);
680 }
681
682 /* Initialize GTK. Any code that interacts with GTK (e.g. creating a widget)
683 * should come after this call. Gtk initialization should happen before we
684 * initialize the config file. */
685 gtk_init (&argc, &argv);
686
687 /* Start up the configuration system and load from file */
688 gint config_init_result = config_init (config_file);
689
690 /* Set up possible overridden config options */
691 setup_config_from_cli_options(cli_options);
692 g_free(cli_options);
693
694 /* We're about to startup X, so set the error handler. */
695 XSetErrorHandler (xerror_handler);
696
697 /* This section shows a modal dialog to notify the user that something has gone wrong when loading the config.
698 * Earlier version only used to print a message to stderr, but since tilda is usually not started from a
699 * console this message would have been lost and a message dialog is much more user friedly.
700 */
701 GtkWidget *dialog = NULL;
702 if(config_init_result == 1) {
703 dialog = gtk_message_dialog_new_with_markup(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
704 TILDA_CONFIG_PARSE_ERROR);
705 } else if (config_init_result != 0) {
706 dialog = gtk_message_dialog_new_with_markup(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
707 TILDA_CONFIG_OTHER_ERROR);
708 }
709
710 if(dialog) {
711 g_message("Running Dialog");
712 gtk_dialog_run(GTK_DIALOG(dialog));
713 gtk_widget_destroy(dialog);
714 }
715
716 load_application_css ();
717 load_custom_css_file ();
718
719 /* create new tilda_window */
720 gboolean success = tilda_window_init (config_file, lock.instance, &tw);
721
722 if(!success) {
723 fprintf(stderr, "tilda.c: initialization failed\n");
724 goto initialization_failed;
725 }
726
727 /* Adding widget title for CSS selection */
728 gtk_widget_set_name (GTK_WIDGET(tw.window), "Main");
729
730 /* Initialize and set up the keybinding to toggle tilda's visibility. */
731 tomboy_keybinder_init ();
732
733 /* Hook up signal handlers */
734 sa.sa_handler = termination_handler;
735 sigemptyset (&sa.sa_mask);
736 sa.sa_flags = 0;
737
738 sigaction (SIGINT, &sa, NULL);
739 sigaction (SIGQUIT, &sa, NULL);
740 sigaction (SIGABRT, &sa, NULL);
741 sigaction (SIGTERM, &sa, NULL);
742 sigaction (SIGKILL, &sa, NULL);
743
744 /* If the config file doesn't exist open up the wizard */
745 if (access (tw.config_file, R_OK) == -1)
746 {
747 /* We probably need a default key, too ... */
748 gchar *default_key = g_strdup_printf ("F%d", tw.instance+1);
749 config_setstr ("key", default_key);
750 g_free (default_key);
751
752 need_wizard = TRUE;
753 }
754
755 /* Show the wizard if we need to.
756 *
757 * Note that the key will be bound upon exiting the wizard */
758 if (need_wizard) {
759 g_print ("Starting the wizard to configure tilda options.\n");
760 wizard (&tw);
761 } else {
762 gint ret = tilda_keygrabber_bind (config_getstr ("key"), &tw);
763
764 if (!ret)
765 {
766 /* The key was unbindable, so we need to show the wizard */
767 const char *message = _("The keybinding you chose for \"Pull Down Terminal\" is invalid. Please choose another.");
768
769 tilda_keybinding_show_invalid_keybinding_dialog (NULL,
770 message);
771 wizard (&tw);
772 }
773 }
774
775 pull (&tw, config_getbool ("hidden") ? PULL_UP : PULL_DOWN, FALSE);
776
777 g_print ("Tilda has started. Press %s to pull down the window.\n",
778 config_getstr ("key"));
779 /* Whew! We're finally all set up and ready to run GTK ... */
780 gtk_main();
781
782 initialization_failed:
783 tilda_window_free(&tw);
784
785 /* Ok, we're at the end of our run. Time to clean up ... */
786 config_free (config_file);
787 g_remove (lock_file);
788 close(lock.file_descriptor);
789 g_free (lock_file);
790 g_free (config_file);
791 return 0;
792 }
793