// $Id: Cxx.cc,v 1.115 2004/05/03 15:26:46 christof Exp $ /* glade--: C++ frontend for glade (Gtk+ User Interface Builder) * Copyright (C) 1998 Christof Petig * Copyright (C) 1999-2000 Adolf Petig GmbH & Co. KG, written by Christof Petig * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "Cxx.hh" #include #include "Configuration.hh" #include "Widget_type.hh" #include "WidgetMap.hh" // for some accesses #include #include #include #define GLADEMM_NAME PACKAGE " V" VERSION WidgetMap_t WidgetMap; static std::string ac_def_comment(const std::string &x) { if (Configuration.autoconf_version T *") .FunctionName("glademm_get") .FunctionArg("const __STD::string &name"); support_h.StartBlock(); support_h.Statement("return reinterpret_cast(glademm_get_Widget(name))"); support_h.ShortComment("2do: testen ... geht aber nicht ohne Methode gleichen Namens"); support_h.EndBlock(); support_c.Declaration("static std::map glademm_widgets"); support_c.Definition().Funct_ReturnType(WriterBase::GtkPrefix()+"Widget *") .FunctionName("glademm_get_Widget") .FunctionArg("const __STD::string &name"); support_c.StartBlock(); support_c.Declaration("std::map::iterator i=glademm_widgets.find(name)"); support_c.Statement("if (i==glademm_widgets.end()) return 0"); support_c.Statement("return (*i).second"); support_c.EndBlock(); support_c.Definition().Funct_ReturnType("void") .FunctionName("glademm_set_Widget") .FunctionArg("const __STD::string &name") .FunctionArg(WriterBase::GtkPrefix()+"Widget *val"); support_c.StartBlock(); support_c.Statement("glademm_widgets[name]=val"); support_c.EndBlock(); } if (Configuration.no_autoconf) { makefile.Dependancy("glademm_support.o"); } else { makefile_am.Dependancy(Configuration.FileName("foo",File_SUPPORT_CC,File_NODIR)); Remember(makefile_am) .Dependancy(Configuration.FileName("foo",File_SUPPORT_HH,File_NODIR)); } WriteFooter(support_h,File_SUPPORT_HH); support_h.close(); WriteFooter(support_c,File_SUPPORT_CC); support_c.close(); } } void Cxx::WriteTags() { MakeFile toplev_Make_am; SystemFile readme,authors,changelog,news,todo; SystemFile po_cl; std::string autogen_name; if (Configuration.debug) top->debug(); if (!Configuration.bare_bones) { main.open(FileNameByType(File_MAIN_CC)); WriteHeader(main,File_MAIN_CC); std::string fname(FileNameByType(File_MAKEFILE)); if (Configuration.no_autoconf) { makefile.open(fname); WriteHeader(makefile,File_MAKEFILE); } if (!Configuration.no_autoconf) { autogen_name=FileNameByType(File_AUTOGEN_SH); autogen.open(autogen_name,std::ios::out); WriteHeader(autogen,File_AUTOGEN_SH); makefile_am.open(FileNameByType(File_MAKEFILE_AM)); WriteHeader(makefile_am,File_MAKEFILE_AM); configure_in.open(FileNameByType(File_CONFIGURE_IN)); WriteHeader(configure_in,File_CONFIGURE_IN); toplev_Make_am.open(FileNameByType(File_toplevel_MAKEFILE_AM)); WriteHeader(toplev_Make_am,File_toplevel_MAKEFILE_AM); fname=FileNameByType(File_README); if (access(fname.c_str(),F_OK)) { readme.open(fname); WriteHeader(readme,File_README); } fname=FileNameByType(File_AUTHORS); if (access(fname.c_str(),F_OK)) { authors.open(fname); WriteHeader(authors,File_AUTHORS); } changelog.open(FileNameByType(File_ChangeLog,0),std::ios::app); WriteHeader(changelog,File_ChangeLog); fname=FileNameByType(File_NEWS); if (access(fname.c_str(),F_OK)) { news.open(fname); WriteHeader(news,File_NEWS); } fname=FileNameByType(File_TODO); if (access(fname.c_str(),F_OK)) { todo.open(fname); WriteHeader(todo,File_TODO); } if (Configuration.autoconf_version=Pkg_Version(2,50,0)) { f << "AC_PREREQ(2.50)\n" "AC_INIT("<< Configuration.main_filename <<", 0.0,[" << Configuration.author_email << "])\n" "AM_INIT_AUTOMAKE\n" "AC_CONFIG_HEADERS(config.h)\n"; } else { f << "AC_INIT("<< (Configuration.source_directory.c_str()+1) << '/' << Configuration.main_filename <<".cc)\n" "AM_INIT_AUTOMAKE("<< Configuration.main_filename <<", 0.0)\n"; f << "AM_CONFIG_HEADER(config.h)\n"; } f << "\n"; if (Configuration.gnome_support && GNOME1) { f << "dnl Pick up the Gnome macros.\n" "AM_ACLOCAL_INCLUDE(macros)\n" "AM_MAINTAINER_MODE\n" // needed! "\n"; } f << "AC_ISC_POSIX\n" "AC_PROG_CC\n" "AM_PROG_CC_STDC\n" "AC_HEADER_STDC\n" "AC_PROG_CPP\n" "AC_PROG_CXX\n" "AC_PROG_CXXCPP\n" "AM_PROG_LIBTOOL\n" "\n"; if (Configuration.gnome_support) f << "# GNOME--:\n" "# (These macros are in the 'macros' directory)\n" "# GNOME_INIT sets the GNOME_CONFIG variable, among other things:\n" "GNOME_INIT\n" "GNOME_COMMON_INIT\n" "GNOME_COMPILE_WARNINGS\n"; if (Configuration.gettext_support) { f << "dnl *************************************************\n" "dnl gettext support\n" "dnl *************************************************\n\n"; // as seen in glade-2 f << "GETTEXT_PACKAGE=" << Configuration.main_filename << '\n'; f << "AC_SUBST(GETTEXT_PACKAGE)\n" "AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,\"$GETTEXT_PACKAGE\""<< ac_def_comment("the gettext domain")<<")\n\n"; f << "dnl Add the languages which your application supports here.\n" "ALL_LINGUAS=\"\"\n"; if (Configuration.gettext_source==Configuration.GT_GNOME) f << "AM_GNOME_GETTEXT\n"; else if (Configuration.gettext_source==Configuration.GT_GLIB) f << "AM_GLIB_GNU_GETTEXT\n"; else // GT_GNU { f << "AM_GNU_GETTEXT_VERSION("<=Pkg_Version(2,3,0)) f << "PKG_CHECK_MODULES(GTKMM,[gtkmm-2.4 >= " << Configuration.gtkmm_version << "],,\n" "\t[PKG_CHECK_MODULES(GTKMM,[gtkmm-2.0 >= 2.0.0])])\n" "AC_SUBST(GTKMM_CFLAGS)\n" "AC_SUBST(GTKMM_LIBS)\n"; else if (GTKMM2) f << "PKG_CHECK_MODULES(GTKMM,[gtkmm-2.0 >= " << Configuration.gtkmm_version << "])\n" "AC_SUBST(GTKMM_CFLAGS)\n" "AC_SUBST(GTKMM_LIBS)\n"; else f << "AM_PATH_GTKMM("<= 2.0.0])\n" "AC_SUBST(LIBGLADE_CFLAGS)\n" "AC_SUBST(LIBGLADE_LIBS)\n"; } f << "\n"; #if 0 "dnl Subst PACKAGE_PIXMAPS_DIR.\n" "PACKAGE_PIXMAPS_DIR=\"`gnome-config --datadir`/pixmaps/${PACKAGE}\"\n" "AC_SUBST(PACKAGE_PIXMAPS_DIR)\n" #endif f << "AC_OUTPUT(Makefile " << (Configuration.source_directory.c_str()+1) << "/Makefile "; if (Configuration.ship_libintl) // glade does this too ..., but does not work on debian f << "intl/Makefile "; if (!GTKMM2) { if (Configuration.gnome_support) f << " macros/Makefile"; } f << ")\n"; break; case File_AUTOGEN_SH: if (Configuration.use_autoreconf) { // I finally gave up and resorted to doing by hand ... f << "#!/bin/sh\n" "# Run this to generate all the initial makefiles, etc.\n" "\n" "# if this does not work for you try glade-- --no-autoreconf\n" "libtoolize --force\n"; if (Configuration.gettext_support) f << "gettextize\n" // the following lines gave me an initial // working gettext environment "# if you know a better way, tell me\n" "if test ! -e po/Makevars\n" "then cp po/Makevars.template po/Makevars\n" "fi\n" "if test ! -e po/LINGUAS\n" "then touch po/LINGUAS\n" "fi\n"; f << "autoreconf --force --install\n"; } else if (Configuration.gnome_support) { if (GNOME2) { f << "#!/bin/sh\n" "# Run this to generate all the initial makefiles, etc.\n" "\n" "srcdir=`dirname $0`\n" "test -z \"$srcdir\" && srcdir=.\n" "\n" "PKG_NAME=\"the package.\"\n" "\n" "(test -f $srcdir/configure.in) || {\n" " echo -n \"**Error**: Directory \"\\`$srcdir\\'\" does not look like the\"\n" " echo \" top-level directory\"\n" " exit 1\n" "}\n" "\n" "which gnome-autogen.sh || {\n" " echo \"You need to install gnome-common from the GNOME CVS\"\n" " exit 1\n" "}\n" "USE_GNOME2_MACROS=1 . gnome-autogen.sh\n"; } else { // this is a verbatim copy of gnome-skel f << "#!/bin/sh\n" "# Run this to generate all the initial makefiles, etc.\n"; WriteCreation(f,tp); f << "# I didn't want to put a copy of 'macros' in every generated package\n" "# so I try to find them at autogen.sh time and copy them here.\n" "# (Normally if you have access to a cvs repository a copy of macros is\n" "# put into your directory at checkout time. E.g. cvs.gnome.org/gnome-common)\n" "if [ ! -e macros ]\n" "then\n" " GLADE_MACROS=`which glade | sed -e 's-bin/glade-share/glade-'`\n" " if [ -r $GLADE_MACROS/gnome/gnome.m4 ]\n" " then\n" // IIRC: this behaviour is standard for older cp, they // do not accept this flag // on the other hand a recent gnome (debian-sid) has // symbolic _relative_ links (deadly when copied) " if cp --dereference /dev/null /dev/zero\n" " then\n" " cp -r --dereference $GLADE_MACROS/gnome macros\n" " else\n" " cp -r $GLADE_MACROS/gnome macros\n" " fi\n" " else\n" " echo \"I can't find glade's gnome m4 macros. Please copy them to ./macros and retry.\"\n" " exit 2\n" " fi\n" "fi\n"; f << "\n" "srcdir=`dirname $0`\n" "test -z \"$srcdir\" && srcdir=.\n" "\n" // FIXME: package name? "PKG_NAME=\"" << Configuration.main_filename << "\"\n" "\n" "(test -f $srcdir/configure.in \\\n" "## put other tests here\n" ") || {\n" " echo -n \"**Error**: Directory \"\\`$srcdir\\'\" does not look like the\"\n" " echo \" top-level $PKG_NAME directory\"\n" " exit 1\n" "}\n" "\n" "export ACLOCAL_FLAGS=\"-I `pwd`/macros $ACLOCAL_FLAGS\"\n" // "ACLOCAL_FLAGS=\"$ACLOCAL_FLAGS -I `aclocal --print-ac-dir`/gnome\" . `aclocal --print-ac-dir`/gnome/autogen.sh\n"; ". $srcdir/macros/autogen.sh\n"; } } else {f << "#!/bin/sh\n"; WriteCreation(f,tp); f << "\n" "if test ! -f install-sh ; then touch install-sh ; fi\n" "\n" "MAKE=`which gnumake`\n" "if test ! -x \"$MAKE\" ; then MAKE=`which gmake` ; fi\n" "if test ! -x \"$MAKE\" ; then MAKE=`which make` ; fi\n" "HAVE_GNU_MAKE=`$MAKE --version|grep -c \"Free Software Foundation\"`\n" "\n" "if test \"$HAVE_GNU_MAKE\" != \"1\"; then \n" "echo Only non-GNU make found: $MAKE\n" "else\n" "echo `$MAKE --version | head -1` found\n" "fi\n" "\n"; if (Configuration.autoconf_version>=Pkg_Version(2,50,0)) // I assume that a newer automake will be good as well { f << "if which autoconf2.50 >/dev/null 2>&1\n" "then AC_POSTFIX=2.50\n" "elif which autoconf >/dev/null 2>&1\n" "then AC_POSTFIX=\"\"\n" "else \n" " echo 'you need autoconfig (2.58+ recommended) to generate the Makefile'\n" " exit 1\n" "fi\n" "echo `autoconf$AC_POSTFIX --version | head -1` found\n" "\n" "if which automake-1.9 >/dev/null 2>&1\n" "then AM_POSTFIX=-1.9\n" "elif which automake-1.8 >/dev/null 2>&1\n" "then AM_POSTFIX=-1.8\n" "elif which automake-1.7 >/dev/null 2>&1\n" "then AM_POSTFIX=-1.7\n" "elif which automake-1.6 >/dev/null 2>&1\n" "then AM_POSTFIX=-1.6\n" "elif which automake >/dev/null 2>&1\n" "then AM_POSTFIX=\"\"\n" "else\n" " echo 'you need automake (1.8.3+ recommended) to generate the Makefile'\n" " exit 1\n" "fi\n" "echo `automake$AM_POSTFIX --version | head -1` found\n" "\n"; } else f << "if test ! -x `which aclocal`\n" "then echo you need autoconfig and automake to generate the Makefile\n" "fi\n" "if test ! -x `which automake`\n" "then echo you need automake to generate the Makefile\n" "fi\n" "\n"; f << "echo This script runs configure and make...\n" "echo You did remember necessary arguments for configure, right?\n" "\n"; f << "# autoreconf$AC_POSTFIX -fim _might_ do the trick, too.\n" "# chose to your taste\n"; f << "aclocal$AM_POSTFIX\n"; f << "libtoolize --force --copy\n"; if (Configuration.gettext_support) f << "gettextize\n" // the following lines gave me an initial // working gettext environment "if test ! -e po/Makevars\n" "then cp po/Makevars.template po/Makevars\n" "fi\n" "if test ! -e po/LINGUAS\n" "then touch po/LINGUAS\n" "fi\n"; f << "autoheader$AC_POSTFIX\n"; f << "automake$AM_POSTFIX --add-missing --copy --gnu\n" "autoconf$AC_POSTFIX\n" "./configure $* && $MAKE\n"; } break; case File_toplevel_MAKEFILE_AM: WriteCreation(f,tp); if (Configuration.gnome_support) { f << "AUTOMAKE_OPTIONS = 1.4\n" "\n"; #if 0 // doesn't work for me (wrong path) "if MAINTAINER_MODE\n" "include $(GNOME_ACLOCAL_DIR)/gnome-macros.dep\n" "endif\n" "\n"; #endif } f << "\nSUBDIRS = "; if (Configuration.gettext_support) f << "po "; if (Configuration.ship_libintl) f << "intl "; if (!GTKMM2) { if (Configuration.gnome_support) f << "macros "; } f << (Configuration.source_directory.c_str()+1) << ' '; f << "\n" "\n" "EXTRA_DIST = AUTHORS TODO README configure "; // if (Configuration.gnome_support) // f << "\\\n""\tmacros/* "; f << "\n"; break; case File_README: WriteCreation(f,tp); f << "\nThis project was generated using glade--\n" "and the README file has not been edited since then ;-).\n"; break; case File_AUTHORS: { if (!Configuration.author_name.empty()) f << Configuration.author_name << " <" << Configuration.author_email << ">"; else if (!Configuration.author_email.empty()) f << Configuration.author_email; f << '\n'; break; } case File_ChangeLog: case File_po_ChangeLog: { f << '\n'; time_t t=time(0); struct tm *tm=localtime(&t); f << tm->tm_year+1900 << '/' << tm->tm_mon+1 << '/' << tm->tm_mday; f << ' '<< tm->tm_hour << ':'; char oldfill=f.OStream().fill('0'); int oldwidth=f.OStream().width(2); f << tm->tm_min << ':'; f.OStream().fill('0'); f.OStream().width(2); f << tm->tm_sec << ' ' << tzname[tm->tm_isdst]; f.OStream().fill(oldfill); f.OStream().width(oldwidth); f << "\n\tupdate files from .glade file\n"; break; } case File_NEWS: break; case File_TODO: f << "- fill README file with something useful\n"; break; case File_po_POTFILES_in: f << "# List of source files containing translatable strings.\n"; f << FileNameByType(File_MAIN_CC,0) << '\n'; break; default: assert(0); } } void Cxx::WriteFooter(CxxFile &f,File_type tp) { if (!f.good()) return; switch(tp) { case File_FOO_HH: case File_FOO_GLADE_HH: assert(0); break; case File_MAIN_CC: f.Definition().Funct_ReturnType("int").FunctionName("main") .FunctionArg("int argc").FunctionArg("char **argv"); f.StartBlock(); if (Configuration.gettext_support) { f.CppIf("defined(ENABLE_NLS)"); f.Statement("bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR)"); if (GTKMM2) f.Statement("bind_textdomain_codeset(GETTEXT_PACKAGE, \"UTF-8\")"); f.Statement("textdomain (GETTEXT_PACKAGE)"); f.EndIf("ENABLE_NLS"); } if (!Configuration.gnome_support) f.Declaration(WriterBase::GtkPrefix()+"Main m(&argc, &argv)"); else { // perhaps trouble with gnome 2.0 and automake 1.5 ? // because there PACKAGE is not defined ? if (GNOME2) { f.Declaration() << WriterBase::GnomePrefix()+"Main m(" << "PACKAGE, VERSION, " << WriterBase::GnomeUIPrefix()+"module_info_get(), " << "argc, argv)"; // FIXME: This is a kludge. Until the day libgnomeuimm // properly initializes bonobouimm (there's a FIXME in // the source there), we need to call wrap_init() // ourself. f.Statement("Gnome::Bonobo::wrap_init()"); } else { f.Declaration() << WriterBase::GnomePrefix()+"Main m(" << "PACKAGE, VERSION, argc, argv)"; } } // isn't there a possibility to set an image path? if (Configuration.use_libglade) { std::string gnome(Configuration.gnome_support?"_gnome":""); f.Statement() << "glade"<Type()=="widget") { Widget w(*i); if (Configuration.libglade_support) { assert(w.getProperty("cxx_visibility","private")=="public"); // needs to access member widget pointer // since libglade classes do not inherit from Gtk::Widget f << "*static_cast<" << // this is not correct, this should be a TypeName call Configuration.InstanceName(w.Name()) << "_glade*>(" << Configuration.InstanceName(w.Name()) << ")->" << Configuration.InstanceName(w.Name()); } else f << '*' << Configuration.InstanceName(w.Name()); break; } } } f <<")"; f.EndLine(); f.write_remembered(1); f.Statement("return 0"); f.EndBlock(); break; case File_SUPPORT_HH: f << "#endif /* GLADEMM_SUPPORT_HH */\n"; break; default: break; } } void Cxx::WriteFooter(SystemFile &f,File_type tp) { if (!f.good()) return; switch(tp) { case File_FOO_HH: case File_MAIN_CC: case File_SUPPORT_HH: case File_ACCONFIG_H: case File_FOO_GLADE_HH: assert(0); break; case File_MAKEFILE_AM: f << "\n\n"; f.write_remembered(); f << "\n\n"; if (Configuration.automake_version>=Pkg_Version(1,5,0)) f << "AM_CXXFLAGS = "; else f << "CXXFLAGS = @CXXFLAGS@ "; if (Configuration.gnome_support) f << "@GNOMEMM_CFLAGS@ "; else f << "@GTKMM_CFLAGS@ "; if (Configuration.libglade_support) f << "@LIBGLADE_CFLAGS@ "; f << '\n'; if (Configuration.gnome_support && Configuration.automake_version=File_NUM_CXX_FILES)?"#":"//"; f << comment << " generated "; f << tm->tm_year+1900 << '/' << tm->tm_mon+1 << '/' << tm->tm_mday; f << ' '<< tm->tm_hour << ':'; char oldfill=f.OStream().fill('0'); int oldwidth=f.OStream().width(2); f << tm->tm_min << ':'; f.OStream().fill('0'); f.OStream().width(2); f << tm->tm_sec << ' ' << tzname[tm->tm_isdst]; f.OStream().fill(oldfill); f.OStream().width(oldwidth); if (!Configuration.author_email.empty()) f << " by " << Configuration.author_email; f << '\n'; f << comment << " using "GLADEMM_NAME"\n"; } /* REMEMBERED LINES: following files use remember() for their purposes: - makefile_am: list of header files - main: 0 creation of toplevel components - main: 1 deletion of heap objects */ const std::string Cxx::FileNameByType(const File_type &tp,int flags) { return Configuration.FileName("foo",tp,flags); }