defer tk windows/menu/widgets creation and Xevent binding setup after xinit.c completes X initialization. This avoids theoretical race condidions if a ConfigureNotify or Expose event is delivered before all Xlib initialization completed.

This commit is contained in:
Stefan Schippers 2020-08-31 13:54:37 +02:00
parent 6608230df9
commit 08bf7cb962
2 changed files with 87 additions and 51 deletions

View File

@ -1340,6 +1340,13 @@ int Tcl_AppInit(Tcl_Interp *inter)
init_done=1; /* 20171008 moved before option processing, otherwise xwin_exit will not be invoked */
/* leaving undo buffer and other garbage around. */
/* */
/* Completing tk windows creation (see xschem.tcl, build_windows) and event binding */
/* *AFTER* X initialization done */
/* */
tcleval("build_windows");
/* */
/* START PROCESSING USER OPTIONS */
/* */
@ -1403,11 +1410,18 @@ int Tcl_AppInit(Tcl_Interp *inter)
}
if(do_print) {
if(!filename) {
fprintf(errfp, "xschem: can't do a print without a filename\n");
dbg(0, "xschem: can't do a print without a filename\n");
tcleval( "exit");
}
if(do_print==1) ps_draw();
else if(do_print == 2) { tcleval("tkwait visibility .drw"); print_image(); }
else if(do_print == 2) {
if(!has_x) {
dbg(0, "xschem: can not do a png export if no X11 present / Xserver running (check if DISPLAY set).\n");
} else {
tcleval("tkwait visibility .drw");
print_image();
}
}
else svg_draw();
}
@ -1439,6 +1453,7 @@ int Tcl_AppInit(Tcl_Interp *inter)
/* END PROCESSING USER OPTIONS */
/* */
if(!no_readline) {
tcleval( "if {![catch {package require tclreadline}]} "
"{::tclreadline::readline customcompleter completer; ::tclreadline::Loop }" ) ;

View File

@ -2870,6 +2870,70 @@ proc toolbar_hide {} {
set $toolbar_visible 0
}
## this function sets up all tk windows and binds X events. It is executed by xinit.c after completing
## all X initialization. This avoids race conditions.
## In previous flow xschem.tcl was setting up windows and events before X initialization was completed by xinit.c.
## this could lead to crashes on some (may be slow) systems due to Configure/Expose events being delivered
## before xschem being ready to handle them.
proc build_windows {} {
global env
if { ( $::OS== "Windows" || [string length [lindex [array get env DISPLAY] 1] ] > 0 )
&& ![info exists no_x]} {
pack .statusbar.2 -side left
pack .statusbar.3 -side left
pack .statusbar.4 -side left
pack .statusbar.5 -side left
pack .statusbar.6 -side left
pack .statusbar.7 -side left
pack .statusbar.1 -side left -fill x
pack .drw -anchor n -side top -fill both -expand true
pack .menubar -anchor n -side top -fill x -before .drw
toolbar_show
pack .statusbar -after .drw -anchor sw -fill x
bind .statusbar.5 <Leave> { xschem set cadgrid $grid; focus .drw}
bind .statusbar.3 <Leave> { xschem set cadsnap $snap; focus .drw}
###
### Tk event handling
###
### bind .drv <event> {xschem callback <type> <x> <y> <keysym> <button of w> <h> <state>}
###
bind . <Visibility> {
if { [winfo exists .dialog] && [winfo ismapped .dialog] && [winfo ismapped .] && [wm stackorder .dialog isbelow . ]} {
raise .dialog .drw
}
}
bind .drw <Double-Button-1> {xschem callback -3 %x %y 0 %b 0 %s}
bind .drw <Double-Button-2> {xschem callback -3 %x %y 0 %b 0 %s}
bind .drw <Double-Button-3> {xschem callback -3 %x %y 0 %b 0 %s}
bind .drw <Expose> {xschem callback %T %x %y 0 %w %h %s}
bind .drw <Configure> {xschem windowid; xschem callback %T %x %y 0 %w %h 0}
bind .drw <ButtonPress> {xschem callback %T %x %y 0 %b 0 %s}
if {$::OS == "Windows"} {
bind .drw <MouseWheel> {
if {%D<0} {
xschem callback 4 %x %y 0 5 0 %s
} else {
xschem callback 4 %x %y 0 4 0 %s
}
}
}
bind .drw <ButtonRelease> {xschem callback %T %x %y 0 %b 0 %s}
bind .drw <KeyPress> {xschem callback %T %x %y %N 0 0 %s}
bind .drw <KeyRelease> {xschem callback %T %x %y %N 0 0 %s} ;# 20161118
bind .drw <Motion> {xschem callback %T %x %y 0 0 0 %s}
bind .drw <Enter> {xschem callback %T %x %y 0 0 0 0 }
bind .drw <Leave> {}
bind .drw <Unmap> {
wm withdraw .infotext
set show_infowindow 0
}
bind .drw "?" { textwindow "${XSCHEM_SHAREDIR}/xschem.help" }
}
}
###
### MAIN PROGRAM
###
@ -3635,57 +3699,13 @@ font configure Underline-Font -underline true -size 24
label .statusbar.6 -text "NETLIST MODE:"
entry .statusbar.7 -textvariable netlist_type -relief sunken -bg white \
-width 10 -state disabled -disabledforeground black
pack .statusbar.2 -side left
pack .statusbar.3 -side left
pack .statusbar.4 -side left
pack .statusbar.5 -side left
pack .statusbar.6 -side left
pack .statusbar.7 -side left
pack .statusbar.1 -side left -fill x
pack .drw -anchor n -side top -fill both -expand true
pack .menubar -anchor n -side top -fill x -before .drw
toolbar_show
pack .statusbar -after .drw -anchor sw -fill x
bind .statusbar.5 <Leave> { xschem set cadgrid $grid; focus .drw}
bind .statusbar.3 <Leave> { xschem set cadsnap $snap; focus .drw}
###
### Tk event handling
###
### bind .drv <event> {xschem callback <type> <x> <y> <keysym> <button of w> <h> <state>}
###
bind . <Visibility> {
if { [winfo exists .dialog] && [winfo ismapped .dialog] && [winfo ismapped .] && [wm stackorder .dialog isbelow . ]} {
raise .dialog .drw
}
}
bind .drw <Double-Button-1> {xschem callback -3 %x %y 0 %b 0 %s}
bind .drw <Double-Button-2> {xschem callback -3 %x %y 0 %b 0 %s}
bind .drw <Double-Button-3> {xschem callback -3 %x %y 0 %b 0 %s}
bind .drw <Expose> {xschem callback %T %x %y 0 %w %h %s}
bind .drw <Configure> {xschem windowid; xschem callback %T %x %y 0 %w %h 0}
bind .drw <ButtonPress> {xschem callback %T %x %y 0 %b 0 %s}
if {$::OS == "Windows"} {
bind .drw <MouseWheel> {
if {%D<0} {
xschem callback 4 %x %y 0 5 0 %s
} else {
xschem callback 4 %x %y 0 4 0 %s
}
}
}
bind .drw <ButtonRelease> {xschem callback %T %x %y 0 %b 0 %s}
bind .drw <KeyPress> {xschem callback %T %x %y %N 0 0 %s}
bind .drw <KeyRelease> {xschem callback %T %x %y %N 0 0 %s} ;# 20161118
bind .drw <Motion> {xschem callback %T %x %y 0 0 0 %s}
bind .drw <Enter> {xschem callback %T %x %y 0 0 0 0 }
bind .drw <Leave> {}
bind .drw <Unmap> {
wm withdraw .infotext
set show_infowindow 0
}
bind .drw "?" { textwindow "${XSCHEM_SHAREDIR}/xschem.help" }
##
## building windows (pack instructions) and event binding (bind instructions) done in proc build_windows
## executed by xinit.c after finalizing X initialization. This avoid potential race conditions
## like Configure or Expose events being generated before xschem being ready to handle them.
##
if {[array exists replace_key]} {
foreach i [array names replace_key] {
@ -3724,3 +3744,4 @@ if { [info exists xschem_listen_port] && ($xschem_listen_port ne {}) } {
puts $err
}
}