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