/* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include #include #include #include #include #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef __GLIBC__ #include #endif #ifndef WAIT_ANY #define WAIT_ANY -1 #endif #include #include #include "libgimpbase/gimpbase.h" #include "config/gimpconfig-dump.h" #include "core/core-types.h" #include "core/gimp.h" #include "app_procs.h" #include "errors.h" #include "sanity.h" #include "units.h" #include "gimp-intl.h" #ifdef G_OS_WIN32 #include #else static void gimp_sigfatal_handler (gint sig_num) G_GNUC_NORETURN; static void gimp_sigchld_handler (gint sig_num); #endif static void gimp_show_version (void); static void gimp_show_help (const gchar *progname); /* * argv processing: * Arguments are either switches, their associated * values, or image files. As switches and their * associated values are processed, those slots in * the argv[] array are NULLed. We do this because * unparsed args are treated as images to load on * startup. * * The GTK switches are processed first (X switches are * processed here, not by any X routines). Then the * general GIMP switches are processed. Any args * left are assumed to be image files the GIMP should * display. * * The exception is the batch switch. When this is * encountered, all remaining args are treated as batch * commands. */ int main (int argc, char **argv) { const gchar *abort_message = NULL; gchar *full_prog_name = NULL; gchar *alternate_system_gimprc = NULL; gchar *alternate_gimprc = NULL; gchar *session_name = NULL; gchar **batch_cmds = NULL; gboolean show_help = FALSE; gboolean no_interface = FALSE; gboolean no_data = FALSE; gboolean no_fonts = FALSE; gboolean no_splash = FALSE; gboolean be_verbose = FALSE; gboolean use_shm = FALSE; gboolean use_cpu_accel = TRUE; gboolean console_messages = FALSE; gboolean use_debug_handler = FALSE; #if ((GIMP_MINOR_VERSION % 2) == 0) GimpStackTraceMode stack_trace_mode = GIMP_STACK_TRACE_NEVER; GimpPDBCompatMode pdb_compat_mode = GIMP_PDB_COMPAT_ON; #else GimpStackTraceMode stack_trace_mode = GIMP_STACK_TRACE_QUERY; GimpPDBCompatMode pdb_compat_mode = GIMP_PDB_COMPAT_WARN; #endif gint i, j; #if 0 g_mem_set_vtable (glib_mem_profiler_table); g_atexit (g_mem_profile); #endif /* Initialize variables */ full_prog_name = argv[0]; /* Initialize i18n support */ setlocale (LC_ALL, ""); bindtextdomain (GETTEXT_PACKAGE"-libgimp", gimp_locale_directory ()); #ifdef HAVE_BIND_TEXTDOMAIN_CODESET bind_textdomain_codeset (GETTEXT_PACKAGE"-libgimp", "UTF-8"); #endif bindtextdomain (GETTEXT_PACKAGE, gimp_locale_directory ()); #ifdef HAVE_BIND_TEXTDOMAIN_CODESET bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); #endif textdomain (GETTEXT_PACKAGE); /* Check argv[] for "--no-interface" before trying to initialize gtk+. * We also check for "--help" or "--version" here since those shouldn't * require gui libs either. */ for (i = 1; i < argc; i++) { const gchar *arg = argv[i]; if (arg[0] != '-') continue; if ((strcmp (arg, "--no-interface") == 0) || (strcmp (arg, "-i") == 0)) { no_interface = TRUE; } else if ((strcmp (arg, "--version") == 0) || (strcmp (arg, "-v") == 0)) { gimp_show_version (); app_exit (EXIT_SUCCESS); } else if ((strcmp (arg, "--help") == 0) || (strcmp (arg, "-h") == 0)) { gimp_show_help (full_prog_name); app_exit (EXIT_SUCCESS); } else if (strncmp (arg, "--dump-gimprc", 13) == 0) { GimpConfigDumpFormat format = GIMP_CONFIG_DUMP_NONE; if (strcmp (arg, "--dump-gimprc") == 0) format = GIMP_CONFIG_DUMP_GIMPRC; if (strcmp (arg, "--dump-gimprc-system") == 0) format = GIMP_CONFIG_DUMP_GIMPRC_SYSTEM; else if (strcmp (arg, "--dump-gimprc-manpage") == 0) format = GIMP_CONFIG_DUMP_GIMPRC_MANPAGE; if (format) { Gimp *gimp; gboolean success; g_type_init (); gimp = g_object_new (GIMP_TYPE_GIMP, NULL); units_init (gimp); success = gimp_config_dump (format); g_object_unref (gimp); app_exit (success ? EXIT_SUCCESS : EXIT_FAILURE); } } } if (! app_libs_init (&no_interface, &argc, &argv)) { const gchar *msg; msg = _("GIMP could not initialize the graphical user interface.\n" "Make sure a proper setup for your display environment exists."); g_print ("%s\n\n", msg); app_exit (EXIT_FAILURE); } abort_message = sanity_check (); if (abort_message) app_abort (no_interface, abort_message); g_set_application_name (_("The GIMP")); #if defined (USE_SYSV_SHM) || defined (USE_POSIX_SHM) || defined (G_OS_WIN32) use_shm = TRUE; #endif #ifdef __GLIBC__ /* Tweak memory allocation so that memory allocated in chunks >= 4k * (64x64 pixel 1bpp tile) gets returned to the system when free'd (). */ mallopt (M_MMAP_THRESHOLD, 64 * 64 - 1); #endif batch_cmds = g_new (gchar *, argc); batch_cmds[0] = NULL; for (i = 1; i < argc; i++) { if (strcmp (argv[i], "--g-fatal-warnings") == 0) { GLogLevelFlags fatal_mask; fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK); fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL; g_log_set_always_fatal (fatal_mask); argv[i] = NULL; } else if ((strcmp (argv[i], "--no-interface") == 0) || (strcmp (argv[i], "-i") == 0)) { no_interface = TRUE; argv[i] = NULL; } else if ((strcmp (argv[i], "--batch") == 0) || (strcmp (argv[i], "-b") == 0)) { argv[i] = NULL; for (j = 0, i++ ; i < argc; j++, i++) { batch_cmds[j] = argv[i]; argv[i] = NULL; } batch_cmds[j] = NULL; if (batch_cmds[0] == NULL) /* We need at least one batch command */ show_help = TRUE; } else if (strcmp (argv[i], "--system-gimprc") == 0) { argv[i] = NULL; if (argc <= ++i) { show_help = TRUE; } else { alternate_system_gimprc = argv[i]; argv[i] = NULL; } } else if ((strcmp (argv[i], "--gimprc") == 0) || (strcmp (argv[i], "-g") == 0)) { argv[i] = NULL; if (argc <= ++i) { show_help = TRUE; } else { alternate_gimprc = argv[i]; argv[i] = NULL; } } else if ((strcmp (argv[i], "--no-data") == 0) || (strcmp (argv[i], "-d") == 0)) { no_data = TRUE; argv[i] = NULL; } else if ((strcmp (argv[i], "--no-fonts") == 0) || (strcmp (argv[i], "-f") == 0)) { no_fonts = TRUE; argv[i] = NULL; } else if ((strcmp (argv[i], "--no-splash") == 0) || (strcmp (argv[i], "-s") == 0)) { no_splash = TRUE; argv[i] = NULL; } else if (strcmp (argv[i], "--verbose") == 0) { be_verbose = TRUE; argv[i] = NULL; } else if (strcmp (argv[i], "--no-shm") == 0) { use_shm = FALSE; argv[i] = NULL; } else if (strcmp (argv[i], "--no-cpu-accel") == 0) { use_cpu_accel = FALSE; argv[i] = NULL; } else if (strcmp (argv[i], "--debug-handlers") == 0) { use_debug_handler = TRUE; argv[i] = NULL; } else if ((strcmp (argv[i], "--console-messages") == 0) || (strcmp (argv[i], "-c") == 0)) { console_messages = TRUE; argv[i] = NULL; } else if (strcmp (argv[i], "--session") == 0) { argv[i] = NULL; if (argc <= ++i) { show_help = TRUE; } else { session_name = argv[i]; argv[i] = NULL; } } else if (strcmp (argv[i], "--stack-trace-mode") == 0) { argv[i] = NULL; if (argc <= ++i) { show_help = TRUE; } else { if (! strcmp (argv[i], "never")) stack_trace_mode = GIMP_STACK_TRACE_NEVER; else if (! strcmp (argv[i], "query")) stack_trace_mode = GIMP_STACK_TRACE_QUERY; else if (! strcmp (argv[i], "always")) stack_trace_mode = GIMP_STACK_TRACE_ALWAYS; else show_help = TRUE; argv[i] = NULL; } } else if (strcmp (argv[i], "--pdb-compat-mode") == 0) { argv[i] = NULL; if (argc <= ++i) { show_help = TRUE; } else { if (! strcmp (argv[i], "off")) pdb_compat_mode = GIMP_PDB_COMPAT_OFF; else if (! strcmp (argv[i], "on")) pdb_compat_mode = GIMP_PDB_COMPAT_ON; else if (! strcmp (argv[i], "warn")) pdb_compat_mode = GIMP_PDB_COMPAT_WARN; else show_help = TRUE; argv[i] = NULL; } } else if (strcmp (argv[i], "--") == 0) { /* * everything after "--" is a parameter (i.e. image to load) */ argv[i] = NULL; break; } else if (argv[i][0] == '-') { /* * anything else starting with a '-' is an error. */ g_print (_("\nInvalid option \"%s\"\n"), argv[i]); show_help = TRUE; } } #ifdef G_OS_WIN32 /* Common windoze apps don't have a console at all. So does Gimp * - if appropiate. This allows to compile as console application * with all it's benefits (like inheriting the console) but hide * it, if the user doesn't want it. */ if (!show_help && !be_verbose && !console_messages) FreeConsole (); #endif if (show_help) { gimp_show_help (full_prog_name); app_exit (EXIT_FAILURE); } #ifndef G_OS_WIN32 /* No use catching these on Win32, the user won't get any * stack trace from glib anyhow. It's better to let Windows inform * about the program error, and offer debugging (if the user * has installed MSVC or some other compiler that knows how to * install itself as a handler for program errors). */ /* Handle fatal signals */ /* these are handled by gimp_terminate() */ gimp_signal_private (SIGHUP, gimp_sigfatal_handler, 0); gimp_signal_private (SIGINT, gimp_sigfatal_handler, 0); gimp_signal_private (SIGQUIT, gimp_sigfatal_handler, 0); gimp_signal_private (SIGABRT, gimp_sigfatal_handler, 0); gimp_signal_private (SIGTERM, gimp_sigfatal_handler, 0); if (stack_trace_mode != GIMP_STACK_TRACE_NEVER) { /* these are handled by gimp_fatal_error() */ gimp_signal_private (SIGBUS, gimp_sigfatal_handler, 0); gimp_signal_private (SIGSEGV, gimp_sigfatal_handler, 0); gimp_signal_private (SIGFPE, gimp_sigfatal_handler, 0); } /* Ignore SIGPIPE because plug_in.c handles broken pipes */ gimp_signal_private (SIGPIPE, SIG_IGN, 0); /* Collect dead children */ gimp_signal_private (SIGCHLD, gimp_sigchld_handler, SA_RESTART); #endif /* G_OS_WIN32 */ gimp_errors_init (full_prog_name, use_debug_handler, stack_trace_mode); app_run (full_prog_name, argc - 1, argv + 1, alternate_system_gimprc, alternate_gimprc, session_name, (const gchar **) batch_cmds, no_interface, no_data, no_fonts, no_splash, be_verbose, use_shm, use_cpu_accel, console_messages, stack_trace_mode, pdb_compat_mode); g_free (batch_cmds); return EXIT_SUCCESS; } static void gimp_show_version (void) { g_print ("%s %s\n", _("GIMP version"), GIMP_VERSION); } static void gimp_show_help (const gchar *progname) { gimp_show_version (); g_print (_("\nUsage: %s [option ... ] [file ... ]\n\n"), gimp_filename_to_utf8 (progname)); g_print (_("Options:\n")); g_print (_(" -h, --help Output this help.\n")); g_print (_(" -v, --version Output version information.\n")); g_print (_(" --verbose Show startup messages.\n")); g_print (_(" --no-shm Do not use shared memory between GIMP and plugins.\n")); g_print (_(" --no-cpu-accel Do not use special CPU accelerations.\n")); g_print (_(" -d, --no-data Do not load brushes, gradients, palettes, patterns.\n")); g_print (_(" -f, --no-fonts Do not load any fonts.\n")); g_print (_(" -i, --no-interface Run without a user interface.\n")); g_print (_(" --display Use the designated X display.\n")); g_print (_(" -s, --no-splash Do not show the startup window.\n")); g_print (_(" --session Use an alternate sessionrc file.\n")); g_print (_(" -g, --gimprc Use an alternate gimprc file.\n")); g_print (_(" --system-gimprc Use an alternate system gimprc file.\n")); g_print (_(" --dump-gimprc Output a gimprc file with default settings.\n")); g_print (_(" -c, --console-messages Display warnings to console instead of a dialog box.\n")); g_print (_(" --debug-handlers Enable non-fatal debugging signal handlers.\n")); g_print (_(" --stack-trace-mode \n" " Debugging mode for fatal signals.\n")); g_print (_(" --pdb-compat-mode \n" " Procedural Database compatibility mode.\n")); g_print (_(" -b, --batch Process commands in batch mode.\n")); g_print ("\n"); }; #ifdef G_OS_WIN32 /* In case we build this as a windowed application */ #ifdef __GNUC__ # ifndef _stdcall # define _stdcall __attribute__((stdcall)) # endif #endif int _stdcall WinMain (struct HINSTANCE__ *hInstance, struct HINSTANCE__ *hPrevInstance, char *lpszCmdLine, int nCmdShow) { return main (__argc, __argv); } #endif /* G_OS_WIN32 */ #ifndef G_OS_WIN32 /* gimp core signal handler for fatal signals */ static void gimp_sigfatal_handler (gint sig_num) { switch (sig_num) { case SIGHUP: case SIGINT: case SIGQUIT: case SIGABRT: case SIGTERM: gimp_terminate (g_strsignal (sig_num)); break; case SIGBUS: case SIGSEGV: case SIGFPE: default: gimp_fatal_error (g_strsignal (sig_num)); break; } } /* gimp core signal handler for death-of-child signals */ static void gimp_sigchld_handler (gint sig_num) { gint pid; gint status; while (TRUE) { pid = waitpid (WAIT_ANY, &status, WNOHANG); if (pid <= 0) break; } } #endif /* ! G_OS_WIN32 */