/************************************************************************* * * GTK Euler * *************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../pixmaps/icon.xpm" #include "../pixmaps/logo.xpm" #ifdef RS6000 #include void gettimer (int, struct timestruc_t *); #endif #include "sysdep.h" #include "mainloop.h" #include "help.h" #include "rc.h" #include "term.h" #include "metagtk.h" #include "metaps.h" #include "output.h" #include "earray.h" /*----------------------------------------------------------------------- * Global variables *----------------------------------------------------------------------*/ static int is_demo = 0; static int in_text = 1; static EulerPrefs prefs; static GtkWidget *term_window = NULL; static GtkWidget *term; static GtkWidget *meta_window = NULL; static GtkWidget *meta; /*----------------------------------------------------------------------- * Euler callbacks *----------------------------------------------------------------------*/ /* text_mode * Switch to text. Graphics should not be deleted. * On a window system make text visible. */ void text_mode (void) { if (!in_text) { in_text=1; gdk_window_raise(term_window->window); } } /* graphic_mode * Switch to graphics. Text must not be deleted. * On a window system make graphics visible. */ void graphic_mode (void) { if (in_text) { in_text=0; gdk_window_raise(meta_window->window); } } /************************************************************************ * * Graphic window * * The graphic screen has coordinates from 0.0 to 1024.0 (double). * There should be a function, which computes the correct screen * coordinates from these internal ones. * ************************************************************************/ int usecolors=1; /* getpixelsize * Compute the size of pixel in screen coordinates. */ void getpixelsize (double *x, double *y) { *x=1024.0/meta->allocation.width; *y=1024.0/meta->allocation.height; } /* gflush * Flush out remaining graphic commands (for multitasking). * This serves to synchronize the graphics on multitasking systems. */ void gflush (void) { } /* * S O U N D W A V E S */ #ifdef WAVES void sys_playwav (char *file) { } #endif /* * G R A P H I C I N P U T */ /* mouse * wait, until the user marked a screen point with the mouse. * Return screen coordinates. */ void mouse (double *x, double *y) { while (1) { if (gdk_events_pending()) { GtkMeta *m = GTK_META(meta); gtk_main_iteration(); if (m->x>0.0 && m->y>0.0) { *x=m->x; *y=m->y; m->x = m->y = -1.0; return; } else { GtkTerm *t = GTK_TERM(term); if (t->scan==escape) { *x=-1.0; *y=-1.0; return; } t->scan = t->code = 0; } } else usleep(1); } } static int notekey=0; /* test_key * see, if user pressed the keyboard. * return the scancode, if he did. */ int test_key () { while (gtk_events_pending()) { GtkTerm *t = GTK_TERM(term); gtk_main_iteration(); if (t->scan==escape) { t->scan = t->code = 0; return escape; } else { if (t->scan) notekey=t->scan; else notekey=t->code; t->scan = t->code = 0; return 0; } } return 0; } int test_code (void) { int key=0; if (notekey) { key=notekey; notekey=0; return key; } while (gtk_events_pending()) { GtkTerm *t=GTK_TERM(term); gtk_main_iteration(); if (t->scan) { key = t->scan; t->scan = t->code = 0; return key; } else if (t->code) { key = t->code; t->scan = t->code = 0; return key; } } return 0; } /************************************************************************ * * Text Window * * The following text screen commands should be emulated on a graphic * work station. This can be done by a standard emulator (e.g. VT100) * or within a window displaying the text. Additional features may be * added, such as viewing old text. But the input line should be * visible as soon as a key is pressed by the user. * ************************************************************************/ /* Clear the text screen */ void clear_screen (void) { gtk_term_clear(term); } /* Print a line onto the text screen, parse tabs and '\n'. * Printing should be done at the cursor position. There is no need * to clear the line at a '\n'. * The cursor should move forward with the print. * Think of the function as a simple emulator. * If you have a line buffered input with echo then do not print, * when the command line is on. */ void gprint (char *s) /* print an output text (no newline) */ { gtk_term_print(term,s); } /* wait for a keystroke. return the scancode and the ascii code. * scancode should be a code from scantyp. Do at least generate * 'enter'. */ gboolean forcebreak = FALSE; int wait_key (int *scan) { int key; GtkTerm *t = GTK_TERM(term); t->scan = t->code = 0; *scan=0; while (!forcebreak) { if (gtk_events_pending()) { gtk_main_iteration(); if (t->scan || t->code) break; t->scan = t->code = 0; } else usleep(1); } if (forcebreak){ t->scan = enter; e_insert(t->history,e_get_length(t->history)-1,e_get_text(t->a,t->cur)+t->promptlen,0); if (e_get_length(t->history) > t->max_history) e_remove(t->history,0); t->hist=e_get_length(t->history)-1; set_editline(e_get_text(t->a,t->cur)+t->promptlen); key = 0; forcebreak = FALSE; } else key = t->code; *scan = t->scan; t->scan = t->code = 0; return key; } /* the command line is active (edit.c) */ void edit_on (void) { gtk_term_edit_on(term); } /* the command line is no longer in use (graphics or computing) (edit.c) */ void edit_off (void) { gtk_term_edit_off(term); } /************************************************************************ * * System * ************************************************************************/ static char path[256]; /* sets the path if dir!=0 and returns the path */ char *cd (char *dir) { chdir(dir); if (getcwd(path,256)) return path; return dir; } static void shellsort(char **buf, int n) { int h, i, j; int seq[28]; int p1=1, p2=1, p3=1, s=-1; /* * establish increment sequence (see Knuth, Vol 3) */ do { if (++s % 2) { seq[s] = 8*p1 - 6*p2 + 1; } else { seq[s] = 9*p1 - 9*p3 + 1; p2 *= 2; p3 *= 2; } p1 *= 2; } while(3*seq[s] < n); s = s > 0 ? s-1 : 0; /* * sort */ while (s >= 0) { /* sort-by-insertion in increments of h */ h = seq[s--]; for (i = h; i= 0 && strcmp(buf[j], t)>0; j -= h) buf[j+h] = buf[j]; buf[j+h] = t; } } } static int match (char *pat, char *s) { if (*pat==0) return *s==0; if (*pat=='*') { pat++; if (!*pat) return 1; while (*s) { if (match(pat,s)) return 1; s++; } return 0; } if (*s==0) return 0; if (*pat=='?') return match(pat+1,s+1); if (*pat!=*s) return 0; return match(pat+1,s+1); } /* * scan a directory and get : * files : an array of entries matching the pattern * files_count : number of files entries * the function returns the max length of a file entry */ int scan_dir(char *dir_name, char *pat, char ** files[], int *files_count) { DIR *dir; struct dirent *entry; int entry_count=0, len=0; char **buf = NULL; dir = opendir(dir_name); if (dir) { while((entry = readdir(dir)) != NULL) { if (match(pat,entry->d_name)) { int l=strlen(entry->d_name); len = MAX(len,l); entry_count ++; buf = (char**)realloc(buf,entry_count*sizeof(char *)); buf[entry_count-1]=(char*)malloc(l+1); strcpy(buf[entry_count-1],entry->d_name); } } closedir(dir); shellsort(buf, entry_count); } *files = buf; *files_count = entry_count; return len; } /* execute * Call an external program, return 0, if there was no error. * No need to support this on multitasking systems. */ int execute (char *dir, char *progname) { return 0; } /* shrink * allows shrinking of memory for single task systems. * simply return 1 if you do not support this or set NOSHRINK in funcs.c */ int shrink (size_t size) { return 1; } /* myclock * define a timer in seconds. */ double myclock (void) { #ifdef RS6000 struct timestruc_t t; gettimer(TIMEOFDAY,&t); return (t.tv_sec+t.tv_nsec/1000000000.0); #else return ((double)(times(NULL)))/CLK_TCK; #endif } /* sys_wait * Wait for time seconds or until a key press. * Return the scan code or 0 (time exceeded). */ void sys_wait (double delay, int *scan) { double now; GtkTerm *t = GTK_TERM(term); now=myclock(); *scan=0; t->scan = t->code = 0; while (myclock()scan) { *scan = notekey = t->scan; t->scan = t->code = 0; } else if (t->code) { *scan = notekey = t->code; t->scan = t->code = 0; } } if (*scan==switch_screen) { if (in_text) { graphic_mode(); wait_key(scan); text_mode(); } else { text_mode(); wait_key(scan); graphic_mode(); } *scan=0; } if (*scan) return; usleep(1); } *scan=0; } /* stack_init * get memory for stack. */ static int stack_init (long size) { ramstart = (char *)malloc(size*1024l); if (!ramstart) return 0; /* fail */ ramend = ramstart+size*1024l; return 1; /* success */ } static void save_rc() { if (prefs.saveatexit) eulerrc_save(&prefs); } static void euler_exit() { save_rc(); exit(0); } /*----------------------------------------------------------------------- * GTK things *----------------------------------------------------------------------*/ static void destroy_yesno_dialog(GtkWidget *widget) { if (widget) { GtkWidget *dialog = (GtkWidget*) g_object_get_data(G_OBJECT(widget), "dialog"); gtk_widget_destroy(dialog); } } static char* get_filename(gpointer data, char *prefix) { char *filename; char *newname; GtkWidget *filechooser = (GtkWidget*)data; filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser)); if (!g_str_has_suffix(filename, prefix)) newname = g_strdup_printf("%s%s", filename, prefix); else newname = g_strdup(filename); return newname; } static void infobox(GtkWidget *parent, char *text) { GtkWidget * dialog; GtkWidget * hbox; GtkWidget * icon; GtkWidget * label; GtkWidget * button; dialog = gtk_dialog_new(); gtk_window_set_title(GTK_WINDOW(dialog),"Information"); gtk_window_set_transient_for(GTK_WINDOW(dialog),GTK_WINDOW(parent)); gtk_window_set_modal(GTK_WINDOW(dialog),TRUE); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); gtk_window_set_position(GTK_WINDOW(dialog),GTK_WIN_POS_MOUSE); g_signal_connect(G_OBJECT(dialog),"delete_event",G_CALLBACK(gtk_widget_destroy),NULL); g_signal_connect(G_OBJECT(dialog),"destroy",G_CALLBACK(gtk_widget_destroy),NULL); gtk_widget_realize(dialog); hbox = gtk_hbox_new(FALSE,10); gtk_container_set_border_width(GTK_CONTAINER(hbox), 10); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),hbox,TRUE,TRUE,0); icon = gtk_image_new_from_stock(GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG); gtk_box_pack_start(GTK_BOX(hbox),icon,FALSE,FALSE,0); label = gtk_label_new(text); gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_LEFT); gtk_box_pack_start(GTK_BOX(hbox),label,TRUE,TRUE,0); /* * setup the buttons (Yes, No and Cancel) */ button = gtk_button_new_from_stock(GTK_STOCK_OK); GTK_WIDGET_SET_FLAGS(button,GTK_CAN_DEFAULT); g_signal_connect_swapped(G_OBJECT(button),"clicked",G_CALLBACK(gtk_widget_destroy),GTK_OBJECT(dialog)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),button,TRUE,TRUE,0); gtk_widget_grab_default(button); gtk_widget_show_all(dialog); } static void yesnoquestion(char *text, GCallback yes_cb, GCallback no_cb, GtkWidget *window) { GtkWidget * dialog; GtkWidget * hbox; GtkWidget * icon; GtkWidget * label; GtkWidget * button; dialog = gtk_dialog_new(); gtk_window_set_title(GTK_WINDOW(dialog),"Question"); gtk_window_set_transient_for(GTK_WINDOW(dialog),GTK_WINDOW(window)); gtk_window_set_modal(GTK_WINDOW(dialog),TRUE); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); gtk_window_set_position(GTK_WINDOW(dialog),GTK_WIN_POS_CENTER_ON_PARENT); g_signal_connect(G_OBJECT(dialog),"delete_event", G_CALLBACK(gtk_widget_destroy),NULL); g_signal_connect(G_OBJECT(dialog),"destroy", G_CALLBACK(gtk_widget_destroy),NULL); gtk_widget_realize(dialog); hbox = gtk_hbox_new(FALSE,10); gtk_container_set_border_width(GTK_CONTAINER(hbox), 10); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),hbox,TRUE,TRUE,0); icon = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG); gtk_box_pack_start(GTK_BOX(hbox),icon,FALSE,FALSE,0); label = gtk_label_new(text); gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_LEFT); gtk_box_pack_start(GTK_BOX(hbox),label,TRUE,TRUE,0); /* * setup the buttons (Yes, No and Cancel) */ button = gtk_button_new_from_stock(GTK_STOCK_YES); GTK_WIDGET_SET_FLAGS(button,GTK_CAN_DEFAULT); g_object_set_data(G_OBJECT(button), "dialog", (gpointer) dialog); if (GTK_IS_FILE_CHOOSER(window)) g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(yes_cb),window); else g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(yes_cb),NULL); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),button,TRUE,TRUE,0); gtk_widget_grab_default(button); button = gtk_button_new_from_stock(GTK_STOCK_NO); GTK_WIDGET_SET_FLAGS(button,GTK_CAN_DEFAULT); g_object_set_data(G_OBJECT(button), "dialog", (gpointer) dialog); if (no_cb) g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(no_cb),NULL); else g_signal_connect_swapped(G_OBJECT(button),"clicked", G_CALLBACK(gtk_widget_destroy),dialog); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),button,TRUE,TRUE,0); button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); GTK_WIDGET_SET_FLAGS(button,GTK_CAN_DEFAULT); if (GTK_IS_FILE_CHOOSER(window)) g_signal_connect_swapped(G_OBJECT(button),"clicked", G_CALLBACK(gtk_widget_destroy),window); g_signal_connect_swapped(G_OBJECT(button),"clicked", G_CALLBACK(gtk_widget_destroy),GTK_OBJECT(dialog)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),button,TRUE,TRUE,0); gtk_widget_show_all(dialog); } /*----------------------------------------------------------------------- * About box *----------------------------------------------------------------------*/ void activate_url(GtkAboutDialog *about, const gchar *url, gpointer data) { char *browser; browser = g_strconcat(prefs.browser," ",url," &", NULL); system(browser); g_free(browser); } static void about() { GtkWidget *aboutdialog; GdkPixbuf *buff; const gchar *authors[] = {"Rene Grothmann ", "Eric Boucharé ", "Puji Prasetiyo ", NULL }; aboutdialog = gtk_about_dialog_new (); buff = gdk_pixbuf_new_from_xpm_data((const char**) logo_xpm); gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (aboutdialog), buff); gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (aboutdialog), VERSION); gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (aboutdialog), "Euler"); gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG (aboutdialog), "Copyright © 2001,2005 Rene Grothmann, Eric Boucharé, Puji Prasetiyo"); gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (aboutdialog), "EULER is a program for quickly and interactively\n" "computing with real and complex numbers and\n" "matrices, or with intervals. It can draw your\n" "functions in two and three dimensions"); gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (aboutdialog), authors); gtk_about_dialog_set_url_hook (activate_url, NULL, NULL); gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (aboutdialog), "http://euler.sourceforge.net"); gtk_about_dialog_set_license(GTK_ABOUT_DIALOG (aboutdialog), "This program is free software; you can redistribute it and/or\n" "modify it under the terms of the GNU Library General Public License as\n" "published by the Free Software Foundation; either version 2 of the\n" "License, or (at your option) any later version.\n" "\n" "This library is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" "Library General Public License for more details.\n" "\n" "You should have received a copy of the GNU Library General Public\n" "License along with the Gnome Library; see the file COPYING.LIB. If not,\n" "write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,\n" "Boston, MA 02111-1307, USA.\n"); gtk_dialog_run (GTK_DIALOG(aboutdialog)); gtk_widget_destroy (aboutdialog); } /*--------------------------------------------------------------------------- * preference box *---------------------------------------------------------------------------*/ static GtkWidget * estack; static GtkWidget * gstack; static GtkWidget * glines; static GtkWidget * browser; static GtkWidget * color_button[16]; static GtkWidget * atexitbut; static GtkWidget * fontbutton; static GtkWidget * editordialog; static GtkWidget * etextview; static short def_colors[3][MAX_COLORS] = { {255,0,100,0 ,0 ,0 ,100,150,100,50,220 ,80 ,80 ,80 ,140,190}, {255,0,0 ,100,0 ,100,100,150,100,50,80 ,220 ,80 ,140 ,140,190}, {255,0,0 ,0 ,100,100, 0,150,100,50,80 ,80 ,220 ,140 , 80,190} }; static void prefs_apply_cb(GtkWidget *widget, gpointer data) { int val, i, j, changed = 0; const gchar *pfont = NULL; val = atol(gtk_entry_get_text(GTK_ENTRY(estack))); if (val) prefs.estack = val; val = atol(gtk_entry_get_text(GTK_ENTRY(gstack))); if (val) prefs.gstack = val; val = atol(gtk_entry_get_text(GTK_ENTRY(glines))); pfont = gtk_font_button_get_font_name(GTK_FONT_BUTTON(fontbutton)); if (pfont) { strcpy(prefs.pfont,pfont); if (editordialog) gtk_widget_modify_font(etextview, pango_font_description_from_string(pfont)); } if (val) { prefs.glines = val; setmetalines(prefs.glines); gtk_meta_update_lines(meta); } for (i=0 ; i<16 ; i++) { GdkColor gcolor; short color[3]; gtk_color_button_get_color(GTK_COLOR_BUTTON(color_button[i]),&gcolor); color[0] = gcolor.red>>8; color[1] = gcolor.green>>8; color[2] = gcolor.blue>>8; for (j=0 ; j<3 ; j++) if (prefs.colors[j][i]!=color[j]) { prefs.colors[j][i]=color[j]; changed =1; } } if (changed) { setmetacolors(prefs.colors); gtk_meta_update_colors(meta); } if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(atexitbut))) prefs.saveatexit = 1; else prefs.saveatexit = 0; if (strlen(gtk_entry_get_text(GTK_ENTRY(browser)))) strcpy(prefs.browser,gtk_entry_get_text(GTK_ENTRY(browser))); } static void prefs_ok_cb(GtkWidget *widget, gpointer data) { prefs_apply_cb(widget,data); } static void prefs_reset_cb(GtkWidget *widget, gpointer data) { GdkColor color; char *s; int i; gtk_entry_set_text(GTK_ENTRY(browser),E_BROWSER_DEFAULT); s = g_strdup_printf("%ld",E_ESTACK_DEFAULT); gtk_entry_set_text(GTK_ENTRY(estack),s); g_free(s); s = g_strdup_printf("%ld",E_GSTACK_DEFAULT); gtk_entry_set_text(GTK_ENTRY(gstack),s); g_free(s); s = g_strdup_printf("%d",E_GLINES_DEFAULT); gtk_entry_set_text(GTK_ENTRY(glines),s); g_free(s); s = g_strdup_printf("%s",E_PFONT_DEFAULT); gtk_font_button_set_font_name(GTK_FONT_BUTTON(fontbutton),s); g_free(s); for (i=0 ; i<16 ; i++) { color.red = ((gushort)def_colors[0][i])<<8; color.green = ((gushort)def_colors[1][i])<<8; color.blue = ((gushort)def_colors[2][i])<<8; gtk_color_button_set_color(GTK_COLOR_BUTTON(color_button[i]), &color); } gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(atexitbut),TRUE); } static void prefs_box() { GtkWidget *dialog; GtkWidget *notebook; GtkWidget *frame; GtkWidget *label; GtkWidget *alignment; GtkWidget *table; GtkWidget *hbox; GtkWidget *pref_vbox; GtkWidget *vbox; GtkWidget *button; int i; char *s; dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (G_OBJECT(dialog),"delete_event", G_CALLBACK(gtk_widget_destroy),NULL); g_signal_connect (G_OBJECT(dialog),"destroy", G_CALLBACK(gtk_widget_destroy),NULL); gtk_window_set_title (GTK_WINDOW (dialog), "Preferences ..."); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); gtk_window_set_type_hint (GTK_WINDOW (dialog), GDK_WINDOW_TYPE_HINT_DIALOG); gtk_window_set_modal(GTK_WINDOW(dialog),TRUE); pref_vbox = gtk_vbox_new (FALSE, 5); gtk_container_add (GTK_CONTAINER (dialog), pref_vbox); gtk_container_set_border_width (GTK_CONTAINER (pref_vbox), 5); notebook = gtk_notebook_new (); gtk_box_pack_start (GTK_BOX (pref_vbox), notebook, TRUE, TRUE, 0); frame = gtk_frame_new (NULL); gtk_container_add (GTK_CONTAINER (notebook), frame); gtk_container_set_border_width (GTK_CONTAINER (frame), 5); alignment = gtk_alignment_new (0, 0, 0, 0); gtk_container_add (GTK_CONTAINER (frame), alignment); vbox = gtk_vbox_new (FALSE, 5); gtk_container_add (GTK_CONTAINER (alignment), vbox); gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); label = gtk_label_new ("You can setup the memory size of the stack used for calculation. This will be effective on Euler restart."); gtk_label_set_line_wrap(GTK_LABEL(label),TRUE); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); hbox = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); label = gtk_label_new ("Stack memory (KB) :"); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); label = gtk_label_new (NULL); gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); estack = gtk_entry_new (); gtk_box_pack_start (GTK_BOX (hbox), estack, FALSE, TRUE, 0); s = g_strdup_printf("%d",prefs.estack); gtk_entry_set_text(GTK_ENTRY(estack),s); g_free(s); label = gtk_label_new ("You can setup the memory size of the buffer used for graphics. This will be effective on Euler][ restart."); gtk_label_set_line_wrap(GTK_LABEL(label),TRUE); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); hbox = gtk_hbox_new (FALSE, 5); gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); label = gtk_label_new ("Graphics buffer (KB) :"); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); label = gtk_label_new (NULL); gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); gstack = gtk_entry_new (); gtk_box_pack_start (GTK_BOX (hbox), gstack, FALSE, TRUE, 0); s = g_strdup_printf("%d",prefs.gstack); gtk_entry_set_text(GTK_ENTRY(gstack),s); g_free(s); label = gtk_label_new ("Memory"); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 0), label); frame = gtk_frame_new (NULL); gtk_container_add (GTK_CONTAINER (notebook), frame); gtk_container_set_border_width (GTK_CONTAINER (frame), 5); alignment = gtk_alignment_new (0, 0, 1, 1); gtk_container_add (GTK_CONTAINER (frame), alignment); vbox = gtk_vbox_new (FALSE, 5); gtk_container_add (GTK_CONTAINER (alignment), vbox); gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); label = gtk_label_new ("You can setup the height of the graphics window in lines of text. This will not change the effective height of the graphics window, but the font size."); gtk_label_set_line_wrap(GTK_LABEL(label),TRUE); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); hbox = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); label = gtk_label_new ("Number of lines :"); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); label = gtk_label_new (NULL); gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); glines = gtk_entry_new (); gtk_box_pack_start (GTK_BOX (hbox), glines, FALSE, FALSE, 0); s = g_strdup_printf("%d",prefs.glines); gtk_entry_set_text(GTK_ENTRY(glines),s); g_free(s); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); label = gtk_label_new("Editor font: "); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); fontbutton = gtk_font_button_new (); gtk_font_button_set_use_font (GTK_FONT_BUTTON (fontbutton), TRUE); gtk_font_button_set_font_name(GTK_FONT_BUTTON (fontbutton), prefs.pfont); gtk_box_pack_start (GTK_BOX (hbox), fontbutton, TRUE, TRUE, 0); label = gtk_label_new ("Font"); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 1), label); frame = gtk_frame_new (NULL); gtk_container_add (GTK_CONTAINER (notebook), frame); gtk_container_set_border_width (GTK_CONTAINER (frame), 5); alignment = gtk_alignment_new (0, 0, 1, 1); gtk_container_add (GTK_CONTAINER (frame), alignment); gtk_container_set_border_width (GTK_CONTAINER (alignment), 5); vbox = gtk_vbox_new (FALSE, 5); gtk_container_add (GTK_CONTAINER (alignment), vbox); label = gtk_label_new ("You can setup the colors used for the graphics. The change will be set when you click on Apply or OK."); gtk_label_set_line_wrap(GTK_LABEL(label),TRUE); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); table = gtk_table_new (8, 4, TRUE); gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0); for (i=0 ; i<8 ; i++) { GdkColor color; s = g_strdup_printf("%d",i); label = gtk_label_new(s); gtk_widget_show (label); gtk_table_attach(GTK_TABLE(table),label,0,1,i,i+1,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,2); color_button[i] = gtk_color_button_new(); color.red = ((gushort)prefs.colors[0][i])<<8; color.green = ((gushort)prefs.colors[1][i])<<8; color.blue = ((gushort)prefs.colors[2][i])<<8; gtk_color_button_set_color(GTK_COLOR_BUTTON(color_button[i]), &color); gtk_widget_show (color_button[i]); gtk_table_attach(GTK_TABLE(table),color_button[i],1,2,i,i+1,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,2); g_free(s); s = g_strdup_printf("%d",i+8); color_button[i+8] = gtk_color_button_new(); color.red = ((gushort)prefs.colors[0][i+8])<<8; color.green = ((gushort)prefs.colors[1][i+8])<<8; color.blue = ((gushort)prefs.colors[2][i+8])<<8; gtk_color_button_set_color(GTK_COLOR_BUTTON(color_button[i+8]), &color); gtk_widget_show (color_button[i+8]); gtk_table_attach(GTK_TABLE(table),color_button[i+8],2,3,i,i+1,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,2); label = gtk_label_new(s); gtk_widget_show (label); gtk_table_attach(GTK_TABLE(table),label,3,4,i,i+1,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,2); g_free(s); } label = gtk_label_new ("Colors"); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 2), label); frame = gtk_frame_new (NULL); gtk_container_add (GTK_CONTAINER (notebook), frame); gtk_container_set_border_width (GTK_CONTAINER (frame), 5); alignment = gtk_alignment_new (0, 0, 1, 1); gtk_container_add (GTK_CONTAINER (frame), alignment); gtk_container_set_border_width (GTK_CONTAINER (alignment), 5); vbox = gtk_vbox_new (FALSE, 5); gtk_container_add (GTK_CONTAINER (alignment), vbox); atexitbut = gtk_check_button_new_with_mnemonic ("Save preferences at Euler exit"); gtk_box_pack_start (GTK_BOX (vbox), atexitbut, FALSE, FALSE, 0); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (atexitbut), TRUE); label = gtk_label_new ("Browser used to view documentation"); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); browser = gtk_entry_new (); gtk_box_pack_start (GTK_BOX (vbox), browser, FALSE, FALSE, 0); s = g_strdup_printf("%s",prefs.browser); gtk_entry_set_text(GTK_ENTRY(browser),s); g_free(s); label = gtk_label_new ("Misc"); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 3), label); hbox = gtk_hbox_new (FALSE, 3); gtk_box_pack_start (GTK_BOX (pref_vbox), hbox, FALSE, TRUE, 0); button = gtk_button_new_with_mnemonic ("Default"); g_signal_connect (G_OBJECT(button), "clicked", G_CALLBACK (prefs_reset_cb),NULL); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); label = gtk_label_new (NULL); gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); button = gtk_button_new_from_stock (GTK_STOCK_CANCEL); g_signal_connect_swapped (G_OBJECT(button), "clicked", G_CALLBACK (gtk_widget_destroy),G_OBJECT(dialog)); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); button = gtk_button_new_with_mnemonic ("Apply"); g_signal_connect (G_OBJECT(button), "clicked", G_CALLBACK (prefs_apply_cb),NULL); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); button = gtk_button_new_from_stock (GTK_STOCK_OK); g_signal_connect (G_OBJECT(button), "clicked", G_CALLBACK (prefs_ok_cb),NULL); g_signal_connect_swapped (G_OBJECT(button), "clicked", G_CALLBACK (gtk_widget_destroy),G_OBJECT(dialog)); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); gtk_widget_show_all(dialog); } static void edit_comment_cb(GtkWidget *widget, gpointer data) { char *text; GtkTextIter start, end; GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data)); if (buffer) { gtk_text_buffer_get_bounds(buffer, &start, &end); text = gtk_text_buffer_get_text(buffer, &start, &end, TRUE); if (g_utf8_validate(text, -1, NULL)) text = g_locale_from_utf8(text, -1, NULL, NULL, NULL); gtk_term_set_comment(term,text); } } /*--------------------------------------------------------------------------- * comment editor *---------------------------------------------------------------------------*/ static void editcomment(char *text) { GtkWidget *dialog; GtkWidget *vbox; GtkWidget *scrolledwindow; GtkWidget *textview; GtkWidget *hbuttonbox; GtkWidget *button; GtkTextBuffer *buffer; dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect(G_OBJECT(dialog),"delete_event", G_CALLBACK(gtk_widget_destroy),NULL); g_signal_connect(G_OBJECT(dialog),"destroy", G_CALLBACK(gtk_widget_destroy),NULL); gtk_window_set_title (GTK_WINDOW (dialog), "Edit comment"); gtk_window_set_default_size (GTK_WINDOW (dialog), 350, 250); gtk_window_set_type_hint (GTK_WINDOW (dialog), GDK_WINDOW_TYPE_HINT_DIALOG); gtk_window_set_modal(GTK_WINDOW(dialog),TRUE); vbox = gtk_vbox_new (FALSE, 5); gtk_container_add (GTK_CONTAINER (dialog), vbox); gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); scrolledwindow = gtk_scrolled_window_new (NULL, NULL); gtk_box_pack_start (GTK_BOX (vbox), scrolledwindow, TRUE, TRUE, 0); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_SHADOW_IN); buffer = gtk_text_buffer_new(NULL); if (text != NULL) gtk_text_buffer_set_text(buffer, text, -1); textview = gtk_text_view_new_with_buffer (buffer); gtk_container_add (GTK_CONTAINER (scrolledwindow), textview); hbuttonbox = gtk_hbutton_box_new (); gtk_widget_show (hbuttonbox); gtk_box_pack_start (GTK_BOX (vbox), hbuttonbox, FALSE, FALSE, 0); button = gtk_button_new_from_stock (GTK_STOCK_CANCEL); g_signal_connect_swapped(G_OBJECT(button),"clicked", G_CALLBACK(gtk_widget_destroy),GTK_OBJECT(dialog)); gtk_container_add (GTK_CONTAINER (hbuttonbox), button); button = gtk_button_new_from_stock (GTK_STOCK_OK); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(edit_comment_cb),GTK_OBJECT(textview)); g_signal_connect_swapped(G_OBJECT(button),"clicked", G_CALLBACK(gtk_widget_destroy),GTK_OBJECT(dialog)); gtk_container_add (GTK_CONTAINER (hbuttonbox), button); gtk_widget_show_all(dialog); } /*--------------------------------------------------------------------------- * menu *---------------------------------------------------------------------------*/ void file_select (GtkFileChooserAction action, gchar *title, gchar *pattern, gchar *filename, GCallback func, GtkWidget *window) { GtkWidget *dialog; GtkWidget *dialog_vbox; GtkWidget *dialog_action_area; GtkWidget *button; GtkFileFilter *filter; dialog = gtk_file_chooser_dialog_new (title, GTK_WINDOW(window), action, NULL); g_signal_connect(G_OBJECT(dialog), "delete_event", G_CALLBACK(gtk_widget_destroy), NULL); g_signal_connect(G_OBJECT(dialog), "destroy", G_CALLBACK(gtk_widget_destroy), NULL); gtk_window_set_type_hint (GTK_WINDOW (dialog), GDK_WINDOW_TYPE_HINT_DIALOG); filter = gtk_file_filter_new (); gtk_file_filter_add_pattern(filter, pattern); gtk_file_filter_set_name(filter, pattern); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); if (filename && action == GTK_FILE_CHOOSER_ACTION_SAVE) gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), g_path_get_basename(filename)); dialog_vbox = GTK_DIALOG (dialog)->vbox; dialog_action_area = GTK_DIALOG (dialog)->action_area; gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area), GTK_BUTTONBOX_END); button = gtk_button_new_from_stock ("gtk-cancel"); g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(gtk_widget_destroy), dialog); gtk_box_pack_start(GTK_BOX(dialog_action_area), button, FALSE, FALSE, 0); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); if (action == GTK_FILE_CHOOSER_ACTION_OPEN) button = gtk_button_new_from_stock ("gtk-open"); else if (action == GTK_FILE_CHOOSER_ACTION_SAVE) button = gtk_button_new_from_stock ("gtk-save"); else return; g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(func),dialog); gtk_box_pack_start(GTK_BOX(dialog_action_area), button, FALSE, FALSE, 0); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_widget_grab_default (button); gtk_widget_show_all(dialog); gtk_dialog_run (GTK_DIALOG (dialog)); } static void open_cb(GtkWidget *widget, gpointer data) { char *filename = get_filename(data, ".en"); if ((!filename) || (strcmp(filename,"") == 0)) return; if (!gtk_term_load(term,filename)) { char *txt = g_strdup_printf("\nI could not open the file\n%s !\n",filename); infobox((GtkWidget*)data, txt); g_free(txt); } else { gtk_widget_destroy((GtkWidget*)data); is_demo = 0; } chdir(g_dirname(filename)); } static void postscript_cb(GtkWidget *widget, gpointer data) { char *filename = get_filename(data, ".eps"); if ((!filename) || (strcmp(filename,"") == 0)) return; if (!dump_postscript(filename)) { char *txt = g_strdup_printf("\nI could not save the postscript graphics to the file\n%s\n",filename); infobox((GtkWidget*)data, txt); g_free(txt); } else gtk_widget_destroy((GtkWidget*)data); } static void overwrite_yes_cb(GtkWidget *widget, gpointer data) { char *filename = get_filename(data, ".en"); destroy_yesno_dialog(widget); if (!gtk_term_save(term,filename)) { char *txt = g_strdup_printf("\nI could not save the notebook to the file\n%s\n",filename); infobox((GtkWidget*)data, txt); g_free(txt); } else gtk_widget_destroy((GtkWidget*)data); chdir(g_dirname(filename)); } static void save_as_cb(GtkWidget *widget, gpointer data) { struct stat statbuf; char *filename = get_filename(data, ".en"); if ((!filename) || (strcmp(filename,"") == 0)) return; if (stat(filename, &statbuf) == 0) /* file exists */ yesnoquestion("Destination file exists, overwrite it?", G_CALLBACK(overwrite_yes_cb), NULL, (GtkWidget*)data); else overwrite_yes_cb(NULL, data); } static void overwrite_yes_open_cb(GtkWidget *widget, gpointer data) { char *filename = get_filename(data, ".en"); destroy_yesno_dialog(widget); if (gtk_term_save(term,filename)) { gtk_widget_destroy((GtkWidget*)data); chdir(g_dirname(filename)); file_select(GTK_FILE_CHOOSER_ACTION_OPEN, "Open A Notebook ...", "*.en", NULL, G_CALLBACK(open_cb), term_window); } else { char *txt = g_strdup_printf("\nI could not save the notebook to the file\n%s\nThe notebook open command is aborted ...\n",filename); infobox((GtkWidget*)data, txt); g_free(txt); chdir(g_dirname(filename)); } } static void save_as_open_cb(GtkWidget *widget, gpointer data) { struct stat statbuf; char *filename = get_filename(data, ".en"); if ((!filename) || (strcmp(filename,"") == 0)) return; if (stat(filename, &statbuf) == 0) /* file exists */ yesnoquestion("Destination file exists, overwrite it?", G_CALLBACK(overwrite_yes_open_cb), NULL, (GtkWidget*)data); else overwrite_yes_open_cb(NULL, data); } static void save_as_new_cb(GtkWidget *widget, gpointer data) { char *filename = get_filename(data, ".en"); if ((!filename) || (strcmp(filename,"") == 0)) return; if (gtk_term_save(term,filename)) { gtk_widget_destroy((GtkWidget*)data); gtk_term_clear_new(term); is_demo = 0; } else { char *txt = g_strdup_printf("\nI could not save the notebook to the file\n%s\nThe new notebook command is aborted ...\n",filename); infobox((GtkWidget*)data, txt); g_free(txt); } chdir(g_dirname(filename)); } static void overwrite_yes_quit_cb(GtkWidget *widget, gpointer data) { char *filename = get_filename(data, ".en"); destroy_yesno_dialog(widget); if (gtk_term_save(term,filename)){ gtk_widget_destroy((GtkWidget*)data); euler_exit(); } else { char *txt = g_strdup_printf("\nI could not save the notebook to the file\n%s\nThe quit notebook command is aborted ...\n",filename); infobox((GtkWidget*)data, txt); g_free(txt); } chdir(g_dirname(filename)); } static void save_as_quit_cb(GtkWidget *widget, gpointer data) { struct stat statbuf; char *filename = get_filename(data, ".en"); if ((!filename) || (strcmp(filename,"") == 0)) return; if (stat(filename, &statbuf) == 0) /* file exists */ yesnoquestion("Destination file exists, overwrite it?", G_CALLBACK(overwrite_yes_quit_cb), NULL, (GtkWidget*)data); else overwrite_yes_quit_cb(NULL, data); } static void yes_quit_cb(GtkWidget *widget, gpointer data) { destroy_yesno_dialog(widget); if (!gtk_term_is_named(term)) file_select(GTK_FILE_CHOOSER_ACTION_SAVE, "Save Notebook As ...", "*.en", "untitled", G_CALLBACK(save_as_quit_cb), term_window); else { gtk_term_save(term,NULL); euler_exit(); } } static void no_quit_cb(GtkWidget *widget, gpointer data) { destroy_yesno_dialog(widget); euler_exit(); } static void quit_cb(GObject *widget, gpointer data) { if (!is_demo && gtk_term_is_changed(term)) yesnoquestion("\nThe current notebook has been modified ...\nDo you want to save it?\n", G_CALLBACK(yes_quit_cb),G_CALLBACK(no_quit_cb),term_window); else euler_exit(); } /*--------------------------------------------------------------------------- * toolbar callbacks *---------------------------------------------------------------------------*/ static void yes_new_cb(GtkWidget *widget, gpointer data) { destroy_yesno_dialog(widget); if (!gtk_term_is_named(term)) file_select(GTK_FILE_CHOOSER_ACTION_SAVE, "Save Notebook As ...", "*.en", "untitled", G_CALLBACK(save_as_new_cb), term_window); else { gtk_term_save(term,NULL); gtk_term_clear_new(term); is_demo = 0; } } static void no_new_cb(GtkWidget *widget, gpointer data) { destroy_yesno_dialog(widget); gtk_term_clear_new(term); is_demo = 0; } static void yes_open_cb(GtkWidget *widget, gpointer data) { destroy_yesno_dialog(widget); if (!gtk_term_is_named(term)) file_select(GTK_FILE_CHOOSER_ACTION_SAVE, "Save Notebook As ...", "*.en", "untitled", G_CALLBACK(save_as_open_cb), term_window); else { gtk_term_save(term,NULL); file_select(GTK_FILE_CHOOSER_ACTION_OPEN, "Open A Notebook ...", "*.en", NULL, G_CALLBACK(open_cb), term_window); } } static void no_open_cb(GtkWidget *widget, gpointer data) { destroy_yesno_dialog(widget); file_select(GTK_FILE_CHOOSER_ACTION_OPEN, "Open A Notebook ...", "*.en", NULL, G_CALLBACK(open_cb), term_window); } /*------------------------------------------------------------- * internal editor *------------------------------------------------------------*/ static GtkWidget * estatusbar; static GtkWidget * entry; static GtkWidget * loadbutton; static GtkWidget * savebutton; static GtkTextBuffer * etextbuffer; static gint row, col; static gchar *efname = ""; static gboolean echanged = FALSE; static void buffer_changed(void) { char *title = g_strdup_printf("Editor [*%s]",efname); gtk_window_set_title(GTK_WINDOW(editordialog), title); g_free(title); echanged = TRUE; gtk_widget_set_sensitive(loadbutton, FALSE); gtk_widget_set_sensitive(savebutton, TRUE); } static void buffer_saved(void) { char *title = g_strdup_printf("Editor [%s]",efname); gtk_window_set_title(GTK_WINDOW(editordialog), title); g_free(title); echanged = FALSE; gtk_widget_set_sensitive(loadbutton, strlen(efname)); gtk_widget_set_sensitive(savebutton, FALSE); } static void clear_editor(void) { efname = ""; gtk_text_buffer_set_text(etextbuffer, "", -1); gtk_widget_grab_focus (etextview); buffer_saved(); } static void get_row_col(GtkTextIter iter, int *row, int *col) { GtkTextIter start; guint tab_size = 8; *row = gtk_text_iter_get_line(&iter); start = iter; gtk_text_iter_set_line_offset(&start, 0); *col = 0; while (!gtk_text_iter_equal(&start, &iter)) { if (gtk_text_iter_get_char (&start) == '\t') (*col) += (tab_size - (*col % tab_size)); else ++(*col); gtk_text_iter_forward_char(&start); } } static void find(GtkTextView *text_view, const gchar *text, GtkTextIter *iter) { GtkTextIter mstart, mend; GtkTextMark *last_pos; if(gtk_text_iter_forward_search(iter, text, 0, &mstart, &mend, NULL)) { gtk_text_buffer_select_range(etextbuffer, &mstart, &mend); last_pos = gtk_text_buffer_create_mark(etextbuffer, "last_pos", &mend, FALSE); gtk_text_view_scroll_to_mark(text_view, last_pos, 0, TRUE, 0.5, 0.5); } } static void save_file(GtkWidget *parent, char *filename) { FILE *file; char *text; GtkTextIter start, end; file = fopen(filename,"w"); if (!file) { char *txt = g_strdup_printf("\nCould not save the file\n%s !\n",filename); infobox(parent, txt); g_free(txt); return; } else { gtk_text_buffer_get_bounds(etextbuffer, &start, &end); text = gtk_text_buffer_get_text(etextbuffer, &start, &end, TRUE); if (g_utf8_validate(text, -1, NULL)) text = g_locale_from_utf8(text, -1, NULL, NULL, NULL); fprintf(file,text); fclose(file); efname = filename; buffer_saved(); if (GTK_IS_FILE_CHOOSER(parent)) gtk_widget_destroy(parent); } chdir(g_dirname(filename)); } static void cursor_moved(void) { char *msg; GtkTextIter iter; int r, c; gtk_text_buffer_get_iter_at_mark (etextbuffer, &iter, gtk_text_buffer_get_insert(etextbuffer)); get_row_col(iter, &r, &c); row = r; col = c; msg = g_strdup_printf("Ln:%d Col:%d", row + 1, col + 1); gtk_statusbar_push(GTK_STATUSBAR (estatusbar), 0, msg); g_free (msg); } static void overwrite_yes_e_cb(GtkWidget *widget, gpointer data) { destroy_yesno_dialog(widget); save_file((GtkWidget*)data, get_filename(data, ".e")); } static void save_as_e_cb(GtkWidget *widget, gpointer data) { struct stat statbuf; char *filename = get_filename(data, ".e"); if ((!filename) || (strcmp(filename,"") == 0)) return; if (stat(filename, &statbuf) == 0) /* file exists */ yesnoquestion("Destination file exists, overwrite it?", G_CALLBACK(overwrite_yes_e_cb), NULL, (GtkWidget*)data); else save_file((GtkWidget*)data, filename); } static void open_file(GtkWidget *parent, char *filename) { FILE *file; char line[1024]; char *text; int length; if ((!filename) || (strcmp(filename,"") == 0)) return; if (!(file = fopen(filename, "r+"))) if (!(file = fopen(filename, "r"))) { char *txt = g_strdup_printf("\nCould not open the file\n%s !\n",filename); infobox(parent, txt); g_free(txt); return; } if (GTK_IS_FILE_CHOOSER(parent)) gtk_widget_destroy(parent); clear_editor(); efname = filename; while(!feof(file) && !ferror(file)) { length = fread(line, sizeof(char), 1023, file); line[length] = '\0'; if (!g_utf8_validate(line, strlen(line), NULL)) { text = g_locale_to_utf8(line, strlen(line), NULL, NULL, NULL); gtk_text_buffer_insert_at_cursor(etextbuffer, text, strlen(text)); } else gtk_text_buffer_insert_at_cursor(etextbuffer, line, strlen(line)); } fclose(file); buffer_saved(); chdir(g_dirname(filename)); } static void open_e_cb(GtkWidget *widget, gpointer data) { open_file((GtkWidget*)data, get_filename(data, ".e")); } static void save_or_save_as(void) { if (strlen(efname)) save_file(editordialog, efname); else file_select(GTK_FILE_CHOOSER_ACTION_SAVE, "Save Module As ...", "*.e", "untitled", G_CALLBACK(save_as_e_cb), editordialog); } static void yes_new_e_cb(GtkWidget *widget, gpointer data) { destroy_yesno_dialog(widget); save_or_save_as(); clear_editor(); } static void no_new_e_cb(GtkWidget *widget, gpointer data) { destroy_yesno_dialog(widget); clear_editor(); } static void yes_open_e_cb(GtkWidget *widget, gpointer data) { destroy_yesno_dialog(widget); save_or_save_as(); file_select(GTK_FILE_CHOOSER_ACTION_OPEN, "Open A Module ...", "*.e", NULL, G_CALLBACK(open_e_cb), editordialog); } static void no_open_e_cb(GtkWidget *widget, gpointer data) { destroy_yesno_dialog(widget); file_select(GTK_FILE_CHOOSER_ACTION_OPEN, "Open module ...", "*.e", NULL, G_CALLBACK(open_e_cb), editordialog); } static void yes_quit_e_cb(GtkWidget *widget, gpointer data) { destroy_yesno_dialog(widget); save_or_save_as(); gtk_widget_destroy(editordialog); editordialog = NULL; } static void no_quit_e_cb(GtkWidget *widget, gpointer data) { destroy_yesno_dialog(widget); gtk_widget_destroy(editordialog); editordialog = NULL; } static void yes_quit_e_quit_cb(GtkWidget *widget, gpointer data) { yes_quit_e_cb(widget, NULL); quit_cb(NULL, NULL); } static void no_quit_e_quit_cb(GtkWidget *widget, gpointer data) { no_quit_e_cb(widget, NULL); quit_cb(NULL, NULL); } static void editor_delete_cb(GtkWidget *widget, gpointer data) { if (echanged) if (widget) yesnoquestion("\nThe current module has been modified ...\nDo you want to save it?\n", G_CALLBACK(yes_quit_e_quit_cb),G_CALLBACK(no_quit_e_quit_cb),editordialog); else yesnoquestion("\nThe current module has been modified ...\nDo you want to save it?\n", G_CALLBACK(yes_quit_e_cb),G_CALLBACK(no_quit_e_cb),editordialog); else { gtk_widget_destroy(editordialog); editordialog = NULL; if (widget) quit_cb(NULL, NULL); } } static void on_editor_new(GtkWidget *widget, gpointer data) { if (echanged) yesnoquestion("\nThe current module has been modified ...\nDo you want to save it?\n", G_CALLBACK(yes_new_e_cb),G_CALLBACK(no_new_e_cb),editordialog); else clear_editor(); } static void on_editor_open(GtkWidget *widget, gpointer data) { if(echanged) yesnoquestion("\nThe current module has been modified ...\nDo you want to save it?\n", G_CALLBACK(yes_open_e_cb),G_CALLBACK(no_open_e_cb),editordialog); else file_select(GTK_FILE_CHOOSER_ACTION_OPEN, "Open A Module ...", "*.e", NULL, G_CALLBACK(open_e_cb), editordialog); } static void on_editor_save(GtkWidget *widget, gpointer data) { save_or_save_as(); } static void on_editor_save_as(GtkWidget *widget, gpointer data) { file_select(GTK_FILE_CHOOSER_ACTION_SAVE, "Save Module As ...", "*.e", strlen(efname) ? efname : "untitled", G_CALLBACK(save_as_e_cb), editordialog); } static void on_editor_find(GtkWidget *widget, gpointer data) { const gchar *text; GtkTextMark *last_pos; GtkTextIter iter; int r, c; text = gtk_entry_get_text(GTK_ENTRY(entry)); if (!strlen(text)) return; last_pos = gtk_text_buffer_get_mark (etextbuffer, "last_pos"); if (last_pos == NULL) gtk_text_buffer_get_start_iter (etextbuffer, &iter); else{ gtk_text_buffer_get_iter_at_mark (etextbuffer, &iter, last_pos); get_row_col(iter, &r, &c); if (row != r || col != (c-strlen(text))) gtk_text_buffer_get_iter_at_line_offset(etextbuffer, &iter, row, col); } find (GTK_TEXT_VIEW(etextview), text, &iter); } static void on_editor_load(GtkWidget *widget, gpointer data) { GtkTerm *t = GTK_TERM(term); if (t->editing) { char *text = g_strdup_printf("load \"%s\"", efname); if (!strlen(efname)) return; if (t->pos<=e_get_text_length(t->a,t->cur)) e_remove_text(t->a,t->cur,1,e_get_text_length(t->a,t->cur)-1); gtk_term_delete_current_output(term); output(text); gtk_term_redraw(term); strcpy(input_line, text); forcebreak = TRUE; g_free(text); } } static void editor(void) { GtkWidget *vbox; GtkWidget *toolbar; GtkWidget *button; GtkWidget *toolitem; GtkWidget *vseparator; GtkWidget *scrolledwindow; GtkWidget *image; GtkTooltips *tips; PangoFontDescription *pfd; GtkIconSize tmp_toolbar_icon_size; if (editordialog) { gdk_window_raise(editordialog->window); return; } editordialog = gtk_window_new (GTK_WINDOW_TOPLEVEL); // gtk_window_set_transient_for(GTK_WINDOW(editordialog),GTK_WINDOW(term_window)); // gtk_window_set_modal(GTK_WINDOW(editordialog),TRUE); gtk_window_set_position(GTK_WINDOW(editordialog),GTK_WIN_POS_MOUSE); gtk_window_set_title (GTK_WINDOW (editordialog), "Editor []"); gtk_window_set_default_size (GTK_WINDOW (editordialog), 500, 400); g_signal_connect_swapped(G_OBJECT(editordialog), "delete_event", G_CALLBACK(editor_delete_cb), NULL); vbox = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (editordialog), vbox); toolbar = gtk_toolbar_new (); gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0); gtk_toolbar_set_tooltips(GTK_TOOLBAR(toolbar), TRUE); gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), FALSE); tips = gtk_tooltips_new(); tmp_toolbar_icon_size = gtk_toolbar_get_icon_size (GTK_TOOLBAR (toolbar)); toolitem = (GtkWidget*) gtk_tool_item_new (); gtk_widget_show (toolitem); gtk_container_add (GTK_CONTAINER (toolbar), toolitem); button = gtk_button_new (); gtk_tooltips_set_tip(tips, button, "Create new module", NULL); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(on_editor_new), NULL); gtk_container_add (GTK_CONTAINER (toolitem), button); image = gtk_image_new_from_stock ("gtk-new", GTK_ICON_SIZE_BUTTON); gtk_container_add (GTK_CONTAINER (button), image); toolitem = (GtkWidget*) gtk_tool_item_new (); gtk_container_add (GTK_CONTAINER (toolbar), toolitem); button = gtk_button_new (); gtk_tooltips_set_tip(tips, button, "Open module", NULL); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(on_editor_open), NULL); gtk_container_add (GTK_CONTAINER (toolitem), button); image = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_BUTTON); gtk_container_add (GTK_CONTAINER (button), image); toolitem = (GtkWidget*) gtk_tool_item_new (); gtk_container_add (GTK_CONTAINER (toolbar), toolitem); savebutton = gtk_button_new (); gtk_tooltips_set_tip(tips, savebutton, "Save module", NULL); gtk_button_set_relief (GTK_BUTTON (savebutton), GTK_RELIEF_NONE); gtk_button_set_focus_on_click (GTK_BUTTON (savebutton), FALSE); g_signal_connect(G_OBJECT(savebutton), "clicked", G_CALLBACK(on_editor_save), NULL); gtk_container_add (GTK_CONTAINER (toolitem), savebutton); image = gtk_image_new_from_stock ("gtk-save", GTK_ICON_SIZE_BUTTON); gtk_container_add (GTK_CONTAINER (savebutton), image); toolitem = (GtkWidget*) gtk_tool_item_new (); gtk_container_add (GTK_CONTAINER (toolbar), toolitem); button = gtk_button_new (); gtk_tooltips_set_tip(tips, button, "Save module as ...", NULL); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(on_editor_save_as), NULL); gtk_container_add (GTK_CONTAINER (toolitem), button); image = gtk_image_new_from_stock ("gtk-save-as", GTK_ICON_SIZE_BUTTON); gtk_container_add (GTK_CONTAINER (button), image); toolitem = (GtkWidget*) gtk_tool_item_new (); gtk_container_add (GTK_CONTAINER (toolbar), toolitem); gtk_container_set_border_width (GTK_CONTAINER (toolitem), 5); vseparator = gtk_vseparator_new (); gtk_container_add (GTK_CONTAINER (toolitem), vseparator); toolitem = (GtkWidget*) gtk_tool_item_new (); gtk_container_add (GTK_CONTAINER (toolbar), toolitem); entry = gtk_entry_new (); gtk_container_add (GTK_CONTAINER (toolitem), entry); toolitem = (GtkWidget*) gtk_tool_item_new (); gtk_container_add (GTK_CONTAINER (toolbar), toolitem); button = gtk_button_new (); gtk_tooltips_set_tip(tips, button, "Find text", NULL); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(on_editor_find), NULL); gtk_container_add (GTK_CONTAINER (toolitem), button); image = gtk_image_new_from_stock ("gtk-find", GTK_ICON_SIZE_BUTTON); gtk_container_add (GTK_CONTAINER (button), image); toolitem = (GtkWidget*) gtk_tool_item_new (); gtk_container_add (GTK_CONTAINER (toolbar), toolitem); gtk_container_set_border_width (GTK_CONTAINER (toolitem), 5); vseparator = gtk_vseparator_new (); gtk_widget_show (vseparator); gtk_container_add (GTK_CONTAINER (toolitem), vseparator); toolitem = (GtkWidget*) gtk_tool_item_new (); gtk_container_add (GTK_CONTAINER (toolbar), toolitem); loadbutton = gtk_button_new (); gtk_tooltips_set_tip(tips, loadbutton, "Load module into euler", NULL); gtk_button_set_relief (GTK_BUTTON (loadbutton), GTK_RELIEF_NONE); gtk_button_set_focus_on_click (GTK_BUTTON (loadbutton), FALSE); g_signal_connect(G_OBJECT(loadbutton), "clicked", G_CALLBACK(on_editor_load), NULL); gtk_container_add (GTK_CONTAINER (toolitem), loadbutton); image = gtk_image_new_from_stock ("gtk-go-down", GTK_ICON_SIZE_BUTTON); gtk_container_add (GTK_CONTAINER (loadbutton), image); scrolledwindow = gtk_scrolled_window_new (NULL, NULL); gtk_box_pack_start (GTK_BOX (vbox), scrolledwindow, TRUE, TRUE, 0); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_SHADOW_IN); etextview = gtk_text_view_new (); pfd = pango_font_description_from_string (prefs.pfont); gtk_widget_modify_font(etextview,pfd); gtk_container_add (GTK_CONTAINER (scrolledwindow), etextview); etextbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(etextview)); g_signal_connect (etextbuffer, "mark_set", G_CALLBACK (cursor_moved), NULL); g_signal_connect (etextbuffer, "changed", G_CALLBACK (cursor_moved), NULL); g_signal_connect (etextbuffer, "changed", G_CALLBACK (buffer_changed), NULL); estatusbar = gtk_statusbar_new(); gtk_box_pack_start(GTK_BOX(vbox), estatusbar, FALSE, FALSE, 0); if (strlen(efname)) open_file(editordialog, efname); gtk_widget_show_all(editordialog); gtk_widget_grab_focus (etextview); cursor_moved(); buffer_saved(); } /*--------------------------------------------------------------------------- * term callbacks and drag & drop *---------------------------------------------------------------------------*/ static guint id; static gboolean savesuccess = FALSE; static GdkAtom text_uri_list, application_octet_stream, text_plain; enum {TARGET_RAW_DATA, TARGET_URI_LIST}; /* Targets which other apps can offer to us */ static GtkTargetEntry targets_to_accept[] = { {"application/octet-stream", 0, TARGET_RAW_DATA}, {"text/uri-list", 0, TARGET_URI_LIST} }; #define MAX_HOST_NAME_LEN 256 /* XXX: Limit */ char our_host_name[MAX_HOST_NAME_LEN]; static gchar *dnd_path=NULL; static void term_changed_cb(GtkWidget *widget, gpointer data) { char *title = g_strdup_printf("Euler [*%s]",gtk_term_get_name(term)); gtk_window_set_title(GTK_WINDOW(term_window), title); g_free(title); } static void term_saved_cb(GtkWidget *widget, gpointer data) { char *title = g_strdup_printf("Euler [%s]",gtk_term_get_name(term)); gtk_window_set_title(GTK_WINDOW(term_window), title); g_free(title); } static void term_editing_cb(GtkWidget *widget, gpointer data) { if (gtk_term_is_initialized(term)) gtk_statusbar_pop(GTK_STATUSBAR(widget),id); else gtk_statusbar_push(GTK_STATUSBAR(widget),id," Editing ..."); } static void term_interpreting_cb(GtkWidget *widget, gpointer data) { gtk_statusbar_push(GTK_STATUSBAR(widget),id," Running ..."); } static gint term_cfg_cb(GtkWidget *widget, GtkAllocation *allocation, gpointer data) { GtkTerm *term = GTK_TERM(widget); prefs.twidth = term->twidth; prefs.theight = term->theight; return FALSE; } static void overwrite_yes_dndopen_cb(GtkWidget *widget, gpointer data) { char *filename = get_filename(data, ".en"); destroy_yesno_dialog(widget); if (gtk_term_save(term,filename)) { gtk_widget_destroy((GtkWidget*)data); chdir(g_dirname(dnd_path)); savesuccess = gtk_term_load(term, dnd_path); } else { char *txt = g_strdup_printf("\nI could not save the notebook to the file\n%s\nThe notebook open command is aborted ...\n",filename); infobox((GtkWidget*)data, txt); g_free(txt); chdir(g_dirname(filename)); savesuccess = FALSE; } } static void save_as_dndopen_cb(GtkWidget *widget, gpointer data) { struct stat statbuf; char *filename = get_filename(data, ".en"); if ((!filename) || (strcmp(filename,"") == 0)) return; if (stat(filename, &statbuf) == 0) /* file exists */ yesnoquestion("Destination file exists, overwrite it?", G_CALLBACK(overwrite_yes_dndopen_cb), NULL, (GtkWidget*)data); else { overwrite_yes_dndopen_cb(NULL, data); gtk_widget_destroy((GtkWidget*)data); } } static void yes_dndopen_cb(GtkWidget *widget, gpointer data) { destroy_yesno_dialog(widget); if (!gtk_term_is_named(term)) file_select(GTK_FILE_CHOOSER_ACTION_SAVE, "Save Notebook As ...", "*.en", "untitled", G_CALLBACK(save_as_dndopen_cb), term_window); else { gtk_term_save(term,NULL); gtk_term_load(term, dnd_path); chdir(g_dirname(dnd_path)); } } static void no_dndopen_cb(GtkWidget *widget, gpointer data) { destroy_yesno_dialog(widget); gtk_term_load(term, dnd_path); chdir(g_dirname(dnd_path)); } static GdkAtom best_raw(GdkDragContext *context); static gboolean provides(GdkDragContext *context, GdkAtom target); /* Convert a list of URIs into a list of strings. * Lines beginning with # are skipped. * The text block passed in is zero terminated (after the final CRLF) */ GSList *uri_list_to_gslist(char *uri_list) { GSList *list = NULL; while (*uri_list) { char *linebreak; char *uri; int length; linebreak = strchr(uri_list, 13); if (!linebreak || linebreak[1] != 10) { infobox(term_window, "Incorrect or missing line break " "in text/uri-list data\n"); return list; } length = linebreak - uri_list; if (length && uri_list[0] != '#') { uri = g_malloc(sizeof(char) * (length + 1)); strncpy(uri, uri_list, length); uri[length] = 0; list = g_slist_append(list, uri); } uri_list = linebreak + 2; } return list; } /* Convert a URI to a local pathname (or NULL if it isn't local). * The returned pointer points inside the input string. * Possible formats: * /path * ///path * //host/path * file://host/path */ char *get_local_path(char *uri) { if (*uri == '/') { char *path; if (uri[1] != '/') return uri; /* Just a local path - no host part */ path = strchr(uri + 2, '/'); if (!path) return NULL; /* //something */ if (path - uri == 2) return path; /* ///path */ if (strlen(our_host_name) == path - uri - 2 && strncmp(uri + 2, our_host_name, path - uri - 2) == 0) return path; /* //myhost/path */ return NULL; /* From a different host */ } else { if (strncasecmp(uri, "file:", 5)) return NULL; /* Don't know this format */ uri += 5; if (*uri == '/') return get_local_path(uri); return NULL; } } /* * This is called when the remote application wants to send us some * data. We get to decide what kind of data we'd like. */ static int drag_drop(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time) { /* FIXME make term_window can't accept dnd if it has a shown transient window */ guchar *leafname = NULL; GdkAtom target; if (gtk_drag_get_source_widget(context)) return TRUE; /* Drag to ourselves - ignore */ if (provides(context, text_uri_list)) target = text_uri_list; else { leafname = g_strdup("Untitled"); target = best_raw(context); } /* Associate the leafname with the context */ if (leafname) g_dataset_set_data_full(context, "uri", leafname, g_free); if (target) gtk_drag_get_data(widget, context, target, time); else gtk_drag_finish(context, FALSE, FALSE, time); return TRUE; } /* Look for the best target type for transferring data */ static GdkAtom best_raw(GdkDragContext *context) { if (provides(context, text_plain)) return text_plain; if (provides(context, application_octet_stream)) return application_octet_stream; infobox(term_window, "I can't get the data from the other application\n"); return GDK_NONE; } /* Is the sended willing to supply this target type? */ static gboolean provides(GdkDragContext *context, GdkAtom target) { GList *targets = context->targets; while (targets && ((GdkAtom) targets->data != target)) targets = targets->next; return targets != NULL; } /* Called when some data arrives from the remote app (which we asked for * in drag_drop. */ static void drag_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint32 time) { if (!selection_data->data) { /* Timeout? */ gtk_drag_finish(context, FALSE, FALSE, time); return; } if (selection_data->target == text_uri_list) { GSList *files; char *localpath; files = uri_list_to_gslist(selection_data->data); if (files == NULL || files->next) { /* Only one file at a time for now */ infobox(term_window, "Sorry, can only load one file at a time"); gtk_drag_finish(context, FALSE, FALSE, time); return; } localpath = get_local_path((char *) files->data); /* Remember the URI for the data */ g_dataset_set_data_full(context,"uri",files->data,g_free); if (localpath) { gboolean success = FALSE; if (gtk_term_is_editing(term)) { if (!is_demo && gtk_term_is_changed(term)) { dnd_path=localpath; yesnoquestion("\nThe current notebook has been modified ...\nDo you want to save it?\n", G_CALLBACK(yes_dndopen_cb),G_CALLBACK(no_dndopen_cb),term_window); success = savesuccess; } else { success = gtk_term_load(term, localpath); chdir(g_dirname(localpath)); } } else { infobox(term_window, "You cannot load another notebook\nwhile the interpreter is running ..."); } gtk_drag_finish(context,success,FALSE,time); } else { gtk_drag_finish(context, FALSE, FALSE, time); } } else { gtk_drag_finish(context, FALSE, FALSE, time); } } /*--------------------------------------------------------------------------- * metagtk callbacks *---------------------------------------------------------------------------*/ static gint meta_cfg_cb(GtkWidget *widget, GdkEventConfigure *event) { prefs.gwidth = event->width; prefs.gheight = event->height; return FALSE; } /*--------------------------------------------------------------------------- * demo callbacks *---------------------------------------------------------------------------*/ static const char *demo_name = NULL; static void save_as_demo_cb(GtkWidget *widget, gpointer data) { char *filename = get_filename(data, ".en"); if ((!filename) || (strcmp(filename,"") == 0)) return; if (gtk_term_save(term,filename)) { gchar *s; chdir(g_dirname(filename)); s = g_strconcat(INSTALL_DIR,"/share/euler/progs/",demo_name,NULL); gtk_term_load(term,s); g_free(s); is_demo = 1; gtk_widget_destroy((GtkWidget*)data); } else { char *txt = g_strdup_printf("\nI could not save the notebook to the file\n%s\nThe notebook open command is aborted ...\n",filename); infobox((GtkWidget*)data, txt); g_free(txt); chdir(g_dirname(filename)); } } static void yes_demo_cb(GtkWidget *widget, gpointer data) { destroy_yesno_dialog(widget); if (!gtk_term_is_named(term)) file_select(GTK_FILE_CHOOSER_ACTION_SAVE, "Save Notebook As ...", "*.en", "untitled", G_CALLBACK(save_as_demo_cb), term_window); else { gchar *s; gtk_term_save(term,NULL); s = g_strconcat(INSTALL_DIR,"/share/euler/progs/",demo_name,NULL); gtk_term_load(term,s); g_free(s); is_demo = 1; } } static void no_demo_cb(GtkWidget *widget, gpointer data) { gchar *s; destroy_yesno_dialog(widget); s = g_strconcat(INSTALL_DIR,"/share/euler/progs/",demo_name,NULL); gtk_term_load(term,s); g_free(s); is_demo = 1; } static void demo_cb(GtkAction *action) { g_return_if_fail(action != NULL); g_return_if_fail(GTK_IS_ACTION(action)); demo_name = gtk_action_get_name(action); if (!is_demo) { if (gtk_term_is_changed(term)) yesnoquestion("\nThe current notebook has been modified ...\nDo you want to save it?\n", G_CALLBACK(yes_demo_cb),G_CALLBACK(no_demo_cb),term_window); else { gchar *s; s = g_strconcat(INSTALL_DIR,"/share/euler/progs/",demo_name,NULL); gtk_term_load(term,s); g_free(s); is_demo = 1; } } else { gchar *s; s = g_strconcat(INSTALL_DIR,"/share/euler/progs/",demo_name,NULL); gtk_term_load(term,s); g_free(s); is_demo = 1; } } /*--------------------------------------------------------------------------- * main *---------------------------------------------------------------------------*/ static void on_file_new(GtkAction *action) { if (!is_demo && gtk_term_is_changed(term)) yesnoquestion("\nThe current notebook has been modified ...\nDo you want to save it?\n", G_CALLBACK(yes_new_cb),G_CALLBACK(no_new_cb),term_window); else { gtk_term_clear_new(term); is_demo = 0; } } static void on_file_open(GtkAction *action) { if (!is_demo && gtk_term_is_changed(term)) yesnoquestion("\nThe current notebook has been modified ...\nDo you want to save it?\n", G_CALLBACK(yes_open_cb),G_CALLBACK(no_open_cb),term_window); else file_select(GTK_FILE_CHOOSER_ACTION_OPEN, "Open A Notebook ...", "*.en", NULL, G_CALLBACK(open_cb), term_window); } static void on_file_save(GtkAction *action) { if (!gtk_term_is_named(term)) file_select(GTK_FILE_CHOOSER_ACTION_SAVE, "Save Notebook As ...", "*.en", "untitled", G_CALLBACK(save_as_cb), term_window); else if (!is_demo) gtk_term_save(term,NULL); } static void on_file_save_as(GtkAction *action) { file_select(GTK_FILE_CHOOSER_ACTION_SAVE, "Save Notebook As ...", "*.en", gtk_term_is_named(term) ? gtk_term_get_name(term) : "untitled", G_CALLBACK(save_as_cb), term_window); } static void on_export_to_postscript(GtkAction *action) { file_select(GTK_FILE_CHOOSER_ACTION_SAVE, "Export Graphics As ...", "*.eps", "untitled", G_CALLBACK(postscript_cb), term_window); } static void on_file_quit(GObject *object) { if (editordialog) { gdk_window_raise(editordialog->window); editor_delete_cb(term_window, NULL); } else quit_cb(object, NULL); } static void on_edit_cut (GtkAction *action) { gtk_term_cut(term); } static void on_edit_copy (GtkAction *action) { gtk_term_copy(term); } static void on_edit_paste (GtkAction *action) { gtk_term_paste(term); } static void on_edit_insert_command (GtkAction *action) { gtk_term_insert_command(term,NULL); } static void on_edit_delete_command (GtkAction *action) { gtk_term_delete_command(term); } static void on_edit_clear_outputs (GtkAction *action) { gtk_term_delete_outputs(term); } static void on_edit_delete_output (GtkAction *action) { gtk_term_delete_current_output(term); } static void on_edit_edit_comment (GtkAction *action) { gchar *buffer = gtk_term_get_comment(term); if (buffer) if (!g_utf8_validate(buffer, -1, NULL)) buffer = g_locale_to_utf8(buffer, -1, NULL, NULL, NULL); editcomment(buffer); } static void on_misc_editor (GtkAction *action) { editor(); } static void on_misc_preferences (GtkAction *action) { prefs_box(); } static void on_help_doc (GtkAction *action) { char *browser; browser = g_strconcat(prefs.browser," ",INSTALL_DIR,"/share/doc/euler/index.html &",NULL); system(browser); g_free(browser); } static void on_help_about (GtkAction *action) { about(); } static GtkActionEntry actionentries[] = { /* file menu */ { "FileMenu" , NULL , "_File" }, { "New" , GTK_STOCK_NEW , "_New" , "N", "Create a new file" , G_CALLBACK (on_file_new) }, { "Open" , GTK_STOCK_OPEN , "_Open" , "O", "Open a file" , G_CALLBACK (on_file_open) }, { "Save" , GTK_STOCK_SAVE , "_Save" , "S", "Save current file" , G_CALLBACK (on_file_save) }, { "SaveAs" , GTK_STOCK_SAVE_AS , "Save _As..." , NULL , "Save to a file" , G_CALLBACK (on_file_save_as) }, { "ExportMenu" , NULL , "Export Graphics To" }, { "Postscript" , NULL , "Postscript" , "P", NULL , G_CALLBACK (on_export_to_postscript) }, { "Quit" , GTK_STOCK_QUIT , "_Quit" , "Q", "Quit" , G_CALLBACK (on_file_quit) }, /* edit menu */ { "EditMenu" , NULL , "_Edit" }, { "Cut" , GTK_STOCK_CUT , "Cu_t" , "X", "Cut selection" , G_CALLBACK (on_edit_cut) }, { "Copy" , GTK_STOCK_COPY , "_Copy" , "C", "Copy selection" , G_CALLBACK (on_edit_copy) }, { "Paste" , GTK_STOCK_PASTE , "_Paste" , "V", "Paste clipboard content" , G_CALLBACK (on_edit_paste) }, { "InsertCommand", GTK_STOCK_ADD , "Insert Command" , "I", "Insert Command" , G_CALLBACK (on_edit_insert_command) }, { "DeleteCommand", GTK_STOCK_REMOVE , "Delete Command" , "D", "Delete Current Command" , G_CALLBACK (on_edit_delete_command) }, { "ClearOutputs" , GTK_STOCK_CLEAR , "Clear All Outputs" , NULL , "Clear All Outputs" , G_CALLBACK (on_edit_clear_outputs) }, { "DeleteOutput" , GTK_STOCK_DELETE , "Delete Current Output" , NULL , "Delete Current Output" , G_CALLBACK (on_edit_delete_output) }, { "EditComment" , GTK_STOCK_JUSTIFY_FILL , "Edit Comment", "E", "Edit Command..." , G_CALLBACK (on_edit_edit_comment) }, /* misc menu */ { "MiscMenu" , NULL , "_Misc" }, { "DemoMenu" , NULL , "Demo" }, { "Editor" , GTK_STOCK_EDIT , "Editor" , NULL , "Internal Editor..." , G_CALLBACK (on_misc_editor) }, { "Preferences" , GTK_STOCK_PREFERENCES, "Preferences" , NULL , NULL , G_CALLBACK (on_misc_preferences) }, /* help menu */ { "HelpMenu" , NULL , "_Help" }, { "Documentation", GTK_STOCK_HELP , "Documentation" , "F1" , NULL , G_CALLBACK (on_help_doc) }, { "About" , GTK_STOCK_ABOUT , "_About" , "A", "About" , G_CALLBACK (on_help_about) }, }; static guint n_actionentries = G_N_ELEMENTS (actionentries); static const gchar *ui_info = "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; int main(int argc, char *argv[]) { GtkWidget *vbox; GtkUIManager *ui; GtkActionGroup *actions,*demoactions; GError *error = NULL; GtkWidget *statusbar; GtkWidget *hbox; GtkWidget *scrollbar; GdkBitmap *icon_mask; GdkPixmap *icon_pixmap; GdkColor alpha; char **entries=NULL; int n_entries=0,i; char *s; /* this should be equivalent to setlocale (LC_ALL, "") */ gtk_set_locale(); /* This must be the same for all locales */ setlocale(LC_NUMERIC, "POSIX"); /* Disable gtk's ability to set the locale. */ /* If gtk is allowed to set the locale, then it will override the */ /* setlocale for LC_NUMERIC (which is important for proper PS output. */ /* This may look funny here, given we make a call to gtk_set_locale() */ /* above. I don't know yet, if this is really the right thing to do. */ gtk_disable_setlocale(); gtk_init (&argc, &argv); prefs = eulerrc_init(); /* allocate stack space */ if (!stack_init(prefs.estack)) { g_print("Stack allocation failed!\nExiting.....\n"); exit(1); } /* allocate graphic stack space */ if (!openmeta(prefs.gstack,NULL)) { g_print("Graphic stack allocation failed!\nExiting.....\n"); exit(1); } setmetalines(prefs.glines); setmetacolors(prefs.colors); /* * setup atoms needed for drag & drop */ text_plain = gdk_atom_intern("text/plain", FALSE); text_uri_list = gdk_atom_intern("text/uri-list", FALSE); application_octet_stream = gdk_atom_intern("application/octet-stream", FALSE); /* * create the graphic window */ meta_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(meta_window), "Euler graphics window"); g_signal_connect(G_OBJECT(meta_window),"delete_event", G_CALLBACK(on_file_quit),NULL); g_signal_connect(G_OBJECT(meta_window),"destroy", G_CALLBACK(on_file_quit),NULL); meta = gtk_meta_new(prefs.gwidth,prefs.gheight); gtk_container_add(GTK_CONTAINER(meta_window),meta); /* * add a hook to collect geometry changes of the graphic window */ g_signal_connect(G_OBJECT(meta_window),"configure_event", G_CALLBACK(meta_cfg_cb),NULL); gtk_widget_show_all(meta_window); /* * create the main window */ term_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (term_window), "Euler []"); gtk_widget_realize(term_window); icon_pixmap = gdk_pixmap_create_from_xpm_d(term_window->window,&icon_mask,&alpha,icon_xpm); gdk_window_set_icon(term_window->window,NULL,icon_pixmap,icon_mask); gdk_window_set_group(meta_window->window,term_window->window); actions = gtk_action_group_new ("Actions"); gtk_action_group_add_actions (actions, actionentries, n_actionentries, NULL); ui = gtk_ui_manager_new (); gtk_ui_manager_insert_action_group (ui, actions, 0); gtk_window_add_accel_group (GTK_WINDOW (term_window), gtk_ui_manager_get_accel_group (ui)); if(!gtk_ui_manager_add_ui_from_string(ui, ui_info, -1, &error)) { g_message ("Building menus failed: %s", error->message); g_error_free (error); } gtk_ui_manager_set_add_tearoffs(ui,TRUE); gtk_toolbar_set_style(GTK_TOOLBAR(gtk_ui_manager_get_widget(ui, "ui/ToolBar")), GTK_TOOLBAR_ICONS); vbox = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (term_window), vbox); gtk_box_pack_start (GTK_BOX (vbox), gtk_ui_manager_get_widget (ui, "/MenuBar"), FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), gtk_ui_manager_get_widget (ui, "/ToolBar"), FALSE, FALSE, 0); /* * parse the install directory for available demos */ s = g_strconcat(INSTALL_DIR,"/share/euler/progs",NULL); scan_dir(s,"*.en",&entries,&n_entries); if (entries) { GtkActionEntry demoentries[n_entries]; for (i=0;iv_adj); GTK_WIDGET_UNSET_FLAGS (scrollbar, GTK_CAN_FOCUS); gtk_box_pack_start(GTK_BOX(hbox),scrollbar,FALSE,FALSE,0); gtk_term_set_scrollbar(term, scrollbar); /* * set the popup menu */ gtk_term_set_popup(term,GTK_MENU(gtk_ui_manager_get_widget(ui,"/Popup"))); statusbar = gtk_statusbar_new (); gtk_box_pack_start (GTK_BOX (vbox), statusbar, FALSE, FALSE, 0); id = gtk_statusbar_get_context_id(GTK_STATUSBAR(statusbar),"euler status messages"); g_signal_connect_swapped(G_OBJECT(term),"term_editing", G_CALLBACK(term_editing_cb),GTK_OBJECT(statusbar)); g_signal_connect_swapped(G_OBJECT(term),"term_interpreting", G_CALLBACK(term_interpreting_cb),GTK_OBJECT(statusbar)); gtk_statusbar_push(GTK_STATUSBAR(statusbar),id," Initializing Euler ..."); g_signal_connect (G_OBJECT(term_window), "delete_event", G_CALLBACK (on_file_quit),NULL); g_signal_connect (G_OBJECT(term_window), "destroy", G_CALLBACK (on_file_quit),NULL); /* * show everything and lets go */ gtk_widget_show_all(term_window); setmetadevice(gtk_meta_get_device(meta)); while (gtk_events_pending()) gtk_main_iteration_do(FALSE); s=g_strconcat(INSTALL_DIR,"/share/euler/help.txt",NULL); loadhelp(s); g_free(s); main_loop(argc,argv); closemeta(); return 0; }