diff options
Diffstat (limited to 'unix')
-rw-r--r-- | unix/Makefile.in | 227 | ||||
-rw-r--r-- | unix/README | 12 | ||||
-rw-r--r-- | unix/configure.in | 103 | ||||
-rw-r--r-- | unix/mkLinks | 120 | ||||
-rw-r--r-- | unix/tkAppInit.c | 13 | ||||
-rw-r--r-- | unix/tkUnix.c | 6 | ||||
-rw-r--r-- | unix/tkUnixButton.c | 49 | ||||
-rw-r--r-- | unix/tkUnixConfig.c | 45 | ||||
-rw-r--r-- | unix/tkUnixCursor.c | 19 | ||||
-rw-r--r-- | unix/tkUnixDefault.h | 13 | ||||
-rw-r--r-- | unix/tkUnixEmbed.c | 61 | ||||
-rw-r--r-- | unix/tkUnixEvent.c | 112 | ||||
-rw-r--r-- | unix/tkUnixFocus.c | 3 | ||||
-rw-r--r-- | unix/tkUnixFont.c | 2770 | ||||
-rw-r--r-- | unix/tkUnixInit.c | 12 | ||||
-rw-r--r-- | unix/tkUnixInt.h | 7 | ||||
-rw-r--r-- | unix/tkUnixKey.c | 90 | ||||
-rw-r--r-- | unix/tkUnixMenu.c | 447 | ||||
-rw-r--r-- | unix/tkUnixMenubu.c | 13 | ||||
-rw-r--r-- | unix/tkUnixPort.h | 19 | ||||
-rw-r--r-- | unix/tkUnixScale.c | 42 | ||||
-rw-r--r-- | unix/tkUnixSelect.c | 85 | ||||
-rw-r--r-- | unix/tkUnixSend.c | 107 | ||||
-rw-r--r-- | unix/tkUnixWm.c | 320 | ||||
-rw-r--r-- | unix/tkUnixXId.c | 7 |
25 files changed, 3420 insertions, 1282 deletions
diff --git a/unix/Makefile.in b/unix/Makefile.in index a4af245..98dc87a 100644 --- a/unix/Makefile.in +++ b/unix/Makefile.in @@ -5,7 +5,7 @@ # "autoconf" program (constructs like "@foo@" will get replaced in the # actual Makefile. # -# RCS: @(#) $Id: Makefile.in,v 1.13 1999/03/10 07:04:45 stanton Exp $ +# RCS: @(#) $Id: Makefile.in,v 1.14 1999/04/16 01:51:44 stanton Exp $ # Current Tk version; used in various names. @@ -76,6 +76,7 @@ MANN_INSTALL_DIR = $(MAN_INSTALL_DIR)/mann # for this version of Tk ("srcdir" will be replaced or has already # been replaced by the configure script): TCL_GENERIC_DIR = @TCL_SRC_DIR@/generic +TCL_UNIX_DIR = @TCL_SRC_DIR@/unix # The directory containing the Tcl library archive file appropriate # for this version of Tk: @@ -110,6 +111,7 @@ X11_INCLUDES = @XINCLUDES@ # can override it). X11_LIB_SWITCHES = @XLIBSW@ + # To turn off the security checks that disallow incoming sends when # the X server appears to be insecure, reverse the comments on the # following lines: @@ -128,22 +130,6 @@ PROTO_FLAGS = MEM_DEBUG_FLAGS = #MEM_DEBUG_FLAGS = -DTCL_MEM_DEBUG -# To enable support for stubs in Tcl. -STUB_LIB_FILE = @STUB_LIB_FILE@ - -TK_STUB_LIB_FILE = @TK_STUB_LIB_FILE@ -#TK_STUB_LIB_FILE = libtkstub.a - -TK_STUB_LIB_FLAG = @TK_STUB_LIB_FLAG@ -#TK_STUB_LIB_FLAG = -ltkstub - - - -# Libraries to use when linking. This definition is determined by the -# configure script. -LIBS = @TCL_BUILD_LIB_SPEC@ @LIBS@ $(X11_LIB_SWITCHES) @DL_LIBS@ @MATH_LIBS@ -lc - - # If your X server is X11R4 or earlier, then you may wish to reverse # the comment characters on the following two lines. This will enable # extra code to speed up XStringToKeysym. In X11R5 and later releases @@ -151,6 +137,12 @@ LIBS = @TCL_BUILD_LIB_SPEC@ @LIBS@ $(X11_LIB_SWITCHES) @DL_LIBS@ @MATH_LIBS@ -l KEYSYM_FLAGS = #KEYSYM_FLAGS = -DREDO_KEYSYM_LOOKUP +# Tk does not used deprecated Tcl constructs so it should +# compile fine with -DTCL_NO_DEPRECATED. To remove its own +# set of deprecated code uncomment the second line. +NO_DEPRECATED_FLAGS= -DTCL_NO_DEPRECATED +#NO_DEPRECATED_FLAGS= -DTCL_NO_DEPRECATED -DTK_NO_DEPRECATED + # Some versions of make, like SGI's, use the following variable to # determine which shell to use for executing commands: SHELL = /bin/sh @@ -172,15 +164,32 @@ INSTALL_DATA = ${INSTALL} -m 644 TK_SHLIB_CFLAGS = @TK_SHLIB_CFLAGS@ +# To enable support for stubs in Tcl. +STUB_LIB_FILE = @STUB_LIB_FILE@ + +TK_STUB_LIB_FILE = @TK_STUB_LIB_FILE@ +#TK_STUB_LIB_FILE = libtkstub.a + +TK_STUB_LIB_FLAG = @TK_STUB_LIB_FLAG@ +#TK_STUB_LIB_FLAG = -ltkstub + TK_LIB_FILE = @TK_LIB_FILE@ #TK_LIB_FILE = libtk.a TK_LIB_FLAG = @TK_LIB_FLAG@ #TK_LIB_FLAG = -ltk +TCL_LIB_SPEC = @TCL_BUILD_LIB_SPEC@ TK_EXP_FILE = @TK_EXP_FILE@ TK_BUILD_EXP_FILE = @TK_BUILD_EXP_FILE@ +TCL_STUB_FLAGS = @TCL_STUB_FLAGS@ + +# Libraries to use when linking. This definition is determined by the +# configure script. +LIBS = @LIBS@ $(X11_LIB_SWITCHES) @DL_LIBS@ @MATH_LIBS@ -lc +WISH_LIBS = $(TCL_LIB_SPEC) @LIBS@ $(X11_LIB_SWITCHES) @DL_LIBS@ @MATH_LIBS@ -lc + # The symbol below provides support for dynamic loading and shared # libraries. See configure.in for a description of what it means. # The values of the symbolis normally set by the configure script. @@ -216,29 +225,28 @@ TOOL_DIR = @TCL_SRC_DIR@/tools CC = @CC@ -CC_SWITCHES = ${CFLAGS} ${CFLAGS_WARNING} ${TK_SHLIB_CFLAGS} \ + +CC_SWITCHES_NO_STUBS = ${CFLAGS} ${CFLAGS_WARNING} ${TK_SHLIB_CFLAGS} \ -I${UNIX_DIR} -I${GENERIC_DIR} \ -I${BMAP_DIR} -I${TCL_GENERIC_DIR} ${X11_INCLUDES} \ ${AC_FLAGS} ${PROTO_FLAGS} \ -${SECURITY_FLAGS} ${MEM_DEBUG_FLAGS} ${KEYSYM_FLAGS} +${SECURITY_FLAGS} ${MEM_DEBUG_FLAGS} ${KEYSYM_FLAGS} ${NO_DEPRECATED_FLAGS} + +CC_SWITCHES = ${CC_SWITCHES_NO_STUBS} ${TCL_STUB_FLAGS} -STUB_CC_SWITCHES = ${CFLAGS} ${CFLAGS_WARNING} ${SHLIB_CFLAGS} \ --I${UNIX_DIR} -I${GENERIC_DIR} \ --I${BMAP_DIR} -I${TCL_GENERIC_DIR} ${X11_INCLUDES} \ -${AC_FLAGS} ${PROTO_FLAGS} \ -${SECURITY_FLAGS} ${MEM_DEBUG_FLAGS} ${KEYSYM_FLAGS} \ - -DTK_SHLIB_EXT=\"${SHLIB_SUFFIX}\" DEPEND_SWITCHES = ${CFLAGS} -I${UNIX_DIR} -I${GENERIC_DIR} \ -I${BMAP_DIR} \ -I${TCL_GENERIC_DIR} ${X11_INCLUDES} \ ${AC_FLAGS} ${PROTO_FLAGS} ${SECURITY_FLAGS} ${MEM_DEBUG_FLAGS} \ -${KEYSYM_FLAGS} -DTK_SHLIB_EXT=\"${SHLIB_SUFFIX}\" +${KEYSYM_FLAGS} WISH_OBJS = tkAppInit.o -TKTEST_OBJS = tkTestInit.o tkTest.o tkSquare.o +TCLTEST_OBJS = ${TCL_BIN_DIR}/tclTest.o ${TCL_BIN_DIR}/tclThreadTest.o \ + ${TCL_BIN_DIR}/tclUnixTest.o +TKTEST_OBJS = $(TCLTEST_OBJS) tkTestInit.o tkTest.o tkSquare.o WIDGOBJS = tkButton.o tkEntry.o tkFrame.o tkListbox.o \ tkMenu.o tkMenubutton.o tkMenuDraw.o tkMessage.o tkScale.o \ @@ -253,19 +261,18 @@ IMAGEOBJS = tkImage.o tkImgBmap.o tkImgGIF.o tkImgPPM.o tkImgPhoto.o TEXTOBJS = tkText.o tkTextBTree.o tkTextDisp.o tkTextImage.o tkTextIndex.o \ tkTextMark.o tkTextTag.o tkTextWind.o -UNIXOBJS = tkUnix.o tkUnix3d.o tkUnixButton.o tkUnixColor.o tkUnixCursor.o \ - tkUnixDialog.o tkUnixDraw.o \ - tkUnixEmbed.o tkUnixEvent.o tkUnixFocus.o tkUnixFont.o tkUnixInit.o \ - tkUnixMenu.o tkUnixMenubu.o tkUnixScale.o tkUnixScrlbr.o \ - tkUnixSelect.o tkUnixSend.o tkUnixWm.o tkUnixXId.o tkStubInit.o +UNIXOBJS = tkUnix.o tkUnix3d.o tkUnixButton.o tkUnixColor.o tkUnixConfig.o \ + tkUnixCursor.o tkUnixDraw.o tkUnixEmbed.o tkUnixEvent.o \ + tkUnixFocus.o tkUnixFont.o tkUnixInit.o tkUnixKey.o tkUnixMenu.o \ + tkUnixMenubu.o tkUnixScale.o tkUnixScrlbr.o tkUnixSelect.o \ + tkUnixSend.o tkUnixWm.o tkUnixXId.o tkStubInit.o tkStubLib.o -STUB_LIB_OBJS = tkStubs.o tkIntStubs.o tkIntPlatStubs.o tkPlatStubs.o \ - tkIntXlibStubs.o tkStubLib.o +STUB_LIB_OBJS = tkStubLib.o OBJS = tk3d.o tkArgv.o tkAtom.o tkBind.o tkBitmap.o tkClipboard.o tkCmds.o \ tkColor.o tkConfig.o tkCursor.o tkError.o tkEvent.o \ tkFocus.o tkFont.o tkGet.o tkGC.o tkGeometry.o tkGrab.o tkGrid.o \ - tkMain.o tkOption.o tkPack.o tkPlace.o \ + tkMain.o tkObj.o tkOldConfig.o tkOption.o tkPack.o tkPlace.o \ tkSelect.o tkUtil.o tkVisual.o tkWindow.o \ $(UNIXOBJS) $(WIDGOBJS) $(CANVOBJS) $(IMAGEOBJS) $(TEXTOBJS) @@ -288,7 +295,7 @@ SRCS = \ $(GENERIC_DIR)/tkPack.c $(GENERIC_DIR)/tkPlace.c \ $(GENERIC_DIR)/tkSelect.c $(GENERIC_DIR)/tkUtil.c \ $(GENERIC_DIR)/tkVisual.c $(GENERIC_DIR)/tkWindow.c \ - $(GENERIC_DIR)/tkButton.c \ + $(GENERIC_DIR)/tkButton.c $(GENERIC_DIR)/tkObj.c \ $(GENERIC_DIR)/tkEntry.c $(GENERIC_DIR)/tkFrame.c \ $(GENERIC_DIR)/tkListbox.c $(GENERIC_DIR)/tkMenu.c \ $(GENERIC_DIR)/tkMenubutton.c $(GENERIC_DIR)/tkMenuDraw.c \ @@ -308,18 +315,19 @@ SRCS = \ $(GENERIC_DIR)/tkTextImage.c \ $(GENERIC_DIR)/tkTextIndex.c $(GENERIC_DIR)/tkTextMark.c \ $(GENERIC_DIR)/tkTextTag.c $(GENERIC_DIR)/tkTextWind.c \ + $(GENERIC_DIR)/tkOldConfig.c \ $(GENERIC_DIR)/tkSquare.c $(GENERIC_DIR)/tkTest.c \ - $(GENERIC_DIR)/tkStubs.c $(GENERIC_DIR)/tkIntStubs.c \ - $(GENERIC_DIR)/tkPlatStubs.c $(GENERIC_DIR)/tkIntPlatStubs.c \ - $(GENERIC_DIR)/tkIntXlibStubs.c $(GENERIC_DIR)/tkInitStubs.c \ + $(GENERIC_DIR)/tkStubInit.c $(GENERIC_DIR)/tkStubLib.c \ $(UNIX_DIR)/tkAppInit.c $(UNIX_DIR)/tkUnix.c \ $(UNIX_DIR)/tkUnix3d.c \ $(UNIX_DIR)/tkUnixButton.c $(UNIX_DIR)/tkUnixColor.c \ + $(UNIX_DIR)/tkUnixConfig.c \ $(UNIX_DIR)/tkUnixCursor.c \ - $(UNIX_DIR)/tkUnixDialog.c $(UNIX_DIR)/tkUnixDraw.c \ + $(UNIX_DIR)/tkUnixDraw.c \ $(UNIX_DIR)/tkUnixEmbed.c $(UNIX_DIR)/tkUnixEvent.c \ $(UNIX_DIR)/tkUnixFocus.c \ $(UNIX_DIR)/tkUnixFont.c $(UNIX_DIR)/tkUnixInit.c \ + $(UNIX_DIR)/tkUnixKey.c \ $(UNIX_DIR)/tkUnixMenu.c $(UNIX_DIR)/tkUnixMenubu.c \ $(UNIX_DIR)/tkUnixScale.c $(UNIX_DIR)/tkUnixScrlbr.c \ $(UNIX_DIR)/tkUnixSelect.c \ @@ -352,23 +360,26 @@ ${STUB_LIB_FILE}: ${STUB_LIB_OBJS} # extensions. used for the Tcl Plugin. -- dl tkLibObjs: @echo ${OBJS} + # This targets actually build the objects needed for the lib in the above # case objs: ${OBJS} wish: $(WISH_OBJS) $(TK_LIB_FILE) $(TK_STUB_LIB_FILE) - $(CC) @LD_FLAGS@ $(WISH_OBJS) @TK_BUILD_LIB_SPEC@ $(LIBS) \ - $(TK_CC_SEARCH_FLAGS) -o wish + $(CC) @LD_FLAGS@ $(WISH_OBJS) \ + @TK_BUILD_LIB_SPEC@ \ + $(WISH_LIBS) $(TK_CC_SEARCH_FLAGS) -o wish tktest: $(TKTEST_OBJS) $(TK_LIB_FILE) - ${CC} @LD_FLAGS@ $(TKTEST_OBJS) @TK_BUILD_LIB_SPEC@ $(LIBS) \ - $(TK_CC_SEARCH_FLAGS) -o tktest + ${CC} @LD_FLAGS@ $(TKTEST_OBJS) \ + @TK_BUILD_LIB_SPEC@ \ + $(WISH_LIBS) $(TK_CC_SEARCH_FLAGS) -o tktest xttest: test.o tkTest.o tkSquare.o $(TK_LIB_FILE) ${CC} @LD_FLAGS@ test.o tkTest.o tkSquare.o \ - @TK_BUILD_LIB_SPEC@ $(LIBS) \ - @TK_LD_SEARCH_FLAGS@ -lXt -o xttest + @TK_BUILD_LIB_SPEC@ \ + $(WISH_LIBS) $(TK_LD_SEARCH_FLAGS) -lXt -o xttest # Note, in the target below TCL_LIBRARY needs to be set or else # "make test" won't work in the case where the compilation directory @@ -380,10 +391,8 @@ test: tktest SHLIB_PATH=`pwd`:${TCL_BIN_DIR}:${SHLIB_PATH}; \ export SHLIB_PATH; \ TCL_LIBRARY=@TCL_SRC_DIR@/library; export TCL_LIBRARY; \ - TK_LIBRARY=$(TOP_DIR)/library; export TK_LIBRARY; \ - ( echo cd $(TOP_DIR)/tests\; source all\; exit ) \ - | ./tktest -geometry +0+0 - + TK_LIBRARY=@TK_SRC_DIR@/library; export TK_LIBRARY; \ + ./tktest $(TOP_DIR)/tests/all.tcl -geometry +0+0 # Useful target to launch a built tktest with the proper path,... runtest: @@ -392,7 +401,7 @@ runtest: SHLIB_PATH=`pwd`:${TCL_BIN_DIR}:${SHLIB_PATH}; \ export SHLIB_PATH; \ TCL_LIBRARY=@TCL_SRC_DIR@/library; export TCL_LIBRARY; \ - TK_LIBRARY=$(TOP_DIR)/library; export TK_LIBRARY; \ + TK_LIBRARY=@TK_SRC_DIR@/library; export TK_LIBRARY; \ ./tktest install: install-binaries install-libraries install-demos install-man @@ -415,15 +424,15 @@ install-binaries: $(TK_LIB_FILE) $(TK_STUB_LIB_FILE) $(TK_BUILD_EXP_FILE) wish @$(INSTALL_DATA) $(TK_LIB_FILE) $(LIB_INSTALL_DIR)/$(TK_LIB_FILE) @(cd $(LIB_INSTALL_DIR); $(RANLIB) $(TK_LIB_FILE)) @chmod 555 $(LIB_INSTALL_DIR)/$(TK_LIB_FILE) + @echo "Installing wish" + @$(INSTALL_PROGRAM) wish $(BIN_INSTALL_DIR)/wish$(VERSION) + @echo "Installing tkConfig.sh" + @$(INSTALL_DATA) tkConfig.sh $(LIB_INSTALL_DIR)/tkConfig.sh @if test "$(TK_BUILD_EXP_FILE)" != ""; then \ echo "Installing $(TK_EXP_FILE)"; \ $(INSTALL_DATA) $(TK_BUILD_EXP_FILE) \ $(LIB_INSTALL_DIR)/$(TK_EXP_FILE); \ fi - @echo "Installing wish" - @$(INSTALL_PROGRAM) wish $(BIN_INSTALL_DIR)/wish$(VERSION) - @echo "Installing tkConfig.sh" - @$(INSTALL_DATA) tkConfig.sh $(LIB_INSTALL_DIR)/tkConfig.sh @if test "$(TK_STUB_LIB_FILE)" != "" ; then \ echo "Installing $(TK_STUB_LIB_FILE)"; \ $(INSTALL_DATA) $(STUB_LIB_FILE) \ @@ -441,9 +450,12 @@ install-libraries: else true; \ fi; \ done; - @echo "Installing tk.h" - @$(INSTALL_DATA) $(GENERIC_DIR)/tk.h $(INCLUDE_INSTALL_DIR)/tk.h - for i in $(SRC_DIR)/library/*.tcl $(SRC_DIR)/library/tclIndex $(SRC_DIR)/library/prolog.ps $(UNIX_DIR)/tkAppInit.c; \ + @for i in $(GENERIC_DIR)/tk.h $(GENERIC_DIR)/tkDecls.h ; \ + do \ + echo "Installing $$i"; \ + $(INSTALL_DATA) $$i $(INCLUDE_INSTALL_DIR); \ + done; + for i in $(SRC_DIR)/library/*.tcl $(SRC_DIR)/library/tclIndex $(UNIX_DIR)/tkAppInit.c; \ do \ echo "Installing $$i"; \ $(INSTALL_DATA) $$i $(SCRIPT_INSTALL_DIR); \ @@ -549,19 +561,19 @@ tkTestInit.o: $(UNIX_DIR)/tkAppInit.c rm -f tkAppInit.sav; \ mv tkAppInit.o tkAppInit.sav; \ fi; - $(CC) -c $(CC_SWITCHES) -DTK_TEST $(UNIX_DIR)/tkAppInit.c + $(CC) -c $(CC_SWITCHES_NO_STUBS) -DTK_TEST $(UNIX_DIR)/tkAppInit.c rm -f tkTestInit.o mv tkAppInit.o tkTestInit.o @if test -f tkAppInit.sav ; then \ mv tkAppInit.sav tkAppInit.o; \ fi; +tkAppInit.o: $(UNIX_DIR)/tkAppInit.c + $(CC) -c $(CC_SWITCHES_NO_STUBS) $(UNIX_DIR)/tkAppInit.c + tk3d.o: $(GENERIC_DIR)/tk3d.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tk3d.c -tkAppInit.o: $(UNIX_DIR)/tkAppInit.c - $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tkAppInit.c - tkArgv.o: $(GENERIC_DIR)/tkArgv.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkArgv.c @@ -619,6 +631,12 @@ tkGrid.o: $(GENERIC_DIR)/tkGrid.c tkMain.o: $(GENERIC_DIR)/tkMain.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkMain.c +tkObj.o: $(GENERIC_DIR)/tkObj.c + $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkObj.c + +tkOldConfig.o: $(GENERIC_DIR)/tkOldConfig.c + $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkOldConfig.c + tkOption.o: $(GENERIC_DIR)/tkOption.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkOption.c @@ -671,7 +689,7 @@ tkScrollbar.o: $(GENERIC_DIR)/tkScrollbar.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkScrollbar.c tkSquare.o: $(GENERIC_DIR)/tkSquare.c - $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkSquare.c + $(CC) -c $(CC_SWITCHES_NO_STUBS) $(GENERIC_DIR)/tkSquare.c tkCanvas.o: $(GENERIC_DIR)/tkCanvas.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkCanvas.c @@ -725,7 +743,7 @@ tkImgPhoto.o: $(GENERIC_DIR)/tkImgPhoto.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkImgPhoto.c tkTest.o: $(GENERIC_DIR)/tkTest.c - $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTest.c + $(CC) -c $(CC_SWITCHES_NO_STUBS) $(GENERIC_DIR)/tkTest.c tkText.o: $(GENERIC_DIR)/tkText.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkText.c @@ -751,6 +769,15 @@ tkTextTag.o: $(GENERIC_DIR)/tkTextTag.c tkTextWind.o: $(GENERIC_DIR)/tkTextWind.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextWind.c +tkStubInit.o: $(GENERIC_DIR)/tkStubInit.c + $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkStubInit.c + +# Stub library binaries, these must be compiled for use in a shared library +# even though they will be placed in a static archive + +tkStubLib.o: $(GENERIC_DIR)/tkStubLib.c + $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkStubLib.c + tkUnix.o: $(UNIX_DIR)/tkUnix.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tkUnix.c @@ -763,12 +790,12 @@ tkUnixButton.o: $(UNIX_DIR)/tkUnixButton.c tkUnixColor.o: $(UNIX_DIR)/tkUnixColor.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tkUnixColor.c +tkUnixConfig.o: $(UNIX_DIR)/tkUnixConfig.c + $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tkUnixConfig.c + tkUnixCursor.o: $(UNIX_DIR)/tkUnixCursor.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tkUnixCursor.c -tkUnixDialog.o: $(UNIX_DIR)/tkUnixDialog.c - $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tkUnixDialog.c - tkUnixDraw.o: $(UNIX_DIR)/tkUnixDraw.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tkUnixDraw.c @@ -788,6 +815,9 @@ tkUnixInit.o: $(UNIX_DIR)/tkUnixInit.c $(GENERIC_DIR)/tkInitScript.h tkConfig.sh $(CC) -c $(CC_SWITCHES) -DTK_LIBRARY=\"${TK_LIBRARY}\" \ $(UNIX_DIR)/tkUnixInit.c +tkUnixKey.o: $(UNIX_DIR)/tkUnixKey.c + $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tkUnixKey.c + tkUnixMenu.o: $(UNIX_DIR)/tkUnixMenu.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tkUnixMenu.c @@ -812,35 +842,24 @@ tkUnixWm.o: $(UNIX_DIR)/tkUnixWm.c tkUnixXId.o: $(UNIX_DIR)/tkUnixXId.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tkUnixXId.c -tkStubInit.o: $(GENERIC_DIR)/tkStubInit.c - $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkStubInit.c - - -# Stub library binaries, these must be compiled for use in a shared library -# even though they will be placed in a static archive - -tkStubs.o: $(GENERIC_DIR)/tkStubs.c - $(CC) -c $(STUB_CC_SWITCHES) $(GENERIC_DIR)/tkStubs.c - -tkIntStubs.o: $(GENERIC_DIR)/tkIntStubs.c - $(CC) -c $(STUB_CC_SWITCHES) $(GENERIC_DIR)/tkIntStubs.c - -tkPlatStubs.o: $(GENERIC_DIR)/tkPlatStubs.c - $(CC) -c $(STUB_CC_SWITCHES) $(GENERIC_DIR)/tkPlatStubs.c +.c.o: + $(CC) -c $(CC_SWITCHES) $< -tkIntPlatStubs.o: $(GENERIC_DIR)/tkIntPlatStubs.c - $(CC) -c $(STUB_CC_SWITCHES) $(GENERIC_DIR)/tkIntPlatStubs.c +# +# Target to check for proper usage of UCHAR macro. +# -tkIntXlibStubs.o: $(GENERIC_DIR)/tkIntXlibStubs.c - $(CC) -c $(STUB_CC_SWITCHES) $(GENERIC_DIR)/tkIntXlibStubs.c +checkuchar: + -egrep isalnum\|isalpha\|iscntrl\|isdigit\|islower\|isprint\|ispunct\|isspace\|isupper\|isxdigit\|toupper\|tolower $(SRCS) | grep -v UCHAR -tkStubLib.o: $(GENERIC_DIR)/tkStubLib.c - $(CC) -c $(STUB_CC_SWITCHES) $(GENERIC_DIR)/tkStubLib.c +# +# Target to make sure that only symbols with "Tk" prefixes are +# exported. +# -.c.o: - $(CC) -c $(CC_SWITCHES) $< +checkexports: $(TK_LIB_FILE) + -nm -p $(TK_LIB_FILE) | awk '$$2 ~ /[TDB]/ { print $$3 }' | sort -n | grep -v '^[Tt]k' -# # Target to regenerate header files and stub files from the *.decls tables. # @@ -865,20 +884,7 @@ checkstubs: if [ $$match -eq 0 ]; then echo $$i; fi \ done -# -# Target to check for proper usage of UCHAR macro. -# -checkuchar: - -egrep isalnum\|isalpha\|iscntrl\|isdigit\|islower\|isprint\|ispunct\|isspace\|isupper\|isxdigit\|toupper\|tolower $(SRCS) | grep -v UCHAR - -# -# Target to make sure that only symbols with "Tk" prefixes are -# exported. -# - -checkexports: $(TK_LIB_FILE) - -nm -p $(TK_LIB_FILE) | awk '$$2 ~ /[TDB]/ { print $$3 }' | sort -n | grep -v '^[Tt]k' # # Target to create a proper Tk distribution from information in the @@ -918,7 +924,8 @@ dist: $(UNIX_DIR)/configure fi; \ done;) mkdir $(DISTDIR)/generic - cp -p $(GENERIC_DIR)/*.c $(GENERIC_DIR)/*.h $(DISTDIR)/generic + cp -p $(GENERIC_DIR)/*.c $(GENERIC_DIR)/*.h $(GENERIC_DIR)/prolog.ps \ + $(DISTDIR)/generic cp -p $(GENERIC_DIR)/README $(DISTDIR)/generic cp -p $(TOP_DIR)/changes $(TOP_DIR)/README $(TOP_DIR)/license.terms \ $(DISTDIR) @@ -955,7 +962,7 @@ dist: $(UNIX_DIR)/configure cp -p $(TOP_DIR)/license.terms $(DISTDIR)/xlib/X11 mkdir $(DISTDIR)/library cp -p $(TOP_DIR)/license.terms $(TOP_DIR)/library/*.tcl \ - $(TOP_DIR)/library/tclIndex $(TOP_DIR)/library/prolog.ps \ + $(TOP_DIR)/library/tclIndex \ $(DISTDIR)/library mkdir $(DISTDIR)/library/images @(cd $(TOP_DIR); for i in library/images/* ; do \ @@ -986,10 +993,8 @@ dist: $(UNIX_DIR)/configure $(TCLDIR)/doc/man.macros $(DISTDIR)/doc mkdir $(DISTDIR)/tests cp -p $(TOP_DIR)/license.terms $(TOP_DIR)/tests/*.test \ - $(TOP_DIR)/tests/visual $(TOP_DIR)/tests/*.tcl \ - $(TOP_DIR)/tests/README $(TOP_DIR)/tests/all \ - $(TOP_DIR)/tests/defs $(TOP_DIR)/tests/option.file* \ - $(DISTDIR)/tests + $(TOP_DIR)/tests/*.tcl $(TOP_DIR)/tests/README \ + $(TOP_DIR)/tests/option.file* $(DISTDIR)/tests # # The following target can only be used for non-patch releases. Use @@ -1002,7 +1007,7 @@ alldist: dist $(DISTROOT)/$(ZIPNAME) cd $(DISTROOT); tar cf $(DISTNAME).tar $(DISTNAME); \ gzip -9 -c $(DISTNAME).tar > $(DISTNAME).tar.gz; \ - compress $(DISTNAME).tar; zip -r8 $(ZIPNAME) $(DISTNAME) + compress $(DISTNAME).tar; zip -qr8 $(ZIPNAME) $(DISTNAME) # # The target below is similar to "alldist" except it works for patch diff --git a/unix/README b/unix/README index 80c6fc3..14d3d40 100644 --- a/unix/README +++ b/unix/README @@ -10,14 +10,14 @@ SGI, as well as PCs running Linux, BSDI, and SCO UNIX. To compile for a PC running Windows, see the README file in the directory ../win. To compile for a Macintosh, see the README file in the directory ../mac. -RCS: @(#) $Id: README,v 1.3 1999/02/09 03:46:27 stanton Exp $ +RCS: @(#) $Id: README,v 1.4 1999/04/16 01:51:45 stanton Exp $ How To Compile And Install Tk: ------------------------------ -(a) Make sure that the Tcl 8.0 release is present in the directory - ../../tcl8.0 (or else use the "--with-tcl" switch described below). - This release of Tk will only work with Tcl 8.0. Also, be sure that +(a) Make sure that the Tcl 8.1 release is present in the directory + ../../tcl8.1a2 (or else use the "--with-tcl" switch described below). + This release of Tk will only work with Tcl 8.1. Also, be sure that you have configured Tcl before you configure Tk. (b) Check for patches as described in ../README. @@ -78,9 +78,9 @@ How To Compile And Install Tk: TCL_LIBRARY environment variable as well (see the Tcl README file for information on this). Note that installed versions of wish, libtk.a, libtk.so, and the Tk library have a version number in their - names, such as "wish8.0" or "libtk8.0.so"; to use the installed + names, such as "wish8.1" or "libtk8.1.so"; to use the installed versions, either specify the version number or create a symbolic - link (e.g. from "wish" to "wish8.0"). + link (e.g. from "wish" to "wish8.1"). If you have trouble compiling Tk, read through the file "porting.notes". It contains information that people have provided diff --git a/unix/configure.in b/unix/configure.in index 99b37c1..4e3f667 100644 --- a/unix/configure.in +++ b/unix/configure.in @@ -3,12 +3,12 @@ dnl This file is an input file used by the GNU "autoconf" program to dnl generate the file "configure", which is run during Tk installation dnl to configure the system for the local environment. AC_INIT(../generic/tk.h) -# RCS: @(#) $Id: configure.in,v 1.29 1999/03/22 21:32:16 redman Exp $ +# RCS: @(#) $Id: configure.in,v 1.30 1999/04/16 01:51:45 stanton Exp $ -TK_VERSION=8.0 +TK_VERSION=8.1 TK_MAJOR_VERSION=8 -TK_MINOR_VERSION=0 -TK_PATCH_LEVEL=".5" +TK_MINOR_VERSION=1 +TK_PATCH_LEVEL=b3 VERSION=${TK_VERSION} if test "${prefix}" = "NONE"; then @@ -19,6 +19,10 @@ if test "${exec_prefix}" = "NONE"; then fi TK_SRC_DIR=`cd $srcdir/..; pwd` +# Most of the checks here are duplicated from Tcl's configure.in +# and should not be redone but rather simply used from the definitions +# found in tclConfig.sh + AC_PROG_RANLIB AC_ARG_ENABLE(gcc, [ --enable-gcc allow use of gcc if available], [tk_ok=$enableval], [tk_ok=no]) @@ -31,6 +35,25 @@ fi AC_C_CROSS AC_HAVE_HEADERS(unistd.h limits.h) +# Threads support +AC_ARG_ENABLE(threads,[ --enable-threads enable Threads support],,enableval="no") + +if test "$enableval" = "yes"; then + AC_MSG_RESULT(Will compile with Threads support) + AC_DEFINE(TCL_THREADS) + AC_DEFINE(_REENTRANT) + + AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -lpthread" + else + AC_MSG_WARN("Don t know how to find pthread lib on your system - you must disable thread support or edit the LIBS in the Makefile...") + fi +else + AC_MSG_RESULT(Will compile without Threads support (normal)) +fi + # set the warning flags depending on whether or not we are using gcc if test "${GCC}" = "yes" ; then # leave -Wimplicit-int out, the X libs generate so many of these warnings @@ -61,10 +84,18 @@ fi #-------------------------------------------------------------------- # See if there was a command-line option for where Tcl is; if # not, assume that its top-level directory is a sibling of ours. +# Try the patch-level-specific directory first, then the general one. #-------------------------------------------------------------------- -AC_ARG_WITH(tcl, [ --with-tcl=DIR use Tcl 8.0 binaries from DIR], - TCL_BIN_DIR=$withval, TCL_BIN_DIR=`cd ../../tcl8.0$TK_PATCH_LEVEL/unix; pwd`) + +if test -d ../../tcl8.1$TK_PATCH_LEVEL/unix; then + TCL_BIN_DEFAULT=../../tcl8.1$TK_PATCH_LEVEL/unix +else + TCL_BIN_DEFAULT=../../tcl8.1/unix +fi + +AC_ARG_WITH(tcl, [ --with-tcl=DIR use Tcl 8.1 binaries from DIR], + TCL_BIN_DIR=$withval, TCL_BIN_DIR=`cd $TCL_BIN_DEFAULT; pwd`) if test ! -d $TCL_BIN_DIR; then AC_MSG_ERROR(Tcl directory $TCL_BIN_DIR doesn't exist) fi @@ -168,6 +199,18 @@ AC_UID_T AC_CHECK_HEADERS(sys/time.h) AC_HEADER_TIME +#------------------------------------------- +# In OS/390 struct pwd has no pw_gecos field +#------------------------------------------- + +AC_MSG_CHECKING([pw_gecos in struct pwd]) +AC_TRY_COMPILE([#include <pwd.h>], + [struct passwd pwd; pwd.pw_gecos;], tk_ok=yes, tk_ok=no) +AC_MSG_RESULT($tk_ok) +if test $tk_ok = yes; then + AC_DEFINE(HAVE_PW_GECOS) +fi + #-------------------------------------------------------------------- # Locate the X11 header files and the X11 library archive. Try # the ac_path_x macro first, but if it doesn't find the X stuff @@ -312,6 +355,10 @@ if test "$tk_checkBoth" = 1; then fi AC_CHECK_FUNC(gethostbyname, , AC_CHECK_LIB(nsl, main, [LIBS="$LIBS -lnsl"])) +# Add the threads support libraries + +LIBS="$LIBS$THREADS_LIBS" + #-------------------------------------------------------------------- # One more check related to the X libraries. The standard releases # of Ultrix don't support the "xauth" mechanism, so send won't work @@ -354,13 +401,6 @@ AC_CHECK_FUNC(sin, , MATH_LIBS="-lm") AC_CHECK_LIB(ieee, main, [MATH_LIBS="-lieee $MATH_LIBS"]) #-------------------------------------------------------------------- -# If this system doesn't have a memmove procedure, use memcpy -# instead. -#-------------------------------------------------------------------- - -AC_CHECK_FUNC(memmove, , [AC_DEFINE(memmove, memcpy)]) - -#-------------------------------------------------------------------- # Figure out whether "char" is unsigned. If so, set a # #define for __CHAR_UNSIGNED__. #-------------------------------------------------------------------- @@ -403,19 +443,23 @@ fi #-------------------------------------------------------------------- AC_ARG_ENABLE(shared, - [ --enable-shared build libtk as a shared library], - [ok=$enableval], [ok=no]) + [ --enable-shared build libtk as a shared library (on by default)], + [ok=$enableval], [ok=yes]) if test "$ok" = "yes" -a "${SHLIB_SUFFIX}" != ""; then TK_SHARED_BUILD=1 TK_SHLIB_CFLAGS="${SHLIB_CFLAGS}" TK_LIB_FILE=libtk${TCL_SHARED_LIB_SUFFIX} - MAKE_LIB='\${SHLIB_LD} -o \${TK_LIB_FILE} \${OBJS} \$(TK_LD_SEARCH_FLAGS) ${SHLIB_LD_LIBS}' + MAKE_LIB="\${SHLIB_LD} -o \${TK_LIB_FILE} \${OBJS} \$(TK_LD_SEARCH_FLAGS) ${TCL_BUILD_STUB_LIB_SPEC} \${LIBS}" RANLIB=":" + + TCL_STUB_FLAGS="-DUSE_TCL_STUBS" else TK_SHARED_BUILD=0 TK_SHLIB_CFLAGS="" TK_LIB_FILE=libtk${TCL_UNSHARED_LIB_SUFFIX} - MAKE_LIB='ar cr \${TK_LIB_FILE} \${OBJS}' + MAKE_LIB="ar cr \${TK_LIB_FILE} \${OBJS}" + + TCL_STUB_FLAGS="" fi DBGX='${TK_DBGX}' @@ -449,35 +493,26 @@ fi # using tcl stub support. #-------------------------------------------------------------------- -# Linking to the Tcl stub library is not supported until Tk is a fully -# loadable extension. +# For now, linking to Tcl stubs is not supported with Tk. It causes +# too many problems with linking. When Tk is a fully loadable +# extension, linking the the Tcl stubs will be supported. -AC_MSG_RESULT(dynamic linking) -TCL_BUILD_STUB_LIB_SPEC="" -TCL_STUB_FLAGS="" -#-------------------------------------------------------------------- -# The statements below define various symbols relating to Tcl -# stub support. -#-------------------------------------------------------------------- # Replace ${VERSION} with contents of ${TK_VERSION} eval "STUB_LIB_FILE=libtkstub${TCL_UNSHARED_LIB_SUFFIX}" -# Replace DBGX with TCL_DBGX -eval "STUB_LIB_FILE=\"${STUB_LIB_FILE}\"" - MAKE_STUB_LIB="ar cr \${STUB_LIB_FILE} \${STUB_LIB_OBJS}" TK_STUB_LIB_FILE=${STUB_LIB_FILE} if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then - TK_STUB_LIB_FLAG="-ltkstub${TK_VERSION}\${TCL_DBGX}" + TK_STUB_LIB_FLAG="-ltkstub${TK_VERSION}\${TK_DBGX}" else - TK_STUB_LIB_FLAG="-ltkstub`echo ${TK_VERSION} | tr -d .`\${TCL_DBGX}" + TK_STUB_LIB_FLAG="-ltkstub`echo ${TK_VERSION} | tr -d .`\${TK_DBGX}" fi TK_BUILD_STUB_LIB_SPEC="-L`pwd` ${TK_STUB_LIB_FLAG}" -TL_STUB_LIB_SPEC="-L${exec_prefix}/lib ${TK_STUB_LIB_FLAG}" +TK_STUB_LIB_SPEC="-L${exec_prefix}/lib ${TK_STUB_LIB_FLAG}" TK_BUILD_STUB_LIB_PATH="`pwd`/${TK_STUB_LIB_FILE}" TK_STUB_LIB_PATH="${exec_prefix}/lib/${TK_STUB_LIB_FILE}" @@ -510,8 +545,8 @@ AC_SUBST(SHLIB_LD_LIBS) AC_SUBST(SHLIB_SUFFIX) AC_SUBST(SHLIB_VERSION) AC_SUBST(TCL_BIN_DIR) -AC_SUBST(TCL_BUILD_LIB_SPEC) AC_SUBST(TCL_BUILD_STUB_LIB_SPEC) +AC_SUBST(TCL_BUILD_LIB_SPEC) AC_SUBST(TCL_DBGX) AC_SUBST(TCL_LIB_FLAG) AC_SUBST(TCL_SRC_DIR) @@ -521,8 +556,6 @@ AC_SUBST(TK_CC_SEARCH_FLAGS) AC_SUBST(TK_LD_SEARCH_FLAGS) AC_SUBST(TK_LIB_FILE) AC_SUBST(TK_LIB_FLAG) -AC_SUBST(TK_BUILD_EXP_FILE) -AC_SUBST(TK_EXP_FILE) AC_SUBST(TK_LIB_SPEC) AC_SUBST(TK_MAJOR_VERSION) AC_SUBST(TK_MINOR_VERSION) diff --git a/unix/mkLinks b/unix/mkLinks index d817703..5b326b6 100644 --- a/unix/mkLinks +++ b/unix/mkLinks @@ -43,6 +43,26 @@ if test -r 3DBorder.3; then rm -f Tk_3DVerticalBevel.3 ln 3DBorder.3 Tk_3DVerticalBevel.3 fi +if test -r 3DBorder.3; then + rm -f Tk_Alloc3DBorderFromObj.3 + ln 3DBorder.3 Tk_Alloc3DBorderFromObj.3 +fi +if test -r GetBitmap.3; then + rm -f Tk_AllocBitmapFromObj.3 + ln GetBitmap.3 Tk_AllocBitmapFromObj.3 +fi +if test -r GetColor.3; then + rm -f Tk_AllocColorFromObj.3 + ln GetColor.3 Tk_AllocColorFromObj.3 +fi +if test -r GetCursor.3; then + rm -f Tk_AllocCursorFromObj.3 + ln GetCursor.3 Tk_AllocCursorFromObj.3 +fi +if test -r GetFont.3; then + rm -f Tk_AllocFontFromObj.3 + ln GetFont.3 Tk_AllocFontFromObj.3 +fi if test -r WindowId.3; then rm -f Tk_Attributes.3 ln WindowId.3 Tk_Attributes.3 @@ -191,6 +211,10 @@ if test -r CrtItemType.3; then rm -f Tk_CreateItemType.3 ln CrtItemType.3 Tk_CreateItemType.3 fi +if test -r SetOptions.3; then + rm -f Tk_CreateOptionTable.3 + ln SetOptions.3 Tk_CreateOptionTable.3 +fi if test -r CrtPhImgFmt.3; then rm -f Tk_CreatePhotoImageFormat.3 ln CrtPhImgFmt.3 Tk_CreatePhotoImageFormat.3 @@ -243,6 +267,10 @@ if test -r DeleteImg.3; then rm -f Tk_DeleteImage.3 ln DeleteImg.3 Tk_DeleteImage.3 fi +if test -r SetOptions.3; then + rm -f Tk_DeleteOptionTable.3 + ln SetOptions.3 Tk_DeleteOptionTable.3 +fi if test -r CrtSelHdlr.3; then rm -f Tk_DeleteSelHandler.3 ln CrtSelHdlr.3 Tk_DeleteSelHandler.3 @@ -311,26 +339,50 @@ if test -r 3DBorder.3; then rm -f Tk_Free3DBorder.3 ln 3DBorder.3 Tk_Free3DBorder.3 fi +if test -r 3DBorder.3; then + rm -f Tk_Free3DBorderFromObj.3 + ln 3DBorder.3 Tk_Free3DBorderFromObj.3 +fi if test -r GetBitmap.3; then rm -f Tk_FreeBitmap.3 ln GetBitmap.3 Tk_FreeBitmap.3 fi +if test -r GetBitmap.3; then + rm -f Tk_FreeBitmapFromObj.3 + ln GetBitmap.3 Tk_FreeBitmapFromObj.3 +fi if test -r GetColor.3; then rm -f Tk_FreeColor.3 ln GetColor.3 Tk_FreeColor.3 fi +if test -r GetColor.3; then + rm -f Tk_FreeColorFromObj.3 + ln GetColor.3 Tk_FreeColorFromObj.3 +fi if test -r GetClrmap.3; then rm -f Tk_FreeColormap.3 ln GetClrmap.3 Tk_FreeColormap.3 fi +if test -r SetOptions.3; then + rm -f Tk_FreeConfigOptions.3 + ln SetOptions.3 Tk_FreeConfigOptions.3 +fi if test -r GetCursor.3; then rm -f Tk_FreeCursor.3 ln GetCursor.3 Tk_FreeCursor.3 fi +if test -r GetCursor.3; then + rm -f Tk_FreeCursorFromObj.3 + ln GetCursor.3 Tk_FreeCursorFromObj.3 +fi if test -r GetFont.3; then rm -f Tk_FreeFont.3 ln GetFont.3 Tk_FreeFont.3 fi +if test -r GetFont.3; then + rm -f Tk_FreeFontFromObj.3 + ln GetFont.3 Tk_FreeFontFromObj.3 +fi if test -r GetGC.3; then rm -f Tk_FreeGC.3 ln GetGC.3 Tk_FreeGC.3 @@ -347,6 +399,10 @@ if test -r GetPixmap.3; then rm -f Tk_FreePixmap.3 ln GetPixmap.3 Tk_FreePixmap.3 fi +if test -r SetOptions.3; then + rm -f Tk_FreeSavedOptions.3 + ln SetOptions.3 Tk_FreeSavedOptions.3 +fi if test -r TextLayout.3; then rm -f Tk_FreeTextLayout.3 ln TextLayout.3 Tk_FreeTextLayout.3 @@ -363,6 +419,10 @@ if test -r 3DBorder.3; then rm -f Tk_Get3DBorder.3 ln 3DBorder.3 Tk_Get3DBorder.3 fi +if test -r 3DBorder.3; then + rm -f Tk_Get3DBorderFromObj.3 + ln 3DBorder.3 Tk_Get3DBorderFromObj.3 +fi if test -r BindTable.3; then rm -f Tk_GetAllBindings.3 ln BindTable.3 Tk_GetAllBindings.3 @@ -371,6 +431,10 @@ if test -r GetAnchor.3; then rm -f Tk_GetAnchor.3 ln GetAnchor.3 Tk_GetAnchor.3 fi +if test -r GetAnchor.3; then + rm -f Tk_GetAnchorFromObj.3 + ln GetAnchor.3 Tk_GetAnchorFromObj.3 +fi if test -r InternAtom.3; then rm -f Tk_GetAtomName.3 ln InternAtom.3 Tk_GetAtomName.3 @@ -387,6 +451,10 @@ if test -r GetBitmap.3; then rm -f Tk_GetBitmapFromData.3 ln GetBitmap.3 Tk_GetBitmapFromData.3 fi +if test -r GetBitmap.3; then + rm -f Tk_GetBitmapFromObj.3 + ln GetBitmap.3 Tk_GetBitmapFromObj.3 +fi if test -r GetCapStyl.3; then rm -f Tk_GetCapStyle.3 ln GetCapStyl.3 Tk_GetCapStyle.3 @@ -399,6 +467,10 @@ if test -r GetColor.3; then rm -f Tk_GetColorByValue.3 ln GetColor.3 Tk_GetColorByValue.3 fi +if test -r GetColor.3; then + rm -f Tk_GetColorFromObj.3 + ln GetColor.3 Tk_GetColorFromObj.3 +fi if test -r GetClrmap.3; then rm -f Tk_GetColormap.3 ln GetClrmap.3 Tk_GetColormap.3 @@ -411,10 +483,18 @@ if test -r GetCursor.3; then rm -f Tk_GetCursorFromData.3 ln GetCursor.3 Tk_GetCursorFromData.3 fi +if test -r GetCursor.3; then + rm -f Tk_GetCursorFromObj.3 + ln GetCursor.3 Tk_GetCursorFromObj.3 +fi if test -r GetFont.3; then rm -f Tk_GetFont.3 ln GetFont.3 Tk_GetFont.3 fi +if test -r GetFont.3; then + rm -f Tk_GetFontFromObj.3 + ln GetFont.3 Tk_GetFontFromObj.3 +fi if test -r GetGC.3; then rm -f Tk_GetGC.3 ln GetGC.3 Tk_GetGC.3 @@ -439,14 +519,34 @@ if test -r GetJustify.3; then rm -f Tk_GetJustify.3 ln GetJustify.3 Tk_GetJustify.3 fi +if test -r GetJustify.3; then + rm -f Tk_GetJustifyFromObj.3 + ln GetJustify.3 Tk_GetJustifyFromObj.3 +fi +if test -r GetPixels.3; then + rm -f Tk_GetMMFromObj.3 + ln GetPixels.3 Tk_GetMMFromObj.3 +fi if test -r GetOption.3; then rm -f Tk_GetOption.3 ln GetOption.3 Tk_GetOption.3 fi +if test -r SetOptions.3; then + rm -f Tk_GetOptionInfo.3 + ln SetOptions.3 Tk_GetOptionInfo.3 +fi +if test -r SetOptions.3; then + rm -f Tk_GetOptionValue.3 + ln SetOptions.3 Tk_GetOptionValue.3 +fi if test -r GetPixels.3; then rm -f Tk_GetPixels.3 ln GetPixels.3 Tk_GetPixels.3 fi +if test -r GetPixels.3; then + rm -f Tk_GetPixelsFromObj.3 + ln GetPixels.3 Tk_GetPixelsFromObj.3 +fi if test -r GetPixmap.3; then rm -f Tk_GetPixmap.3 ln GetPixmap.3 Tk_GetPixmap.3 @@ -455,6 +555,10 @@ if test -r GetRelief.3; then rm -f Tk_GetRelief.3 ln GetRelief.3 Tk_GetRelief.3 fi +if test -r GetRelief.3; then + rm -f Tk_GetReliefFromObj.3 + ln GetRelief.3 Tk_GetReliefFromObj.3 +fi if test -r GetRootCrd.3; then rm -f Tk_GetRootCoords.3 ln GetRootCrd.3 Tk_GetRootCoords.3 @@ -499,6 +603,10 @@ if test -r ImgChanged.3; then rm -f Tk_ImageChanged.3 ln ImgChanged.3 Tk_ImageChanged.3 fi +if test -r SetOptions.3; then + rm -f Tk_InitOptions.3 + ln SetOptions.3 Tk_InitOptions.3 +fi if test -r InternAtom.3; then rm -f Tk_InternAtom.3 ln InternAtom.3 Tk_InternAtom.3 @@ -611,9 +719,9 @@ if test -r Name.3; then rm -f Tk_NameToWindow.3 ln Name.3 Tk_NameToWindow.3 fi -if test -r ConfigWidg.3; then +if test -r SetOptions.3; then rm -f Tk_Offset.3 - ln ConfigWidg.3 Tk_Offset.3 + ln SetOptions.3 Tk_Offset.3 fi if test -r OwnSelect.3; then rm -f Tk_OwnSelection.3 @@ -691,6 +799,10 @@ if test -r Restack.3; then rm -f Tk_RestackWindow.3 ln Restack.3 Tk_RestackWindow.3 fi +if test -r SetOptions.3; then + rm -f Tk_RestoreSavedOptions.3 + ln SetOptions.3 Tk_RestoreSavedOptions.3 +fi if test -r RestrictEv.3; then rm -f Tk_RestrictEvents.3 ln RestrictEv.3 Tk_RestrictEvents.3 @@ -723,6 +835,10 @@ if test -r GeomReq.3; then rm -f Tk_SetInternalBorder.3 ln GeomReq.3 Tk_SetInternalBorder.3 fi +if test -r SetOptions.3; then + rm -f Tk_SetOptions.3 + ln SetOptions.3 Tk_SetOptions.3 +fi if test -r ConfigWind.3; then rm -f Tk_SetWindowBackground.3 ln ConfigWind.3 Tk_SetWindowBackground.3 diff --git a/unix/tkAppInit.c b/unix/tkAppInit.c index 5591d98..cf283fb 100644 --- a/unix/tkAppInit.c +++ b/unix/tkAppInit.c @@ -5,15 +5,16 @@ * use in wish and similar Tk-based applications. * * Copyright (c) 1993 The Regents of the University of California. - * Copyright (c) 1994 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkAppInit.c,v 1.3 1999/02/04 20:57:18 stanton Exp $ + * RCS: @(#) $Id: tkAppInit.c,v 1.4 1999/04/16 01:51:45 stanton Exp $ */ #include "tk.h" +#include "locale.h" /* * The following variable is a special hack that is needed in order for @@ -24,6 +25,7 @@ extern int matherr(); int *tclDummyMathPtr = (int *) matherr; #ifdef TK_TEST +extern int Tcltest_Init _ANSI_ARGS_((Tcl_Interp *interp)); extern int Tktest_Init _ANSI_ARGS_((Tcl_Interp *interp)); #endif /* TK_TEST */ @@ -64,7 +66,7 @@ main(argc, argv) * * Results: * Returns a standard Tcl completion code, and leaves an error - * message in interp->result if an error occurs. + * message in the interp's result if an error occurs. * * Side effects: * Depends on the startup script. @@ -84,6 +86,11 @@ Tcl_AppInit(interp) } Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit); #ifdef TK_TEST + if (Tcltest_Init(interp) == TCL_ERROR) { + return TCL_ERROR; + } + Tcl_StaticPackage(interp, "Tcltest", Tcltest_Init, + (Tcl_PackageInitProc *) NULL); if (Tktest_Init(interp) == TCL_ERROR) { return TCL_ERROR; } diff --git a/unix/tkUnix.c b/unix/tkUnix.c index b50ee42..769a0b7 100644 --- a/unix/tkUnix.c +++ b/unix/tkUnix.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnix.c,v 1.3 1999/03/10 07:04:45 stanton Exp $ + * RCS: @(#) $Id: tkUnix.c,v 1.4 1999/04/16 01:51:45 stanton Exp $ */ #include <tkInt.h> @@ -40,7 +40,8 @@ TkGetServerInfo(interp, tkwin) Tk_Window tkwin; /* Token for window; this selects a * particular display and server. */ { - char buffer[50], buffer2[50]; + char buffer[8 + TCL_INTEGER_SPACE * 2]; + char buffer2[TCL_INTEGER_SPACE]; sprintf(buffer, "X%dR%d ", ProtocolVersion(Tk_Display(tkwin)), ProtocolRevision(Tk_Display(tkwin))); @@ -77,7 +78,6 @@ TkGetDefaultScreenName(interp, screenName) } return screenName; } - /* *---------------------------------------------------------------------- diff --git a/unix/tkUnixButton.c b/unix/tkUnixButton.c index 29570d3..2d4cb25 100644 --- a/unix/tkUnixButton.c +++ b/unix/tkUnixButton.c @@ -4,12 +4,12 @@ * This file implements the Unix specific portion of the button * widgets. * - * Copyright (c) 1996 by Sun Microsystems, Inc. + * Copyright (c) 1996-1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixButton.c,v 1.2 1998/09/14 18:23:55 stanton Exp $ + * RCS: @(#) $Id: tkUnixButton.c,v 1.3 1999/04/16 01:51:45 stanton Exp $ */ #include "tkButton.h" @@ -85,12 +85,11 @@ TkpDisplayButton(clientData) int x = 0; /* Initialization only needed to stop * compiler warning. */ int y, relief; - register Tk_Window tkwin = butPtr->tkwin; + Tk_Window tkwin = butPtr->tkwin; int width, height; - int offset; /* 0 means this is a label widget. 1 means - * it is a flavor of button, so we offset - * the text to make the button appear to - * move up and down as the relief changes. */ + int offset; /* 1 means this is a button widget, so we + * offset the text to make the button appear + * to move up and down as the relief changes. */ butPtr->flags &= ~REDRAW_PENDING; if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { @@ -98,16 +97,16 @@ TkpDisplayButton(clientData) } border = butPtr->normalBorder; - if ((butPtr->state == tkDisabledUid) && (butPtr->disabledFg != NULL)) { + if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) { gc = butPtr->disabledGC; - } else if ((butPtr->state == tkActiveUid) + } else if ((butPtr->state == STATE_ACTIVE) && !Tk_StrictMotif(butPtr->tkwin)) { gc = butPtr->activeTextGC; border = butPtr->activeBorder; } else { gc = butPtr->normalTextGC; } - if ((butPtr->flags & SELECTED) && (butPtr->state != tkActiveUid) + if ((butPtr->flags & SELECTED) && (butPtr->state != STATE_ACTIVE) && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) { border = butPtr->selectBorder; } @@ -141,7 +140,7 @@ TkpDisplayButton(clientData) * Display image or bitmap or text for button. */ - if (butPtr->image != None) { + if (butPtr->image != NULL) { Tk_SizeOfImage(butPtr->image, &width, &height); imageOrBitmap: @@ -213,7 +212,7 @@ TkpDisplayButton(clientData) y -= dim/2; if (dim > 2*butPtr->borderWidth) { Tk_Draw3DRectangle(tkwin, pixmap, border, x, y, dim, dim, - butPtr->borderWidth, + butPtr->borderWidth, (butPtr->flags & SELECTED) ? TK_RELIEF_SUNKEN : TK_RELIEF_RAISED); x += butPtr->borderWidth; @@ -222,7 +221,7 @@ TkpDisplayButton(clientData) if (butPtr->flags & SELECTED) { GC gc; - gc = Tk_3DBorderGC(tkwin,(butPtr->selectBorder != NULL) + gc = Tk_3DBorderGC(tkwin, (butPtr->selectBorder != NULL) ? butPtr->selectBorder : butPtr->normalBorder, TK_3D_FLAT_GC); XFillRectangle(butPtr->display, pixmap, gc, x, y, @@ -269,7 +268,7 @@ TkpDisplayButton(clientData) * must temporarily modify the GC. */ - if ((butPtr->state == tkDisabledUid) + if ((butPtr->state == STATE_DISABLED) && ((butPtr->disabledFg == NULL) || (butPtr->image != NULL))) { if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn && (butPtr->selectBorder != NULL)) { @@ -297,7 +296,8 @@ TkpDisplayButton(clientData) if (relief != TK_RELIEF_FLAT) { int inset = butPtr->highlightWidth; - if (butPtr->defaultState == tkActiveUid) { + + if (butPtr->defaultState == DEFAULT_ACTIVE) { /* * Draw the default ring with 2 pixels of space between the * default ring and the button and the default ring and the @@ -319,15 +319,14 @@ TkpDisplayButton(clientData) Tk_Height(tkwin) - 2*inset, 2, TK_RELIEF_FLAT); inset += 2; - } else if (butPtr->defaultState == tkNormalUid) { + } else if (butPtr->defaultState == DEFAULT_NORMAL) { /* * Leave room for the default ring and write over any text or * background color. */ Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0, - 0, Tk_Width(tkwin), - Tk_Height(tkwin), 5, TK_RELIEF_FLAT); + 0, Tk_Width(tkwin), Tk_Height(tkwin), 5, TK_RELIEF_FLAT); inset += 5; } @@ -339,7 +338,7 @@ TkpDisplayButton(clientData) Tk_Width(tkwin) - 2*inset, Tk_Height(tkwin) - 2*inset, butPtr->borderWidth, relief); } - if (butPtr->highlightWidth != 0) { + if (butPtr->highlightWidth > 0) { GC gc; if (butPtr->flags & GOT_FOCUS) { @@ -354,7 +353,7 @@ TkpDisplayButton(clientData) * padding space left for a default ring. */ - if (butPtr->defaultState == tkNormalUid) { + if (butPtr->defaultState == DEFAULT_NORMAL) { TkDrawInsetFocusHighlight(tkwin, gc, butPtr->highlightWidth, pixmap, 5); } else { @@ -398,16 +397,13 @@ TkpComputeButtonGeometry(butPtr) int width, height, avgWidth; Tk_FontMetrics fm; - if (butPtr->highlightWidth < 0) { - butPtr->highlightWidth = 0; - } butPtr->inset = butPtr->highlightWidth + butPtr->borderWidth; /* * Leave room for the default ring if needed. */ - if (butPtr->defaultState != tkDisabledUid) { + if (butPtr->defaultState != DEFAULT_DISABLED) { butPtr->inset += 5; } butPtr->indicatorSpace = 0; @@ -433,9 +429,10 @@ TkpComputeButtonGeometry(butPtr) goto imageOrBitmap; } else { Tk_FreeTextLayout(butPtr->textLayout); + butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont, - butPtr->text, -1, butPtr->wrapLength, butPtr->justify, 0, - &butPtr->textWidth, &butPtr->textHeight); + Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength, + butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight); width = butPtr->textWidth; height = butPtr->textHeight; diff --git a/unix/tkUnixConfig.c b/unix/tkUnixConfig.c new file mode 100644 index 0000000..26f7dd1 --- /dev/null +++ b/unix/tkUnixConfig.c @@ -0,0 +1,45 @@ +/* + * tkUnixConfig.c -- + * + * This module implements the Unix system defaults for + * the configuration package. + * + * Copyright (c) 1997 by Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkUnixConfig.c,v 1.2 1999/04/16 01:51:45 stanton Exp $ + */ + +#include "tk.h" +#include "tkInt.h" + + +/* + *---------------------------------------------------------------------- + * + * TkpGetSystemDefault -- + * + * Given a dbName and className for a configuration option, + * return a string representation of the option. + * + * Results: + * Returns a Tk_Uid that is the string identifier that identifies + * this option. Returns NULL if there are no system defaults + * that match this pair. + * + * Side effects: + * None, once the package is initialized. + * + *---------------------------------------------------------------------- + */ + +Tcl_Obj * +TkpGetSystemDefault(tkwin, dbName, className) + Tk_Window tkwin; /* A window to use. */ + char *dbName; /* The option database name. */ + char *className; /* The name of the option class. */ +{ + return NULL; +} diff --git a/unix/tkUnixCursor.c b/unix/tkUnixCursor.c index 876ea2d..8755a3c 100644 --- a/unix/tkUnixCursor.c +++ b/unix/tkUnixCursor.c @@ -3,12 +3,12 @@ * * This file contains X specific cursor manipulation routines. * - * Copyright (c) 1995 Sun Microsystems, Inc. + * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixCursor.c,v 1.3 1998/09/14 18:23:55 stanton Exp $ + * RCS: @(#) $Id: tkUnixCursor.c,v 1.4 1999/04/16 01:51:45 stanton Exp $ */ #include "tkPort.h" @@ -218,7 +218,7 @@ TkGetCursorByName(interp, tkwin, string) if (dispPtr->cursorFont == None) { dispPtr->cursorFont = XLoadFont(display, CURSORFONT); if (dispPtr->cursorFont == None) { - interp->result = "couldn't load cursor font"; + Tcl_SetResult(interp, "couldn't load cursor font", TCL_STATIC); goto cleanup; } } @@ -282,8 +282,9 @@ TkGetCursorByName(interp, tkwin, string) goto cleanup; } if ((maskWidth != width) && (maskHeight != height)) { - interp->result = - "source and mask bitmaps have different sizes"; + Tcl_SetResult(interp, + "source and mask bitmaps have different sizes", + TCL_STATIC); goto cleanup; } if (XParseColor(display, Tk_Colormap(tkwin), argv[2], @@ -323,6 +324,9 @@ TkGetCursorByName(interp, tkwin, string) badString: + if (argv) { + ckfree((char *) argv); + } Tcl_AppendResult(interp, "bad cursor spec \"", string, "\"", (char *) NULL); return NULL; @@ -382,7 +386,7 @@ TkCreateCursorFromData(tkwin, source, mask, width, height, xHot, yHot, /* *---------------------------------------------------------------------- * - * TkFreeCursor -- + * TkpFreeCursor -- * * This procedure is called to release a cursor allocated by * TkGetCursorByName. @@ -397,11 +401,10 @@ TkCreateCursorFromData(tkwin, source, mask, width, height, xHot, yHot, */ void -TkFreeCursor(cursorPtr) +TkpFreeCursor(cursorPtr) TkCursor *cursorPtr; { TkUnixCursor *unixCursorPtr = (TkUnixCursor *) cursorPtr; XFreeCursor(unixCursorPtr->display, (Cursor) unixCursorPtr->info.cursor); Tk_FreeXId(unixCursorPtr->display, (XID) unixCursorPtr->info.cursor); - ckfree((char *) unixCursorPtr); } diff --git a/unix/tkUnixDefault.h b/unix/tkUnixDefault.h index 2967207..04225ad 100644 --- a/unix/tkUnixDefault.h +++ b/unix/tkUnixDefault.h @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixDefault.h,v 1.2 1998/09/14 18:23:55 stanton Exp $ + * RCS: @(#) $Id: tkUnixDefault.h,v 1.3 1999/04/16 01:51:45 stanton Exp $ */ #ifndef _TKUNIXDEFAULT @@ -59,7 +59,8 @@ #define DEF_CHKRAD_FG DEF_BUTTON_FG #define DEF_BUTTON_FONT "Helvetica -12 bold" #define DEF_BUTTON_HEIGHT "0" -#define DEF_BUTTON_HIGHLIGHT_BG NORMAL_BG +#define DEF_BUTTON_HIGHLIGHT_BG_COLOR DEF_BUTTON_BG_COLOR +#define DEF_BUTTON_HIGHLIGHT_BG_MONO DEF_BUTTON_BG_MONO #define DEF_BUTTON_HIGHLIGHT BLACK #define DEF_LABEL_HIGHLIGHT_WIDTH "0" #define DEF_BUTTON_HIGHLIGHT_WIDTH "1" @@ -282,7 +283,8 @@ #define DEF_MENUBUTTON_FONT "Helvetica -12 bold" #define DEF_MENUBUTTON_FG BLACK #define DEF_MENUBUTTON_HEIGHT "0" -#define DEF_MENUBUTTON_HIGHLIGHT_BG NORMAL_BG +#define DEF_MENUBUTTON_HIGHLIGHT_BG_COLOR DEF_MENUBUTTON_BG_COLOR +#define DEF_MENUBUTTON_HIGHLIGHT_BG_MONO DEF_MENUBUTTON_BG_MONO #define DEF_MENUBUTTON_HIGHLIGHT BLACK #define DEF_MENUBUTTON_HIGHLIGHT_WIDTH "0" #define DEF_MENUBUTTON_IMAGE (char *) NULL @@ -341,14 +343,15 @@ #define DEF_SCALE_FG_COLOR BLACK #define DEF_SCALE_FG_MONO BLACK #define DEF_SCALE_FROM "0" -#define DEF_SCALE_HIGHLIGHT_BG NORMAL_BG +#define DEF_SCALE_HIGHLIGHT_BG_COLOR DEF_SCALE_BG_COLOR +#define DEF_SCALE_HIGHLIGHT_BG_MONO DEF_SCALE_BG_MONO #define DEF_SCALE_HIGHLIGHT BLACK #define DEF_SCALE_HIGHLIGHT_WIDTH "1" #define DEF_SCALE_LABEL "" #define DEF_SCALE_LENGTH "100" #define DEF_SCALE_ORIENT "vertical" #define DEF_SCALE_RELIEF "flat" -#define DEF_SCALE_REPEAT_DELAY "300" +#define DEF_SCALE_REPEAT_DELAY "300" #define DEF_SCALE_REPEAT_INTERVAL "100" #define DEF_SCALE_RESOLUTION "1" #define DEF_SCALE_TROUGH_COLOR TROUGH diff --git a/unix/tkUnixEmbed.c b/unix/tkUnixEmbed.c index 2a8bac0..e996a0b 100644 --- a/unix/tkUnixEmbed.c +++ b/unix/tkUnixEmbed.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixEmbed.c,v 1.2 1998/09/14 18:23:56 stanton Exp $ + * RCS: @(#) $Id: tkUnixEmbed.c,v 1.3 1999/04/16 01:51:46 stanton Exp $ */ #include "tkInt.h" @@ -46,9 +46,11 @@ typedef struct Container { * this process. */ } Container; -static Container *firstContainerPtr = NULL; - /* First in list of all containers +typedef struct ThreadSpecificData { + Container *firstContainerPtr; /* First in list of all containers * managed by this process. */ +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; /* * Prototypes for static procedures defined in this file: @@ -83,7 +85,7 @@ static void EmbedWindowDeleted _ANSI_ARGS_((TkWindow *winPtr)); * Results: * The return value is normally TCL_OK. If an error occurs (such * as string not being a valid window spec), then the return value - * is TCL_ERROR and an error message is left in interp->result if + * is TCL_ERROR and an error message is left in the interp's result if * interp is non-NULL. * * Side effects: @@ -108,6 +110,8 @@ TkpUseWindow(interp, tkwin, string) Tk_ErrorHandler handler; Container *containerPtr; XWindowAttributes parentAtts; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (winPtr->window != None) { panic("TkUseWindow: X window already assigned"); @@ -157,7 +161,7 @@ TkpUseWindow(interp, tkwin, string) * app. are in the same process. */ - for (containerPtr = firstContainerPtr; containerPtr != NULL; + for (containerPtr = tsdPtr->firstContainerPtr; containerPtr != NULL; containerPtr = containerPtr->nextPtr) { if (containerPtr->parent == parent) { winPtr->flags |= TK_BOTH_HALVES; @@ -171,8 +175,8 @@ TkpUseWindow(interp, tkwin, string) containerPtr->parentRoot = parentAtts.root; containerPtr->parentPtr = NULL; containerPtr->wrapper = None; - containerPtr->nextPtr = firstContainerPtr; - firstContainerPtr = containerPtr; + containerPtr->nextPtr = tsdPtr->firstContainerPtr; + tsdPtr->firstContainerPtr = containerPtr; } containerPtr->embeddedPtr = winPtr; winPtr->flags |= TK_EMBEDDED; @@ -204,6 +208,8 @@ TkpMakeWindow(winPtr, parent) * which the window is to be created. */ { Container *containerPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (winPtr->flags & TK_EMBEDDED) { /* @@ -213,7 +219,7 @@ TkpMakeWindow(winPtr, parent) * into a wrapper window later. */ - for (containerPtr = firstContainerPtr; ; + for (containerPtr = tsdPtr->firstContainerPtr; ; containerPtr = containerPtr->nextPtr) { if (containerPtr == NULL) { panic("TkMakeWindow couldn't find container for window"); @@ -259,6 +265,8 @@ TkpMakeContainer(tkwin) { TkWindow *winPtr = (TkWindow *) tkwin; Container *containerPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); /* * Register the window as a container so that, for example, we can @@ -272,8 +280,8 @@ TkpMakeContainer(tkwin) containerPtr->parentPtr = winPtr; containerPtr->wrapper = None; containerPtr->embeddedPtr = NULL; - containerPtr->nextPtr = firstContainerPtr; - firstContainerPtr = containerPtr; + containerPtr->nextPtr = tsdPtr->firstContainerPtr; + tsdPtr->firstContainerPtr = containerPtr; winPtr->flags |= TK_CONTAINER; /* @@ -383,6 +391,8 @@ ContainerEventProc(clientData, eventPtr) TkWindow *winPtr = (TkWindow *) clientData; Container *containerPtr; Tk_ErrorHandler errHandler; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); /* * Ignore any X protocol errors that happen in this procedure @@ -397,7 +407,7 @@ ContainerEventProc(clientData, eventPtr) * Find the Container structure associated with the parent window. */ - for (containerPtr = firstContainerPtr; + for (containerPtr = tsdPtr->firstContainerPtr; containerPtr->parent != eventPtr->xmaprequest.parent; containerPtr = containerPtr->nextPtr) { if (containerPtr == NULL) { @@ -697,8 +707,11 @@ TkpGetOtherWindow(winPtr) * embedded window. */ { Container *containerPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - for (containerPtr = firstContainerPtr; containerPtr != NULL; + for (containerPtr = tsdPtr->firstContainerPtr; + containerPtr != NULL; containerPtr = containerPtr->nextPtr) { if (containerPtr->embeddedPtr == winPtr) { return containerPtr->parentPtr; @@ -741,6 +754,8 @@ TkpRedirectKeyEvent(winPtr, eventPtr) { Container *containerPtr; Window saved; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); /* * First, find the top-level window corresponding to winPtr. @@ -769,7 +784,7 @@ TkpRedirectKeyEvent(winPtr, eventPtr) * application. Send the event back to the container. */ - for (containerPtr = firstContainerPtr; + for (containerPtr = tsdPtr->firstContainerPtr; containerPtr->embeddedPtr != winPtr; containerPtr = containerPtr->nextPtr) { /* Empty loop body. */ @@ -811,12 +826,14 @@ TkpClaimFocus(topLevelPtr, force) { XEvent event; Container *containerPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (!(topLevelPtr->flags & TK_EMBEDDED)) { return; } - for (containerPtr = firstContainerPtr; + for (containerPtr = tsdPtr->firstContainerPtr; containerPtr->embeddedPtr != topLevelPtr; containerPtr = containerPtr->nextPtr) { /* Empty loop body. */ @@ -861,6 +878,8 @@ TkpTestembedCmd(clientData, interp, argc, argv) Container *containerPtr; Tcl_DString dString; char buffer[50]; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if ((argc > 1) && (strcmp(argv[1], "all") == 0)) { all = 1; @@ -868,7 +887,7 @@ TkpTestembedCmd(clientData, interp, argc, argv) all = 0; } Tcl_DStringInit(&dString); - for (containerPtr = firstContainerPtr; containerPtr != NULL; + for (containerPtr = tsdPtr->firstContainerPtr; containerPtr != NULL; containerPtr = containerPtr->nextPtr) { Tcl_DStringStartSublist(&dString); if (containerPtr->parent == None) { @@ -933,6 +952,8 @@ EmbedWindowDeleted(winPtr) * was deleted. */ { Container *containerPtr, *prevPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); /* * Find the Container structure for this window work. Delete the @@ -941,7 +962,7 @@ EmbedWindowDeleted(winPtr) */ prevPtr = NULL; - containerPtr = firstContainerPtr; + containerPtr = tsdPtr->firstContainerPtr; while (1) { if (containerPtr->embeddedPtr == winPtr) { containerPtr->wrapper = None; @@ -958,7 +979,7 @@ EmbedWindowDeleted(winPtr) if ((containerPtr->embeddedPtr == NULL) && (containerPtr->parentPtr == NULL)) { if (prevPtr == NULL) { - firstContainerPtr = containerPtr->nextPtr; + tsdPtr->firstContainerPtr = containerPtr->nextPtr; } else { prevPtr->nextPtr = containerPtr->nextPtr; } @@ -989,9 +1010,11 @@ TkUnixContainerId(winPtr) TkWindow *winPtr; /* Tk's structure for an embedded window. */ { Container *containerPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - for (containerPtr = firstContainerPtr; containerPtr != NULL; - containerPtr = containerPtr->nextPtr) { + for (containerPtr = tsdPtr->firstContainerPtr; + containerPtr != NULL; containerPtr = containerPtr->nextPtr) { if (containerPtr->embeddedPtr == winPtr) { return containerPtr->parent; } diff --git a/unix/tkUnixEvent.c b/unix/tkUnixEvent.c index 12e58f4..4353154 100644 --- a/unix/tkUnixEvent.c +++ b/unix/tkUnixEvent.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixEvent.c,v 1.2 1998/09/14 18:23:56 stanton Exp $ + * RCS: @(#) $Id: tkUnixEvent.c,v 1.3 1999/04/16 01:51:46 stanton Exp $ */ #include "tkInt.h" @@ -17,10 +17,14 @@ #include <signal.h> /* - * The following static indicates whether this module has been initialized. + * The following static indicates whether this module has been initialized + * in the current thread. */ -static int initialized = 0; +typedef struct ThreadSpecificData { + int initialized; +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; /* * Prototypes for procedures that are referenced only in this file: @@ -34,6 +38,8 @@ static void DisplayFileProc _ANSI_ARGS_((ClientData clientData, int flags)); static void DisplaySetupProc _ANSI_ARGS_((ClientData clientData, int flags)); +static void TransferXEventsToTcl _ANSI_ARGS_((Display *display)); + /* *---------------------------------------------------------------------- @@ -55,8 +61,11 @@ static void DisplaySetupProc _ANSI_ARGS_((ClientData clientData, void TkCreateXEventSource() { - if (!initialized) { - initialized = 1; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + if (!tsdPtr->initialized) { + tsdPtr->initialized = 1; Tcl_CreateEventSource(DisplaySetupProc, DisplayCheckProc, NULL); Tcl_CreateExitHandler(DisplayExitHandler, NULL); } @@ -83,8 +92,11 @@ static void DisplayExitHandler(clientData) ClientData clientData; /* Not used. */ { + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + Tcl_DeleteEventSource(DisplaySetupProc, DisplayCheckProc, NULL); - initialized = 0; + tsdPtr->initialized = 0; } /* @@ -185,7 +197,7 @@ DisplaySetupProc(clientData, flags) return; } - for (dispPtr = tkDisplayList; dispPtr != NULL; + for (dispPtr = TkGetDisplayList(); dispPtr != NULL; dispPtr = dispPtr->nextPtr) { /* @@ -196,7 +208,7 @@ DisplaySetupProc(clientData, flags) */ XFlush(dispPtr->display); - if (XQLength(dispPtr->display) > 0) { + if (QLength(dispPtr->display) > 0) { Tcl_SetMaxBlockTime(&blockTime); } } @@ -205,6 +217,43 @@ DisplaySetupProc(clientData, flags) /* *---------------------------------------------------------------------- * + * TransferXEventsToTcl + * + * Transfer events from the X event queue to the Tk event queue. + * + * Results: + * None. + * + * Side effects: + * Moves queued X events onto the Tcl event queue. + * + *---------------------------------------------------------------------- + */ + + +static void +TransferXEventsToTcl(display) + Display *display; +{ + int numFound; + XEvent event; + + numFound = QLength(display); + + /* + * Transfer events from the X event queue to the Tk event queue. + */ + + while (numFound > 0) { + XNextEvent(display, &event); + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + numFound--; + } +} + +/* + *---------------------------------------------------------------------- + * * DisplayCheckProc -- * * This procedure checks for events sitting in the X event @@ -225,29 +274,19 @@ DisplayCheckProc(clientData, flags) int flags; { TkDisplay *dispPtr; - XEvent event; - int numFound; if (!(flags & TCL_WINDOW_EVENTS)) { return; } - for (dispPtr = tkDisplayList; dispPtr != NULL; + for (dispPtr = TkGetDisplayList(); dispPtr != NULL; dispPtr = dispPtr->nextPtr) { XFlush(dispPtr->display); - numFound = XQLength(dispPtr->display); - - /* - * Transfer events from the X event queue to the Tk event queue. - */ - - while (numFound > 0) { - XNextEvent(dispPtr->display, &event); - Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); - numFound--; - } + TransferXEventsToTcl(dispPtr->display); } } + + /* *---------------------------------------------------------------------- @@ -273,7 +312,6 @@ DisplayFileProc(clientData, flags) { TkDisplay *dispPtr = (TkDisplay *) clientData; Display *display = dispPtr->display; - XEvent event; int numFound; XFlush(display); @@ -311,15 +349,7 @@ DisplayFileProc(clientData, flags) (void) signal(SIGPIPE, oldHandler); } - /* - * Transfer events from the X event queue to the Tk event queue. - */ - - while (numFound > 0) { - XNextEvent(display, &event); - Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); - numFound--; - } + TransferXEventsToTcl(display); } /* @@ -394,10 +424,10 @@ TkUnixDoOneXEvent(timePtr) */ memset((VOID *) readMask, 0, MASK_SIZE*sizeof(fd_mask)); - for (dispPtr = tkDisplayList; dispPtr != NULL; + for (dispPtr = TkGetDisplayList(); dispPtr != NULL; dispPtr = dispPtr->nextPtr) { XFlush(dispPtr->display); - if (XQLength(dispPtr->display) > 0) { + if (QLength(dispPtr->display) > 0) { blockTime.tv_sec = 0; blockTime.tv_usec = 0; } @@ -425,12 +455,12 @@ TkUnixDoOneXEvent(timePtr) * Process any new events on the display connections. */ - for (dispPtr = tkDisplayList; dispPtr != NULL; + for (dispPtr = TkGetDisplayList(); dispPtr != NULL; dispPtr = dispPtr->nextPtr) { fd = ConnectionNumber(dispPtr->display); index = fd/(NBBY*sizeof(fd_mask)); bit = 1 << (fd%(NBBY*sizeof(fd_mask))); - if ((readMask[index] & bit) || (XQLength(dispPtr->display) > 0)) { + if ((readMask[index] & bit) || (QLength(dispPtr->display) > 0)) { DisplayFileProc((ClientData)dispPtr, TCL_READABLE); } } @@ -480,19 +510,11 @@ void TkpSync(display) Display *display; /* Display to sync. */ { - int numFound = 0; - XEvent event; - XSync(display, False); /* * Transfer events from the X event queue to the Tk event queue. */ + TransferXEventsToTcl(display); - numFound = XQLength(display); - while (numFound > 0) { - XNextEvent(display, &event); - Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); - numFound--; - } } diff --git a/unix/tkUnixFocus.c b/unix/tkUnixFocus.c index afab537..17dbb04 100644 --- a/unix/tkUnixFocus.c +++ b/unix/tkUnixFocus.c @@ -9,14 +9,13 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixFocus.c,v 1.2 1998/09/14 18:23:56 stanton Exp $ + * RCS: @(#) $Id: tkUnixFocus.c,v 1.3 1999/04/16 01:51:46 stanton Exp $ */ #include "tkInt.h" #include "tkPort.h" #include "tkUnixInt.h" -extern int tclFocusDebug; /* *---------------------------------------------------------------------- diff --git a/unix/tkUnixFont.c b/unix/tkUnixFont.c index 638db14..43312e9 100644 --- a/unix/tkUnixFont.c +++ b/unix/tkUnixFont.c @@ -4,96 +4,388 @@ * Contains the Unix implementation of the platform-independant * font package interface. * - * Copyright (c) 1996 Sun Microsystems, Inc. + * Copyright (c) 1996-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixFont.c,v 1.5 1999/03/10 07:04:45 stanton Exp $ + * RCS: @(#) $Id: tkUnixFont.c,v 1.6 1999/04/16 01:51:46 stanton Exp $ */ -#include "tkPort.h" -#include "tkInt.h" #include "tkUnixInt.h" - #include "tkFont.h" -#ifndef ABS -#define ABS(n) (((n) < 0) ? -(n) : (n)) -#endif +/* + * The preferred font encodings. + */ + +static CONST char *encodingList[] = { + "iso8859-1", "jis0208", "jis0212", NULL +}; + +/* + * The following structure represents a font family. It is assumed that + * all screen fonts constructed from the same "font family" share certain + * properties; all screen fonts with the same "font family" point to a + * shared instance of this structure. The most important shared property + * is the character existence metrics, used to determine if a screen font + * can display a given Unicode character. + * + * Under Unix, there are three attributes that uniquely identify a "font + * family": the foundry, face name, and charset. + */ + +#define FONTMAP_SHIFT 10 + +#define FONTMAP_PAGES (1 << (sizeof(Tcl_UniChar)*8 - FONTMAP_SHIFT)) +#define FONTMAP_BITSPERPAGE (1 << FONTMAP_SHIFT) + +typedef struct FontFamily { + struct FontFamily *nextPtr; /* Next in list of all known font families. */ + int refCount; /* How many SubFonts are referring to this + * FontFamily. When the refCount drops to + * zero, this FontFamily may be freed. */ + /* + * Key. + */ + + Tk_Uid foundry; /* Foundry key for this FontFamily. */ + Tk_Uid faceName; /* Face name key for this FontFamily. */ + Tcl_Encoding encoding; /* Encoding key for this FontFamily. */ + + /* + * Derived properties. + */ + + int isTwoByteFont; /* 1 if this is a double-byte font, 0 + * otherwise. */ + char *fontMap[FONTMAP_PAGES]; + /* Two-level sparse table used to determine + * quickly if the specified character exists. + * As characters are encountered, more pages + * in this table are dynamically alloced. The + * contents of each page is a bitmask + * consisting of FONTMAP_BITSPERPAGE bits, + * representing whether this font can be used + * to display the given character at the + * corresponding bit position. The high bits + * of the character are used to pick which + * page of the table is used. */ +} FontFamily; + +/* + * The following structure encapsulates an individual screen font. A font + * object is made up of however many SubFonts are necessary to display a + * stream of multilingual characters. + */ + +typedef struct SubFont { + char **fontMap; /* Pointer to font map from the FontFamily, + * cached here to save a dereference. */ + XFontStruct *fontStructPtr; /* The specific screen font that will be + * used when displaying/measuring chars + * belonging to the FontFamily. */ + FontFamily *familyPtr; /* The FontFamily for this SubFont. */ +} SubFont; /* - * The following structure represents Unix's implementation of a font. + * The following structure represents Unix's implementation of a font + * object. */ +#define SUBFONT_SPACE 3 +#define BASE_CHARS 256 + typedef struct UnixFont { TkFont font; /* Stuff used by generic font package. Must * be first in structure. */ - Display *display; /* The display to which font belongs. */ - XFontStruct *fontStructPtr; /* X information about font. */ - char types[256]; /* Array giving types of all characters in - * the font, used when displaying control - * characters. See below for definition. */ - int widths[256]; /* Array giving widths of all possible - * characters in the font. */ + SubFont staticSubFonts[SUBFONT_SPACE]; + /* Builtin space for a limited number of + * SubFonts. */ + int numSubFonts; /* Length of following array. */ + SubFont *subFontArray; /* Array of SubFonts that have been loaded + * in order to draw/measure all the characters + * encountered by this font so far. All fonts + * start off with one SubFont initialized by + * AllocFont() from the original set of font + * attributes. Usually points to + * staticSubFonts, but may point to malloced + * space if there are lots of SubFonts. */ + SubFont controlSubFont; /* Font to use to display control-character + * expansions. */ + + Display *display; /* Display that owns font. */ + int pixelSize; /* Original pixel size used when font was + * constructed. */ + TkXLFDAttributes xa; /* Additional attributes that specify the + * preferred foundry and encoding to use when + * constructing additional SubFonts. */ + int widths[BASE_CHARS]; /* Widths of first 256 chars in the base + * font, for handling common case. */ int underlinePos; /* Offset from baseline to origin of - * underline bar (used for simulating a native - * underlined font). */ + * underline bar (used when drawing underlined + * font) (pixels). */ int barHeight; /* Height of underline or overstrike bar - * (used for simulating a native underlined or - * strikeout font). */ + * (used when drawing underlined or strikeout + * font) (pixels). */ } UnixFont; /* - * Possible values for entries in the "types" field in a UnixFont structure, - * which classifies the types of all characters in the given font. This - * information is used when measuring and displaying characters. - * - * NORMAL: Standard character. - * REPLACE: This character doesn't print: instead of - * displaying character, display a replacement - * sequence like "\n" (for those characters where - * ANSI C defines such a sequence) or a sequence - * of the form "\xdd" where dd is the hex equivalent - * of the character. - * SKIP: Don't display anything for this character. This - * is only used where the font doesn't contain - * all the characters needed to generate - * replacement sequences. - */ - -#define NORMAL 0 -#define REPLACE 1 -#define SKIP 2 + * The following structure and definition is used to keep track of the + * alternative names for various encodings. Asking for an encoding that + * matches one of the alias patterns will result in actually getting the + * encoding by its real name. + */ + +typedef struct EncodingAlias { + char *realName; /* The real name of the encoding to load if + * the provided name matched the pattern. */ + char *aliasPattern; /* Pattern for encoding name, of the form + * that is acceptable to Tcl_StringMatch. */ +} EncodingAlias; /* - * Characters used when displaying control sequences. + * Just some utility structures used for passing around values in helper + * procedures. */ + +typedef struct FontAttributes { + TkFontAttributes fa; + TkXLFDAttributes xa; +} FontAttributes; + + +typedef struct ThreadSpecificData { + FontFamily *fontFamilyList; /* The list of font families that are + * currently loaded. As screen fonts + * are loaded, this list grows to hold + * information about what characters + * exist in each font family. */ + FontFamily controlFamily; /* FontFamily used to handle control + * character expansions. The encoding + * of this FontFamily converts UTF-8 to + * backslashed escape sequences. */ +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; -static char hexChars[] = "0123456789abcdefxtnvr\\"; +/* + * The set of builtin encoding alises to convert the XLFD names for the + * encodings into the names expected by the Tcl encoding package. + */ + +static EncodingAlias encodingAliases[] = { + {"gb2312", "gb2312*"}, + {"big5", "big5*"}, + {"cns11643-1", "cns11643*-1"}, + {"cns11643-1", "cns11643*.1-0"}, + {"cns11643-2", "cns11643*-2"}, + {"cns11643-2", "cns11643*.2-0"}, + {"jis0201", "jisx0202*"}, + {"jis0208", "jisc6226*"}, + {"jis0208", "jisx0208*"}, + {"jis0212", "jisx0212*"}, + {"tis620", "tis620*"}, + {"ksc5601", "ksc5601*"}, + {"dingbats", "*dingbats"}, + {NULL, NULL} +}; /* - * The following table maps some control characters to sequences like '\n' - * rather than '\x10'. A zero entry in the table means no such mapping - * exists, and the table only maps characters less than 0x10. + * Procedures used only in this file. */ -static char mapChars[] = { - 0, 0, 0, 0, 0, 0, 0, - 'a', 'b', 't', 'n', 'v', 'f', 'r', - 0 -}; +static FontFamily * AllocFontFamily _ANSI_ARGS_((Display *display, + XFontStruct *fontStructPtr, int base)); +static SubFont * CanUseFallback _ANSI_ARGS_((UnixFont *fontPtr, + char *fallbackName, int ch)); +static SubFont * CanUseFallbackWithAliases _ANSI_ARGS_(( + UnixFont *fontPtr, char *fallbackName, + int ch, Tcl_DString *nameTriedPtr)); +static int ControlUtfProc _ANSI_ARGS_((ClientData clientData, + CONST char *src, int srcLen, int flags, + Tcl_EncodingState *statePtr, char *dst, + int dstLen, int *srcReadPtr, int *dstWrotePtr, + int *dstCharsPtr)); +static XFontStruct * CreateClosestFont _ANSI_ARGS_((Tk_Window tkwin, + CONST TkFontAttributes *faPtr, + CONST TkXLFDAttributes *xaPtr)); +static SubFont * FindSubFontForChar _ANSI_ARGS_((UnixFont *fontPtr, + int ch)); +static void FontMapInsert _ANSI_ARGS_((SubFont *subFontPtr, + int ch)); +static void FontMapLoadPage _ANSI_ARGS_((SubFont *subFontPtr, + int row)); +static int FontMapLookup _ANSI_ARGS_((SubFont *subFontPtr, + int ch)); +static void FreeFontFamily _ANSI_ARGS_((FontFamily *afPtr)); +static CONST char * GetEncodingAlias _ANSI_ARGS_((CONST char *name)); +static int GetFontAttributes _ANSI_ARGS_((Display *display, + XFontStruct *fontStructPtr, FontAttributes *faPtr)); +static XFontStruct * GetScreenFont _ANSI_ARGS_((Display *display, + FontAttributes *wantPtr, char **nameList, + int bestIdx[], unsigned int bestScore[])); +static XFontStruct * GetSystemFont _ANSI_ARGS_((Display *display)); +static int IdentifySymbolEncodings _ANSI_ARGS_(( + FontAttributes *faPtr)); +static void InitFont _ANSI_ARGS_((Tk_Window tkwin, + XFontStruct *fontStructPtr, UnixFont *fontPtr)); +static void InitSubFont _ANSI_ARGS_((Display *display, + XFontStruct *fontStructPtr, int base, + SubFont *subFontPtr)); +static char ** ListFonts _ANSI_ARGS_((Display *display, + CONST char *faceName, int *numNamesPtr)); +static char ** ListFontOrAlias _ANSI_ARGS_((Display *display, + CONST char *faceName, int *numNamesPtr)); +static unsigned int RankAttributes _ANSI_ARGS_((FontAttributes *wantPtr, + FontAttributes *gotPtr)); +static void ReleaseFont _ANSI_ARGS_((UnixFont *fontPtr)); +static void ReleaseSubFont _ANSI_ARGS_((Display *display, + SubFont *subFontPtr)); +static int SeenName _ANSI_ARGS_((CONST char *name, + Tcl_DString *dsPtr)); + +/* + *------------------------------------------------------------------------- + * + * TkpFontPkgInit -- + * + * This procedure is called when an application is created. It + * initializes all the structures that are used by the + * platform-dependent code on a per application basis. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------- + */ -static UnixFont * AllocFont _ANSI_ARGS_((TkFont *tkFontPtr, - Tk_Window tkwin, XFontStruct *fontStructPtr, - CONST char *fontName)); -static void DrawChars _ANSI_ARGS_((Display *display, - Drawable drawable, GC gc, UnixFont *fontPtr, - CONST char *source, int numChars, int x, - int y)); -static int GetControlCharSubst _ANSI_ARGS_((int c, char buf[4])); +void +TkpFontPkgInit(mainPtr) + TkMainInfo *mainPtr; /* The application being created. */ +{ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + Tcl_EncodingType type; + SubFont dummy; + int i; + + if (tsdPtr->controlFamily.encoding == NULL) { + type.encodingName = "X11ControlChars"; + type.toUtfProc = ControlUtfProc; + type.fromUtfProc = ControlUtfProc; + type.freeProc = NULL; + type.clientData = NULL; + type.nullSize = 0; + + tsdPtr->controlFamily.refCount = 2; + tsdPtr->controlFamily.encoding = Tcl_CreateEncoding(&type); + tsdPtr->controlFamily.isTwoByteFont = 0; + + dummy.familyPtr = &tsdPtr->controlFamily; + dummy.fontMap = tsdPtr->controlFamily.fontMap; + for (i = 0x00; i < 0x20; i++) { + FontMapInsert(&dummy, i); + FontMapInsert(&dummy, i + 0x80); + } + } +} + +/* + *------------------------------------------------------------------------- + * + * ControlUtfProc -- + * + * Convert from UTF-8 into the ASCII expansion of a control + * character. + * + * Results: + * Returns TCL_OK if conversion was successful. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------- + */ +static int +ControlUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, + srcReadPtr, dstWrotePtr, dstCharsPtr) + ClientData clientData; /* Not used. */ + CONST char *src; /* Source string in UTF-8. */ + int srcLen; /* Source string length in bytes. */ + int flags; /* Conversion control flags. */ + Tcl_EncodingState *statePtr;/* Place for conversion routine to store + * state information used during a piecewise + * conversion. Contents of statePtr are + * initialized and/or reset by conversion + * routine under control of flags argument. */ + char *dst; /* Output buffer in which converted string + * is stored. */ + int dstLen; /* The maximum length of output buffer in + * bytes. */ + int *srcReadPtr; /* Filled with the number of bytes from the + * source string that were converted. This + * may be less than the original source length + * if there was a problem converting some + * source characters. */ + int *dstWrotePtr; /* Filled with the number of bytes that were + * stored in the output buffer as a result of + * the conversion. */ + int *dstCharsPtr; /* Filled with the number of characters that + * correspond to the bytes stored in the + * output buffer. */ +{ + CONST char *srcStart, *srcEnd; + char *dstStart, *dstEnd; + Tcl_UniChar ch; + int result; + static char hexChars[] = "0123456789abcdef"; + static char mapChars[] = { + 0, 0, 0, 0, 0, 0, 0, + 'a', 'b', 't', 'n', 'v', 'f', 'r' + }; + + result = TCL_OK; + + srcStart = src; + srcEnd = src + srcLen; + + dstStart = dst; + dstEnd = dst + dstLen - 6; + + for ( ; src < srcEnd; ) { + if (dst > dstEnd) { + result = TCL_CONVERT_NOSPACE; + break; + } + src += Tcl_UtfToUniChar(src, &ch); + dst[0] = '\\'; + if ((ch < sizeof(mapChars)) && (mapChars[ch] != 0)) { + dst[1] = mapChars[ch]; + dst += 2; + } else if (ch < 256) { + dst[1] = 'x'; + dst[2] = hexChars[(ch >> 4) & 0xf]; + dst[3] = hexChars[ch & 0xf]; + dst += 4; + } else { + dst[1] = 'u'; + dst[2] = hexChars[(ch >> 12) & 0xf]; + dst[3] = hexChars[(ch >> 8) & 0xf]; + dst[4] = hexChars[(ch >> 4) & 0xf]; + dst[5] = hexChars[ch & 0xf]; + dst += 6; + } + } + *srcReadPtr = src - srcEnd; + *dstWrotePtr = dst - dstStart; + *dstCharsPtr = dst - dstStart; + return result; +} /* *--------------------------------------------------------------------------- @@ -116,18 +408,20 @@ static int GetControlCharSubst _ANSI_ARGS_((int c, char buf[4])); * the contents of the generic TkFont before calling TkpDeleteFont(). * * Side effects: - * None. + * Memory allocated. * *--------------------------------------------------------------------------- */ - + TkFont * TkpGetNativeFont(tkwin, name) Tk_Window tkwin; /* For display where font will be used. */ CONST char *name; /* Platform-specific font name. */ { + UnixFont *fontPtr; XFontStruct *fontStructPtr; - char *p; + FontAttributes fa; + CONST char *p; int hasSpace, dashes, hasWild; /* @@ -141,7 +435,7 @@ TkpGetNativeFont(tkwin, name) */ hasSpace = dashes = hasWild = 0; - for (p = (char *) name; *p != '\0'; p++) { + for (p = name; *p != '\0'; p++) { if (*p == ' ') { if (p[1] == '-') { return NULL; @@ -159,10 +453,36 @@ TkpGetNativeFont(tkwin, name) fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), name); if (fontStructPtr == NULL) { - return NULL; + /* + * Handle all names that look like XLFDs here. Otherwise, when + * TkpGetFontFromAttributes is called from generic code, any + * foundry or encoding information specified in the XLFD will have + * been parsed out and lost. But make sure we don't have an + * "-option value" string since TkFontParseXLFD would return a + * false success when attempting to parse it. + */ + + if (name[0] == '-') { + if (name[1] != '*') { + char *dash; + + dash = strchr(name + 1, '-'); + if ((dash == NULL) || (isspace(UCHAR(dash[-1])))) { + return NULL; + } + } + } else if (name[0] != '*') { + return NULL; + } + if (TkFontParseXLFD(name, &fa.fa, &fa.xa) != TCL_OK) { + return NULL; + } + fontStructPtr = CreateClosestFont(tkwin, &fa.fa, &fa.xa); } + fontPtr = (UnixFont *) ckalloc(sizeof(UnixFont)); + InitFont(tkwin, fontStructPtr, fontPtr); - return (TkFont *) AllocFont(NULL, tkwin, fontStructPtr, name); + return (TkFont *) fontPtr; } /* @@ -189,7 +509,7 @@ TkpGetNativeFont(tkwin, name) * the contents of the generic TkFont before calling TkpDeleteFont(). * * Side effects: - * None. + * Memory allocated. * *--------------------------------------------------------------------------- */ @@ -202,249 +522,29 @@ TkpGetFontFromAttributes(tkFontPtr, tkwin, faPtr) * will be released. If NULL, a new TkFont * structure is allocated. */ Tk_Window tkwin; /* For display where font will be used. */ - CONST TkFontAttributes *faPtr; /* Set of attributes to match. */ + CONST TkFontAttributes *faPtr; + /* Set of attributes to match. */ { - int numNames, score, i, scaleable, pixelsize, xaPixelsize; - int bestIdx, bestScore, bestScaleableIdx, bestScaleableScore; - TkXLFDAttributes xa; - char buf[256]; UnixFont *fontPtr; - char **nameList; + TkXLFDAttributes xa; XFontStruct *fontStructPtr; - CONST char *fmt, *family; - double d; - - family = faPtr->family; - if (family == NULL) { - family = "*"; - } - - pixelsize = -faPtr->pointsize; - if (pixelsize < 0) { - d = -pixelsize * 25.4 / 72; - d *= WidthOfScreen(Tk_Screen(tkwin)); - d /= WidthMMOfScreen(Tk_Screen(tkwin)); - d += 0.5; - pixelsize = (int) d; - } - - /* - * Replace the standard Windows and Mac family names with the names that - * X likes. - */ - - if ((strcasecmp("Times New Roman", family) == 0) - || (strcasecmp("New York", family) == 0)) { - family = "Times"; - } else if ((strcasecmp("Courier New", family) == 0) - || (strcasecmp("Monaco", family) == 0)) { - family = "Courier"; - } else if ((strcasecmp("Arial", family) == 0) - || (strcasecmp("Geneva", family) == 0)) { - family = "Helvetica"; - } - - /* - * First try for the Q&D exact match. - */ - -#if 0 - sprintf(buf, "-*-%.200s-%s-%c-normal-*-*-%d-*-*-*-*-iso8859-1", family, - ((faPtr->weight > TK_FW_NORMAL) ? "bold" : "medium"), - ((faPtr->slant == TK_FS_ROMAN) ? 'r' : - (faPtr->slant == TK_FS_ITALIC) ? 'i' : 'o'), - faPtr->pointsize * 10); - fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), buf); -#else - fontStructPtr = NULL; -#endif - - if (fontStructPtr != NULL) { - goto end; - } - /* - * Couldn't find exact match. Now fall back to other available - * physical fonts. - */ - - fmt = "-*-%.240s-*-*-*-*-*-*-*-*-*-*-*-*"; - sprintf(buf, fmt, family); - nameList = XListFonts(Tk_Display(tkwin), buf, 10000, &numNames); - if (numNames == 0) { - /* - * Try getting some system font. - */ - - sprintf(buf, fmt, "fixed"); - nameList = XListFonts(Tk_Display(tkwin), buf, 10000, &numNames); - if (numNames == 0) { - getsystem: - fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), "fixed"); - if (fontStructPtr == NULL) { - fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), "*"); - if (fontStructPtr == NULL) { - panic("TkpGetFontFromAttributes: cannot get any font"); - } - } - goto end; - } - } - - /* - * Inspect each of the XLFDs and pick the one that most closely - * matches the desired attributes. - */ - - bestIdx = 0; - bestScore = INT_MAX; - bestScaleableIdx = 0; - bestScaleableScore = INT_MAX; - - for (i = 0; i < numNames; i++) { - score = 0; - scaleable = 0; - if (TkParseXLFD(nameList[i], &xa) != TCL_OK) { - continue; - } - xaPixelsize = -xa.fa.pointsize; - - /* - * Since most people used to use -adobe-* in their XLFDs, - * preserve the preference for "adobe" foundry. Otherwise - * some applications looks may change slightly if another foundry - * is chosen. - */ - - if (strcasecmp(xa.foundry, "adobe") != 0) { - score += 3000; - } - if (xa.fa.pointsize == 0) { - /* - * A scaleable font is almost always acceptable, but the - * corresponding bitmapped font would be better. - */ - - score += 10; - scaleable = 1; - } else { - /* - * A font that is too small is better than one that is too - * big. - */ - - if (xaPixelsize > pixelsize) { - score += (xaPixelsize - pixelsize) * 120; - } else { - score += (pixelsize - xaPixelsize) * 100; - } - } - - score += ABS(xa.fa.weight - faPtr->weight) * 30; - score += ABS(xa.fa.slant - faPtr->slant) * 25; - if (xa.slant == TK_FS_OBLIQUE) { - /* - * Italic fonts are preferred over oblique. */ - - score += 4; - } - - if (xa.setwidth != TK_SW_NORMAL) { - /* - * The normal setwidth is highly preferred. - */ - score += 2000; - } - if (xa.charset == TK_CS_OTHER) { - /* - * The standard character set is highly preferred over - * foreign languages charsets (because we don't support - * other languages yet). - */ - score += 11000; - } - if ((xa.charset == TK_CS_NORMAL) && (xa.encoding != 1)) { - /* - * The '1' encoding for the characters above 0x7f is highly - * preferred over the other encodings. - */ - score += 8000; - } - - if (scaleable) { - if (score < bestScaleableScore) { - bestScaleableIdx = i; - bestScaleableScore = score; - } - } else { - if (score < bestScore) { - bestIdx = i; - bestScore = score; - } - } - if (score == 0) { - break; - } - } - /* - * Now we know which is the closest matching scaleable font and the - * closest matching bitmapped font. If the scaleable font was a - * better match, try getting the scaleable font; however, if the - * scalable font was not actually available in the desired - * pointsize, fall back to the closest bitmapped font. - */ + TkInitXLFDAttributes(&xa); + fontStructPtr = CreateClosestFont(tkwin, faPtr, &xa); - fontStructPtr = NULL; - if (bestScaleableScore < bestScore) { - char *str, *rest; - - /* - * Fill in the desired pointsize info for this font. - */ - - tryscale: - str = nameList[bestScaleableIdx]; - for (i = 0; i < XLFD_PIXEL_SIZE - 1; i++) { - str = strchr(str + 1, '-'); - } - rest = str; - for (i = XLFD_PIXEL_SIZE - 1; i < XLFD_REGISTRY; i++) { - rest = strchr(rest + 1, '-'); - } - *str = '\0'; - sprintf(buf, "%.240s-*-%d-*-*-*-*-*%s", nameList[bestScaleableIdx], - pixelsize, rest); - *str = '-'; - fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), buf); - bestScaleableScore = INT_MAX; - } - if (fontStructPtr == NULL) { - strcpy(buf, nameList[bestIdx]); - fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), buf); - if (fontStructPtr == NULL) { - /* - * This shouldn't happen because the font name is one of the - * names that X gave us to use, but it does anyhow. - */ - - if (bestScaleableScore < INT_MAX) { - goto tryscale; - } else { - XFreeFontNames(nameList); - goto getsystem; - } - } + fontPtr = (UnixFont *) tkFontPtr; + if (fontPtr == NULL) { + fontPtr = (UnixFont *) ckalloc(sizeof(UnixFont)); + } else { + ReleaseFont(fontPtr); } - XFreeFontNames(nameList); + InitFont(tkwin, fontStructPtr, fontPtr); - end: - fontPtr = AllocFont(tkFontPtr, tkwin, fontStructPtr, buf); - fontPtr->font.fa.underline = faPtr->underline; + fontPtr->font.fa.underline = faPtr->underline; fontPtr->font.fa.overstrike = faPtr->overstrike; return (TkFont *) fontPtr; } - /* *--------------------------------------------------------------------------- @@ -472,9 +572,7 @@ TkpDeleteFont(tkFontPtr) UnixFont *fontPtr; fontPtr = (UnixFont *) tkFontPtr; - - XFreeFont(fontPtr->display, fontPtr->fontStructPtr); - ckfree((char *) fontPtr); + ReleaseFont(fontPtr); } /* @@ -486,7 +584,7 @@ TkpDeleteFont(tkFontPtr) * on the display of the given window. * * Results: - * interp->result is modified to hold a list of all the available + * Modifies interp's result object to hold a list of all the available * font families. * * Side effects: @@ -494,52 +592,80 @@ TkpDeleteFont(tkFontPtr) * *--------------------------------------------------------------------------- */ - + void TkpGetFontFamilies(interp, tkwin) - Tcl_Interp *interp; - Tk_Window tkwin; + Tcl_Interp *interp; /* Interp to hold result. */ + Tk_Window tkwin; /* For display to query. */ { int i, new, numNames; - char *family, *end, *p; + char *family; Tcl_HashTable familyTable; Tcl_HashEntry *hPtr; Tcl_HashSearch search; char **nameList; + Tcl_Obj *resultPtr, *strPtr; - Tcl_InitHashTable(&familyTable, TCL_STRING_KEYS); + resultPtr = Tcl_GetObjResult(interp); - nameList = XListFonts(Tk_Display(tkwin), "*", 10000, &numNames); + Tcl_InitHashTable(&familyTable, TCL_STRING_KEYS); + nameList = ListFonts(Tk_Display(tkwin), "*", &numNames); for (i = 0; i < numNames; i++) { - if (nameList[i][0] != '-') { - continue; - } - family = strchr(nameList[i] + 1, '-'); - if (family == NULL) { - continue; - } - family++; - end = strchr(family, '-'); - if (end == NULL) { - continue; - } - *end = '\0'; - for (p = family; *p != '\0'; p++) { - if (isupper(UCHAR(*p))) { - *p = tolower(UCHAR(*p)); - } - } + family = strchr(nameList[i] + 1, '-') + 1; + strchr(family, '-')[0] = '\0'; Tcl_CreateHashEntry(&familyTable, family, &new); } + XFreeFontNames(nameList); hPtr = Tcl_FirstHashEntry(&familyTable, &search); while (hPtr != NULL) { - Tcl_AppendElement(interp, Tcl_GetHashKey(&familyTable, hPtr)); + strPtr = Tcl_NewStringObj(Tcl_GetHashKey(&familyTable, hPtr), -1); + Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); hPtr = Tcl_NextHashEntry(&search); } Tcl_DeleteHashTable(&familyTable); - XFreeFontNames(nameList); +} + +/* + *------------------------------------------------------------------------- + * + * TkpGetSubFonts -- + * + * A function used by the testing package for querying the actual + * screen fonts that make up a font object. + * + * Results: + * Modifies interp's result object to hold a list containing the + * names of the screen fonts that make up the given font object. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------- + */ + +void +TkpGetSubFonts(interp, tkfont) + Tcl_Interp *interp; + Tk_Font tkfont; +{ + int i; + Tcl_Obj *objv[3]; + Tcl_Obj *resultPtr, *listPtr; + UnixFont *fontPtr; + FontFamily *familyPtr; + + resultPtr = Tcl_GetObjResult(interp); + fontPtr = (UnixFont *) tkfont; + for (i = 0; i < fontPtr->numSubFonts; i++) { + familyPtr = fontPtr->subFontArray[i].familyPtr; + objv[0] = Tcl_NewStringObj(familyPtr->faceName, -1); + objv[1] = Tcl_NewStringObj(familyPtr->foundry, -1); + objv[2] = Tcl_NewStringObj(Tcl_GetEncodingName(familyPtr->encoding), -1); + listPtr = Tcl_NewListObj(3, objv); + Tcl_ListObjAppendElement(NULL, resultPtr, listPtr); + } } /* @@ -553,7 +679,7 @@ TkpGetFontFamilies(interp, tkwin) * the characters. * * Results: - * The return value is the number of characters from source that + * The return value is the number of bytes from source that * fit into the span that extends from 0 to maxLength. *lengthPtr is * filled with the x-coordinate of the right edge of the last * character that did fit. @@ -563,18 +689,19 @@ TkpGetFontFamilies(interp, tkwin) * *--------------------------------------------------------------------------- */ + int -Tk_MeasureChars(tkfont, source, numChars, maxLength, flags, lengthPtr) +Tk_MeasureChars(tkfont, source, numBytes, maxLength, flags, lengthPtr) Tk_Font tkfont; /* Font in which characters will be drawn. */ - CONST char *source; /* Characters to be displayed. Need not be + CONST char *source; /* UTF-8 string to be displayed. Need not be * '\0' terminated. */ - int numChars; /* Maximum number of characters to consider + int numBytes; /* Maximum number of bytes to consider * from source string. */ - int maxLength; /* If > 0, maxLength specifies the longest - * permissible line length; don't consider any - * character that would cross this - * x-position. If <= 0, then line length is - * unbounded and the flags argument is + int maxLength; /* If >= 0, maxLength specifies the longest + * permissible line length in pixels; don't + * consider any character that would cross + * this x-position. If < 0, then line length + * is unbounded and the flags argument is * ignored. */ int flags; /* Various flag bits OR-ed together: * TK_PARTIAL_OK means include the last char @@ -587,99 +714,179 @@ Tk_MeasureChars(tkfont, source, numChars, maxLength, flags, lengthPtr) * terminating character. */ { UnixFont *fontPtr; - CONST char *p; /* Current character. */ - CONST char *term; /* Pointer to most recent character that - * may legally be a terminating character. */ - int termX; /* X-position just after term. */ - int curX; /* X-position corresponding to p. */ - int newX; /* X-position corresponding to p+1. */ - int c, sawNonSpace; + SubFont *lastSubFontPtr; + int curX, curByte; - fontPtr = (UnixFont *) tkfont; + /* + * Unix does not use kerning or fractional character widths when + * displaying text on the screen. So that means we can safely measure + * individual characters or spans of characters and add up the widths + * w/o any "off-by-one-pixel" errors. + */ - if (numChars == 0) { - *lengthPtr = 0; - return 0; - } + fontPtr = (UnixFont *) tkfont; - if (maxLength <= 0) { - maxLength = INT_MAX; - } + lastSubFontPtr = &fontPtr->subFontArray[0]; - newX = curX = termX = 0; - p = term = source; - sawNonSpace = !isspace(UCHAR(*p)); + if (numBytes == 0) { + curX = 0; + curByte = 0; + } else if (maxLength < 0) { + CONST char *p, *end, *next; + Tcl_UniChar ch; + SubFont *thisSubFontPtr; + FontFamily *familyPtr; + Tcl_DString runString; - /* - * Scan the input string one character at a time, calculating width. - */ + /* + * A three step process: + * 1. Find a contiguous range of characters that can all be + * represented by a single screen font. + * 2. Convert those chars to the encoding of that font. + * 3. Measure converted chars. + */ - for (c = UCHAR(*p); ; ) { - newX += fontPtr->widths[c]; - if (newX > maxLength) { - break; + curX = 0; + end = source + numBytes; + for (p = source; p < end; ) { + next = p + Tcl_UtfToUniChar(p, &ch); + thisSubFontPtr = FindSubFontForChar(fontPtr, ch); + if (thisSubFontPtr != lastSubFontPtr) { + familyPtr = lastSubFontPtr->familyPtr; + Tcl_UtfToExternalDString(familyPtr->encoding, source, + p - source, &runString); + if (familyPtr->isTwoByteFont) { + curX += XTextWidth16(lastSubFontPtr->fontStructPtr, + (XChar2b *) Tcl_DStringValue(&runString), + Tcl_DStringLength(&runString) / 2); + } else { + curX += XTextWidth(lastSubFontPtr->fontStructPtr, + Tcl_DStringValue(&runString), + Tcl_DStringLength(&runString)); + } + Tcl_DStringFree(&runString); + lastSubFontPtr = thisSubFontPtr; + source = p; + } + p = next; } - curX = newX; - numChars--; - p++; - if (numChars == 0) { - term = p; - termX = curX; - break; + familyPtr = lastSubFontPtr->familyPtr; + Tcl_UtfToExternalDString(familyPtr->encoding, source, p - source, + &runString); + if (familyPtr->isTwoByteFont) { + curX += XTextWidth16(lastSubFontPtr->fontStructPtr, + (XChar2b *) Tcl_DStringValue(&runString), + Tcl_DStringLength(&runString) >> 1); + } else { + curX += XTextWidth(lastSubFontPtr->fontStructPtr, + Tcl_DStringValue(&runString), + Tcl_DStringLength(&runString)); } + Tcl_DStringFree(&runString); + curByte = numBytes; + } else { + CONST char *p, *end, *next, *term; + int newX, termX, sawNonSpace, dstWrote; + Tcl_UniChar ch; + FontFamily *familyPtr; + char buf[16]; + + /* + * How many chars will fit in the space allotted? + * This first version may be inefficient because it measures + * every character individually. + */ - c = UCHAR(*p); - if (isspace(c)) { - if (sawNonSpace) { - term = p; + next = source + Tcl_UtfToUniChar(source, &ch); + newX = curX = termX = 0; + + term = source; + end = source + numBytes; + + sawNonSpace = (ch > 255) || !isspace(ch); + familyPtr = lastSubFontPtr->familyPtr; + for (p = source; ; ) { + if ((ch < BASE_CHARS) && (fontPtr->widths[ch] != 0)) { + newX += fontPtr->widths[ch]; + } else { + lastSubFontPtr = FindSubFontForChar(fontPtr, ch); + familyPtr = lastSubFontPtr->familyPtr; + Tcl_UtfToExternal(NULL, familyPtr->encoding, p, next - p, + 0, NULL, buf, sizeof(buf), NULL, &dstWrote, NULL); + if (familyPtr->isTwoByteFont) { + newX += XTextWidth16(lastSubFontPtr->fontStructPtr, + (XChar2b *) buf, dstWrote >> 1); + } else { + newX += XTextWidth(lastSubFontPtr->fontStructPtr, buf, + dstWrote); + } + } + if (newX > maxLength) { + break; + } + curX = newX; + p = next; + if (p >= end) { + term = end; termX = curX; - sawNonSpace = 0; + break; } - } else { - sawNonSpace = 1; - } - } - /* - * P points to the first character that doesn't fit in the desired - * span. Use the flags to figure out what to return. - */ + next += Tcl_UtfToUniChar(next, &ch); + if ((ch < 256) && isspace(ch)) { + if (sawNonSpace) { + term = p; + termX = curX; + sawNonSpace = 0; + } + } else { + sawNonSpace = 1; + } + } - if ((flags & TK_PARTIAL_OK) && (numChars > 0) && (curX < maxLength)) { /* - * Include the first character that didn't quite fit in the desired - * span. The width returned will include the width of that extra - * character. + * P points to the first character that doesn't fit in the desired + * span. Use the flags to figure out what to return. */ - numChars--; - curX = newX; - p++; - } - if ((flags & TK_AT_LEAST_ONE) && (term == source) && (numChars > 0)) { - term = p; - termX = curX; - if (term == source) { - term++; - termX = newX; + if ((flags & TK_PARTIAL_OK) && (p < end) && (curX < maxLength)) { + /* + * Include the first character that didn't quite fit in the desired + * span. The width returned will include the width of that extra + * character. + */ + + curX = newX; + p += Tcl_UtfToUniChar(p, &ch); + } + if ((flags & TK_AT_LEAST_ONE) && (term == source) && (p < end)) { + term = p; + termX = curX; + if (term == source) { + term += Tcl_UtfToUniChar(term, &ch); + termX = newX; + } + } else if ((p >= end) || !(flags & TK_WHOLE_WORDS)) { + term = p; + termX = curX; } - } else if ((numChars == 0) || !(flags & TK_WHOLE_WORDS)) { - term = p; - termX = curX; + + curX = termX; + curByte = term - source; } - *lengthPtr = termX; - return term-source; + *lengthPtr = curX; + return curByte; } /* *--------------------------------------------------------------------------- * - * Tk_DrawChars, DrawChars -- + * Tk_DrawChars -- * * Draw a string of characters on the screen. Tk_DrawChars() - * expands control characters that occur in the string to \X or - * \xXX sequences. DrawChars() just draws the strings. + * expands control characters that occur in the string to + * \xNN sequences. * * Results: * None. @@ -691,255 +898,359 @@ Tk_MeasureChars(tkfont, source, numChars, maxLength, flags, lengthPtr) */ void -Tk_DrawChars(display, drawable, gc, tkfont, source, numChars, x, y) +Tk_DrawChars(display, drawable, gc, tkfont, source, numBytes, x, y) Display *display; /* Display on which to draw. */ Drawable drawable; /* Window or pixmap in which to draw. */ GC gc; /* Graphics context for drawing characters. */ Tk_Font tkfont; /* Font in which characters will be drawn; * must be the same as font used in GC. */ - CONST char *source; /* Characters to be displayed. Need not be + CONST char *source; /* UTF-8 string to be displayed. Need not be * '\0' terminated. All Tk meta-characters * (tabs, control characters, and newlines) * should be stripped out of the string that * is passed to this function. If they are * not stripped out, they will be displayed as * regular printing characters. */ - int numChars; /* Number of characters in string. */ + int numBytes; /* Number of bytes in string. */ int x, y; /* Coordinates at which to place origin of * string when drawing. */ { UnixFont *fontPtr; - CONST char *p; - int i, type; - char buf[4]; + SubFont *thisSubFontPtr, *lastSubFontPtr; + Tcl_DString runString; + CONST char *p, *end, *next; + int xStart, needWidth; + Tcl_UniChar ch; + FontFamily *familyPtr; fontPtr = (UnixFont *) tkfont; - - p = source; - for (i = 0; i < numChars; i++) { - type = fontPtr->types[UCHAR(*p)]; - if (type != NORMAL) { - DrawChars(display, drawable, gc, fontPtr, source, p - source, x, y); - x += XTextWidth(fontPtr->fontStructPtr, source, p - source); - if (type == REPLACE) { - DrawChars(display, drawable, gc, fontPtr, buf, - GetControlCharSubst(UCHAR(*p), buf), x, y); - x += fontPtr->widths[UCHAR(*p)]; + lastSubFontPtr = &fontPtr->subFontArray[0]; + + xStart = x; + + end = source + numBytes; + for (p = source; p < end; ) { + next = p + Tcl_UtfToUniChar(p, &ch); + thisSubFontPtr = FindSubFontForChar(fontPtr, ch); + if (thisSubFontPtr != lastSubFontPtr) { + if (p > source) { + familyPtr = lastSubFontPtr->familyPtr; + Tcl_UtfToExternalDString(familyPtr->encoding, source, + p - source, &runString); + if (familyPtr->isTwoByteFont) { + XDrawString16(display, drawable, gc, x, y, + (XChar2b *) Tcl_DStringValue(&runString), + Tcl_DStringLength(&runString) / 2); + + x += XTextWidth16(lastSubFontPtr->fontStructPtr, + (XChar2b *) Tcl_DStringValue(&runString), + Tcl_DStringLength(&runString) / 2); + } else { + XDrawString(display, drawable, gc, x, y, + Tcl_DStringValue(&runString), + Tcl_DStringLength(&runString)); + x += XTextWidth(lastSubFontPtr->fontStructPtr, + Tcl_DStringValue(&runString), + Tcl_DStringLength(&runString)); + } + Tcl_DStringFree(&runString); } - source = p + 1; + lastSubFontPtr = thisSubFontPtr; + source = p; + XSetFont(display, gc, lastSubFontPtr->fontStructPtr->fid); } - p++; + p = next; } - DrawChars(display, drawable, gc, fontPtr, source, p - source, x, y); -} - -static void -DrawChars(display, drawable, gc, fontPtr, source, numChars, x, y) - Display *display; /* Display on which to draw. */ - Drawable drawable; /* Window or pixmap in which to draw. */ - GC gc; /* Graphics context for drawing characters. */ - UnixFont *fontPtr; /* Font in which characters will be drawn; - * must be the same as font used in GC. */ - CONST char *source; /* Characters to be displayed. Need not be - * '\0' terminated. All Tk meta-characters - * (tabs, control characters, and newlines) - * should be stripped out of the string that - * is passed to this function. If they are - * not stripped out, they will be displayed as - * regular printing characters. */ - int numChars; /* Number of characters in string. */ - int x, y; /* Coordinates at which to place origin of - * string when drawing. */ -{ - /* - * Perform a quick sanity check to ensure we won't overflow the X - * coordinate space. - */ - - if ((x + (fontPtr->fontStructPtr->max_bounds.width * numChars) > 0x7fff)) { - int length; - - /* - * The string we are being asked to draw is too big and would overflow - * the X coordinate space. Unfortunatley X servers aren't too bright - * and so they won't deal with this case cleanly. We need to truncate - * the string before sending it to X. - */ - - numChars = Tk_MeasureChars((Tk_Font) fontPtr, source, numChars, - 0x7fff - x, 0, &length); + needWidth = fontPtr->font.fa.underline + fontPtr->font.fa.overstrike; + if (p > source) { + familyPtr = lastSubFontPtr->familyPtr; + Tcl_UtfToExternalDString(familyPtr->encoding, source, p - source, + &runString); + if (familyPtr->isTwoByteFont) { + XDrawString16(display, drawable, gc, x, y, + (XChar2b *) Tcl_DStringValue(&runString), + Tcl_DStringLength(&runString) >> 1); + if (needWidth) { + x += XTextWidth16(lastSubFontPtr->fontStructPtr, + (XChar2b *) Tcl_DStringValue(&runString), + Tcl_DStringLength(&runString) >> 1); + } + } else { + XDrawString(display, drawable, gc, x, y, + Tcl_DStringValue(&runString), + Tcl_DStringLength(&runString)); + if (needWidth) { + x += XTextWidth(lastSubFontPtr->fontStructPtr, + Tcl_DStringValue(&runString), + Tcl_DStringLength(&runString)); + } + } + Tcl_DStringFree(&runString); } - XDrawString(display, drawable, gc, x, y, source, numChars); + if (lastSubFontPtr != &fontPtr->subFontArray[0]) { + XSetFont(display, gc, fontPtr->subFontArray[0].fontStructPtr->fid); + } if (fontPtr->font.fa.underline != 0) { - XFillRectangle(display, drawable, gc, x, + XFillRectangle(display, drawable, gc, xStart, y + fontPtr->underlinePos, - (unsigned) XTextWidth(fontPtr->fontStructPtr, source, numChars), - (unsigned) fontPtr->barHeight); + (unsigned) (x - xStart), (unsigned) fontPtr->barHeight); } if (fontPtr->font.fa.overstrike != 0) { y -= fontPtr->font.fm.descent + (fontPtr->font.fm.ascent) / 10; - XFillRectangle(display, drawable, gc, x, y, - (unsigned) XTextWidth(fontPtr->fontStructPtr, source, numChars), - (unsigned) fontPtr->barHeight); + XFillRectangle(display, drawable, gc, xStart, y, + (unsigned) (x - xStart), (unsigned) fontPtr->barHeight); } } /* - *--------------------------------------------------------------------------- + *------------------------------------------------------------------------- * - * AllocFont -- + * CreateClosestFont -- * * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes(). - * Allocates and intializes the memory for a new TkFont that - * wraps the platform-specific data. + * Given a set of font attributes, construct a close XFontStruct. + * If requested face name is not available, automatically + * substitutes an alias for requested face name. If encoding is + * not specified (or the requested one is not available), + * automatically chooses another encoding from the list of + * preferred encodings. If the foundry is not specified (or + * is not available) automatically prefers "adobe" foundry. + * For all other attributes, if the requested value was not + * available, the appropriate "close" value will be used. * * Results: - * Returns pointer to newly constructed TkFont. - * - * The caller is responsible for initializing the fields of the - * TkFont that are used exclusively by the generic TkFont code, and - * for releasing those fields before calling TkpDeleteFont(). + * Return value is the XFontStruct that best matched the + * requested attributes. The return value is never NULL; some + * font will always be returned. * * Side effects: - * Memory allocated. + * None. * - *--------------------------------------------------------------------------- - */ + *------------------------------------------------------------------------- + */ -static UnixFont * -AllocFont(tkFontPtr, tkwin, fontStructPtr, fontName) - TkFont *tkFontPtr; /* If non-NULL, store the information in - * this existing TkFont structure, rather than - * allocating a new structure to hold the - * font; the existing contents of the font - * will be released. If NULL, a new TkFont - * structure is allocated. */ +static XFontStruct * +CreateClosestFont(tkwin, faPtr, xaPtr) Tk_Window tkwin; /* For display where font will be used. */ - XFontStruct *fontStructPtr; /* X information about font. */ - CONST char *fontName; /* The string passed to XLoadQueryFont() to - * construct the fontStructPtr. */ + CONST TkFontAttributes *faPtr; + /* Set of generic attributes to match. */ + CONST TkXLFDAttributes *xaPtr; + /* Set of X-specific attributes to match. */ { - UnixFont *fontPtr; - unsigned long value; - int i, width, firstChar, lastChar, n, replaceOK; - char *name, *p; - char buf[4]; - TkXLFDAttributes xa; - double d; - - if (tkFontPtr != NULL) { - fontPtr = (UnixFont *) tkFontPtr; - XFreeFont(fontPtr->display, fontPtr->fontStructPtr); - } else { - fontPtr = (UnixFont *) ckalloc(sizeof(UnixFont)); + FontAttributes want; + char **nameList; + int numNames, nameIdx; + Display *display; + XFontStruct *fontStructPtr; + int bestIdx[2]; + unsigned int bestScore[2]; + + want.fa = *faPtr; + want.xa = *xaPtr; + + if (want.xa.foundry == NULL) { + want.xa.foundry = Tk_GetUid("adobe"); + } + if (want.fa.family == NULL) { + want.fa.family = Tk_GetUid("fixed"); + } + want.fa.size = -TkFontGetPixels(tkwin, faPtr->size); + if (want.xa.charset == NULL || *want.xa.charset == '\0') { + want.xa.charset = Tk_GetUid("iso8859-1"); /* locale. */ } + display = Tk_Display(tkwin); + /* - * Encapsulate the generic stuff in the TkFont. + * Algorithm to get the closest font to the name requested. + * + * try fontname + * try all aliases for fontname + * foreach fallback for fontname + * try the fallback + * try all aliases for the fallback */ - fontPtr->font.fid = fontStructPtr->fid; - - if (XGetFontProperty(fontStructPtr, XA_FONT, &value) && (value != 0)) { - name = Tk_GetAtomName(tkwin, (Atom) value); - TkInitFontAttributes(&xa.fa); - if (TkParseXLFD(name, &xa) == TCL_OK) { - goto ok; + nameList = ListFontOrAlias(display, want.fa.family, &numNames); + if (numNames == 0) { + char ***fontFallbacks; + int i, j; + char *fallback; + + fontFallbacks = TkFontGetFallbacks(); + for (i = 0; fontFallbacks[i] != NULL; i++) { + for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) { + if (strcasecmp(want.fa.family, fallback) == 0) { + break; + } + } + if (fallback != NULL) { + for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) { + nameList = ListFontOrAlias(display, fallback, &numNames); + if (numNames != 0) { + goto found; + } + } + } + } + nameList = ListFonts(display, "fixed", &numNames); + if (numNames == 0) { + nameList = ListFonts(display, "*", &numNames); + } + if (numNames == 0) { + return GetSystemFont(display); } } - TkInitFontAttributes(&xa.fa); - if (TkParseXLFD(fontName, &xa) != TCL_OK) { - TkInitFontAttributes(&fontPtr->font.fa); - fontPtr->font.fa.family = Tk_GetUid(fontName); - } else { - ok: - fontPtr->font.fa = xa.fa; + found: + bestIdx[0] = -1; + bestIdx[1] = -1; + bestScore[0] = (unsigned int) -1; + bestScore[1] = (unsigned int) -1; + for (nameIdx = 0; nameIdx < numNames; nameIdx++) { + FontAttributes got; + int scalable; + unsigned int score; + + if (TkFontParseXLFD(nameList[nameIdx], &got.fa, &got.xa) != TCL_OK) { + continue; + } + IdentifySymbolEncodings(&got); + scalable = (got.fa.size == 0); + score = RankAttributes(&want, &got); + if (score <= bestScore[scalable]) { + bestIdx[scalable] = nameIdx; + bestScore[scalable] = score; + } + if (score == 0) { + break; + } } - if (fontPtr->font.fa.pointsize < 0) { - d = -fontPtr->font.fa.pointsize * 72 / 25.4; - d *= WidthMMOfScreen(Tk_Screen(tkwin)); - d /= WidthOfScreen(Tk_Screen(tkwin)); - d += 0.5; - fontPtr->font.fa.pointsize = (int) d; + fontStructPtr = GetScreenFont(display, &want, nameList, bestIdx, bestScore); + XFreeFontNames(nameList); + + if (fontStructPtr == NULL) { + return GetSystemFont(display); } - - fontPtr->font.fm.ascent = fontStructPtr->ascent; - fontPtr->font.fm.descent = fontStructPtr->descent; - fontPtr->font.fm.maxWidth = fontStructPtr->max_bounds.width; - fontPtr->font.fm.fixed = 1; - fontPtr->display = Tk_Display(tkwin); - fontPtr->fontStructPtr = fontStructPtr; + return fontStructPtr; +} + +/* + *--------------------------------------------------------------------------- + * + * InitFont -- + * + * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes(). + * Initializes the memory for a new UnixFont that wraps the + * platform-specific data. + * + * The caller is responsible for initializing the fields of the + * TkFont that are used exclusively by the generic TkFont code, and + * for releasing those fields before calling TkpDeleteFont(). + * + * Results: + * Fills the WinFont structure. + * + * Side effects: + * Memory allocated. + * + *--------------------------------------------------------------------------- + */ + +static void +InitFont(tkwin, fontStructPtr, fontPtr) + Tk_Window tkwin; /* For screen where font will be used. */ + XFontStruct *fontStructPtr; /* X information about font. */ + UnixFont *fontPtr; /* Filled with information constructed from + * the above arguments. */ +{ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + unsigned long value; + int minHi, maxHi, minLo, maxLo, fixed, width, limit, i, n; + FontAttributes fa; + TkFontAttributes *faPtr; + TkFontMetrics *fmPtr; + SubFont *controlPtr, *subFontPtr; + char *pageMap; + Display *display; /* - * Classify the characters. + * Get all font attributes and metrics. */ - - firstChar = fontStructPtr->min_char_or_byte2; - lastChar = fontStructPtr->max_char_or_byte2; - for (i = 0; i < 256; i++) { - if ((i == 0177) || (i < firstChar) || (i > lastChar)) { - fontPtr->types[i] = REPLACE; - } else { - fontPtr->types[i] = NORMAL; + + display = Tk_Display(tkwin); + GetFontAttributes(display, fontStructPtr, &fa); + + minHi = fontStructPtr->min_byte1; + maxHi = fontStructPtr->max_byte1; + minLo = fontStructPtr->min_char_or_byte2; + maxLo = fontStructPtr->max_char_or_byte2; + + fixed = 1; + if (fontStructPtr->per_char != NULL) { + width = 0; + limit = (maxHi - minHi + 1) * (maxLo - minLo + 1); + for (i = 0; i < limit; i++) { + n = fontStructPtr->per_char[i].width; + if (n != 0) { + if (width == 0) { + width = n; + } else if (width != n) { + fixed = 0; + break; + } + } } } - /* - * Compute the widths for all the normal characters. Any other - * characters are given an initial width of 0. Also, this determines - * if this is a fixed or variable width font, by comparing the widths - * of all the normal characters. - */ - - width = 0; + fontPtr->font.fid = fontStructPtr->fid; + + faPtr = &fontPtr->font.fa; + faPtr->family = fa.fa.family; + faPtr->size = TkFontGetPoints(tkwin, fa.fa.size); + faPtr->weight = fa.fa.weight; + faPtr->slant = fa.fa.slant; + faPtr->underline = 0; + faPtr->overstrike = 0; + + fmPtr = &fontPtr->font.fm; + fmPtr->ascent = fontStructPtr->ascent; + fmPtr->descent = fontStructPtr->descent; + fmPtr->maxWidth = fontStructPtr->max_bounds.width; + fmPtr->fixed = fixed; + + fontPtr->display = display; + fontPtr->pixelSize = TkFontGetPixels(tkwin, fa.fa.size); + fontPtr->xa = fa.xa; + + fontPtr->numSubFonts = 1; + fontPtr->subFontArray = fontPtr->staticSubFonts; + InitSubFont(display, fontStructPtr, 1, &fontPtr->subFontArray[0]); + + fontPtr->controlSubFont = fontPtr->subFontArray[0]; + subFontPtr = FindSubFontForChar(fontPtr, '0'); + controlPtr = &fontPtr->controlSubFont; + controlPtr->fontStructPtr = subFontPtr->fontStructPtr; + controlPtr->familyPtr = &tsdPtr->controlFamily; + controlPtr->fontMap = tsdPtr->controlFamily.fontMap; + + pageMap = fontPtr->subFontArray[0].fontMap[0]; for (i = 0; i < 256; i++) { - if (fontPtr->types[i] != NORMAL) { + if ((minHi > 0) || (i < minLo) || (i > maxLo) || + (((pageMap[i >> 3] >> (i & 7)) & 1) == 0)) { n = 0; } else if (fontStructPtr->per_char == NULL) { n = fontStructPtr->max_bounds.width; } else { - n = fontStructPtr->per_char[i - firstChar].width; + n = fontStructPtr->per_char[i - minLo].width; } fontPtr->widths[i] = n; - if (n != 0) { - if (width == 0) { - width = n; - } else if (width != n) { - fontPtr->font.fm.fixed = 0; - } - } - } - - /* - * Compute the widths of the characters that should be replaced with - * control character expansions. If the appropriate chars are not - * available in this font, then control character expansions will not - * be used; control chars will be invisible & zero-width. - */ - - replaceOK = 1; - for (p = hexChars; *p != '\0'; p++) { - if ((UCHAR(*p) < firstChar) || (UCHAR(*p) > lastChar)) { - replaceOK = 0; - break; - } - } - for (i = 0; i < 256; i++) { - if (fontPtr->types[i] == REPLACE) { - if (replaceOK) { - n = GetControlCharSubst(i, buf); - for ( ; --n >= 0; ) { - fontPtr->widths[i] += fontPtr->widths[UCHAR(buf[n])]; - } - } else { - fontPtr->types[i] = SKIP; - } - } } + if (XGetFontProperty(fontStructPtr, XA_UNDERLINE_POSITION, &value)) { fontPtr->underlinePos = value; @@ -953,9 +1264,6 @@ AllocFont(tkFontPtr, tkwin, fontStructPtr, fontName) } fontPtr->barHeight = 0; if (XGetFontProperty(fontStructPtr, XA_UNDERLINE_THICKNESS, &value)) { - /* - * Sometimes this is 0 even though it shouldn't be. - */ fontPtr->barHeight = value; } if (fontPtr->barHeight == 0) { @@ -984,23 +1292,627 @@ AllocFont(tkFontPtr, tkwin, fontStructPtr, fontName) fontPtr->barHeight = 1; } } +} + +/* + *------------------------------------------------------------------------- + * + * ReleaseFont -- + * + * Called to release the unix-specific contents of a TkFont. + * The caller is responsible for freeing the memory used by the + * font itself. + * + * Results: + * None. + * + * Side effects: + * Memory is freed. + * + *--------------------------------------------------------------------------- + */ + +static void +ReleaseFont(fontPtr) + UnixFont *fontPtr; /* The font to delete. */ +{ + int i; - return fontPtr; + for (i = 0; i < fontPtr->numSubFonts; i++) { + ReleaseSubFont(fontPtr->display, &fontPtr->subFontArray[i]); + } + if (fontPtr->subFontArray != fontPtr->staticSubFonts) { + ckfree((char *) fontPtr->subFontArray); + } } /* + *------------------------------------------------------------------------- + * + * InitSubFont -- + * + * Wrap a screen font and load the FontFamily that represents + * it. Used to prepare a SubFont so that characters can be mapped + * from UTF-8 to the charset of the font. + * + * Results: + * The subFontPtr is filled with information about the font. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------- + */ + +static void +InitSubFont(display, fontStructPtr, base, subFontPtr) + Display *display; /* Display in which font will be used. */ + XFontStruct *fontStructPtr; /* The screen font. */ + int base; /* Non-zero if this SubFont is being used + * as the base font for a font object. */ + SubFont *subFontPtr; /* Filled with SubFont constructed from + * above attributes. */ +{ + subFontPtr->fontStructPtr = fontStructPtr; + subFontPtr->familyPtr = AllocFontFamily(display, fontStructPtr, base); + subFontPtr->fontMap = subFontPtr->familyPtr->fontMap; +} + +/* + *------------------------------------------------------------------------- + * + * ReleaseSubFont -- + * + * Called to release the contents of a SubFont. The caller is + * responsible for freeing the memory used by the SubFont itself. + * + * Results: + * None. + * + * Side effects: + * Memory and resources are freed. + * *--------------------------------------------------------------------------- + */ + +static void +ReleaseSubFont(display, subFontPtr) + Display *display; /* Display which owns screen font. */ + SubFont *subFontPtr; /* The SubFont to delete. */ +{ + XFreeFont(display, subFontPtr->fontStructPtr); + FreeFontFamily(subFontPtr->familyPtr); +} + +/* + *------------------------------------------------------------------------- + * + * AllocFontFamily -- * - * GetControlCharSubst -- + * Find the FontFamily structure associated with the given font + * name. The information should be stored by the caller in a + * SubFont and used when determining if that SubFont supports a + * character. * - * When displaying text in a widget, a backslashed escape sequence - * is substituted for control characters that occur in the text. - * Given a control character, fill in a buffer with the replacement - * string that should be displayed. + * Cannot use the string name used to construct the font as the + * key, because the capitalization may not be canonical. Therefore + * use the face name actually retrieved from the font metrics as + * the key. * * Results: - * The return value is the length of the substitute string. buf is - * filled with the substitute string; it is not '\0' terminated. + * A pointer to a FontFamily. The reference count in the FontFamily + * is automatically incremented. When the SubFont is released, the + * reference count is decremented. When no SubFont is using this + * FontFamily, it may be deleted. + * + * Side effects: + * A new FontFamily structure will be allocated if this font family + * has not been seen. TrueType character existence metrics are + * loaded into the FontFamily structure. + * + *------------------------------------------------------------------------- + */ + +static FontFamily * +AllocFontFamily(display, fontStructPtr, base) + Display *display; /* Display in which font will be used. */ + XFontStruct *fontStructPtr; /* Screen font whose FontFamily is to be + * returned. */ + int base; /* Non-zero if this font family is to be + * used in the base font of a font object. */ +{ + FontFamily *familyPtr; + FontAttributes fa; + Tcl_Encoding encoding; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + GetFontAttributes(display, fontStructPtr, &fa); + encoding = Tcl_GetEncoding(NULL, GetEncodingAlias(fa.xa.charset)); + + familyPtr = tsdPtr->fontFamilyList; + for (; familyPtr != NULL; familyPtr = familyPtr->nextPtr) { + if ((familyPtr->faceName == fa.fa.family) + && (familyPtr->foundry == fa.xa.foundry) + && (familyPtr->encoding == encoding)) { + Tcl_FreeEncoding(encoding); + familyPtr->refCount++; + return familyPtr; + } + } + + familyPtr = (FontFamily *) ckalloc(sizeof(FontFamily)); + memset(familyPtr, 0, sizeof(FontFamily)); + familyPtr->nextPtr = tsdPtr->fontFamilyList; + tsdPtr->fontFamilyList = familyPtr; + + /* + * Set key for this FontFamily. + */ + + familyPtr->foundry = fa.xa.foundry; + familyPtr->faceName = fa.fa.family; + familyPtr->encoding = encoding; + + /* + * An initial refCount of 2 means that FontFamily information will + * persist even when the SubFont that loaded the FontFamily is released. + * Change it to 1 to cause FontFamilies to be unloaded when not in use. + */ + + familyPtr->refCount = 2; + familyPtr->isTwoByteFont = (fontStructPtr->min_byte1 > 0); + return familyPtr; +} + +/* + *------------------------------------------------------------------------- + * + * FreeFontFamily -- + * + * Called to free an FontFamily when the SubFont is finished using + * it. Frees the contents of the FontFamily and the memory used by + * the FontFamily itself. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------- + */ + +static void +FreeFontFamily(familyPtr) + FontFamily *familyPtr; /* The FontFamily to delete. */ +{ + FontFamily **familyPtrPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + int i; + + if (familyPtr == NULL) { + return; + } + familyPtr->refCount--; + if (familyPtr->refCount > 0) { + return; + } + Tcl_FreeEncoding(familyPtr->encoding); + for (i = 0; i < FONTMAP_PAGES; i++) { + if (familyPtr->fontMap[i] != NULL) { + ckfree(familyPtr->fontMap[i]); + } + } + + /* + * Delete from list. + */ + + for (familyPtrPtr = &tsdPtr->fontFamilyList; ; ) { + if (*familyPtrPtr == familyPtr) { + *familyPtrPtr = familyPtr->nextPtr; + break; + } + familyPtrPtr = &(*familyPtrPtr)->nextPtr; + } + + ckfree((char *) familyPtr); +} + +/* + *------------------------------------------------------------------------- + * + * FindSubFontForChar -- + * + * Determine which screen font is necessary to use to + * display the given character. If the font object does not have + * a screen font that can display the character, another screen font + * may be loaded into the font object, following a set of preferred + * fallback rules. + * + * Results: + * The return value is the SubFont to use to display the given + * character. + * + * Side effects: + * The contents of fontPtr are modified to cache the results + * of the lookup and remember any SubFonts that were dynamically + * loaded. + * + *------------------------------------------------------------------------- + */ + +static SubFont * +FindSubFontForChar(fontPtr, ch) + UnixFont *fontPtr; /* The font object with which the character + * will be displayed. */ + int ch; /* The Unicode character to be displayed. */ +{ + int i, j, k, numNames; + char *faceName, *fallback; + char **aliases, **nameList, **anyFallbacks; + char ***fontFallbacks; + SubFont *subFontPtr; + Tcl_DString ds; + + if (FontMapLookup(&fontPtr->subFontArray[0], ch)) { + return &fontPtr->subFontArray[0]; + } + + for (i = 1; i < fontPtr->numSubFonts; i++) { + if (FontMapLookup(&fontPtr->subFontArray[i], ch)) { + return &fontPtr->subFontArray[i]; + } + } + + if (FontMapLookup(&fontPtr->controlSubFont, ch)) { + return &fontPtr->controlSubFont; + } + + /* + * Keep track of all face names that we check, so we don't check some + * name multiple times if it can be reached by multiple paths. + */ + + Tcl_DStringInit(&ds); + + /* + * Are there any other fonts with the same face name as the base + * font that could display this character, e.g., if the base font + * is adobe:fixed:iso8859-1, we could might be able to use + * misc:fixed:iso8859-8 or sony:fixed:jisx0208.1983-0 + */ + + faceName = fontPtr->font.fa.family; + if (SeenName(faceName, &ds) == 0) { + subFontPtr = CanUseFallback(fontPtr, faceName, ch); + if (subFontPtr != NULL) { + goto end; + } + } + + aliases = TkFontGetAliasList(faceName); + + subFontPtr = NULL; + fontFallbacks = TkFontGetFallbacks(); + for (i = 0; fontFallbacks[i] != NULL; i++) { + for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) { + if (strcasecmp(fallback, faceName) == 0) { + /* + * If the base font has a fallback... + */ + + goto tryfallbacks; + } else if (aliases != NULL) { + /* + * Or if an alias for the base font has a fallback... + */ + + for (k = 0; aliases[k] != NULL; k++) { + if (strcasecmp(fallback, aliases[k]) == 0) { + goto tryfallbacks; + } + } + } + } + continue; + + tryfallbacks: + + /* + * ...then see if we can use one of the fallbacks, or an + * alias for one of the fallbacks. + */ + + for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) { + subFontPtr = CanUseFallbackWithAliases(fontPtr, fallback, ch, &ds); + if (subFontPtr != NULL) { + goto end; + } + } + } + + /* + * See if we can use something from the global fallback list. + */ + + anyFallbacks = TkFontGetGlobalClass(); + for (i = 0; (fallback = anyFallbacks[i]) != NULL; i++) { + subFontPtr = CanUseFallbackWithAliases(fontPtr, fallback, ch, &ds); + if (subFontPtr != NULL) { + goto end; + } + } + + /* + * Try all face names available in the whole system until we + * find one that can be used. + */ + + nameList = ListFonts(fontPtr->display, "*", &numNames); + for (i = 0; i < numNames; i++) { + fallback = strchr(nameList[i] + 1, '-') + 1; + strchr(fallback, '-')[0] = '\0'; + if (SeenName(fallback, &ds) == 0) { + subFontPtr = CanUseFallback(fontPtr, fallback, ch); + if (subFontPtr != NULL) { + XFreeFontNames(nameList); + goto end; + } + } + } + XFreeFontNames(nameList); + + end: + Tcl_DStringFree(&ds); + + if (subFontPtr == NULL) { + /* + * No font can display this character, so it will be displayed as a + * control character expansion. + */ + + subFontPtr = &fontPtr->controlSubFont; + FontMapInsert(subFontPtr, ch); + } + return subFontPtr; +} + +/* + *------------------------------------------------------------------------- + * + * FontMapLookup -- + * + * See if the screen font can display the given character. + * + * Results: + * The return value is 0 if the screen font cannot display the + * character, non-zero otherwise. + * + * Side effects: + * New pages are added to the font mapping cache whenever the + * character belongs to a page that hasn't been seen before. + * When a page is loaded, information about all the characters on + * that page is stored, not just for the single character in + * question. + * + *------------------------------------------------------------------------- + */ + +static int +FontMapLookup(subFontPtr, ch) + SubFont *subFontPtr; /* Contains font mapping cache to be queried + * and possibly updated. */ + int ch; /* Character to be tested. */ +{ + int row, bitOffset; + + row = ch >> FONTMAP_SHIFT; + if (subFontPtr->fontMap[row] == NULL) { + FontMapLoadPage(subFontPtr, row); + } + bitOffset = ch & (FONTMAP_BITSPERPAGE - 1); + return (subFontPtr->fontMap[row][bitOffset >> 3] >> (bitOffset & 7)) & 1; +} + +/* + *------------------------------------------------------------------------- + * + * FontMapInsert -- + * + * Tell the font mapping cache that the given screen font should be + * used to display the specified character. This is called when no + * font on the system can be be found that can display that + * character; we lie to the font and tell it that it can display + * the character, otherwise we would end up re-searching the entire + * fallback hierarchy every time that character was seen. + * + * Results: + * None. + * + * Side effects: + * New pages are added to the font mapping cache whenever the + * character belongs to a page that hasn't been seen before. + * When a page is loaded, information about all the characters on + * that page is stored, not just for the single character in + * question. + * + *------------------------------------------------------------------------- + */ + +static void +FontMapInsert(subFontPtr, ch) + SubFont *subFontPtr; /* Contains font mapping cache to be + * updated. */ + int ch; /* Character to be added to cache. */ +{ + int row, bitOffset; + + row = ch >> FONTMAP_SHIFT; + if (subFontPtr->fontMap[row] == NULL) { + FontMapLoadPage(subFontPtr, row); + } + bitOffset = ch & (FONTMAP_BITSPERPAGE - 1); + subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7); +} + +/* + *------------------------------------------------------------------------- + * + * FontMapLoadPage -- + * + * Load information about all the characters on a given page. + * This information consists of one bit per character that indicates + * whether the associated screen font can (1) or cannot (0) display + * the characters on the page. + * + * Results: + * None. + * + * Side effects: + * Mempry allocated. + * + *------------------------------------------------------------------------- + */ +static void +FontMapLoadPage(subFontPtr, row) + SubFont *subFontPtr; /* Contains font mapping cache to be + * updated. */ + int row; /* Index of the page to be loaded into + * the cache. */ +{ + char src[TCL_UTF_MAX], buf[16]; + int minHi, maxHi, minLo, maxLo, scale, checkLo; + int i, end, bitOffset, isTwoByteFont, n; + Tcl_Encoding encoding; + XFontStruct *fontStructPtr; + XCharStruct *widths; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + subFontPtr->fontMap[row] = (char *) ckalloc(FONTMAP_BITSPERPAGE / 8); + memset(subFontPtr->fontMap[row], 0, FONTMAP_BITSPERPAGE / 8); + + if (subFontPtr->familyPtr == &tsdPtr->controlFamily) { + return; + } + + fontStructPtr = subFontPtr->fontStructPtr; + encoding = subFontPtr->familyPtr->encoding; + isTwoByteFont = subFontPtr->familyPtr->isTwoByteFont; + + widths = fontStructPtr->per_char; + minHi = fontStructPtr->min_byte1; + maxHi = fontStructPtr->max_byte1; + minLo = fontStructPtr->min_char_or_byte2; + maxLo = fontStructPtr->max_char_or_byte2; + scale = maxLo - minLo + 1; + checkLo = minLo; + + if (! isTwoByteFont) { + if (minLo < 32) { + checkLo = 32; + } + } + + end = (row + 1) << FONTMAP_SHIFT; + for (i = row << FONTMAP_SHIFT; i < end; i++) { + int hi, lo; + + if (Tcl_UtfToExternal(NULL, encoding, src, Tcl_UniCharToUtf(i, src), + TCL_ENCODING_STOPONERROR, NULL, buf, sizeof(buf), NULL, + NULL, NULL) != TCL_OK) { + continue; + } + if (isTwoByteFont) { + hi = ((unsigned char *) buf)[0]; + lo = ((unsigned char *) buf)[1]; + } else { + hi = 0; + lo = ((unsigned char *) buf)[0]; + } + if ((hi < minHi) || (hi > maxHi) || (lo < checkLo) || (lo > maxLo)) { + continue; + } + n = (hi - minHi) * scale + lo - minLo; + if ((widths == NULL) || ((widths[n].width + widths[n].rbearing) != 0)) { + bitOffset = i & (FONTMAP_BITSPERPAGE - 1); + subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7); + } + } +} + +/* + *--------------------------------------------------------------------------- + * + * CanUseFallbackWithAliases -- + * + * Helper function for FindSubFontForChar. Determine if the + * specified face name (or an alias of the specified face name) + * can be used to construct a screen font that can display the + * given character. + * + * Results: + * See CanUseFallback(). + * + * Side effects: + * If the name and/or one of its aliases was rejected, the + * rejected string is recorded in nameTriedPtr so that it won't + * be tried again. + * + *--------------------------------------------------------------------------- + */ + +static SubFont * +CanUseFallbackWithAliases(fontPtr, faceName, ch, nameTriedPtr) + UnixFont *fontPtr; /* The font object that will own the new + * screen font. */ + char *faceName; /* Desired face name for new screen font. */ + int ch; /* The Unicode character that the new + * screen font must be able to display. */ + Tcl_DString *nameTriedPtr; /* Records face names that have already + * been tried. It is possible for the same + * face name to be queried multiple times when + * trying to find a suitable screen font. */ +{ + SubFont *subFontPtr; + char **aliases; + int i; + + if (SeenName(faceName, nameTriedPtr) == 0) { + subFontPtr = CanUseFallback(fontPtr, faceName, ch); + if (subFontPtr != NULL) { + return subFontPtr; + } + } + aliases = TkFontGetAliasList(faceName); + if (aliases != NULL) { + for (i = 0; aliases[i] != NULL; i++) { + if (SeenName(aliases[i], nameTriedPtr) == 0) { + subFontPtr = CanUseFallback(fontPtr, aliases[i], ch); + if (subFontPtr != NULL) { + return subFontPtr; + } + } + } + } + return NULL; +} + +/* + *--------------------------------------------------------------------------- + * + * SeenName -- + * + * Used to determine we have already tried and rejected the given + * face name when looking for a screen font that can support some + * Unicode character. + * + * Results: + * The return value is 0 if this face name has not already been seen, + * non-zero otherwise. * * Side effects: * None. @@ -1009,19 +1921,663 @@ AllocFont(tkFontPtr, tkwin, fontStructPtr, fontName) */ static int -GetControlCharSubst(c, buf) - int c; /* The control character to be replaced. */ - char buf[4]; /* Buffer that gets replacement string. It - * only needs to be 4 characters long. */ +SeenName(name, dsPtr) + CONST char *name; /* The name to check. */ + Tcl_DString *dsPtr; /* Contains names that have already been + * seen. */ +{ + CONST char *seen, *end; + + seen = Tcl_DStringValue(dsPtr); + end = seen + Tcl_DStringLength(dsPtr); + while (seen < end) { + if (strcasecmp(seen, name) == 0) { + return 1; + } + seen += strlen(seen) + 1; + } + Tcl_DStringAppend(dsPtr, (char *) name, (int) (strlen(name) + 1)); + return 0; +} + +/* + *------------------------------------------------------------------------- + * + * CanUseFallback -- + * + * If the specified screen font has not already been loaded + * into the font object, determine if the specified screen + * font can display the given character. + * + * Results: + * The return value is a pointer to a newly allocated SubFont, + * owned by the font object. This SubFont can be used to display + * the given character. The SubFont represents the screen font + * with the base set of font attributes from the font object, but + * using the specified face name. NULL is returned if the font + * object already holds a reference to the specified font or if + * the specified font doesn't exist or cannot display the given + * character. + * + * Side effects: + * The font object's subFontArray is updated to contain a reference + * to the newly allocated SubFont. + * + *------------------------------------------------------------------------- + */ + +static SubFont * +CanUseFallback(fontPtr, faceName, ch) + UnixFont *fontPtr; /* The font object that will own the new + * screen font. */ + char *faceName; /* Desired face name for new screen font. */ + int ch; /* The Unicode character that the new + * screen font must be able to display. */ { - buf[0] = '\\'; - if ((c < sizeof(mapChars)) && (mapChars[c] != 0)) { - buf[1] = mapChars[c]; - return 2; + int i, nameIdx, numNames, srcLen; + Tk_Uid hateFoundry; + int bestIdx[2]; + CONST char *charset, *hateCharset; + unsigned int bestScore[2]; + char **nameList, **nameListOrig; + FontAttributes want, got; + char src[TCL_UTF_MAX]; + Display *display; + SubFont subFont; + XFontStruct *fontStructPtr; + Tcl_DString dsEncodings; + int numEncodings; + Tcl_Encoding *encodingCachePtr; + + /* + * Assume: the face name is times. + * Assume: adobe:times:iso8859-1 has already been used. + * + * Are there any versions of times that can display this + * character (e.g., perhaps linotype:times:iso8859-2)? + * a. Get list of all times fonts. + * b1. Cross out all names whose encodings we've already used. + * b2. Cross out all names whose foundry & encoding we've already seen. + * c. Cross out all names whose encoding cannot handle the character. + * d. Rank each name and pick the best match. + * e. If that font cannot actually display the character, cross + * out all names with the same foundry and encoding and go + * back to (c). + */ + + display = fontPtr->display; + nameList = ListFonts(display, faceName, &numNames); + if (numNames == 0) { + return NULL; + } + nameListOrig = nameList; + + srcLen = Tcl_UniCharToUtf(ch, src); + + want.fa = fontPtr->font.fa; + want.xa = fontPtr->xa; + + want.fa.family = Tk_GetUid(faceName); + want.fa.size = -fontPtr->pixelSize; + + hateFoundry = NULL; + hateCharset = NULL; + numEncodings = 0; + Tcl_DStringInit(&dsEncodings); + + charset = NULL; /* lint, since numNames must be > 0 to get here. */ + + retry: + bestIdx[0] = -1; + bestIdx[1] = -1; + bestScore[0] = (unsigned int) -1; + bestScore[1] = (unsigned int) -1; + for (nameIdx = 0; nameIdx < numNames; nameIdx++) { + Tcl_Encoding encoding; + char dst[16]; + int scalable, srcRead, dstWrote; + unsigned int score; + + if (nameList[nameIdx] == NULL) { + continue; + } + if (TkFontParseXLFD(nameList[nameIdx], &got.fa, &got.xa) != TCL_OK) { + goto crossout; + } + IdentifySymbolEncodings(&got); + charset = GetEncodingAlias(got.xa.charset); + if (hateFoundry != NULL) { + /* + * E. If the font we picked cannot actually display the + * character, cross out all names with the same foundry and + * encoding. + */ + + if ((hateFoundry == got.xa.foundry) + && (strcmp(hateCharset, charset) == 0)) { + goto crossout; + } + } else { + /* + * B. Cross out all names whose encodings we've already used. + */ + + for (i = 0; i < fontPtr->numSubFonts; i++) { + encoding = fontPtr->subFontArray[i].familyPtr->encoding; + if (strcmp(charset, Tcl_GetEncodingName(encoding)) == 0) { + goto crossout; + } + } + } + + /* + * C. Cross out all names whose encoding cannot handle the character. + */ + + encodingCachePtr = (Tcl_Encoding *) Tcl_DStringValue(&dsEncodings); + for (i = numEncodings; --i >= 0; encodingCachePtr++) { + encoding = *encodingCachePtr; + if (strcmp(Tcl_GetEncodingName(encoding), charset) == 0) { + break; + } + } + if (i < 0) { + encoding = Tcl_GetEncoding(NULL, charset); + if (encoding == NULL) { + goto crossout; + } + + Tcl_DStringAppend(&dsEncodings, (char *) &encoding, + sizeof(encoding)); + numEncodings++; + } + Tcl_UtfToExternal(NULL, encoding, src, srcLen, + TCL_ENCODING_STOPONERROR, NULL, dst, sizeof(dst), &srcRead, + &dstWrote, NULL); + if (dstWrote == 0) { + goto crossout; + } + + /* + * D. Rank each name and pick the best match. + */ + + scalable = (got.fa.size == 0); + score = RankAttributes(&want, &got); + if (score <= bestScore[scalable]) { + bestIdx[scalable] = nameIdx; + bestScore[scalable] = score; + } + if (score == 0) { + break; + } + continue; + + crossout: + if (nameList == nameListOrig) { + /* + * Not allowed to change pointers to memory that X gives you, + * so make a copy. + */ + + nameList = (char **) ckalloc(numNames * sizeof(char *)); + memcpy(nameList, nameListOrig, numNames * sizeof(char *)); + } + nameList[nameIdx] = NULL; + } + + fontStructPtr = GetScreenFont(display, &want, nameList, bestIdx, bestScore); + + encodingCachePtr = (Tcl_Encoding *) Tcl_DStringValue(&dsEncodings); + for (i = numEncodings; --i >= 0; encodingCachePtr++) { + Tcl_FreeEncoding(*encodingCachePtr); + } + Tcl_DStringFree(&dsEncodings); + numEncodings = 0; + + if (fontStructPtr == NULL) { + if (nameList != nameListOrig) { + ckfree((char *) nameList); + } + XFreeFontNames(nameListOrig); + return NULL; + } + + InitSubFont(display, fontStructPtr, 0, &subFont); + if (FontMapLookup(&subFont, ch) == 0) { + /* + * E. If the font we picked cannot actually display the character, + * cross out all names with the same foundry and encoding and pick + * another font. + */ + + hateFoundry = got.xa.foundry; + hateCharset = charset; + ReleaseSubFont(display, &subFont); + goto retry; + } + if (nameList != nameListOrig) { + ckfree((char *) nameList); + } + XFreeFontNames(nameListOrig); + + if (fontPtr->numSubFonts >= SUBFONT_SPACE) { + SubFont *newPtr; + + newPtr = (SubFont *) ckalloc(sizeof(SubFont) * (fontPtr->numSubFonts + 1)); + memcpy((char *) newPtr, fontPtr->subFontArray, + fontPtr->numSubFonts * sizeof(SubFont)); + if (fontPtr->subFontArray != fontPtr->staticSubFonts) { + ckfree((char *) fontPtr->subFontArray); + } + fontPtr->subFontArray = newPtr; + } + fontPtr->subFontArray[fontPtr->numSubFonts] = subFont; + fontPtr->numSubFonts++; + return &fontPtr->subFontArray[fontPtr->numSubFonts - 1]; +} + +/* + *--------------------------------------------------------------------------- + * + * RankAttributes -- + * + * Determine how close the attributes of the font in question match + * the attributes that we want. + * + * Results: + * The return value is the score; lower numbers are better. + * *scalablePtr is set to 0 if the font was not scalable, 1 otherwise. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +static unsigned int +RankAttributes(wantPtr, gotPtr) + FontAttributes *wantPtr; /* The desired attributes. */ + FontAttributes *gotPtr; /* The attributes we have to live with. */ +{ + unsigned int penalty; + + penalty = 0; + if (gotPtr->xa.foundry != wantPtr->xa.foundry) { + penalty += 4500; + } + if (gotPtr->fa.family != wantPtr->fa.family) { + penalty += 9000; + } + if (gotPtr->fa.weight != wantPtr->fa.weight) { + penalty += 90; + } + if (gotPtr->fa.slant != wantPtr->fa.slant) { + penalty += 60; + } + if (gotPtr->xa.slant != wantPtr->xa.slant) { + penalty += 10; + } + if (gotPtr->xa.setwidth != wantPtr->xa.setwidth) { + penalty += 1000; + } + + if (gotPtr->fa.size == 0) { + /* + * A scalable font is almost always acceptable, but the + * corresponding bitmapped font would be better. + */ + + penalty += 10; } else { - buf[1] = 'x'; - buf[2] = hexChars[(c >> 4) & 0xf]; - buf[3] = hexChars[c & 0xf]; - return 4; + int diff; + + /* + * It's worse to be too large than to be too small. + */ + + diff = (-gotPtr->fa.size - -wantPtr->fa.size); + if (diff > 0) { + penalty += 600; + } else if (diff < 0) { + penalty += 150; + diff = -diff; + } + penalty += 150 * diff; } + if (gotPtr->xa.charset != wantPtr->xa.charset) { + int i; + CONST char *gotAlias, *wantAlias; + + penalty += 65000; + gotAlias = GetEncodingAlias(gotPtr->xa.charset); + wantAlias = GetEncodingAlias(wantPtr->xa.charset); + if (strcmp(gotAlias, wantAlias) != 0) { + penalty += 30000; + for (i = 0; encodingList[i] != NULL; i++) { + if (strcmp(gotAlias, encodingList[i]) == 0) { + penalty -= 30000; + break; + } + penalty += 20000; + } + } + } + return penalty; } + +/* + *--------------------------------------------------------------------------- + * + * GetScreenFont -- + * + * Given the names for the best scalable and best bitmapped font, + * actually construct an XFontStruct based on the best XLFD. + * This is where all the alias and fallback substitution bottoms + * out. + * + * Results: + * The screen font that best corresponds to the set of attributes. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +static XFontStruct * +GetScreenFont(display, wantPtr, nameList, bestIdx, bestScore) + Display *display; /* Display for new XFontStruct. */ + FontAttributes *wantPtr; /* Contains desired actual pixel-size if the + * best font was scalable. */ + char **nameList; /* Array of XLFDs. */ + int bestIdx[2]; /* Indices into above array for XLFD of + * best bitmapped and best scalable font. */ + unsigned int bestScore[2]; /* Scores of best bitmapped and best + * scalable font. XLFD corresponding to + * lowest score will be constructed. */ +{ + XFontStruct *fontStructPtr; + + if ((bestIdx[0] < 0) && (bestIdx[1] < 0)) { + return NULL; + } + + /* + * Now we know which is the closest matching scalable font and the + * closest matching bitmapped font. If the scalable font was a + * better match, try getting the scalable font; however, if the + * scalable font was not actually available in the desired + * pointsize, fall back to the closest bitmapped font. + */ + + fontStructPtr = NULL; + if (bestScore[1] < bestScore[0]) { + char *str, *rest; + char buf[256]; + int i; + + /* + * Fill in the desired pixel size for this font. + */ + + tryscale: + str = nameList[bestIdx[1]]; + for (i = 0; i < XLFD_PIXEL_SIZE; i++) { + str = strchr(str + 1, '-'); + } + rest = str; + for (i = XLFD_PIXEL_SIZE; i < XLFD_CHARSET; i++) { + rest = strchr(rest + 1, '-'); + } + *str = '\0'; + sprintf(buf, "%.200s-%d-*-*-*-*-*%s", nameList[bestIdx[1]], + -wantPtr->fa.size, rest); + *str = '-'; + fontStructPtr = XLoadQueryFont(display, buf); + bestScore[1] = INT_MAX; + } + if (fontStructPtr == NULL) { + fontStructPtr = XLoadQueryFont(display, nameList[bestIdx[0]]); + if (fontStructPtr == NULL) { + /* + * This shouldn't happen because the font name is one of the + * names that X gave us to use, but it does anyhow. + */ + + if (bestScore[1] < INT_MAX) { + goto tryscale; + } + return GetSystemFont(display); + } + } + return fontStructPtr; +} + +/* + *--------------------------------------------------------------------------- + * + * GetSystemFont -- + * + * Absolute fallback mechanism, called when we need a font and no + * other font can be found and/or instantiated. + * + * Results: + * A pointer to a font. Never NULL. + * + * Side effects: + * If there are NO fonts installed on the system, this call will + * panic, but how did you get X running in that case? + * + *--------------------------------------------------------------------------- + */ + +static XFontStruct * +GetSystemFont(display) + Display *display; /* Display for new XFontStruct. */ +{ + XFontStruct *fontStructPtr; + + fontStructPtr = XLoadQueryFont(display, "fixed"); + if (fontStructPtr == NULL) { + fontStructPtr = XLoadQueryFont(display, "*"); + if (fontStructPtr == NULL) { + panic("TkpGetFontFromAttributes: cannot get any font"); + } + } + return fontStructPtr; +} + +/* + *--------------------------------------------------------------------------- + * + * GetFontAttributes -- + * + * Given a screen font, determine its actual attributes, which are + * not necessarily the attributes that were used to construct it. + * + * Results: + * *faPtr is filled with the screen font's attributes. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +static int +GetFontAttributes(display, fontStructPtr, faPtr) + Display *display; /* Display that owns the screen font. */ + XFontStruct *fontStructPtr; /* Screen font to query. */ + FontAttributes *faPtr; /* For storing attributes of screen font. */ +{ + unsigned long value; + char *p, *name; + + if ((XGetFontProperty(fontStructPtr, XA_FONT, &value) != False) && + (value != 0)) { + name = XGetAtomName(display, (Atom) value); + for (p = name; *p != '\0'; p++) { + if (isupper(UCHAR(*p))) { /* INTL: native text */ + *p = tolower(UCHAR(*p)); /* INTL: native text */ + } + } + if (TkFontParseXLFD(name, &faPtr->fa, &faPtr->xa) != TCL_OK) { + faPtr->fa.family = Tk_GetUid(name); + faPtr->xa.foundry = Tk_GetUid(""); + faPtr->xa.charset = Tk_GetUid(""); + } + XFree(name); + } else { + TkInitFontAttributes(&faPtr->fa); + TkInitXLFDAttributes(&faPtr->xa); + faPtr->fa.family = Tk_GetUid(""); + faPtr->xa.foundry = Tk_GetUid(""); + faPtr->xa.charset = Tk_GetUid(""); + } + return IdentifySymbolEncodings(faPtr); +} + +/* + *--------------------------------------------------------------------------- + * + * ListFonts -- + * + * Utility function to return the array of all XLFDs on the system + * with the specified face name. + * + * Results: + * The return value is an array of XLFDs, which should be freed with + * XFreeFontNames(), or NULL if no XLFDs matched the requested name. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +static char ** +ListFonts(display, faceName, numNamesPtr) + Display *display; /* Display to query. */ + CONST char *faceName; /* Desired face name, or "*" for all. */ + int *numNamesPtr; /* Filled with length of returned array, or + * 0 if no names were found. */ +{ + char buf[256]; + + sprintf(buf, "-*-%.80s-*-*-*-*-*-*-*-*-*-*-*-*", faceName); + return XListFonts(display, buf, 10000, numNamesPtr); +} + +static char ** +ListFontOrAlias(display, faceName, numNamesPtr) + Display *display; /* Display to query. */ + CONST char *faceName; /* Desired face name, or "*" for all. */ + int *numNamesPtr; /* Filled with length of returned array, or + * 0 if no names were found. */ +{ + char **nameList, **aliases; + int i; + + nameList = ListFonts(display, faceName, numNamesPtr); + if (nameList != NULL) { + return nameList; + } + aliases = TkFontGetAliasList(faceName); + if (aliases != NULL) { + for (i = 0; aliases[i] != NULL; i++) { + nameList = ListFonts(display, aliases[i], numNamesPtr); + if (nameList != NULL) { + return nameList; + } + } + } + *numNamesPtr = 0; + return NULL; +} + +/* + *--------------------------------------------------------------------------- + * + * IdentifySymbolEncodings -- + * + * If the font attributes refer to a symbol font, update the + * charset field of the font attributes so that it reflects the + * encoding of that symbol font. In general, the raw value for + * the charset field parsed from an XLFD is meaningless for symbol + * fonts. + * + * Symbol fonts are all fonts whose name appears in the symbolClass. + * + * Results: + * The return value is non-zero if the font attributes specify a + * symbol font, or 0 otherwise. If a non-zero value is returned + * the charset field of the font attributes will be changed to + * the string that represents the actual encoding for the symbol font. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +static int +IdentifySymbolEncodings(faPtr) + FontAttributes *faPtr; +{ + int i, j; + char **aliases, **symbolClass; + + symbolClass = TkFontGetSymbolClass(); + for (i = 0; symbolClass[i] != NULL; i++) { + if (strcasecmp(faPtr->fa.family, symbolClass[i]) == 0) { + faPtr->xa.charset = Tk_GetUid(GetEncodingAlias(symbolClass[i])); + return 1; + } + aliases = TkFontGetAliasList(symbolClass[i]); + for (j = 0; (aliases != NULL) && (aliases[j] != NULL); j++) { + if (strcasecmp(faPtr->fa.family, aliases[j]) == 0) { + faPtr->xa.charset = Tk_GetUid(GetEncodingAlias(aliases[j])); + return 1; + } + } + } + return 0; +} + +/* + *--------------------------------------------------------------------------- + * + * GetEncodingAlias -- + * + * Map the name of an encoding to another name that should be used + * when actually loading the encoding. For instance, the encodings + * "jisc6226.1978", "jisx0208.1983", "jisx0208.1990", and + * "jisx0208.1996" are well-known names for the same encoding and + * are represented by one encoding table: "jis0208". + * + * Results: + * As above. If the name has no alias, the original name is returned. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +static CONST char * +GetEncodingAlias(name) + CONST char *name; /* The name to look up. */ +{ + EncodingAlias *aliasPtr; + + for (aliasPtr = encodingAliases; aliasPtr->aliasPattern != NULL; ) { + if (Tcl_StringMatch((char *) name, aliasPtr->aliasPattern)) { + return aliasPtr->realName; + } + aliasPtr++; + } + return name; +} + + diff --git a/unix/tkUnixInit.c b/unix/tkUnixInit.c index 158a2f6..5aa68ef 100644 --- a/unix/tkUnixInit.c +++ b/unix/tkUnixInit.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixInit.c,v 1.3 1998/09/14 18:23:57 stanton Exp $ + * RCS: @(#) $Id: tkUnixInit.c,v 1.4 1999/04/16 01:51:46 stanton Exp $ */ #include "tkInt.h" @@ -32,7 +32,7 @@ * * Results: * Returns a standard Tcl result. Leaves an error message or result - * in interp->result. + * in the interp's result. * * Side effects: * Sets "tk_library" Tcl variable, runs "tk.tcl" script. @@ -109,9 +109,9 @@ TkpDisplayWarning(msg, title) { Tcl_Channel errChannel = Tcl_GetStdChannel(TCL_STDERR); if (errChannel) { - Tcl_Write(errChannel, title, -1); - Tcl_Write(errChannel, ": ", 2); - Tcl_Write(errChannel, msg, -1); - Tcl_Write(errChannel, "\n", 1); + Tcl_WriteChars(errChannel, title, -1); + Tcl_WriteChars(errChannel, ": ", 2); + Tcl_WriteChars(errChannel, msg, -1); + Tcl_WriteChars(errChannel, "\n", 1); } } diff --git a/unix/tkUnixInt.h b/unix/tkUnixInt.h index ade08ff..4a99d47 100644 --- a/unix/tkUnixInt.h +++ b/unix/tkUnixInt.h @@ -10,17 +10,20 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixInt.h,v 1.3 1999/03/10 07:04:46 stanton Exp $ + * RCS: @(#) $Id: tkUnixInt.h,v 1.4 1999/04/16 01:51:46 stanton Exp $ */ #ifndef _TKUNIXINT #define _TKUNIXINT +#ifndef _TKINT +#include "tkInt.h" +#endif + /* * Prototypes for procedures that are referenced in files other * than the ones they're defined in. */ - #include "tkIntPlatDecls.h" #endif /* _TKUNIXINT */ diff --git a/unix/tkUnixKey.c b/unix/tkUnixKey.c new file mode 100644 index 0000000..64b2218 --- /dev/null +++ b/unix/tkUnixKey.c @@ -0,0 +1,90 @@ +/* + * tkUnixKey.c -- + * + * This file contains routines for dealing with international keyboard + * input. + * + * Copyright (c) 1997 by Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkUnixKey.c,v 1.2 1999/04/16 01:51:46 stanton Exp $ + */ + +#include "tkInt.h" + + +/* + *---------------------------------------------------------------------- + * + * TkpGetString -- + * + * Retrieve the UTF string associated with a keyboard event. + * + * Results: + * Returns the UTF string. + * + * Side effects: + * Stores the input string in the specified Tcl_DString. Modifies + * the internal input state. This routine can only be called + * once for a given event. + * + *---------------------------------------------------------------------- + */ + +char * +TkpGetString(winPtr, eventPtr, dsPtr) + TkWindow *winPtr; /* Window where event occurred: needed to + * get input context. */ + XEvent *eventPtr; /* X keyboard event. */ + Tcl_DString *dsPtr; /* Uninitialized or empty string to hold + * result. */ +{ + int len; + Tcl_DString buf; + Status status; + + /* + * Overallocate the dstring to the maximum stack amount. + */ + + Tcl_DStringInit(&buf); + Tcl_DStringSetLength(&buf, TCL_DSTRING_STATIC_SIZE-1); + +#ifdef TK_USE_INPUT_METHODS + if ((winPtr->inputContext != NULL) + && (eventPtr->type == KeyPress)) { + len = XmbLookupString(winPtr->inputContext, &eventPtr->xkey, + Tcl_DStringValue(&buf), Tcl_DStringLength(&buf), + (KeySym *) NULL, &status); + /* + * If the buffer wasn't big enough, grow the buffer and try again. + */ + + if (status == XBufferOverflow) { + Tcl_DStringSetLength(&buf, len); + len = XmbLookupString(winPtr->inputContext, &eventPtr->xkey, + Tcl_DStringValue(&buf), len, (KeySym *) NULL, &status); + } + if ((status != XLookupChars) + && (status != XLookupBoth)) { + len = 0; + } + } else { + len = XLookupString(&eventPtr->xkey, Tcl_DStringValue(&buf), + Tcl_DStringLength(&buf), (KeySym *) NULL, + (XComposeStatus *) NULL); + } +#else /* TK_USE_INPUT_METHODS */ + len = XLookupString(&eventPtr->xkey, Tcl_DStringValue(&buf), + Tcl_DStringLength(&buf), (KeySym *) NULL, + (XComposeStatus *) NULL); +#endif /* TK_USE_INPUT_METHODS */ + Tcl_DStringSetLength(&buf, len); + + Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&buf), len, dsPtr); + Tcl_DStringFree(&buf); + + return Tcl_DStringValue(dsPtr); +} diff --git a/unix/tkUnixMenu.c b/unix/tkUnixMenu.c index 0867844..1a499cc 100644 --- a/unix/tkUnixMenu.c +++ b/unix/tkUnixMenu.c @@ -3,12 +3,12 @@ * * This module implements the UNIX platform-specific features of menus. * - * Copyright (c) 1996-1997 by Sun Microsystems, Inc. + * Copyright (c) 1996-1998 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixMenu.c,v 1.2 1998/09/14 18:23:57 stanton Exp $ + * RCS: @(#) $Id: tkUnixMenu.c,v 1.3 1999/04/16 01:51:46 stanton Exp $ */ #include "tkPort.h" @@ -178,7 +178,7 @@ TkpDestroyMenuEntry(mEntryPtr) * * Results: * Returns standard TCL result. If TCL_ERROR is returned, then - * interp->result contains an error message. + * the interp's result contains an error message. * * Side effects: * Configuration information get set for mePtr; old resources @@ -198,11 +198,11 @@ TkpConfigureMenuEntry(mePtr) * see if the child menu is a help menu. */ - if ((mePtr->type == CASCADE_ENTRY) && (mePtr->name != NULL)) { + if ((mePtr->type == CASCADE_ENTRY) && (mePtr->namePtr != NULL)) { TkMenuReferences *menuRefPtr; - menuRefPtr = TkFindMenuReferences(mePtr->menuPtr->interp, - mePtr->name); + menuRefPtr = TkFindMenuReferencesObj(mePtr->menuPtr->interp, + mePtr->namePtr); if ((menuRefPtr != NULL) && (menuRefPtr->menuPtr != NULL)) { SetHelpMenu(menuRefPtr->menuPtr); } @@ -321,32 +321,46 @@ GetMenuIndicatorGeometry(menuPtr, mePtr, tkfont, fmPtr, widthPtr, heightPtr) int *widthPtr; /* The resulting width */ int *heightPtr; /* The resulting height */ { - if (!mePtr->hideMargin && mePtr->indicatorOn && - ((mePtr->type == CHECK_BUTTON_ENTRY) - || (mePtr->type == RADIO_BUTTON_ENTRY))) { - if ((mePtr->image != NULL) || (mePtr->bitmap != None)) { - *widthPtr = (14 * mePtr->height) / 10; - *heightPtr = mePtr->height; - if (mePtr->type == CHECK_BUTTON_ENTRY) { - mePtr->platformEntryData = - (TkMenuPlatformEntryData) ((65 * mePtr->height) / 100); + if ((mePtr->type == CHECK_BUTTON_ENTRY) + || (mePtr->type == RADIO_BUTTON_ENTRY)) { + if (!mePtr->hideMargin && mePtr->indicatorOn) { + if ((mePtr->image != NULL) || (mePtr->bitmapPtr != NULL)) { + *widthPtr = (14 * mePtr->height) / 10; + *heightPtr = mePtr->height; + if (mePtr->type == CHECK_BUTTON_ENTRY) { + mePtr->platformEntryData = + (TkMenuPlatformEntryData) ((65 * mePtr->height) + / 100); + } else { + mePtr->platformEntryData = + (TkMenuPlatformEntryData) ((75 * mePtr->height) + / 100); + } } else { - mePtr->platformEntryData = - (TkMenuPlatformEntryData) ((75 * mePtr->height) / 100); - } - } else { - *widthPtr = *heightPtr = mePtr->height; - if (mePtr->type == CHECK_BUTTON_ENTRY) { - mePtr->platformEntryData = (TkMenuPlatformEntryData) + *widthPtr = *heightPtr = mePtr->height; + if (mePtr->type == CHECK_BUTTON_ENTRY) { + mePtr->platformEntryData = (TkMenuPlatformEntryData) ((80 * mePtr->height) / 100); - } else { - mePtr->platformEntryData = (TkMenuPlatformEntryData) + } else { + mePtr->platformEntryData = (TkMenuPlatformEntryData) mePtr->height; + } } + } else { + int borderWidth; + + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, + menuPtr->borderWidthPtr, &borderWidth); + *heightPtr = 0; + *widthPtr = borderWidth; } } else { + int borderWidth; + + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr, + &borderWidth); *heightPtr = 0; - *widthPtr = menuPtr->borderWidth; + *widthPtr = borderWidth; } } @@ -379,8 +393,11 @@ GetMenuAccelGeometry(menuPtr, mePtr, tkfont, fmPtr, widthPtr, heightPtr) *heightPtr = fmPtr->linespace; if (mePtr->type == CASCADE_ENTRY) { *widthPtr = 2 * CASCADE_ARROW_WIDTH; - } else if ((menuPtr->menuType != MENUBAR) && (mePtr->accel != NULL)) { - *widthPtr = Tk_TextWidth(tkfont, mePtr->accel, mePtr->accelLength); + } else if ((menuPtr->menuType != MENUBAR) + && (mePtr->accelPtr != NULL)) { + char *accel = Tcl_GetStringFromObj(mePtr->accelPtr, NULL); + + *widthPtr = Tk_TextWidth(tkfont, accel, mePtr->accelLength); } else { *widthPtr = 0; } @@ -416,8 +433,10 @@ DrawMenuEntryBackground(menuPtr, mePtr, d, activeBorder, bgBorder, x, y, int width; /* Width of entry rect */ int height; /* Height of entry rect */ { - if (mePtr->state == tkActiveUid) { + if (mePtr->state == ENTRY_ACTIVE) { int relief; + int activeBorderWidth; + bgBorder = activeBorder; if ((menuPtr->menuType == MENUBAR) @@ -427,9 +446,11 @@ DrawMenuEntryBackground(menuPtr, mePtr, d, activeBorder, bgBorder, x, y, } else { relief = TK_RELIEF_RAISED; } - + + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, + menuPtr->activeBorderWidthPtr, &activeBorderWidth); Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder, x, y, width, height, - menuPtr->activeBorderWidth, relief); + activeBorderWidth, relief); } else { Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder, x, y, width, height, 0, TK_RELIEF_FLAT); @@ -470,6 +491,7 @@ DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr, activeBorder, int drawArrow; /* Whether or not to draw arrow. */ { XPoint points[3]; + int borderWidth, activeBorderWidth; /* * Draw accelerator or cascade arrow. @@ -479,9 +501,13 @@ DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr, activeBorder, return; } + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr, + &borderWidth); + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr, + &activeBorderWidth); if ((mePtr->type == CASCADE_ENTRY) && drawArrow) { - points[0].x = x + width - menuPtr->borderWidth - - menuPtr->activeBorderWidth - CASCADE_ARROW_WIDTH; + points[0].x = x + width - borderWidth - activeBorderWidth + - CASCADE_ARROW_WIDTH; points[0].y = y + (height - CASCADE_ARROW_HEIGHT)/2; points[1].x = points[0].x; points[1].y = points[0].y + CASCADE_ARROW_HEIGHT; @@ -491,13 +517,15 @@ DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr, activeBorder, DECORATION_BORDER_WIDTH, (menuPtr->postedCascade == mePtr) ? TK_RELIEF_SUNKEN : TK_RELIEF_RAISED); - } else if (mePtr->accel != NULL) { - int left = x + mePtr->labelWidth + menuPtr->activeBorderWidth + } else if (mePtr->accelPtr != NULL) { + char *accel = Tcl_GetStringFromObj(mePtr->accelPtr, NULL); + int left = x + mePtr->labelWidth + activeBorderWidth + mePtr->indicatorSpace; + if (menuPtr->menuType == MENUBAR) { left += 5; } - Tk_DrawChars(menuPtr->display, d, gc, tkfont, mePtr->accel, + Tk_DrawChars(menuPtr->display, d, gc, tkfont, accel, mePtr->accelLength, left, (y + (height + fmPtr->ascent - fmPtr->descent) / 2)); } @@ -535,62 +563,67 @@ DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont, fmPtr, int width; /* Width of menu entry */ int height; /* Height of menu entry */ { - /* * Draw check-button indicator. */ - if ((mePtr->type == CHECK_BUTTON_ENTRY) - && mePtr->indicatorOn) { - int dim, top, left; + if ((mePtr->type == CHECK_BUTTON_ENTRY) && mePtr->indicatorOn) { + int dim, top, left; + int activeBorderWidth; + Tk_3DBorder border; dim = (int) mePtr->platformEntryData; - left = x + menuPtr->activeBorderWidth - + (mePtr->indicatorSpace - dim)/2; + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, + menuPtr->activeBorderWidthPtr, &activeBorderWidth); + left = x + activeBorderWidth + (mePtr->indicatorSpace - dim)/2; if (menuPtr->menuType == MENUBAR) { left += 5; } - top = y + (height - dim)/2; - Tk_Fill3DRectangle(menuPtr->tkwin, d, menuPtr->border, left, top, dim, + top = y + (height - dim)/2; + border = Tk_Get3DBorderFromObj(menuPtr->tkwin, + menuPtr->borderPtr); + Tk_Fill3DRectangle(menuPtr->tkwin, d, border, left, top, dim, dim, DECORATION_BORDER_WIDTH, TK_RELIEF_SUNKEN); - left += DECORATION_BORDER_WIDTH; - top += DECORATION_BORDER_WIDTH; - dim -= 2*DECORATION_BORDER_WIDTH; - if ((dim > 0) && (mePtr->entryFlags - & ENTRY_SELECTED)) { + left += DECORATION_BORDER_WIDTH; + top += DECORATION_BORDER_WIDTH; + dim -= 2*DECORATION_BORDER_WIDTH; + if ((dim > 0) && (mePtr->entryFlags + & ENTRY_SELECTED)) { XFillRectangle(menuPtr->display, d, indicatorGC, left, top, (unsigned int) dim, (unsigned int) dim); - } + } } /* * Draw radio-button indicator. */ - if ((mePtr->type == RADIO_BUTTON_ENTRY) - && mePtr->indicatorOn) { - XPoint points[4]; - int radius; + if ((mePtr->type == RADIO_BUTTON_ENTRY) && mePtr->indicatorOn) { + XPoint points[4]; + int radius; + Tk_3DBorder border; + border = Tk_Get3DBorderFromObj(menuPtr->tkwin, + menuPtr->borderPtr); radius = ((int) mePtr->platformEntryData)/2; - points[0].x = x + (mePtr->indicatorSpace + points[0].x = x + (mePtr->indicatorSpace - (int) mePtr->platformEntryData)/2; points[0].y = y + (height)/2; - points[1].x = points[0].x + radius; - points[1].y = points[0].y + radius; - points[2].x = points[1].x + radius; - points[2].y = points[0].y; - points[3].x = points[1].x; - points[3].y = points[0].y - radius; - if (mePtr->entryFlags & ENTRY_SELECTED) { - XFillPolygon(menuPtr->display, d, indicatorGC, points, 4, Convex, - CoordModeOrigin); - } else { - Tk_Fill3DPolygon(menuPtr->tkwin, d, menuPtr->border, points, 4, + points[1].x = points[0].x + radius; + points[1].y = points[0].y + radius; + points[2].x = points[1].x + radius; + points[2].y = points[0].y; + points[3].x = points[1].x; + points[3].y = points[0].y - radius; + if (mePtr->entryFlags & ENTRY_SELECTED) { + XFillPolygon(menuPtr->display, d, indicatorGC, points, 4, + Convex, CoordModeOrigin); + } else { + Tk_Fill3DPolygon(menuPtr->tkwin, d, border, points, 4, DECORATION_BORDER_WIDTH, TK_RELIEF_FLAT); - } - Tk_Draw3DPolygon(menuPtr->tkwin, d, menuPtr->border, points, 4, - DECORATION_BORDER_WIDTH, TK_RELIEF_SUNKEN); + } + Tk_Draw3DPolygon(menuPtr->tkwin, d, border, points, 4, + DECORATION_BORDER_WIDTH, TK_RELIEF_SUNKEN); } } @@ -626,6 +659,7 @@ DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height) { XPoint points[2]; int margin; + Tk_3DBorder border; if (menuPtr->menuType == MENUBAR) { return; @@ -636,7 +670,8 @@ DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height) points[0].y = y + height/2; points[1].x = width - 1; points[1].y = points[0].y; - Tk_Draw3DPolygon(menuPtr->tkwin, d, menuPtr->border, points, 2, 1, + border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr); + Tk_Draw3DPolygon(menuPtr->tkwin, d, border, points, 2, 1, TK_RELIEF_RAISED); } @@ -658,30 +693,27 @@ DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height) */ static void -DrawMenuEntryLabel( - menuPtr, /* The menu we are drawing */ - mePtr, /* The entry we are drawing */ - d, /* What we are drawing into */ - gc, /* The gc we are drawing into */ - tkfont, /* The precalculated font */ - fmPtr, /* The precalculated font metrics */ - x, /* left edge */ - y, /* right edge */ - width, /* width of entry */ - height) /* height of entry */ - TkMenu *menuPtr; - TkMenuEntry *mePtr; - Drawable d; - GC gc; - Tk_Font tkfont; - CONST Tk_FontMetrics *fmPtr; - int x, y, width, height; +DrawMenuEntryLabel(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height) + TkMenu *menuPtr; /* The menu we are drawing. */ + TkMenuEntry *mePtr; /* The entry we are drawing. */ + Drawable d; /* What we are drawing into. */ + GC gc; /* The gc we are drawing into.*/ + Tk_Font tkfont; /* The precalculated font. */ + CONST Tk_FontMetrics *fmPtr;/* The precalculated font metrics. */ + int x; /* Left edge. */ + int y; /* Top edge. */ + int width; /* width of entry. */ + int height; /* height of entry. */ { int baseline; int indicatorSpace = mePtr->indicatorSpace; - int leftEdge = x + indicatorSpace + menuPtr->activeBorderWidth; + int activeBorderWidth; + int leftEdge; int imageHeight, imageWidth; + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr, + &activeBorderWidth); + leftEdge = x + indicatorSpace + activeBorderWidth; if (menuPtr->menuType == MENUBAR) { leftEdge += 5; } @@ -703,27 +735,25 @@ DrawMenuEntryLabel( imageHeight, d, leftEdge, (int) (y + (mePtr->height - imageHeight)/2)); } - } else if (mePtr->bitmap != None) { + } else if (mePtr->bitmapPtr != None) { int width, height; - - Tk_SizeOfBitmap(menuPtr->display, - mePtr->bitmap, &width, &height); - XCopyPlane(menuPtr->display, - mePtr->bitmap, d, - gc, 0, 0, (unsigned) width, (unsigned) height, leftEdge, + Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr); + Tk_SizeOfBitmap(menuPtr->display,bitmap, &width, &height); + XCopyPlane(menuPtr->display, bitmap, d, gc, 0, 0, (unsigned) width, + (unsigned) height, leftEdge, (int) (y + (mePtr->height - height)/2), 1); } else { if (mePtr->labelLength > 0) { - Tk_DrawChars(menuPtr->display, d, gc, - tkfont, mePtr->label, mePtr->labelLength, - leftEdge, baseline); + char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL); + Tk_DrawChars(menuPtr->display, d, gc, tkfont, label, + mePtr->labelLength, leftEdge, baseline); DrawMenuUnderline(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height); } } - if (mePtr->state == tkDisabledUid) { - if (menuPtr->disabledFg == NULL) { + if (mePtr->state == ENTRY_DISABLED) { + if (menuPtr->disabledFgPtr == NULL) { XFillRectangle(menuPtr->display, d, menuPtr->disabledGC, x, y, (unsigned) width, (unsigned) height); } else if ((mePtr->image != NULL) @@ -768,15 +798,24 @@ DrawMenuUnderline(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height) int height; { int indicatorSpace = mePtr->indicatorSpace; + if (mePtr->underline >= 0) { - int leftEdge = x + indicatorSpace + menuPtr->activeBorderWidth; + int activeBorderWidth; + int leftEdge; + char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL); + char *start = Tcl_UtfAtIndex(label, mePtr->underline); + char *end = Tcl_UtfNext(start); + + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, + menuPtr->activeBorderWidthPtr, &activeBorderWidth); + leftEdge = x + indicatorSpace + activeBorderWidth; if (menuPtr->menuType == MENUBAR) { leftEdge += 5; } - - Tk_UnderlineChars(menuPtr->display, d, gc, tkfont, mePtr->label, + + Tk_UnderlineChars(menuPtr->display, d, gc, tkfont, label, leftEdge, y + (height + fmPtr->ascent - fmPtr->descent) / 2, - mePtr->underline, mePtr->underline + 1); + start - label, end - label); } } @@ -866,7 +905,7 @@ GetTearoffEntryGeometry(menuPtr, mePtr, tkfont, fmPtr, widthPtr, heightPtr) *widthPtr = 0; } else { *heightPtr = fmPtr->linespace; - *widthPtr = Tk_TextWidth(tkfont, "W", -1); + *widthPtr = Tk_TextWidth(tkfont, "W", 1); } } @@ -903,21 +942,32 @@ TkpComputeMenubarGeometry(menuPtr) int helpMenuIndex = -1; TkMenuEntry *mePtr; int lastEntry; + Tk_Font menuFont; + int borderWidth; + int activeBorderWidth; if (menuPtr->tkwin == NULL) { return; } + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr, + &borderWidth); + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr, + &activeBorderWidth); maxWidth = 0; if (menuPtr->numEntries == 0) { height = 0; } else { + int borderWidth; + maxWindowWidth = Tk_Width(menuPtr->tkwin); if (maxWindowWidth == 1) { maxWindowWidth = 0x7ffffff; } currentRowHeight = 0; - x = y = menuPtr->borderWidth; + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr, + &borderWidth); + x = y = borderWidth; lastRowBreak = 0; currentRowWidth = 0; @@ -929,21 +979,22 @@ TkpComputeMenubarGeometry(menuPtr) * and if an entry has a font set, we will measure it as we come * to it, and then we decide which set to give the geometry routines. */ - - Tk_GetFontMetrics(menuPtr->tkfont, &menuMetrics); + + menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr); + Tk_GetFontMetrics(menuFont, &menuMetrics); for (i = 0; i < menuPtr->numEntries; i++) { mePtr = menuPtr->entries[i]; mePtr->entryFlags &= ~ENTRY_LAST_COLUMN; - tkfont = mePtr->tkfont; - if (tkfont == NULL) { - tkfont = menuPtr->tkfont; - fmPtr = &menuMetrics; - } else { + if (mePtr->fontPtr != NULL) { + tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr); Tk_GetFontMetrics(tkfont, &entryMetrics); fmPtr = &entryMetrics; + } else { + tkfont = menuFont; + fmPtr = &menuMetrics; } - + /* * For every entry, we need to check to see whether or not we * wrap. If we do wrap, then we have to adjust all of the previous @@ -956,24 +1007,21 @@ TkpComputeMenubarGeometry(menuPtr) || (mePtr->type == TEAROFF_ENTRY)) { mePtr->height = mePtr->width = 0; } else { - - GetMenuLabelGeometry(mePtr, tkfont, fmPtr, - &width, &height); - mePtr->height = height + 2 * menuPtr->activeBorderWidth + 10; + GetMenuLabelGeometry(mePtr, tkfont, fmPtr, &width, &height); + mePtr->height = height + 2 * activeBorderWidth + 10; mePtr->width = width; - - GetMenuIndicatorGeometry(menuPtr, mePtr, - tkfont, fmPtr, &width, &height); + + GetMenuIndicatorGeometry(menuPtr, mePtr, tkfont, fmPtr, + &width, &height); mePtr->indicatorSpace = width; if (width > 0) { mePtr->width += width; } - mePtr->width += 2 * menuPtr->activeBorderWidth + 10; + mePtr->width += 2 * activeBorderWidth + 10; } if (mePtr->entryFlags & ENTRY_HELP_MENU) { helpMenuIndex = i; - } else if (x + mePtr->width + menuPtr->borderWidth - > maxWindowWidth) { + } else if (x + mePtr->width + borderWidth > maxWindowWidth) { if (i == lastRowBreak) { mePtr->y = y; @@ -982,7 +1030,7 @@ TkpComputeMenubarGeometry(menuPtr) y += mePtr->height; currentRowHeight = 0; } else { - x = menuPtr->borderWidth; + x = borderWidth; for (j = lastRowBreak; j < i; j++) { menuPtr->entries[j]->y = y + currentRowHeight - menuPtr->entries[j]->height; @@ -996,7 +1044,7 @@ TkpComputeMenubarGeometry(menuPtr) if (x > maxWidth) { maxWidth = x; } - x = menuPtr->borderWidth; + x = borderWidth; } else { x += mePtr->width; if (mePtr->height > currentRowHeight) { @@ -1010,11 +1058,10 @@ TkpComputeMenubarGeometry(menuPtr) lastEntry--; } if ((lastEntry >= 0) && (x + menuPtr->entries[lastEntry]->width - + menuPtr->borderWidth > maxWidth)) { - maxWidth = x + menuPtr->entries[lastEntry]->width - + menuPtr->borderWidth; + + borderWidth > maxWidth)) { + maxWidth = x + menuPtr->entries[lastEntry]->width + borderWidth; } - x = menuPtr->borderWidth; + x = borderWidth; for (j = lastRowBreak; j < menuPtr->numEntries; j++) { if (j == helpMenuIndex) { continue; @@ -1028,17 +1075,17 @@ TkpComputeMenubarGeometry(menuPtr) if (helpMenuIndex != -1) { mePtr = menuPtr->entries[helpMenuIndex]; - if (x + mePtr->width + menuPtr->borderWidth > maxWindowWidth) { + if (x + mePtr->width + borderWidth > maxWindowWidth) { y += currentRowHeight; currentRowHeight = mePtr->height; - x = menuPtr->borderWidth; + x = borderWidth; } else if (mePtr->height > currentRowHeight) { currentRowHeight = mePtr->height; } - mePtr->x = maxWindowWidth - menuPtr->borderWidth - mePtr->width; + mePtr->x = maxWindowWidth - borderWidth - mePtr->width; mePtr->y = y + currentRowHeight - mePtr->height; } - height = y + currentRowHeight + menuPtr->borderWidth; + height = y + currentRowHeight + borderWidth; } width = Tk_Width(menuPtr->tkwin); @@ -1089,6 +1136,7 @@ DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height) { XPoint points[2]; int margin, segmentWidth, maxX; + Tk_3DBorder border; if (menuPtr->menuType != MASTER_MENU) { return; @@ -1100,15 +1148,16 @@ DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height) points[1].y = points[0].y; segmentWidth = 6; maxX = width - 1; + border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr); while (points[0].x < maxX) { points[1].x = points[0].x + segmentWidth; if (points[1].x > maxX) { points[1].x = maxX; } - Tk_Draw3DPolygon(menuPtr->tkwin, d, menuPtr->border, points, 2, 1, + Tk_Draw3DPolygon(menuPtr->tkwin, d, border, points, 2, 1, TK_RELIEF_RAISED); - points[0].x += 2*segmentWidth; + points[0].x += 2 * segmentWidth; } } @@ -1235,8 +1284,7 @@ TkpDrawMenuEntry(mePtr, d, tkfont, menuMetricsPtr, x, y, width, height, * Choose the gc for drawing the foreground part of the entry. */ - if ((mePtr->state == tkActiveUid) - && !strictMotif) { + if ((mePtr->state == ENTRY_ACTIVE) && !strictMotif) { gc = mePtr->activeGC; if (gc == NULL) { gc = menuPtr->activeGC; @@ -1248,17 +1296,21 @@ TkpDrawMenuEntry(mePtr, d, tkfont, menuMetricsPtr, x, y, width, height, for (cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr; cascadeEntryPtr != NULL; cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) { - if (strcmp(cascadeEntryPtr->name, - Tk_PathName(menuPtr->tkwin)) == 0) { - if (cascadeEntryPtr->state == tkDisabledUid) { - parentDisabled = 1; + if (cascadeEntryPtr->namePtr != NULL) { + char *name = Tcl_GetStringFromObj(cascadeEntryPtr->namePtr, + NULL); + + if (strcmp(name, Tk_PathName(menuPtr->tkwin)) == 0) { + if (cascadeEntryPtr->state == ENTRY_DISABLED) { + parentDisabled = 1; + } + break; } - break; } } - if (((parentDisabled || (mePtr->state == tkDisabledUid))) - && (menuPtr->disabledFg != NULL)) { + if (((parentDisabled || (mePtr->state == ENTRY_DISABLED))) + && (menuPtr->disabledFgPtr != NULL)) { gc = mePtr->disabledGC; if (gc == NULL) { gc = menuPtr->disabledGC; @@ -1274,24 +1326,22 @@ TkpDrawMenuEntry(mePtr, d, tkfont, menuMetricsPtr, x, y, width, height, if (indicatorGC == NULL) { indicatorGC = menuPtr->indicatorGC; } - - bgBorder = mePtr->border; - if (bgBorder == NULL) { - bgBorder = menuPtr->border; - } + + bgBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin, + (mePtr->borderPtr == NULL) + ? menuPtr->borderPtr : mePtr->borderPtr); if (strictMotif) { activeBorder = bgBorder; } else { - activeBorder = mePtr->activeBorder; - if (activeBorder == NULL) { - activeBorder = menuPtr->activeBorder; - } + activeBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin, + (mePtr->activeBorderPtr == NULL) + ? menuPtr->activeBorderPtr : mePtr->activeBorderPtr); } - if (mePtr->tkfont == NULL) { + if (mePtr->fontPtr == NULL) { fmPtr = menuMetricsPtr; } else { - tkfont = mePtr->tkfont; + tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr); Tk_GetFontMetrics(tkfont, &entryMetrics); fmPtr = &entryMetrics; } @@ -1354,13 +1404,16 @@ GetMenuLabelGeometry(mePtr, tkfont, fmPtr, widthPtr, heightPtr) if (mePtr->image != NULL) { Tk_SizeOfImage(mePtr->image, widthPtr, heightPtr); - } else if (mePtr->bitmap != (Pixmap) NULL) { - Tk_SizeOfBitmap(menuPtr->display, mePtr->bitmap, widthPtr, heightPtr); + } else if (mePtr->bitmapPtr != NULL) { + Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr); + Tk_SizeOfBitmap(menuPtr->display, bitmap, widthPtr, heightPtr); } else { *heightPtr = fmPtr->linespace; - if (mePtr->label != NULL) { - *widthPtr = Tk_TextWidth(tkfont, mePtr->label, mePtr->labelLength); + if (mePtr->labelPtr != NULL) { + char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL); + + *widthPtr = Tk_TextWidth(tkfont, label, mePtr->labelLength); } else { *widthPtr = 0; } @@ -1392,18 +1445,23 @@ TkpComputeStandardMenuGeometry( menuPtr) /* Structure describing menu. */ TkMenu *menuPtr; { - Tk_Font tkfont; + Tk_Font tkfont, menuFont; Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr; int x, y, height, width, indicatorSpace, labelWidth, accelWidth; int windowWidth, windowHeight, accelSpace; int i, j, lastColumnBreak = 0; TkMenuEntry *mePtr; + int borderWidth, activeBorderWidth; if (menuPtr->tkwin == NULL) { return; } - x = y = menuPtr->borderWidth; + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr, + &borderWidth); + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr, + &activeBorderWidth); + x = y = borderWidth; indicatorSpace = labelWidth = accelWidth = 0; windowHeight = windowWidth = 0; @@ -1418,20 +1476,21 @@ TkpComputeStandardMenuGeometry( * give all of the geometry/drawing the entry's font and metrics. */ - Tk_GetFontMetrics(menuPtr->tkfont, &menuMetrics); - accelSpace = Tk_TextWidth(menuPtr->tkfont, "M", 1); + menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr); + Tk_GetFontMetrics(menuFont, &menuMetrics); + accelSpace = Tk_TextWidth(menuFont, "M", 1); for (i = 0; i < menuPtr->numEntries; i++) { mePtr = menuPtr->entries[i]; - tkfont = mePtr->tkfont; - if (tkfont == NULL) { - tkfont = menuPtr->tkfont; - fmPtr = &menuMetrics; - } else { - Tk_GetFontMetrics(tkfont, &entryMetrics); - fmPtr = &entryMetrics; - } - + if (mePtr->fontPtr == NULL) { + tkfont = menuFont; + fmPtr = &menuMetrics; + } else { + tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr); + Tk_GetFontMetrics(tkfont, &entryMetrics); + fmPtr = &entryMetrics; + } + if ((i > 0) && mePtr->columnBreak) { if (accelWidth != 0) { labelWidth += accelSpace; @@ -1440,16 +1499,16 @@ TkpComputeStandardMenuGeometry( menuPtr->entries[j]->indicatorSpace = indicatorSpace; menuPtr->entries[j]->labelWidth = labelWidth; menuPtr->entries[j]->width = indicatorSpace + labelWidth - + accelWidth + 2 * menuPtr->activeBorderWidth; + + accelWidth + 2 * activeBorderWidth; menuPtr->entries[j]->x = x; menuPtr->entries[j]->entryFlags &= ~ENTRY_LAST_COLUMN; } x += indicatorSpace + labelWidth + accelWidth - + 2 * menuPtr->activeBorderWidth; + + 2 * activeBorderWidth; windowWidth = x; indicatorSpace = labelWidth = accelWidth = 0; lastColumnBreak = i; - y = menuPtr->borderWidth; + y = borderWidth; } if (mePtr->type == SEPARATOR_ENTRY) { @@ -1507,8 +1566,7 @@ TkpComputeStandardMenuGeometry( indicatorSpace = width; } - mePtr->height += 2 * menuPtr->activeBorderWidth + - MENU_DIVIDER_HEIGHT; + mePtr->height += 2 * activeBorderWidth + MENU_DIVIDER_HEIGHT; } mePtr->y = y; y += mePtr->height; @@ -1524,15 +1582,15 @@ TkpComputeStandardMenuGeometry( menuPtr->entries[j]->indicatorSpace = indicatorSpace; menuPtr->entries[j]->labelWidth = labelWidth; menuPtr->entries[j]->width = indicatorSpace + labelWidth - + accelWidth + 2 * menuPtr->activeBorderWidth; + + accelWidth + 2 * activeBorderWidth; menuPtr->entries[j]->x = x; menuPtr->entries[j]->entryFlags |= ENTRY_LAST_COLUMN; } windowWidth = x + indicatorSpace + labelWidth + accelWidth - + 2 * menuPtr->activeBorderWidth + 2 * menuPtr->borderWidth; + + 2 * activeBorderWidth + 2 * borderWidth; - windowHeight += menuPtr->borderWidth; + windowHeight += borderWidth; /* * The X server doesn't like zero dimensions, so round up to at least @@ -1601,3 +1659,30 @@ TkpMenuInit() * Nothing to do. */ } + + +/* + *---------------------------------------------------------------------- + * + * TkpMenuThreadInit -- + * + * Does platform-specific initialization of thread-specific + * menu state. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkpMenuThreadInit() +{ + /* + * Nothing to do. + */ +} + diff --git a/unix/tkUnixMenubu.c b/unix/tkUnixMenubu.c index 7c33033..d8cba87 100644 --- a/unix/tkUnixMenubu.c +++ b/unix/tkUnixMenubu.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixMenubu.c,v 1.2 1998/09/14 18:23:57 stanton Exp $ + * RCS: @(#) $Id: tkUnixMenubu.c,v 1.3 1999/04/16 01:51:47 stanton Exp $ */ #include "tkMenubutton.h" @@ -84,10 +84,11 @@ TkpDisplayMenuButton(clientData) return; } - if ((mbPtr->state == tkDisabledUid) && (mbPtr->disabledFg != NULL)) { + if ((mbPtr->state == STATE_DISABLED) && (mbPtr->disabledFg != NULL)) { gc = mbPtr->disabledGC; border = mbPtr->normalBorder; - } else if ((mbPtr->state == tkActiveUid) && !Tk_StrictMotif(mbPtr->tkwin)) { + } else if ((mbPtr->state == STATE_ACTIVE) + && !Tk_StrictMotif(mbPtr->tkwin)) { gc = mbPtr->activeTextGC; border = mbPtr->activeBorder; } else { @@ -142,8 +143,8 @@ TkpDisplayMenuButton(clientData) * foreground color, generate the stippled effect. */ - if ((mbPtr->state == tkDisabledUid) - && ((mbPtr->disabledFg == NULL) || (mbPtr->image != NULL))) { + if (((mbPtr->state == STATE_DISABLED) + && (mbPtr->disabledFg == NULL)) || (mbPtr->image != NULL)) { XFillRectangle(mbPtr->display, pixmap, mbPtr->disabledGC, mbPtr->inset, mbPtr->inset, (unsigned) (Tk_Width(tkwin) - 2*mbPtr->inset), @@ -248,7 +249,7 @@ TkpDestroyMenuButton(mbPtr) void TkpComputeMenuButtonGeometry(mbPtr) - register TkMenuButton *mbPtr; /* Widget record for menu button. */ + TkMenuButton *mbPtr; /* Widget record for menu button. */ { int width, height, mm, pixels; diff --git a/unix/tkUnixPort.h b/unix/tkUnixPort.h index 590e22a..242d127 100644 --- a/unix/tkUnixPort.h +++ b/unix/tkUnixPort.h @@ -7,12 +7,11 @@ * * Copyright (c) 1991-1993 The Regents of the University of California. * Copyright (c) 1994-1996 Sun Microsystems, Inc. - * Copyright (c) 1998 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixPort.h,v 1.4 1999/03/10 07:04:46 stanton Exp $ + * RCS: @(#) $Id: tkUnixPort.h,v 1.5 1999/04/16 01:51:47 stanton Exp $ */ #ifndef _UNIXPORT @@ -176,9 +175,16 @@ extern int errno; #endif /* + * Declarations for various library procedures that may not be declared + * in any other header file. + */ + + +/* * These functions do nothing under Unix, so we just eliminate calls to them. */ +#define TkpButtonSetDefaults(specPtr) {} #define TkpDestroyButton(butPtr) {} #define TkSelUpdateClipboard(a,b) {} #define TkSetPixmapColormap(p,c) {} @@ -214,13 +220,12 @@ extern int errno; #define ALWAYS_SHOW_SELECTION /* - * tclInt.h is included to get declarations of the following functions. - * void panic _ANSI_ARGS_(TCL_VARARGS(char *,format)); - * void TclpGetTime _ANSI_ARGS_((Tcl_Time *time)); + * The following declaration is used to get access to a private Tcl interface + * that is needed for portability reasons. */ - + #ifndef _TCLINT -# include <tclInt.h> +#include <tclInt.h> #endif #endif /* _UNIXPORT */ diff --git a/unix/tkUnixScale.c b/unix/tkUnixScale.c index b61b99a..5d7e9a1 100644 --- a/unix/tkUnixScale.c +++ b/unix/tkUnixScale.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixScale.c,v 1.2 1998/09/14 18:23:57 stanton Exp $ + * RCS: @(#) $Id: tkUnixScale.c,v 1.3 1999/04/16 01:51:47 stanton Exp $ */ #include "tkScale.h" @@ -177,7 +177,7 @@ DisplayVerticalScale(scalePtr, drawable, drawnAreaPtr) (unsigned) scalePtr->width, (unsigned) (Tk_Height(tkwin) - 2*scalePtr->inset - 2*scalePtr->borderWidth)); - if (scalePtr->state == tkActiveUid) { + if (scalePtr->state == STATE_ACTIVE) { sliderBorder = scalePtr->activeBorder; } else { sliderBorder = scalePtr->bgBorder; @@ -210,8 +210,9 @@ DisplayVerticalScale(scalePtr, drawable, drawnAreaPtr) Tk_GetFontMetrics(scalePtr->tkfont, &fm); Tk_DrawChars(scalePtr->display, drawable, scalePtr->textGC, - scalePtr->tkfont, scalePtr->label, scalePtr->labelLength, - scalePtr->vertLabelX, scalePtr->inset + (3*fm.ascent)/2); + scalePtr->tkfont, Tcl_GetString(scalePtr->labelPtr), + scalePtr->labelLength, scalePtr->vertLabelX, + scalePtr->inset + (3*fm.ascent)/2); } } @@ -376,7 +377,7 @@ DisplayHorizontalScale(scalePtr, drawable, drawnAreaPtr) (unsigned) (Tk_Width(tkwin) - 2*scalePtr->inset - 2*scalePtr->borderWidth), (unsigned) scalePtr->width); - if (scalePtr->state == tkActiveUid) { + if (scalePtr->state == STATE_ACTIVE) { sliderBorder = scalePtr->activeBorder; } else { sliderBorder = scalePtr->bgBorder; @@ -409,8 +410,9 @@ DisplayHorizontalScale(scalePtr, drawable, drawnAreaPtr) Tk_GetFontMetrics(scalePtr->tkfont, &fm); Tk_DrawChars(scalePtr->display, drawable, scalePtr->textGC, - scalePtr->tkfont, scalePtr->label, scalePtr->labelLength, - scalePtr->inset + fm.ascent/2, scalePtr->horizLabelY + fm.ascent); + scalePtr->tkfont, Tcl_GetString(scalePtr->labelPtr), + scalePtr->labelLength, scalePtr->inset + fm.ascent/2, + scalePtr->horizLabelY + fm.ascent); } } @@ -512,10 +514,12 @@ TkpDisplayScale(clientData) Tcl_Preserve((ClientData) scalePtr); Tcl_Preserve((ClientData) interp); - if ((scalePtr->flags & INVOKE_COMMAND) && (scalePtr->command != NULL)) { + if ((scalePtr->flags & INVOKE_COMMAND) + && (scalePtr->commandPtr != NULL)) { sprintf(string, scalePtr->format, scalePtr->value); - result = Tcl_VarEval(interp, scalePtr->command, " ", string, - (char *) NULL); + + result = Tcl_VarEval(interp, Tcl_GetString(scalePtr->commandPtr), + " ", string, (char *) NULL); if (result != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (command executed by scale)"); Tcl_BackgroundError(interp); @@ -549,7 +553,7 @@ TkpDisplayScale(clientData) * different. */ - if (scalePtr->vertical) { + if (scalePtr->orient == ORIENT_VERTICAL) { DisplayVerticalScale(scalePtr, pixmap, &drawnArea); } else { DisplayHorizontalScale(scalePtr, pixmap, &drawnArea); @@ -575,7 +579,8 @@ TkpDisplayScale(clientData) if (scalePtr->flags & GOT_FOCUS) { gc = Tk_GCForColor(scalePtr->highlightColorPtr, pixmap); } else { - gc = Tk_GCForColor(scalePtr->highlightBgColorPtr, pixmap); + gc = Tk_GCForColor( + Tk_3DBorderColor(scalePtr->highlightBorder), pixmap); } Tk_DrawFocusHighlight(tkwin, gc, scalePtr->highlightWidth, pixmap); } @@ -621,7 +626,7 @@ TkpScaleElement(scalePtr, x, y) { int sliderFirst; - if (scalePtr->vertical) { + if (scalePtr->orient == ORIENT_VERTICAL) { if ((x < scalePtr->vertTroughX) || (x >= (scalePtr->vertTroughX + 2*scalePtr->borderWidth + scalePtr->width))) { @@ -712,11 +717,11 @@ TkpSetScaleValue(scalePtr, value, setVar, invokeCommand) } TkEventuallyRedrawScale(scalePtr, REDRAW_SLIDER); - if (setVar && (scalePtr->varName != NULL)) { + if (setVar && (scalePtr->varNamePtr != NULL)) { sprintf(string, scalePtr->format, scalePtr->value); scalePtr->flags |= SETTING_VAR; - Tcl_SetVar(scalePtr->interp, scalePtr->varName, string, - TCL_GLOBAL_ONLY); + Tcl_SetVar(scalePtr->interp, Tcl_GetString(scalePtr->varNamePtr), + string, TCL_GLOBAL_ONLY); scalePtr->flags &= ~SETTING_VAR; } } @@ -748,7 +753,7 @@ TkpPixelToValue(scalePtr, x, y) { double value, pixelRange; - if (scalePtr->vertical) { + if (scalePtr->orient == ORIENT_VERTICAL) { pixelRange = Tk_Height(scalePtr->tkwin) - scalePtr->sliderLength - 2*scalePtr->inset - 2*scalePtr->borderWidth; value = y; @@ -809,7 +814,8 @@ TkpValueToPixel(scalePtr, value) double valueRange; valueRange = scalePtr->toValue - scalePtr->fromValue; - pixelRange = (scalePtr->vertical ? Tk_Height(scalePtr->tkwin) + pixelRange = (scalePtr->orient == ORIENT_VERTICAL + ? Tk_Height(scalePtr->tkwin) : Tk_Width(scalePtr->tkwin)) - scalePtr->sliderLength - 2*scalePtr->inset - 2*scalePtr->borderWidth; if (valueRange == 0) { diff --git a/unix/tkUnixSelect.c b/unix/tkUnixSelect.c index 1b27b70..2b79a70 100644 --- a/unix/tkUnixSelect.c +++ b/unix/tkUnixSelect.c @@ -4,12 +4,12 @@ * This file contains X specific routines for manipulating * selections. * - * Copyright (c) 1995 Sun Microsystems, Inc. + * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixSelect.c,v 1.2 1998/09/14 18:23:57 stanton Exp $ + * RCS: @(#) $Id: tkUnixSelect.c,v 1.3 1999/04/16 01:51:47 stanton Exp $ */ #include "tkInt.h" @@ -57,9 +57,12 @@ typedef struct IncrInfo { * retrievals currently pending. */ } IncrInfo; -static IncrInfo *pendingIncrs = NULL; - /* List of all incr structures + +typedef struct ThreadSpecificData { + IncrInfo *pendingIncrs; /* List of all incr structures * currently active. */ +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; /* * Largest property that we'll accept when sending or receiving the @@ -98,7 +101,7 @@ static void SelTimeoutProc _ANSI_ARGS_((ClientData clientData)); * Results: * The return value is a standard Tcl return value. * If an error occurs (such as no selection exists) - * then an error message is left in interp->result. + * then an error message is left in the interp's result. * * Side effects: * None. @@ -230,6 +233,8 @@ TkSelPropProc(eventPtr) int numItems; char *propPtr; Tk_ErrorHandler errorHandler; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); /* * See if this event announces the deletion of a property being @@ -240,7 +245,7 @@ TkSelPropProc(eventPtr) if (eventPtr->xproperty.state != PropertyDelete) { return; } - for (incrPtr = pendingIncrs; incrPtr != NULL; + for (incrPtr = tsdPtr->pendingIncrs; incrPtr != NULL; incrPtr = incrPtr->nextPtr) { if (incrPtr->reqWindow != eventPtr->xproperty.window) { continue; @@ -269,12 +274,12 @@ TkSelPropProc(eventPtr) } else { TkSelInProgress ip; ip.selPtr = selPtr; - ip.nextPtr = pendingPtr; - pendingPtr = &ip; + ip.nextPtr = TkSelGetInProgress(); + TkSelSetInProgress(&ip); numItems = (*selPtr->proc)(selPtr->clientData, incrPtr->offsets[i], (char *) buffer, TK_SEL_BYTES_AT_ONCE); - pendingPtr = ip.nextPtr; + TkSelSetInProgress(ip.nextPtr); if (ip.selPtr == NULL) { /* * The selection handler deleted itself. @@ -422,9 +427,12 @@ TkSelEventProc(tkwin, eventPtr) if ((type == XA_STRING) || (type == dispPtr->textAtom) || (type == dispPtr->compoundTextAtom)) { if (format != 8) { - sprintf(retrPtr->interp->result, - "bad format for string selection: wanted \"8\", got \"%d\"", - format); + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, + "bad format for string selection: wanted \"8\", got \"%d\"", + format); + Tcl_SetResult(retrPtr->interp, buf, TCL_VOLATILE); retrPtr->result = TCL_ERROR; return; } @@ -456,9 +464,12 @@ TkSelEventProc(tkwin, eventPtr) char *string; if (format != 32) { - sprintf(retrPtr->interp->result, - "bad format for selection: wanted \"32\", got \"%d\"", - format); + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, + "bad format for selection: wanted \"32\", got \"%d\"", + format); + Tcl_SetResult(retrPtr->interp, buf, TCL_VOLATILE); retrPtr->result = TCL_ERROR; return; } @@ -580,6 +591,8 @@ ConvertSelection(winPtr, eventPtr) Tk_ErrorHandler errorHandler; TkSelectionInfo *infoPtr; TkSelInProgress ip; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); errorHandler = Tk_CreateErrorHandler(eventPtr->display, -1, -1,-1, (int (*)()) NULL, (ClientData) NULL); @@ -694,12 +707,12 @@ ConvertSelection(winPtr, eventPtr) } } else { ip.selPtr = selPtr; - ip.nextPtr = pendingPtr; - pendingPtr = &ip; + ip.nextPtr = TkSelGetInProgress(); + TkSelSetInProgress(&ip); type = selPtr->format; numItems = (*selPtr->proc)(selPtr->clientData, 0, (char *) buffer, TK_SEL_BYTES_AT_ONCE); - pendingPtr = ip.nextPtr; + TkSelSetInProgress(ip.nextPtr); if ((ip.selPtr == NULL) || (numItems < 0)) { incr.multAtoms[2*i + 1] = None; continue; @@ -761,8 +774,8 @@ ConvertSelection(winPtr, eventPtr) incr.idleTime = 0; incr.reqWindow = reply.requestor; incr.time = infoPtr->time; - incr.nextPtr = pendingIncrs; - pendingIncrs = &incr; + incr.nextPtr = tsdPtr->pendingIncrs; + tsdPtr->pendingIncrs = &incr; } if (multiple) { XChangeProperty(reply.display, reply.requestor, reply.property, @@ -798,10 +811,10 @@ ConvertSelection(winPtr, eventPtr) -1, -1,-1, (int (*)()) NULL, (ClientData) NULL); XSelectInput(reply.display, reply.requestor, 0L); Tk_DeleteErrorHandler(errorHandler); - if (pendingIncrs == &incr) { - pendingIncrs = incr.nextPtr; + if (tsdPtr->pendingIncrs == &incr) { + tsdPtr->pendingIncrs = incr.nextPtr; } else { - for (incrPtr2 = pendingIncrs; incrPtr2 != NULL; + for (incrPtr2 = tsdPtr->pendingIncrs; incrPtr2 != NULL; incrPtr2 = incrPtr2->nextPtr) { if (incrPtr2->nextPtr == &incr) { incrPtr2->nextPtr = incr.nextPtr; @@ -891,10 +904,12 @@ SelRcvIncrProc(clientData, eventPtr) || (type == retrPtr->winPtr->dispPtr->textAtom) || (type == retrPtr->winPtr->dispPtr->compoundTextAtom)) { if (format != 8) { - Tcl_SetResult(retrPtr->interp, (char *) NULL, TCL_STATIC); - sprintf(retrPtr->interp->result, - "bad format for string selection: wanted \"8\", got \"%d\"", - format); + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, + "bad format for string selection: wanted \"8\", got \"%d\"", + format); + Tcl_SetResult(retrPtr->interp, buf, TCL_VOLATILE); retrPtr->result = TCL_ERROR; goto done; } @@ -909,10 +924,12 @@ SelRcvIncrProc(clientData, eventPtr) char *string; if (format != 32) { - Tcl_SetResult(retrPtr->interp, (char *) NULL, TCL_STATIC); - sprintf(retrPtr->interp->result, - "bad format for selection: wanted \"32\", got \"%d\"", - format); + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, + "bad format for selection: wanted \"32\", got \"%d\"", + format); + Tcl_SetResult(retrPtr->interp, buf, TCL_VOLATILE); retrPtr->result = TCL_ERROR; goto done; } @@ -964,8 +981,8 @@ SelectionSize(selPtr) size = TK_SEL_BYTES_AT_ONCE; ip.selPtr = selPtr; - ip.nextPtr = pendingPtr; - pendingPtr = &ip; + ip.nextPtr = TkSelGetInProgress(); + TkSelSetInProgress(&ip); do { chunkSize = (*selPtr->proc)(selPtr->clientData, size, (char *) buffer, TK_SEL_BYTES_AT_ONCE); @@ -975,7 +992,7 @@ SelectionSize(selPtr) } size += chunkSize; } while (chunkSize == TK_SEL_BYTES_AT_ONCE); - pendingPtr = ip.nextPtr; + TkSelSetInProgress(ip.nextPtr); return size; } diff --git a/unix/tkUnixSend.c b/unix/tkUnixSend.c index 79d5e7a..597911f 100644 --- a/unix/tkUnixSend.c +++ b/unix/tkUnixSend.c @@ -7,11 +7,12 @@ * * Copyright (c) 1989-1994 The Regents of the University of California. * Copyright (c) 1994-1996 Sun Microsystems, Inc. + * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixSend.c,v 1.3 1999/02/04 21:00:36 stanton Exp $ + * RCS: @(#) $Id: tkUnixSend.c,v 1.4 1999/04/16 01:51:47 stanton Exp $ */ #include "tkPort.h" @@ -39,10 +40,6 @@ typedef struct RegisteredInterp { * NULL means end of list. */ } RegisteredInterp; -static RegisteredInterp *registry = NULL; - /* List of all interpreters - * registered by this process. */ - /* * A registry of all interpreters for a display is kept in a * property "InterpRegistry" on the root window of the display. @@ -109,9 +106,15 @@ typedef struct PendingCommand { * list. */ } PendingCommand; -static PendingCommand *pendingCommands = NULL; - /* List of all commands currently +typedef struct ThreadSpecificData { + PendingCommand *pendingCommands; + /* List of all commands currently * being waited for. */ + RegisteredInterp *interpListPtr; + /* List of all interpreters registered + * in the current process. */ +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; /* * The information below is used for communication between processes @@ -745,18 +748,15 @@ Tk_SetAppName(tkwin, name) RegisteredInterp *riPtr, *riPtr2; Window w; TkWindow *winPtr = (TkWindow *) tkwin; - TkDisplay *dispPtr; + TkDisplay *dispPtr = winPtr->dispPtr; NameRegistry *regPtr; Tcl_Interp *interp; char *actualName; Tcl_DString dString; int offset, i; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); -#ifdef __WIN32__ - return name; -#endif /* __WIN32__ */ - - dispPtr = winPtr->dispPtr; interp = winPtr->mainPtr->interp; if (dispPtr->commTkwin == NULL) { SendInit(interp, winPtr->dispPtr); @@ -768,7 +768,7 @@ Tk_SetAppName(tkwin, name) */ regPtr = RegOpen(interp, winPtr->dispPtr, 1); - for (riPtr = registry; ; riPtr = riPtr->nextPtr) { + for (riPtr = tsdPtr->interpListPtr; ; riPtr = riPtr->nextPtr) { if (riPtr == NULL) { /* @@ -780,9 +780,9 @@ Tk_SetAppName(tkwin, name) riPtr = (RegisteredInterp *) ckalloc(sizeof(RegisteredInterp)); riPtr->interp = interp; riPtr->dispPtr = winPtr->dispPtr; - riPtr->nextPtr = registry; + riPtr->nextPtr = tsdPtr->interpListPtr; + tsdPtr->interpListPtr = riPtr; riPtr->name = NULL; - registry = riPtr; Tcl_CreateCommand(interp, "send", Tk_SendCmd, (ClientData) riPtr, DeleteProc); if (Tcl_IsSafe(interp)) { @@ -838,7 +838,8 @@ Tk_SetAppName(tkwin, name) */ if (w == Tk_WindowId(dispPtr->commTkwin)) { - for (riPtr2 = registry; riPtr2 != NULL; riPtr2 = riPtr2->nextPtr) { + for (riPtr2 = tsdPtr->interpListPtr; riPtr2 != NULL; + riPtr2 = riPtr2->nextPtr) { if ((riPtr2->interp != interp) && (strcmp(riPtr2->name, actualName) == 0)) { goto nextSuffix; @@ -901,7 +902,7 @@ Tk_SendCmd(clientData, interp, argc, argv) Window commWindow; PendingCommand pending; register RegisteredInterp *riPtr; - char *destName, buffer[30]; + char *destName; int result, c, async, i, firstArg; size_t length; Tk_RestrictProc *prevRestrictProc; @@ -910,6 +911,8 @@ Tk_SendCmd(clientData, interp, argc, argv) Tcl_Time timeout; NameRegistry *regPtr; Tcl_DString request; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); Tcl_Interp *localInterp; /* Used when the interpreter to * send the command to is within * the same process. */ @@ -971,7 +974,8 @@ Tk_SendCmd(clientData, interp, argc, argv) * could be the same! */ - for (riPtr = registry; riPtr != NULL; riPtr = riPtr->nextPtr) { + for (riPtr = tsdPtr->interpListPtr; riPtr != NULL; + riPtr = riPtr->nextPtr) { if ((riPtr->dispPtr != dispPtr) || (strcmp(riPtr->name, destName) != 0)) { continue; @@ -993,6 +997,7 @@ Tk_SendCmd(clientData, interp, argc, argv) } if (interp != localInterp) { if (result == TCL_ERROR) { + Tcl_Obj *errorObjPtr; /* * An error occurred, so transfer error information from the @@ -1006,17 +1011,11 @@ Tk_SendCmd(clientData, interp, argc, argv) Tcl_ResetResult(interp); Tcl_AddErrorInfo(interp, Tcl_GetVar2(localInterp, "errorInfo", (char *) NULL, TCL_GLOBAL_ONLY)); - Tcl_SetVar2(interp, "errorCode", (char *) NULL, - Tcl_GetVar2(localInterp, "errorCode", (char *) NULL, - TCL_GLOBAL_ONLY), TCL_GLOBAL_ONLY); + errorObjPtr = Tcl_GetVar2Ex(localInterp, "errorCode", NULL, + TCL_GLOBAL_ONLY); + Tcl_SetObjErrorCode(interp, errorObjPtr); } - if (localInterp->freeProc != TCL_STATIC) { - interp->result = localInterp->result; - interp->freeProc = localInterp->freeProc; - localInterp->freeProc = TCL_STATIC; - } else { - Tcl_SetResult(interp, localInterp->result, TCL_VOLATILE); - } + Tcl_SetObjResult(interp, Tcl_GetObjResult(localInterp)); Tcl_ResetResult(localInterp); } Tcl_Release((ClientData) riPtr); @@ -1047,6 +1046,8 @@ Tk_SendCmd(clientData, interp, argc, argv) Tcl_DStringAppend(&request, "\0c\0-n ", 6); Tcl_DStringAppend(&request, destName, -1); if (!async) { + char buffer[TCL_INTEGER_SPACE * 2]; + sprintf(buffer, "%x %d", (unsigned int) Tk_WindowId(dispPtr->commTkwin), tkSendSerial); @@ -1090,8 +1091,8 @@ Tk_SendCmd(clientData, interp, argc, argv) pending.errorInfo = NULL; pending.errorCode = NULL; pending.gotResponse = 0; - pending.nextPtr = pendingCommands; - pendingCommands = &pending; + pending.nextPtr = tsdPtr->pendingCommands; + tsdPtr->pendingCommands = &pending; /* * Enter a loop processing X events until the result comes @@ -1139,10 +1140,10 @@ Tk_SendCmd(clientData, interp, argc, argv) * and return the result. */ - if (pendingCommands != &pending) { + if (tsdPtr->pendingCommands != &pending) { panic("Tk_SendCmd: corrupted send stack"); } - pendingCommands = pending.nextPtr; + tsdPtr->pendingCommands = pending.nextPtr; if (pending.errorInfo != NULL) { /* * Special trick: must clear the interp's result before calling @@ -1156,8 +1157,9 @@ Tk_SendCmd(clientData, interp, argc, argv) ckfree(pending.errorInfo); } if (pending.errorCode != NULL) { - Tcl_SetVar2(interp, "errorCode", (char *) NULL, pending.errorCode, - TCL_GLOBAL_ONLY); + Tcl_Obj *errorObjPtr; + errorObjPtr = Tcl_NewStringObj(pending.errorCode, -1); + Tcl_SetObjErrorCode(interp, errorObjPtr); ckfree(pending.errorCode); } Tcl_SetResult(interp, pending.result, TCL_DYNAMIC); @@ -1174,10 +1176,10 @@ Tk_SendCmd(clientData, interp, argc, argv) * of a particular window. * * Results: - * A standard Tcl return value. Interp->result will be set + * A standard Tcl return value. The interp's result will be set * to hold a list of all the interpreter names defined for * tkwin's display. If an error occurs, then TCL_ERROR - * is returned and interp->result will hold an error message. + * is returned and the interp's result will hold an error message. * * Side effects: * None. @@ -1342,6 +1344,8 @@ SendEventProc(clientData, eventPtr) unsigned long numItems, bytesAfter; Atom actualType; Tcl_Interp *remoteInterp; /* Interp in which to execute the command. */ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if ((eventPtr->xproperty.atom != dispPtr->commProperty) || (eventPtr->xproperty.state != PropertyNewValue)) { @@ -1466,7 +1470,7 @@ SendEventProc(clientData, eventPtr) * Locate the application, then execute the script. */ - for (riPtr = registry; ; riPtr = riPtr->nextPtr) { + for (riPtr = tsdPtr->interpListPtr; ; riPtr = riPtr->nextPtr) { if (riPtr == NULL) { if (commWindow != None) { Tcl_DStringAppend(&reply, @@ -1501,7 +1505,8 @@ SendEventProc(clientData, eventPtr) */ if (commWindow != None) { - Tcl_DStringAppend(&reply, remoteInterp->result, -1); + Tcl_DStringAppend(&reply, Tcl_GetStringResult(remoteInterp), + -1); if (result == TCL_ERROR) { char *varValue; @@ -1532,7 +1537,7 @@ SendEventProc(clientData, eventPtr) returnResult: if (commWindow != None) { if (result != TCL_OK) { - char buffer[20]; + char buffer[TCL_INTEGER_SPACE]; sprintf(buffer, "%d", result); Tcl_DStringAppend(&reply, "\0-c ", 4); @@ -1607,7 +1612,7 @@ SendEventProc(clientData, eventPtr) * waiting for it. */ - for (pcPtr = pendingCommands; pcPtr != NULL; + for (pcPtr = tsdPtr->pendingCommands; pcPtr != NULL; pcPtr = pcPtr->nextPtr) { if ((serial != pcPtr->serial) || (pcPtr->result != NULL)) { continue; @@ -1705,6 +1710,8 @@ AppendErrorProc(clientData, errorPtr) { PendingCommand *pendingPtr = (PendingCommand *) clientData; register PendingCommand *pcPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (pendingPtr == NULL) { return 0; @@ -1714,7 +1721,7 @@ AppendErrorProc(clientData, errorPtr) * Make sure this command is still pending. */ - for (pcPtr = pendingCommands; pcPtr != NULL; + for (pcPtr = tsdPtr->pendingCommands; pcPtr != NULL; pcPtr = pcPtr->nextPtr) { if ((pcPtr == pendingPtr) && (pcPtr->result == NULL)) { pcPtr->result = (char *) ckalloc((unsigned) @@ -1754,15 +1761,17 @@ DeleteProc(clientData) RegisteredInterp *riPtr = (RegisteredInterp *) clientData; register RegisteredInterp *riPtr2; NameRegistry *regPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); regPtr = RegOpen(riPtr->interp, riPtr->dispPtr, 1); RegDeleteName(regPtr, riPtr->name); RegClose(regPtr); - if (registry == riPtr) { - registry = riPtr->nextPtr; + if (tsdPtr->interpListPtr == riPtr) { + tsdPtr->interpListPtr = riPtr->nextPtr; } else { - for (riPtr2 = registry; riPtr2 != NULL; + for (riPtr2 = tsdPtr->interpListPtr; riPtr2 != NULL; riPtr2 = riPtr2->nextPtr) { if (riPtr2->nextPtr == riPtr) { riPtr2->nextPtr = riPtr->nextPtr; @@ -1806,7 +1815,8 @@ SendRestrictProc(clientData, eventPtr) if (eventPtr->type != PropertyNotify) { return TK_DEFER_EVENT; } - for (dispPtr = tkDisplayList; dispPtr != NULL; dispPtr = dispPtr->nextPtr) { + for (dispPtr = TkGetDisplayList(); dispPtr != NULL; + dispPtr = dispPtr->nextPtr) { if ((eventPtr->xany.display == dispPtr->display) && (eventPtr->xproperty.window == Tk_WindowId(dispPtr->commTkwin))) { @@ -1841,9 +1851,12 @@ UpdateCommWindow(dispPtr) { Tcl_DString names; RegisteredInterp *riPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); Tcl_DStringInit(&names); - for (riPtr = registry; riPtr != NULL; riPtr = riPtr->nextPtr) { + for (riPtr = tsdPtr->interpListPtr; riPtr != NULL; + riPtr = riPtr->nextPtr) { Tcl_DStringAppendElement(&names, riPtr->name); } XChangeProperty(dispPtr->display, Tk_WindowId(dispPtr->commTkwin), diff --git a/unix/tkUnixWm.c b/unix/tkUnixWm.c index 1caf65d..c87fe53 100644 --- a/unix/tkUnixWm.c +++ b/unix/tkUnixWm.c @@ -8,12 +8,11 @@ * * Copyright (c) 1991-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * Copyright (c) 1998 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixWm.c,v 1.3 1998/09/30 23:46:17 rjohnson Exp $ + * RCS: @(#) $Id: tkUnixWm.c,v 1.4 1999/04/16 01:51:47 stanton Exp $ */ #include "tkPort.h" @@ -267,21 +266,10 @@ typedef struct TkWmInfo { /* * This module keeps a list of all top-level windows, primarily to - * simplify the job of Tk_CoordsToWindow. + * simplify the job of Tk_CoordsToWindow. The list is called + * firstWmPtr and is stored in the TkDisplay structure. */ -static WmInfo *firstWmPtr = NULL; /* Points to first top-level window. */ - - -/* - * The variable below is used to enable or disable tracing in this - * module. If tracing is enabled, then information is printed on - * standard output about interesting interactions with the window - * manager. - */ - -static int wmTracing = 0; - /* * The following structures are the official type records for geometry * management of top-level and menubar windows. @@ -337,6 +325,7 @@ static void ReparentEvent _ANSI_ARGS_((WmInfo *wmPtr, XReparentEvent *eventPtr)); static void TopLevelReqProc _ANSI_ARGS_((ClientData dummy, Tk_Window tkwin)); +static void UpdateCommand _ANSI_ARGS_((TkWindow *winPtr)); static void UpdateGeometryInfo _ANSI_ARGS_(( ClientData clientData)); static void UpdateHints _ANSI_ARGS_((TkWindow *winPtr)); @@ -378,6 +367,7 @@ TkWmNewWindow(winPtr) TkWindow *winPtr; /* Newly-created top-level window. */ { register WmInfo *wmPtr; + TkDisplay *dispPtr = winPtr->dispPtr; wmPtr = (WmInfo *) ckalloc(sizeof(WmInfo)); wmPtr->winPtr = winPtr; @@ -433,8 +423,8 @@ TkWmNewWindow(winPtr) wmPtr->cmdArgv = NULL; wmPtr->clientMachine = NULL; wmPtr->flags = WM_NEVER_MAPPED; - wmPtr->nextPtr = firstWmPtr; - firstWmPtr = wmPtr; + wmPtr->nextPtr = (WmInfo *) dispPtr->firstWmPtr; + dispPtr->firstWmPtr = wmPtr; winPtr->wmInfoPtr = wmPtr; UpdateVRootGeometry(wmPtr); @@ -480,6 +470,8 @@ TkWmMapWindow(winPtr) char *string; if (wmPtr->flags & WM_NEVER_MAPPED) { + Tcl_DString ds; + wmPtr->flags &= ~WM_NEVER_MAPPED; /* @@ -498,16 +490,22 @@ TkWmMapWindow(winPtr) */ string = (wmPtr->title != NULL) ? wmPtr->title : winPtr->nameUid; - if (XStringListToTextProperty(&string, 1, &textProp) != 0) { + Tcl_UtfToExternalDString(NULL, string, -1, &ds); + string = Tcl_DStringValue(&ds); + if (XStringListToTextProperty(&(Tcl_DStringValue(&ds)), 1, + &textProp) != 0) { XSetWMName(winPtr->display, wmPtr->wrapperPtr->window, &textProp); XFree((char *) textProp.value); } - + Tcl_DStringFree(&ds); + TkWmSetClass(winPtr); if (wmPtr->iconName != NULL) { + Tcl_UtfToExternalDString(NULL, wmPtr->iconName, -1, &ds); XSetIconName(winPtr->display, wmPtr->wrapperPtr->window, - wmPtr->iconName); + Tcl_DStringValue(&ds)); + Tcl_DStringFree(&ds); } if (wmPtr->master != None) { @@ -519,16 +517,17 @@ TkWmMapWindow(winPtr) UpdateHints(winPtr); UpdateWmProtocols(wmPtr); if (wmPtr->cmdArgv != NULL) { - XSetCommand(winPtr->display, wmPtr->wrapperPtr->window, - wmPtr->cmdArgv, wmPtr->cmdArgc); + UpdateCommand(winPtr); } if (wmPtr->clientMachine != NULL) { - if (XStringListToTextProperty(&wmPtr->clientMachine, 1, &textProp) - != 0) { + Tcl_UtfToExternalDString(NULL, wmPtr->clientMachine, -1, &ds); + if (XStringListToTextProperty(&(Tcl_DStringValue(&ds)), 1, + &textProp) != 0) { XSetWMClientMachine(winPtr->display, wmPtr->wrapperPtr->window, &textProp); XFree((char *) textProp.value); } + Tcl_DStringFree(&ds); } } if (wmPtr->hints.initial_state == WithdrawnState) { @@ -630,12 +629,13 @@ TkWmDeadWindow(winPtr) if (wmPtr == NULL) { return; } - if (firstWmPtr == wmPtr) { - firstWmPtr = wmPtr->nextPtr; + if ((WmInfo *) winPtr->dispPtr->firstWmPtr == wmPtr) { + winPtr->dispPtr->firstWmPtr = wmPtr->nextPtr; } else { register WmInfo *prevPtr; - for (prevPtr = firstWmPtr; ; prevPtr = prevPtr->nextPtr) { + for (prevPtr = (WmInfo *) winPtr->dispPtr->firstWmPtr; ; + prevPtr = prevPtr->nextPtr) { if (prevPtr == NULL) { panic("couldn't unlink window in TkWmDeadWindow"); } @@ -740,13 +740,18 @@ TkWmSetClass(winPtr) if (winPtr->classUid != NULL) { XClassHint *classPtr; + Tcl_DString name, class; + Tcl_UtfToExternalDString(NULL, winPtr->nameUid, -1, &name); + Tcl_UtfToExternalDString(NULL, winPtr->classUid, -1, &class); classPtr = XAllocClassHint(); - classPtr->res_name = winPtr->nameUid; - classPtr->res_class = winPtr->classUid; + classPtr->res_name = Tcl_DStringValue(&name); + classPtr->res_class = Tcl_DStringValue(&class); XSetClassHint(winPtr->display, winPtr->wmInfoPtr->wrapperPtr->window, classPtr); XFree((char *) classPtr); + Tcl_DStringFree(&name); + Tcl_DStringFree(&class); } } @@ -781,6 +786,7 @@ Tk_WmCmd(clientData, interp, argc, argv) register WmInfo *wmPtr; int c; size_t length; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; if (argc < 2) { wrongNumArgs: @@ -798,10 +804,11 @@ Tk_WmCmd(clientData, interp, argc, argv) return TCL_ERROR; } if (argc == 2) { - interp->result = (wmTracing) ? "on" : "off"; + Tcl_SetResult(interp, ((dispPtr->wmTracing) ? "on" : "off"), + TCL_STATIC); return TCL_OK; } - return Tcl_GetBoolean(interp, argv[2], &wmTracing); + return Tcl_GetBoolean(interp, argv[2], &dispPtr->wmTracing); } if (argc < 3) { @@ -828,9 +835,12 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->sizeHintsFlags & PAspect) { - sprintf(interp->result, "%d %d %d %d", wmPtr->minAspect.x, + char buf[TCL_INTEGER_SPACE * 4]; + + sprintf(buf, "%d %d %d %d", wmPtr->minAspect.x, wmPtr->minAspect.y, wmPtr->maxAspect.x, wmPtr->maxAspect.y); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } return TCL_OK; } @@ -845,7 +855,8 @@ Tk_WmCmd(clientData, interp, argc, argv) } if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) || (denom2 <= 0)) { - interp->result = "aspect number can't be <= 0"; + Tcl_SetResult(interp, "aspect number can't be <= 0", + TCL_STATIC); return TCL_ERROR; } wmPtr->minAspect.x = numer1; @@ -866,7 +877,7 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->clientMachine != NULL) { - interp->result = wmPtr->clientMachine; + Tcl_SetResult(interp, wmPtr->clientMachine, TCL_STATIC); } return TCL_OK; } @@ -890,12 +901,16 @@ Tk_WmCmd(clientData, interp, argc, argv) strcpy(wmPtr->clientMachine, argv[3]); if (!(wmPtr->flags & WM_NEVER_MAPPED)) { XTextProperty textProp; - if (XStringListToTextProperty(&wmPtr->clientMachine, 1, &textProp) - != 0) { + Tcl_DString ds; + + Tcl_UtfToExternalDString(NULL, wmPtr->clientMachine, -1, &ds); + if (XStringListToTextProperty(&(Tcl_DStringValue(&ds)), 1, + &textProp) != 0) { XSetWMClientMachine(winPtr->display, wmPtr->wrapperPtr->window, &textProp); XFree((char *) textProp.value); } + Tcl_DStringFree(&ds); } } else if ((c == 'c') && (strncmp(argv[1], "colormapwindows", length) == 0) && (length >= 3)) { @@ -985,8 +1000,9 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->cmdArgv != NULL) { - interp->result = Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv); - interp->freeProc = TCL_DYNAMIC; + Tcl_SetResult(interp, + Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv), + TCL_DYNAMIC); } return TCL_OK; } @@ -1010,8 +1026,7 @@ Tk_WmCmd(clientData, interp, argc, argv) wmPtr->cmdArgc = cmdArgc; wmPtr->cmdArgv = cmdArgv; if (!(wmPtr->flags & WM_NEVER_MAPPED)) { - XSetCommand(winPtr->display, wmPtr->wrapperPtr->window, - cmdArgv, cmdArgc); + UpdateCommand(winPtr); } } else if ((c == 'd') && (strncmp(argv[1], "deiconify", length) == 0)) { if (argc != 3) { @@ -1041,7 +1056,8 @@ Tk_WmCmd(clientData, interp, argc, argv) return TCL_ERROR; } if (argc == 3) { - interp->result = wmPtr->hints.input ? "passive" : "active"; + Tcl_SetResult(interp, (wmPtr->hints.input ? "passive" : "active"), + TCL_STATIC); return TCL_OK; } c = argv[3][0]; @@ -1059,6 +1075,7 @@ Tk_WmCmd(clientData, interp, argc, argv) } else if ((c == 'f') && (strncmp(argv[1], "frame", length) == 0) && (length >= 2)) { Window window; + char buf[TCL_INTEGER_SPACE]; if (argc != 3) { Tcl_AppendResult(interp, "wrong # arguments: must be \"", @@ -1069,7 +1086,8 @@ Tk_WmCmd(clientData, interp, argc, argv) if (window == None) { window = Tk_WindowId((Tk_Window) winPtr); } - sprintf(interp->result, "0x%x", (unsigned int) window); + sprintf(buf, "0x%x", (unsigned int) window); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if ((c == 'g') && (strncmp(argv[1], "geometry", length) == 0) && (length >= 2)) { char xSign, ySign; @@ -1082,6 +1100,8 @@ Tk_WmCmd(clientData, interp, argc, argv) return TCL_ERROR; } if (argc == 3) { + char buf[16 + TCL_INTEGER_SPACE * 4]; + xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+'; ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+'; if (wmPtr->gridWin != NULL) { @@ -1093,8 +1113,9 @@ Tk_WmCmd(clientData, interp, argc, argv) width = winPtr->changes.width; height = winPtr->changes.height; } - sprintf(interp->result, "%dx%d%c%d%c%d", width, height, - xSign, wmPtr->x, ySign, wmPtr->y); + sprintf(buf, "%dx%d%c%d%c%d", width, height, xSign, wmPtr->x, + ySign, wmPtr->y); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_OK; } if (*argv[3] == '\0') { @@ -1115,9 +1136,12 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->sizeHintsFlags & PBaseSize) { - sprintf(interp->result, "%d %d %d %d", wmPtr->reqGridWidth, + char buf[TCL_INTEGER_SPACE * 4]; + + sprintf(buf, "%d %d %d %d", wmPtr->reqGridWidth, wmPtr->reqGridHeight, wmPtr->widthInc, wmPtr->heightInc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } return TCL_OK; } @@ -1144,19 +1168,19 @@ Tk_WmCmd(clientData, interp, argc, argv) return TCL_ERROR; } if (reqWidth < 0) { - interp->result = "baseWidth can't be < 0"; + Tcl_SetResult(interp, "baseWidth can't be < 0", TCL_STATIC); return TCL_ERROR; } if (reqHeight < 0) { - interp->result = "baseHeight can't be < 0"; + Tcl_SetResult(interp, "baseHeight can't be < 0", TCL_STATIC); return TCL_ERROR; } if (widthInc < 0) { - interp->result = "widthInc can't be < 0"; + Tcl_SetResult(interp, "widthInc can't be < 0", TCL_STATIC); return TCL_ERROR; } if (heightInc < 0) { - interp->result = "heightInc can't be < 0"; + Tcl_SetResult(interp, "heightInc can't be < 0", TCL_STATIC); return TCL_ERROR; } Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc, @@ -1177,7 +1201,7 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->hints.flags & WindowGroupHint) { - interp->result = wmPtr->leaderName; + Tcl_SetResult(interp, wmPtr->leaderName, TCL_STATIC); } return TCL_OK; } @@ -1222,8 +1246,9 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->hints.flags & IconPixmapHint) { - interp->result = Tk_NameOfBitmap(winPtr->display, - wmPtr->hints.icon_pixmap); + Tcl_SetResult(interp, + Tk_NameOfBitmap(winPtr->display, wmPtr->hints.icon_pixmap), + TCL_STATIC); } return TCL_OK; } @@ -1277,8 +1302,9 @@ Tk_WmCmd(clientData, interp, argc, argv) } else { if (XIconifyWindow(winPtr->display, wmPtr->wrapperPtr->window, winPtr->screenNum) == 0) { - interp->result = - "couldn't send iconify message to window manager"; + Tcl_SetResult(interp, + "couldn't send iconify message to window manager", + TCL_STATIC); return TCL_ERROR; } WaitForMapNotify(winPtr, 0); @@ -1295,8 +1321,9 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->hints.flags & IconMaskHint) { - interp->result = Tk_NameOfBitmap(winPtr->display, - wmPtr->hints.icon_mask); + Tcl_SetResult(interp, + Tk_NameOfBitmap(winPtr->display, wmPtr->hints.icon_mask), + TCL_STATIC); } return TCL_OK; } @@ -1322,17 +1349,20 @@ Tk_WmCmd(clientData, interp, argc, argv) return TCL_ERROR; } if (argc == 3) { - interp->result = (wmPtr->iconName != NULL) ? wmPtr->iconName : ""; + Tcl_SetResult(interp, + ((wmPtr->iconName != NULL) ? wmPtr->iconName : ""), + TCL_STATIC); return TCL_OK; } else { - if (wmPtr->iconName != NULL) { - ckfree(wmPtr->iconName); - } wmPtr->iconName = ckalloc((unsigned) (strlen(argv[3]) + 1)); strcpy(wmPtr->iconName, argv[3]); if (!(wmPtr->flags & WM_NEVER_MAPPED)) { + Tcl_DString ds; + + Tcl_UtfToExternalDString(NULL, wmPtr->iconName, -1, &ds); XSetIconName(winPtr->display, wmPtr->wrapperPtr->window, - wmPtr->iconName); + Tcl_DStringValue(&ds)); + Tcl_DStringFree(&ds); } } } else if ((c == 'i') && (strncmp(argv[1], "iconposition", length) == 0) @@ -1347,8 +1377,11 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->hints.flags & IconPositionHint) { - sprintf(interp->result, "%d %d", wmPtr->hints.icon_x, + char buf[TCL_INTEGER_SPACE * 2]; + + sprintf(buf, "%d %d", wmPtr->hints.icon_x, wmPtr->hints.icon_y); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } return TCL_OK; } @@ -1378,7 +1411,7 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->icon != NULL) { - interp->result = Tk_PathName(wmPtr->icon); + Tcl_SetResult(interp, Tk_PathName(wmPtr->icon), TCL_STATIC); } return TCL_OK; } @@ -1447,8 +1480,9 @@ Tk_WmCmd(clientData, interp, argc, argv) if (XWithdrawWindow(Tk_Display(tkwin2), Tk_WindowId(wmPtr2->wrapperPtr), Tk_ScreenNumber(tkwin2)) == 0) { - interp->result = - "couldn't send withdraw message to window manager"; + Tcl_SetResult(interp, + "couldn't send withdraw message to window manager", + TCL_STATIC); return TCL_ERROR; } WaitForMapNotify((TkWindow *) tkwin2, 0); @@ -1464,8 +1498,11 @@ Tk_WmCmd(clientData, interp, argc, argv) return TCL_ERROR; } if (argc == 3) { + char buf[TCL_INTEGER_SPACE * 2]; + GetMaxSize(wmPtr, &width, &height); - sprintf(interp->result, "%d %d", width, height); + sprintf(buf, "%d %d", width, height); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_OK; } if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK) @@ -1485,8 +1522,10 @@ Tk_WmCmd(clientData, interp, argc, argv) return TCL_ERROR; } if (argc == 3) { - sprintf(interp->result, "%d %d", wmPtr->minWidth, - wmPtr->minHeight); + char buf[TCL_INTEGER_SPACE * 2]; + + sprintf(buf, "%d %d", wmPtr->minWidth, wmPtr->minHeight); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_OK; } if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK) @@ -1510,9 +1549,9 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) { - interp->result = "1"; + Tcl_SetResult(interp, "1", TCL_STATIC); } else { - interp->result = "0"; + Tcl_SetResult(interp, "0", TCL_STATIC); } return TCL_OK; } @@ -1537,9 +1576,9 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->sizeHintsFlags & USPosition) { - interp->result = "user"; + Tcl_SetResult(interp, "user", TCL_STATIC); } else if (wmPtr->sizeHintsFlags & PPosition) { - interp->result = "program"; + Tcl_SetResult(interp, "program", TCL_STATIC); } return TCL_OK; } @@ -1593,7 +1632,7 @@ Tk_WmCmd(clientData, interp, argc, argv) for (protPtr = wmPtr->protPtr; protPtr != NULL; protPtr = protPtr->nextPtr) { if (protPtr->protocol == protocol) { - interp->result = protPtr->command; + Tcl_SetResult(interp, protPtr->command, TCL_STATIC); return TCL_OK; } } @@ -1640,9 +1679,12 @@ Tk_WmCmd(clientData, interp, argc, argv) return TCL_ERROR; } if (argc == 3) { - sprintf(interp->result, "%d %d", + char buf[TCL_INTEGER_SPACE * 2]; + + sprintf(buf, "%d %d", (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) ? 0 : 1, (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) ? 0 : 1); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_OK; } if ((Tcl_GetBoolean(interp, argv[3], &width) != TCL_OK) @@ -1671,9 +1713,9 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->sizeHintsFlags & USSize) { - interp->result = "user"; + Tcl_SetResult(interp, "user", TCL_STATIC); } else if (wmPtr->sizeHintsFlags & PSize) { - interp->result = "program"; + Tcl_SetResult(interp, "program", TCL_STATIC); } return TCL_OK; } @@ -1705,15 +1747,15 @@ Tk_WmCmd(clientData, interp, argc, argv) return TCL_ERROR; } if (wmPtr->iconFor != NULL) { - interp->result = "icon"; + Tcl_SetResult(interp, "icon", TCL_STATIC); } else if (wmPtr->withdrawn) { - interp->result = "withdrawn"; + Tcl_SetResult(interp, "withdrawn", TCL_STATIC); } else if (Tk_IsMapped((Tk_Window) winPtr) || ((wmPtr->flags & WM_NEVER_MAPPED) && (wmPtr->hints.initial_state == NormalState))) { - interp->result = "normal"; + Tcl_SetResult(interp, "normal", TCL_STATIC); } else { - interp->result = "iconic"; + Tcl_SetResult(interp, "iconic", TCL_STATIC); } } else if ((c == 't') && (strncmp(argv[1], "title", length) == 0) && (length >= 2)) { @@ -1723,24 +1765,25 @@ Tk_WmCmd(clientData, interp, argc, argv) return TCL_ERROR; } if (argc == 3) { - interp->result = (wmPtr->title != NULL) ? wmPtr->title - : winPtr->nameUid; + Tcl_SetResult(interp, + ((wmPtr->title != NULL) ? wmPtr->title : winPtr->nameUid), + TCL_STATIC); return TCL_OK; } else { - if (wmPtr->title != NULL) { - ckfree(wmPtr->title); - } wmPtr->title = ckalloc((unsigned) (strlen(argv[3]) + 1)); strcpy(wmPtr->title, argv[3]); if (!(wmPtr->flags & WM_NEVER_MAPPED)) { XTextProperty textProp; + Tcl_DString ds; - if (XStringListToTextProperty(&wmPtr->title, 1, + Tcl_UtfToExternalDString(NULL, wmPtr->title, -1, &ds); + if (XStringListToTextProperty(&(Tcl_DStringValue(&ds)), 1, &textProp) != 0) { XSetWMName(winPtr->display, wmPtr->wrapperPtr->window, &textProp); XFree((char *) textProp.value); } + Tcl_DStringFree(&ds); } } } else if ((c == 't') && (strncmp(argv[1], "transient", length) == 0) @@ -1755,7 +1798,7 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->master != None) { - interp->result = wmPtr->masterWindowName; + Tcl_SetResult(interp, wmPtr->masterWindowName, TCL_STATIC); } return TCL_OK; } @@ -1810,8 +1853,9 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (XWithdrawWindow(winPtr->display, wmPtr->wrapperPtr->window, winPtr->screenNum) == 0) { - interp->result = - "couldn't send withdraw message to window manager"; + Tcl_SetResult(interp, + "couldn't send withdraw message to window manager", + TCL_STATIC); return TCL_ERROR; } WaitForMapNotify(winPtr, 0); @@ -2029,6 +2073,7 @@ ConfigureEvent(wmPtr, configEventPtr) { TkWindow *wrapperPtr = wmPtr->wrapperPtr; TkWindow *winPtr = wmPtr->winPtr; + TkDisplay *dispPtr = wmPtr->winPtr->dispPtr; /* * Update size information from the event. There are a couple of @@ -2046,7 +2091,7 @@ ConfigureEvent(wmPtr, configEventPtr) if (((wrapperPtr->changes.width != configEventPtr->width) || (wrapperPtr->changes.height != configEventPtr->height)) && !(wmPtr->flags & WM_SYNC_PENDING)){ - if (wmTracing) { + if (dispPtr->wmTracing) { printf("TopLevelEventProc: user changed %s size to %dx%d\n", winPtr->pathName, configEventPtr->width, configEventPtr->height); @@ -2110,7 +2155,7 @@ ConfigureEvent(wmPtr, configEventPtr) wmPtr->configHeight = configEventPtr->height; } - if (wmTracing) { + if (dispPtr->wmTracing) { printf("ConfigureEvent: %s x = %d y = %d, width = %d, height = %d", winPtr->pathName, configEventPtr->x, configEventPtr->y, configEventPtr->width, configEventPtr->height); @@ -2213,6 +2258,7 @@ ReparentEvent(wmPtr, reparentEventPtr) unsigned long numItems, bytesAfter; unsigned int dummy; Tk_ErrorHandler handler; + TkDisplay *dispPtr = wmPtr->winPtr->dispPtr; /* * Identify the root window for wrapperPtr. This is tricky because of @@ -2238,7 +2284,7 @@ ReparentEvent(wmPtr, reparentEventPtr) && (actualType == XA_WINDOW))) { if ((actualFormat == 32) && (numItems == 1)) { vRoot = wmPtr->vRoot = *virtualRootPtr; - } else if (wmTracing) { + } else if (dispPtr->wmTracing) { printf("%s format %d numItems %ld\n", "ReparentEvent got bogus VROOT property:", actualFormat, numItems); @@ -2247,7 +2293,7 @@ ReparentEvent(wmPtr, reparentEventPtr) } Tk_DeleteErrorHandler(handler); - if (wmTracing) { + if (dispPtr->wmTracing) { printf("ReparentEvent: %s reparented to 0x%x, vRoot = 0x%x\n", wmPtr->winPtr->pathName, (unsigned int) reparentEventPtr->parent, (unsigned int) vRoot); @@ -2344,6 +2390,7 @@ ComputeReparentGeometry(wmPtr) Window dummy2; Status status; Tk_ErrorHandler handler; + TkDisplay *dispPtr = wmPtr->winPtr->dispPtr; handler = Tk_CreateErrorHandler(wrapperPtr->display, -1, -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL); @@ -2410,7 +2457,7 @@ ComputeReparentGeometry(wmPtr) wmPtr->wrapperPtr->changes.x = x + wmPtr->xInParent; wmPtr->wrapperPtr->changes.y = y + wmPtr->yInParent; - if (wmTracing) { + if (dispPtr->wmTracing) { printf("wrapperPtr coords %d,%d, wmPtr coords %d,%d, offsets %d %d\n", wrapperPtr->changes.x, wrapperPtr->changes.y, wmPtr->x, wmPtr->y, wmPtr->xInParent, wmPtr->yInParent); @@ -2443,6 +2490,7 @@ WrapperEventProc(clientData, eventPtr) { WmInfo *wmPtr = (WmInfo *) clientData; XEvent mapEvent; + TkDisplay *dispPtr = wmPtr->winPtr->dispPtr; wmPtr->flags |= WM_VROOT_OFFSET_STALE; if (eventPtr->type == DestroyNotify) { @@ -2462,7 +2510,7 @@ WrapperEventProc(clientData, eventPtr) Tk_DestroyWindow((Tk_Window) wmPtr->winPtr); Tk_DeleteErrorHandler(handler); } - if (wmTracing) { + if (dispPtr->wmTracing) { printf("TopLevelEventProc: %s deleted\n", wmPtr->winPtr->pathName); } } else if (eventPtr->type == ConfigureNotify) { @@ -2725,7 +2773,7 @@ UpdateGeometryInfo(clientData) } wmPtr->configWidth = width; wmPtr->configHeight = height; - if (wmTracing) { + if (winPtr->dispPtr->wmTracing) { printf("UpdateGeometryInfo moving to %d %d, resizing to %d x %d,\n", x, y, width, height); } @@ -2746,7 +2794,7 @@ UpdateGeometryInfo(clientData) } wmPtr->configWidth = width; wmPtr->configHeight = height; - if (wmTracing) { + if (winPtr->dispPtr->wmTracing) { printf("UpdateGeometryInfo resizing to %d x %d\n", width, height); } XResizeWindow(winPtr->display, wmPtr->wrapperPtr->window, @@ -2947,7 +2995,7 @@ WaitForConfigureNotify(winPtr, serial) ConfigureNotify, &event); wmPtr->flags &= ~WM_SYNC_PENDING; if (code != TCL_OK) { - if (wmTracing) { + if (winPtr->dispPtr->wmTracing) { printf("WaitForConfigureNotify giving up on %s\n", winPtr->pathName); } @@ -2959,7 +3007,7 @@ WaitForConfigureNotify(winPtr, serial) } } wmPtr->flags &= ~WM_MOVE_PENDING; - if (wmTracing) { + if (winPtr->dispPtr->wmTracing) { printf("WaitForConfigureNotify finished with %s, serial %ld\n", winPtr->pathName, serial); } @@ -3135,14 +3183,14 @@ WaitForMapNotify(winPtr, mapped) * just quit. */ - if (wmTracing) { + if (winPtr->dispPtr->wmTracing) { printf("WaitForMapNotify giving up on %s\n", winPtr->pathName); } break; } } wmPtr->flags &= ~WM_MOVE_PENDING; - if (wmTracing) { + if (winPtr->dispPtr->wmTracing) { printf("WaitForMapNotify finished with %s\n", winPtr->pathName); } } @@ -3188,7 +3236,7 @@ UpdateHints(winPtr) * * Results: * A standard Tcl return value, plus an error message in - * interp->result if an error occurs. + * the interp's result if an error occurs. * * Side effects: * The size and/or location of winPtr may change. @@ -3441,6 +3489,7 @@ Tk_CoordsToWindow(rootX, rootY, tkwin) int x, y, childX, childY, tmpx, tmpy, bd; WmInfo *wmPtr; TkWindow *winPtr, *childPtr, *nextPtr; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; /* * Step 1: scan the list of toplevel windows to see if there is a @@ -3452,7 +3501,7 @@ Tk_CoordsToWindow(rootX, rootY, tkwin) parent = window = RootWindowOfScreen(Tk_Screen(tkwin)); x = rootX; y = rootY; - for (wmPtr = firstWmPtr; wmPtr != NULL; wmPtr = wmPtr->nextPtr) { + for (wmPtr = (WmInfo *) dispPtr->firstWmPtr; wmPtr != NULL; wmPtr = wmPtr->nextPtr) { if (Tk_Screen(wmPtr->winPtr) != Tk_Screen(tkwin)) { continue; } @@ -3487,7 +3536,8 @@ Tk_CoordsToWindow(rootX, rootY, tkwin) if (child == None) { return NULL; } - for (wmPtr = firstWmPtr; wmPtr != NULL; wmPtr = wmPtr->nextPtr) { + for (wmPtr = (WmInfo *) dispPtr->firstWmPtr; wmPtr != NULL; + wmPtr = wmPtr->nextPtr) { if (wmPtr->reparent == child) { goto gotToplevel; } @@ -3644,7 +3694,7 @@ UpdateVRootGeometry(wmPtr) (unsigned int *) &wmPtr->vRootWidth, (unsigned int *) &wmPtr->vRootHeight, (unsigned int *) &bd, &dummy); - if (wmTracing) { + if (winPtr->dispPtr->wmTracing) { printf("UpdateVRootGeometry: x = %d, y = %d, width = %d, ", wmPtr->vRootX, wmPtr->vRootY, wmPtr->vRootWidth); printf("height = %d, status = %d\n", wmPtr->vRootHeight, status); @@ -4818,3 +4868,63 @@ TkpGetWrapperWindow(winPtr) return wmPtr->wrapperPtr; } + +/* + *---------------------------------------------------------------------- + * + * UpdateCommand -- + * + * Update the WM_COMMAND property, taking care to translate + * the command strings into the external encoding. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +UpdateCommand(winPtr) + TkWindow *winPtr; +{ + register WmInfo *wmPtr = winPtr->wmInfoPtr; + Tcl_DString cmds, ds; + int i, *offsets; + char **cmdArgv; + + /* + * Translate the argv strings into the external encoding. To avoid + * allocating lots of memory, the strings are appended to a buffer + * with nulls between each string. + * + * This code is tricky because we need to pass and array of pointers + * to XSetCommand. However, we can't compute the pointers as we go + * because the DString buffer space could get reallocated. So, store + * offsets for each element as we go, then compute pointers from the + * offsets once the entire DString is done. + */ + + cmdArgv = (char **) ckalloc(sizeof(char *) * wmPtr->cmdArgc); + offsets = (int *) ckalloc( sizeof(int) * wmPtr->cmdArgc); + Tcl_DStringInit(&cmds); + for (i = 0; i < wmPtr->cmdArgc; i++) { + Tcl_UtfToExternalDString(NULL, wmPtr->cmdArgv[i], -1, &ds); + offsets[i] = Tcl_DStringLength(&cmds); + Tcl_DStringAppend(&cmds, Tcl_DStringValue(&ds), + Tcl_DStringLength(&ds)+1); + Tcl_DStringFree(&ds); + } + cmdArgv[0] = Tcl_DStringValue(&cmds); + for (i = 1; i < wmPtr->cmdArgc; i++) { + cmdArgv[i] = cmdArgv[0] + offsets[i]; + } + + XSetCommand(winPtr->display, wmPtr->wrapperPtr->window, + cmdArgv, wmPtr->cmdArgc); + Tcl_DStringFree(&cmds); + ckfree((char *) cmdArgv); + ckfree((char *) offsets); +} diff --git a/unix/tkUnixXId.c b/unix/tkUnixXId.c index 65dc5e0..833011c 100644 --- a/unix/tkUnixXId.c +++ b/unix/tkUnixXId.c @@ -12,12 +12,12 @@ * George C. Kaplan and Michael Hoegeman. * * Copyright (c) 1993 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixXId.c,v 1.2 1998/09/14 18:23:58 stanton Exp $ + * RCS: @(#) $Id: tkUnixXId.c,v 1.3 1999/04/16 01:51:48 stanton Exp $ */ /* @@ -28,9 +28,8 @@ #define XLIB_ILLEGAL_ACCESS 1 -#include "tkInt.h" -#include "tkPort.h" #include "tkUnixInt.h" +#include "tkPort.h" /* * A structure of the following type is used to hold one or more |