Move miscellaneous functions to their own files (new misc.[ch]).
[geeqie.git] / src / main.c
1 /*
2  * Geeqie
3  * (C) 2006 John Ellis
4  * Copyright (C) 2008 The Geeqie Team
5  *
6  * Author: John Ellis
7  *
8  * This software is released under the GNU General Public License (GNU GPL).
9  * Please read the included file COPYING for more information.
10  * This software comes with no warranty of any kind, use at your own risk!
11  */
12
13
14 #include "main.h"
15
16 #include "cache.h"
17 #include "collect.h"
18 #include "collect-io.h"
19 #include "filedata.h"
20 #include "filefilter.h"
21 #include "history_list.h"
22 #include "image-overlay.h"
23 #include "layout.h"
24 #include "layout_image.h"
25 #include "options.h"
26 #include "remote.h"
27 #include "similar.h"
28 #include "ui_fileops.h"
29 #include "ui_utildlg.h"
30 #include "cache_maint.h"
31 #include "thumb.h"
32
33 #include <gdk/gdkkeysyms.h> /* for keyboard values */
34
35
36 #include <math.h>
37 #ifdef G_OS_UNIX
38 #include <pwd.h>
39 #endif
40
41
42 static RemoteConnection *remote_connection = NULL;
43
44
45 /*
46  *-----------------------------------------------------------------------------
47  * keyboard functions
48  *-----------------------------------------------------------------------------
49  */
50
51 void keyboard_scroll_calc(gint *x, gint *y, GdkEventKey *event)
52 {
53         static gint delta = 0;
54         static guint32 time_old = 0;
55         static guint keyval_old = 0;
56
57         if (event->state & GDK_CONTROL_MASK)
58                 {
59                 if (*x < 0) *x = G_MININT / 2;
60                 if (*x > 0) *x = G_MAXINT / 2;
61                 if (*y < 0) *y = G_MININT / 2;
62                 if (*y > 0) *y = G_MAXINT / 2;
63
64                 return;
65                 }
66
67         if (options->progressive_key_scrolling)
68                 {
69                 guint32 time_diff;
70
71                 time_diff = event->time - time_old;
72
73                 /* key pressed within 125ms ? (1/8 second) */
74                 if (time_diff > 125 || event->keyval != keyval_old) delta = 0;
75
76                 time_old = event->time;
77                 keyval_old = event->keyval;
78
79                 delta += 2;
80                 }
81         else
82                 {
83                 delta = 8;
84                 }
85
86         *x = *x * delta;
87         *y = *y * delta;
88 }
89
90
91
92 /*
93  *-----------------------------------------------------------------------------
94  * command line parser (private) hehe, who needs popt anyway?
95  *-----------------------------------------------------------------------------
96  */
97
98 static gint startup_blank = FALSE;
99 static gint startup_full_screen = FALSE;
100 static gint startup_in_slideshow = FALSE;
101 static gint startup_command_line_collection = FALSE;
102
103
104 static void parse_command_line_add_file(const gchar *file_path, gchar **path, gchar **file,
105                                         GList **list, GList **collection_list)
106 {
107         gchar *path_parsed;
108
109         path_parsed = g_strdup(file_path);
110         parse_out_relatives(path_parsed);
111
112         if (file_extension_match(path_parsed, GQ_COLLECTION_EXT))
113                 {
114                 *collection_list = g_list_append(*collection_list, path_parsed);
115                 }
116         else
117                 {
118                 if (!*path) *path = remove_level_from_path(path_parsed);
119                 if (!*file) *file = g_strdup(path_parsed);
120                 *list = g_list_prepend(*list, file_data_new_simple(path_parsed));
121                 }
122 }
123
124 static void parse_command_line_add_dir(const gchar *dir, gchar **path, gchar **file,
125                                        GList **list)
126 {
127         GList *files;
128         gchar *path_parsed;
129         FileData *dir_fd;
130
131         path_parsed = g_strdup(dir);
132         parse_out_relatives(path_parsed);
133         dir_fd = file_data_new_simple(path_parsed);
134         
135
136         if (filelist_read(dir_fd, &files, NULL))
137                 {
138                 GList *work;
139
140                 files = filelist_filter(files, FALSE);
141                 files = filelist_sort_path(files);
142
143                 work = files;
144                 while (work)
145                         {
146                         FileData *fd = work->data;
147                         if (!*path) *path = remove_level_from_path(fd->path);
148                         if (!*file) *file = g_strdup(fd->path);
149                         *list = g_list_prepend(*list, fd);
150
151                         work = work->next;
152                         }
153
154                 g_list_free(files);
155                 }
156
157         g_free(path_parsed);
158         file_data_unref(dir_fd);
159 }
160
161 static void parse_command_line_process_dir(const gchar *dir, gchar **path, gchar **file,
162                                            GList **list, gchar **first_dir)
163 {
164
165         if (!*list && !*first_dir)
166                 {
167                 *first_dir = g_strdup(dir);
168                 }
169         else
170                 {
171                 if (*first_dir)
172                         {
173                         parse_command_line_add_dir(*first_dir, path, file, list);
174                         g_free(*first_dir);
175                         *first_dir = NULL;
176                         }
177                 parse_command_line_add_dir(dir, path, file, list);
178                 }
179 }
180
181 static void parse_command_line_process_file(const gchar *file_path, gchar **path, gchar **file,
182                                             GList **list, GList **collection_list, gchar **first_dir)
183 {
184
185         if (*first_dir)
186                 {
187                 parse_command_line_add_dir(*first_dir, path, file, list);
188                 g_free(*first_dir);
189                 *first_dir = NULL;
190                 }
191         parse_command_line_add_file(file_path, path, file, list, collection_list);
192 }
193
194 static void parse_command_line(gint argc, gchar *argv[], gchar **path, gchar **file,
195                                GList **cmd_list, GList **collection_list,
196                                gchar **geometry)
197 {
198         GList *list = NULL;
199         GList *remote_list = NULL;
200         GList *remote_errors = NULL;
201         gint remote_do = FALSE;
202         gchar *first_dir = NULL;
203
204         if (argc > 1)
205                 {
206                 gint i;
207                 gchar *base_dir = get_current_dir();
208                 i = 1;
209                 while (i < argc)
210                         {
211                         const gchar *cmd_line = argv[i];
212                         gchar *cmd_all = g_build_filename(base_dir, cmd_line, NULL);
213
214                         if (cmd_line[0] == G_DIR_SEPARATOR && isdir(cmd_line))
215                                 {
216                                 parse_command_line_process_dir(cmd_line, path, file, &list, &first_dir);
217                                 }
218                         else if (isdir(cmd_all))
219                                 {
220                                 parse_command_line_process_dir(cmd_all, path, file, &list, &first_dir);
221                                 }
222                         else if (cmd_line[0] == G_DIR_SEPARATOR && isfile(cmd_line))
223                                 {
224                                 parse_command_line_process_file(cmd_line, path, file,
225                                                                 &list, collection_list, &first_dir);
226                                 }
227                         else if (isfile(cmd_all))
228                                 {
229                                 parse_command_line_process_file(cmd_all, path, file,
230                                                                 &list, collection_list, &first_dir);
231                                 }
232                         else if (strncmp(cmd_line, "--debug", 7) == 0 && (cmd_line[7] == '\0' || cmd_line[7] == '='))
233                                 {
234                                 /* do nothing but do not produce warnings */
235                                 }
236                         else if (strcmp(cmd_line, "+t") == 0 ||
237                                  strcmp(cmd_line, "--with-tools") == 0)
238                                 {
239                                 options->layout.tools_float = FALSE;
240                                 options->layout.tools_hidden = FALSE;
241
242                                 remote_list = g_list_append(remote_list, "+t");
243                                 }
244                         else if (strcmp(cmd_line, "-t") == 0 ||
245                                  strcmp(cmd_line, "--without-tools") == 0)
246                                 {
247                                 options->layout.tools_hidden = TRUE;
248
249                                 remote_list = g_list_append(remote_list, "-t");
250                                 }
251                         else if (strcmp(cmd_line, "-f") == 0 ||
252                                  strcmp(cmd_line, "--fullscreen") == 0)
253                                 {
254                                 startup_full_screen = TRUE;
255                                 }
256                         else if (strcmp(cmd_line, "-s") == 0 ||
257                                  strcmp(cmd_line, "--slideshow") == 0)
258                                 {
259                                 startup_in_slideshow = TRUE;
260                                 }
261                         else if (strcmp(cmd_line, "-l") == 0 ||
262                                  strcmp(cmd_line, "--list") == 0)
263                                 {
264                                 startup_command_line_collection = TRUE;
265                                 }
266                         else if (strncmp(cmd_line, "--geometry=", 11) == 0)
267                                 {
268                                 if (!*geometry) *geometry = g_strdup(cmd_line + 11);
269                                 }
270                         else if (strcmp(cmd_line, "-r") == 0 ||
271                                  strcmp(cmd_line, "--remote") == 0)
272                                 {
273                                 if (!remote_do)
274                                         {
275                                         remote_do = TRUE;
276                                         remote_list = remote_build_list(remote_list, argc - i, &argv[i], &remote_errors);
277                                         }
278                                 }
279                         else if (strcmp(cmd_line, "-rh") == 0 ||
280                                  strcmp(cmd_line, "--remote-help") == 0)
281                                 {
282                                 remote_help();
283                                 exit(0);
284                                 }
285                         else if (strcmp(cmd_line, "--blank") == 0)
286                                 {
287                                 startup_blank = TRUE;
288                                 }
289                         else if (strcmp(cmd_line, "-v") == 0 ||
290                                  strcmp(cmd_line, "--version") == 0)
291                                 {
292                                 printf_term("%s %s\n", GQ_APPNAME, VERSION);
293                                 exit(0);
294                                 }
295                         else if (strcmp(cmd_line, "--alternate") == 0)
296                                 {
297                                 /* enable faster experimental algorithm */
298                                 log_printf("Alternate similarity algorithm enabled\n");
299                                 image_sim_alternate_set(TRUE);
300                                 }
301                         else if (strcmp(cmd_line, "-h") == 0 ||
302                                  strcmp(cmd_line, "--help") == 0)
303                                 {
304                                 printf_term("%s %s\n", GQ_APPNAME, VERSION);
305                                 printf_term(_("Usage: %s [options] [path]\n\n"), GQ_APPNAME_LC);
306                                 print_term(_("valid options are:\n"));
307                                 print_term(_("  +t, --with-tools           force show of tools\n"));
308                                 print_term(_("  -t, --without-tools        force hide of tools\n"));
309                                 print_term(_("  -f, --fullscreen           start in full screen mode\n"));
310                                 print_term(_("  -s, --slideshow            start in slideshow mode\n"));
311                                 print_term(_("  -l, --list                 open collection window for command line\n"));
312                                 print_term(_("      --geometry=GEOMETRY    set main window location\n"));
313                                 print_term(_("  -r, --remote               send following commands to open window\n"));
314                                 print_term(_("  -rh,--remote-help          print remote command list\n"));
315 #ifdef DEBUG
316                                 print_term(_("  --debug[=level]            turn on debug output\n"));
317 #endif
318                                 print_term(_("  -v, --version              print version info\n"));
319                                 print_term(_("  -h, --help                 show this message\n\n"));
320
321 #if 0
322                                 /* these options are not officially supported!
323                                  * only for testing new features, no need to translate them */
324                                 print_term(  "  --alternate                use alternate similarity algorithm\n");
325 #endif
326
327                                 exit(0);
328                                 }
329                         else if (!remote_do)
330                                 {
331                                 printf_term(_("invalid or ignored: %s\nUse --help for options\n"), cmd_line);
332                                 }
333
334                         g_free(cmd_all);
335                         i++;
336                         }
337                 g_free(base_dir);
338                 parse_out_relatives(*path);
339                 parse_out_relatives(*file);
340                 }
341
342         list = g_list_reverse(list);
343
344         if (!*path && first_dir)
345                 {
346                 *path = first_dir;
347                 first_dir = NULL;
348
349                 parse_out_relatives(*path);
350                 }
351         g_free(first_dir);
352
353         if (remote_do)
354                 {
355                 if (remote_errors)
356                         {
357                         GList *work = remote_errors;
358                         
359                         printf_term(_("Invalid or ignored remote options: "));
360                         while (work)
361                                 {
362                                 gchar *opt = work->data;
363                                                 
364                                 printf_term("%s%s", (work == remote_errors) ? "" : ", ", opt);
365                                 work = work->next;
366                                 }
367
368                         printf_term(_("\nUse --remote-help for valid remote options.\n"));
369                         }
370
371                 remote_control(argv[0], remote_list, *path, list, *collection_list);
372                 }
373         g_list_free(remote_list);
374
375         if (list && list->next)
376                 {
377                 *cmd_list = list;
378                 }
379         else
380                 {
381                 filelist_free(list);
382                 *cmd_list = NULL;
383                 }
384 }
385
386 static void parse_command_line_for_debug_option(gint argc, gchar *argv[])
387 {
388 #ifdef DEBUG
389         const gchar *debug_option = "--debug";
390         gint len = strlen(debug_option);
391
392         if (argc > 1)
393                 {
394                 gint i;
395
396                 for (i = 1; i < argc; i++)
397                         {
398                         const gchar *cmd_line = argv[i];
399                         if (strncmp(cmd_line, debug_option, len) == 0)
400                                 {
401                                 gint cmd_line_len = strlen(cmd_line);
402
403                                 /* we now increment the debug state for verbosity */
404                                 if (cmd_line_len == len)
405                                         debug_level_add(1);
406                                 else if (cmd_line[len] == '=' && g_ascii_isdigit(cmd_line[len+1]))
407                                         {
408                                         gint n = atoi(cmd_line + len + 1);
409                                         if (n < 0) n = 1;
410                                         debug_level_add(n);
411                                         }
412                                 }
413                         }
414                 }
415
416         DEBUG_1("debugging output enabled (level %d)", get_debug_level());
417 #endif
418 }
419
420 /*
421  *-----------------------------------------------------------------------------
422  * startup, init, and exit
423  *-----------------------------------------------------------------------------
424  */
425
426 #define RC_HISTORY_NAME "history"
427
428 static void keys_load(void)
429 {
430         gchar *path;
431
432         path = g_build_filename(homedir(), GQ_RC_DIR, RC_HISTORY_NAME, NULL);
433         history_list_load(path);
434         g_free(path);
435 }
436
437 static void keys_save(void)
438 {
439         gchar *path;
440
441         path = g_build_filename(homedir(), GQ_RC_DIR, RC_HISTORY_NAME, NULL);
442         history_list_save(path);
443         g_free(path);
444 }
445
446 static void check_for_home_path(gchar *path)
447 {
448         gchar *buf;
449
450         buf = g_build_filename(homedir(), path, NULL);
451         if (!isdir(buf))
452                 {
453                 log_printf(_("Creating %s dir:%s\n"), GQ_APPNAME, buf);
454
455                 if (!mkdir_utf8(buf, 0755))
456                         {
457                         log_printf(_("Could not create dir:%s\n"), buf);
458                         }
459                 }
460         g_free(buf);
461 }
462
463 static void accel_map_save(void)
464 {
465         gchar *path;
466         gchar *pathl;
467
468         path = g_build_filename(homedir(), GQ_RC_DIR, "accels", NULL);
469         pathl = path_from_utf8(path);
470         gtk_accel_map_save(pathl);
471         g_free(pathl);
472         g_free(path);
473 }
474
475 static void accel_map_load(void)
476 {
477         gchar *path;
478         gchar *pathl;
479
480         path = g_build_filename(homedir(), GQ_RC_DIR, "accels", NULL);
481         pathl = path_from_utf8(path);
482         gtk_accel_map_load(pathl);
483         g_free(pathl);
484         g_free(path);
485 }
486
487 static void gtkrc_load(void)
488 {
489         gchar *path;
490         gchar *pathl;
491
492         /* If a gtkrc file exists in the rc directory, add it to the
493          * list of files to be parsed at the end of gtk_init() */
494         path = g_build_filename(homedir(), GQ_RC_DIR, "gtkrc", NULL);
495         pathl = path_from_utf8(path);
496         if (access(pathl, R_OK) == 0)
497                 gtk_rc_add_default_file(pathl);
498         g_free(pathl);
499         g_free(path);
500 }
501
502 static void exit_program_final(void)
503 {
504         LayoutWindow *lw = NULL;
505
506         remote_close(remote_connection);
507
508         collect_manager_flush();
509
510         save_options(options);
511         keys_save();
512         accel_map_save();
513
514         if (layout_valid(&lw))
515                 {
516                 layout_free(lw);
517                 }
518
519         gtk_main_quit();
520 }
521
522 static GenericDialog *exit_dialog = NULL;
523
524 static void exit_confirm_cancel_cb(GenericDialog *gd, gpointer data)
525 {
526         exit_dialog = NULL;
527         generic_dialog_close(gd);
528 }
529
530 static void exit_confirm_exit_cb(GenericDialog *gd, gpointer data)
531 {
532         exit_dialog = NULL;
533         generic_dialog_close(gd);
534         exit_program_final();
535 }
536
537 static gint exit_confirm_dlg(void)
538 {
539         GtkWidget *parent;
540         LayoutWindow *lw;
541         gchar *msg;
542
543         if (exit_dialog)
544                 {
545                 gtk_window_present(GTK_WINDOW(exit_dialog->dialog));
546                 return TRUE;
547                 }
548
549         if (!collection_window_modified_exists()) return FALSE;
550
551         parent = NULL;
552         lw = NULL;
553         if (layout_valid(&lw))
554                 {
555                 parent = lw->window;
556                 }
557
558         msg = g_strdup_printf("%s - %s", GQ_APPNAME, _("exit"));
559         exit_dialog = generic_dialog_new(msg,
560                                 GQ_WMCLASS, "exit", parent, FALSE,
561                                 exit_confirm_cancel_cb, NULL);
562         g_free(msg);
563         msg = g_strdup_printf(_("Quit %s"), GQ_APPNAME);
564         generic_dialog_add_message(exit_dialog, GTK_STOCK_DIALOG_QUESTION,
565                                    msg, _("Collections have been modified. Quit anyway?"));
566         g_free(msg);
567         generic_dialog_add_button(exit_dialog, GTK_STOCK_QUIT, NULL, exit_confirm_exit_cb, TRUE);
568
569         gtk_widget_show(exit_dialog->dialog);
570
571         return TRUE;
572 }
573
574 void exit_program(void)
575 {
576         layout_image_full_screen_stop(NULL);
577
578         if (exit_confirm_dlg()) return;
579
580         exit_program_final();
581 }
582
583 gint main(gint argc, gchar *argv[])
584 {
585         LayoutWindow *lw;
586         gchar *path = NULL;
587         gchar *cmd_path = NULL;
588         gchar *cmd_file = NULL;
589         GList *cmd_list = NULL;
590         GList *collection_list = NULL;
591         CollectionData *first_collection = NULL;
592         gchar *geometry = NULL;
593         gchar *buf;
594         CollectionData *cd = NULL;
595
596 #ifdef HAVE_GTHREAD
597         g_thread_init (NULL);
598         gdk_threads_init();
599         gdk_threads_enter();
600 #endif
601         
602         /* init execution time counter (debug only) */
603         init_exec_time();
604
605         /* setup locale, i18n */
606         gtk_set_locale();
607
608 #ifdef ENABLE_NLS
609         bindtextdomain(PACKAGE, GQ_LOCALEDIR);
610         bind_textdomain_codeset(PACKAGE, "UTF-8");
611         textdomain(PACKAGE);
612 #endif
613
614         /* setup random seed for random slideshow */
615         srand(time(NULL));
616
617 #if 1
618         log_printf("%s %s, This is an alpha release.\n", GQ_APPNAME, VERSION);
619 #endif
620
621         /* register global notify functions */
622         file_data_register_notify_func(cache_notify_cb, NULL, NOTIFY_PRIORITY_HIGH);
623         file_data_register_notify_func(thumb_notify_cb, NULL, NOTIFY_PRIORITY_HIGH);
624         file_data_register_notify_func(collect_manager_notify_cb, NULL, NOTIFY_PRIORITY_LOW);
625
626         parse_command_line_for_debug_option(argc, argv);
627
628         options = init_options(NULL);
629         setup_default_options(options);
630         load_options(options);
631
632         parse_command_line(argc, argv, &cmd_path, &cmd_file, &cmd_list, &collection_list, &geometry);
633
634         gtkrc_load();
635         gtk_init(&argc, &argv);
636
637         if (gtk_major_version < GTK_MAJOR_VERSION ||
638             (gtk_major_version == GTK_MAJOR_VERSION && gtk_minor_version < GTK_MINOR_VERSION) )
639                 {
640                 log_printf("!!! This is a friendly warning.\n");
641                 log_printf("!!! The version of GTK+ in use now is older than when %s was compiled.\n", GQ_APPNAME);
642                 log_printf("!!!  compiled with GTK+-%d.%d\n", GTK_MAJOR_VERSION, GTK_MINOR_VERSION);
643                 log_printf("!!!   running with GTK+-%d.%d\n", gtk_major_version, gtk_minor_version);
644                 log_printf("!!! %s may quit unexpectedly with a relocation error.\n", GQ_APPNAME);
645                 }
646
647         check_for_home_path(GQ_RC_DIR);
648         check_for_home_path(GQ_RC_DIR_COLLECTIONS);
649         check_for_home_path(GQ_CACHE_RC_THUMB);
650         check_for_home_path(GQ_CACHE_RC_METADATA);
651
652         keys_load();
653         filter_add_defaults();
654         filter_rebuild();
655
656         accel_map_load();
657
658         if (startup_blank)
659                 {
660                 g_free(cmd_path);
661                 cmd_path = NULL;
662                 g_free(cmd_file);
663                 cmd_file = NULL;
664                 filelist_free(cmd_list);
665                 cmd_list = NULL;
666                 string_list_free(collection_list);
667                 collection_list = NULL;
668
669                 path = NULL;
670                 }
671         else if (cmd_path)
672                 {
673                 path = g_strdup(cmd_path);
674                 }
675         else if (options->startup.restore_path && options->startup.path && isdir(options->startup.path))
676                 {
677                 path = g_strdup(options->startup.path);
678                 }
679         else
680                 {
681                 path = get_current_dir();
682                 }
683
684         lw = layout_new_with_geometry(NULL, options->layout.tools_float, options->layout.tools_hidden, geometry);
685         layout_sort_set(lw, options->file_sort.method, options->file_sort.ascending);
686
687         if (collection_list && !startup_command_line_collection)
688                 {
689                 GList *work;
690
691                 work = collection_list;
692                 while (work)
693                         {
694                         CollectWindow *cw;
695                         const gchar *path;
696
697                         path = work->data;
698                         work = work->next;
699
700                         cw = collection_window_new(path);
701                         if (!first_collection && cw) first_collection = cw->cd;
702                         }
703                 }
704
705         if (cmd_list ||
706             (startup_command_line_collection && collection_list))
707                 {
708                 GList *work;
709
710                 if (startup_command_line_collection)
711                         {
712                         CollectWindow *cw;
713
714                         cw = collection_window_new("");
715                         cd = cw->cd;
716                         }
717                 else
718                         {
719                         cd = collection_new("");        /* if we pass NULL, untitled counter is falsely increm. */
720                         }
721
722                 g_free(cd->path);
723                 cd->path = NULL;
724                 g_free(cd->name);
725                 cd->name = g_strdup(_("Command line"));
726
727                 collection_path_changed(cd);
728
729                 work = cmd_list;
730                 while (work)
731                         {
732                         collection_add(cd, file_data_new_simple((gchar *)work->data), FALSE);
733                         work = work->next;
734                         }
735
736                 work = collection_list;
737                 while (work)
738                         {
739                         collection_load(cd, (gchar *)work->data, COLLECTION_LOAD_APPEND);
740                         work = work->next;
741                         }
742
743                 layout_set_path(lw, path);
744                 if (cd->list) layout_image_set_collection(lw, cd, cd->list->data);
745
746                 /* mem leak, we never unref this collection when !startup_command_line_collection
747                  * (the image view of the main window does not hold a ref to the collection)
748                  * this is sort of unavoidable, for if it did hold a ref, next/back
749                  * may not work as expected when closing collection windows.
750                  *
751                  * collection_unref(cd);
752                  */
753
754                 }
755         else if (cmd_file)
756                 {
757                 layout_set_path(lw, cmd_file);
758                 }
759         else
760                 {
761                 layout_set_path(lw, path);
762                 if (first_collection)
763                         {
764                         layout_image_set_collection(lw, first_collection,
765                                                     collection_get_first(first_collection));
766                         }
767                 }
768
769         image_osd_set(lw->image, options->image_overlay.common.state | (options->image_overlay.common.show_at_startup ? OSD_SHOW_INFO : OSD_SHOW_NOTHING));
770
771         g_free(geometry);
772         g_free(cmd_path);
773         g_free(cmd_file);
774         filelist_free(cmd_list);
775         string_list_free(collection_list);
776         g_free(path);
777
778         if (startup_full_screen) layout_image_full_screen_start(lw);
779         if (startup_in_slideshow) layout_image_slideshow_start(lw);
780
781         buf = g_build_filename(homedir(), GQ_RC_DIR, ".command", NULL);
782         remote_connection = remote_server_init(buf, cd);
783         g_free(buf);
784         
785         gtk_main();
786 #ifdef HAVE_GTHREAD
787         gdk_threads_leave();
788 #endif
789         return 0;
790 }