* installer/win32/dia.nsi: Save diagrams by default in "My Pictures";
[dia.git] / app / app_procs.c
blob4567125d71f75a1858fb030f9aadf1766cc1c6bf
1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/types.h>
24 #include <errno.h>
25 #include <sys/stat.h>
26 #include <string.h>
27 #include <signal.h>
28 #include <locale.h>
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
33 /* wants to be included early to avoid complains about setjmp.h */
34 #ifdef HAVE_LIBPNG
35 #include <png.h> /* just for the version stuff */
36 #endif
38 #include <gtk/gtk.h>
39 #include <gmodule.h>
41 #if (defined (HAVE_LIBPOPT) && defined (HAVE_POPT_H)) || defined (GNOME)
42 #define HAVE_POPT
43 #endif
45 #ifdef GNOME
46 #include <gnome.h>
47 #else
48 # ifdef HAVE_POPT_H
49 # include <popt.h>
50 # else
51 /* sorry about the mess, but one should not use conditional defined types in
52 * unconditional function call in the first place ... --hb */
53 typedef void* poptContext;
54 # endif
55 #endif
57 /* apparently there is no clean way to use glib-2.6 GOption with gnome */
58 #if GLIB_CHECK_VERSION(2,5,5) && !defined GNOME
59 # define USE_GOPTION 1
60 #else
61 # define USE_GOPTION 0
62 #endif
64 #ifdef HAVE_FREETYPE
65 #include <pango/pangoft2.h>
66 #endif
68 #include <libxml/parser.h>
69 #include <libxml/xmlerror.h>
71 #ifdef G_OS_WIN32
72 #include <direct.h>
73 #define mkdir(s,a) _mkdir(s)
74 #endif
76 #include "intl.h"
77 #include "app_procs.h"
78 #include "object.h"
79 #include "color.h"
80 #include "tool.h"
81 #include "interface.h"
82 #include "modify_tool.h"
83 #include "group.h"
84 #include "message.h"
85 #include "display.h"
86 #include "layer_dialog.h"
87 #include "load_save.h"
88 #include "preferences.h"
89 #include "dia_dirs.h"
90 #include "render_eps.h"
91 #include "sheet.h"
92 #include "plug-ins.h"
93 #include "recent_files.h"
94 #include "authors.h"
95 #include "autosave.h"
96 #include "dynamic_refresh.h"
97 #include "dia_image.h"
98 #include "persistence.h"
99 #include "sheets.h"
100 #include "utils.h"
102 #if defined(HAVE_LIBPNG) && defined(HAVE_LIBART)
103 extern DiaExportFilter png_export_filter;
104 #endif
106 static gboolean
107 handle_initial_diagram(const char *input_file_name,
108 const char *export_file_name,
109 const char *export_file_format,
110 const char *size,
111 char *show_layers);
113 static void create_user_dirs(void);
114 static PluginInitResult internal_plugin_init(PluginInfo *info);
115 static void process_opts(int argc, char **argv,
116 #if USE_GOPTION
117 GOptionContext* context, GOptionEntry options[],
118 #elif defined HAVE_POPT
119 poptContext poptCtx, struct poptOption options[],
120 #endif
121 GSList **files, char **export_file_name,
122 char **export_file_format, char **size,
123 char **show_layers, gboolean *nosplash);
124 static gboolean handle_all_diagrams(GSList *files, char *export_file_name,
125 char *export_file_format, char *size, char *show_layers);
126 static void print_credits(gboolean credits);
128 static gboolean dia_is_interactive = TRUE;
129 static void
130 stderr_message_internal(const char *title, const char *fmt,
131 va_list *args, va_list *args2);
133 static void
134 stderr_message_internal(const char *title, const char *fmt,
135 va_list *args, va_list *args2)
137 static gchar *buf = NULL;
138 static gint alloc = 0;
139 gint len;
141 len = format_string_length_upper_bound (fmt, args);
143 if (len >= alloc) {
144 if (buf)
145 g_free (buf);
147 alloc = nearest_pow (MAX(len + 1, 1024));
149 buf = g_new (char, alloc);
152 vsprintf (buf, fmt, *args2);
154 fprintf(stderr,
155 "%s: %s\n",
156 title,buf);
159 #ifdef GNOME
161 static void
162 session_die (gpointer client_data)
164 gtk_main_quit ();
167 static int
168 save_state (GnomeClient *client,
169 gint phase,
170 GnomeRestartStyle save_style,
171 gint shutdown,
172 GnomeInteractStyle interact_style,
173 gint fast,
174 gpointer client_data)
176 gchar *argv[20];
177 gint i = 0;
178 GList *l;
179 Diagram *dia;
181 argv[i++] = "dia";
183 for(l = dia_open_diagrams(); l != NULL; l = g_list_next(l)) {
184 dia = (Diagram *)l->data;
185 if(!dia->unsaved) {
186 argv[i++] = dia->filename;
190 gnome_client_set_restart_command (client, i, argv);
191 gnome_client_set_clone_command (client, i, argv);
193 return TRUE;
195 #endif
197 char *
198 build_output_file_name(const char *infname, const char *format)
200 /* FIXME: probably overly confident... */
201 char *p = strrchr(infname,'.');
202 char *tmp;
203 if (!p) {
204 return g_strconcat(infname,".",format,NULL);
206 tmp = g_malloc0(strlen(infname)+1+strlen(format)+1);
207 memcpy(tmp,infname,p-infname);
208 strcat(tmp,".");
209 strcat(tmp,format);
210 return tmp;
213 /* Handle the string between commas. We have either of:
215 * 1. XX, the number XX
216 * 2. -XX, every number until XX
217 * 3. XX-, every number from XX until n_layers
218 * 4. XX-YY, every number between XX-YY
220 static void
221 show_layers_parse_numbers(DiagramData *diagdata, gboolean *visible_layers, gint n_layers, const char *str)
223 char *p;
224 unsigned long int low = 0;
225 unsigned long int high = n_layers;
226 unsigned long int i;
228 if (str == NULL)
229 return;
231 /* Case 2, starts with '-' */
232 if (*str == '-') {
233 str++;
234 low = 0;
235 high = strtoul(str, &p, 10)+1;
236 /* This must be a number (otherwise we would have called parse_name) */
237 g_assert(p != str);
239 else {
240 /* Case 1, 3 or 4 */
241 low = strtoul(str, &p, 10);
242 high = low+1; /* Assume case 1 */
243 g_assert(p != str);
244 if (*p == '-')
246 /* Case 3 or 4 */
247 str = p + 1;
248 if (*str == '\0') /* Case 3 */
249 high = n_layers;
250 else
252 high = strtoul(str, &p, 10)+1;
253 g_assert(p != str);
258 if ( high <= low ) {
259 /* This is not an errror */
260 g_print(_("Warning: invalid layer range %lu - %lu\n"), low, high-1 );
261 return;
263 if (high > n_layers)
264 high = n_layers;
266 /* Set the visible layers */
267 for ( i = low; i < high; i++ )
269 Layer *lay = (Layer *)g_ptr_array_index(diagdata->layers, i);
271 if (visible_layers[i] == TRUE)
272 g_print(_("Warning: Layer %lu (%s) selected more than once.\n"), i, lay->name);
273 visible_layers[i] = TRUE;
277 static void
278 show_layers_parse_word(DiagramData *diagdata, gboolean *visible_layers, gint n_layers, const char *str)
280 GPtrArray *layers = diagdata->layers;
281 gboolean found = FALSE;
283 /* Apply --show-layers=LAYER,LAYER,... switch. 13.3.2004 sampo@iki.fi */
284 if (layers) {
285 int len,k = 0;
286 Layer *lay;
287 char *p;
288 for (k = 0; k < layers->len; k++) {
289 lay = (Layer *)g_ptr_array_index(layers, k);
291 if (lay->name) {
292 len = strlen(lay->name);
293 if ((p = strstr(str, lay->name)) != NULL) {
294 if (((p == str) || (p[-1] == ',')) /* zap false positives */
295 && ((p[len] == 0) || (p[len] == ','))){
296 found = TRUE;
297 if (visible_layers[k] == TRUE)
298 g_print(_("Warning: Layer %d (%s) selected more than once.\n"), k, lay->name);
299 visible_layers[k] = TRUE;
306 if (found == FALSE)
307 g_print(_("Warning: There is no layer named %s\n"), str);
310 static void
311 show_layers_parse_string(DiagramData *diagdata, gboolean *visible_layers, gint n_layers, const char *str)
313 gchar **pp;
314 int i;
316 pp = g_strsplit(str, ",", 100);
318 for (i = 0; pp[i]; i++) {
319 gchar *p = pp[i];
321 /* Skip the empty string */
322 if (strlen(p) == 0)
323 continue;
325 /* If the string is only numbers and '-' chars, it is parsed as a
326 * number range. Otherwise it is parsed as a layer name.
328 if (strlen(p) != strspn(p, "0123456789-") )
329 show_layers_parse_word(diagdata, visible_layers, n_layers, p);
330 else
331 show_layers_parse_numbers(diagdata, visible_layers, n_layers, p);
334 g_strfreev(pp);
338 static void
339 handle_show_layers(DiagramData *diagdata, const char *show_layers)
341 gboolean *visible_layers;
342 Layer *layer;
343 int i;
345 visible_layers = g_malloc(diagdata->layers->len * sizeof(gboolean));
346 /* Assume all layers are non-visible */
347 for (i=0;i<diagdata->layers->len;i++)
348 visible_layers[i] = FALSE;
350 /* Split the layer-range by commas */
351 show_layers_parse_string(diagdata, visible_layers, diagdata->layers->len,
352 show_layers);
354 /* Set the visibility of the layers */
355 for (i=0;i<diagdata->layers->len;i++) {
356 layer = g_ptr_array_index(diagdata->layers, i);
358 if (visible_layers[i] == TRUE)
359 layer->visible = TRUE;
360 else
361 layer->visible = FALSE;
363 g_free(visible_layers);
367 const char *argv0 = NULL;
369 /** Convert infname to outfname, using input filter inf and export filter
370 * ef. If either is null, try to guess them.
371 * size might be NULL.
373 static gboolean
374 do_convert(const char *infname,
375 const char *outfname, DiaExportFilter *ef,
376 const char *size,
377 char *show_layers)
379 DiaImportFilter *inf;
380 DiagramData *diagdata = NULL;
382 inf = filter_guess_import_filter(infname);
383 if (!inf)
384 inf = &dia_import_filter;
386 if (ef == NULL) {
387 ef = filter_guess_export_filter(outfname);
388 if (!ef) {
389 g_critical(_("%s error: don't know how to export into %s\n"),
390 argv0,outfname);
391 exit(1);
395 dia_is_interactive = FALSE;
397 if (0==strcmp(infname,outfname)) {
398 g_critical(_("%s error: input and output file name is identical: %s"),
399 argv0, infname);
400 exit(1);
403 diagdata = g_object_new (DIA_TYPE_DIAGRAM_DATA, NULL);
405 if (!inf->import_func(infname,diagdata,inf->user_data)) {
406 g_critical(_("%s error: need valid input file %s\n"),
407 argv0, infname);
408 exit(1);
411 /* Apply --show-layers */
412 if (show_layers)
413 handle_show_layers(diagdata, show_layers);
415 /* Do our best in providing the size to the filter, but don't abuse user_data
416 * too much for it. It _must not_ be changed after initialization and there
417 * are quite some filter selecting their output format by it. --hb
419 if (size) {
420 if (ef == filter_get_by_name ("png-libart")) /* the warning we get is appropriate, don't cast */
421 ef->export_func(diagdata, outfname, infname, size);
422 else {
423 g_warning ("--size parameter unsupported for %s filter",
424 ef->unique_name ? ef->unique_name : "selected");
425 ef->export_func(diagdata, outfname, infname, ef->user_data);
428 else
429 ef->export_func(diagdata, outfname, infname, ef->user_data);
430 /* if (!quiet) */ fprintf(stdout,
431 _("%s --> %s\n"),
432 infname,outfname);
433 g_object_unref(diagdata);
434 return TRUE;
437 void debug_break(void); /* shut gcc up */
438 int debug_break_dont_optimize = 1;
439 void
440 debug_break(void)
442 if (debug_break_dont_optimize > 0)
443 debug_break_dont_optimize -= 1;
446 static void
447 dump_dependencies(void)
449 #ifdef __GNUC__
450 g_print ("Compiler: GCC " __VERSION__ "\n");
451 #elif defined _MSC_VER
452 g_print ("Compiler: MSC %d\n", _MSC_VER);
453 #else
454 g_print ("Compiler: unknown\n");
455 #endif
456 /* some flags/defines which may be interesting */
457 g_print (" with : "
458 #ifdef G_THREADS_ENABLED
459 "threads "
460 #endif
461 #ifdef HAVE_CAIRO
462 "cairo "
463 #endif
464 #ifdef GNOME
465 "gnome "
466 #endif
467 #ifdef HAVE_GNOMEPRINT
468 "gnomeprint "
469 #endif
470 #ifdef HAVE_LIBART
471 "libart "
472 #endif
473 "\n");
475 /* print out all those dependies, both compile and runtime if possible
476 * Note: this is not meant to be complete but does only include libaries
477 * which may or have cause(d) us trouble in some versions
479 g_print ("Library versions\n");
480 #ifdef HAVE_LIBPNG
481 g_print ("libpng : %s (%s)\n", png_get_header_ver(NULL), PNG_LIBPNG_VER_STRING);
482 #endif
483 #ifdef HAVE_FREETYPE
485 FT_Library ft_library;
486 FT_Int ft_major_version;
487 FT_Int ft_minor_version;
488 FT_Int ft_micro_version;
490 if (FT_Init_FreeType (&ft_library) == 0) {
491 FT_Library_Version (ft_library,
492 &ft_major_version,
493 &ft_minor_version,
494 &ft_micro_version);
496 g_print ("freetype: %d.%d.%d\n", ft_major_version, ft_minor_version, ft_micro_version);
497 FT_Done_FreeType (ft_library);
499 else
500 g_print ("freetype: ?.?.?\n");
502 #endif
504 gint libxml_version = atoi(xmlParserVersion);
506 g_print ("libxml : %d.%d.%d (%s)\n",
507 libxml_version / 100 / 100, libxml_version / 100 % 100, libxml_version % 100, LIBXML_DOTTED_VERSION);
509 g_print ("glib : %d.%d.%d (%d.%d.%d)\n",
510 glib_major_version, glib_minor_version, glib_micro_version,
511 GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
512 g_print ("pango : version not available\n"); /* Pango does not provide such */
513 #if 0
515 gchar linkedname[1024];
516 gint len = 0;
518 /* relying on PREFIX is wrong */
519 if ((len = readlink (PREFIX "/lib/libpango-1.0.so", linkedname, 1023)) > 0) {
520 /* man 2 readlink : does not append a NUL character */
521 linkedname[len] = '\0';
522 g_print ("%s/%s\n", PREFIX, linkedname);
525 #endif
526 g_print ("gtk+ : %d.%d.%d (%d.%d.%d)\n",
527 gtk_major_version, gtk_minor_version, gtk_micro_version,
528 GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION);
530 #if 0
531 /* we could read $PREFIX/share/gnome-about/gnome-version.xml
532 * but is it worth the effort ? */
533 g_print ("gnome : %d.%d.%d (%d.%d.%d)\n"
534 gnome_major_version, gnome_minor_version, gnome_micro_version,
535 GNOME_MAJOR_VERSION, GNOME_MINOR_VERSION, GNOME_MICRO_VERSION);
536 #endif
539 gboolean
540 app_is_interactive(void)
542 return dia_is_interactive;
545 /** Handle loading of diagrams given on command line, including conversions.
546 * Returns TRUE if any automatic conversions were performed.
547 * Note to future hackers: 'size' is currently the only argument that can be
548 * sent to exporters. If more arguments are desired, please don't just add
549 * even more arguments, but create a more general system.
551 static gboolean
552 handle_initial_diagram(const char *in_file_name,
553 const char *out_file_name,
554 const char *export_file_format,
555 const char *size,
556 char* show_layers) {
557 DDisplay *ddisp = NULL;
558 Diagram *diagram = NULL;
559 gboolean made_conversions = FALSE;
561 if (export_file_format) {
562 char *export_file_name = NULL;
563 DiaExportFilter *ef = NULL;
565 /* First try guessing based on extension */
566 export_file_name = build_output_file_name(in_file_name,
567 export_file_format);
569 /* to make the --size hack even uglier but work again for the only filter supporting it */
570 if ( size && strcmp(export_file_format, "png") == 0)
571 ef = filter_get_by_name ("png-libart");
572 if (!ef)
573 ef = filter_guess_export_filter(export_file_name);
574 if (ef == NULL) {
575 ef = filter_get_by_name(export_file_format);
576 if (ef == NULL) {
577 g_critical(_("Can't find output format/filter %s\n"), export_file_format);
578 return FALSE;
580 g_free (export_file_name);
581 export_file_name = build_output_file_name(in_file_name,
582 ef->extensions[0]);
584 made_conversions |= do_convert(in_file_name,
585 (out_file_name != NULL?out_file_name:export_file_name),
586 ef, size, show_layers);
587 g_free(export_file_name);
588 } else if (out_file_name) {
589 DiaExportFilter *ef = NULL;
591 /* if this looks like an ugly hack to you, agreed ;) */
592 if (size && strstr(out_file_name, ".png"))
593 ef = filter_get_by_name ("png-libart");
595 made_conversions |= do_convert(in_file_name, out_file_name, ef,
596 size, show_layers);
597 } else {
598 if (g_file_test(in_file_name, G_FILE_TEST_EXISTS)) {
599 diagram = diagram_load (in_file_name, NULL);
600 } else
601 diagram = new_diagram (in_file_name);
603 if (diagram != NULL) {
604 diagram_update_extents(diagram);
605 if (app_is_interactive()) {
606 layer_dialog_set_diagram(diagram);
607 /* the display initial diagram holds two references */
608 ddisp = new_display(diagram);
609 } else {
610 g_object_unref(diagram);
614 return made_conversions;
617 #ifdef G_OS_WIN32
618 static void
619 myXmlErrorReporting (void *ctx, const char* msg, ...)
621 va_list args;
622 gchar *string;
624 va_start(args, msg);
625 string = g_strdup_vprintf (msg, args);
626 g_print ("%s", string ? string : "xml error (null)?");
627 va_end(args);
629 g_free(string);
631 #endif
633 #ifdef HAVE_FREETYPE
634 /* Translators: This is an option, not to be translated */
635 #define EPS_PANGO "eps-pango, "
636 #else
637 #define EPS_PANGO ""
638 #endif
640 #ifdef G_OS_WIN32
641 /* Translators: This is an option, not to be translated */
642 #define WMF "wmf, "
643 #else
644 #define WMF ""
645 #endif
647 void
648 app_init (int argc, char **argv)
650 static gboolean nosplash = FALSE;
651 static gboolean nonew = FALSE;
652 static gboolean credits = FALSE;
653 static gboolean version = FALSE;
654 static gboolean verbose = FALSE;
655 static gboolean log_to_stderr = FALSE;
656 #ifdef GNOME
657 GnomeClient *client;
658 #endif
659 static char *export_file_name = NULL;
660 static char *export_file_format = NULL;
661 static char *size = NULL;
662 static char *show_layers = NULL;
663 gboolean made_conversions = FALSE;
664 GSList *files = NULL;
666 gchar *export_format_string =
667 /* Translators: The argument is a list of options, not to be translated */
668 g_strdup_printf(_("Select the filter/format out of: %s"),
669 "cgm, dia, dxf, eps, eps-builtin, " EPS_PANGO
670 "fig, mp, plt, hpgl, png ("
671 # if defined(HAVE_LIBPNG) && defined(HAVE_LIBART)
672 "png-libart, "
673 # endif
674 # ifdef HAVE_CAIRO
675 "cairo-png, cairo-alpha-png, "
676 # endif
677 /* we always have pixbuf but don't know exactly all it's *few* save formats */
678 "pixbuf-png), jpg, "
679 "shape, svg, tex, " WMF
680 "wpg");
682 #if USE_GOPTION
683 GOptionContext *context = NULL;
684 static GOptionEntry options[] =
686 {"export", 'e', 0, G_OPTION_ARG_STRING, NULL /* &export_file_name */,
687 N_("Export loaded file and exit"), N_("OUTPUT")},
688 {"filter",'t', 0, G_OPTION_ARG_STRING, NULL /* &export_file_format */,
689 NULL /* &export_format_string */, N_("TYPE") },
690 {"size", 's', 0, G_OPTION_ARG_STRING, NULL,
691 N_("Export graphics size"), N_("WxH")},
692 {"show-layers", 'L', 0, G_OPTION_ARG_STRING, NULL,
693 N_("Show only specified layers (e.g. when exporting). Can be either the layer name or a range of layer numbers (X-Y)"),
694 N_("LAYER,LAYER,...")},
695 {"nosplash", 'n', 0, G_OPTION_ARG_NONE, &nosplash,
696 N_("Don't show the splash screen"), NULL },
697 {"nonew", 'n', 0, G_OPTION_ARG_NONE, &nonew,
698 N_("Don't create empty diagram"), NULL },
699 {"log-to-stderr", 'l', 0, G_OPTION_ARG_NONE, &log_to_stderr,
700 N_("Send error messages to stderr instead of showing dialogs."), NULL },
701 {"credits", 'c', 0, G_OPTION_ARG_NONE, &credits,
702 N_("Display credits list and exit"), NULL },
703 {"verbose", 0, 0, G_OPTION_ARG_NONE, &verbose,
704 N_("Generate verbose output"), NULL },
705 {"version", 'v', 0, G_OPTION_ARG_NONE, &version,
706 N_("Display version and exit"), NULL },
707 { NULL }
709 #elif defined HAVE_POPT
710 poptContext context = NULL;
711 struct poptOption options[] =
713 {"export", 'e', POPT_ARG_STRING, NULL /* &export_file_name */, 0,
714 N_("Export loaded file and exit"), N_("OUTPUT")},
715 {"filter",'t', POPT_ARG_STRING, NULL /* &export_file_format */,
716 0, export_format_string, N_("TYPE")
718 {"size", 's', POPT_ARG_STRING, NULL, 0,
719 N_("Export graphics size"), N_("WxH")},
720 {"show-layers", 'L', POPT_ARG_STRING, NULL, 0, /* 13.3.2004 sampo@iki.fi */
721 N_("Show only specified layers (e.g. when exporting). Can be either the layer name or a range of layer numbers (X-Y)"),
722 N_("LAYER,LAYER,...")},
723 {"nosplash", 'n', POPT_ARG_NONE, &nosplash, 0,
724 N_("Don't show the splash screen"), NULL },
725 {"nonew", 'n', POPT_ARG_NONE, &nonew, 0,
726 N_("Don't create empty diagram"), NULL },
727 {"log-to-stderr", 'l', POPT_ARG_NONE, &log_to_stderr, 0,
728 N_("Send error messages to stderr instead of showing dialogs."), NULL },
729 {"credits", 'c', POPT_ARG_NONE, &credits, 0,
730 N_("Display credits list and exit"), NULL },
731 {"verbose", 0, POPT_ARG_NONE, &verbose, 0,
732 N_("Generate verbose output"), NULL },
733 {"version", 'v', POPT_ARG_NONE, &version, 0,
734 N_("Display version and exit"), NULL },
735 {"help", 'h', POPT_ARG_NONE, 0, 1, N_("Show this help message") },
736 {(char *) NULL, '\0', 0, NULL, 0}
738 #endif
740 #if USE_GOPTION
741 options[0].arg_data = &export_file_name;
742 options[1].arg_data = &export_file_format;
743 options[1].description = export_format_string;
744 options[2].arg_data = &size;
745 options[3].arg_data = &show_layers;
746 #elif defined HAVE_POPT
747 options[0].arg = &export_file_name;
748 options[1].arg = &export_file_format;
749 options[2].arg = &size;
750 options[3].arg = &show_layers;
751 #endif
753 argv0 = (argc > 0) ? argv[0] : "(none)";
755 gtk_set_locale();
756 setlocale(LC_NUMERIC, "C");
758 #ifdef G_OS_WIN32
759 /* calculate runtime directory */
761 gchar* localedir = dia_get_lib_directory ("locale");
763 bindtextdomain(GETTEXT_PACKAGE, localedir);
764 g_free (localedir);
766 #else
767 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
768 #endif
769 textdomain(GETTEXT_PACKAGE);
771 process_opts(argc, argv,
772 #if defined HAVE_POPT || USE_GOPTION
773 context, options,
774 #endif
775 &files,
776 &export_file_name, &export_file_format, &size, &show_layers, &nosplash);
778 #if defined ENABLE_NLS && defined HAVE_BIND_TEXTDOMAIN_CODESET
779 bind_textdomain_codeset(GETTEXT_PACKAGE,"UTF-8");
780 #endif
781 textdomain(GETTEXT_PACKAGE);
783 if (argv && dia_is_interactive && !version) {
784 #ifdef GNOME
785 GnomeProgram *program =
786 gnome_program_init (PACKAGE, VERSION, LIBGNOMEUI_MODULE,
787 argc, argv,
788 /* haven't found a quick way to pass GOption here */
789 GNOME_PARAM_POPT_TABLE, options,
790 GNOME_PROGRAM_STANDARD_PROPERTIES,
791 GNOME_PARAM_NONE);
792 g_object_get(program, "popt-context", &context, NULL);
793 client = gnome_master_client();
794 if(client == NULL) {
795 g_warning(_("Can't connect to session manager!\n"));
797 else {
798 g_signal_connect(GTK_OBJECT (client), "save_yourself",
799 G_CALLBACK (save_state), NULL);
800 g_signal_connect(GTK_OBJECT (client), "die",
801 G_CALLBACK (session_die), NULL);
804 /* This smaller icon is 48x48, standard Gnome size */
805 gnome_window_icon_set_default_from_file (GNOME_ICONDIR"/dia_gnome_icon.png");
807 #else
808 # ifdef G_THREADS_ENABLED
809 g_thread_init (NULL);
810 # endif
811 gtk_init(&argc, &argv);
812 #endif
814 else {
815 #ifdef G_THREADS_ENABLED
816 g_thread_init (NULL);
817 #endif
818 g_type_init();
819 #ifdef GDK_WINDOWING_WIN32
821 * On windoze there is no command line without display so this call is harmless.
822 * But it is needed to avoid failing in gdk functions just because there is a
823 * display check. Still a little hack ...
825 gtk_init(&argc, &argv);
826 #endif
829 /* done with option parsing, don't leak */
830 g_free(export_format_string);
832 if (version) {
833 #if (defined __TIME__) && (defined __DATE__)
834 /* TRANSLATOR: 2nd and 3rd %s are time and date respectively. */
835 printf(g_locale_from_utf8(_("Dia version %s, compiled %s %s\n"), -1, NULL, NULL, NULL), VERSION, __TIME__, __DATE__);
836 #else
837 printf(g_locale_from_utf8(_("Dia version %s\n"), -1, NULL, NULL, NULL), VERSION);
838 #endif
839 if (verbose)
840 dump_dependencies();
841 exit(0);
844 if (!dia_is_interactive)
845 log_to_stderr = TRUE;
847 if (log_to_stderr)
848 set_message_func(stderr_message_internal);
850 print_credits(credits);
852 LIBXML_TEST_VERSION;
854 #ifdef G_OS_WIN32
855 xmlSetGenericErrorFunc(NULL, myXmlErrorReporting);
856 #endif
858 stdprops_init();
860 if (dia_is_interactive) {
861 dia_image_init();
863 gdk_rgb_init();
865 gtk_rc_parse("diagtkrc");
867 if (!nosplash) {
868 app_splash_init("");
872 if (dia_is_interactive)
873 create_user_dirs();
875 /* Init cursors: */
876 if (dia_is_interactive) {
877 color_init();
878 default_cursor = gdk_cursor_new(GDK_LEFT_PTR);
879 ddisplay_set_all_cursor(default_cursor);
882 object_registry_init();
884 dia_register_plugins();
885 dia_register_builtin_plugin(internal_plugin_init);
887 load_all_sheets(); /* new mechanism */
889 dia_object_defaults_load (NULL, TRUE /* prefs.object_defaults_create_lazy */);
891 debug_break();
893 if (object_get_type("Standard - Box") == NULL) {
894 message_error(_("Couldn't find standard objects when looking for "
895 "object-libs; exiting...\n"));
896 g_critical( _("Couldn't find standard objects when looking for "
897 "object-libs in '%s'; exiting...\n"), dia_get_lib_directory("dia"));
898 exit(1);
901 persistence_load();
903 /** Must load prefs after persistence */
904 prefs_init();
906 if (dia_is_interactive) {
908 /* further initialization *before* reading files */
909 active_tool = create_modify_tool();
911 create_toolbox();
913 persistence_register_window_create("layer_window",
914 (NullaryFunc*)&create_layer_dialog);
917 /*fill recent file menu */
918 recent_file_history_init();
920 /* Set up autosave to check every 5 minutes */
921 gtk_timeout_add(5*60*1000, autosave_check_autosave, NULL);
923 create_tree_window();
925 persistence_register_window_create("sheets_main_dialog",
926 (NullaryFunc*)&sheets_dialog_create);
929 /* In current setup, we can't find the autosaved files. */
930 /*autosave_restore_documents();*/
934 made_conversions = handle_all_diagrams(files, export_file_name,
935 export_file_format, size, show_layers);
936 if (dia_is_interactive && files == NULL && !nonew) {
937 gchar *filename = g_filename_from_utf8(_("Diagram1.dia"), -1, NULL, NULL, NULL);
938 Diagram *diagram = new_diagram (filename);
939 g_free(filename);
942 if (diagram != NULL) {
943 diagram_update_extents(diagram);
944 if (app_is_interactive()) {
945 layer_dialog_set_diagram(diagram);
946 new_display(diagram);
950 g_slist_free(files);
951 if (made_conversions) exit(0);
953 dynobj_refresh_init();
956 #if 0
957 /* app_procs.c: warning: `set_true_callback' defined but not used */
958 static void
959 set_true_callback(GtkWidget *w, int *data)
961 *data = TRUE;
963 #endif
965 gboolean
966 app_exit(void)
968 GList *list;
969 GSList *slist;
972 * The following "solves" a crash related to a second call of app_exit,
973 * after gtk_main_quit was called. It may be a win32 gtk-1.3.x bug only
974 * but the check shouldn't hurt on *ix either. --hb
976 static gboolean app_exit_once = FALSE;
978 if (app_exit_once) {
979 g_error(_("This shouldn't happen. Please file a bug report at bugzilla.gnome.org\n"
980 "describing how you can cause this message to appear.\n"));
981 return FALSE;
984 if (diagram_modified_exists()) {
985 GtkWidget *dialog;
986 GtkWidget *button;
988 dialog = gtk_message_dialog_new(
989 NULL, GTK_DIALOG_MODAL,
990 GTK_MESSAGE_QUESTION,
991 GTK_BUTTONS_NONE, /* no standard buttons */
992 _("Quitting without saving modified diagrams"));
993 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
994 _("Modified diagrams exist. "
995 "Are you sure you want to quit Dia "
996 "without saving them?"));
998 gtk_window_set_title (GTK_WINDOW(dialog), _("Quit Dia"));
1000 button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
1001 gtk_dialog_add_action_widget (GTK_DIALOG(dialog), button, GTK_RESPONSE_CANCEL);
1002 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1003 gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
1005 button = gtk_button_new_from_stock (GTK_STOCK_QUIT);
1006 gtk_dialog_add_action_widget (GTK_DIALOG(dialog), button, GTK_RESPONSE_OK);
1008 gtk_widget_show_all (dialog);
1010 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_OK) {
1011 gtk_widget_destroy(dialog);
1012 return FALSE;
1014 gtk_widget_destroy(dialog);
1016 prefs_save();
1018 persistence_save();
1020 dynobj_refresh_finish();
1022 dia_object_defaults_save (NULL);
1024 /* Free loads of stuff (toolbox) */
1026 list = dia_open_diagrams();
1027 while (list!=NULL) {
1028 Diagram *dia = (Diagram *)list->data;
1029 list = g_list_next(list);
1031 slist = dia->displays;
1032 while (slist!=NULL) {
1033 DDisplay *ddisp = (DDisplay *)slist->data;
1034 slist = g_slist_next(slist);
1036 gtk_widget_destroy(ddisp->shell);
1039 /* The diagram is freed when the last display is destroyed */
1043 /* save pluginrc */
1044 if (dia_is_interactive)
1045 dia_pluginrc_write();
1047 gtk_main_quit();
1048 #ifndef G_OS_WIN32
1049 /* This printf seems to prevent a race condition with unrefs. */
1050 /* Yuck. -Lars */
1051 g_print(_("Thank you for using Dia.\n"));
1052 #endif
1053 app_exit_once = TRUE;
1055 return TRUE;
1058 static void create_user_dirs(void)
1060 gchar *dir, *subdir;
1062 #ifdef G_OS_WIN32
1063 /* not necessary to quit the program with g_error, everywhere else
1064 * dia_config_filename appears to be used. Spit out a warning ...
1066 if (!g_get_home_dir())
1068 g_warning(_("Could not create per-user Dia config directory"));
1069 return; /* ... and return. Probably removes my one and only FAQ. --HB */
1071 #endif
1072 dir = g_strconcat(g_get_home_dir(), G_DIR_SEPARATOR_S ".dia", NULL);
1073 if (mkdir(dir, 0755) && errno != EEXIST) {
1074 #ifndef G_OS_WIN32
1075 g_critical(_("Could not create per-user Dia config directory"));
1076 exit(1);
1077 #else /* HB: it this really a reason to exit the program on *nix ? */
1078 g_warning(_("Could not create per-user Dia config directory. Please make "
1079 "sure that the environment variable HOME points to an existing directory."));
1080 #endif
1083 /* it is no big deal if these directories can't be created */
1084 subdir = g_strconcat(dir, G_DIR_SEPARATOR_S "objects", NULL);
1085 mkdir(subdir, 0755);
1086 g_free(subdir);
1087 subdir = g_strconcat(dir, G_DIR_SEPARATOR_S "shapes", NULL);
1088 mkdir(subdir, 0755);
1089 g_free(subdir);
1090 subdir = g_strconcat(dir, G_DIR_SEPARATOR_S "sheets", NULL);
1091 mkdir(subdir, 0755);
1092 g_free(subdir);
1094 g_free(dir);
1097 static PluginInitResult
1098 internal_plugin_init(PluginInfo *info)
1100 if (!dia_plugin_info_init(info, "Internal",
1101 _("Objects and filters internal to dia"),
1102 NULL, NULL))
1103 return DIA_PLUGIN_INIT_ERROR;
1105 /* register the group object type */
1106 object_register_type(&group_type);
1108 /* register import filters */
1109 filter_register_import(&dia_import_filter);
1111 /* register export filters */
1112 /* Standard Dia format */
1113 filter_register_export(&dia_export_filter);
1114 /* EPS with PS fonts */
1115 filter_register_export(&eps_export_filter);
1116 #ifdef HAVE_FREETYPE
1117 /* EPS with Pango rendering */
1118 filter_register_export(&eps_ft2_export_filter);
1119 #endif
1120 #if defined(HAVE_LIBPNG) && defined(HAVE_LIBART)
1121 /* PNG with libart rendering */
1122 filter_register_export(&png_export_filter);
1123 #endif
1125 return DIA_PLUGIN_INIT_OK;
1128 /* Note: running in locale encoding */
1129 static void
1130 process_opts(int argc, char **argv,
1131 #if USE_GOPTION
1132 GOptionContext *context, GOptionEntry options[],
1133 #elif defined HAVE_POPT
1134 poptContext poptCtx, struct poptOption options[],
1135 #endif
1136 GSList **files, char **export_file_name,
1137 char **export_file_format, char **size,
1138 char **show_layers, gboolean* nosplash)
1140 #if defined HAVE_POPT && !USE_GOPTION
1141 int rc = 0;
1142 poptCtx = poptGetContext(PACKAGE, argc, (const char **)argv, options, 0);
1143 poptSetOtherOptionHelp(poptCtx, _("[OPTION...] [FILE...]"));
1144 while (rc >= 0) {
1145 if((rc = poptGetNextOpt(poptCtx)) < -1) {
1146 fprintf(stderr,_("Error on option %s: %s.\nRun '%s --help' to see a full list of available command line options.\n"),
1147 poptBadOption(poptCtx, 0),
1148 poptStrerror(rc),
1149 argv[0]);
1150 exit(1);
1152 if(rc == 1) {
1153 poptPrintHelp(poptCtx, stderr, 0);
1154 exit(0);
1157 #endif
1158 if (argv) {
1159 #if defined HAVE_POPT && !USE_GOPTION
1160 while (poptPeekArg(poptCtx)) {
1161 char *in_file_name = (char *)poptGetArg(poptCtx);
1162 if (*in_file_name != '\0')
1163 *files = g_slist_append(*files, in_file_name);
1165 poptFreeContext(poptCtx);
1166 #elif USE_GOPTION
1167 GError *error = NULL;
1168 int i;
1170 context = g_option_context_new(_("[FILE...]"));
1171 g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE);
1172 # if GTK_CHECK_VERSION(2,5,7)
1173 /* at least Gentoo was providing GLib-2.6 but Gtk+-2.4.14 */
1174 g_option_context_add_group (context, gtk_get_option_group (FALSE));
1175 # endif
1176 if (!g_option_context_parse (context, &argc, &argv, &error)) {
1177 if (error) { /* IMO !error here is a bug upstream, triggered with --gdk-debug=updates */
1178 g_print ("%s", error->message);
1179 g_error_free (error);
1180 } else {
1181 g_print ("Invalid option?");
1184 g_option_context_free(context);
1185 exit(0);
1187 if (argc < 2) {
1188 g_option_context_free(context);
1189 return;
1191 for (i = 1; i < argc; i++) {
1192 if (!g_file_test (argv[i], G_FILE_TEST_IS_REGULAR)) {
1193 g_print (_("'%s' not found!\n"), argv[i]);
1194 g_option_context_free(context);
1195 exit(2);
1197 *files = g_slist_append(*files, argv[i]);
1199 g_option_context_free(context);
1200 #else
1201 int i;
1203 for (i=1; i<argc; i++) {
1204 char *in_file_name = argv[i]; /* unless it's an option... */
1206 if (0==strcmp(argv[i],"-t")) {
1207 if (i < (argc-1)) {
1208 i++;
1209 *export_file_format = argv[i];
1210 continue;
1212 } else if (0 == strcmp(argv[i],"-e")) {
1213 if (i < (argc-1)) {
1214 i++;
1215 *export_file_name = argv[i];
1216 continue;
1218 } else if (0 == strcmp(argv[i],"-s")) {
1219 if (i < (argc-1)) {
1220 i++;
1221 *size = argv[i];
1222 continue;
1224 } else if (0 == strcmp(argv[i],"-L")) {
1225 if (i < (argc-1)) {
1226 i++;
1227 *show_layers = argv[i];
1228 continue;
1230 } else if (0 == strcmp(argv[i],"-n")) {
1231 *nosplash = 1;
1232 continue;
1234 *files = g_slist_append(*files, in_file_name);
1236 #endif
1238 if (*export_file_name || *export_file_format || *size)
1239 dia_is_interactive = FALSE;
1242 static gboolean
1243 handle_all_diagrams(GSList *files, char *export_file_name,
1244 char *export_file_format, char *size, char *show_layers)
1246 GSList *node = NULL;
1247 gboolean made_conversions = FALSE;
1249 for (node = files; node; node = node->next) {
1250 made_conversions |=
1251 handle_initial_diagram(node->data, export_file_name,
1252 export_file_format, size, show_layers);
1254 return made_conversions;
1257 /* --credits option. Added by Andrew Ferrier.
1259 Hopefully we're not ignoring anything too crucial by
1260 quitting directly after the credits.
1262 The phrasing of the English here might need changing
1263 if we switch from plural to non-plural (say, only
1264 one maintainer).
1266 static void
1267 print_credits(gboolean credits)
1269 if (credits) {
1270 int i;
1271 const gint nauthors = (sizeof(authors) / sizeof(authors[0])) - 1;
1272 const gint ndocumentors = (sizeof(documentors) / sizeof(documentors[0])) - 1;
1274 g_print(_("The original author of Dia was:\n\n"));
1275 for (i = 0; i < NUMBER_OF_ORIG_AUTHORS; i++) {
1276 g_print("%s\n", authors[i]);
1279 g_print(_("\nThe current maintainers of Dia are:\n\n"));
1280 for (i = NUMBER_OF_ORIG_AUTHORS; i < NUMBER_OF_ORIG_AUTHORS + NUMBER_OF_MAINTAINERS; i++) {
1281 g_print("%s\n", authors[i]);
1284 g_print(_("\nOther authors are:\n\n"));
1285 for (i = NUMBER_OF_ORIG_AUTHORS + NUMBER_OF_MAINTAINERS; i < nauthors; i++) {
1286 g_print("%s\n", authors[i]);
1289 g_print(_("\nDia is documented by:\n\n"));
1290 for (i = 0; i < ndocumentors; i++) {
1291 g_print("%s\n", documentors[i]);
1294 exit(0);
1298 /* parses a string of the form "[0-9]*x[0-9]*" and transforms it into
1299 two long values width and height. */
1300 void
1301 parse_size(gchar *size, long *width, long *height)
1303 if (size) {
1304 gchar** array = g_strsplit(size, "x", 3);
1305 *width = (array[0])? strtol(array[0], NULL, 10): 0;
1306 *height = (array[1])? strtol(array[1], NULL, 10): 0;
1307 g_strfreev(array);
1309 else {
1310 *width = 0;
1311 *height = 0;
1315 int app_is_embedded(void)
1317 return 0;