From d6b513e1e2cebc8b7158126f8c92f170b5472ccb Mon Sep 17 00:00:00 2001 From: Stefan Frederik Date: Mon, 10 Jan 2022 18:54:07 +0100 Subject: [PATCH] issue warning if opening same circuit in different tabs, if tabbed if is active edit sch/sym in new window will do in a new tab --- src/actions.c | 76 +++-- src/callback.c | 6 + src/globals.c | 2 +- src/options.c | 4 +- src/save.c | 1 - src/scheduler.c | 60 ++-- src/xinit.c | 845 ++++++++++++++++++++++++++---------------------- src/xschem.h | 16 +- src/xschem.tcl | 33 +- 9 files changed, 590 insertions(+), 453 deletions(-) diff --git a/src/actions.c b/src/actions.c index f14f68b0..7feb40db 100644 --- a/src/actions.c +++ b/src/actions.c @@ -445,29 +445,39 @@ void saveas(const char *f, int type) /* changed name from ask_save_file to save void ask_new_file(void) { - char fullname[PATH_MAX]; /* overflow safe 20161125 */ + char f[PATH_MAX]; /* overflow safe 20161125 */ if(!has_x) return; - if(xctx->modified) { if(save(1) == -1 ) return; /* user cancels save, so do nothing. */ } tcleval("load_file_dialog {Load file} .sch.sym INITIALLOADDIR"); - my_snprintf(fullname, S(fullname),"%s", tclresult()); - - - if( fullname[0] ) { - dbg(1, "ask_new_file(): load file: %s\n", fullname); - clear_all_hilights(); - xctx->currsch = 0; - unselect_all(); - remove_symbols(); - load_schematic(1, fullname,1); /* 20180925.1 */ - tclvareval("update_recent_file {", fullname, "}", NULL); - my_strdup(1, &xctx->sch_path[xctx->currsch],"."); - xctx->sch_path_hash[xctx->currsch] = 0; - xctx->sch_inst_number[xctx->currsch] = 1; - zoom_full(1, 0, 1, 0.97); + my_snprintf(f, S(f),"%s", tclresult()); + if(f[0]) { + char win_path[WINDOW_PATH_SIZE]; + int skip = 0; + dbg(1, "ask_new_file(): load: f=%s\n", f); + + if(check_loaded(f, win_path)) { + char msg[PATH_MAX + 100]; + my_snprintf(msg, S(msg), "alert_ {xschem load: %s already open: %s}", f, win_path); + if(has_x) tcleval(msg); + else dbg(0, "ask_new_file: %s already open: %s\n", f, win_path); + skip = 1; + } + if(!skip) { + dbg(1, "ask_new_file(): load file: %s\n", f); + clear_all_hilights(); + xctx->currsch = 0; + unselect_all(); + remove_symbols(); + load_schematic(1, f,1); /* 20180925.1 */ + tclvareval("update_recent_file {", f, "}", NULL); + my_strdup(1, &xctx->sch_path[xctx->currsch],"."); + xctx->sch_path_hash[xctx->currsch] = 0; + xctx->sch_inst_number[xctx->currsch] = 1; + zoom_full(1, 0, 1, 0.97); + } } } @@ -965,16 +975,32 @@ int place_symbol(int pos, const char *symbol_name, double x, double y, short rot void symbol_in_new_window(void) { + char filename[PATH_MAX]; + char win_path[WINDOW_PATH_SIZE]; rebuild_selected_array(); + if(xctx->lastsel !=1 || xctx->sel_array[0].type!=ELEMENT) { - new_xschem_process(xctx->sch[xctx->currsch],1); + my_strncpy(filename, xctx->sch[xctx->currsch], S(filename)); + if(tclgetvar("tabbed_interface")[0] == '1' && !check_loaded(filename, win_path)) { + tcleval("create_new_tab"); + tclvareval("xschem load ", filename, NULL); + } else { + new_xschem_process(filename, 1); + } } else { - new_xschem_process(abs_sym_path(xctx->inst[xctx->sel_array[0].n].name, ""),1); + my_strncpy(filename, abs_sym_path(xctx->inst[xctx->sel_array[0].n].name, ""), S(filename)); + if(tclgetvar("tabbed_interface")[0] == '1') { + if(!check_loaded(filename, win_path)) { + tcleval("create_new_tab"); + tclvareval("xschem load ", filename, NULL); + } + } else { + new_xschem_process(filename, 1); + } } - } @@ -982,6 +1008,7 @@ void schematic_in_new_window(void) { char *sch = NULL; char filename[PATH_MAX]; + char win_path[WINDOW_PATH_SIZE]; rebuild_selected_array(); if(xctx->lastsel !=1 || xctx->sel_array[0].type!=ELEMENT) { @@ -1011,7 +1038,14 @@ void schematic_in_new_window(void) my_strncpy(filename, add_ext(abs_sym_path(xctx->inst[xctx->sel_array[0].n].name, ""), ".sch"), S(filename)); } - new_xschem_process(filename, 0); + if(tclgetvar("tabbed_interface")[0] == '1') { + if(!check_loaded(filename, win_path)) { + tcleval("create_new_tab"); + tclvareval("xschem load ", filename, NULL); + } + } else { + new_xschem_process(filename, 0); + } } } diff --git a/src/callback.c b/src/callback.c index 441a530f..7c193580 100644 --- a/src/callback.c +++ b/src/callback.c @@ -1455,12 +1455,18 @@ int callback(const char *winpath, int event, int mx, int my, KeySym key, } if(key=='e' && state == Mod1Mask) /* edit schematic in new window */ { + int save = xctx->semaphore; + xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ schematic_in_new_window(); + xctx->semaphore = save; break; } if(key=='i' && state == Mod1Mask) /* edit symbol in new window */ { + int save = xctx->semaphore; + xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ symbol_in_new_window(); + xctx->semaphore = save; break; } if( (key=='e' && state == ControlMask) || (key==XK_BackSpace)) /* back */ diff --git a/src/globals.c b/src/globals.c index d7bfd0bf..280081ca 100644 --- a/src/globals.c +++ b/src/globals.c @@ -162,7 +162,6 @@ int help=0; /* help option set to global scope, printing help is deferred */ /* when configuration xschemrc has been read 20140406 */ FILE *errfp = NULL; int no_readline=0; -char *filename=NULL; /* filename given on cmdline */ char home_dir[PATH_MAX]; /* home dir obtained via getpwuid */ char user_conf_dir[PATH_MAX]; char pwd_dir[PATH_MAX]; /* obtained via getcwd() */ @@ -200,6 +199,7 @@ int cli_opt_netlist_type = 0; int cli_opt_flat_netlist = 0; char cli_opt_plotfile[PATH_MAX] = ""; char cli_opt_netlist_dir[PATH_MAX] = ""; +char cli_opt_filename[PATH_MAX] = ""; /* filename given on cmdline */ /* --------------------------------------------------- */ diff --git a/src/options.c b/src/options.c index ef8918e5..91de50d2 100644 --- a/src/options.c +++ b/src/options.c @@ -230,9 +230,9 @@ int process_options(int argc, char *argv[]) } if (arg_cnt>=2) { dbg(1, "process_option(): file name given: %s\n",argv[1]); - my_strdup(291, &filename, argv[1]); + my_strncpy(cli_opt_filename, argv[1], S(cli_opt_filename)); #ifndef __unix__ - change_to_unix_fn(filename); + change_to_unix_fn(cli_opt_filename); #endif } return arg_cnt; diff --git a/src/save.c b/src/save.c index 1eb45d8d..403161ab 100644 --- a/src/save.c +++ b/src/save.c @@ -1060,7 +1060,6 @@ void load_schematic(int load_symbols, const char *filename, int reset_undo) /* 2 char msg[PATH_MAX+100]; struct stat buf; int i; - xctx->prep_hi_structs=0; xctx->prep_net_structs=0; xctx->prep_hash_inst=0; diff --git a/src/scheduler.c b/src/scheduler.c index b50b9355..1b6a2ba7 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -165,7 +165,6 @@ void xschem_cmd_help(int argc, const char **argv) "load\n", "load_new_window\n", "load_symbol\n", - "load_symbol\n", "log\n", "logic_set\n", "make_sch\n", @@ -1548,17 +1547,31 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg cmd_found = 1; if(argc==3) { if(!has_x || !xctx->modified || save(1) != -1 ) { /* save(1)==-1 --> user cancel */ + char f[PATH_MAX]; + char win_path[WINDOW_PATH_SIZE]; + int skip = 0; dbg(1, "scheduler(): load: filename=%s\n", argv[2]); - clear_all_hilights(); - xctx->currsch = 0; - unselect_all(); - remove_symbols(); - load_schematic(1, abs_sym_path(argv[2], ""), 1); - tclvareval("update_recent_file {", abs_sym_path(argv[2], ""), "}", NULL); - my_strdup(375, &xctx->sch_path[xctx->currsch],"."); - xctx->sch_path_hash[xctx->currsch] = 0; - xctx->sch_inst_number[xctx->currsch] = 1; - zoom_full(1, 0, 1, 0.97); + my_strncpy(f, abs_sym_path(argv[2], ""), S(f)); + + if(f[0] && check_loaded(f, win_path)) { + char msg[PATH_MAX + 100]; + my_snprintf(msg, S(msg), "alert_ {xschem load: %s already open: %s}", f, win_path); + if(has_x) tcleval(msg); + else dbg(0, "xschem load: %s already open: %s\n", f, win_path); + skip = 1; + } + if(!skip) { + clear_all_hilights(); + xctx->currsch = 0; + unselect_all(); + remove_symbols(); + load_schematic(1, f, 1); + tclvareval("update_recent_file {", f, "}", NULL); + my_strdup(375, &xctx->sch_path[xctx->currsch],"."); + xctx->sch_path_hash[xctx->currsch] = 0; + xctx->sch_inst_number[xctx->currsch] = 1; + zoom_full(1, 0, 1, 0.97); + } } } else if(argc==2) { @@ -1582,32 +1595,18 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg } } - else if(!strcmp(argv[1], "load_symbol")) - { - int save, missing = 0; - cmd_found = 1; - if(argc > 2) { - save = xctx->symbols; - match_symbol(argv[2]); - if( xctx->symbols != save && !strcmp( xctx->sym[xctx->symbols - 1].type, "missing") ) { - missing = 1; - remove_symbol( xctx->symbols - 1); - } - } - Tcl_SetResult(interp, missing ? "0" : "1", TCL_STATIC); - } - else if(!strcmp(argv[1],"load_symbol") ) { cmd_found = 1; if(argc==3) { + char f[PATH_MAX]; dbg(1, "scheduler(): load: filename=%s\n", argv[2]); + my_strncpy(f, abs_sym_path(argv[2], ""), S(f)); clear_all_hilights(); xctx->currsch = 0; unselect_all(); remove_symbols(); - /* load_symbol(argv[2]); */ - load_schematic(0, abs_sym_path(argv[2], ""), 1); + load_schematic(0, f, 1); my_strdup(374, &xctx->sch_path[xctx->currsch],"."); xctx->sch_path_hash[xctx->currsch] = 0; xctx->sch_inst_number[xctx->currsch] = 1; @@ -1823,8 +1822,9 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg xctx->last_command = 0; rebuild_selected_array(); if(xctx->lastsel && xctx->sel_array[0].type==ELEMENT) { - tclvareval("set INITIALINSTDIR [file dirname {", - abs_sym_path(xctx->inst[xctx->sel_array[0].n].name, ""), "}]", NULL); + char f[PATH_MAX]; + my_strncpy(f, abs_sym_path(xctx->inst[xctx->sel_array[0].n].name, ""), S(f)); + tclvareval("set INITIALINSTDIR [file dirname {", f, "}]", NULL); } ret = place_symbol(-1,NULL,xctx->mousex_snap, xctx->mousey_snap, 0, 0, NULL, 4, 1, 1/*to_push_undo*/); } diff --git a/src/xinit.c b/src/xinit.c index b6dc6ebb..1e3ed8f1 100644 --- a/src/xinit.c +++ b/src/xinit.c @@ -24,8 +24,6 @@ #ifdef __unix__ #include /* getpwuid */ #endif -/* max number of windows (including main) a single xschem process can handle */ -#define MAX_NEW_WINDOWS 20 static int init_done=0; /* 20150409 to avoid double call by Xwindows close and TclExitHandler */ static XSetWindowAttributes winattr; @@ -39,6 +37,11 @@ typedef int myproc( int argc, const char *argv[]); +/* variables for handling multiple windows/tabs */ +static Xschem_ctx *save_xctx[MAX_NEW_WINDOWS]; /* save pointer to current schematic context structure */ +static char window_path[MAX_NEW_WINDOWS][WINDOW_PATH_SIZE]; +static int window_count = 0; + /* ----------------------------------------------------------------------- */ /* EWMH message handling routines 20071027... borrowed from wmctrl code */ /* ----------------------------------------------------------------------- */ @@ -373,7 +376,7 @@ static void free_xschem_data() my_free(1123, &xctx->enable_layer); my_free(1121, &xctx->active_layer); my_free(1295, &xctx->top_path); - my_free(1295, &xctx->current_win_path); + my_free(1463, &xctx->current_win_path); my_free(1120, &xctx->fill_type); if(xctx->inst_redraw_table) my_free(604, &xctx->inst_redraw_table); my_free(269, &xctx); @@ -412,12 +415,20 @@ static void alloc_xschem_data(const char *top_path, const char *win_path) xctx->tail_undo_ptr = 0; xctx->undo_dirname = NULL; - if(!strcmp(tclgetvar("undo_type"), "disk")) xctx->undo_type = 0; - else xctx->undo_type = 1; /* "memory" */ - xctx->push_undo = &push_undo; - xctx->pop_undo = &pop_undo; - xctx->delete_undo = &delete_undo; - xctx->clear_undo = &clear_undo; + if(!strcmp(tclgetvar("undo_type"), "disk")) { + xctx->undo_type = 0; + xctx->push_undo = push_undo; + xctx->pop_undo = pop_undo; + xctx->delete_undo = delete_undo; + xctx->clear_undo = clear_undo; + + } else { + xctx->undo_type = 1; /* "memory" */ + xctx->push_undo = mem_push_undo; + xctx->pop_undo = mem_pop_undo; + xctx->delete_undo = mem_delete_undo; + xctx->clear_undo = mem_clear_undo; + } xctx->undo_initialized = 0; xctx->zoom=CADINITIALZOOM; xctx->mooz=1/CADINITIALZOOM; @@ -678,7 +689,7 @@ void xwin_exit(void) dbg(1, "xwin_exit(): removing font\n"); for(i=0;i<127;i++) my_free(1140, &character[i]); dbg(1, "xwin_exit(): closed display\n"); - my_free(1141, &filename); + my_strncpy(cli_opt_filename, "", S(cli_opt_filename)); my_free(1143, &xschem_executable); record_global_node(2, NULL, NULL); /* delete global node array */ dbg(1, "xwin_exit(): deleted undo buffer\n"); @@ -897,7 +908,7 @@ int source_tcl_file(char *s) return TCL_OK; } -void preview_window(const char *what, const char *win_path, const char *filename) +void preview_window(const char *what, const char *win_path, const char *fname) { static char *current_file = NULL; static Xschem_ctx *save_xctx = NULL; /* save pointer to current schematic context structure */ @@ -916,11 +927,11 @@ void preview_window(const char *what, const char *win_path, const char *filename else if(!strcmp(what, "draw")) { dbg(1, "preview_window() draw\n"); xctx = preview_xctx; - if(!current_file || strcmp(filename, current_file) ) { + if(!current_file || strcmp(fname, current_file) ) { if(current_file) { delete_schematic_data(); } - my_strdup(117, ¤t_file, filename); + my_strdup(117, ¤t_file, fname); xctx = NULL; /* reset for preview */ alloc_xschem_data(".dialog", ".dialog.drw"); /* alloc data into xctx */ init_pixdata(); /* populate xctx->fill_type array that is used in create_gc() to set fill styles */ @@ -931,7 +942,7 @@ void preview_window(const char *what, const char *win_path, const char *filename build_colors(0.0, 0.0); resetwin(1, 0, 1, 0, 0); /* create preview pixmap. resetwin(create_pixmap, clear_pixmap, force) */ dbg(1, "preview_window() draw, load schematic\n"); - load_schematic(1,filename, 0); + load_schematic(1,fname, 0); } zoom_full(1, 0, 1, 0.97); /* draw */ xctx = save_xctx; @@ -952,6 +963,419 @@ void preview_window(const char *what, const char *win_path, const char *filename } } +/* check if filename is already loaded into a tab or window */ +/* caller should supply a win_path string for storing matching window path */ +int check_loaded(const char *f, char *win_path) +{ + int i; + Xschem_ctx *ctx; + int found = 0; + for(i = 0; i < MAX_NEW_WINDOWS; i++) { + ctx = save_xctx[i]; + if(ctx) { + if(!strcmp(ctx->sch[ctx->currsch], f)) { + found = 1; + my_strncpy(win_path, window_path[i], S(window_path[i])); + break; + } + } + } + return found; +} + +static void switch_window(int *window_count, const char *win_path) +{ + int i, n; + Tk_Window tkwin; + if(*window_count) { + dbg(1, "new_schematic() switch: %s\n", win_path); + tkwin = Tk_NameToWindow(interp, win_path, mainwindow); /* NULL if win_path not existing */ + if(!tkwin) dbg(0, "new_schematic(\"switch\",...): Warning: %s has been destroyed\n", win_path); + n = -1; + if(tkwin) for(i = 0; i < MAX_NEW_WINDOWS; i++) { + if(!strcmp(win_path, window_path[i])) { + n = i; + break; + } + } + if(n == -1) { + dbg(0, "new_schematic(\"switch\"...): no window to switch to found: %s\n", win_path); + return; + } + /* if window was closed then tkwin == 0 --> do nothing */ + if(tkwin && n >= 0 && n < MAX_NEW_WINDOWS) { + xctx = save_xctx[n]; + set_modify(-1); /* sets window title */ + } + } +} + +static void switch_tab(int *window_count, const char *win_path) +{ + int i, n; + if(*window_count) { + dbg(1, "new_schematic() switch_tab: %s\n", win_path); + n = -1; + for(i = 0; i < MAX_NEW_WINDOWS; i++) { + if(!strcmp(win_path, window_path[i])) { + n = i; + break; + } + } + if(n == -1) { + dbg(0, "new_schematic(\"switch_tab\"...): no tab to switch to found: %s\n", win_path); + return; + } + /* if window was closed then tkwin == 0 --> do nothing */ + if(n >= 0 && n < MAX_NEW_WINDOWS) { + tclvareval("save_ctx ", xctx->current_win_path, NULL); + xctx = save_xctx[n]; + tclvareval("restore_ctx ", win_path, NULL); + tclvareval("housekeeping_ctx", NULL); + tclvareval("reconfigure_layers_button {}", NULL); + xctx->window = save_xctx[0]->window; + resetwin(1, 1, 1, 0, 0); + set_modify(-1); /* sets window title */ + draw(); + } + } +} + +static void create_new_window(int *window_count, const char *fname) +{ + Window win_id; + char toppath[WINDOW_PATH_SIZE]; + int i, n; + + dbg(1, "new_schematic() create\n"); + if(*window_count && fname && fname[0] && check_loaded(fname, toppath)) { + char msg[PATH_MAX+100]; + my_snprintf(msg, S(msg), "alert_ {create_new_window: %s already open: %s}", fname, toppath); + if(has_x) + tcleval(msg); + else + dbg(0, "create_new_window: %s already open: %s\n", fname, toppath); + return; + } + if(*window_count == 0) { + for(i = 0; i < MAX_NEW_WINDOWS; i++) { + save_xctx[i] = NULL; + my_strncpy(window_path[i], "", S(window_path[i])); + } + tclvareval("save_ctx ", xctx->current_win_path, NULL); + save_xctx[0] = xctx; /* save current schematic */ + /* window_path[0] = Tk_NameToWindow(interp, ".drw", mainwindow); */ + my_strncpy(window_path[0], xctx->current_win_path, S(window_path[0])); + } + if(*window_count + 1 >= MAX_NEW_WINDOWS) { + dbg(0, "new_schematic(\"create\"...): no more free slots\n"); + return; /* no more free slots */ + } + (*window_count)++; + tcleval(".menubar.view.menu entryconfigure 21 -state disabled"); + n = -1; + for(i = 1; i < MAX_NEW_WINDOWS; i++) { /* search 1st free slot */ + if(save_xctx[i] == NULL) { + n = i; + break; + } + } + if(n == -1) { + dbg(0, "new_schematic(\"create\"...): no more free slots\n"); + return; + } + my_snprintf(window_path[n], S(window_path[n]), ".x%d.drw", n); + my_snprintf(toppath, S(toppath), ".x%d", n); + tclvareval("toplevel ", toppath, " -bg {} -width 400 -height 400", NULL); + tclvareval("build_widgets ", toppath, NULL); + tclvareval("pack_widgets ", toppath, " ; update", NULL); + Tk_MakeWindowExist(Tk_NameToWindow(interp, window_path[n], mainwindow)); + win_id = Tk_WindowId(Tk_NameToWindow(interp, window_path[n], mainwindow)); + Tk_ChangeWindowAttributes(Tk_NameToWindow(interp, window_path[n], mainwindow), CWBackingStore, &winattr); + xctx = NULL; + alloc_xschem_data(toppath, window_path[n]); /* alloc data into xctx */ + xctx->netlist_type = CAD_SPICE_NETLIST; /* for new windows start with spice netlist mode */ + tclsetvar("netlist_type","spice"); + init_pixdata();/* populate xctx->fill_type array that is used in create_gc() to set fill styles */ + save_xctx[n] = xctx; + dbg(1, "new_schematic() draw, load schematic\n"); + xctx->window = win_id; + set_snap(0); /* set default value specified in xschemrc as 'snap' else CADSNAP */ + set_grid(0); /* set default value specified in xschemrc as 'grid' else CADGRID */ + create_gc(); + enable_layers(); + build_colors(0.0, 0.0); + resetwin(1, 0, 1, 0, 0); /* create preview pixmap. resetwin(create_pixmap, clear_pixmap, force, w, h) */ + /* draw empty window so if following load fails due to missing file window appears correctly drawn */ + zoom_full(1, 0, 1, 0.97); + load_schematic(1, fname, 1); + zoom_full(1, 0, 1, 0.97); /* draw */ + tclvareval("set_bindings ", window_path[n], NULL); + tclvareval("save_ctx ", window_path[n], NULL); + windowid(toppath); +} + +static void create_new_tab(int *window_count, const char *win_path, const char *fname) +{ + int i, n; + char open_path[WINDOW_PATH_SIZE]; + + dbg(1, "new_schematic() new_tab, creating...\n"); + if(*window_count && fname && fname[0] && check_loaded(fname, open_path)) { + char msg[PATH_MAX+100]; + my_snprintf(msg, S(msg), "alert_ {create_new_tab: %s already open: %s}", fname, open_path); + if(has_x) + tcleval(msg); + else + dbg(0, "create_new_tab: %s already open: %s\n", fname, open_path); + switch_tab(window_count, open_path); + return; + } + if(*window_count == 0) { + for(i = 0; i < MAX_NEW_WINDOWS; i++) { + save_xctx[i] = NULL; + my_strncpy(window_path[i], "", S(window_path[i])); + } + tclvareval("save_ctx ", xctx->current_win_path, NULL); + save_xctx[0] = xctx; /* save current schematic */ + my_strncpy(window_path[0], xctx->current_win_path, S(window_path[0])); + } + if(*window_count + 1 >= MAX_NEW_WINDOWS) { + dbg(0, "new_schematic(\"new_tab\"...): no more free slots\n"); + return; /* no more free slots */ + } + (*window_count)++; + tcleval(".menubar.view.menu entryconfigure 21 -state disabled"); + n = -1; + for(i = 1; i < MAX_NEW_WINDOWS; i++) { /* search 1st free slot */ + if(save_xctx[i] == NULL) { + n = i; + break; + } + } + if(n == -1) { + dbg(0, "new_schematic(\"newtab\"...): no more free slots\n"); + return; + } + my_strncpy(window_path[n], win_path, S(window_path[n])); + xctx = NULL; + alloc_xschem_data("", win_path); /* alloc data into xctx */ + xctx->netlist_type = CAD_SPICE_NETLIST; /* for new windows start with spice netlist mode */ + tclsetvar("netlist_type","spice"); + init_pixdata();/* populate xctx->fill_type array that is used in create_gc() to set fill styles */ + save_xctx[n] = xctx; + dbg(1, "new_schematic() draw, load schematic\n"); + xctx->window = save_xctx[0]->window; + set_snap(0); /* set default value specified in xschemrc as 'snap' else CADSNAP */ + set_grid(0); /* set default value specified in xschemrc as 'grid' else CADGRID */ + create_gc(); + enable_layers(); + build_colors(0.0, 0.0); + resetwin(1, 0, 1, 0, 0); /* create pixmap. resetwin(create_pixmap, clear_pixmap, force, w, h) */ + /* draw empty window so if following load fails due to missing file window appears correctly drawn */ + zoom_full(1, 0, 1, 0.97); + load_schematic(1,fname, 1); + zoom_full(1, 0, 1, 0.97); /* draw */ +} + +static void destroy_window(int *window_count, const char *win_path) +{ + int i, n; + Xschem_ctx *savectx; + Tk_Window tkwin; + savectx = xctx; + if(*window_count) { + int close = 0; + dbg(1, "new_schematic() destroy {%s}\n", win_path); + if(xctx->modified && has_x) { + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] -message \"" + "[get_cell [xschem get schname] 0]" + ": UNSAVED data: want to exit?\""); + if(strcmp(tclresult(),"ok")==0) close = 1; + } + else close = 1; + Tcl_ResetResult(interp); + if(close) { + tkwin = Tk_NameToWindow(interp, win_path, mainwindow); /* NULL if win_path not existing */ + if(!tkwin) dbg(0, "new_schematic(\"destroy\", ...): Warning: %s has been destroyed\n", win_path); + n = -1; + if(tkwin) for(i = 1; i < MAX_NEW_WINDOWS; i++) { + if(!strcmp(win_path, window_path[i])) { + n = i; + break; + } + } + if(n == -1) { + dbg(0, "new_schematic(\"destroy\"...): no window to destroy found: %s\n", win_path); + return; + } + if(tkwin && n >= 1 && n < MAX_NEW_WINDOWS) { + /* delete Tcl context of deleted schematic window */ + tclvareval("delete_ctx ", win_path, NULL); + xctx = save_xctx[n]; + /* set saved ctx to main window if current is to be destroyed */ + if(savectx == xctx) savectx = save_xctx[0]; + tclvareval("winfo toplevel ", win_path, NULL); + delete_schematic_data(); + save_xctx[n] = NULL; + Tk_DestroyWindow(Tk_NameToWindow(interp, window_path[n], mainwindow)); + tclvareval("destroy ", tclresult(), NULL); + my_strncpy(window_path[n], "", S(window_path[n])); + (*window_count)--; + if(*window_count == 0) tcleval(".menubar.view.menu entryconfigure 21 -state normal"); + } + } + /* following 3 lines must be done also if window not closed */ + xctx = savectx; /* restore previous schematic or main window if previous destroyed */ + tclvareval("restore_ctx ", xctx->current_win_path, " ; housekeeping_ctx", NULL); + set_modify(-1); /* sets window title */ + } else { + dbg(0, "new_schematic() destroy_tab: there are no additional tabs\n"); + } +} + +static void destroy_tab(int *window_count, const char *win_path) +{ + int i, n; + if(*window_count) { + int close = 0; + dbg(1, "new_schematic() destroy_tab\n"); + + if(strcmp(win_path, xctx->current_win_path)) { + dbg(0, "new_schematic(\"destroy_tab\", %s): must be in this tab to destroy\n", win_path); + return; + } + if(xctx->modified && has_x) { + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] -message \"" + "[get_cell [xschem get schname] 0]" + ": UNSAVED data: want to exit?\""); + if(strcmp(tclresult(),"ok")==0) close = 1; + } + else close = 1; + Tcl_ResetResult(interp); + if(close) { + n = -1; + for(i = 1; i < MAX_NEW_WINDOWS; i++) { + if(!strcmp(win_path, window_path[i])) { + n = i; + break; + } + } + if(n == -1) { + dbg(0, "new_schematic(\"destroy_tab\"...): no tab to destroy found: %s\n", win_path); + return; + } + if(n >= 1 && n < MAX_NEW_WINDOWS) { + tclvareval("delete_ctx ", win_path, NULL); + tclvareval("delete_tab ", win_path, NULL); + xctx = save_xctx[n]; + delete_schematic_data(); + save_xctx[n] = NULL; + my_strncpy(window_path[n], "", S(window_path[n])); + /* delete Tcl context of deleted schematic window */ + (*window_count)--; + if(*window_count == 0) tcleval(".menubar.view.menu entryconfigure 21 -state normal"); + } + xctx = save_xctx[0]; /* restore main (.drw) schematic */ + tclvareval("restore_ctx ", xctx->current_win_path, " ; housekeeping_ctx", NULL); + set_modify(-1); /* sets window title */ + draw(); + } + } else { + dbg(0, "new_schematic() destroy_tab: there are no additional tabs\n"); + } +} + +static void destroy_all_windows(int *window_count) +{ + int i; + Xschem_ctx *savectx; + Tk_Window tkwin; + savectx = xctx; + if(*window_count) { + int close; + dbg(1, "new_schematic() destroy_all\n"); + for(i = 1; i < MAX_NEW_WINDOWS; i++) { + if(window_path[i][0]) { + tkwin = Tk_NameToWindow(interp, window_path[i], mainwindow); /* NULL if win_path not existing */ + if(!tkwin) dbg(0, "new_schematic(\"switch\",...): Warning: %s has been destroyed\n", window_path[i]); + else { + xctx = save_xctx[i]; + close = 0; + /* reset old focused window so callback() will force repaint on expose events */ + if(xctx->modified && has_x) { + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] -message \"" + "[get_cell [xschem get schname] 0]" + ": UNSAVED data: want to exit?\""); + if(strcmp(tclresult(),"ok")==0) close = 1; + } + else close = 1; + Tcl_ResetResult(interp); + if(close) { + tclvareval("winfo toplevel ", window_path[i], NULL); + delete_schematic_data(); + /* set saved ctx to main window if previous is about to be destroyed */ + if(savectx == save_xctx[i]) savectx = save_xctx[0]; + save_xctx[i] = NULL; + Tk_DestroyWindow(Tk_NameToWindow(interp, window_path[i], mainwindow)); + tclvareval("destroy ", tclresult(), NULL); + /* delete Tcl context of deleted schematic window */ + tclvareval("delete_ctx ", window_path[i], NULL); + my_strncpy(window_path[i], "", S(window_path[i])); + (*window_count)--; + if(*window_count == 0) tcleval(".menubar.view.menu entryconfigure 21 -state normal"); + } + } + } + } + /* following 3 lines must be done also if windows not closed */ + xctx = savectx; /* restore previous schematic or main if old is destroyed */ + tclvareval("restore_ctx ", xctx->current_win_path, " ; housekeeping_ctx", NULL); + set_modify(-1); /* sets window title */ + } +} + +static void destroy_all_tabs(int *window_count) +{ + int i; + Xschem_ctx *savectx; + savectx = xctx; + if(*window_count) { + int close; + dbg(1, "new_schematic() destroy_all_tabs\n"); + for(i = 1; i < MAX_NEW_WINDOWS; i++) { + if(window_path[i][0]) { + xctx = save_xctx[i]; + close = 0; + /* reset old focused window so callback() will force repaint on expose events */ + if(xctx->modified && has_x) { + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] -message \"" + "[get_cell [xschem get schname] 0]" + ": UNSAVED data: want to exit?\""); + if(strcmp(tclresult(),"ok")==0) close = 1; + } + else close = 1; + Tcl_ResetResult(interp); + if(close) { + /* delete Tcl context of deleted schematic window */ + tclvareval("delete_ctx ", window_path[i], NULL); + tclvareval("delete_tab ", window_path[i], NULL); + delete_schematic_data(); + /* set saved ctx to main window if previous is about to be destroyed */ + if(savectx == save_xctx[i]) savectx = save_xctx[0]; + save_xctx[i] = NULL; + my_strncpy(window_path[i], "", S(window_path[i])); + (*window_count)--; + if(*window_count == 0) tcleval(".menubar.view.menu entryconfigure 21 -state normal"); + } + } + } + /* following 3 lines must be done also if windows not closed */ + xctx = savectx; /* restore previous schematic or main if old is destroyed */ + tclvareval("restore_ctx ", xctx->current_win_path, " ; housekeeping_ctx", NULL); + set_modify(-1); /* sets window title */ + } +} /* top_path is the path prefix of win_path: * @@ -959,15 +1383,8 @@ void preview_window(const char *what, const char *win_path, const char *filename * ".drw" "" * ".x1.drw" ".x1" */ -int new_schematic(const char *what, const char *win_path, const char *filename) +int new_schematic(const char *what, const char *win_path, const char *fname) { - static int cnt = 0; - static Xschem_ctx *save_xctx[MAX_NEW_WINDOWS]; /* save pointer to current schematic context structure */ - /* static Tk_Window new_window[MAX_NEW_WINDOWS]; */ - static char new_window[MAX_NEW_WINDOWS][30]; - int i, n; - Tk_Window tkwin; - char toppath[30]; int tabbed_interface; const char *tmp; @@ -976,364 +1393,34 @@ int new_schematic(const char *what, const char *win_path, const char *filename) if(tmp[0] == '1') tabbed_interface = 1; } dbg(1, "new_schematic(): current_win_path=%s, what=%s, win_path=%s\n", xctx->current_win_path, what, win_path); - /********************** NTABS **********************/ if(!strcmp(what, "ntabs")) { - return cnt; + return window_count; } else if(!strcmp(what, "create")) { - /********************** CREATE **********************/ if(!tabbed_interface) { - Window win_id; - dbg(1, "new_schematic() create\n"); - if(cnt == 0) { - for(i = 0; i < MAX_NEW_WINDOWS; i++) { - save_xctx[i] = NULL; - my_strncpy(new_window[i], "", S(new_window[i])); - } - tclvareval("save_ctx ", xctx->current_win_path, NULL); - save_xctx[0] = xctx; /* save current schematic */ - /* new_window[0] = Tk_NameToWindow(interp, ".drw", mainwindow); */ - my_strncpy(new_window[0], xctx->current_win_path, S(new_window[0])); - } - if(cnt + 1 >= MAX_NEW_WINDOWS) { - dbg(0, "new_schematic(\"create\"...): no more free slots\n"); - return cnt; /* no more free slots */ - } - cnt++; - tcleval(".menubar.view.menu entryconfigure 21 -state disabled"); - n = -1; - for(i = 1; i < MAX_NEW_WINDOWS; i++) { /* search 1st free slot */ - if(save_xctx[i] == NULL) { - n = i; - break; - } - } - if(n == -1) { - dbg(0, "new_schematic(\"create\"...): no more free slots\n"); - return cnt; - } - my_snprintf(new_window[n], S(new_window[n]), ".x%d.drw", n); - my_snprintf(toppath, S(toppath), ".x%d", n); - tclvareval("toplevel ", toppath, " -bg {} -width 400 -height 400", NULL); - tclvareval("build_widgets ", toppath, NULL); - tclvareval("pack_widgets ", toppath, " ; update", NULL); - Tk_MakeWindowExist(Tk_NameToWindow(interp, new_window[n], mainwindow)); - win_id = Tk_WindowId(Tk_NameToWindow(interp, new_window[n], mainwindow)); - Tk_ChangeWindowAttributes(Tk_NameToWindow(interp, new_window[n], mainwindow), CWBackingStore, &winattr); - dbg(1, "new_schematic() draw\n"); - xctx = NULL; /* reset for preview */ - alloc_xschem_data(toppath, new_window[n]); /* alloc data into xctx */ - xctx->netlist_type = CAD_SPICE_NETLIST; /* for new windows start with spice netlist mode */ - tclsetvar("netlist_type","spice"); - init_pixdata();/* populate xctx->fill_type array that is used in create_gc() to set fill styles */ - save_xctx[n] = xctx; - dbg(1, "new_schematic() draw, load schematic\n"); - xctx->window = win_id; - set_snap(0); /* set default value specified in xschemrc as 'snap' else CADSNAP */ - set_grid(0); /* set default value specified in xschemrc as 'grid' else CADGRID */ - create_gc(); - enable_layers(); - build_colors(0.0, 0.0); - resetwin(1, 0, 1, 0, 0); /* create preview pixmap. resetwin(create_pixmap, clear_pixmap, force, w, h) */ - /* draw empty window so if following load fails due to missing file window appears correctly drawn */ - zoom_full(1, 0, 1, 0.97); - load_schematic(1,filename, 1); - zoom_full(1, 0, 1, 0.97); /* draw */ - tclvareval("set_bindings ", new_window[n], NULL); - tclvareval("save_ctx ", new_window[n], NULL); - windowid(toppath); - /********************** CREATE_TAB **********************/ + create_new_window(&window_count, fname); } else { - dbg(1, "new_schematic() new_tab, creating...\n"); - if(cnt == 0) { - for(i = 0; i < MAX_NEW_WINDOWS; i++) { - save_xctx[i] = NULL; - my_strncpy(new_window[i], "", S(new_window[i])); - } - tclvareval("save_ctx ", xctx->current_win_path, NULL); - save_xctx[0] = xctx; /* save current schematic */ - my_strncpy(new_window[0], xctx->current_win_path, S(new_window[0])); - } - if(cnt + 1 >= MAX_NEW_WINDOWS) { - dbg(0, "new_schematic(\"new_tab\"...): no more free slots\n"); - return cnt; /* no more free slots */ - } - cnt++; - tcleval(".menubar.view.menu entryconfigure 21 -state disabled"); - n = -1; - for(i = 1; i < MAX_NEW_WINDOWS; i++) { /* search 1st free slot */ - if(save_xctx[i] == NULL) { - n = i; - break; - } - } - if(n == -1) { - dbg(0, "new_schematic(\"newtab\"...): no more free slots\n"); - return cnt; - } - my_strncpy(new_window[n], win_path, S(new_window[n])); - xctx = NULL; /* reset for preview */ - alloc_xschem_data("", win_path); /* alloc data into xctx */ - xctx->netlist_type = CAD_SPICE_NETLIST; /* for new windows start with spice netlist mode */ - tclsetvar("netlist_type","spice"); - init_pixdata();/* populate xctx->fill_type array that is used in create_gc() to set fill styles */ - save_xctx[n] = xctx; - dbg(1, "new_schematic() draw, load schematic\n"); - xctx->window = save_xctx[0]->window; - set_snap(0); /* set default value specified in xschemrc as 'snap' else CADSNAP */ - set_grid(0); /* set default value specified in xschemrc as 'grid' else CADGRID */ - create_gc(); - enable_layers(); - build_colors(0.0, 0.0); - resetwin(1, 0, 1, 0, 0); /* create pixmap. resetwin(create_pixmap, clear_pixmap, force, w, h) */ - /* draw empty window so if following load fails due to missing file window appears correctly drawn */ - zoom_full(1, 0, 1, 0.97); - load_schematic(1,filename, 1); - zoom_full(1, 0, 1, 0.97); /* draw */ + create_new_tab(&window_count, win_path, fname); } } else if(!strcmp(what, "destroy")) { - /********************** DESTROY **********************/ if(!tabbed_interface) { - Xschem_ctx *savectx; - savectx = xctx; - if(cnt) { - int close = 0; - dbg(1, "new_schematic() destroy {%s}\n", win_path); - if(xctx->modified && has_x) { - tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] -message \"" - "[get_cell [xschem get schname] 0]" - ": UNSAVED data: want to exit?\""); - if(strcmp(tclresult(),"ok")==0) close = 1; - } - else close = 1; - Tcl_ResetResult(interp); - if(close) { - tkwin = Tk_NameToWindow(interp, win_path, mainwindow); /* NULL if win_path not existing */ - if(!tkwin) dbg(0, "new_schematic(\"destroy\", ...): Warning: %s has been destroyed\n", win_path); - n = -1; - if(tkwin) for(i = 1; i < MAX_NEW_WINDOWS; i++) { - if(!strcmp(win_path, new_window[i])) { - n = i; - break; - } - } - if(n == -1) { - dbg(0, "new_schematic(\"destroy\"...): no window to destroy found: %s\n", win_path); - return cnt; - } - if(tkwin && n >= 1 && n < MAX_NEW_WINDOWS) { - /* delete Tcl context of deleted schematic window */ - tclvareval("delete_ctx ", win_path, NULL); - xctx = save_xctx[n]; - /* set saved ctx to main window if current is to be destroyed */ - if(savectx == xctx) savectx = save_xctx[0]; - tclvareval("winfo toplevel ", win_path, NULL); - delete_schematic_data(); - save_xctx[n] = NULL; - Tk_DestroyWindow(Tk_NameToWindow(interp, new_window[n], mainwindow)); - tclvareval("destroy ", tclresult(), NULL); - my_strncpy(new_window[n], "", S(new_window[n])); - cnt--; - if(cnt == 0) tcleval(".menubar.view.menu entryconfigure 21 -state normal"); - } - } - /* following 3 lines must be done also if window not closed */ - xctx = savectx; /* restore previous schematic or main window if previous destroyed */ - tclvareval("restore_ctx ", xctx->current_win_path, " ; housekeeping_ctx", NULL); - set_modify(-1); /* sets window title */ - } - /********************** DESTROY_TAB **********************/ + destroy_window(&window_count, win_path); } else { - if(cnt) { - int close = 0; - dbg(1, "new_schematic() destroy_tab\n"); - - if(strcmp(win_path, xctx->current_win_path)) { - dbg(0, "new_schematic(\"destroy_tab\", %s): must be in this tab to destroy\n", win_path); - return cnt; - } - if(xctx->modified && has_x) { - tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] -message \"" - "[get_cell [xschem get schname] 0]" - ": UNSAVED data: want to exit?\""); - if(strcmp(tclresult(),"ok")==0) close = 1; - } - else close = 1; - Tcl_ResetResult(interp); - if(close) { - n = -1; - for(i = 1; i < MAX_NEW_WINDOWS; i++) { - if(!strcmp(win_path, new_window[i])) { - n = i; - break; - } - } - if(n == -1) { - dbg(0, "new_schematic(\"destroy_tab\"...): no tab to destroy found: %s\n", win_path); - return cnt; - } - if(n >= 1 && n < MAX_NEW_WINDOWS) { - tclvareval("delete_ctx ", win_path, NULL); - tclvareval("delete_tab ", win_path, NULL); - xctx = save_xctx[n]; - delete_schematic_data(); - save_xctx[n] = NULL; - my_strncpy(new_window[n], "", S(new_window[n])); - /* delete Tcl context of deleted schematic window */ - cnt--; - if(cnt == 0) tcleval(".menubar.view.menu entryconfigure 21 -state normal"); - } - xctx = save_xctx[0]; /* restore main (.drw) schematic */ - tclvareval("restore_ctx ", xctx->current_win_path, " ; housekeeping_ctx", NULL); - set_modify(-1); /* sets window title */ - draw(); - } - } else { - dbg(0, "new_schematic() destroy_tab: there are no additional tabs\n"); - } + destroy_tab(&window_count, win_path); } } else if(!strcmp(what, "destroy_all")) { - /********************** DESTROY_ALL **********************/ if(!tabbed_interface) { - Xschem_ctx *savectx; - savectx = xctx; - if(cnt) { - int close; - dbg(1, "new_schematic() destroy_all\n"); - for(i = 1; i < MAX_NEW_WINDOWS; i++) { - if(new_window[i][0]) { - tkwin = Tk_NameToWindow(interp, new_window[i], mainwindow); /* NULL if win_path not existing */ - if(!tkwin) dbg(0, "new_schematic(\"switch\",...): Warning: %s has been destroyed\n", new_window[i]); - else { - xctx = save_xctx[i]; - close = 0; - /* reset old focused window so callback() will force repaint on expose events */ - if(xctx->modified && has_x) { - tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] -message \"" - "[get_cell [xschem get schname] 0]" - ": UNSAVED data: want to exit?\""); - if(strcmp(tclresult(),"ok")==0) close = 1; - } - else close = 1; - Tcl_ResetResult(interp); - if(close) { - tclvareval("winfo toplevel ", new_window[i], NULL); - delete_schematic_data(); - /* set saved ctx to main window if previous is about to be destroyed */ - if(savectx == save_xctx[i]) savectx = save_xctx[0]; - save_xctx[i] = NULL; - Tk_DestroyWindow(Tk_NameToWindow(interp, new_window[i], mainwindow)); - tclvareval("destroy ", tclresult(), NULL); - /* delete Tcl context of deleted schematic window */ - tclvareval("delete_ctx ", new_window[i], NULL); - my_strncpy(new_window[i], "", S(new_window[i])); - cnt--; - if(cnt == 0) tcleval(".menubar.view.menu entryconfigure 21 -state normal"); - } - } - } - } - } - /* following 3 lines must be done also if windows not closed */ - xctx = savectx; /* restore previous schematic or main if old is destroyed */ - tclvareval("restore_ctx ", xctx->current_win_path, " ; housekeeping_ctx", NULL); - set_modify(-1); /* sets window title */ - /********************* DESTROY_ALL_TABS ******************/ + destroy_all_windows(&window_count); } else { - Xschem_ctx *savectx; - savectx = xctx; - if(cnt) { - int close; - dbg(1, "new_schematic() destroy_all_tabs\n"); - for(i = 1; i < MAX_NEW_WINDOWS; i++) { - if(new_window[i][0]) { - xctx = save_xctx[i]; - close = 0; - /* reset old focused window so callback() will force repaint on expose events */ - if(xctx->modified && has_x) { - tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] -message \"" - "[get_cell [xschem get schname] 0]" - ": UNSAVED data: want to exit?\""); - if(strcmp(tclresult(),"ok")==0) close = 1; - } - else close = 1; - Tcl_ResetResult(interp); - if(close) { - /* delete Tcl context of deleted schematic window */ - tclvareval("delete_ctx ", new_window[i], NULL); - tclvareval("delete_tab ", new_window[i], NULL); - delete_schematic_data(); - /* set saved ctx to main window if previous is about to be destroyed */ - if(savectx == save_xctx[i]) savectx = save_xctx[0]; - save_xctx[i] = NULL; - my_strncpy(new_window[i], "", S(new_window[i])); - cnt--; - if(cnt == 0) tcleval(".menubar.view.menu entryconfigure 21 -state normal"); - } - } - } - } - /* following 3 lines must be done also if windows not closed */ - xctx = savectx; /* restore previous schematic or main if old is destroyed */ - tclvareval("restore_ctx ", xctx->current_win_path, " ; housekeeping_ctx", NULL); - set_modify(-1); /* sets window title */ - - + destroy_all_tabs(&window_count); } } else if(!strcmp(what, "switch")) { - /********************** SWITCH **********************/ if(!tabbed_interface) { - if(cnt) { - dbg(1, "new_schematic() switch: %s\n", win_path); - tkwin = Tk_NameToWindow(interp, win_path, mainwindow); /* NULL if win_path not existing */ - if(!tkwin) dbg(0, "new_schematic(\"switch\",...): Warning: %s has been destroyed\n", win_path); - n = -1; - if(tkwin) for(i = 0; i < MAX_NEW_WINDOWS; i++) { - if(!strcmp(win_path, new_window[i])) { - n = i; - break; - } - } - if(n == -1) { - dbg(0, "new_schematic(\"switch\"...): no window to switch to found: %s\n", win_path); - return cnt; - } - /* if window was closed then tkwin == 0 --> do nothing */ - if(tkwin && n >= 0 && n < MAX_NEW_WINDOWS) { - xctx = save_xctx[n]; - set_modify(-1); /* sets window title */ - } - } - /********************** SWITCH_TAB **********************/ + switch_window(&window_count, win_path); } else { - if(cnt) { - dbg(1, "new_schematic() switch_tab: %s\n", win_path); - n = -1; - for(i = 0; i < MAX_NEW_WINDOWS; i++) { - if(!strcmp(win_path, new_window[i])) { - n = i; - break; - } - } - if(n == -1) { - dbg(0, "new_schematic(\"switch_tab\"...): no tab to switch to found: %s\n", win_path); - return cnt; - } - /* if window was closed then tkwin == 0 --> do nothing */ - if(n >= 0 && n < MAX_NEW_WINDOWS) { - tclvareval("save_ctx ", xctx->current_win_path, NULL); - xctx = save_xctx[n]; - tclvareval("restore_ctx ", win_path, NULL); - tclvareval("housekeeping_ctx", NULL); - tclvareval("reconfigure_layers_button {}", NULL); - xctx->window = save_xctx[0]->window; - resetwin(1, 1, 1, 0, 0); - set_modify(-1); /* sets window title */ - draw(); - } - } + switch_tab(&window_count, win_path); } } - return cnt; + return window_count; } void change_linewidth(double w) @@ -2080,23 +2167,23 @@ int Tcl_AppInit(Tcl_Interp *inter) my_snprintf(pwd_dir, S(pwd_dir), "%s", tclgetvar("env(PWD)")); } - if(filename) { + if(cli_opt_filename[0]) { char f[PATH_MAX]; #ifdef __unix__ - if(filename[0] == '~' && filename[1] == '/') { - my_snprintf(f, S(f), "%s%s", home_dir, filename + 1); - } else if(filename[0] == '.' && filename[1] == '/') { - my_snprintf(f, S(f), "%s%s", pwd_dir, filename + 1); - } else if(filename[0] !='/') { - my_snprintf(f, S(f), "%s/%s", pwd_dir, filename); + if(cli_opt_filename[0] == '~' && cli_opt_filename[1] == '/') { + my_snprintf(f, S(f), "%s%s", home_dir, cli_opt_filename + 1); + } else if(cli_opt_filename[0] == '.' && cli_opt_filename[1] == '/') { + my_snprintf(f, S(f), "%s%s", pwd_dir, cli_opt_filename + 1); + } else if(cli_opt_filename[0] !='/') { + my_snprintf(f, S(f), "%s/%s", pwd_dir, cli_opt_filename); } else { - my_snprintf(f, S(f), "%s", filename); + my_snprintf(f, S(f), "%s", cli_opt_filename); } #else - my_strncpy(f, abs_sym_path(filename, ""), S(f)); + my_strncpy(f, abs_sym_path(cli_opt_filename, ""), S(f)); #endif - dbg(1, "Tcl_AppInit(): filename %s given, removing symbols\n", filename); + dbg(1, "Tcl_AppInit(): cli_opt_filename %s given, removing symbols\n", cli_opt_filename); remove_symbols(); /* if do_netlist=1 call load_schematic with 'reset_undo=0' avoiding call to tcl is_xschem_file that could change xctx->netlist_type to symbol */ @@ -2104,16 +2191,16 @@ int Tcl_AppInit(Tcl_Interp *inter) tclvareval("update_recent_file {", f, "}", NULL); } else if(!tcl_script[0]) { char * tmp; - char filename[PATH_MAX]; + char fname[PATH_MAX]; tmp = (char *) tclgetvar("XSCHEM_START_WINDOW"); #ifndef __unix__ change_to_unix_fn(tmp); #endif dbg(1, "Tcl_AppInit(): tmp=%s\n", tmp? tmp: "NULL"); - my_strncpy(filename, abs_sym_path(tmp, ""), S(filename)); + my_strncpy(fname, abs_sym_path(tmp, ""), S(fname)); /* if do_netlist=1 call load_schematic with 'reset_undo=0' avoiding call to tcl is_xschem_file that could change xctx->netlist_type to symbol */ - load_schematic(1, filename, !do_netlist); + load_schematic(1, fname, !do_netlist); } tclsetintvar("tctx::max_new_windows", MAX_NEW_WINDOWS); @@ -2125,7 +2212,7 @@ int Tcl_AppInit(Tcl_Interp *inter) if(xctx->flat_netlist) fprintf(errfp, "xschem: flat netlist requested\n"); } - if(!filename) { + if(!cli_opt_filename[0]) { fprintf(errfp, "xschem: cant do a netlist without a filename\n"); tcleval("exit"); } @@ -2143,7 +2230,7 @@ int Tcl_AppInit(Tcl_Interp *inter) } } if(do_print) { - if(!filename) { + if(!cli_opt_filename[0]) { dbg(0, "xschem: can't do a print without a filename\n"); tcleval("exit"); } @@ -2173,7 +2260,7 @@ int Tcl_AppInit(Tcl_Interp *inter) } if(do_simulation) { - if(!filename) { + if(!cli_opt_filename[0]) { fprintf(errfp, "xschem: can't do a simulation without a filename\n"); tcleval("exit"); } @@ -2181,7 +2268,7 @@ int Tcl_AppInit(Tcl_Interp *inter) } if(do_waves) { - if(!filename) { + if(!cli_opt_filename[0]) { fprintf(errfp, "xschem: can't show simulation waves without a filename\n"); tcleval("exit"); } diff --git a/src/xschem.h b/src/xschem.h index 86817eaa..67c1ffb7 100644 --- a/src/xschem.h +++ b/src/xschem.h @@ -125,6 +125,10 @@ extern char win_temp_dir[PATH_MAX]; #define CADHEIGHT 700 /* initial window size */ #define CADWIDTH 1000 +/* max number of windows (including main) a single xschem process can handle */ +#define MAX_NEW_WINDOWS 20 +#define WINDOW_PATH_SIZE 30 + #define BACKLAYER 0 #define WIRELAYER 1 #define GRIDLAYER 2 @@ -904,7 +908,7 @@ typedef struct { int netlist_count; /* netlist counter incremented at any cell being netlisted */ int hide_symbols; int netlist_type; - char * top_path; + char *top_path; /* top_path is the path prefix of drawing canvas (current_win_path): * * current_win_path @@ -966,7 +970,6 @@ extern char *cad_icon[]; extern int do_print; extern FILE *errfp; extern int no_readline; -extern char *filename; extern char home_dir[PATH_MAX]; /* home dir obtained via getpwuid */ extern char user_conf_dir[PATH_MAX]; /* usually ~/.xschem */ extern char pwd_dir[PATH_MAX]; /* obtained via getcwd() */ @@ -996,6 +999,7 @@ extern int cli_opt_netlist_type; extern int cli_opt_flat_netlist; extern char cli_opt_plotfile[PATH_MAX]; extern char cli_opt_netlist_dir[PATH_MAX]; +extern char cli_opt_filename[PATH_MAX]; /*********** Following data is relative to the current schematic ***********/ extern Xschem_ctx *xctx; @@ -1021,7 +1025,7 @@ extern void here(double i); extern void print_version(void); extern int set_netlist_dir(int force, char *dir); extern void netlist_options(int i); -extern int check_lib(int what, const char * s); +extern int check_lib(int what, const char *s); extern void select_all(void); extern void change_linewidth(double w); extern void schematic_in_new_window(void); @@ -1200,6 +1204,8 @@ extern void mem_pop_undo(int redo, int set_modify_status); extern void mem_delete_undo(void); extern void mem_clear_undo(void); extern void load_schematic(int load_symbol, const char *abs_name, int reset_undo); +/* check if filename already in an open window/tab */ +extern int check_loaded(const char *f, char *win_path); extern void link_symbols_to_instances(int from); extern void load_ascii_string(char **ptr, FILE *fd); extern void read_xschem_file(FILE *fd); @@ -1369,8 +1375,8 @@ extern void list_hilights(void); extern void change_layer(); extern void launcher(); extern void windowid(const char *winpath); -extern void preview_window(const char *what, const char *tk_win_path, const char *filename); -extern int new_schematic(const char *what, const char *win_path, const char *filename); +extern void preview_window(const char *what, const char *tk_win_path, const char *fname); +extern int new_schematic(const char *what, const char *win_path, const char *fname); extern int window_state (Display *disp, Window win, char *arg); extern void toggle_fullscreen(const char *topwin); extern void toggle_only_probes(); diff --git a/src/xschem.tcl b/src/xschem.tcl index 94f48525..fa305dd4 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -3718,7 +3718,7 @@ proc toolbar_hide { { topwin {} } } { proc setup_tabbed_interface {} { global tabbed_interface - set top_path [xschem get top_path] + set top_path {} if { $tabbed_interface } { frame $top_path.tabs button $top_path.tabs.x0 -padx 2 -pady 0 -text Main -command {xschem new_schematic switch .drw} @@ -3734,11 +3734,11 @@ proc setup_tabbed_interface {} { if {$tabbed_interface} { $top_path.menubar.file.menu entryconfigure 6 -state disabled $top_path.menubar.file.menu entryconfigure 7 -state disabled + set_tab_names } else { $top_path.menubar.file.menu entryconfigure 6 -state normal $top_path.menubar.file.menu entryconfigure 7 -state normal } - set_tab_names } proc delete_tab {path} { @@ -3824,7 +3824,7 @@ proc set_tab_names {} { set top_path [xschem get top_path] if {$tabname eq {}} { set tabname .x0} # puts "set_tab_names : currwin=$currwin" - ${top_path}.tabs$tabname configure -text [file rootname [file tail [xschem get schname]]] -bg Palegreen + ${top_path}.tabs$tabname configure -text [file tail [xschem get schname]] -bg Palegreen for { set i 0} { $i < $tctx::max_new_windows} { incr i} { if { [winfo exists ${top_path}.tabs.x$i] && ($tabname ne ".x$i")} { ${top_path}.tabs.x$i configure -bg $tctx::tab_bg @@ -3833,13 +3833,27 @@ proc set_tab_names {} { } } +proc test2 {} { + global tabbed_interface + + set tabbed_interface 0 + xschem load [abs_sym_path testbench.sch] + xschem load_new_window [abs_sym_path poweramp.sch] + xschem load_new_window [abs_sym_path mos_power_ampli.sch] + xschem load_new_window [abs_sym_path rom8k.sch] + xschem load_new_window [abs_sym_path autozero_comp.sch] + xschem load_new_window [abs_sym_path LCC_instances.sch] + xschem load_new_window [abs_sym_path simulate_ff.sch] + xschem load_new_window [abs_sym_path led_driver.sch] + xschem load_new_window [abs_sym_path solar_panel.sch] +} proc test1 {} { global tabbed_interface set tabbed_interface 1 setup_tabbed_interface - xschem load [abs_sym_path rom8k.sch] + xschem load [abs_sym_path testbench.sch] create_new_tab xschem load [abs_sym_path poweramp.sch] create_new_tab @@ -4144,16 +4158,6 @@ proc build_widgets { {topwin {} } } { set mbg {-bg gray50} set bbg {-bg gray50 -highlightthickness 0} } - - if { $tabbed_interface } { - frame $topwin.tabs - button $topwin.tabs.x0 -padx 2 -pady 0 -text Main -command {xschem new_schematic switch .drw} - # button $topwin.tabs.x1 -padx 2 -pady 0 -text Tab1 -command {xschem new_schematic switch .x1.drw} - # button $topwin.tabs.x2 -padx 2 -pady 0 -text Tab2 -command {xschem new_schematic switch .x2.drw} - button $topwin.tabs.add -padx 0 -pady 0 -text { + } -command create_new_tab - # pack $topwin.tabs.x0 $topwin.tabs.x1 $topwin.tabs.x2 $topwin.tabs.add -side left - pack $topwin.tabs.x0 $topwin.tabs.add -side left - } eval frame $topwin.menubar -relief raised -bd 2 $mbg toolbar_toolbar $topwin eval menubutton $topwin.menubar.file -text "File" -menu $topwin.menubar.file.menu \ @@ -4622,6 +4626,7 @@ proc build_widgets { {topwin {} } } { focus $topwin.drw if { $topwin == {} } {set rootwin .} else { set rootwin $topwin} + setup_tabbed_interface wm title $rootwin "xschem - " wm iconname $rootwin "xschem - " $rootwin configure -background {}