From: salome <> Date: Tue, 28 Sep 2004 09:41:16 +0000 (+0000) Subject: initial X-Git-Tag: V0^0 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=0ef55552ec69b1f196a76eff3707c430c5bc8315;p=tools%2Feficas.git initial --- 0ef55552ec69b1f196a76eff3707c430c5bc8315 diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 00000000..8f1fca6d --- /dev/null +++ b/Makefile.in @@ -0,0 +1,99 @@ +# -* Makefile *- +# +# Author : Patrick GOLDBRONN (CEA) +# Date : 28/06/2001 +# + +# source path +top_srcdir=@top_srcdir@ +top_builddir=. +srcdir=@srcdir@ +VPATH=.:@srcdir@:@top_srcdir@/bin:@top_srcdir@/resources:./bin:@top_srcdir@/idl + + +@COMMENCE@ + +SUBDIRS = src + +RESOURCES_FILES = \ +EFICASCatalog.xml \ +EFICAS_en.xml \ +eficashomard.png \ +eficas.png \ +eficaster.png + +BIN_SCRIPT= \ +VERSION + +# copy header files in common directory +ifeq ($(HAVE_SSTREAM),yes) + include_list=include/salome/SALOMEconfig.h +else + include_list=include/salome/SALOMEconfig.h include/salome/sstream +endif + +#inc: idl $(include_list) +inc: $(include_list) + +include/salome/SALOMEconfig.h: salome_adm/unix/SALOMEconfig.ref + -$(RM) $@ + $(LN_S) ../../$< $@ + +# test if SALOMEconfig.h has changed (contents) +salome_adm/unix/SALOMEconfig.ref: salome_adm/unix/SALOMEconfig.h + @if ! [ -a $@ ]; then \ + cp -p $< $@; \ + fi; \ + if ! cmp $< $@; then \ + cp -p $< $@; \ + fi; \ + +include/salome/sstream: salome_adm/unix/sstream + -$(RM) $@ + $(LN_S) ../../$< $@ + +#depend: depend_idl + +#depend_idl: +# (cd idl ; $(MAKE) $@) || exit 1 + +# doc is already build : if you want to had documents, go manually to doc and run 'make doc' +#doc: +# (cd doc && $(MAKE) $@) || exit 1 + +install-end: +# finish libtool install +# @$(LT) --mode=finish $(libdir) + +install-include: $(include_list) + $(INSTALL) -d $(includedir) + @for f in X $(include_list); do \ + if test $$f != X; then \ + ($(INSTALL_DATA) $$f $(includedir)/. || exit 1); \ + fi; \ + done + +# install script in $(bindir) : +install-bin: $(BIN_SCRIPT) + $(INSTALL) -d $(bindir) + if test $(BIN_SCRIPT)X != X; then \ + $(INSTALL_PROGRAM) $^ $(bindir); \ + fi + +#uninstall: uninstall-idl + +#uninstall-idl: +# $(RM) $(idldir)/*.idl + +distclean: distclean-other + +distclean-other: + -$(RM) salome_adm/unix/*~ salome_adm/unix/*% salome_adm/unix/*.bak salome_adm/unix/*.new salome_adm/unix/*.old + -$(RM) salome_adm/unix/make_* + -$(RM) salome_adm/unix/depend salome_adm/unix/SALOMEconfig.h + -$(RM) config.cache config.log config.status + +@MODULE@ + +install: install-bin install-include install-end + diff --git a/adm_local/unix/config_files/README b/adm_local/unix/config_files/README new file mode 100644 index 00000000..c9e7d6af --- /dev/null +++ b/adm_local/unix/config_files/README @@ -0,0 +1 @@ +this file is needed by cvs to create the directory \ No newline at end of file diff --git a/adm_local/unix/make_commence.in b/adm_local/unix/make_commence.in new file mode 100644 index 00000000..f6d5ea9c --- /dev/null +++ b/adm_local/unix/make_commence.in @@ -0,0 +1,249 @@ +# common directories to put headerfiles +inc_builddir=$(top_builddir)/include/salome + +@SET_MAKE@ +SHELL=/bin/sh + +# header missing + +HAVE_SSTREAM=@HAVE_SSTREAM@ + + +LIBS=@LIBS@ +LDFLAGS=@LDFLAGS@ -L$(top_builddir)/lib/salome -Xlinker -rpath-link -Xlinker -L$(top_builddir)/lib/salome +# add libstdc++ to link c++ library with libtool ! +LDFLAGS+= -lstdc++ + +CP=@CP@ + +# CPP + +CPP=@CPP@ +CXXCPP=@CXXCPP@ +CPPFLAGS=@CPPFLAGS@ -I$(inc_builddir) -I$(srcdir) -I. + +# C + +CC = @CC@ +CFLAGS = @CFLAGS@ +C_DEPEND_FLAG = @C_DEPEND_FLAG@ + +# C++ + +CXX = @CXX@ +CXXFLAGS = @CXXFLAGS@ +CXX_DEPEND_FLAG = @CXX_DEPEND_FLAG@ + +# JAVA + +JAVA_INCLUDES = @JAVA_INCLUDES@ +JAVA_LIBS = @JAVA_LIBS@ +JAVA_LDPATH = @JAVA_LDPATH@ + +# PYTHON + +PYTHON = @PYTHON@ +PYTHONHOME = @PYTHONHOME@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +PYTHON_VERSION = @PYTHON_VERSION@ +PYTHON_SITE = @PYTHON_SITE@ +PYTHON_SITE_INSTALL = @PYTHON_SITE_INSTALL@ + +# QT + +QT_ROOT = @QT_ROOT@ +QT_INCLUDES = @QT_INCLUDES@ +QT_MT_INCLUDES = @QT_INCLUDES@ -DQT_THREAD_SUPPORT +QT_LIBS = @QT_LIBS@ +QT_MT_LIBS = @QT_MT_LIBS@ + +MOC = @MOC@ +UIC = @UIC@ + + +#QWT + +QWT_INCLUDES=@QWT_INCLUDES@ +QWT_LIBS=@QWT_LIBS@ + +# SIP +SIP = @SIP@ +SIP_INCLUDES = @SIP_INCLUDES@ +SIP_LIBS = @SIP_LIBS@ + +# PYQT +PYQT_SIPS = @PYQT_SIPS@ +PYQT_LIBS = @PYQT_LIBS@ + +# openGL +OGL_INCLUDES=@OGL_INCLUDES@ +OGL_LIBS=@OGL_LIBS@ + +# VTK +VTK_INCLUDES=@VTK_INCLUDES@ +VTK_LIBS=@VTK_LIBS@ + +# HDF5 + +HDF5_INCLUDES=@HDF5_INCLUDES@ +HDF5_LIBS=@HDF5_LIBS@ +HDF5_MT_LIBS=@HDF5_MT_LIBS@ + +# MED2 + +MED2_INCLUDES=@MED2_INCLUDES@ +MED2_LIBS=@MED2_LIBS@ +MED2_MT_LIBS=@MED2_MT_LIBS@ + +# OpenCasCade + +OCC_INCLUDES=@CAS_CPPFLAGS@ +OCC_CXXFLAGS=@CAS_CXXFLAGS@ + +OCC_KERNEL_LIBS=@CAS_KERNEL@ +OCC_OCAF_LIBS=@CAS_OCAF@ +OCC_VIEWER_LIBS=@CAS_VIEWER@ +OCC_MODELER_LIBS=@CAS_MODELER@ +OCC_DATAEXCHANGE_LIBS=@CAS_DATAEXCHANGE@ +OCC_LIBS=@CAS_LDFLAGS@ + +# MPICH + +MPICH_INCLUDES=@MPICH_INCLUDES@ +MPICH_LIBS=@MPICH_LIBS@ + +# Swig C++ Python + +SWIG = @SWIG@ +SWIG_FLAGS = @SWIG_FLAGS@ -I$(inc_builddir) -I$(srcdir) -I. + +# OMNIORB + +OMNIORB_ROOT = @OMNIORB_ROOT@ +OMNIORB_INCLUDES = @OMNIORB_INCLUDES@ +OMNIORB_LIBS = @OMNIORB_LIBS@ +OMNIORB_CXXFLAGS = @OMNIORB_CXXFLAGS@ + +OMNIORB_IDL = @OMNIORB_IDL@ +OMNIORB_IDLCXXFLAGS = @OMNIORB_IDLCXXFLAGS@ +OMNIORB_IDLPYFLAGS = @OMNIORB_IDLPYFLAGS@ -I$(top_srcdir)/idl -I$(top_builddir)/idl -I$(KERNEL_ROOT_DIR)/idl/salome + +OMNIORB_IDL_CLN_H = @OMNIORB_IDL_CLN_H@ +OMNIORB_IDL_CLN_CXX = @OMNIORB_IDL_CLN_CXX@ +OMNIORB_IDL_CLN_OBJ = @OMNIORB_IDL_CLN_OBJ@ + +OMNIORB_IDL_SRV_H = @OMNIORB_IDL_SRV_H@ +OMNIORB_IDL_SRV_CXX = @OMNIORB_IDL_SRV_CXX@ +OMNIORB_IDL_SRV_OBJ = @OMNIORB_IDL_SRV_OBJ@ + +# Default ORB + +CORBA_ROOT = @CORBA_ROOT@ +CORBA_INCLUDES = @CORBA_INCLUDES@ +CORBA_LIBS = @CORBA_LIBS@ +CORBA_CXXFLAGS = @CORBA_CXXFLAGS@ + +IDLCXXFLAGS = -bcxx @IDLCXXFLAGS@ -I$(top_srcdir)/idl -I$(top_builddir)/idl -I$(KERNEL_ROOT_DIR)/idl/salome +IDLPYFLAGS = @IDLPYFLAGS@ + +IDL = @IDL@ + +IDL_CLN_H = @IDL_CLN_H@ +IDL_CLN_CXX = @IDL_CLN_CXX@ +IDL_CLN_OBJ = @IDL_CLN_OBJ@ + +IDL_SRV_H = @IDL_SRV_H@ +IDL_SRV_CXX = @IDL_SRV_CXX@ +IDL_SRV_OBJ = @IDL_SRV_OBJ@ + +CPPFLAGS+= $(CORBA_INCLUDES) +CXXFLAGS+= $(CORBA_CXXFLAGS) + +# add corba libs when link salome application ! +#LDFLAGS+= $(CORBA_LIBS) +LIBS+=$(CORBA_LIBS) + +## Shared libraries +LT_STATIC_EXEC=@LT_STATIC_EXEC@ +DYNAMIC_DIRS=@DYNAMIC_DIRS@ +LT_LIB=libtool +LT=$(top_builddir)/libtool +LT_COMPILE=$(LT) --mode=compile $(CC) +LT_LINK_LIB=$(LT_LIB) --mode=link $(CC) -rpath $(libdir) +LT_LINK_EXE=$(LT) --mode=link $(CC) $(LT_STATIC_EXEC) -dlopen self -rpath $(bindir) $(DYNAMIC_DIRS) +LT_RUN=$(LT) --mode=execute +LT_INSTALL_PROG=$(LT) --mode=install $(INSTALL_PROGRAM) +LT_INSTALL_LIB=$(LT) --mode=install $(INSTALL_DATA) +LT_UNINSTALL=$(LT) --mode=uninstall $(RM) + +INSTALL=@INSTALL@ +INSTALL_PROGRAM=@INSTALL_PROGRAM@ +INSTALL_DATA=@INSTALL_DATA@ + +# create a symbolic link (or a copie ?) +LN_S=@LN_S@ + +## Installation points +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@/salome +libdir=@libdir@/salome +# warning : if user give this path in configure we could have salome/salome :-( +includedir=@includedir@/salome +datadir=@datadir@/salome +idldir=$(prefix)/idl/salome +sharedpydir=@libdir@/python$(PYTHON_VERSION)/site-packages/salome/shared_modules + +docdir=$(datadir)/doc + +# +# begin of package rules +# + +.PHONY: all lib bin inc resources tests install uninstall dep depend depend_idl cleandep mostlyclean clean distclean + +.SUFFIXES: .cxx .cc .c .f .o .lo .idl .py .i .ui .po .qm + +all: + $(MAKE) inc + $(MAKE) depend_idl + $(MAKE) depend + $(MAKE) lib + $(MAKE) bin + $(MAKE) resources + +# +# add target to build administrative files +# + +Makefile: $(top_builddir)/config.status $(srcdir)/Makefile.in + cd $(top_builddir) ; ./config.status + +$(top_builddir)/config.status: $(top_srcdir)/configure + cd $(top_builddir) ; ./config.status --recheck + +# VPATH contain $(srcdir), so make configure is good in top_srcdir and we must add target configure otherwise :-) +ifneq ($(top_srcdir),$(srcdir)) +configure: $(top_srcdir)/configure +endif + +$(top_srcdir)/configure: $(top_srcdir)/configure.in $(top_srcdir)/aclocal.m4 + cd $(top_srcdir) ; autoconf + +$(top_srcdir)/configure.in: $(top_srcdir)/configure.in.base + cd $(top_srcdir) && ./build_configure + + +ACLOCAL_SRC = \ +ac_cxx_bool.m4 check_corba.m4 check_vtk.m4 \ +ac_cxx_depend_flag.m4 check_hdf5.m4 enable_pthreads.m4 \ +ac_cxx_mutable.m4 check_mico.m4 libtool.m4 \ +ac_cxx_namespaces.m4 check_omniorb.m4 pyembed.m4 \ +ac_cxx_partial_specialization.m4 check_opengl.m4 python.m4 \ +ac_cxx_typename.m4 check_pthreads.m4 check_cas.m4 \ +ac_cc_warnings.m4 check_qt.m4 check_med2.m4 \ +check_swig.m4 + +$(top_srcdir)/aclocal.m4: $(ACLOCAL_SRC:%=@KERNEL_ROOT_DIR@/salome_adm/unix/config_files/%) + cd $(top_srcdir) ; aclocal --acdir=adm_local/unix/config_files -I @KERNEL_ROOT_DIR@/salome_adm/unix/config_files diff --git a/adm_local/unix/make_omniorb.in b/adm_local/unix/make_omniorb.in new file mode 100644 index 00000000..91cfe574 --- /dev/null +++ b/adm_local/unix/make_omniorb.in @@ -0,0 +1,53 @@ +#======================================================================= +# Begin specific part to omniorb +# (include from file adm/unix/make_omniorb generated by +# adm/unix/make_omniorb.in) +#======================================================================= +# -* Makefile *- +# +# Author : Patrick GOLDBRONN (CEA) +# Date : 29/06/2001 +# $Header: /home/salome/PlateFormePAL/Bases_CVS_EDF/Modules_EDF/ASTER_SRC/adm_local/unix/make_omniorb.in,v 1.1.1.1 2003/09/23 17:30:26 salome Exp $ +# + +# Client and server object are the same with omniorb +# There are one header file and one source file generate + +#IDLOBJ=$(IDLSRC:%.idl=%$(IDL_CLN_OBJ)) + +# dependancies between idl and it's generated files +%$(OMNIORB_IDL_CLN_CXX) %$(OMNIORB_IDL_CLN_H): ${KERNEL_ROOT_DIR}/idl/salome/%.idl + $(OMNIORB_IDL) $(IDLCXXFLAGS) $(OMNIORB_IDLCXXFLAGS) $< + +%$(OMNIORB_IDL_CLN_CXX) %$(OMNIORB_IDL_CLN_H): ${top_srcdir}/idl/%.idl + $(OMNIORB_IDL) $(IDLCXXFLAGS) $(OMNIORB_IDLCXXFLAGS) $< + +# dependncies between idl files +depend_idl: .depidl + +# we use cpp to generate dependencies between idl files. +# we change cpp output to keep only idl file and transform it to get a suitable rule +.depidl: $(IDL_FILES) + @touch $@ + @for dep in $? dummy; do \ + if [ $$dep != "dummy" ]; then \ + echo Building dependencies for $$dep; \ + basedep=`basename $$dep .idl`; \ + header="$$basedep"$(IDL_CLN_H); \ + sed '\%^'"$$header"':%,\%[^\\]$$%d' <$@ >$@- && mv $@- $@; \ + $(CPP) $(C_DEPEND_FLAG) -I$(srcdir) $$dep 2>/dev/null | \ + sed `echo "s%$$basedep\\.idl%$$header:%g"` | \ + sed 's% $(srcdir)/% %g' | \ + sed 's% $(top_srcdir)/% %g' | \ + sed 's% $(top_builddir)/% %g' | \ + sed 's%^.*:\.o: *%%' | sed 's%^ *\\ *%%'| sed 's%^ *\(.*\):%\1:%' | \ + sed 's/\.idl/$(IDL_CLN_H)/' >>$@; \ + echo '' >>$@; \ + fi; \ + done ; + +-include .depidl + +#======================================================================= +# End specific part to omniorb +#======================================================================= diff --git a/bin/VERSION b/bin/VERSION new file mode 100755 index 00000000..995a6692 --- /dev/null +++ b/bin/VERSION @@ -0,0 +1 @@ +THIS IS SALOME 2 RNTL - TESTPQT VERSION: 1.1a diff --git a/build_configure b/build_configure new file mode 100755 index 00000000..e95b0ad1 --- /dev/null +++ b/build_configure @@ -0,0 +1,216 @@ +#!/bin/bash + +# +# Tool for updating list of .in file for the SALOME project +# and regenerating configure script +# +# Author : Marc Tajchman - CEA +# Date : 10/10/2002 +# $Header $ +# + +ORIG_DIR=`pwd` +CONF_DIR=`echo $0 | sed -e "s,[^/]*$,,;s,/$,,;s,^$,.,"` + +######################################################################## +# Test if the KERNEL_ROOT_DIR is set correctly + +if test ! -d "${KERNEL_ROOT_DIR}"; then + echo "failed : KERNEL_ROOT_DIR variable is not correct !" + exit +fi + +# Test if the KERNEL_SRC is set correctly + +#if test ! -d "${KERNEL_SRC}"; then +# echo "failed : KERNEL_SRC variable is not correct !" +# exit +#fi +######################################################################## +# find_in - utility function +# +# usage : +# find_in directory filename +# +# Finds files following the *.in pattern, recursively in the +# directory (first argument). +# Results are appended into the file (second argument) +# +# Difference from the standard unix find is that files are tested +# before directories +# + +find_in() +{ + local i + local f=$2 + +# if the first argument is not a directory, returns + + if [ ! -d "$1" ] ; then + return + fi + +# dont look in the CVS directories + + case $1 in + */CVS) return ;; + *) ;; + esac + +# for each regular file contained in the directory +# test if it's a .in file + + for i in "$1"/* + do + if [ -f "$i" ] ; then + case $i in + *.in) echo " "$i" \\" >> $f;; + *) ;; + esac + fi + done + +# for each subdirectory of the first argument, proceeds recursively + + for i in "$1"/* + do + if [ -d "$i" ] ; then + find_in "$i" "$f" + fi + done +} + + +####################################################################### +# Generate list of .in files (Makefile.in, config.h.in, etc) +# appending it in file configure.in + +cd ${CONF_DIR} +ABS_CONF_DIR=`pwd` + +# +# Common part of the configure.in file +# +chmod u+w configure.in.base +if ! \cp -f configure.in.base configure.in_tmp1 +then + echo + echo "error : can't create files in" ${CONF_DIR} + echo "aborting ..." + chmod u-w configure.in.base + exit +fi +chmod u-w configure.in.base + +if [ -e "${CONF_DIR}/salome_adm" ] ; then + \rm -f ${CONF_DIR}/salome_adm +fi + +# make a link allowing AC_OUTPUT to find the salome_adm/.../*.in files +echo "" >> configure.in_tmp1 +echo 'ln -fs ${KERNEL_ROOT_DIR}/salome_adm ${ROOT_SRCDIR}' >> configure.in_tmp1 + +echo "" >> configure.in_tmp1 +echo "AC_OUTPUT([ \\" >> configure.in_tmp1 + +# +# List of .in files in the adm/unix directory +# These files MUST be on top of AC_OUTPUT list so we +# put them "manually" +# + +echo " ./salome_adm/unix/SALOMEconfig.h \\" >> configure.in_tmp1 +echo " ./salome_adm/unix/F77config.h \\" >> configure.in_tmp1 +echo " ./salome_adm/unix/sstream \\" >> configure.in_tmp1 +echo " ./salome_adm/unix/depend \\" >> configure.in_tmp1 +#echo " ./salome_adm/unix/make_omniorb \\" >> configure.in_tmp1 +echo " ./adm_local/unix/make_omniorb \\" >> configure.in_tmp1 +echo " ./salome_adm/unix/envScript \\" >> configure.in_tmp1 +#echo " ./salome_adm/unix/make_commence \\" >> configure.in_tmp1 +echo " ./adm_local/unix/make_commence \\" >> configure.in_tmp1 +echo " ./salome_adm/unix/make_conclude \\" >> configure.in_tmp1 +#echo " ./adm_local/unix/make_conclude \\" >> configure.in_tmp1 +echo " ./salome_adm/unix/make_module \\" >> configure.in_tmp1 + +\rm -f configure.in_tmp2 +touch configure.in_tmp2 +find_in . configure.in_tmp2 + +sed -e '/^ .\/salome_adm/d' \ + -e '/configure.in/d' \ + -e '/^ .\/adm_local/d' \ + -e 's/.in / /' \ + configure.in_tmp2 >> configure.in_tmp1 + +echo "])" >> configure.in_tmp1 + +# delete the link created for AC_OUTPUT +echo "" >> configure.in_tmp1 +#echo 'rm -f ${ROOT_SRCDIR}/salome_adm' >> configure.in_tmp1 +\mv configure.in_tmp1 configure.in_new +\rm -f configure.in_tmp2 + + +######################################################################## +# Create new (or replace old) configure.in file +# Print a message if the file is write protected +# + +echo +if test ! -f configure.in +then + echo -n "Creating new file 'configure.in' ... " + if \mv configure.in_new configure.in >& /dev/null + then + echo "done" + else + echo "error, check your file permissions" + fi +else + echo -n "Updating 'configure.in' file ... " + if ! \cp configure.in configure.in_old >& /dev/null + then + echo + echo + echo "Can't backup previous configure.in" + echo -n "Continue (you will not be able to revert) - (Y/N) ? " + read R + case "x$R" in + xn*) exit;; + xN*) exit;; + esac + echo + echo -n " " + fi + if \cp configure.in_new configure.in >& /dev/null + then + echo "done" + else + echo + echo "error, can't update previous configure.in" + fi +fi + +######################################################################## +# Use autoconf to rebuild the configure script +# + +if test -f configure +then + echo -n "Updating 'configure' script ... " +else + echo -n "Creating 'configure' script ... " +fi + +aclocal --acdir=adm_local/unix/config_files -I ${KERNEL_ROOT_DIR}/salome_adm/unix/config_files +if autoconf +then + echo "done" +else + echo "failed (check file permissions and/or user quotas ...)" +fi + +cd ${ORIG_DIR} + +echo diff --git a/doc/Makefile.in b/doc/Makefile.in new file mode 100644 index 00000000..069960a6 --- /dev/null +++ b/doc/Makefile.in @@ -0,0 +1,32 @@ + +# -* Makefile *- +# +# Author : Patrick GOLDBRONN (CEA) +# Date : 30/11/2001 +# +# source path +top_srcdir=@top_srcdir@ +top_builddir=.. +srcdir=@srcdir@ +VPATH=.:@srcdir@ + +SUBDIRS= + +doc: + @@SETX@; for d in $(SUBDIRS); do \ + (cd $$d && $(MAKE) $@) || exit 1; \ + done +clean: + @@SETX@; for d in $(SUBDIRS); do \ + (cd $$d && $(MAKE) $@) || exit 1; \ + done + +distclean: clean + @@SETX@; for d in $(SUBDIRS); do \ + (cd $$d && $(MAKE) $@) || exit 1; \ + done + +install: + @@SETX@; for d in $(SUBDIRS); do \ + (cd $$d && $(MAKE) $@) || exit 1; \ + done diff --git a/resources/EFICASCatalog.xml b/resources/EFICASCatalog.xml new file mode 100644 index 00000000..2568f668 --- /dev/null +++ b/resources/EFICASCatalog.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + EFICAS + EFICAS GUI + Data + P.RASCLE + 1.0 + EDF - RD + 1 + eficas.png + 'linux' ~ OS + + + diff --git a/resources/EFICAS_en.xml b/resources/EFICAS_en.xml new file mode 100644 index 00000000..617dac71 --- /dev/null +++ b/resources/EFICAS_en.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/eficas.png b/resources/eficas.png new file mode 100644 index 00000000..081f72e8 Binary files /dev/null and b/resources/eficas.png differ diff --git a/resources/eficashomard.png b/resources/eficashomard.png new file mode 100644 index 00000000..8df8f604 Binary files /dev/null and b/resources/eficashomard.png differ diff --git a/resources/eficaster.png b/resources/eficaster.png new file mode 100644 index 00000000..8ceb9f9a Binary files /dev/null and b/resources/eficaster.png differ diff --git a/src/EFICASGUI/.param_etude.skel b/src/EFICASGUI/.param_etude.skel new file mode 100644 index 00000000..d7367e26 --- /dev/null +++ b/src/EFICASGUI/.param_etude.skel @@ -0,0 +1,13 @@ +# Fichier adlv100a.para : regroupe les paramètres d'exécution de l'étude + +masterdir = "%(REP_ETUDE)s" +etude = "%(ETUDE)s" +prof_etd = ( +("comm","%(COMMAND_FILE_NAME)s","%(LOCAL_USER)s","%(LOCAL_MACHINE)s","1.i","D"), +("med","%(MESH_FILE_NAME)s","%(LOCAL_USER)s","%(LOCAL_MACHINE)s","21","D"), +("resu","%(REP_ETUDE)s/%(ETUDE)s.resu","%(LOCAL_USER)s","%(LOCAL_MACHINE)s","8","R"), +("med","%(REP_ETUDE)s/%(ETUDE)s.med","%(LOCAL_USER)s","%(LOCAL_MACHINE)s","80","R"), +("mess","%(REP_ETUDE)s/%(ETUDE)s.mess","%(LOCAL_USER)s","%(LOCAL_MACHINE)s","6","R"), +("unv","%(REP_ETUDE)s/%(ETUDE)s.unv","%(LOCAL_USER)s","%(LOCAL_MACHINE)s","30","R"), +("base","%(REP_ETUDE)s/%(ETUDE)s.base","%(LOCAL_USER)s","%(LOCAL_MACHINE)s","40","R"), +) diff --git a/src/EFICASGUI/EFICASGUI.py b/src/EFICASGUI/EFICASGUI.py new file mode 100644 index 00000000..59852ca8 --- /dev/null +++ b/src/EFICASGUI/EFICASGUI.py @@ -0,0 +1,104 @@ +""" + Interface PyQt +""" +import qt +import libSALOME_Swig +import SalomePyQt + +# Variable globale pour stocker le Workspace de Salome + +WORKSPACE=None +studyId=None + +# ----------------------------------------------------------------------------- + +import notifqt +#import Tkinter +#root=Tkinter.Tk() +#root.withdraw() + +def g(): + print "lastWindowClosed()" + root.destroy() + +qt.QObject.connect(qt.qApp,qt.SIGNAL("lastWindowClosed()"),g) + +# ----------------------------------------------------------------------------- + +import salome + +sg=salome.SalomeGUI() +sgPyQt=SalomePyQt.SalomePyQt() +print "EFicasGUI :: :::::::::::::::::::::::::::::::::::::::::::::::::::::" + +# ----------------------------------------------------------------------------- + +def setWorkSpace(workSpace): + print "EficasGUI --- setWorkSpace" + global WORKSPACE + print workSpace + WORKSPACE=workSpace + print "WORKSPACE: ",WORKSPACE + # le desktop + d=sgPyQt.getDesktop() + + # creation d'une message box + #qt.QMessageBox.information(d,"titre","message") + + # recuperation du workspace + ws=sgPyQt.getMainFrame() + print ws + +# ----------------------------------------------------------------------------- + +def OnGUIEvent(commandID) : + print "EficasGUI :: OnGUIEvent :::::::::::::::::::::::::::::::::commandID,WORKSPACE = ",commandID,WORKSPACE + if dict_command.has_key(commandID): + print "OnGUIEvent :::::::::: commande associée : ",commandID + dict_command[commandID](WORKSPACE) + else: + print "Pas de commande associée a : ",commandID + +# ----------------------------------------------------------------------------- + +def setSettings(): + print "setSettings" + print sgPyQt.getStudyId() + +# ----------------------------------------------------------------------------- + +def activeStudyChanged(ID): + global studyId + # ne marche pas car sg est supposé résider dans une etude + # studyId=sg.getActiveStudyId() + studyId=ID + print "studyId: ",sg.getActiveStudyId() + print "On a changé d'étude active",studyId + print sgPyQt.getStudyId() + + +# ----------------------------------------------------------------------------- + +import eficasSalome + +def runEficas(ws): + print "runEficas" + eficasSalome.runEficas(ws,"ASTER") + +def runEficaspourHomard(ws): + print "runEficas" + eficasSalome.runEficas(ws,"HOMARD") + +def runEficasHomard(): + print "runEficas" + eficasSalome.runEficas(None,"HOMARD") + +# Partie applicative + +dict_command={ + 941:runEficas, + 946:runEficaspourHomard, + 4041:runEficas, + 4046:runEficaspourHomard, + } + diff --git a/src/EFICASGUI/EFICAS_icons.po b/src/EFICASGUI/EFICAS_icons.po new file mode 100644 index 00000000..b386757a --- /dev/null +++ b/src/EFICASGUI/EFICAS_icons.po @@ -0,0 +1,11 @@ +# This is a Qt message file in .po format. Each msgid starts with +# a scope. This scope should *NOT* be translated - eg. "Foo::Bar" +# would be translated to "Pub", not "Foo::Pub". +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"POT-Creation-Date: 2002-05-28 10:57:43 AM CEST\n" +"PO-Revision-Date: YYYY-MM-DD\n" +"Last-Translator: FULLNAME \n" +"Content-Type: text/plain; charset=iso-8859-1\n" + diff --git a/src/EFICASGUI/EFICAS_msg_en.po b/src/EFICASGUI/EFICAS_msg_en.po new file mode 100644 index 00000000..b386757a --- /dev/null +++ b/src/EFICASGUI/EFICAS_msg_en.po @@ -0,0 +1,11 @@ +# This is a Qt message file in .po format. Each msgid starts with +# a scope. This scope should *NOT* be translated - eg. "Foo::Bar" +# would be translated to "Pub", not "Foo::Pub". +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"POT-Creation-Date: 2002-05-28 10:57:43 AM CEST\n" +"PO-Revision-Date: YYYY-MM-DD\n" +"Last-Translator: FULLNAME \n" +"Content-Type: text/plain; charset=iso-8859-1\n" + diff --git a/src/EFICASGUI/Makefile.in b/src/EFICASGUI/Makefile.in new file mode 100644 index 00000000..b4a1bc67 --- /dev/null +++ b/src/EFICASGUI/Makefile.in @@ -0,0 +1,55 @@ +#============================================================================== +# File : Makefile.in +# Created : dim déc 9 18:35:11 CET 2001 +# Author : Paul RASCLE, EDF +# Project : SALOME +# Copyright : EDF 2001 +#============================================================================== + +# source path +top_srcdir=@top_srcdir@ +top_builddir=../.. +srcdir=@srcdir@ +VPATH=.:@srcdir@:@top_srcdir@/idl:$(top_builddir)/idl:${KERNEL_ROOT_DIR}/idl/salome + + +@COMMENCE@ + +# header files +EXPORT_HEADERS= + + +# Libraries targets + +LIB = +LIB_SRC = + +LIB_CLIENT_IDL = + +LIB_SERVER_IDL = + +# .po files to transform in .qm +PO_FILES = EFICAS_msg_en.po EFICAS_icons.po + +EXPORT_PYSCRIPTS = \ +dataEficas.py \ +eficasEtude.py \ +EFICASGUI.py \ +salomedsgui.py \ +SMESH_utils.py \ +eficasSalome.py + +PYUIC = pyuic + +%.py:%.ui + $(PYUIC) $< -o $@ + +# additionnal information to compil and link file + +CPPFLAGS += $(QT_INCLUDES) $(VTK_INCLUDES) $(OCC_INCLUDES) $(PYTHON_INCLUDES) $(SIP_INCLUDES) +CPPFLAGS += -I$(top_builddir)/SALOME/src/SALOME_PYQT +CXXFLAGS += + +LDFLAGS += $(PYTHON_LIBS) $(PYQT_LIBS) -lSalomeGUI + +@CONCLUDE@ diff --git a/src/EFICASGUI/SMESH_utils.py b/src/EFICASGUI/SMESH_utils.py new file mode 100644 index 00000000..d9c097db --- /dev/null +++ b/src/EFICASGUI/SMESH_utils.py @@ -0,0 +1,164 @@ +#============================================================================= +# File : SMESH_utils.py +# Created : jeu fév 20 18:53:34 CET 2003 +# Author : Paul RASCLE, EDF +# Project : SALOME +# Copyright : EDF 2003 +# $Header: /home/salome/PlateFormePAL/Bases_CVS_EDF/Modules_EDF/ASTER_SRC/src/ASTER/SMESH_utils.py,v 1.1.1.1.2.1 2004/05/18 11:40:20 salome Exp $ +#============================================================================= + +from omniORB import CORBA +import LifeCycleCORBA +import SALOMEDS +import GEOM +import SMESH + +# initialise the ORB +orb = CORBA.ORB_init([''], CORBA.ORB_ID) + +# create an LifeCycleCORBA instance +lcc = LifeCycleCORBA.LifeCycleCORBA(orb) + +geom = lcc.FindOrLoadComponent("FactoryServer", "GEOM") +smesh = lcc.FindOrLoadComponent("FactoryServer", "SMESH") + + #-------------------------------------------------------------------------- + +def entryToIor(myStudy,entry): + myBuilder = myStudy.NewBuilder() + ior = None + SO = None + try: + SO = myStudy.FindObjectID(entry) + except: + print "invalid entry: ",entry + SO = None + if SO != None: + boo,iorso = myBuilder.FindAttribute(SO,"AttributeIOR") + if boo == 0: + print "no IOR attribute on study object: ", entry + else: + iorString = iorso.Value() + print iorString + ior = orb.string_to_object(iorString) + return ior + + #-------------------------------------------------------------------------- + +def entryToName2(myStudy,entry): + myBuilder = myStudy.NewBuilder() + name =[] + SO = None + try: + SO = myStudy.FindObjectID(entry) + except: + print "invalid entry: ",entry + SO = None + if SO != None: + boo,nameso = myBuilder.FindAttribute(SO,"AttributeName") + if boo == 0: + print "no Name attribute on study object: ", entry + else: + name.append(nameso.Value()) + return name + +def entryToName(myStudy,entryList): + myBuilder = myStudy.NewBuilder() + name =[] + SO = None + for entry in entryList: + try: + SO = myStudy.FindObjectID(entry) + except: + print "invalid entry: ",entry + SO = None + if SO != None: + boo,nameso = myBuilder.FindAttribute(SO,"AttributeName") + if boo == 0: + print "no Name attribute on study object: ", entry + else: + name.append(nameso.Value()) + return name + + + #-------------------------------------------------------------------------- + +def getMainShape(myStudy,entry): + anObject=entryToIor(myStudy,entry) + subShape=anObject._narrow(GEOM.GEOM_Shape) + if subShape == None: + print "entry does not give a shape: ", entry + return None + isMain=subShape._get_IsMainShape() + if isMain: + iorMain=subShape + else: + iorStringMain=subShape._get_MainName() + iorMain = orb.string_to_object(iorStringMain) + return iorMain + + +def getMainShapeName(myStudy,entry): + anObject=entryToIor(myStudy,entry) + subShape=anObject._narrow(GEOM.GEOM_Shape) + if subShape == None: + print "entry does not give a shape: ", entry + return None + isMain=subShape._get_IsMainShape() + if isMain: + iorMain=subShape + else: + iorStringMain=subShape._get_MainName() + iorMain = orb.string_to_object(iorStringMain) + stringior= orb.object_to_string(iorMain) + return stringior + #-------------------------------------------------------------------------- + +def getSMESHSubShapeIndexes(myStudy, entryList, typenoeudorcell = 0): + # typenoeudorcell = 0 on traite des noeuds + # typenoeudorcell = 1 on traite des faces + refList = [] + subShapeIndexes = [] + if len(entryList) > 0: + iorMain = getMainShapeName(myStudy, entryList[0]) + + myCL=smesh.GetOrCreateCL(str(iorMain)) + + if len(entryList) > 0: + for idShape in entryList: + print "idShape" + print idShape + refShape = entryToName2(myStudy,idShape) + if refShape != None: + for Shape in refShape: + refList.append(Shape) + IORShape = entryToIor(myStudy,idShape) + myCL.SetIdAsCL(orb.object_to_string(IORShape),typenoeudorcell) + + studyId = myStudy._get_StudyId() + return refList + + #-------------------------------------------------------------------------- + +def getAsterGroupNo(myStudy,entryList): + typenoeudorcell = 0 + subShapeIndexes = getSMESHSubShapeIndexes(myStudy, entryList,typenoeudorcell) + labelGroupNo = [] + for val in subShapeIndexes: + labelGroupNo.append(val) + return labelGroupNo + + #-------------------------------------------------------------------------- + +def getAsterGroupMa(myStudy,entryList): + typenoeudorcell = 1 + subShapeIndexes = getSMESHSubShapeIndexes(myStudy, entryList,typenoeudorcell) + labelGroupMa = [] + for val in subShapeIndexes: + #label="GMM%d"%(val) + labelGroupMa.append(val) + print labelGroupMa + return labelGroupMa + + #-------------------------------------------------------------------------- + diff --git a/src/EFICASGUI/dataEficas.py b/src/EFICASGUI/dataEficas.py new file mode 100644 index 00000000..9450b9af --- /dev/null +++ b/src/EFICASGUI/dataEficas.py @@ -0,0 +1,36 @@ +import sys,os + +eficas_root=os.environ["EFICAS_ROOT"] + +sys.path[:0]=[os.path.join(eficas_root,'Aster'), + os.path.join(eficas_root,'Homard'), + eficas_root, + os.path.join(eficas_root,'Editeur'), + ] + +# Modules Python +import Tkinter + +# Modules Eficas +import import_code +import splash + + +def init(top,code="ASTER"): + splash.init_splash(top,code=code,titre="Lancement d'EFICAS pour %s" %code) + splash._splash.configure(text="Chargement d'EFICAS en cours.\n Veuillez patienter ...") + # Enregistrement dans l étude + import eficasEtude + MaRef=eficasEtude.Eficas_In_Study() + + import eficas + class MyEficas(eficas.EFICAS): + def quit(self): + eficas.EFICAS.quit(self) + self.top.destroy() + + def contexte(self): + self.salome=MaRef + + moi=MyEficas(top,code=code) + moi.contexte() diff --git a/src/EFICASGUI/eficasEtude.py b/src/EFICASGUI/eficasEtude.py new file mode 100644 index 00000000..c2a9d394 --- /dev/null +++ b/src/EFICASGUI/eficasEtude.py @@ -0,0 +1,52 @@ +#============================================================================= +# File : EficasEtude.py +# Created : mar fév 25 09:48:34 CET 2003 +# Author : Pascale NOYRET, EDF +# Project : SALOME +# Copyright : EDF 2003 +# $Header: /home/salome/PlateFormePAL/Bases_CVS_EDF/Modules_EDF/ASTER_SRC/src/ASTERGUI/eficasEtude.py,v 1.1.1.1.2.1 2004/05/18 11:40:21 salome Exp $ +#============================================================================= + +import salome +import re +from tkFileDialog import asksaveasfilename + +import salomedsgui +aGuiDS=salomedsgui.guiDS() + +#-------------------------------------------------------------------------- + +class Eficas_In_Study: + + def __init__(self): + import SMESH_utils + self.enregistre() + self.liste_deja_la=[] + + def enregistre(self): + self.fatherId=aGuiDS.enregistre("Eficas") + salome.sg.updateObjBrowser(0) + + def rangeInStudy(self,fichier): + if fichier not in self.liste_deja_la : + self.liste_deja_la.append(fichier) + Nom=re.split("/",fichier)[-1] + + self.commId=aGuiDS.createItemInStudy(self.fatherId,Nom) + aGuiDS.setExternalFileAttribute(self.commId,"FICHIER_EFICAS",fichier) + salome.sg.updateObjBrowser(0) + + def creeConfigTxt(self,fichier,dico): + sauvegarde = asksaveasfilename(title="fichier config.txt", + defaultextension='.txt', + initialdir = fichier) + f=open(sauvegarde,'w+') + for unite in dico.keys(): + print unite + type=dico[unite][0] + fic=dico[unite][1:] + ligne="fort."+str(unite)+" "+type+" "+fic + f.write(ligne) + f.close() + self.rangeInStudy(sauvegarde) + diff --git a/src/EFICASGUI/eficasSalome.py b/src/EFICASGUI/eficasSalome.py new file mode 100644 index 00000000..964a7068 --- /dev/null +++ b/src/EFICASGUI/eficasSalome.py @@ -0,0 +1,43 @@ +import qt +import notifqt +# ----------------------------------------------------------------------------- +import sys + +# Remplacement de la fonction exit standard par une fonction +# qui n'interrompt pas l'execution +sys._exit=sys.exit + +def exit(ier): + print "appel de exit: ",ier + +sys.exit=exit +# Fin remplacement + +initialised=0 +import Tkinter +root=Tkinter.Tk() +root.withdraw() + + +def runEficas(ws,code="ASTER"): + global initialised + if not initialised: + t=Tkinter.Toplevel() + t.withdraw() + print t.geometry() + print t.winfo_geometry() + import dataEficas; dataEficas.init(t,code) + t.update() + print t.geometry() + print t.winfo_geometry() + t.deiconify() + t.update() + + #initialised=1 + +def runHomard() : + runEficas(None,"HOMARD") + +def runAster() : + runEficas(None,"ASTER") + diff --git a/src/EFICASGUI/salomedsgui.py b/src/EFICASGUI/salomedsgui.py new file mode 100644 index 00000000..d30549c9 --- /dev/null +++ b/src/EFICASGUI/salomedsgui.py @@ -0,0 +1,154 @@ +# Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +# CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org +# +# +# +# File : salomedsgui.py +# Author : Paul RASCLE, EDF +# Module : KERNEL +# +#-------------------------------------------------------------------------- + +import salome +import SALOMEDS +import string,os + +class guiDS: + """ + Study (SALOMEDS) interface from python gui (ex: IAPP embedded PyQt GUI) + """ + _myStudyManager = None + _myStudy = None + _myBuilder = None + _father = None + _component = None + + def __init__(self): + self._myStudyManager = salome.myStudyManager + self._myStudy = salome.myStudy + self._myBuilder = self._myStudy.NewBuilder() + + def enregistre(self,myModule): + if self._father is None: + father = self._myStudy.FindComponent(myModule) + if father is None: + father = self._myBuilder.NewComponent(myModule) + A1 = self._myBuilder.FindOrCreateAttribute(father,"AttributeName") + FName = A1._narrow(SALOMEDS.AttributeName) + FName.SetValue(myModule) + self._father = father + self._component = myModule + return self._father.GetID() + + def createItemInStudy(self,fatherId,objectName): + objId = None + if self._component is not None: + listSO = self._myStudy.FindObjectByName(objectName,self._component) + if len(listSO) == 0: + father = self._myStudy.FindObjectID(fatherId) + newObj = self._myBuilder.NewObject(father) + A1= self._myBuilder.FindOrCreateAttribute(newObj,"AttributeName") + FName = A1._narrow(SALOMEDS.AttributeName) + FName.SetValue(objectName) + objId = newObj.GetID() + return objId + + def getReference(self,objectId): + mySO = self._myStudy.FindObjectID(objectId) + boo,RefSO = mySO.ReferencedObject() + if boo: + objectId=RefSO.GetID() + return objectId + + def addReference(self,fatherId,refId): + father = self._myStudy.FindObjectID(fatherId) + ref = self._myStudy.FindObjectID(refId) + newObj = self._myBuilder.NewObject(father) + A1 = self._myBuilder.FindOrCreateAttribute(ref,"AttributeName") + FName = A1._narrow(SALOMEDS.AttributeName) + Name_ref = FName.Value() + path_father , none = string.split(self._myStudy.GetObjectPath(ref),Name_ref) + path_father , none = os.path.split(path_father) + #print "salomedsgui::addReference : path_father_ref = ",path_father + #print "salomedsgui::addReference : Path_father = ",self._myStudy.GetObjectPath(father) + if self._myStudy.GetObjectPath(father) != path_father : + self._myBuilder.Addreference(newObj,ref) + + def setExternalFileAttribute(self,objectId,filetype,filename): + mySO = self._myStudy.FindObjectID(objectId) + A1 = self._myBuilder.FindOrCreateAttribute(mySO,"AttributeExternalFileDef") + AFileName = A1._narrow(SALOMEDS.AttributeExternalFileDef) + AFileName.SetValue(filename) + print filename + A2 = self._myBuilder.FindOrCreateAttribute(mySO,"AttributeFileType") + AFileType = A2._narrow(SALOMEDS.AttributeFileType) + print filetype + AFileType.SetValue(filetype) + print filetype + + def getExternalFileAttribute(self,filetype, objectId): + print filetype + print objectId + mySO = self._myStudy.FindObjectID(objectId) + boo,RefSO = mySO.ReferencedObject() + if boo: + print RefSO + mySO = RefSO + print mySO + val="" + boo,attr = self._myBuilder.FindAttribute(mySO,"AttributeFileType") + print "AttributeFileType ",boo + if boo: + boo=0 + val=attr.Value() + print val + if val==filetype: + boo,attr = self._myBuilder.FindAttribute(mySO,"AttributeExternalFileDef") + val="" + if boo: + val=attr.Value() + attribute=val + return (boo,attribute) + + def getNameAttribute(self, objectId): + mySO = self._myStudy.FindObjectID(objectId) + boo,RefSO = mySO.ReferencedObject() + if boo: + mySO = RefSO + boo,attr = self._myBuilder.FindAttribute(mySO,"AttributeName") + val="" + if boo: + val=attr.Value() + print val + return val + + + def getChildren(self, objectId): + children=[] + mySO = self._myStudy.FindObjectID(objectId) + boo,RefSO = mySO.ReferencedObject() + if boo: + mySO = RefSO + it = self._myStudy.NewChildIterator(mySO) + while it.More(): + CSO = it.Value() + children.append(CSO.GetID()) + it.Next() + print children + return children diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 00000000..4694a720 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,20 @@ +#============================================================================== +# File : Makefile.in +# Created : ven déc 7 13:32:20 CET 2001 +# Author : Paul RASCLE, EDF +# Project : SALOME +# Copyright : EDF 2001 +# $Header: /home/salome/PlateFormePAL/Bases_CVS_EDF/Modules_EDF/ASTER_SRC/src/Makefile.in,v 1.3.2.1 2004/06/07 17:40:26 salome Exp $ +#============================================================================== + +# source path +top_srcdir=@top_srcdir@ +top_builddir=.. +srcdir=@srcdir@ +VPATH=.:@srcdir@ + +@COMMENCE@ + +SUBDIRS = TclQtNotifier EFICASGUI + +@MODULE@ diff --git a/src/TclQtNotifier/Makefile.in b/src/TclQtNotifier/Makefile.in new file mode 100644 index 00000000..c85d71dc --- /dev/null +++ b/src/TclQtNotifier/Makefile.in @@ -0,0 +1,48 @@ +# -* Makefile *- +# +# Author : Nicolas REJNERI +# Date : Sun May 05 11:45:40 2002 +# $Header $ +# + +# source path +top_srcdir=@top_srcdir@ +top_builddir=../.. +srcdir=@srcdir@ +VPATH=.:@srcdir@:@top_srcdir@/idl:$(top_builddir)/idl:${KERNEL_ROOT_DIR}/idl/salome + + +@COMMENCE@ + +# header files +EXPORT_HEADERS= + +# Libraries targets +LIB = + +LIB_SRC = + +LIB_MOC = + +LIB_CLIENT_IDL = + +LIB_SERVER_IDL = + +EXPORT_PYSCRIPTS = + +# additionnal information to compil and link file + +lib: notifqt.so + +notifqt.so: moc_notify.cpp + python setup.py install --install-lib=$(top_builddir)/lib/salome + + +install: notifqt.so + $(INSTALL) -d $(libdir) + cp -p $(top_builddir)/lib/salome/notifqt.so $(libdir) + + +#pattern rules +moc_%.cpp : %.h + $(MOC) $< -o $@ diff --git a/src/TclQtNotifier/moc_notify.refcpp b/src/TclQtNotifier/moc_notify.refcpp new file mode 100644 index 00000000..4f13f468 --- /dev/null +++ b/src/TclQtNotifier/moc_notify.refcpp @@ -0,0 +1,183 @@ +/**************************************************************************** +** Notifier meta object code from reading C++ file 'notify.h' +** +** Created: Wed Feb 5 17:19:07 2003 +** by: The Qt MOC ($Id: moc_notify.refcpp,v 1.1.2.1 2004/05/18 11:40:21 salome Exp $) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#undef QT_NO_COMPAT +#include "notify.h" +#include +#include + +#include +#if !defined(Q_MOC_OUTPUT_REVISION) || (Q_MOC_OUTPUT_REVISION != 19) +#error "This file was generated using the moc from 3.0.6. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +const char *Notifier::className() const +{ + return "Notifier"; +} + +QMetaObject *Notifier::metaObj = 0; +static QMetaObjectCleanUp cleanUp_Notifier; + +#ifndef QT_NO_TRANSLATION +QString Notifier::tr( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "Notifier", s, c, QApplication::DefaultCodec ); + else + return QString::fromLatin1( s ); +} +#ifndef QT_NO_TRANSLATION_UTF8 +QString Notifier::trUtf8( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "Notifier", s, c, QApplication::UnicodeUTF8 ); + else + return QString::fromUtf8( s ); +} +#endif // QT_NO_TRANSLATION_UTF8 + +#endif // QT_NO_TRANSLATION + +QMetaObject* Notifier::staticMetaObject() +{ + if ( metaObj ) + return metaObj; + QMetaObject* parentObject = QObject::staticMetaObject(); + static const QUMethod slot_0 = {"dataReceived", 0, 0 }; + static const QUMethod slot_1 = {"dataWritable", 0, 0 }; + static const QUMethod slot_2 = {"dataExcept", 0, 0 }; + static const QMetaData slot_tbl[] = { + { "dataReceived()", &slot_0, QMetaData::Public }, + { "dataWritable()", &slot_1, QMetaData::Public }, + { "dataExcept()", &slot_2, QMetaData::Public } + }; + metaObj = QMetaObject::new_metaobject( + "Notifier", parentObject, + slot_tbl, 3, + 0, 0, +#ifndef QT_NO_PROPERTIES + 0, 0, + 0, 0, +#endif // QT_NO_PROPERTIES + 0, 0 ); + cleanUp_Notifier.setMetaObject( metaObj ); + return metaObj; +} + +void* Notifier::qt_cast( const char* clname ) +{ + if ( !qstrcmp( clname, "Notifier" ) ) return (Notifier*)this; + return QObject::qt_cast( clname ); +} + +bool Notifier::qt_invoke( int _id, QUObject* _o ) +{ + switch ( _id - staticMetaObject()->slotOffset() ) { + case 0: dataReceived(); break; + case 1: dataWritable(); break; + case 2: dataExcept(); break; + default: + return QObject::qt_invoke( _id, _o ); + } + return TRUE; +} + +bool Notifier::qt_emit( int _id, QUObject* _o ) +{ + return QObject::qt_emit(_id,_o); +} +#ifndef QT_NO_PROPERTIES + +bool Notifier::qt_property( int _id, int _f, QVariant* _v) +{ + return QObject::qt_property( _id, _f, _v); +} +#endif // QT_NO_PROPERTIES + + +const char *Timer::className() const +{ + return "Timer"; +} + +QMetaObject *Timer::metaObj = 0; +static QMetaObjectCleanUp cleanUp_Timer; + +#ifndef QT_NO_TRANSLATION +QString Timer::tr( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "Timer", s, c, QApplication::DefaultCodec ); + else + return QString::fromLatin1( s ); +} +#ifndef QT_NO_TRANSLATION_UTF8 +QString Timer::trUtf8( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "Timer", s, c, QApplication::UnicodeUTF8 ); + else + return QString::fromUtf8( s ); +} +#endif // QT_NO_TRANSLATION_UTF8 + +#endif // QT_NO_TRANSLATION + +QMetaObject* Timer::staticMetaObject() +{ + if ( metaObj ) + return metaObj; + QMetaObject* parentObject = QObject::staticMetaObject(); + static const QUMethod slot_0 = {"timeout", 0, 0 }; + static const QMetaData slot_tbl[] = { + { "timeout()", &slot_0, QMetaData::Public } + }; + metaObj = QMetaObject::new_metaobject( + "Timer", parentObject, + slot_tbl, 1, + 0, 0, +#ifndef QT_NO_PROPERTIES + 0, 0, + 0, 0, +#endif // QT_NO_PROPERTIES + 0, 0 ); + cleanUp_Timer.setMetaObject( metaObj ); + return metaObj; +} + +void* Timer::qt_cast( const char* clname ) +{ + if ( !qstrcmp( clname, "Timer" ) ) return (Timer*)this; + return QObject::qt_cast( clname ); +} + +bool Timer::qt_invoke( int _id, QUObject* _o ) +{ + switch ( _id - staticMetaObject()->slotOffset() ) { + case 0: timeout(); break; + default: + return QObject::qt_invoke( _id, _o ); + } + return TRUE; +} + +bool Timer::qt_emit( int _id, QUObject* _o ) +{ + return QObject::qt_emit(_id,_o); +} +#ifndef QT_NO_PROPERTIES + +bool Timer::qt_property( int _id, int _f, QVariant* _v) +{ + return QObject::qt_property( _id, _f, _v); +} +#endif // QT_NO_PROPERTIES diff --git a/src/TclQtNotifier/notifqtmodule.cpp b/src/TclQtNotifier/notifqtmodule.cpp new file mode 100644 index 00000000..721ef37b --- /dev/null +++ b/src/TclQtNotifier/notifqtmodule.cpp @@ -0,0 +1,873 @@ +#include +#include +#include +using namespace std; +#include +#include +#include +#include + +/* + * With Qt version 3.0, we must use this horrible hack : #define private public + * With Qt version > 3.0, this no more needed + * So commentarize #define QT30, with Qt version > 3.0 + */ +#undef QT32 +#define QT30 +#ifdef QT30 +#define private public /* We need to use processNextEvent(), + therefore we need + access to the internal variables. */ +#include +#undef private /* On revient au normal */ +#else +#include +#include +#endif + +#include + + +#include "notify.h" +#include + +extern "C" void QtFileProc(FileHandler *,int); +extern "C" void QtTimerProc(); +extern "C" bool processQtEvent(bool ); +extern "C" int qtlooplevel(); +extern "C" void notifierFilter(int ); + +//#define _DEBUG_ +# ifdef _DEBUG_ +# define HERE {cout<loopLevel(); +#else + return qApp->eventLoop()->loopLevel(); +#endif +} + +extern "C" bool processQtEvent(bool canWait) +{ + bool flag; + /* + * This function is called by WaitForEvent (internal loop of + * Tcl Notifier) so only some Qt events will be taken in account. + * We install a filter on qApp + * before processing next qt event with wait. + */ + notifierFilter(1); +#ifdef QT30 + flag= qApp->processNextEvent(canWait); +#else + if(canWait){ + flag= qApp->eventLoop()->processEvents(QEventLoop::AllEvents | QEventLoop::WaitForMore ); + }else{ + flag= qApp->eventLoop()->processEvents(QEventLoop::AllEvents ); + } +#endif + notifierFilter(0); + return flag; +} + +/* + * This object (Notifier) calls QtFileProc when some data is present + * on f->fd socket (Tk X11 socket) + */ +Notifier::Notifier(FileHandler *f,int mask):QObject() + { + fhdr=f; + if (mask & TCL_READABLE){ + sn = new QSocketNotifier( f->fd, QSocketNotifier::Read ); + QObject::connect( sn, SIGNAL(activated(int)), this, SLOT(dataReceived()) ); + }else if (mask & TCL_WRITABLE){ + sn = new QSocketNotifier( f->fd, QSocketNotifier::Write ); + QObject::connect( sn, SIGNAL(activated(int)), this, SLOT(dataWritable()) ); + }else if (mask & TCL_EXCEPTION){ + sn = new QSocketNotifier( f->fd, QSocketNotifier::Exception ); + QObject::connect( sn, SIGNAL(activated(int)), this, SLOT(dataExcept()) ); + } + } + +void Notifier::dataReceived() + { + //fprintf(stderr,"dataReceived\n"); + QtFileProc(fhdr,TCL_READABLE); + } +void Notifier::dataWritable() + { + //fprintf(stderr,"dataWritable\n"); + QtFileProc(fhdr,TCL_WRITABLE); + } +void Notifier::dataExcept() + { + //fprintf(stderr,"dataExcept\n"); + QtFileProc(fhdr,TCL_EXCEPTION); + } + +Timer::Timer():QObject() +{ + // Create a QT timer + timer= new QTimer(this); + // Connect it + connect( timer, SIGNAL(timeout()), this,SLOT(timeout()) ); + // but don't start it +} +void Timer::timeout() +{ + MESSAGE("timeout"); + /* + * QT timer associated to Tcl notifier has fired + * stop it + * and call Tcl notifier function QtTimerProc + */ + timer->stop(); + QtTimerProc(); +} + + +Filter::Filter():QObject() +{ + mustFilter=0; + // Install it as an application-global event filter to catch ... + SCRUTE(qApp); + qApp->installEventFilter( this ); +} + +bool Filter::eventFilter( QObject *obj, QEvent *event ) +{ + MESSAGE("Filter::eventFilter"); + SCRUTE(event->type()); + if (mustFilter){ + /* + * We are in a modal TK loop (WaitForEvent has been called) + * so we ignore some Qt events + */ + if(event->type() == QEvent::MouseButtonPress) return TRUE; + if(event->type() == QEvent::MouseButtonRelease)return TRUE; + if(event->type() == QEvent::MouseButtonDblClick)return TRUE; + //if(event->type() == QEvent::KeyPress)return TRUE; + if(event->type() == 6)return TRUE; + //if(event->type() == QEvent::KeyRelease)return TRUE; + if(event->type() == 7)return TRUE; + // We don't allow to close Qt windows in Tk modal loop + if(event->type() == QEvent::Close)return TRUE; + } + return QObject::eventFilter( obj, event ); // don't eat event +} + +/* + * The following structure is what is added to the Tcl event queue when + * file handlers are ready to fire. + */ + +typedef struct FileHandlerEvent { + Tcl_Event header; /* Information that is standard for + * all events. */ + int fd; /* File descriptor that is ready. Used + * to find the FileHandler structure for + * the file (can't point directly to the + * FileHandler structure because it could + * go away while the event is queued). */ +} FileHandlerEvent; + +/* + * The following static structure contains the state information for the + * Qt based implementation of the Tcl notifier. + */ + +static struct NotifierState { + int currentTimeout; + Filter *filter; + Timer *timer; + FileHandler *firstFileHandlerPtr; /* Pointer to head of file handler + * list. */ +} notifier; + +/* + * The following static indicates whether this module has been initialized. + */ +static int initialized = 0; + +extern "C" void InitNotifier (void); + +static Tk_RestrictAction EventRestrictProc(ClientData arg, XEvent *eventPtr) +{ + /* + * We are in a modal QT loop (qApp->loopLevel() > 1) + * so we ignore some TK events + */ + //printf("event : %d\n",eventPtr->type); + if (qtlooplevel() == 1) return TK_PROCESS_EVENT; + if(eventPtr->type == ButtonRelease)return TK_DISCARD_EVENT; + if(eventPtr->type == ButtonPress)return TK_DISCARD_EVENT; + if(eventPtr->type == KeyRelease)return TK_DISCARD_EVENT; + if(eventPtr->type == KeyPress)return TK_DISCARD_EVENT; + if(eventPtr->type == MotionNotify)return TK_DISCARD_EVENT; + return TK_PROCESS_EVENT; +} + +static void restrictevents() +{ + ClientData info,oldArg; + //if (qtlooplevel()>1) Tk_RestrictEvents(EventRestrictProc,&info,&oldArg); + if (qtlooplevel()>0) Tk_RestrictEvents(EventRestrictProc,&info,&oldArg); + else Tk_RestrictEvents(NULL,&info,&oldArg); +} +/* + *---------------------------------------------------------------------- + * + * SetTimer -- + * + * This procedure sets the current notifier timeout value. + * + * Results: + * None. + * + * Side effects: + * Replaces any previous timer. + * + * This function starts or stops the notifier timer + * It called when Tcl_SetTime(xxx) is called + * This notifier timer calls QtTimerProc when timer event occurs + *---------------------------------------------------------------------- + */ + +static void +SetTimer(Tcl_Time *timePtr) + /* Timeout value, may be NULL. */ +{ + long timeout; + MESSAGE("SetTimer"); + + if (!initialized) { + InitNotifier(); + } + + if (notifier.currentTimeout != 0) { + // stopQtTimer(); + // printf("stop timer \n"); + notifier.timer->timer->stop(); + notifier.currentTimeout = 0; + } + if (timePtr) { + timeout = timePtr->sec * 1000 + timePtr->usec / 1000; + // startQtTimer(timeout); + // printf("start timer %ld\n",timeout); + notifier.timer->timer->start(timeout); + notifier.currentTimeout = 1; + } +} + +/* + * Ask _tkinter to service all pending events + */ + +static void DoEvents() +{ + long ret=1; + MESSAGE("DoEvents"); + SIP_BLOCK_THREADS + //Tcl_ServiceAll(); + PyObject * tkinter=PyImport_ImportModule("_tkinter"); + while(ret==1){ + // Process one Tcl event without blocking + MESSAGE("dooneevent call"); + PyObject *res=PyObject_CallMethod(tkinter,"dooneevent","i",2); + if(!res){ + PyErr_Print(); + SIP_UNBLOCK_THREADS + return; + } + ret= PyInt_AsLong(res); + SCRUTE(ret); + Py_DECREF(res); + //SCRUTE(res->ob_refcnt); + // usleep(20000); + } + + Py_DECREF(tkinter); + SCRUTE(tkinter->ob_refcnt); + SIP_UNBLOCK_THREADS + MESSAGE("end of DoEvents"); + return; +} + +/* + * If running is 1, we have already called DoEvents and so dooneevent from + * _tkinter module. It's a recursive call so don't call again DoEvents + * it will block.We are in Tcl so it's safe to call directly Tcl_ServiceAll. + * If running is 0, we are running out of _tkinter module so we must + * call Tcl_ServiceAll through dooneevent from _tkinter module + */ +static int running=1; +static int waitfor=0; +/* + * ServiceAll could be called recursively so be careful + */ +static void ServiceAll() +{ + if(running==1){ + // It's safe to call directly Tcl_ServiceAll + Tcl_ServiceAll(); + }else if(waitfor==1){ + // It's safe to call directly Tcl_ServiceAll + Tcl_ServiceAll(); + }else{ + // Call Tcl_ServiceAll through Python _tkinter module interface + // to have safe state + running=1; + DoEvents(); + running=0; + } +} +/* + *---------------------------------------------------------------------- + * + * QtTimerProc -- + * + * This procedure is the QtTimerCallbackProc used to handle + * timeouts. + * + * Results: + * None. + * + * Side effects: + * Processes all queued events. + * + * This function is declared to the Tcl notifier + * notifierprocs.setTimerProc = SetTimer; + * Tcl_SetNotifier(¬ifierprocs); + * This function is called when a timer event occurs + *---------------------------------------------------------------------- + */ + +void QtTimerProc() +{ + MESSAGE("QtTimerProc"); + restrictevents(); + ServiceAll(); +} + +/* + *---------------------------------------------------------------------- + * + * CreateFileHandler -- + * + * This procedure registers a file handler with the Qt notifier. + * + * Results: + * None. + * + * Side effects: + * Creates a new file handler structure and registers one or more + * input procedures with Qt. + * + *---------------------------------------------------------------------- + * CCAR: + * Cette procedure est appelee par Tcl via le notifier (notifier.createFileHandlerProc) + * Elle est chargée d'enregistrer dans la boucle Qt un file handler dont le file + * descripteur sera celui de la connexion X spécifique de Tk. + * Ainsi on peut deriver le traitement des evenements X de Tk vers les procedures + * qui sont localisées dans ce fichier + * This function is declared to the Tcl notifier + * notifierprocs.createFileHandlerProc = CreateFileHandler + * Tcl_SetNotifier(¬ifierprocs); + * Then Tcl calls it during initialization : ???? + */ + +static void +CreateFileHandler(int fd, int mask, Tcl_FileProc proc, ClientData clientData) +/* int fd; Handle of stream to watch. + * int mask; OR'ed combination of TCL_READABLE, + * TCL_WRITABLE, and TCL_EXCEPTION: + * indicates conditions under which + * proc should be called. + * Tcl_FileProc *proc; Procedure to call for each + * selected event. + * ClientData clientData; Arbitrary data to pass to proc. + */ +{ + FileHandler *filePtr; + + MESSAGE("CreateFileHandler"); + + if (!initialized) { + InitNotifier(); + } + + for (filePtr = notifier.firstFileHandlerPtr; filePtr != NULL; + filePtr = filePtr->nextPtr) { + if (filePtr->fd == fd) { + break; + } + } + if (filePtr == NULL) { + filePtr = (FileHandler*) ckalloc(sizeof(FileHandler)); + filePtr->fd = fd; + filePtr->readyMask = 0; + filePtr->mask = 0; + filePtr->nextPtr = notifier.firstFileHandlerPtr; + notifier.firstFileHandlerPtr = filePtr; + } + filePtr->proc = proc; + filePtr->clientData = clientData; + /* + * Enregistrement avec la boucle Qt + * Toute activité sur le file descripteur fd (connexion X spécifique Tk) + * sera détectée et redirigée vers la procédure QtFileProc + * Create a Notifier object to redirect X11 events present on socket filePtr->fd + * towards QtFileProc + */ + filePtr->qtNotifier=new Notifier(filePtr,mask); + + filePtr->mask = mask; +} + +/* + *---------------------------------------------------------------------- + * + * DeleteFileHandler -- + * + * Cancel a previously-arranged callback arrangement for + * a file. + * + * Results: + * None. + * + * Side effects: + * If a callback was previously registered on file, remove it. + * + *---------------------------------------------------------------------- + */ + +static void +DeleteFileHandler(int fd) +/* + * int fd; Stream id for which to remove + * callback procedure. + */ +{ + FileHandler *filePtr, *prevPtr; + + if (!initialized) { + InitNotifier(); + } + + /* + * Find the entry for the given file (and return if there + * isn't one). + */ + + for (prevPtr = NULL, filePtr = notifier.firstFileHandlerPtr; ; + prevPtr = filePtr, filePtr = filePtr->nextPtr) { + if (filePtr == NULL) { + return; + } + if (filePtr->fd == fd) { + break; + } + } + + /* + * Clean up information in the callback record. + */ + + if (prevPtr == NULL) { + notifier.firstFileHandlerPtr = filePtr->nextPtr; + } else { + prevPtr->nextPtr = filePtr->nextPtr; + } + /* + * Destruction du notifier Qt + */ + delete filePtr->qtNotifier; + + ckfree((char *) filePtr); +} + +static int FileHandlerEventProc(Tcl_Event *evPtr, int flags); +/* + *---------------------------------------------------------------------- + * + * QtFileProc -- + * + * These procedures are called by Qt when a file becomes readable, + * writable, or has an exception. + * + * Results: + * None. + * + * Side effects: + * Makes an entry on the Tcl event queue if the event is + * interesting. + * + *---------------------------------------------------------------------- + * Lorsqu'une activité est detectée sur le file descripteur fd cette + * procédure crée un evenement Tcl qu'elle rajoute dans la queue Tcl + * Elle demande ensuite de servir (Tcl_ServiceAll) tous les evenements + * Tcl présents dans la queue Tcl + * L'evenement est créé avec comme procédure de traitement associée FileHandlerEventProc + */ + +void QtFileProc(FileHandler *filePtr,int mask) +{ + FileHandlerEvent *fileEvPtr; + MESSAGE("QtFileProc"); + + /* + * Ignore unwanted or duplicate events. + */ + + if (!(filePtr->mask & mask) || (filePtr->readyMask & mask)) { + return; + } + + /* + * This is an interesting event, so put it onto the event queue. + * On demande qu'il soit traité avec la procédure FileHandlerEventProc + */ + + filePtr->readyMask |= mask; + + fileEvPtr = (FileHandlerEvent *) ckalloc(sizeof(FileHandlerEvent)); + fileEvPtr->header.proc = FileHandlerEventProc; + fileEvPtr->fd = filePtr->fd; + Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL); + + /* + * Process events on the Tcl event queue before returning to Qt. + */ + + // On entre dans la boucle de traitement des evenements Tcl (retour vers Python?) + /* + * L'evenement file sera traité ce qui conduit à mettre les evenements X + * dans la queue Tcl. Ces evenements (X) seront alors traités dans la foulée + * La source d'evenement X enregistrée par Tcl_CreateEventSource est egalement + * consultée pendant cette phase (assertion a verifier) + */ + + restrictevents(); + ServiceAll(); + + // On revient vers la boucle Qt +} + +/* + *---------------------------------------------------------------------- + * + * FileHandlerEventProc -- + * + * This procedure is called by Tcl_ServiceEvent when a file event + * reaches the front of the event queue. This procedure is + * responsible for actually handling the event by invoking the + * callback for the file handler. + * + * Results: + * Returns 1 if the event was handled, meaning it should be removed + * from the queue. Returns 0 if the event was not handled, meaning + * it should stay on the queue. The only time the event isn't + * handled is if the TCL_FILE_EVENTS flag bit isn't set. + * + * Side effects: + * Whatever the file handler's callback procedure does. + * + *---------------------------------------------------------------------- + */ + +static int +FileHandlerEventProc(Tcl_Event *evPtr, int flags) +/* + * Tcl_Event *evPtr; Event to service. + * int flags; Flags that indicate what events to + * handle, such as TCL_FILE_EVENTS. + */ +{ + FileHandler *filePtr; + FileHandlerEvent *fileEvPtr = (FileHandlerEvent *) evPtr; + int mask; + MESSAGE("FileHandlerEventProc"); + + if (!(flags & TCL_FILE_EVENTS)) { + return 0; + } + + /* + * Search through the file handlers to find the one whose handle matches + * the event. We do this rather than keeping a pointer to the file + * handler directly in the event, so that the handler can be deleted + * while the event is queued without leaving a dangling pointer. + */ + + for (filePtr = notifier.firstFileHandlerPtr; filePtr != NULL; + filePtr = filePtr->nextPtr) { + if (filePtr->fd != fileEvPtr->fd) { + continue; + } + + /* + * The code is tricky for two reasons: + * 1. The file handler's desired events could have changed + * since the time when the event was queued, so AND the + * ready mask with the desired mask. + * 2. The file could have been closed and re-opened since + * the time when the event was queued. This is why the + * ready mask is stored in the file handler rather than + * the queued event: it will be zeroed when a new + * file handler is created for the newly opened file. + */ + + mask = filePtr->readyMask & filePtr->mask; + filePtr->readyMask = 0; + if (mask != 0) { + // On utilise ici la procédure enregistrée avec le file handler + // Normalement il s'agit de DisplayFileProc (fichier unix/tkUnixEvent.c de Tk) + (*filePtr->proc)(filePtr->clientData, mask); + } + break; + } + return 1; +} + + +/* + *---------------------------------------------------------------------- + * + * WaitForEvent -- + * + * This function is called by Tcl_DoOneEvent to wait for new + * events on the message queue. If the block time is 0, then + * Tcl_WaitForEvent just polls without blocking. + * + * Results: + * Returns 1 if an event was found, else 0. This ensures that + * Tcl_DoOneEvent will return 1, even if the event is handled + * by non-Tcl code. + * + * Side effects: + * Queues file events that are detected by the select. + * + *---------------------------------------------------------------------- + */ + +static int +WaitForEvent( + Tcl_Time *timePtr) /* Maximum block time, or NULL. */ +{ + int ret; + //bool old_app_exit_loop; + int timeout; + MESSAGE("WaitForEvent"); + + if (!initialized) { + InitNotifier(); + } + + //SCRUTE(Tk_GetNumMainWindows()); + //if(Tk_GetNumMainWindows()<1){ + // That should not have happened. quit now ??? + //qApp->quit(); + //} + + if (timePtr) { + // Wait with timeout + MESSAGE("Have timeout"); + timeout = timePtr->sec * 1000 + timePtr->usec / 1000; + if (timeout == 0) { + // Try to process one event without waiting + MESSAGE("Process an event without waiting"); + /* + * We are already in Tkinter module so Tcl calls + * should be done directly without using DoEvents + * wrapping + */ + SCRUTE(running); + waitfor=1; + ret=processQtEvent(FALSE); + waitfor=0; + if (ret) { + MESSAGE("Qt event caught"); + // an event has been proccessed + return 1; + } else { + // no event has been proccessed + MESSAGE("No Qt event caught"); + return 0; + } + } else { + MESSAGE("Start the timer"); + Tcl_SetTimer(timePtr); + } + } else { + // timePtr == NULL, blocking wait of an event + } + // Blocking wait + MESSAGE("Wait an event"); + SCRUTE(running); + waitfor=1; + ret=processQtEvent(TRUE); + waitfor=0; +/* + if(ret==FALSE && qApp->app_exit_loop == TRUE){ + MESSAGE("Critical : qt loop is ended and we will loop forever"); + old_app_exit_loop = qApp->app_exit_loop; + qApp->app_exit_loop=FALSE; + processQtEvent(TRUE); + qApp->app_exit_loop=old_app_exit_loop; + } +*/ + return 1; +} + +/* + *---------------------------------------------------------------------- + * + * NotifierExitHandler -- + * + * This function is called to cleanup the notifier state before + * Tcl is unloaded. + * + * Results: + * None. + * + * Side effects: + * Destroys the notifier window. + * + *---------------------------------------------------------------------- + */ + +static void +NotifierExitHandler( + ClientData clientData) /* Not used. */ +{ + delete notifier.timer; + delete notifier.filter; + + for (; notifier.firstFileHandlerPtr != NULL; ) { + Tcl_DeleteFileHandler(notifier.firstFileHandlerPtr->fd); + } + initialized = 0; +} + +/* + *---------------------------------------------------------------------- + * + * InitNotifier -- + * + * Initializes the notifier state. + * + * Results: + * None. + * + * Side effects: + * Creates a new exit handler. + * + *---------------------------------------------------------------------- + * La procedure InitNotifier doit etre appelée avant d'initialiser Tcl et Tk + * par Tcl_Init et Tk_Init + * Tcl_SetNotifier enregistre les procedures du notifier aupres de Tcl + * et en particulier notifier.createFileHandlerProc en tant que tclStubs.tcl_CreateFileHandler + * lui meme appelé par Tcl_CreateFileHandler qui est appelé à l'initialisation par + * TkpOpenDisplay avec comme argument proc : DisplayFileProc + * TkpOpenDisplay est lui meme appelé par GetScreen qui est appelé à l'initialisation + * par CreateTopLevelWindow + * + * Tk_Init appelle Initialize qui + * 1 - crée une toplevel par appel à TkCreateFrame + * cette création a comme effet de bord l'appel à GetScreen + * 2 - appelle TkpInit qui réalise des initialisations spécifiques + * dont TkCreateXEventSource() qui crée une source d'évenements Tcl par + * Tcl_CreateEventSource(DisplaySetupProc, DisplayCheckProc, NULL); + * Cette source est enregistrée dans la liste des sources qui mémorise + * les procédures dans source->setupProc et source->checkProc + * Les sources sont appelées par Tcl_ServiceAll qui appelle Tcl_ServiceEvent + * qui traite un evenement + * + * La procédure DisplayFileProc appelle TransferXEventsToTcl qui met les evenements + * X dans la queue Tk en appelant Tk_QueueWindowEvent + * Tk_QueueWindowEvent appelle soit Tcl_DoWhenIdle soit Tcl_QueueEvent pour mettre + * cet evenement dans la queue Tcl + * Tcl_QueueEvent appelle QueueEvent qui fait le travail + * + */ + +extern "C" void InitNotifier() +{ + MESSAGE("InitNotifier"); + + /* + * Only reinitialize if we are not in exit handling. The notifier + * can get reinitialized after its own exit handler has run, because + * of exit handlers for the I/O and timer sub-systems (order dependency). + */ + + if (TclInExit()) { + return; + } + initialized = 1; + memset(¬ifier, 0, sizeof(notifier)); + notifier.timer= new Timer(); + notifier.filter= new Filter(); + + Tcl_SetServiceMode(TCL_SERVICE_ALL); +} + +ClientData +initNotifierProc() +{ +return (ClientData) 0; +} + +void InitNotifierProcs() +{ + Tcl_NotifierProcs notifierprocs; + MESSAGE("InitNotifierProcs"); + memset(¬ifierprocs, 0, sizeof(notifierprocs)); + notifierprocs.createFileHandlerProc = CreateFileHandler; + notifierprocs.deleteFileHandlerProc = DeleteFileHandler; + notifierprocs.setTimerProc = SetTimer; + notifierprocs.waitForEventProc = WaitForEvent; +#if TCL_MINOR_VERSION > 3 + notifierprocs.initNotifierProc = initNotifierProc; +#endif + MESSAGE("Tcl_SetNotifier"); + Tcl_SetNotifier(¬ifierprocs); + MESSAGE("Tcl_CreateExitHandler"); + Tcl_CreateExitHandler(NotifierExitHandler, NULL); +} + +extern "C" void notifierFilter(int filter) +{ + notifier.filter->mustFilter=filter; +} + +static PyMethodDef Module_Methods[] = + { + {NULL, NULL} + }; + +extern "C" void initnotifqt() +{ +PyObject *m; +static char modulename[] = "notifqt"; +MESSAGE("initnotifqt"); +// Protect Tcl notifier if qApp is not started +if(qApp) InitNotifierProcs(); +/* + * If the module is linked with the right lib (qt-mt) + * this module and libqtcmodule share global variables as qApp + * and others + */ +// We are called from Python so initialize the ServiceAll trick. +running=0; +m = Py_InitModule(modulename, Module_Methods); +} diff --git a/src/TclQtNotifier/notify.h b/src/TclQtNotifier/notify.h new file mode 100644 index 00000000..00f908bb --- /dev/null +++ b/src/TclQtNotifier/notify.h @@ -0,0 +1,55 @@ +#include +#include +#include +#include + +#include +EXTERN int TclInExit _ANSI_ARGS_((void)); + +class Notifier; + +typedef struct FileHandler { + int fd; + int mask; /* Mask of desired events: TCL_READABLE, etc. */ + int readyMask; /* Events that have been seen since the + last time FileHandlerEventProc was called + for this file. */ + Notifier *qtNotifier; + Tcl_FileProc *proc; /* Procedure to call, in the style of + * Tcl_CreateFileHandler. */ + ClientData clientData; /* Argument to pass to proc. */ + struct FileHandler *nextPtr;/* Next in list of all files we care about. */ +} FileHandler; + +class Notifier : public QObject +{ + Q_OBJECT +public: + Notifier(FileHandler *,int); +public slots: + void dataReceived(); + void dataWritable(); + void dataExcept(); +private: + QSocketNotifier *sn; + FileHandler *fhdr; +}; + +class Filter : public QObject +{ +public: + Filter(); + bool eventFilter( QObject *, QEvent * ); + int mustFilter; +}; + +class Timer : public QObject +{ + Q_OBJECT +public: + Timer(); + QTimer *timer; +public slots: + void timeout(); +}; + diff --git a/src/TclQtNotifier/setup.py.in b/src/TclQtNotifier/setup.py.in new file mode 100644 index 00000000..0ac1b118 --- /dev/null +++ b/src/TclQtNotifier/setup.py.in @@ -0,0 +1,75 @@ +from distutils.core import setup, Extension + +import os,sys + +TCLHOME=os.getenv("TCLHOME") +if not TCLHOME: + print "TCLHOME not set : use /usr" + TCLHOME="/usr" +TKINCL=os.path.join(TCLHOME,"include") + +QT_INCLUDES="@QT_INCLUDES@".split() +SIP_INCLUDES="@SIP_INCLUDES@".split() +QT_LIBS="@QT_MT_LIBS@".split() +PYQT_LIBS="@PYQT_LIBS@".split() + +PYDIR=sys.prefix +VERS="%s.%s" % (sys.version_info[0],sys.version_info[1]) + +def find_file(filename, std_dirs, paths): + """Searches for the directory where a given file is located, + and returns a possibly-empty list of additional directories, or None + if the file couldn't be found at all. + + 'filename' is the name of a file, such as readline.h or libcrypto.a. + 'std_dirs' is the list of standard system directories; if the + file is found in one of them, no additional directives are needed. + 'paths' is a list of additional locations to check; if the file is + found in one of them, the resulting list will contain the directory. + """ + + # Check the standard locations + for dir in std_dirs: + f = os.path.join(dir, filename) + if os.path.exists(f): return [] + + # Check the additional directories + for dir in paths: + f = os.path.join(dir, filename) + if os.path.exists(f): + return [dir] + + # Not found anywhere + return None + +inc_dirs=[TKINCL] + +for version in ['8.4', '8.3', '8.2', '8.1', '8.0']: + # Check for the include files on Debian, where + # they're put in /usr/include/{tcl,tk}X.Y + debian_tcl_include = [ '/usr/include/tcl' + version ] + debian_tk_include = [ '/usr/include/tk' + version ] + debian_tcl_include + tcl_includes = find_file('tcl.h', inc_dirs, debian_tcl_include) + tk_includes = find_file('tk.h', inc_dirs, debian_tk_include) + if tcl_includes and tk_includes: + break + +print "Found Tk version:",version +print "Found Tcl includes:",tcl_includes +print "Found Tk includes:",tk_includes + +include_dirs=[".", "@srcdir@", TKINCL]+tcl_includes+tk_includes +libs_tk=["tk"+version,"tcl"+version] + +setup(name="notifqt", version="1.0", + ext_modules=[ + Extension("notifqt", ["@srcdir@/notifqtmodule.cpp", "moc_notify.cpp", ], + include_dirs=include_dirs, + library_dirs=[ ], + libraries=libs_tk, + extra_compile_args= SIP_INCLUDES + QT_INCLUDES, + extra_objects=[], + extra_link_args=QT_LIBS + PYQT_LIBS , + ) + ]) + diff --git a/src/patchTkinter/Makefile.in b/src/patchTkinter/Makefile.in new file mode 100644 index 00000000..dcea295c --- /dev/null +++ b/src/patchTkinter/Makefile.in @@ -0,0 +1,43 @@ +# -* Makefile *- +# +# Author : Nicolas REJNERI +# Date : Sun May 05 11:45:40 2002 +# $Header $ +# + +# source path +top_srcdir=@top_srcdir@ +top_builddir=../.. +srcdir=@srcdir@ +VPATH=.:@srcdir@:@top_srcdir@/idl:$(top_builddir)/idl:${KERNEL_ROOT_DIR}/idl/salome + + +@COMMENCE@ + +# header files +EXPORT_HEADERS= + +# Libraries targets +LIB = + +LIB_SRC = + +LIB_MOC = + +LIB_CLIENT_IDL = + +LIB_SERVER_IDL = + +EXPORT_PYSCRIPTS = + +# additionnal information to compil and link file + +_tkinter.so: + python setup.py install --install-lib=$(top_builddir)/lib/salome + +lib: _tkinter.so + +install: _tkinter.so + $(INSTALL) -d $(libdir) + cp -p $(top_builddir)/lib/salome/_tkinter.so $(libdir) + diff --git a/src/patchTkinter/_tkinter.c b/src/patchTkinter/_tkinter.c new file mode 100644 index 00000000..35e9bbb3 --- /dev/null +++ b/src/patchTkinter/_tkinter.c @@ -0,0 +1,2318 @@ +/*********************************************************** +Copyright (C) 1994 Steen Lumholt. + + All Rights Reserved + +******************************************************************/ + +/* _tkinter.c -- Interface to libtk.a and libtcl.a. */ + +/* TCL/TK VERSION INFO: + + Only Tcl/Tk 8.0 and later are supported. Older versions are not + supported. (Use Python 1.5.2 if you cannot upgrade your Tcl/Tk + libraries.) +*/ + +/* XXX Further speed-up ideas, involving Tcl 8.0 features: + + - In Tcl_Call(), create Tcl objects from the arguments, possibly using + intelligent mappings between Python objects and Tcl objects (e.g. ints, + floats and Tcl window pointers could be handled specially). + + - Register a new Tcl type, "Python callable", which can be called more + efficiently and passed to Tcl_EvalObj() directly (if this is possible). + +*/ + + +#include "Python.h" +#include + +#ifdef WITH_THREAD +#include "pythread.h" +#endif + +#ifdef MS_WINDOWS +#include +#endif + +#ifdef macintosh +#define MAC_TCL +#endif + +#ifdef TK_FRAMEWORK +#include +#include +#else +#include +#include +#endif + +#define TKMAJORMINOR (TK_MAJOR_VERSION*1000 + TK_MINOR_VERSION) + +#if TKMAJORMINOR < 8000 +#error "Tk older than 8.0 not supported" +#endif + +#if defined(macintosh) +/* Sigh, we have to include this to get at the tcl qd pointer */ +#include +/* And this one we need to clear the menu bar */ +#include +#endif + +#if !(defined(MS_WINDOWS) || defined(__CYGWIN__) || defined(macintosh)) +/* Mac has it, but it doesn't really work:-( */ +#define HAVE_CREATEFILEHANDLER +#endif + +#ifdef HAVE_CREATEFILEHANDLER + +/* Tcl_CreateFileHandler() changed several times; these macros deal with the + messiness. In Tcl 8.0 and later, it is not available on Windows (and on + Unix, only because Jack added it back); when available on Windows, it only + applies to sockets. */ + +#ifdef MS_WINDOWS +#define FHANDLETYPE TCL_WIN_SOCKET +#else +#define FHANDLETYPE TCL_UNIX_FD +#endif + +/* If Tcl can wait for a Unix file descriptor, define the EventHook() routine + which uses this to handle Tcl events while the user is typing commands. */ + +#if FHANDLETYPE == TCL_UNIX_FD +#define WAIT_FOR_STDIN +#endif + +#endif /* HAVE_CREATEFILEHANDLER */ + +#ifdef MS_WINDOWS +#include +#define WAIT_FOR_STDIN +#endif + +#ifdef WITH_THREAD + +/* The threading situation is complicated. Tcl is not thread-safe, except for + Tcl 8.1, which will probably remain in alpha status for another 6 months + (and the README says that Tk will probably remain thread-unsafe forever). + So we need to use a lock around all uses of Tcl. Previously, the Python + interpreter lock was used for this. However, this causes problems when + other Python threads need to run while Tcl is blocked waiting for events. + + To solve this problem, a separate lock for Tcl is introduced. Holding it + is incompatible with holding Python's interpreter lock. The following four + macros manipulate both locks together. + + ENTER_TCL and LEAVE_TCL are brackets, just like Py_BEGIN_ALLOW_THREADS and + Py_END_ALLOW_THREADS. They should be used whenever a call into Tcl is made + that could call an event handler, or otherwise affect the state of a Tcl + interpreter. These assume that the surrounding code has the Python + interpreter lock; inside the brackets, the Python interpreter lock has been + released and the lock for Tcl has been acquired. + + Sometimes, it is necessary to have both the Python lock and the Tcl lock. + (For example, when transferring data from the Tcl interpreter result to a + Python string object.) This can be done by using different macros to close + the ENTER_TCL block: ENTER_OVERLAP reacquires the Python lock (and restores + the thread state) but doesn't release the Tcl lock; LEAVE_OVERLAP_TCL + releases the Tcl lock. + + By contrast, ENTER_PYTHON and LEAVE_PYTHON are used in Tcl event + handlers when the handler needs to use Python. Such event handlers are + entered while the lock for Tcl is held; the event handler presumably needs + to use Python. ENTER_PYTHON releases the lock for Tcl and acquires + the Python interpreter lock, restoring the appropriate thread state, and + LEAVE_PYTHON releases the Python interpreter lock and re-acquires the lock + for Tcl. It is okay for ENTER_TCL/LEAVE_TCL pairs to be contained inside + the code between ENTER_PYTHON and LEAVE_PYTHON. + + These locks expand to several statements and brackets; they should not be + used in branches of if statements and the like. + +*/ + +static PyThread_type_lock tcl_lock = 0; +static PyThreadState *tcl_tstate = NULL; + +#define ENTER_TCL \ + { PyThreadState *tstate = PyThreadState_Get(); Py_BEGIN_ALLOW_THREADS \ + PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; + +#define LEAVE_TCL \ + tcl_tstate = NULL; PyThread_release_lock(tcl_lock); Py_END_ALLOW_THREADS} + +#define ENTER_OVERLAP \ + Py_END_ALLOW_THREADS + +#define LEAVE_OVERLAP_TCL \ + tcl_tstate = NULL; PyThread_release_lock(tcl_lock); } + +#define ENTER_PYTHON \ + { PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \ + PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); } + +#define LEAVE_PYTHON \ + { PyThreadState *tstate = PyEval_SaveThread(); \ + PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; } + +#else + +#define ENTER_TCL +#define LEAVE_TCL +#define ENTER_OVERLAP +#define LEAVE_OVERLAP_TCL +#define ENTER_PYTHON +#define LEAVE_PYTHON + +#endif + +/* + * EDF-CCAR : Ajout de la fonction PyServiceAll + */ + +#ifdef WITH_THREAD +#warning "avec thread" +void PyServiceAll(void){ + if(tcl_tstate != NULL){ + /* + * We are already in the Tcl protected zone + * No need to acquire the tcl_lock (it's already on) + */ + Tcl_ServiceAll(); + return; + } + /* + * We are not in the Tcl protected zone + * Must acquire the tcl_lock + */ + ENTER_TCL + Tcl_ServiceAll(); + LEAVE_TCL +} +#else +#warning "sans thread" +void PyServiceAll(void){ + Tcl_ServiceAll(); +} +#endif + +/* + * EDF-CCAR : Fin de la fonction PyServiceAll + */ + +#ifdef macintosh + +/* +** Additional cruft needed by Tcl/Tk on the Mac. +** This is for Tcl 7.5 and Tk 4.1 (patch release 1). +*/ + +/* ckfree() expects a char* */ +#define FREECAST (char *) + +#include /* For EventRecord */ + +typedef int (*TclMacConvertEventPtr) (EventRecord *eventPtr); +void Tcl_MacSetEventProc(TclMacConvertEventPtr procPtr); +int TkMacConvertEvent(EventRecord *eventPtr); + +staticforward int PyMacConvertEvent(EventRecord *eventPtr); + +#include +extern int SIOUXIsAppWindow(WindowPtr); + +#endif /* macintosh */ + +#ifndef FREECAST +#define FREECAST (char *) +#endif + +/**** Tkapp Object Declaration ****/ + +staticforward PyTypeObject Tkapp_Type; + +typedef struct { + PyObject_HEAD + Tcl_Interp *interp; +} TkappObject; + +#define Tkapp_Check(v) ((v)->ob_type == &Tkapp_Type) +#define Tkapp_Interp(v) (((TkappObject *) (v))->interp) +#define Tkapp_Result(v) Tcl_GetStringResult(Tkapp_Interp(v)) + +#define DEBUG_REFCNT(v) (printf("DEBUG: id=%p, refcnt=%i\n", \ +(void *) v, ((PyObject *) v)->ob_refcnt)) + + + +/**** Error Handling ****/ + +static PyObject *Tkinter_TclError; +static int quitMainLoop = 0; +static int errorInCmd = 0; +static PyObject *excInCmd; +static PyObject *valInCmd; +static PyObject *trbInCmd; + + + +static PyObject * +Tkinter_Error(PyObject *v) +{ + PyErr_SetString(Tkinter_TclError, Tkapp_Result(v)); + return NULL; +} + + + +/**** Utils ****/ + +#ifdef WITH_THREAD +#ifndef MS_WINDOWS + +/* Millisecond sleep() for Unix platforms. */ + +static void +Sleep(int milli) +{ + /* XXX Too bad if you don't have select(). */ + struct timeval t; + t.tv_sec = milli/1000; + t.tv_usec = (milli%1000) * 1000; + select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t); +} +#endif /* MS_WINDOWS */ +#endif /* WITH_THREAD */ + + +static char * +AsString(PyObject *value, PyObject *tmp) +{ + if (PyString_Check(value)) + return PyString_AsString(value); +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(value)) { + PyObject *v = PyUnicode_AsUTF8String(value); + if (v == NULL) + return NULL; + if (PyList_Append(tmp, v) != 0) { + Py_DECREF(v); + return NULL; + } + Py_DECREF(v); + return PyString_AsString(v); + } +#endif + else { + PyObject *v = PyObject_Str(value); + if (v == NULL) + return NULL; + if (PyList_Append(tmp, v) != 0) { + Py_DECREF(v); + return NULL; + } + Py_DECREF(v); + return PyString_AsString(v); + } +} + + + +#define ARGSZ 64 + +static char * +Merge(PyObject *args) +{ + PyObject *tmp = NULL; + char *argvStore[ARGSZ]; + char **argv = NULL; + int fvStore[ARGSZ]; + int *fv = NULL; + int argc = 0, fvc = 0, i; + char *res = NULL; + + if (!(tmp = PyList_New(0))) + return NULL; + + argv = argvStore; + fv = fvStore; + + if (args == NULL) + argc = 0; + + else if (!PyTuple_Check(args)) { + argc = 1; + fv[0] = 0; + if (!(argv[0] = AsString(args, tmp))) + goto finally; + } + else { + argc = PyTuple_Size(args); + + if (argc > ARGSZ) { + argv = (char **)ckalloc(argc * sizeof(char *)); + fv = (int *)ckalloc(argc * sizeof(int)); + if (argv == NULL || fv == NULL) { + PyErr_NoMemory(); + goto finally; + } + } + + for (i = 0; i < argc; i++) { + PyObject *v = PyTuple_GetItem(args, i); + if (PyTuple_Check(v)) { + fv[i] = 1; + if (!(argv[i] = Merge(v))) + goto finally; + fvc++; + } + else if (v == Py_None) { + argc = i; + break; + } + else { + fv[i] = 0; + if (!(argv[i] = AsString(v, tmp))) + goto finally; + fvc++; + } + } + } + res = Tcl_Merge(argc, argv); + if (res == NULL) + PyErr_SetString(Tkinter_TclError, "merge failed"); + + finally: + for (i = 0; i < fvc; i++) + if (fv[i]) { + ckfree(argv[i]); + } + if (argv != argvStore) + ckfree(FREECAST argv); + if (fv != fvStore) + ckfree(FREECAST fv); + + Py_DECREF(tmp); + return res; +} + + + +static PyObject * +Split(char *list) +{ + int argc; + char **argv; + PyObject *v; + + if (list == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + + if (Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) { + /* Not a list. + * Could be a quoted string containing funnies, e.g. {"}. + * Return the string itself. + */ + return PyString_FromString(list); + } + + if (argc == 0) + v = PyString_FromString(""); + else if (argc == 1) + v = PyString_FromString(argv[0]); + else if ((v = PyTuple_New(argc)) != NULL) { + int i; + PyObject *w; + + for (i = 0; i < argc; i++) { + if ((w = Split(argv[i])) == NULL) { + Py_DECREF(v); + v = NULL; + break; + } + PyTuple_SetItem(v, i, w); + } + } + Tcl_Free(FREECAST argv); + return v; +} + + + +/**** Tkapp Object ****/ + +#ifndef WITH_APPINIT +int +Tcl_AppInit(Tcl_Interp *interp) +{ + Tk_Window main; + + main = Tk_MainWindow(interp); + if (Tcl_Init(interp) == TCL_ERROR) { + PySys_WriteStderr("Tcl_Init error: %s\n", Tcl_GetStringResult(interp)); + return TCL_ERROR; + } + if (Tk_Init(interp) == TCL_ERROR) { + PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp)); + return TCL_ERROR; + } + return TCL_OK; +} +#endif /* !WITH_APPINIT */ + + + + +/* Initialize the Tk application; see the `main' function in + * `tkMain.c'. + */ + +static void EnableEventHook(void); /* Forward */ +static void DisableEventHook(void); /* Forward */ + +static TkappObject * +Tkapp_New(char *screenName, char *baseName, char *className, int interactive) +{ + TkappObject *v; + char *argv0; + + v = PyObject_New(TkappObject, &Tkapp_Type); + if (v == NULL) + return NULL; + + v->interp = Tcl_CreateInterp(); + +#if defined(macintosh) + /* This seems to be needed */ + ClearMenuBar(); + TkMacInitMenus(v->interp); +#endif + + /* Delete the 'exit' command, which can screw things up */ + Tcl_DeleteCommand(v->interp, "exit"); + + if (screenName != NULL) + Tcl_SetVar2(v->interp, "env", "DISPLAY", + screenName, TCL_GLOBAL_ONLY); + + if (interactive) + Tcl_SetVar(v->interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY); + else + Tcl_SetVar(v->interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY); + + /* This is used to get the application class for Tk 4.1 and up */ + argv0 = (char*)ckalloc(strlen(className) + 1); + if (!argv0) { + PyErr_NoMemory(); + Py_DECREF(v); + return NULL; + } + + strcpy(argv0, className); + if (isupper((int)(argv0[0]))) + argv0[0] = tolower(argv0[0]); + Tcl_SetVar(v->interp, "argv0", argv0, TCL_GLOBAL_ONLY); + ckfree(argv0); + + if (Tcl_AppInit(v->interp) != TCL_OK) + return (TkappObject *)Tkinter_Error((PyObject *)v); + + EnableEventHook(); + + return v; +} + + + +/** Tcl Eval **/ + +#if TKMAJORMINOR >= 8001 +#define USING_OBJECTS +#endif + +#ifdef USING_OBJECTS + +static Tcl_Obj* +AsObj(PyObject *value) +{ + Tcl_Obj *result; + + if (PyString_Check(value)) + return Tcl_NewStringObj(PyString_AS_STRING(value), + PyString_GET_SIZE(value)); + else if (PyInt_Check(value)) + return Tcl_NewLongObj(PyInt_AS_LONG(value)); + else if (PyFloat_Check(value)) + return Tcl_NewDoubleObj(PyFloat_AS_DOUBLE(value)); + else if (PyTuple_Check(value)) { + Tcl_Obj **argv = (Tcl_Obj**) + ckalloc(PyTuple_Size(value)*sizeof(Tcl_Obj*)); + int i; + if(!argv) + return 0; + for(i=0;i 8001 */ + /* In Tcl 8.2 and later, use Tcl_NewUnicodeObj() */ + if (sizeof(Py_UNICODE) != sizeof(Tcl_UniChar)) { + /* XXX Should really test this at compile time */ + PyErr_SetString(PyExc_SystemError, + "Py_UNICODE and Tcl_UniChar differ in size"); + return 0; + } + return Tcl_NewUnicodeObj(PyUnicode_AS_UNICODE(value), + PyUnicode_GET_SIZE(value)); +#endif /* TKMAJORMINOR > 8001 */ + } +#endif + else { + PyObject *v = PyObject_Str(value); + if (!v) + return 0; + result = AsObj(v); + Py_DECREF(v); + return result; + } +} + +static PyObject * +Tkapp_Call(PyObject *self, PyObject *args) +{ + Tcl_Obj *objStore[ARGSZ]; + Tcl_Obj **objv = NULL; + int objc = 0, i; + PyObject *res = NULL; + Tcl_Interp *interp = Tkapp_Interp(self); + /* Could add TCL_EVAL_GLOBAL if wrapped by GlobalCall... */ + int flags = TCL_EVAL_DIRECT; + + objv = objStore; + + if (args == NULL) + /* do nothing */; + + else if (!PyTuple_Check(args)) { + objv[0] = AsObj(args); + if (objv[0] == 0) + goto finally; + objc = 1; + Tcl_IncrRefCount(objv[0]); + } + else { + objc = PyTuple_Size(args); + + if (objc > ARGSZ) { + objv = (Tcl_Obj **)ckalloc(objc * sizeof(char *)); + if (objv == NULL) { + PyErr_NoMemory(); + objc = 0; + goto finally; + } + } + + for (i = 0; i < objc; i++) { + PyObject *v = PyTuple_GetItem(args, i); + if (v == Py_None) { + objc = i; + break; + } + objv[i] = AsObj(v); + if (!objv[i]) { + /* Reset objc, so it attempts to clear + objects only up to i. */ + objc = i; + goto finally; + } + Tcl_IncrRefCount(objv[i]); + } + } + + ENTER_TCL + + i = Tcl_EvalObjv(interp, objc, objv, flags); + + ENTER_OVERLAP + if (i == TCL_ERROR) + Tkinter_Error(self); + else { + /* We could request the object result here, but doing + so would confuse applications that expect a string. */ + char *s = Tcl_GetStringResult(interp); + char *p = s; + + /* If the result contains any bytes with the top bit set, + it's UTF-8 and we should decode it to Unicode */ +#ifdef Py_USING_UNICODE + while (*p != '\0') { + if (*p & 0x80) + break; + p++; + } + + if (*p == '\0') + res = PyString_FromStringAndSize(s, (int)(p-s)); + else { + /* Convert UTF-8 to Unicode string */ + p = strchr(p, '\0'); + res = PyUnicode_DecodeUTF8(s, (int)(p-s), "strict"); + if (res == NULL) { + PyErr_Clear(); + res = PyString_FromStringAndSize(s, (int)(p-s)); + } + } +#else + p = strchr(p, '\0'); + res = PyString_FromStringAndSize(s, (int)(p-s)); +#endif + } + + LEAVE_OVERLAP_TCL + + finally: + for (i = 0; i < objc; i++) + Tcl_DecrRefCount(objv[i]); + if (objv != objStore) + ckfree(FREECAST objv); + return res; +} + +#else /* !USING_OBJECTS */ + +static PyObject * +Tkapp_Call(PyObject *self, PyObject *args) +{ + /* This is copied from Merge() */ + PyObject *tmp = NULL; + char *argvStore[ARGSZ]; + char **argv = NULL; + int fvStore[ARGSZ]; + int *fv = NULL; + int argc = 0, fvc = 0, i; + PyObject *res = NULL; /* except this has a different type */ + Tcl_CmdInfo info; /* and this is added */ + Tcl_Interp *interp = Tkapp_Interp(self); /* and this too */ + + if (!(tmp = PyList_New(0))) + return NULL; + + argv = argvStore; + fv = fvStore; + + if (args == NULL) + argc = 0; + + else if (!PyTuple_Check(args)) { + argc = 1; + fv[0] = 0; + if (!(argv[0] = AsString(args, tmp))) + goto finally; + } + else { + argc = PyTuple_Size(args); + + if (argc > ARGSZ) { + argv = (char **)ckalloc(argc * sizeof(char *)); + fv = (int *)ckalloc(argc * sizeof(int)); + if (argv == NULL || fv == NULL) { + PyErr_NoMemory(); + goto finally; + } + } + + for (i = 0; i < argc; i++) { + PyObject *v = PyTuple_GetItem(args, i); + if (PyTuple_Check(v)) { + fv[i] = 1; + if (!(argv[i] = Merge(v))) + goto finally; + fvc++; + } + else if (v == Py_None) { + argc = i; + break; + } + else { + fv[i] = 0; + if (!(argv[i] = AsString(v, tmp))) + goto finally; + fvc++; + } + } + } + /* End code copied from Merge() */ + + /* All this to avoid a call to Tcl_Merge() and the corresponding call + to Tcl_SplitList() inside Tcl_Eval()... It can save a bundle! */ + if (Py_VerboseFlag >= 2) { + for (i = 0; i < argc; i++) + PySys_WriteStderr("%s ", argv[i]); + } + ENTER_TCL + info.proc = NULL; + if (argc < 1 || + !Tcl_GetCommandInfo(interp, argv[0], &info) || + info.proc == NULL) + { + char *cmd; + cmd = Tcl_Merge(argc, argv); + i = Tcl_Eval(interp, cmd); + ckfree(cmd); + } + else { + Tcl_ResetResult(interp); + i = (*info.proc)(info.clientData, interp, argc, argv); + } + ENTER_OVERLAP + if (info.proc == NULL && Py_VerboseFlag >= 2) + PySys_WriteStderr("... use TclEval "); + if (i == TCL_ERROR) { + if (Py_VerboseFlag >= 2) + PySys_WriteStderr("... error: '%s'\n", + Tcl_GetStringResult(interp)); + Tkinter_Error(self); + } + else { + if (Py_VerboseFlag >= 2) + PySys_WriteStderr("-> '%s'\n", Tcl_GetStringResult(interp)); + res = PyString_FromString(Tcl_GetStringResult(interp)); + } + LEAVE_OVERLAP_TCL + + /* Copied from Merge() again */ + finally: + for (i = 0; i < fvc; i++) + if (fv[i]) { + ckfree(argv[i]); + } + if (argv != argvStore) + ckfree(FREECAST argv); + if (fv != fvStore) + ckfree(FREECAST fv); + + Py_DECREF(tmp); + return res; +} + +#endif /* !USING_OBJECTS */ + +static PyObject * +Tkapp_GlobalCall(PyObject *self, PyObject *args) +{ + /* Could do the same here as for Tkapp_Call(), but this is not used + much, so I can't be bothered. Unfortunately Tcl doesn't export a + way for the user to do what all its Global* variants do (save and + reset the scope pointer, call the local version, restore the saved + scope pointer). */ + + char *cmd; + PyObject *res = NULL; + + cmd = Merge(args); + if (cmd) { + int err; + ENTER_TCL + err = Tcl_GlobalEval(Tkapp_Interp(self), cmd); + ENTER_OVERLAP + if (err == TCL_ERROR) + res = Tkinter_Error(self); + else + res = PyString_FromString(Tkapp_Result(self)); + LEAVE_OVERLAP_TCL + ckfree(cmd); + } + + return res; +} + +static PyObject * +Tkapp_Eval(PyObject *self, PyObject *args) +{ + char *script; + PyObject *res = NULL; + int err; + + if (!PyArg_ParseTuple(args, "s:eval", &script)) + return NULL; + + ENTER_TCL + err = Tcl_Eval(Tkapp_Interp(self), script); + ENTER_OVERLAP + if (err == TCL_ERROR) + res = Tkinter_Error(self); + else + res = PyString_FromString(Tkapp_Result(self)); + LEAVE_OVERLAP_TCL + return res; +} + +static PyObject * +Tkapp_GlobalEval(PyObject *self, PyObject *args) +{ + char *script; + PyObject *res = NULL; + int err; + + if (!PyArg_ParseTuple(args, "s:globaleval", &script)) + return NULL; + + ENTER_TCL + err = Tcl_GlobalEval(Tkapp_Interp(self), script); + ENTER_OVERLAP + if (err == TCL_ERROR) + res = Tkinter_Error(self); + else + res = PyString_FromString(Tkapp_Result(self)); + LEAVE_OVERLAP_TCL + return res; +} + +static PyObject * +Tkapp_EvalFile(PyObject *self, PyObject *args) +{ + char *fileName; + PyObject *res = NULL; + int err; + + if (!PyArg_ParseTuple(args, "s:evalfile", &fileName)) + return NULL; + + ENTER_TCL + err = Tcl_EvalFile(Tkapp_Interp(self), fileName); + ENTER_OVERLAP + if (err == TCL_ERROR) + res = Tkinter_Error(self); + + else + res = PyString_FromString(Tkapp_Result(self)); + LEAVE_OVERLAP_TCL + return res; +} + +static PyObject * +Tkapp_Record(PyObject *self, PyObject *args) +{ + char *script; + PyObject *res = NULL; + int err; + + if (!PyArg_ParseTuple(args, "s", &script)) + return NULL; + + ENTER_TCL + err = Tcl_RecordAndEval(Tkapp_Interp(self), script, TCL_NO_EVAL); + ENTER_OVERLAP + if (err == TCL_ERROR) + res = Tkinter_Error(self); + else + res = PyString_FromString(Tkapp_Result(self)); + LEAVE_OVERLAP_TCL + return res; +} + +static PyObject * +Tkapp_AddErrorInfo(PyObject *self, PyObject *args) +{ + char *msg; + + if (!PyArg_ParseTuple(args, "s:adderrorinfo", &msg)) + return NULL; + ENTER_TCL + Tcl_AddErrorInfo(Tkapp_Interp(self), msg); + LEAVE_TCL + + Py_INCREF(Py_None); + return Py_None; +} + + + +/** Tcl Variable **/ + +static PyObject * +SetVar(PyObject *self, PyObject *args, int flags) +{ + char *name1, *name2, *ok, *s; + PyObject *newValue; + PyObject *tmp; + + tmp = PyList_New(0); + if (!tmp) + return NULL; + + if (PyArg_ParseTuple(args, "sO:setvar", &name1, &newValue)) { + /* XXX Merge? */ + s = AsString(newValue, tmp); + if (s == NULL) + return NULL; + ENTER_TCL + ok = Tcl_SetVar(Tkapp_Interp(self), name1, s, flags); + LEAVE_TCL + } + else { + PyErr_Clear(); + if (PyArg_ParseTuple(args, "ssO:setvar", + &name1, &name2, &newValue)) { + s = AsString(newValue, tmp); + if (s == NULL) + return NULL; + ENTER_TCL + ok = Tcl_SetVar2(Tkapp_Interp(self), name1, name2, + s, flags); + LEAVE_TCL + } + else { + Py_DECREF(tmp); + return NULL; + } + } + Py_DECREF(tmp); + + if (!ok) + return Tkinter_Error(self); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +Tkapp_SetVar(PyObject *self, PyObject *args) +{ + return SetVar(self, args, TCL_LEAVE_ERR_MSG); +} + +static PyObject * +Tkapp_GlobalSetVar(PyObject *self, PyObject *args) +{ + return SetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY); +} + + + +static PyObject * +GetVar(PyObject *self, PyObject *args, int flags) +{ + char *name1, *name2=NULL, *s; + PyObject *res = NULL; + + if (!PyArg_ParseTuple(args, "s|s:getvar", &name1, &name2)) + return NULL; + ENTER_TCL + if (name2 == NULL) + s = Tcl_GetVar(Tkapp_Interp(self), name1, flags); + + else + s = Tcl_GetVar2(Tkapp_Interp(self), name1, name2, flags); + ENTER_OVERLAP + + if (s == NULL) + res = Tkinter_Error(self); + else + res = PyString_FromString(s); + LEAVE_OVERLAP_TCL + return res; +} + +static PyObject * +Tkapp_GetVar(PyObject *self, PyObject *args) +{ + return GetVar(self, args, TCL_LEAVE_ERR_MSG); +} + +static PyObject * +Tkapp_GlobalGetVar(PyObject *self, PyObject *args) +{ + return GetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY); +} + + + +static PyObject * +UnsetVar(PyObject *self, PyObject *args, int flags) +{ + char *name1, *name2=NULL; + PyObject *res = NULL; + int code; + + if (!PyArg_ParseTuple(args, "s|s:unsetvar", &name1, &name2)) + return NULL; + ENTER_TCL + if (name2 == NULL) + code = Tcl_UnsetVar(Tkapp_Interp(self), name1, flags); + + else + code = Tcl_UnsetVar2(Tkapp_Interp(self), name1, name2, flags); + ENTER_OVERLAP + + if (code == TCL_ERROR) + res = Tkinter_Error(self); + else { + Py_INCREF(Py_None); + res = Py_None; + } + LEAVE_OVERLAP_TCL + return res; +} + +static PyObject * +Tkapp_UnsetVar(PyObject *self, PyObject *args) +{ + return UnsetVar(self, args, TCL_LEAVE_ERR_MSG); +} + +static PyObject * +Tkapp_GlobalUnsetVar(PyObject *self, PyObject *args) +{ + return UnsetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY); +} + + + +/** Tcl to Python **/ + +static PyObject * +Tkapp_GetInt(PyObject *self, PyObject *args) +{ + char *s; + int v; + + if (!PyArg_ParseTuple(args, "s:getint", &s)) + return NULL; + if (Tcl_GetInt(Tkapp_Interp(self), s, &v) == TCL_ERROR) + return Tkinter_Error(self); + return Py_BuildValue("i", v); +} + +static PyObject * +Tkapp_GetDouble(PyObject *self, PyObject *args) +{ + char *s; + double v; + + if (!PyArg_ParseTuple(args, "s:getdouble", &s)) + return NULL; + if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR) + return Tkinter_Error(self); + return Py_BuildValue("d", v); +} + +static PyObject * +Tkapp_GetBoolean(PyObject *self, PyObject *args) +{ + char *s; + int v; + + if (!PyArg_ParseTuple(args, "s:getboolean", &s)) + return NULL; + if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR) + return Tkinter_Error(self); + return Py_BuildValue("i", v); +} + +static PyObject * +Tkapp_ExprString(PyObject *self, PyObject *args) +{ + char *s; + PyObject *res = NULL; + int retval; + + if (!PyArg_ParseTuple(args, "s:exprstring", &s)) + return NULL; + ENTER_TCL + retval = Tcl_ExprString(Tkapp_Interp(self), s); + ENTER_OVERLAP + if (retval == TCL_ERROR) + res = Tkinter_Error(self); + else + res = Py_BuildValue("s", Tkapp_Result(self)); + LEAVE_OVERLAP_TCL + return res; +} + +static PyObject * +Tkapp_ExprLong(PyObject *self, PyObject *args) +{ + char *s; + PyObject *res = NULL; + int retval; + long v; + + if (!PyArg_ParseTuple(args, "s:exprlong", &s)) + return NULL; + ENTER_TCL + retval = Tcl_ExprLong(Tkapp_Interp(self), s, &v); + ENTER_OVERLAP + if (retval == TCL_ERROR) + res = Tkinter_Error(self); + else + res = Py_BuildValue("l", v); + LEAVE_OVERLAP_TCL + return res; +} + +static PyObject * +Tkapp_ExprDouble(PyObject *self, PyObject *args) +{ + char *s; + PyObject *res = NULL; + double v; + int retval; + + if (!PyArg_ParseTuple(args, "s:exprdouble", &s)) + return NULL; + PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0) + ENTER_TCL + retval = Tcl_ExprDouble(Tkapp_Interp(self), s, &v); + ENTER_OVERLAP + PyFPE_END_PROTECT(retval) + if (retval == TCL_ERROR) + res = Tkinter_Error(self); + else + res = Py_BuildValue("d", v); + LEAVE_OVERLAP_TCL + return res; +} + +static PyObject * +Tkapp_ExprBoolean(PyObject *self, PyObject *args) +{ + char *s; + PyObject *res = NULL; + int retval; + int v; + + if (!PyArg_ParseTuple(args, "s:exprboolean", &s)) + return NULL; + ENTER_TCL + retval = Tcl_ExprBoolean(Tkapp_Interp(self), s, &v); + ENTER_OVERLAP + if (retval == TCL_ERROR) + res = Tkinter_Error(self); + else + res = Py_BuildValue("i", v); + LEAVE_OVERLAP_TCL + return res; +} + + + +static PyObject * +Tkapp_SplitList(PyObject *self, PyObject *args) +{ + char *list; + int argc; + char **argv; + PyObject *v; + int i; + + if (!PyArg_ParseTuple(args, "et:splitlist", "utf-8", &list)) + return NULL; + + if (Tcl_SplitList(Tkapp_Interp(self), list, &argc, &argv) == TCL_ERROR) + return Tkinter_Error(self); + + if (!(v = PyTuple_New(argc))) + return NULL; + + for (i = 0; i < argc; i++) { + PyObject *s = PyString_FromString(argv[i]); + if (!s || PyTuple_SetItem(v, i, s)) { + Py_DECREF(v); + v = NULL; + goto finally; + } + } + + finally: + ckfree(FREECAST argv); + return v; +} + +static PyObject * +Tkapp_Split(PyObject *self, PyObject *args) +{ + char *list; + + if (!PyArg_ParseTuple(args, "et:split", "utf-8", &list)) + return NULL; + return Split(list); +} + +static PyObject * +Tkapp_Merge(PyObject *self, PyObject *args) +{ + char *s = Merge(args); + PyObject *res = NULL; + + if (s) { + res = PyString_FromString(s); + ckfree(s); + } + + return res; +} + + + +/** Tcl Command **/ + +/* Client data struct */ +typedef struct { + PyObject *self; + PyObject *func; +} PythonCmd_ClientData; + +static int +PythonCmd_Error(Tcl_Interp *interp) +{ + errorInCmd = 1; + PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd); + LEAVE_PYTHON + return TCL_ERROR; +} + +/* This is the Tcl command that acts as a wrapper for Python + * function or method. + */ +static int +PythonCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) +{ + PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData; + PyObject *self, *func, *arg, *res, *tmp; + int i, rv; + char *s; + + ENTER_PYTHON + + /* TBD: no error checking here since we know, via the + * Tkapp_CreateCommand() that the client data is a two-tuple + */ + self = data->self; + func = data->func; + + /* Create argument list (argv1, ..., argvN) */ + if (!(arg = PyTuple_New(argc - 1))) + return PythonCmd_Error(interp); + + for (i = 0; i < (argc - 1); i++) { + PyObject *s = PyString_FromString(argv[i + 1]); + if (!s || PyTuple_SetItem(arg, i, s)) { + Py_DECREF(arg); + return PythonCmd_Error(interp); + } + } + res = PyEval_CallObject(func, arg); + Py_DECREF(arg); + + if (res == NULL) + return PythonCmd_Error(interp); + + if (!(tmp = PyList_New(0))) { + Py_DECREF(res); + return PythonCmd_Error(interp); + } + + s = AsString(res, tmp); + if (s == NULL) { + rv = PythonCmd_Error(interp); + } + else { + Tcl_SetResult(Tkapp_Interp(self), s, TCL_VOLATILE); + rv = TCL_OK; + } + + Py_DECREF(res); + Py_DECREF(tmp); + + LEAVE_PYTHON + + return rv; +} + +static void +PythonCmdDelete(ClientData clientData) +{ + PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData; + + ENTER_PYTHON + Py_XDECREF(data->self); + Py_XDECREF(data->func); + PyMem_DEL(data); + LEAVE_PYTHON +} + + + +static PyObject * +Tkapp_CreateCommand(PyObject *self, PyObject *args) +{ + PythonCmd_ClientData *data; + char *cmdName; + PyObject *func; + Tcl_Command err; + + if (!PyArg_ParseTuple(args, "sO:createcommand", &cmdName, &func)) + return NULL; + if (!PyCallable_Check(func)) { + PyErr_SetString(PyExc_TypeError, "command not callable"); + return NULL; + } + + data = PyMem_NEW(PythonCmd_ClientData, 1); + if (!data) + return NULL; + Py_XINCREF(self); + Py_XINCREF(func); + data->self = self; + data->func = func; + + ENTER_TCL + err = Tcl_CreateCommand(Tkapp_Interp(self), cmdName, PythonCmd, + (ClientData)data, PythonCmdDelete); + LEAVE_TCL + if (err == NULL) { + PyErr_SetString(Tkinter_TclError, "can't create Tcl command"); + PyMem_DEL(data); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + + + +static PyObject * +Tkapp_DeleteCommand(PyObject *self, PyObject *args) +{ + char *cmdName; + int err; + + if (!PyArg_ParseTuple(args, "s:deletecommand", &cmdName)) + return NULL; + ENTER_TCL + err = Tcl_DeleteCommand(Tkapp_Interp(self), cmdName); + LEAVE_TCL + if (err == -1) { + PyErr_SetString(Tkinter_TclError, "can't delete Tcl command"); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + + + +#ifdef HAVE_CREATEFILEHANDLER +/** File Handler **/ + +typedef struct _fhcdata { + PyObject *func; + PyObject *file; + int id; + struct _fhcdata *next; +} FileHandler_ClientData; + +static FileHandler_ClientData *HeadFHCD; + +static FileHandler_ClientData * +NewFHCD(PyObject *func, PyObject *file, int id) +{ + FileHandler_ClientData *p; + p = PyMem_NEW(FileHandler_ClientData, 1); + if (p != NULL) { + Py_XINCREF(func); + Py_XINCREF(file); + p->func = func; + p->file = file; + p->id = id; + p->next = HeadFHCD; + HeadFHCD = p; + } + return p; +} + +static void +DeleteFHCD(int id) +{ + FileHandler_ClientData *p, **pp; + + pp = &HeadFHCD; + while ((p = *pp) != NULL) { + if (p->id == id) { + *pp = p->next; + Py_XDECREF(p->func); + Py_XDECREF(p->file); + PyMem_DEL(p); + } + else + pp = &p->next; + } +} + +static void +FileHandler(ClientData clientData, int mask) +{ + FileHandler_ClientData *data = (FileHandler_ClientData *)clientData; + PyObject *func, *file, *arg, *res; + + ENTER_PYTHON + func = data->func; + file = data->file; + + arg = Py_BuildValue("(Oi)", file, (long) mask); + res = PyEval_CallObject(func, arg); + Py_DECREF(arg); + + if (res == NULL) { + errorInCmd = 1; + PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd); + } + Py_XDECREF(res); + LEAVE_PYTHON +} + +static PyObject * +Tkapp_CreateFileHandler(PyObject *self, PyObject *args) + /* args is (file, mask, func) */ +{ + FileHandler_ClientData *data; + PyObject *file, *func; + int mask, tfile; + + if (!PyArg_ParseTuple(args, "OiO:createfilehandler", + &file, &mask, &func)) + return NULL; + tfile = PyObject_AsFileDescriptor(file); + if (tfile < 0) + return NULL; + if (!PyCallable_Check(func)) { + PyErr_SetString(PyExc_TypeError, "bad argument list"); + return NULL; + } + + data = NewFHCD(func, file, tfile); + if (data == NULL) + return NULL; + + /* Ought to check for null Tcl_File object... */ + ENTER_TCL + Tcl_CreateFileHandler(tfile, mask, FileHandler, (ClientData) data); + LEAVE_TCL + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +Tkapp_DeleteFileHandler(PyObject *self, PyObject *args) +{ + PyObject *file; + int tfile; + + if (!PyArg_ParseTuple(args, "O:deletefilehandler", &file)) + return NULL; + tfile = PyObject_AsFileDescriptor(file); + if (tfile < 0) + return NULL; + + DeleteFHCD(tfile); + + /* Ought to check for null Tcl_File object... */ + ENTER_TCL + Tcl_DeleteFileHandler(tfile); + LEAVE_TCL + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_CREATEFILEHANDLER */ + + +/**** Tktt Object (timer token) ****/ + +staticforward PyTypeObject Tktt_Type; + +typedef struct { + PyObject_HEAD + Tcl_TimerToken token; + PyObject *func; +} TkttObject; + +static PyObject * +Tktt_DeleteTimerHandler(PyObject *self, PyObject *args) +{ + TkttObject *v = (TkttObject *)self; + PyObject *func = v->func; + + if (!PyArg_ParseTuple(args, ":deletetimerhandler")) + return NULL; + if (v->token != NULL) { + Tcl_DeleteTimerHandler(v->token); + v->token = NULL; + } + if (func != NULL) { + v->func = NULL; + Py_DECREF(func); + Py_DECREF(v); /* See Tktt_New() */ + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef Tktt_methods[] = +{ + {"deletetimerhandler", Tktt_DeleteTimerHandler, 1}, + {NULL, NULL} +}; + +static TkttObject * +Tktt_New(PyObject *func) +{ + TkttObject *v; + + v = PyObject_New(TkttObject, &Tktt_Type); + if (v == NULL) + return NULL; + + Py_INCREF(func); + v->token = NULL; + v->func = func; + + /* Extra reference, deleted when called or when handler is deleted */ + Py_INCREF(v); + return v; +} + +static void +Tktt_Dealloc(PyObject *self) +{ + TkttObject *v = (TkttObject *)self; + PyObject *func = v->func; + + Py_XDECREF(func); + + PyObject_Del(self); +} + +static PyObject * +Tktt_Repr(PyObject *self) +{ + TkttObject *v = (TkttObject *)self; + char buf[100]; + + PyOS_snprintf(buf, sizeof(buf), "", v, + v->func == NULL ? ", handler deleted" : ""); + return PyString_FromString(buf); +} + +static PyObject * +Tktt_GetAttr(PyObject *self, char *name) +{ + return Py_FindMethod(Tktt_methods, self, name); +} + +static PyTypeObject Tktt_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size */ + "tktimertoken", /*tp_name */ + sizeof(TkttObject), /*tp_basicsize */ + 0, /*tp_itemsize */ + Tktt_Dealloc, /*tp_dealloc */ + 0, /*tp_print */ + Tktt_GetAttr, /*tp_getattr */ + 0, /*tp_setattr */ + 0, /*tp_compare */ + Tktt_Repr, /*tp_repr */ + 0, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash */ +}; + + + +/** Timer Handler **/ + +static void +TimerHandler(ClientData clientData) +{ + TkttObject *v = (TkttObject *)clientData; + PyObject *func = v->func; + PyObject *res; + + if (func == NULL) + return; + + v->func = NULL; + + ENTER_PYTHON + + res = PyEval_CallObject(func, NULL); + Py_DECREF(func); + Py_DECREF(v); /* See Tktt_New() */ + + if (res == NULL) { + errorInCmd = 1; + PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd); + } + else + Py_DECREF(res); + + LEAVE_PYTHON +} + +static PyObject * +Tkapp_CreateTimerHandler(PyObject *self, PyObject *args) +{ + int milliseconds; + PyObject *func; + TkttObject *v; + + if (!PyArg_ParseTuple(args, "iO:createtimerhandler", + &milliseconds, &func)) + return NULL; + if (!PyCallable_Check(func)) { + PyErr_SetString(PyExc_TypeError, "bad argument list"); + return NULL; + } + v = Tktt_New(func); + v->token = Tcl_CreateTimerHandler(milliseconds, TimerHandler, + (ClientData)v); + + return (PyObject *) v; +} + + +/** Event Loop **/ + +static PyObject * +Tkapp_MainLoop(PyObject *self, PyObject *args) +{ + int threshold = 0; +#ifdef WITH_THREAD + PyThreadState *tstate = PyThreadState_Get(); +#endif + + if (!PyArg_ParseTuple(args, "|i:mainloop", &threshold)) + return NULL; + + quitMainLoop = 0; + while (Tk_GetNumMainWindows() > threshold && + !quitMainLoop && + !errorInCmd) + { + int result; + +#ifdef WITH_THREAD + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(tcl_lock, 1); + tcl_tstate = tstate; + result = Tcl_DoOneEvent(TCL_DONT_WAIT); + tcl_tstate = NULL; + PyThread_release_lock(tcl_lock); + if (result == 0) + Sleep(20); + Py_END_ALLOW_THREADS +#else + result = Tcl_DoOneEvent(0); +#endif + + if (PyErr_CheckSignals() != 0) + return NULL; + if (result < 0) + break; + } + quitMainLoop = 0; + + if (errorInCmd) { + errorInCmd = 0; + PyErr_Restore(excInCmd, valInCmd, trbInCmd); + excInCmd = valInCmd = trbInCmd = NULL; + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +Tkapp_DoOneEvent(PyObject *self, PyObject *args) +{ + int flags = 0; + int rv; + + if (!PyArg_ParseTuple(args, "|i:dooneevent", &flags)) + return NULL; + + ENTER_TCL + rv = Tcl_DoOneEvent(flags); + LEAVE_TCL + return Py_BuildValue("i", rv); +} + +static PyObject * +Tkapp_Quit(PyObject *self, PyObject *args) +{ + + if (!PyArg_ParseTuple(args, ":quit")) + return NULL; + + quitMainLoop = 1; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +Tkapp_InterpAddr(PyObject *self, PyObject *args) +{ + + if (!PyArg_ParseTuple(args, ":interpaddr")) + return NULL; + + return PyInt_FromLong((long)Tkapp_Interp(self)); +} + + + +/**** Tkapp Method List ****/ + +static PyMethodDef Tkapp_methods[] = +{ + {"call", Tkapp_Call, 0}, + {"globalcall", Tkapp_GlobalCall, 0}, + {"eval", Tkapp_Eval, 1}, + {"globaleval", Tkapp_GlobalEval, 1}, + {"evalfile", Tkapp_EvalFile, 1}, + {"record", Tkapp_Record, 1}, + {"adderrorinfo", Tkapp_AddErrorInfo, 1}, + {"setvar", Tkapp_SetVar, 1}, + {"globalsetvar", Tkapp_GlobalSetVar, 1}, + {"getvar", Tkapp_GetVar, 1}, + {"globalgetvar", Tkapp_GlobalGetVar, 1}, + {"unsetvar", Tkapp_UnsetVar, 1}, + {"globalunsetvar", Tkapp_GlobalUnsetVar, 1}, + {"getint", Tkapp_GetInt, 1}, + {"getdouble", Tkapp_GetDouble, 1}, + {"getboolean", Tkapp_GetBoolean, 1}, + {"exprstring", Tkapp_ExprString, 1}, + {"exprlong", Tkapp_ExprLong, 1}, + {"exprdouble", Tkapp_ExprDouble, 1}, + {"exprboolean", Tkapp_ExprBoolean, 1}, + {"splitlist", Tkapp_SplitList, 1}, + {"split", Tkapp_Split, 1}, + {"merge", Tkapp_Merge, 0}, + {"createcommand", Tkapp_CreateCommand, 1}, + {"deletecommand", Tkapp_DeleteCommand, 1}, +#ifdef HAVE_CREATEFILEHANDLER + {"createfilehandler", Tkapp_CreateFileHandler, 1}, + {"deletefilehandler", Tkapp_DeleteFileHandler, 1}, +#endif + {"createtimerhandler", Tkapp_CreateTimerHandler, 1}, + {"mainloop", Tkapp_MainLoop, 1}, + {"dooneevent", Tkapp_DoOneEvent, 1}, + {"quit", Tkapp_Quit, 1}, + {"interpaddr", Tkapp_InterpAddr, 1}, + {NULL, NULL} +}; + + + +/**** Tkapp Type Methods ****/ + +static void +Tkapp_Dealloc(PyObject *self) +{ + ENTER_TCL + Tcl_DeleteInterp(Tkapp_Interp(self)); + LEAVE_TCL + PyObject_Del(self); + DisableEventHook(); +} + +static PyObject * +Tkapp_GetAttr(PyObject *self, char *name) +{ + return Py_FindMethod(Tkapp_methods, self, name); +} + +static PyTypeObject Tkapp_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size */ + "tkapp", /*tp_name */ + sizeof(TkappObject), /*tp_basicsize */ + 0, /*tp_itemsize */ + Tkapp_Dealloc, /*tp_dealloc */ + 0, /*tp_print */ + Tkapp_GetAttr, /*tp_getattr */ + 0, /*tp_setattr */ + 0, /*tp_compare */ + 0, /*tp_repr */ + 0, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash */ +}; + + + +/**** Tkinter Module ****/ + +typedef struct { + PyObject* tuple; + int size; /* current size */ + int maxsize; /* allocated size */ +} FlattenContext; + +static int +_bump(FlattenContext* context, int size) +{ + /* expand tuple to hold (at least) size new items. + return true if successful, false if an exception was raised */ + + int maxsize = context->maxsize * 2; + + if (maxsize < context->size + size) + maxsize = context->size + size; + + context->maxsize = maxsize; + + return _PyTuple_Resize(&context->tuple, maxsize) >= 0; +} + +static int +_flatten1(FlattenContext* context, PyObject* item, int depth) +{ + /* add tuple or list to argument tuple (recursively) */ + + int i, size; + + if (depth > 1000) { + PyErr_SetString(PyExc_ValueError, + "nesting too deep in _flatten"); + return 0; + } else if (PyList_Check(item)) { + size = PyList_GET_SIZE(item); + /* preallocate (assume no nesting) */ + if (context->size + size > context->maxsize && + !_bump(context, size)) + return 0; + /* copy items to output tuple */ + for (i = 0; i < size; i++) { + PyObject *o = PyList_GET_ITEM(item, i); + if (PyList_Check(o) || PyTuple_Check(o)) { + if (!_flatten1(context, o, depth + 1)) + return 0; + } else if (o != Py_None) { + if (context->size + 1 > context->maxsize && + !_bump(context, 1)) + return 0; + Py_INCREF(o); + PyTuple_SET_ITEM(context->tuple, + context->size++, o); + } + } + } else if (PyTuple_Check(item)) { + /* same, for tuples */ + size = PyTuple_GET_SIZE(item); + if (context->size + size > context->maxsize && + !_bump(context, size)) + return 0; + for (i = 0; i < size; i++) { + PyObject *o = PyTuple_GET_ITEM(item, i); + if (PyList_Check(o) || PyTuple_Check(o)) { + if (!_flatten1(context, o, depth + 1)) + return 0; + } else if (o != Py_None) { + if (context->size + 1 > context->maxsize && + !_bump(context, 1)) + return 0; + Py_INCREF(o); + PyTuple_SET_ITEM(context->tuple, + context->size++, o); + } + } + } else { + PyErr_SetString(PyExc_TypeError, "argument must be sequence"); + return 0; + } + return 1; +} + +static PyObject * +Tkinter_Flatten(PyObject* self, PyObject* args) +{ + FlattenContext context; + PyObject* item; + + if (!PyArg_ParseTuple(args, "O:_flatten", &item)) + return NULL; + + context.maxsize = PySequence_Size(item); + if (context.maxsize <= 0) + return PyTuple_New(0); + + context.tuple = PyTuple_New(context.maxsize); + if (!context.tuple) + return NULL; + + context.size = 0; + + if (!_flatten1(&context, item,0)) + return NULL; + + if (_PyTuple_Resize(&context.tuple, context.size)) + return NULL; + + return context.tuple; +} + +static PyObject * +Tkinter_Create(PyObject *self, PyObject *args) +{ + char *screenName = NULL; + char *baseName = NULL; + char *className = NULL; + int interactive = 0; + + baseName = strrchr(Py_GetProgramName(), '/'); + if (baseName != NULL) + baseName++; + else + baseName = Py_GetProgramName(); + className = "Tk"; + + if (!PyArg_ParseTuple(args, "|zssi:create", + &screenName, &baseName, &className, + &interactive)) + return NULL; + + return (PyObject *) Tkapp_New(screenName, baseName, className, + interactive); +} + +static PyMethodDef moduleMethods[] = +{ + {"_flatten", Tkinter_Flatten, 1}, + {"create", Tkinter_Create, 1}, +#ifdef HAVE_CREATEFILEHANDLER + {"createfilehandler", Tkapp_CreateFileHandler, 1}, + {"deletefilehandler", Tkapp_DeleteFileHandler, 1}, +#endif + {"createtimerhandler", Tkapp_CreateTimerHandler, 1}, + {"mainloop", Tkapp_MainLoop, 1}, + {"dooneevent", Tkapp_DoOneEvent, 1}, + {"quit", Tkapp_Quit, 1}, + {NULL, NULL} +}; + +#ifdef WAIT_FOR_STDIN + +static int stdin_ready = 0; + +#ifndef MS_WINDOWS +static void +MyFileProc(void *clientData, int mask) +{ + stdin_ready = 1; +} +#endif + +static PyThreadState *event_tstate = NULL; + +static int +EventHook(void) +{ +#ifndef MS_WINDOWS + int tfile; +#endif +#ifdef WITH_THREAD + PyEval_RestoreThread(event_tstate); +#endif + stdin_ready = 0; + errorInCmd = 0; +#ifndef MS_WINDOWS + tfile = fileno(stdin); + Tcl_CreateFileHandler(tfile, TCL_READABLE, MyFileProc, NULL); +#endif + while (!errorInCmd && !stdin_ready) { + int result; +#ifdef MS_WINDOWS + if (_kbhit()) { + stdin_ready = 1; + break; + } +#endif +#if defined(WITH_THREAD) || defined(MS_WINDOWS) + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(tcl_lock, 1); + tcl_tstate = event_tstate; + + result = Tcl_DoOneEvent(TCL_DONT_WAIT); + + tcl_tstate = NULL; + PyThread_release_lock(tcl_lock); + if (result == 0) + Sleep(20); + Py_END_ALLOW_THREADS +#else + result = Tcl_DoOneEvent(0); +#endif + + if (result < 0) + break; + } +#ifndef MS_WINDOWS + Tcl_DeleteFileHandler(tfile); +#endif + if (errorInCmd) { + errorInCmd = 0; + PyErr_Restore(excInCmd, valInCmd, trbInCmd); + excInCmd = valInCmd = trbInCmd = NULL; + PyErr_Print(); + } +#ifdef WITH_THREAD + PyEval_SaveThread(); +#endif + return 0; +} + +#endif + +static void +EnableEventHook(void) +{ +#ifdef WAIT_FOR_STDIN + if (PyOS_InputHook == NULL) { +#ifdef WITH_THREAD + event_tstate = PyThreadState_Get(); +#endif + PyOS_InputHook = EventHook; + } +#endif +} + +static void +DisableEventHook(void) +{ +#ifdef WAIT_FOR_STDIN + if (Tk_GetNumMainWindows() == 0 && PyOS_InputHook == EventHook) { + PyOS_InputHook = NULL; + } +#endif +} + + +/* all errors will be checked in one fell swoop in init_tkinter() */ +static void +ins_long(PyObject *d, char *name, long val) +{ + PyObject *v = PyInt_FromLong(val); + if (v) { + PyDict_SetItemString(d, name, v); + Py_DECREF(v); + } +} +static void +ins_string(PyObject *d, char *name, char *val) +{ + PyObject *v = PyString_FromString(val); + if (v) { + PyDict_SetItemString(d, name, v); + Py_DECREF(v); + } +} + + +DL_EXPORT(void) +init_tkinter(void) +{ + PyObject *m, *d; + + Tkapp_Type.ob_type = &PyType_Type; + +#ifdef WITH_THREAD + tcl_lock = PyThread_allocate_lock(); +#endif + + m = Py_InitModule("_tkinter", moduleMethods); + + d = PyModule_GetDict(m); + Tkinter_TclError = Py_BuildValue("s", "TclError"); + PyDict_SetItemString(d, "TclError", Tkinter_TclError); + + ins_long(d, "READABLE", TCL_READABLE); + ins_long(d, "WRITABLE", TCL_WRITABLE); + ins_long(d, "EXCEPTION", TCL_EXCEPTION); + ins_long(d, "WINDOW_EVENTS", TCL_WINDOW_EVENTS); + ins_long(d, "FILE_EVENTS", TCL_FILE_EVENTS); + ins_long(d, "TIMER_EVENTS", TCL_TIMER_EVENTS); + ins_long(d, "IDLE_EVENTS", TCL_IDLE_EVENTS); + ins_long(d, "ALL_EVENTS", TCL_ALL_EVENTS); + ins_long(d, "DONT_WAIT", TCL_DONT_WAIT); + ins_string(d, "TK_VERSION", TK_VERSION); + ins_string(d, "TCL_VERSION", TCL_VERSION); + + PyDict_SetItemString(d, "TkappType", (PyObject *)&Tkapp_Type); + + Tktt_Type.ob_type = &PyType_Type; + PyDict_SetItemString(d, "TkttType", (PyObject *)&Tktt_Type); + + +#ifdef TK_AQUA + /* Tk_MacOSXSetupTkNotifier must be called before Tcl's subsystems + * start waking up. Note that Tcl_FindExecutable will do this, this + * code must be above it! The original warning from + * tkMacOSXAppInit.c is copied below. + * + * NB - You have to swap in the Tk Notifier BEFORE you start up the + * Tcl interpreter for now. It probably should work to do this + * in the other order, but for now it doesn't seem to. + * + */ + Tk_MacOSXSetupTkNotifier(); +#endif + + + /* This helps the dynamic loader; in Unicode aware Tcl versions + it also helps Tcl find its encodings. */ + Tcl_FindExecutable(Py_GetProgramName()); + + if (PyErr_Occurred()) + return; + +#if 0 + /* This was not a good idea; through bindings, + Tcl_Finalize() may invoke Python code but at that point the + interpreter and thread state have already been destroyed! */ + Py_AtExit(Tcl_Finalize); +#endif + +#ifdef macintosh + /* + ** Part of this code is stolen from MacintoshInit in tkMacAppInit. + ** Most of the initializations in that routine (toolbox init calls and + ** such) have already been done for us, so we only need these. + */ + tcl_macQdPtr = &qd; + + Tcl_MacSetEventProc(PyMacConvertEvent); +#if GENERATINGCFM + mac_addlibresources(); +#endif /* GENERATINGCFM */ +#endif /* macintosh */ +} + + + +#ifdef macintosh + +/* +** Anyone who embeds Tcl/Tk on the Mac must define panic(). +*/ + +void +panic(char * format, ...) +{ + va_list varg; + + va_start(varg, format); + + vfprintf(stderr, format, varg); + (void) fflush(stderr); + + va_end(varg); + + Py_FatalError("Tcl/Tk panic"); +} + +/* +** Pass events to SIOUX before passing them to Tk. +*/ + +static int +PyMacConvertEvent(EventRecord *eventPtr) +{ + WindowPtr frontwin; + /* + ** Sioux eats too many events, so we don't pass it everything. We + ** always pass update events to Sioux, and we only pass other events if + ** the Sioux window is frontmost. This means that Tk menus don't work + ** in that case, but at least we can scroll the sioux window. + ** Note that the SIOUXIsAppWindow() routine we use here is not really + ** part of the external interface of Sioux... + */ + frontwin = FrontWindow(); + if ( eventPtr->what == updateEvt || SIOUXIsAppWindow(frontwin) ) { + if (SIOUXHandleOneEvent(eventPtr)) + return 0; /* Nothing happened to the Tcl event queue */ + } + return TkMacConvertEvent(eventPtr); +} + +#if GENERATINGCFM + +/* +** Additional Mac specific code for dealing with shared libraries. +*/ + +#include +#include + +static int loaded_from_shlib = 0; +static FSSpec library_fss; + +/* +** If this module is dynamically loaded the following routine should +** be the init routine. It takes care of adding the shared library to +** the resource-file chain, so that the tk routines can find their +** resources. +*/ +OSErr pascal +init_tkinter_shlib(CFragInitBlockPtr data) +{ + __initialize(); + if ( data == nil ) return noErr; + if ( data->fragLocator.where == kDataForkCFragLocator ) { + library_fss = *data->fragLocator.u.onDisk.fileSpec; + loaded_from_shlib = 1; + } else if ( data->fragLocator.where == kResourceCFragLocator ) { + library_fss = *data->fragLocator.u.inSegs.fileSpec; + loaded_from_shlib = 1; + } + return noErr; +} + +/* +** Insert the library resources into the search path. Put them after +** the resources from the application. Again, we ignore errors. +*/ +static +mac_addlibresources(void) +{ + if ( !loaded_from_shlib ) + return; + (void)FSpOpenResFile(&library_fss, fsRdPerm); +} + +#endif /* GENERATINGCFM */ +#endif /* macintosh */ diff --git a/src/patchTkinter/setup.py.in b/src/patchTkinter/setup.py.in new file mode 100644 index 00000000..3c77cb45 --- /dev/null +++ b/src/patchTkinter/setup.py.in @@ -0,0 +1,223 @@ +# Autodetecting setup.py script for building the Python extensions +# +# To be fixed: +# Implement --disable-modules setting +# + +__version__ = "$Revision: 1.1.1.1 $" + +import sys, os, getopt +from distutils import sysconfig +from distutils import text_file +from distutils.errors import * +from distutils.core import Extension, setup +from distutils.command.build_ext import build_ext + +# This global variable is used to hold the list of modules to be disabled. +disabled_module_list = [] + +def find_file(filename, std_dirs, paths): + """Searches for the directory where a given file is located, + and returns a possibly-empty list of additional directories, or None + if the file couldn't be found at all. + + 'filename' is the name of a file, such as readline.h or libcrypto.a. + 'std_dirs' is the list of standard system directories; if the + file is found in one of them, no additional directives are needed. + 'paths' is a list of additional locations to check; if the file is + found in one of them, the resulting list will contain the directory. + """ + + # Check the standard locations + for dir in std_dirs: + f = os.path.join(dir, filename) + if os.path.exists(f): return [] + + # Check the additional directories + for dir in paths: + f = os.path.join(dir, filename) + if os.path.exists(f): + return [dir] + + # Not found anywhere + return None + +def find_library_file(compiler, libname, std_dirs, paths): + filename = compiler.library_filename(libname, lib_type='shared') + result = find_file(filename, std_dirs, paths) + if result is not None: return result + + filename = compiler.library_filename(libname, lib_type='static') + result = find_file(filename, std_dirs, paths) + return result + +def module_enabled(extlist, modname): + """Returns whether the module 'modname' is present in the list + of extensions 'extlist'.""" + extlist = [ext for ext in extlist if ext.name == modname] + return len(extlist) + +class PyBuildExt(build_ext): + + def build_extensions(self): + + # Detect which modules should be compiled + self.detect_modules() + + # Remove modules that are present on the disabled list + self.extensions = [ext for ext in self.extensions + if ext.name not in disabled_module_list] + + # When you run "make CC=altcc" or something similar, you really want + # those environment variables passed into the setup.py phase. Here's + # a small set of useful ones. + compiler = os.environ.get('CC') + linker_so = os.environ.get('LDSHARED') + args = {} + # unfortunately, distutils doesn't let us provide separate C and C++ + # compilers + if compiler is not None: + (ccshared,) = sysconfig.get_config_vars('CCSHARED') + args['compiler_so'] = compiler + ' ' + ccshared + if linker_so is not None: + args['linker_so'] = linker_so + ' -shared' + self.compiler.set_executables(**args) + + build_ext.build_extensions(self) + + def build_extension(self, ext): + + try: + build_ext.build_extension(self, ext) + except (CCompilerError, DistutilsError), why: + self.announce('WARNING: building of extension "%s" failed: %s' % + (ext.name, sys.exc_info()[1])) + + def get_platform (self): + # Get value of sys.platform + platform = sys.platform + if platform[:6] =='cygwin': + platform = 'cygwin' + elif platform[:4] =='beos': + platform = 'beos' + + return platform + + def detect_modules(self): + # Ensure that /usr/local is always used + if '/usr/local/lib' not in self.compiler.library_dirs: + self.compiler.library_dirs.insert(0, '/usr/local/lib') + if '/usr/local/include' not in self.compiler.include_dirs: + self.compiler.include_dirs.insert(0, '/usr/local/include' ) + + # lib_dirs and inc_dirs are used to search for files; + # if a file is found in one of those directories, it can + # be assumed that no additional -I,-L directives are needed. + lib_dirs = self.compiler.library_dirs + ['/lib', '/usr/lib'] + inc_dirs = self.compiler.include_dirs + ['/usr/include'] + exts = [] + + platform = self.get_platform() + + # Check for MacOS X, which doesn't need libm.a at all + math_libs = ['m'] + if platform in ['Darwin1.2', 'beos']: + math_libs = [] + + # Call the method for detecting whether _tkinter can be compiled + self.detect_tkinter(inc_dirs, lib_dirs) + + + def detect_tkinter(self, inc_dirs, lib_dirs): + # The _tkinter module. + + # Assume we haven't found any of the libraries or include files + tcllib = tklib = tcl_includes = tk_includes = None + for version in ['8.4', '8.3', '8.2', '8.1', '8.0']: + tklib = self.compiler.find_library_file(lib_dirs, + 'tk' + version ) + tcllib = self.compiler.find_library_file(lib_dirs, + 'tcl' + version ) + if tklib and tcllib: + # Exit the loop when we've found the Tcl/Tk libraries + break + + # Now check for the header files + if tklib and tcllib: + # Check for the include files on Debian, where + # they're put in /usr/include/{tcl,tk}X.Y + debian_tcl_include = [ '/usr/include/tcl' + version ] + debian_tk_include = [ '/usr/include/tk' + version ] + debian_tcl_include + tcl_includes = find_file('tcl.h', inc_dirs, debian_tcl_include) + tk_includes = find_file('tk.h', inc_dirs, debian_tk_include) + + if (tcllib is None or tklib is None and + tcl_includes is None or tk_includes is None): + # Something's missing, so give up + return + + # OK... everything seems to be present for Tcl/Tk. + + include_dirs = [] ; libs = [] ; defs = [] ; added_lib_dirs = [] + for dir in tcl_includes + tk_includes: + if dir not in include_dirs: + include_dirs.append(dir) + + # Check for various platform-specific directories + platform = self.get_platform() + if platform == 'sunos5': + include_dirs.append('/usr/openwin/include') + added_lib_dirs.append('/usr/openwin/lib') + elif os.path.exists('/usr/X11R6/include'): + include_dirs.append('/usr/X11R6/include') + added_lib_dirs.append('/usr/X11R6/lib') + elif os.path.exists('/usr/X11R5/include'): + include_dirs.append('/usr/X11R5/include') + added_lib_dirs.append('/usr/X11R5/lib') + else: + # Assume default location for X11 + include_dirs.append('/usr/X11/include') + added_lib_dirs.append('/usr/X11/lib') + + # Check for BLT extension + if self.compiler.find_library_file(lib_dirs + added_lib_dirs, 'BLT8.0'): + defs.append( ('WITH_BLT', 1) ) + libs.append('BLT8.0') + + # Add the Tcl/Tk libraries + libs.append('tk'+version) + libs.append('tcl'+version) + + if platform in ['aix3', 'aix4']: + libs.append('ld') + + # Finally, link with the X11 libraries + libs.append('X11') + + ext = Extension('_tkinter', ['@srcdir@/_tkinter.c', '@srcdir@/tkappinit.c'], + define_macros=[('WITH_APPINIT', 1)] + defs, + include_dirs = include_dirs, + libraries = libs, + library_dirs = added_lib_dirs, + ) + self.extensions[0]=ext + + # XXX handle these, but how to detect? + # *** Uncomment and edit for PIL (TkImaging) extension only: + # -DWITH_PIL -I../Extensions/Imaging/libImaging tkImaging.c \ + # *** Uncomment and edit for TOGL extension only: + # -DWITH_TOGL togl.c \ + # *** Uncomment these for TOGL extension only: + # -lGL -lGLU -lXext -lXmu \ + +def main(): + setup(name = 'Python standard library', + version = '%d.%d' % sys.version_info[:2], + ext_modules=[Extension('_tkinter', ['_tkinter.c'])], + cmdclass = {'build_ext':PyBuildExt}, + ) + +# --install-platlib +if __name__ == '__main__': + #sysconfig.set_python_build() + main() diff --git a/src/patchTkinter/tkappinit.c b/src/patchTkinter/tkappinit.c new file mode 100644 index 00000000..96c545d7 --- /dev/null +++ b/src/patchTkinter/tkappinit.c @@ -0,0 +1,139 @@ +/* appinit.c -- Tcl and Tk application initialization. + + The function Tcl_AppInit() below initializes various Tcl packages. + It is called for each Tcl interpreter created by _tkinter.create(). + It needs to be compiled with -DWITH_ flags for each package + that you are statically linking with. You may have to add sections + for packages not yet listed below. + + Note that those packages for which Tcl_StaticPackage() is called with + a NULL first argument are known as "static loadable" packages to + Tcl but not actually initialized. To use these, you have to load + it explicitly, e.g. tkapp.eval("load {} Blt"). + */ + +#include +#include + +int +Tcl_AppInit(Tcl_Interp *interp) +{ + Tk_Window main_window; + +#ifdef TK_AQUA +#ifndef MAX_PATH_LEN +#define MAX_PATH_LEN 1024 +#endif + char tclLibPath[MAX_PATH_LEN], tkLibPath[MAX_PATH_LEN]; + Tcl_Obj* pathPtr; + + /* pre- Tcl_Init code copied from tkMacOSXAppInit.c */ + Tk_MacOSXOpenBundleResources (interp, "com.tcltk.tcllibrary", + tclLibPath, MAX_PATH_LEN, 0); + + if (tclLibPath[0] != '\0') { + Tcl_SetVar(interp, "tcl_library", tclLibPath, TCL_GLOBAL_ONLY); + Tcl_SetVar(interp, "tclDefaultLibrary", tclLibPath, TCL_GLOBAL_ONLY); + Tcl_SetVar(interp, "tcl_pkgPath", tclLibPath, TCL_GLOBAL_ONLY); + } + + if (tclLibPath[0] != '\0') { + Tcl_SetVar(interp, "tcl_library", tclLibPath, TCL_GLOBAL_ONLY); + Tcl_SetVar(interp, "tclDefaultLibrary", tclLibPath, TCL_GLOBAL_ONLY); + Tcl_SetVar(interp, "tcl_pkgPath", tclLibPath, TCL_GLOBAL_ONLY); + } +#endif + if (Tcl_Init (interp) == TCL_ERROR) + return TCL_ERROR; + +#ifdef TK_AQUA + /* pre- Tk_Init code copied from tkMacOSXAppInit.c */ + Tk_MacOSXOpenBundleResources (interp, "com.tcltk.tklibrary", + tkLibPath, MAX_PATH_LEN, 1); + + if (tclLibPath[0] != '\0') { + pathPtr = Tcl_NewStringObj(tclLibPath, -1); + } else { + Tcl_Obj *pathPtr = TclGetLibraryPath(); + } + + if (tkLibPath[0] != '\0') { + Tcl_Obj *objPtr; + + Tcl_SetVar(interp, "tk_library", tkLibPath, TCL_GLOBAL_ONLY); + objPtr = Tcl_NewStringObj(tkLibPath, -1); + Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); + } + + TclSetLibraryPath(pathPtr); +#endif + + if (Tk_Init (interp) == TCL_ERROR) + return TCL_ERROR; + + main_window = Tk_MainWindow(interp); + +#ifdef TK_AQUA + TkMacOSXInitAppleEvents(interp); + TkMacOSXInitMenus(interp); +#endif + +#ifdef WITH_MOREBUTTONS + { + extern Tcl_CmdProc studButtonCmd; + extern Tcl_CmdProc triButtonCmd; + + Tcl_CreateCommand(interp, "studbutton", studButtonCmd, + (ClientData) main_window, NULL); + Tcl_CreateCommand(interp, "tributton", triButtonCmd, + (ClientData) main_window, NULL); + } +#endif + +#ifdef WITH_PIL /* 0.2b5 and later -- not yet released as of May 14 */ + { + extern void TkImaging_Init(Tcl_Interp *); + TkImaging_Init(interp); + /* XXX TkImaging_Init() doesn't have the right return type */ + /*Tcl_StaticPackage(interp, "Imaging", TkImaging_Init, NULL);*/ + } +#endif + +#ifdef WITH_PIL_OLD /* 0.2b4 and earlier */ + { + extern void TkImaging_Init(void); + /* XXX TkImaging_Init() doesn't have the right prototype */ + /*Tcl_StaticPackage(interp, "Imaging", TkImaging_Init, NULL);*/ + } +#endif + +#ifdef WITH_TIX + { + extern int Tix_Init(Tcl_Interp *interp); + extern int Tix_SafeInit(Tcl_Interp *interp); + Tcl_StaticPackage(NULL, "Tix", Tix_Init, Tix_SafeInit); + } +#endif + +#ifdef WITH_BLT + { + extern int Blt_Init(Tcl_Interp *); + extern int Blt_SafeInit(Tcl_Interp *); + Tcl_StaticPackage(NULL, "Blt", Blt_Init, Blt_SafeInit); + } +#endif + +#ifdef WITH_TOGL + { + /* XXX I've heard rumors that this doesn't work */ + extern int Togl_Init(Tcl_Interp *); + /* XXX Is there no Togl_SafeInit? */ + Tcl_StaticPackage(NULL, "Togl", Togl_Init, NULL); + } +#endif + +#ifdef WITH_XXX + +#endif + return TCL_OK; +}