/* LIBPIKA - The PIKA Library * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball * * pika.c * * This library is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see * . */ #include "config.h" #define _GNU_SOURCE /* for the sigaction stuff */ #include #include #include #include #include #include #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifndef WAIT_ANY #define WAIT_ANY -1 #endif #include #include #ifndef G_OS_WIN32 #include "libpikabase/pikasignal.h" #else #ifdef HAVE_EXCHNDL #include #include #endif #include #endif #ifdef HAVE_SYS_SELECT_H #include #endif #if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN) # ifdef STRICT # undef STRICT # endif # define STRICT # ifdef _WIN32_WINNT # undef _WIN32_WINNT # endif # define _WIN32_WINNT 0x0601 # include # include # undef RGB #endif #include #include "pika.h" #include "libpikabase/pikabase-private.h" #include "libpikabase/pikaprotocol.h" #include "libpikabase/pikawire.h" #include "pika-debug.h" #include "pika-private.h" #include "pika-shm.h" #include "pikagpparams.h" #include "pikapdb-private.h" #include "pikaplugin-private.h" #include "pikaunitcache.h" #include "libpika-intl.h" static void pika_close (void); #ifdef G_OS_WIN32 #ifdef HAVE_EXCHNDL static LONG WINAPI pika_plugin_sigfatal_handler (PEXCEPTION_POINTERS pExceptionInfo); static LPTOP_LEVEL_EXCEPTION_FILTER _prevExceptionFilter = NULL; static gchar *plug_in_backtrace_path = NULL; #endif #else /* ! G_OS_WIN32 */ static void pika_plugin_sigfatal_handler (gint sig_num); #endif /* G_OS_WIN32 */ static PikaPlugIn *PLUG_IN = NULL; static PikaPDB *PDB = NULL; static gint _tile_width = -1; static gint _tile_height = -1; static gboolean _show_help_button = TRUE; static gboolean _export_color_profile = FALSE; static gboolean _export_comment = FALSE; static gboolean _export_exif = FALSE; static gboolean _export_xmp = FALSE; static gboolean _export_iptc = FALSE; static gboolean _export_thumbnail = TRUE; static gint32 _num_processors = 1; static PikaCheckSize _check_size = PIKA_CHECK_SIZE_MEDIUM_CHECKS; static PikaCheckType _check_type = PIKA_CHECK_TYPE_GRAY_CHECKS; static PikaRGB _check_custom_color1 = PIKA_CHECKS_CUSTOM_COLOR1; static PikaRGB _check_custom_color2 = PIKA_CHECKS_CUSTOM_COLOR2; static gint _default_display_id = -1; static gchar *_wm_class = NULL; static gchar *_display_name = NULL; static gint _monitor_number = 0; static guint32 _timestamp = 0; static gchar *_icon_theme_dir = NULL; static const gchar *progname = NULL; static PikaStackTraceMode stack_trace_mode = PIKA_STACK_TRACE_NEVER; /** * pika_main: * @plug_in_type: the type of the #PikaPlugIn subclass of the plug-in * @argc: the number of arguments * @argv: (array length=argc): the arguments * * The main plug-in function that must be called with the plug-in's * #PikaPlugIn subclass #GType and the 'argc' and 'argv' that are passed * to the platform's main(). * * See also: PIKA_MAIN(), #PikaPlugIn. * * Returns: an exit status as defined by the C library, * on success EXIT_SUCCESS. * * Since: 3.0 **/ gint pika_main (GType plug_in_type, gint argc, gchar *argv[]) { enum { ARG_PROGNAME, ARG_PIKA, ARG_PROTOCOL_VERSION, ARG_READ_FD, ARG_WRITE_FD, ARG_MODE, ARG_STACK_TRACE_MODE, N_ARGS }; GIOChannel *read_channel; GIOChannel *write_channel; gchar *basename; gint protocol_version; #ifdef G_OS_WIN32 gint i, j, k; /* Reduce risks */ SetDllDirectoryW (L""); /* On Windows, set DLL search path to $INSTALLDIR/bin so that GEGL * file operations can find their respective file library DLLs (such * as jasper, etc.) without needing to set external PATH. */ { const gchar *install_dir; gchar *bin_dir; LPWSTR w_bin_dir; w_bin_dir = NULL; install_dir = pika_installation_directory (); bin_dir = g_build_filename (install_dir, "bin", NULL); w_bin_dir = g_utf8_to_utf16 (bin_dir, -1, NULL, NULL, NULL); if (w_bin_dir) { SetDllDirectoryW (w_bin_dir); g_free (w_bin_dir); } g_free (bin_dir); } #ifdef HAVE_EXCHNDL /* Use Dr. Mingw (dumps backtrace on crash) if it is available. */ { time_t t; gchar *filename; gchar *dir; wchar_t *plug_in_backtrace_path_utf16; /* This has to be the non-roaming directory (i.e., the local * directory) as backtraces correspond to the binaries on this * system. */ dir = g_build_filename (g_get_user_data_dir (), PIKADIR, PIKA_USER_VERSION, "CrashLog", NULL); /* Ensure the path exists. */ g_mkdir_with_parents (dir, 0700); time (&t); filename = g_strdup_printf ("%s-crash-%" G_GUINT64_FORMAT ".txt", g_get_prgname(), t); plug_in_backtrace_path = g_build_filename (dir, filename, NULL); g_free (filename); g_free (dir); /* Similar to core crash handling in app/signals.c, the order here * is very important! */ if (! _prevExceptionFilter) _prevExceptionFilter = SetUnhandledExceptionFilter (pika_plugin_sigfatal_handler); ExcHndlInit (); plug_in_backtrace_path_utf16 = g_utf8_to_utf16 (plug_in_backtrace_path, -1, NULL, NULL, NULL); if (plug_in_backtrace_path_utf16) { ExcHndlSetLogFileNameW (plug_in_backtrace_path_utf16); g_free (plug_in_backtrace_path_utf16); } } #endif /* HAVE_EXCHNDL */ #ifndef _WIN64 { typedef BOOL (WINAPI *t_SetProcessDEPPolicy) (DWORD dwFlags); t_SetProcessDEPPolicy p_SetProcessDEPPolicy; p_SetProcessDEPPolicy = GetProcAddress (GetModuleHandleW (L"kernel32.dll"), "SetProcessDEPPolicy"); if (p_SetProcessDEPPolicy) (*p_SetProcessDEPPolicy) (PROCESS_DEP_ENABLE|PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION); } #endif /* _WIN64 */ /* Group all our windows together on the taskbar */ { typedef HRESULT (WINAPI *t_SetCurrentProcessExplicitAppUserModelID) (PCWSTR lpPathName); t_SetCurrentProcessExplicitAppUserModelID p_SetCurrentProcessExplicitAppUserModelID; p_SetCurrentProcessExplicitAppUserModelID = (t_SetCurrentProcessExplicitAppUserModelID) GetProcAddress (GetModuleHandleW (L"shell32.dll"), "SetCurrentProcessExplicitAppUserModelID"); if (p_SetCurrentProcessExplicitAppUserModelID) (*p_SetCurrentProcessExplicitAppUserModelID) (L"pika.PikaApplication"); } /* Check for exe file name with spaces in the path having been split up * by buggy NT C runtime, or something. I don't know why this happens * on NT (including w2k), but not on w95/98. */ for (i = 1; i < argc; i++) { k = strlen (argv[i]); if (k > 10) { if (g_ascii_strcasecmp (argv[i] + k - 4, ".exe") == 0) { /* Found the end of the executable name, most probably. * Splice the parts of the name back together. */ GString *s; s = g_string_new (argv[ARG_PROGNAME]); for (j = 1; j <= i; j++) { s = g_string_append_c (s, ' '); s = g_string_append (s, argv[j]); } argv[ARG_PROGNAME] = s->str; /* Move rest of argv down */ for (j = 1; j < argc - i; j++) argv[j] = argv[j + i]; argv[argc - i] = NULL; argc -= i; break; } } } #endif /* G_OS_WIN32 */ g_assert (plug_in_type != G_TYPE_NONE); if ((argc != N_ARGS) || (strcmp (argv[ARG_PIKA], "-pika") != 0)) { g_printerr ("%s is a PIKA plug-in and must be run by PIKA to be used\n", argv[ARG_PROGNAME]); return EXIT_FAILURE; } pika_env_init (TRUE); progname = argv[ARG_PROGNAME]; basename = g_path_get_basename (progname); g_set_prgname (basename); protocol_version = atoi (argv[ARG_PROTOCOL_VERSION]); if (protocol_version < PIKA_PROTOCOL_VERSION) { g_printerr ("Could not execute plug-in \"%s\"\n(%s)\n" "because PIKA is using an older version of the " "plug-in protocol.\n", pika_filename_to_utf8 (g_get_prgname ()), pika_filename_to_utf8 (progname)); return EXIT_FAILURE; } else if (protocol_version > PIKA_PROTOCOL_VERSION) { g_printerr ("Could not execute plug-in \"%s\"\n(%s)\n" "because it uses an obsolete version of the " "plug-in protocol.\n", pika_filename_to_utf8 (g_get_prgname ()), pika_filename_to_utf8 (progname)); return EXIT_FAILURE; } _pika_debug_init (basename); g_free (basename); stack_trace_mode = (PikaStackTraceMode) CLAMP (atoi (argv[ARG_STACK_TRACE_MODE]), PIKA_STACK_TRACE_NEVER, PIKA_STACK_TRACE_ALWAYS); #ifndef G_OS_WIN32 /* No use catching these on Win32, the user won't get any meaningful * stack trace from glib anyhow. It's better to let Windows inform * about the program error, and offer debugging if the plug-in * has been built with MSVC, and the user has MSVC installed. */ pika_signal_private (SIGHUP, pika_plugin_sigfatal_handler, 0); pika_signal_private (SIGINT, pika_plugin_sigfatal_handler, 0); pika_signal_private (SIGQUIT, pika_plugin_sigfatal_handler, 0); pika_signal_private (SIGTERM, pika_plugin_sigfatal_handler, 0); pika_signal_private (SIGABRT, pika_plugin_sigfatal_handler, 0); pika_signal_private (SIGBUS, pika_plugin_sigfatal_handler, 0); pika_signal_private (SIGSEGV, pika_plugin_sigfatal_handler, 0); pika_signal_private (SIGFPE, pika_plugin_sigfatal_handler, 0); /* Ignore SIGPIPE from crashing Pika */ pika_signal_private (SIGPIPE, SIG_IGN, 0); /* Restart syscalls interrupted by SIGCHLD */ pika_signal_private (SIGCHLD, SIG_DFL, SA_RESTART); #endif /* ! G_OS_WIN32 */ #ifdef G_OS_WIN32 read_channel = g_io_channel_win32_new_fd (atoi (argv[ARG_READ_FD])); write_channel = g_io_channel_win32_new_fd (atoi (argv[ARG_WRITE_FD])); #else read_channel = g_io_channel_unix_new (atoi (argv[ARG_READ_FD])); write_channel = g_io_channel_unix_new (atoi (argv[ARG_WRITE_FD])); #endif g_io_channel_set_encoding (read_channel, NULL, NULL); g_io_channel_set_encoding (write_channel, NULL, NULL); g_io_channel_set_buffered (read_channel, FALSE); g_io_channel_set_buffered (write_channel, FALSE); g_io_channel_set_close_on_unref (read_channel, TRUE); g_io_channel_set_close_on_unref (write_channel, TRUE); /* initialize GTypes, they need to be known to g_type_from_name() */ { GType init_types[] = { G_TYPE_INT, G_TYPE_PARAM_INT, G_TYPE_UCHAR, G_TYPE_PARAM_UCHAR, G_TYPE_STRING, G_TYPE_PARAM_STRING, G_TYPE_STRV, G_TYPE_PARAM_BOXED, G_TYPE_BYTES, G_TYPE_PARAM_BOXED, PIKA_TYPE_ARRAY, PIKA_TYPE_PARAM_ARRAY, PIKA_TYPE_INT32_ARRAY, PIKA_TYPE_PARAM_INT32_ARRAY, PIKA_TYPE_FLOAT_ARRAY, PIKA_TYPE_PARAM_FLOAT_ARRAY, PIKA_TYPE_RGB_ARRAY, PIKA_TYPE_PARAM_RGB_ARRAY, PIKA_TYPE_OBJECT_ARRAY, PIKA_TYPE_PARAM_OBJECT_ARRAY, PIKA_TYPE_DISPLAY, PIKA_TYPE_PARAM_DISPLAY, PIKA_TYPE_IMAGE, PIKA_TYPE_PARAM_IMAGE, PIKA_TYPE_ITEM, PIKA_TYPE_PARAM_ITEM, PIKA_TYPE_DRAWABLE, PIKA_TYPE_PARAM_DRAWABLE, PIKA_TYPE_LAYER, PIKA_TYPE_PARAM_LAYER, PIKA_TYPE_TEXT_LAYER, PIKA_TYPE_PARAM_TEXT_LAYER, PIKA_TYPE_CHANNEL, PIKA_TYPE_PARAM_CHANNEL, PIKA_TYPE_LAYER_MASK, PIKA_TYPE_PARAM_LAYER_MASK, PIKA_TYPE_SELECTION, PIKA_TYPE_PARAM_SELECTION, PIKA_TYPE_VECTORS, PIKA_TYPE_PARAM_VECTORS, PIKA_TYPE_BRUSH, PIKA_TYPE_PARAM_BRUSH, PIKA_TYPE_FONT, PIKA_TYPE_PARAM_FONT, PIKA_TYPE_GRADIENT, PIKA_TYPE_PARAM_GRADIENT, PIKA_TYPE_PALETTE, PIKA_TYPE_PARAM_PALETTE, PIKA_TYPE_PATTERN, PIKA_TYPE_PARAM_PATTERN }; gint i; for (i = 0; i < G_N_ELEMENTS (init_types); i++, i++) { GType type = init_types[i]; if (G_TYPE_IS_CLASSED (type)) g_type_class_ref (type); } pika_enums_init (); } /* initialize units */ { PikaUnitVtable vtable; vtable.unit_get_number_of_units = _pika_unit_cache_get_number_of_units; vtable.unit_get_number_of_built_in_units = _pika_unit_cache_get_number_of_built_in_units; vtable.unit_new = _pika_unit_cache_new; vtable.unit_get_deletion_flag = _pika_unit_cache_get_deletion_flag; vtable.unit_set_deletion_flag = _pika_unit_cache_set_deletion_flag; vtable.unit_get_factor = _pika_unit_cache_get_factor; vtable.unit_get_digits = _pika_unit_cache_get_digits; vtable.unit_get_identifier = _pika_unit_cache_get_identifier; vtable.unit_get_symbol = _pika_unit_cache_get_symbol; vtable.unit_get_abbreviation = _pika_unit_cache_get_abbreviation; vtable.unit_get_singular = _pika_unit_cache_get_singular; vtable.unit_get_plural = _pika_unit_cache_get_plural; pika_base_init (&vtable); } /* initialize i18n support */ setlocale (LC_ALL, ""); pika_bind_text_domain (GETTEXT_PACKAGE"-libpika", pika_locale_directory ()); #ifdef HAVE_BIND_TEXTDOMAIN_CODESET bind_textdomain_codeset (GETTEXT_PACKAGE"-libpika", "UTF-8"); #endif _pika_debug_configure (stack_trace_mode); PLUG_IN = g_object_new (plug_in_type, "program-name", progname, "read-channel", read_channel, "write-channel", write_channel, NULL); g_assert (PIKA_IS_PLUG_IN (PLUG_IN)); if (strcmp (argv[ARG_MODE], "-query") == 0) { if (_pika_get_debug_flags () & PIKA_DEBUG_QUERY) _pika_debug_stop (); _pika_plug_in_query (PLUG_IN); pika_close (); return EXIT_SUCCESS; } if (strcmp (argv[ARG_MODE], "-init") == 0) { if (_pika_get_debug_flags () & PIKA_DEBUG_INIT) _pika_debug_stop (); _pika_plug_in_init (PLUG_IN); pika_close (); return EXIT_SUCCESS; } if (_pika_get_debug_flags () & PIKA_DEBUG_RUN) _pika_debug_stop (); else if (_pika_get_debug_flags () & PIKA_DEBUG_PID) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Here I am!"); _pika_plug_in_run (PLUG_IN); pika_close (); g_io_channel_unref (read_channel); g_io_channel_unref (write_channel); return EXIT_SUCCESS; } /** * pika_get_plug_in: * * This function returns the plug-in's #PikaPlugIn instance, which is * a a singleton that can exist exactly once per running plug-in. * * Returns: (transfer none) (nullable): The plug-in's #PikaPlugIn singleton. * * Since: 3.0 **/ PikaPlugIn * pika_get_plug_in (void) { return PLUG_IN; } /** * pika_get_pdb: * * This function returns the plug-in's #PikaPDB instance, which is a * singleton that can exist exactly once per running plug-in. * * Returns: (transfer none) (nullable): The plug-in's #PikaPDB singleton. * * Since: 3.0 **/ PikaPDB * pika_get_pdb (void) { if (! PDB) PDB = _pika_pdb_new (PLUG_IN); return PDB; } /** * pika_quit: * * Forcefully causes the PIKA library to exit and close down its * connection to main pika application. This function never returns. **/ void pika_quit (void) { pika_close (); #if defined G_OS_WIN32 && defined HAVE_EXCHNDL if (plug_in_backtrace_path) g_free (plug_in_backtrace_path); #endif exit (EXIT_SUCCESS); } /** * pika_tile_width: * * Returns the tile width PIKA is using. * * This is a constant value given at plug-in configuration time. * * Returns: the tile_width **/ guint pika_tile_width (void) { return _tile_width; } /** * pika_tile_height: * * Returns the tile height PIKA is using. * * This is a constant value given at plug-in configuration time. * * Returns: the tile_height **/ guint pika_tile_height (void) { return _tile_height; } /** * pika_show_help_button: * * Returns whether or not PikaDialog should automatically add a help * button if help_func and help_id are given. * * This is a constant value given at plug-in configuration time. * * Returns: the show_help_button boolean * * Since: 2.2 **/ gboolean pika_show_help_button (void) { return _show_help_button; } /** * pika_export_color_profile: * * Returns whether file plug-ins should default to exporting the * image's color profile. * * Returns: TRUE if preferences are set to export the color profile. * * Since: 2.10.4 **/ gboolean pika_export_color_profile (void) { return _export_color_profile; } /** * pika_export_comment: * * Returns whether file plug-ins should default to exporting the * image's comment. * * Returns: TRUE if preferences are set to export the comment. * * Since: 3.0 **/ gboolean pika_export_comment (void) { return _export_comment; } /** * pika_export_exif: * * Returns whether file plug-ins should default to exporting Exif * metadata, according preferences (original settings is %FALSE since * metadata can contain sensitive information). * * Returns: TRUE if preferences are set to export Exif. * * Since: 2.10 **/ gboolean pika_export_exif (void) { return _export_exif; } /** * pika_export_xmp: * * Returns whether file plug-ins should default to exporting XMP * metadata, according preferences (original settings is %FALSE since * metadata can contain sensitive information). * * Returns: TRUE if preferences are set to export XMP. * * Since: 2.10 **/ gboolean pika_export_xmp (void) { return _export_xmp; } /** * pika_export_iptc: * * Returns whether file plug-ins should default to exporting IPTC * metadata, according preferences (original settings is %FALSE since * metadata can contain sensitive information). * * Returns: TRUE if preferences are set to export IPTC. * * Since: 2.10 **/ gboolean pika_export_iptc (void) { return _export_iptc; } /** * pika_export_thumbnail: * * Returns whether file plug-ins should default to exporting the * image's comment. * * Returns: TRUE if preferences are set to export the thumbnail. * * Since: 3.0 **/ gboolean pika_export_thumbnail (void) { return _export_thumbnail; } /** * pika_get_num_processors: * * Returns the number of threads set explicitly by the user in the * preferences. This information can be used by plug-ins wishing to * follow user settings for multi-threaded implementations. * * Returns: the preferred number of threads to use. * * Since: 3.0 **/ gint32 pika_get_num_processors (void) { return _num_processors; } /** * pika_check_size: * * Returns the size of the checkerboard to be used in previews. * * This is a constant value given at plug-in configuration time. * * Returns: the check_size value * * Since: 2.2 **/ PikaCheckSize pika_check_size (void) { return _check_size; } /** * pika_check_type: * * Returns the type of the checkerboard to be used in previews. * * This is a constant value given at plug-in configuration time. * * Returns: the check_type value * * Since: 2.2 **/ PikaCheckType pika_check_type (void) { return _check_type; } /** * pika_check_custom_color1: * * Returns the first checkerboard custom color that can * be used in previews. * * This is a constant value given at plug-in configuration time. * * Return value: the _check_custom_color1 value * * Since: 3.0 **/ const PikaRGB * pika_check_custom_color1 (void) { return &_check_custom_color1; } /** * pika_check_custom_color2: * * Returns the second checkerboard custom color that can * be used in previews. * * This is a constant value given at plug-in configuration time. * * Return value: the _check_custom_color2 value * * Since: 3.0 **/ const PikaRGB * pika_check_custom_color2 (void) { return &_check_custom_color2; } /** * pika_default_display: * * Returns the default display ID. This corresponds to the display the * running procedure's menu entry was invoked from. * * This is a constant value given at plug-in configuration time. * * Returns: (transfer none): the default display ID * The object belongs to libpika and you should not free it. **/ PikaDisplay * pika_default_display (void) { return pika_display_get_by_id (_default_display_id); } /** * pika_wm_class: * * Returns the window manager class to be used for plug-in windows. * * This is a constant value given at plug-in configuration time. * * Returns: the window manager class **/ const gchar * pika_wm_class (void) { return _wm_class; } /** * pika_display_name: * * Returns the display to be used for plug-in windows. * * This is a constant value given at plug-in configuration time. * Will return %NULL if PIKA has been started with no GUI, either * via "--no-interface" flag, or a console build. * * Returns: the display name **/ const gchar * pika_display_name (void) { return _display_name; } /** * pika_monitor_number: * * Returns the monitor number to be used for plug-in windows. * * This is a constant value given at plug-in configuration time. * * Returns: the monitor number **/ gint pika_monitor_number (void) { return _monitor_number; } /** * pika_user_time: * * Returns the timestamp of the user interaction that should be set on * the plug-in window. This is handled transparently, plug-in authors * do not have to care about it. * * This is a constant value given at plug-in configuration time. * * Returns: timestamp for plug-in window * * Since: 2.6 **/ guint32 pika_user_time (void) { return _timestamp; } /** * pika_icon_theme_dir: * * Returns the directory of the current icon theme. * * This is a constant value given at plug-in configuration time. * * Returns: the icon theme directory * * Since: 2.10.4 **/ const gchar * pika_icon_theme_dir (void) { return _icon_theme_dir; } /** * pika_get_progname: * * Returns the plug-in's executable name. * * Returns: the executable name **/ const gchar * pika_get_progname (void) { return progname; } /* private functions */ static void pika_close (void) { if (_pika_get_debug_flags () & PIKA_DEBUG_QUIT) _pika_debug_stop (); _pika_plug_in_quit (PLUG_IN); if (PDB) g_object_run_dispose (G_OBJECT (PDB)); g_clear_object (&PDB); g_object_run_dispose (G_OBJECT (PLUG_IN)); g_clear_object (&PLUG_IN); } #ifdef G_OS_WIN32 #ifdef HAVE_EXCHNDL static LONG WINAPI pika_plugin_sigfatal_handler (PEXCEPTION_POINTERS pExceptionInfo) { g_printerr ("Plugin signal handler: %s: fatal error\n", progname); SetUnhandledExceptionFilter (_prevExceptionFilter); /* For simplicity, do not make a difference between QUERY and ALWAYS * on Windows (at least not for now). */ if (stack_trace_mode != PIKA_STACK_TRACE_NEVER && g_file_test (plug_in_backtrace_path, G_FILE_TEST_IS_REGULAR)) { FILE *stream; guchar buffer[256]; size_t read_len; stream = g_fopen (plug_in_backtrace_path, "r"); do { /* Just read and output directly the file content. */ read_len = fread (buffer, 1, sizeof (buffer) - 1, stream); buffer[read_len] = '\0'; g_printerr ("%s", buffer); } while (read_len); fclose (stream); } if (_prevExceptionFilter && _prevExceptionFilter != pika_plugin_sigfatal_handler) return _prevExceptionFilter (pExceptionInfo); else return EXCEPTION_CONTINUE_SEARCH; } #endif /* HAVE_EXCHNDL */ #else /* ! G_OS_WIN32 */ static void pika_plugin_sigfatal_handler (gint sig_num) { switch (sig_num) { case SIGHUP: case SIGINT: case SIGQUIT: case SIGTERM: g_printerr ("%s terminated: %s\n", progname, g_strsignal (sig_num)); break; case SIGABRT: case SIGBUS: case SIGSEGV: case SIGFPE: case SIGPIPE: default: g_printerr ("%s: fatal error: %s\n", progname, g_strsignal (sig_num)); switch (stack_trace_mode) { case PIKA_STACK_TRACE_NEVER: break; case PIKA_STACK_TRACE_QUERY: { sigset_t sigset; sigemptyset (&sigset); sigprocmask (SIG_SETMASK, &sigset, NULL); pika_stack_trace_query (progname); } break; case PIKA_STACK_TRACE_ALWAYS: { sigset_t sigset; sigemptyset (&sigset); sigprocmask (SIG_SETMASK, &sigset, NULL); pika_stack_trace_print (progname, stdout, NULL); } break; } break; } /* Do not end with pika_quit(). * We want the plug-in to continue its normal crash course, otherwise * we won't get the "Plug-in crashed" error in PIKA. */ exit (EXIT_FAILURE); } #endif /* G_OS_WIN32 */ void _pika_config (GPConfig *config) { GFile *file; gchar *path; _tile_width = config->tile_width; _tile_height = config->tile_height; _check_size = config->check_size; _check_type = config->check_type; _check_custom_color1 = config->check_custom_color1; _check_custom_color2 = config->check_custom_color2; _show_help_button = config->show_help_button ? TRUE : FALSE; _export_color_profile = config->export_color_profile ? TRUE : FALSE; _export_exif = config->export_exif ? TRUE : FALSE; _export_xmp = config->export_xmp ? TRUE : FALSE; _export_iptc = config->export_iptc ? TRUE : FALSE; _export_comment = config->export_comment; _num_processors = config->num_processors; _default_display_id = config->default_display_id; _wm_class = g_strdup (config->wm_class); _display_name = g_strdup (config->display_name); _monitor_number = config->monitor_number; _timestamp = config->timestamp; _icon_theme_dir = g_strdup (config->icon_theme_dir); if (config->app_name) g_set_application_name (config->app_name); pika_cpu_accel_set_use (config->use_cpu_accel); file = pika_file_new_for_config_path (config->swap_path, NULL); path = g_file_get_path (file); g_object_set (gegl_config (), "tile-cache-size", config->tile_cache_size, "swap", path, "swap-compression", config->swap_compression, "threads", (gint) config->num_processors, "use-opencl", config->use_opencl, "application-license", "GPL3", NULL); g_free (path); g_object_unref (file); _pika_shm_open (config->shm_id); }