2 * Grace - GRaphing, Advanced Computation and Exploration of data
4 * Home page: http://plasma-gate.weizmann.ac.il/Grace/
6 * Copyright (c) 2001-2006 Grace Development Team
8 * Maintained by Evgeny Stambulchik
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 # include <cups/cups.h>
41 #include "core_utils.h"
44 GUI
*gui_new(GraceApp
*gapp
)
48 gui
= xmalloc(sizeof(GUI
));
52 memset(gui
, 0, sizeof(GUI
));
60 gui
->focus_policy
= FOCUS_CLICK
;
61 gui
->draw_focus_flag
= TRUE
;
63 gui
->crosshair_cursor
= FALSE
;
67 gui
->instant_update
= FALSE
;
69 gui
->statusbar
= TRUE
;
72 gui
->install_cmap
= CMAP_INSTALL_AUTO
;
73 gui
->private_cmap
= FALSE
;
75 #if defined WITH_XMHTML
76 gui
->force_external_viewer
= FALSE
;
78 gui
->force_external_viewer
= TRUE
;
84 void gui_free(GUI
*gui
)
93 RunTime
*runtime_new(GraceApp
*gapp
)
98 rt
= xmalloc(sizeof(RunTime
));
102 memset(rt
, 0, sizeof(RunTime
));
107 rt
->print_dests
= NULL
;
108 rt
->print_cmd
= NULL
;
109 rt
->gapp_editor
= NULL
;
110 rt
->help_viewer
= NULL
;
111 rt
->workingdir
= NULL
;
116 rt
->use_cups
= FALSE
;
120 if ((s
= getenv("GRACE_PRINT_CMD")) == NULL
) {
123 rt
->print_cmd
= copy_string(NULL
, s
);
127 /* if no print command defined, print to file by default */
128 if (string_is_empty(rt
->print_cmd
)) {
135 if ((s
= getenv("GRACE_EDITOR")) == NULL
) {
138 rt
->gapp_editor
= copy_string(NULL
, s
);
141 if ((s
= getenv("GRACE_HELPVIEWER")) == NULL
) {
144 rt
->help_viewer
= copy_string(NULL
, s
);
145 if (!strstr(rt
->help_viewer
, "%s")) {
146 rt
->help_viewer
= concat_strings(rt
->help_viewer
, " %s");
149 /* working directory */
150 rt
->workingdir
= xmalloc(GR_MAXPATHLEN
);
151 if (!getcwd(rt
->workingdir
, GR_MAXPATHLEN
- 1)) {
155 if (rt
->workingdir
[strlen(rt
->workingdir
)-1] != '/') {
156 rt
->workingdir
= concat_strings(rt
->workingdir
, "/");
159 if (!rt
->print_cmd
||
167 if (gapp_init_print(rt
) != RETURN_SUCCESS
) {
172 rt
->print_file
[0] = '\0';
177 rt
->date_hint
= FMT_nohint
;
179 rt
->timer_delay
= 200;
181 rt
->autoscale_onread
= AUTOSCALE_XY
;
184 rt
->scrollper
= 0.05;
189 rt
->emergency_save
= FALSE
;
195 void runtime_free(RunTime
*rt
)
203 for (i
= 0; i
< rt
->num_print_dests
; i
++) {
204 PrintDest
*pd
= &rt
->print_dests
[i
];
209 for (j
= 0; j
< pd
->nogroups
; j
++) {
210 PrintOptGroup
*og
= &pd
->ogroups
[j
];
214 for (k
= 0; k
< og
->nopts
; k
++) {
215 PrintOption
*po
= &og
->opts
[k
];
218 dict_free(po
->choices
);
224 xfree(rt
->print_dests
);
226 xfree(rt
->print_cmd
);
227 xfree(rt
->gapp_editor
);
228 xfree(rt
->help_viewer
);
229 xfree(rt
->workingdir
);
232 gapp_close(rt
->resfp
);
238 static void eval_proc(GVarType type
, GVarData vardata
, void *udata
)
246 stufftext("(nil)\n");
249 sprintf(buf
, "%g\n", vardata
.num
);
253 stufftext(vardata
.boolval
? "true":"false");
259 for (i
= 0; da
&& i
< da
->size
; i
++) {
260 sprintf(buf
, " %g ", da
->x
[i
]);
266 stufftext(vardata
.str
);
270 errmsg("unknown data type");
275 GraceApp
*gapp_new(void)
279 gapp
= xmalloc(sizeof(GraceApp
));
283 memset(gapp
, 0, sizeof(GraceApp
));
285 if (grace_init() != RETURN_SUCCESS
) {
290 gapp
->grace
= grace_new(bi_home());
295 graal_set_eval_proc(grace_get_graal(gapp
->grace
), eval_proc
);
297 grace_set_udata(gapp
->grace
, gapp
);
299 gapp
->rt
= runtime_new(gapp
);
305 gapp
->gui
= gui_new(gapp
);
311 gapp
->pc
= container_new(grace_get_qfactory(gapp
->grace
), AMEM_MODEL_SIMPLE
);
320 void gapp_free(GraceApp
*gapp
)
328 for (i
= 0; i
< gapp
->gpcount
; i
++) {
329 gproject_free(gapp
->gplist
[i
]);
333 quark_free(gapp
->pc
);
335 runtime_free(gapp
->rt
);
336 grace_free(gapp
->grace
);
341 GraceApp
*gapp_from_quark(const Quark
*q
)
343 GraceApp
*gapp
= NULL
;
345 Grace
*grace
= grace_from_quark(q
);
346 gapp
= grace_get_udata(grace
);
352 RunTime
*rt_from_quark(const Quark
*q
)
354 GraceApp
*gapp
= gapp_from_quark(q
);
362 GUI
*gui_from_quark(const Quark
*q
)
364 GraceApp
*gapp
= gapp_from_quark(q
);
372 GProject
*gproject_from_quark(const Quark
*q
)
377 Quark
*project
= get_parent_project(q
);
383 gapp
= gapp_from_quark(project
);
385 for (i
= 0; i
< gapp
->gpcount
; i
++) {
386 gp
= gapp
->gplist
[i
];
387 if (gproject_get_top(gp
) == project
) {
395 int gapp_add_gproject(GraceApp
*gapp
, GProject
*gp
)
400 return RETURN_FAILURE
;
403 p
= xrealloc(gapp
->gplist
, (gapp
->gpcount
+ 1)*sizeof(GProject
));
405 return RETURN_FAILURE
;
409 gapp
->gplist
[gapp
->gpcount
] = gp
;
412 return RETURN_SUCCESS
;
415 int gapp_delete_gproject(GraceApp
*gapp
, GProject
*gp
)
417 unsigned int i
, j
= 0;
422 return RETURN_FAILURE
;
425 p
= xmalloc((gapp
->gpcount
- 1)*sizeof(GProject
));
427 return RETURN_FAILURE
;
430 for (i
= 0; i
< gapp
->gpcount
; i
++) {
431 gpr
= gapp
->gplist
[i
];
444 if (gapp
->gp
== gp
) {
450 return RETURN_SUCCESS
;
453 int gapp_set_active_gproject(GraceApp
*gapp
, GProject
*gp
)
456 return RETURN_FAILURE
;
460 quark_set_active2(gproject_get_top(gapp
->gp
), FALSE
);
462 quark_set_active2(gproject_get_top(gp
), TRUE
);
467 /* Set dimensions of all devices */
468 grace_sync_canvas_devices(gp
);
470 /* Reset set autocolorization index */
471 gapp
->rt
->setcolor
= 0;
473 /* Request update of color selectors */
474 gapp
->gui
->need_colorsel_update
= TRUE
;
476 /* Request update of font selectors */
477 gapp
->gui
->need_fontsel_update
= TRUE
;
479 clean_graph_selectors(NULL
, QUARK_ETYPE_DELETE
, NULL
);
480 clean_frame_selectors(NULL
, QUARK_ETYPE_DELETE
, NULL
);
482 return RETURN_SUCCESS
;
485 int gapp_set_gproject_id(GraceApp
*gapp
, GProject
*gp
, int id
)
487 Quark
*q
= gproject_get_top(gp
);
489 return quark_move2(q
, quark_parent_get(q
), id
);
492 int gapp_get_gproject_id(GraceApp
*gapp
, GProject
*gp
)
494 Quark
*q
= gproject_get_top(gp
);
496 return quark_get_id(q
);
500 * flag to indicate destination of hardcopy output,
501 * ptofile = 0 means print to printer, otherwise print to file
503 void set_ptofile(GraceApp
*gapp
, int flag
)
505 gapp
->rt
->ptofile
= flag
;
508 int get_ptofile(const GraceApp
*gapp
)
510 return gapp
->rt
->ptofile
;
514 * set the current print device
516 int set_printer(GraceApp
*gapp
, int device
)
518 Canvas
*canvas
= grace_get_canvas(gapp
->grace
);
519 Device_entry
*d
= get_device_props(canvas
, device
);
520 if (!d
|| d
->type
== DEVICE_TERM
) {
521 return RETURN_FAILURE
;
523 gapp
->rt
->hdevice
= device
;
524 if (d
->type
!= DEVICE_PRINT
) {
525 set_ptofile(gapp
, TRUE
);
527 return RETURN_SUCCESS
;
531 int set_printer_by_name(GraceApp
*gapp
, const char *dname
)
533 Canvas
*canvas
= grace_get_canvas(gapp
->grace
);
536 device
= get_device_by_name(canvas
, dname
);
538 return set_printer(gapp
, device
);
541 int set_page_dimensions(GraceApp
*gapp
, int wpp
, int hpp
, int rescale
)
543 if (wpp
<= 0 || hpp
<= 0 || !gapp
|| !gapp
->gp
) {
544 return RETURN_FAILURE
;
546 int wpp_old
, hpp_old
;
547 Project
*pr
= project_get_data(gproject_get_top(gapp
->gp
));
549 return RETURN_FAILURE
;
552 wpp_old
= pr
->page_wpp
;
553 hpp_old
= pr
->page_hpp
;
558 if (hpp
*wpp_old
- wpp
*hpp_old
!= 0) {
559 /* aspect ratio changed */
561 double old_aspectr
, new_aspectr
;
563 old_aspectr
= (double) wpp_old
/hpp_old
;
564 new_aspectr
= (double) wpp
/hpp
;
565 if (old_aspectr
>= 1.0 && new_aspectr
>= 1.0) {
566 ext_x
= new_aspectr
/old_aspectr
;
568 } else if (old_aspectr
<= 1.0 && new_aspectr
<= 1.0) {
570 ext_y
= old_aspectr
/new_aspectr
;
571 } else if (old_aspectr
>= 1.0 && new_aspectr
<= 1.0) {
572 ext_x
= 1.0/old_aspectr
;
573 ext_y
= 1.0/new_aspectr
;
579 rescale_viewport(gproject_get_top(gapp
->gp
), ext_x
, ext_y
);
583 grace_sync_canvas_devices(gapp
->gp
);
585 return RETURN_SUCCESS
;
590 static void parse_group(PrintDest
*pd
, ppd_group_t
*group
)
592 int i
, j
; /* Looping vars */
593 ppd_option_t
*option
; /* Current option */
594 ppd_choice_t
*choice
; /* Current choice */
595 ppd_group_t
*subgroup
; /* Current subgroup */
599 pd
->ogroups
= xrealloc(pd
->ogroups
, (pd
->nogroups
+ 1)*sizeof(PrintOptGroup
));
604 og
= &pd
->ogroups
[pd
->nogroups
];
607 og
->name
= copy_string(NULL
, group
->name
);
608 og
->text
= copy_string(NULL
, group
->text
);
610 og
->opts
= xcalloc(group
->num_options
, sizeof(PrintOption
));
616 for (i
= 0, option
= group
->options
, po
= og
->opts
; i
< group
->num_options
; i
++, option
++) {
617 po
->name
= copy_string(NULL
, option
->keyword
);
618 po
->text
= copy_string(NULL
, option
->text
);
620 po
->choices
= dict_new();
622 dict_resize(po
->choices
, option
->num_choices
);
623 for (j
= 0, choice
= option
->choices
; j
< option
->num_choices
; j
++, choice
++) {
627 de
.name
= choice
->choice
;
628 de
.descr
= choice
->text
;
629 dict_entry_copy(&po
->choices
->entries
[j
], &de
);
631 if (choice
->marked
) {
632 po
->selected
= de
.key
;
633 dict_entry_copy(&po
->choices
->defaults
, &de
);
636 if (po
->selected
!= -1) {
643 dict_free(po
->choices
);
647 for (i
= 0, subgroup
= group
->subgroups
; i
< group
->num_subgroups
; i
++, subgroup
++) {
648 parse_group(pd
, subgroup
);
653 int gapp_init_print(RunTime
*rt
)
661 rt
->num_print_dests
= cupsGetDests(&dests
);
662 if (!rt
->num_print_dests
) {
663 /* no CUPS printers defined or CUPS not running */
664 rt
->use_cups
= FALSE
;
666 rt
->print_dests
= xcalloc(rt
->num_print_dests
, sizeof(PrintDest
));
667 if (rt
->print_dests
== NULL
) {
668 return RETURN_FAILURE
;
672 for (i
= 0; i
< rt
->num_print_dests
; i
++) {
673 cups_dest_t
*dest
= &dests
[i
];
674 PrintDest
*pd
= &rt
->print_dests
[i
];
678 const char *filename
; /* PPD filename */
679 ppd_file_t
*ppd
; /* PPD data */
680 ppd_group_t
*group
; /* Current group */
682 printer
= copy_string(NULL
, dest
->name
);
683 if (dest
->instance
) {
684 printer
= concat_strings(printer
, "/");
685 printer
= concat_strings(printer
, dest
->instance
);
688 pd
->name
= copy_string(NULL
, dest
->name
);
689 pd
->inst
= copy_string(NULL
, dest
->instance
);
690 pd
->printer
= printer
;
692 if (dest
->is_default
) {
696 if ((filename
= cupsGetPPD(dest
->name
)) == NULL
) {
700 if ((ppd
= ppdOpenFile(filename
)) == NULL
) {
705 ppdMarkDefaults(ppd
);
706 cupsMarkOptions(ppd
, dest
->num_options
, dest
->options
);
708 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++) {
709 parse_group(pd
, group
);
715 cupsFreeDests(rt
->num_print_dests
, dests
);
718 rt
->num_print_dests
= 0;
721 return RETURN_SUCCESS
;
724 int gapp_print(const GraceApp
*gapp
, const char *fname
)
727 int retval
= RETURN_SUCCESS
;
729 if (gapp
->rt
->use_cups
) {
730 PrintDest
*pd
= &gapp
->rt
->print_dests
[gapp
->rt
->print_dest
];
734 cups_option_t
*options
= NULL
;
736 for (i
= 0; i
< pd
->nogroups
; i
++) {
737 PrintOptGroup
*og
= &pd
->ogroups
[i
];
739 for (j
= 0; j
< og
->nopts
; j
++) {
740 PrintOption
*po
= &og
->opts
[j
];
743 if (po
->selected
!= po
->choices
->defaults
.key
) {
744 dict_get_name_by_key(po
->choices
, po
->selected
, &value
);
745 num_options
= cupsAddOption(po
->name
, value
, num_options
, &options
);
750 jobid
= cupsPrintFile(pd
->name
, fname
, "Grace", num_options
, options
);
752 errmsg(ippErrorString(cupsLastError()));
753 retval
= RETURN_FAILURE
;
758 sprintf(tbuf
, "%s %s", get_print_cmd(gapp
), fname
);
765 #define VP_EPSILON 0.001
768 * If writing to a file, check to see if it exists
770 void do_hardcopy(const GProject
*gp
)
772 Quark
*project
= gproject_get_top(gp
);
773 GraceApp
*gapp
= gapp_from_quark(project
);
776 char fname
[GR_MAXPATHLEN
];
779 int truncated_out
, res
;
787 canvas
= grace_get_canvas(gapp
->grace
);
789 if (get_ptofile(gapp
)) {
790 if (string_is_empty(rt
->print_file
)) {
791 Device_entry
*dev
= get_device_props(canvas
, rt
->hdevice
);
792 sprintf(rt
->print_file
, "%s.%s",
793 QIDSTR(project
), dev
->fext
);
795 strcpy(fname
, rt
->print_file
);
796 prstream
= gapp_openw(gapp
, fname
);
798 strcpy(fname
, "gappXXXXXX");
799 prstream
= gapp_tmpfile(fname
);
802 if (prstream
== NULL
) {
806 canvas_set_prstream(canvas
, prstream
);
808 select_device(canvas
, rt
->hdevice
);
810 res
= gproject_render(gp
);
812 gapp_close(prstream
);
814 if (res
!= RETURN_SUCCESS
) {
818 get_bbox(canvas
, BBOX_TYPE_GLOB
, &v
);
819 project_get_viewport(project
, &vx
, &vy
);
820 if (v
.xv1
< 0.0 - VP_EPSILON
|| v
.xv2
> vx
+ VP_EPSILON
||
821 v
.yv1
< 0.0 - VP_EPSILON
|| v
.yv2
> vy
+ VP_EPSILON
) {
822 truncated_out
= TRUE
;
824 truncated_out
= FALSE
;
827 if (get_ptofile(gapp
) == FALSE
) {
828 if (truncated_out
== FALSE
||
829 yesno("Printout is truncated. Continue?", NULL
, NULL
, NULL
)) {
830 gapp_print(gapp
, fname
);
831 #ifndef PRINT_CMD_UNLINKS
836 if (truncated_out
== TRUE
) {
837 errmsg("Output is truncated - tune device dimensions");
842 int gui_is_page_free(const GUI
*gui
)
844 return gui
->page_free
;
847 void gui_set_page_free(GUI
*gui
, int onoff
)
849 if (gui
->page_free
== onoff
) {
854 errmsg("Can not change layout after initialization of GUI");
857 gui
->page_free
= onoff
;
861 void gui_set_barebones(GUI
*gui
)
864 gui
->toolbar
= FALSE
;
865 gui
->statusbar
= FALSE
;