Fixed a compiler warning

master
Yevgen Muntyan 2017-10-25 15:38:16 -07:00
commit 694ed16f11
1017 changed files with 330771 additions and 0 deletions

57
.hgignore Normal file
View File

@ -0,0 +1,57 @@
syntax: glob
Makefile.in
depcomp
compile
config.guess
config.sub
configure
doc/help.stamp
install-sh
ltmain.sh
test-driver
m4/intltool.m4
m4/libtool.m4
m4/ltoptions.m4
m4/ltsugar.m4
m4/ltversion.m4
m4/lt~obsolete.m4
missing
po-gsv/Makefile.in.in
po/Makefile.in.in
build/
autom4te.cache/
aclocal.m4
*~
*.orig
*.bak
*.tmp
*.rej
*.pyc
.goutputstream-*
po*/dist
po*/pot
po/notexist
po/missing
config.h.in
plat/win32/gtk-win/tarballs/
plat/win32/gtk-win/debug/
plat/win32/gtk-win/release/
plat/win32/gtk-win/bdist-debug/
plat/win32/gtk-win/bdist-release/
api/moo.xml
api/gtk.xml
moo/plugins/usertools/old/
moo/moopython/pygtk/moo-generated.defs
moo/moopython/plugins/old/
moo/moolua/moo-lua-api.cpp
moo/moolua/gtk-lua-api.cpp
doc/help/
doc/built/
po-gsv/po-original/
po-gsv/po-stripped/
plat/msvs/deps/
plat/msvs/Debug/
plat/msvs/medit.ncb
plat/msvs/medit.suo
plat/msvs/medit.vcproj.*.user
plat/msvs/medit.sln

5
AUTHORS Normal file
View File

@ -0,0 +1,5 @@
Yevgen Muntyan <emuntyan@users.sourceforge.net>
Daniel Poelzleithner <mooedit@poelzi.org>
Lasse Makholm
Ryan Anonymous
Ulrich Eckhardt <ulrich.eckhardt@base-42.de>

237
CMakeLists.txt Normal file
View File

@ -0,0 +1,237 @@
cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0048 NEW)
if(WIN32)
include(cmake/PrecompiledHeader.cmake)
endif()
list(APPEND EXTRA_DIST
tools/genenums.py
tools/glade2c.py
tools/xml2h.py
plat/win32/installer.iss.in
plat/win32/istrans.sh
plat/win32/mingw-configure
)
# zzz
# if MOO_OS_WIN32
# plat/win32/installer.iss: $(top_srcdir)/plat/win32/installer.iss.in $(top_builddir)/config.status
# $(AM_V_at)$(MKDIR_P) plat/win32
# $(AM_V_GEN)cd $(top_builddir) && ./config.status --silent --file=plat/win32/installer.iss
# installer: plat/win32/installer.iss install
# $(MEDIT_INNO_COMPILER) plat/win32/installer.iss
# copy:
# cp moo/medit.exe "/win/Program Files (x86)/medit/bin/"
# bd_tmpdir = medit-win-dist-tmp
# bd_distdir = $(PACKAGE)-$(VERSION)
# bd_pzip = $(PACKAGE)-portable-$(VERSION)
# bd_zip = $(PACKAGE)-$(VERSION)
# portable: install
# rm -fr $(bd_tmpdir)
# mkdir $(bd_tmpdir)
# cp -lR ${prefix} $(bd_tmpdir)/$(bd_distdir)
# cd $(bd_tmpdir) && zip -r9 $(bd_zip).zip $(bd_distdir)
# echo "This file enables portable mode for medit" > $(bd_tmpdir)/$(bd_distdir)/bin/$(MEDIT_PORTABLE_MAGIC_FILE_NAME)
# cd $(bd_tmpdir) && zip -r9 $(bd_pzip).zip $(bd_distdir)
# mv $(bd_tmpdir)/$(bd_pzip).zip $(bd_tmpdir)/$(bd_zip).zip .
# rm -fr $(bd_tmpdir)
# bdist: installer portable
# endif
# zzz @MOO_PO_SUBDIRS_RULE@
set(MOO_MAJOR_VERSION 1)
set(MOO_MINOR_VERSION 2)
set(MOO_MICRO_VERSION 90)
set(_moo_version_suffix_ "-devel")
set(MOO_MODULE_MAJOR_VERSION 2)
set(MOO_MODULE_MINOR_VERSION 0)
set(MOO_VERSION "${MOO_MAJOR_VERSION}.${MOO_MINOR_VERSION}.${MOO_MICRO_VERSION}")
set(MOO_DISPLAY_VERSION "${MOO_VERSION}${_moo_version_suffix_}")
project(medit VERSION ${MOO_VERSION})
# keep in sync with po/maintain
set(MOO_PACKAGE_NAME "medit-1")
set(MOO_WEBSITE "http://mooedit.sourceforge.net/")
set(MOO_WEB_CONTACT "http://mooedit.sourceforge.net/contact.html")
set(MOO_EMAIL "emuntyan@users.sourceforge.net")
set(MOO_COPYRIGHT "2004-2015 Yevgen Muntyan <${MOO_EMAIL}>")
set(MOO_PREFS_XML_FILE_NAME "prefs.xml")
set(MOO_STATE_XML_FILE_NAME "state.xml")
set(MOO_NAMED_SESSION_XML_FILE_NAME "session-%s.xml")
set(MOO_SESSION_XML_FILE_NAME "session.xml")
set(MEDIT_PORTABLE_MAGIC_FILE_NAME "medit-portable")
set(MEDIT_PORTABLE_DATA_DIR "medit-portable-data")
set(MEDIT_PORTABLE_CACHE_DIR "medit-portable-cache")
set(MOO_DATA_DIR "share/${MOO_PACKAGE_NAME}")
set(MOO_LIB_DIR "lib/${MOO_PACKAGE_NAME}")
set(MOO_DOC_DIR "share/doc/${MOO_PACKAGE_NAME}")
set(MOO_HELP_DIR "${MOO_DOC_DIR}/help")
set(MOO_TEXT_LANG_FILES_DIR "${MOO_DATA_DIR}/language-specs")
set(MOO_PYTHON_PLUGIN_DIR "${MOO_DATA_DIR}/plugins")
set(MOO_PYTHON_LIB_DIR "${MOO_DATA_DIR}/python")
if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif()
if(WIN32 AND CMAKE_CONFIGURATION_TYPES)
set(CMAKE_CONFIGURATION_TYPES Release Debug)
set(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING
"Reset the configurations to what we need" FORCE)
endif()
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
if(WIN32)
set(MOO_OS_WIN32 TRUE)
else()
set(MOO_OS_UNIX TRUE)
endif()
set(MOO_BUILD_FROM_MSVC ${MOO_OS_WIN32} CACHE BOOL "Create a win32 build from MSVC gtk build")
set(MOO_BUILD_FROM_MINGW FALSE CACHE BOOL "Create a win32 build from mingw gtk build")
if(NOT MOO_BUILD_FROM_MINGW AND NOT MOO_BUILD_FROM_MSVC)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED gtk+-2.0)
pkg_check_modules(GMODULE REQUIRED gmodule-2.0)
#execute_process(
# COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=glib_genmarshal glib-2.0
# OUTPUT_VARIABLE GLIB_GENMARSHAL
# OUTPUT_STRIP_TRAILING_WHITESPACE
# RESULT_VARIABLE RESULT)
#if(NOT RESULT EQUAL 0)
# MESSAGE(FATAL_ERROR "Could not find glib-genmarshal")
#endif()
execute_process(
COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=glib_mkenums glib-2.0
OUTPUT_VARIABLE GLIB_MKENUMS
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE RESULT)
if(NOT RESULT EQUAL 0)
MESSAGE(FATAL_ERROR "Could not find glib-mkenums")
endif()
pkg_check_modules(XLIB x11 xext xrender ice sm)
pkg_check_modules(LIBXML2 REQUIRED libxml-2.0)
else()
if(MOO_BUILD_FROM_MINGW)
set(MOO_GTK_DIR "C:/Projects/gtk/release/target" CACHE PATH "Gtk root dir")
set(MOO_GTK_DIST_DIR "C:/Projects/gtk/release/bdist" CACHE PATH "Gtk binary dir")
set(GTK_LIBRARIES libgtk-win32-2.0-0 libatk-1.0-0 libgdk-win32-2.0-0 libgdk_pixbuf-2.0-0
libpango-1.0-0 libpangocairo-1.0-0 libcairo-2
libgio-2.0-0 libgobject-2.0-0 libgmodule-2.0-0 libgthread-2.0-0 libglib-2.0-0 libintl-8
libmooglib-0)
set(LIBXML2_LIBRARIES "libxml2-2")
else()
set(MOO_GTK_DIR "C:/gtk-build/gtk/x64/release" CACHE PATH "Gtk root dir")
set(MOO_GTK_DIST_DIR "C:/gtk-build/gtk/x64/bdist" CACHE PATH "Gtk binary dir")
set(MOO_PYTHON_DIST_DIR "C:/projects/python-bdist" CACHE PATH "Python binary dir")
set(GTK_LIBRARIES atk-1.0 cairo gdk_pixbuf-2.0 gdk-win32-2.0 gio-2.0 glib-2.0 gmodule-2.0 gobject-2.0
gthread-2.0 gtk-win32-2.0 iconv intl libffi libpng16 pango-1.0 pangocairo-1.0 pixman-1 zlib1)
set(LIBXML2_LIBRARIES libxml2)
endif()
#set(CMAKE_INSTALL_PREFIX ${MOO_GTK_DIR} CACHE PATH "CMake install prefix" FORCE)
include_directories(SYSTEM "${MOO_GTK_DIR}/include")
include_directories(SYSTEM "${MOO_GTK_DIR}/include/glib-2.0")
include_directories(SYSTEM "${MOO_GTK_DIR}/lib/glib-2.0/include")
include_directories(SYSTEM "${MOO_GTK_DIR}/lib/gtk-2.0/include")
include_directories(SYSTEM "${MOO_GTK_DIR}/include/gtk-2.0")
include_directories(SYSTEM "${MOO_GTK_DIR}/include/gdk-pixbuf-2.0")
include_directories(SYSTEM "${MOO_GTK_DIR}/include/pango-1.0")
include_directories(SYSTEM "${MOO_GTK_DIR}/include/atk-1.0")
include_directories(SYSTEM "${MOO_GTK_DIR}/include/cairo")
include_directories(SYSTEM "${MOO_GTK_DIR}/include/libxml2")
set(GTK_LIBRARY_DIRS "${MOO_GTK_DIR}/lib")
set(ENV{PATH} "ENV{PATH};${MOO_GTK_DIR}/bin")
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/moo/mooutils/moowin32/ms")
foreach(var CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
set(${var} "${${var}} /MP /Zo /wd4996")
# "C4706: assignment within conditional expression" - it's a good warning, it catches
# 'if(x = 5)'. Unfortunately it also complains about 'while ((p = x()))' which is fine
# and is used a lot. Additional parentheses don't silence it, unlike with gcc.
set(${var} "${${var}} /W4 /WX /wd4244 /wd4800 /wd4100 /wd4127 /wd4054 /wd4055 /wd4306 /wd4706 /wd4125 /wd4389 /wd4152 /wd4505")
set(${var}_RELEASE "${${var}_RELEASE} /Zi")
string(REPLACE "/Ob1" "/Ob2" ${var}_RELWITHDEBINFO "${${var}_RELWITHDEBINFO}")
if (true)
# /MDd means link with the debug crt library, which we don't want; and /D_DEBUG forces
# that as well because of some includes; turn them off.
string(REPLACE "/MDd" "/MD" ${var}_DEBUG "${${var}_DEBUG}")
string(REPLACE "/D_DEBUG" "/DENABLE_DEBUG=1 /DDEBUG=1 /DMOO_DEBUG=1" ${var}_DEBUG "${${var}_DEBUG}")
else()
string(REPLACE "/D_DEBUG" "/DENABLE_DEBUG=1 /DDEBUG=1 /DMOO_DEBUG=1 /D_DEBUG" ${var}_DEBUG "${${var}_DEBUG}")
endif()
endforeach()
foreach(mode EXE MODULE SHARED STATIC)
set(CMAKE_${mode}_LINKER_FLAGS "${CMAKE_${mode}_LINKER_FLAGS} /DEBUG")
endforeach()
endif()
find_program(GLIB_GENMARSHAL glib-genmarshal HINTS ${MOO_GTK_DIR}/bin/glib-genmarshal.exe)
find_program(GDK_PIXBUF_CSOURCE gdk-pixbuf-csource HINTS ${MOO_GTK_DIR}/bin/gdk-pixbuf-csource.exe)
#find_library(LIBM m)
find_package(Gettext REQUIRED)
set(GETTEXT_PACKAGE "${MOO_PACKAGE_NAME}")
set(GETTEXT_PACKAGE_GSV "${MOO_PACKAGE_NAME}-gsv")
# MOO_INTL
set(PythonInterp_FIND_VERSION TRUE)
set(PythonInterp_FIND_VERSION_MAJOR 2)
find_package(PythonInterp REQUIRED)
set(MOO_PYTHON "${PYTHON_EXECUTABLE}")
set(MOO_ENABLE_PYTHON TRUE CACHE BOOL "Use python")
add_definitions(-DHAVE_CONFIG_H=1 -DXDG_PREFIX=_moo_edit_xdg -DG_LOG_DOMAIN=\"Moo\")
#add_definitions(-DGDK_DISABLE_DEPRECATED=1)
#add_definitions(-DGTK_DISABLE_DEPRECATED=1)
if(WIN32)
add_definitions(-DUNICODE=1 -D_UNICODE=1 -D__WIN32__=1 -DSTRICT=1 -D_CRT_SECURE_NO_WARNINGS=1 -D_CRT_NONSTDC_NO_WARNINGS=1)
set(MOO_NEED_GETTIMEOFDAY TRUE)
set(HAVE_UNISTD_H TRUE)
set(HAVE_BIND_TEXTDOMAIN_CODESET TRUE)
list(APPEND MEDIT_LIBS Shlwapi.lib)
endif(WIN32)
# zzz SUBDIRS = po po-gsv api doc moo
add_subdirectory(api)
# add_subdirectory(doc)
#set(ENABLE_NLS TRUE)
#add_subdirectory(po)
#add_subdirectory(po-gsv)
add_subdirectory(moo)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config-cmake.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
if(WIN32)
install(DIRECTORY plat/win32/medit-data/bin plat/win32/medit-data/etc DESTINATION .)
endif(WIN32)
if(WIN32)
include(plat/win32/installer.cmake)
endif()

504
COPYING Normal file
View File

@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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, or (at your option) any later version.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

339
COPYING.GPL Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

28
INSTALL Normal file
View File

@ -0,0 +1,28 @@
medit uses autotools for the build. Quick build with default options:
tar xjf medit-x.x.x.tar.bz2
cd medit-x.x.x
./configure
make
make install
This will configure, build, and install medit to /usr/local.
medit requires development packages of the following: gtk2, libxml2, python2, pygtk2.
For example, on Debian you may need to install libgtk2.0-dev, libxml2-dev, python2.7-dev, python-gtk2-dev.
If you checked out a copy of mercurial repository, then do the following to build:
./autogen.sh
./configure --enable-dev-mode
make
make install
Building medit from Mercurial requires the following, in addition to the dependencies
listed above: automake, autoconf, libtool, intltool, docbook, xsltproc, txt2tags.
Other tools may be required and configure may not check for them, please report those
to the author.
To build a python module which could be used in other programs, use
--enable-moo-module --enable-shared --disable-static configure flags in addition
to above.

85
LICENSE Normal file
View File

@ -0,0 +1,85 @@
medit is distributed under GPL version 2 licence, its text
you can find in COPYING.GPL file. Nevertheless, everything but
several lang files (see the list below) is under LGPL version
2.1 or "version 2.1 or later", see COPYING file for its text.
Portions of code are written not by me, those are clearly
marked as such (copyright headers in files copied from other
projects, or comments in source). Below is the list of
third-party files/code with their copyrights and licenses.
If you want to use my code and LGPL doesn't work for you
because you have special clause in your license which is not
LGPL-compatible, or other garbage like that, I will gladly
release it under double license, or do something like that.
Just tell me what exactly is needed.
If you aren't too picky about legal stuff, then you can simply
take code and use it in free software as you like, provided
you leave the copyright and project name in there (unless it's a
small portion of code of course, simple copy/paste must be free
as in WTFPL). This applies to all files (and only to those) which
do have copyright notice inside; WTFPL will work fine for the rest.
Third-party stuff, for debian/copyright. Everything below
is under LGPL unless noted otherwise.
moo/moolua/lua/*:
Lua, LuaFileSystem. Distributed under MIT
license, see moo/moolua/COPYRIGHT, moo/moolua/ext/README.lfs.
Copyright (C) 1994-2007 Lua.org, PUC-Rio.
Copyright 2003-2007 PUC-Rio
moo/mooedit/plugins/ctags/readtags.[hc]
Exuberant Ctags code, public domain
Copyright (c) 1996-2003, Darren Hiebert
moo/mooutils/moofontsel.h:
moo/mooutils/moofontsel.c:
GTK font selector modified to show monospace fonts
(C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
moo/mooutils/mooencodings-data.h:
(C) 2002 Red Hat, Inc.
(C) 2000-2002 Free Software Foundation, Inc.
moo/mooapp/smclient/*: - eggsmclient library
(C) 2007 Novell, Inc.
moo/mooutils/pcre/*: pcre library by by Philip Hazel
BSD-licensed, (C) 1997-2006 University of Cambridge
moo/mooedit/gtksourceview/upstream/*:
moo/mooedit/language-specs/*:
gtksourceview library
Written over many years by many people, see the files.
Among those, GPL'ed files:
moo/mooedit/language-specs/gtkrc.lang
moo/mooedit/language-specs/ini.lang
moo/mooedit/language-specs/lua.lang
moo/mooedit/language-specs/msil.lang
moo/mooedit/language-specs/nemerle.lang
moo/mooedit/language-specs/pascal.lang
moo/mooedit/language-specs/php.lang
moo/mooedit/language-specs/R.lang
moo/mooedit/language-specs/ruby.lang
moo/moopython/codegen/*: pygtk codegen
(C) 2004 Gustavo Carneiro <gjc@gnome.org>
(C) ???? James Henstridge <james@daa.com.au>
(C) ???? Johan Dahlin <johan@gnome.org>
moo/mooutils/xdgmime/*: xdgmime library
(C) 2003,2004 Red Hat, Inc.
(C) 2003,2004 Jonathan Blandford <jrb@alum.mit.edu>
moo/xdg-utils:
Looks like some sort of BSD license
(C) 2006 Kevin Krammer <kevin.krammer@gmx.at>
(C) 2006 Jeremy White <jwhite@codeweavers.com>
moo/mooutils/pixmaps/medit.png:
xedit.png icon from Crystal Clear icon theme by Everaldo Coelho,
http://www.everaldo.com

58
Makefile.am Normal file
View File

@ -0,0 +1,58 @@
ACLOCAL_AMFLAGS = -I m4 $(ACLOCAL_FLAGS)
SUBDIRS = po po-gsv api doc moo
EXTRA_DIST = \
tools/genenums.py \
tools/glade2c.py \
tools/xml2h.py
DISTCHECK_CONFIGURE_FLAGS =
if MOO_DEV_MODE
DISTCHECK_CONFIGURE_FLAGS += MAKEFLAGS=-j3
endif
if MOO_STRICT_MODE
DISTCHECK_CONFIGURE_FLAGS += --enable-strict
endif
CLEANFILES =
include plat/win32/Makefile.incl
if MOO_OS_WIN32
CLEANFILES += plat/win32/installer.iss
plat/win32/installer.iss: $(top_srcdir)/plat/win32/installer.iss.in $(top_builddir)/config.status
$(AM_V_at)$(MKDIR_P) plat/win32
$(AM_V_GEN)cd $(top_builddir) && ./config.status --silent --file=plat/win32/installer.iss
installer: plat/win32/installer.iss install
$(MEDIT_INNO_COMPILER) plat/win32/installer.iss
copy:
cp moo/medit.exe "/win/Program Files (x86)/medit/bin/"
bd_tmpdir = medit-win-dist-tmp
bd_distdir = $(PACKAGE)-$(VERSION)
bd_pzip = $(PACKAGE)-portable-$(VERSION)
bd_zip = $(PACKAGE)-$(VERSION)
portable: install
rm -fr $(bd_tmpdir)
mkdir $(bd_tmpdir)
cp -lR ${prefix} $(bd_tmpdir)/$(bd_distdir)
cd $(bd_tmpdir) && zip -r9 $(bd_zip).zip $(bd_distdir)
echo "This file enables portable mode for medit" > $(bd_tmpdir)/$(bd_distdir)/bin/$(MEDIT_PORTABLE_MAGIC_FILE_NAME)
cd $(bd_tmpdir) && zip -r9 $(bd_pzip).zip $(bd_distdir)
mv $(bd_tmpdir)/$(bd_pzip).zip $(bd_tmpdir)/$(bd_zip).zip .
rm -fr $(bd_tmpdir)
bdist: installer portable
endif
test:
$(MAKE) $(AM_MAKEFLAGS) all
$(MAKE) $(AM_MAKEFLAGS) check
$(MAKE) $(AM_MAKEFLAGS) uninstall
$(MAKE) $(AM_MAKEFLAGS) check
$(MAKE) $(AM_MAKEFLAGS) install
$(MAKE) $(AM_MAKEFLAGS) installcheck
fullcheck:
$(MAKE) $(AM_MAKEFLAGS) test
$(MAKE) $(AM_MAKEFLAGS) distcheck
@MOO_PO_SUBDIRS_RULE@

651
NEWS Normal file
View File

@ -0,0 +1,651 @@
2014-03-20 Yevgen Muntyan <emuntyan@users.sourceforge.net>
* === Released 1.2.0 ===
Updated Spanish translation by Eulogio Serradilla.
New Polish translation by Piotr Orzechowski.
Fixed a bug in parsing grep output for UNC paths on windows.
Updated syntax highlighting definitions.
Fixed compilation with new glib and gcc.
Exposed more functionality, in particular the output pane, to scripts.
Finally made file completion case-insensitive on windows.
2012-11-25 Yevgen Muntyan <emuntyan@users.sourceforge.net>
* === Released 1.1.2 ===
Updated Japanese translation from Toshiharu Kudoh.
Updated German translation by Debianer.
Partial workaround for the Gtk bug with Shift key: make Shift-Fn
key combinations work as global shortcuts.
2012-07-27 Yevgen Muntyan <emuntyan@users.sourceforge.net>
* === Released 1.1.1 ===
Fixed some build errors:
Check for sys/wait.h, so that HAVE_SYS_WAIT_H is defined when needed.
Link with gmodule explicitly.
2012-03-04 Yevgen Muntyan <emuntyan@users.sourceforge.net>
* === Released 1.1.0 ===
Fixed few memory leaks.
Improved documentation.
Made lua scripts use UTF-8 strings by default.
Fixed font selector in terminal pane.
Fixed clicks and drags with Shift key pressed.
Store 'Show hidden files' setting of file selector in preferences.
Added Japanese translation by Toshiharu Kudoh.
Updated Spanish translation by Sebikul.
Added Finnish translation by Tommi Nieminen.
2011-10-23 Yevgen Muntyan <emuntyan@users.sourceforge.net>
* === Released 1.0.5 ===
Fixed a bug where filename "12d1:1446" was treated as file "12d1"
and line number 1446.
Unbroke keyboard shortcuts when running under gtk-2.24.7.
2011-09-11 Yevgen Muntyan <emuntyan@users.sourceforge.net>
* === Released 1.0.4 ===
Added protobuf lang file by Pavel Artyomkin.
2011-04-14 Yevgen Muntyan <emuntyan@users.sourceforge.net>
* === Released 1.0.3 ===
Fixed "Move to Split Notebook" command.
2011-04-04 Yevgen Muntyan <emuntyan@users.sourceforge.net>
* === Released 1.0.2 ===
Fixed importing pygobject and pygtk with python-2.7 (at least on
openSUSE newer pygtk in medit was broken).
2011-02-26 Yevgen Muntyan <emuntyan@users.sourceforge.net>
* === Released 1.0.1 ===
Updated Russian translation.
Fixed a crash on windows when syntax highlighting gets disabled
because of very long lines.
Updated ini.lang.
2011-01-29 Yevgen Muntyan <emuntyan@users.sourceforge.net>
* === Released 1.0.0 ===
New release which breaks backwards compatibility (which won't be
broken again for long time, not until medit-2.0). Bugs have been
fixed, features have been implemented, new bugs have been introduced.
Highlights:
- Consistent API for Python and Lua scripts, generated from
source code, together with documentation. This allows for
much more powerful Lua scripts.
- Added option to show all spaces, not just Tab characters.
- Allow searching in a list of directories instead of just a single one.
- Added --geometry command line option.
- Added split views - multiple views of the same document in one
notebook tab.
- Windows can display two notebooks to allow viewing two different
documents at the same as well.
- Build system uses autotools again. Cmake is nice but not nice enough.
2010-10-05 Yevgen Muntyan <emuntyan@sourceforge.net>
* === Released 0.10.5 ===
Added an option to show spaces, not just tabs.
Added linker flags to fix build on some Linux distributions.
Fixed bug where Select All menu item wouldn't select text on
some builds (found by Andrey Frantsuzov).
2010-04-29 Yevgen Muntyan <emuntyan@users.sourceforge.net>
* === Released 0.10.4 ===
Python plugins are back.
2010-04-16 Yevgen Muntyan <emuntyan@users.sourceforge.net>
* === Released 0.10.3 ===
Fixed crash in Find File command.
Windows: downgraded gtk to 2.16.6 because of problems with
"client-side windows" feature. Fixed a bug with synaptics
touchpad where scrolling would stop working after a dialog
was shown.
2010-04-14 Yevgen Muntyan <emuntyan@users.sourceforge.net>
* === Released 0.10.2 ===
Added back man page, fixed compilation on systems where cmake
builds dynamic libraries by default.
On windows, made medit use case-insensitive filename comparison
and fixed scrolling with a Synaptics touchpad.
2010-03-19 Yevgen Muntyan <emuntyan@users.sourceforge.net>
* === Released 0.10.1 ===
Restored lost ctags plugin. Added simple installation
instructions.
2010-02-28 Yevgen Muntyan <emuntyan@users.sourceforge.net>
* === Released 0.10.0 ===
2008-08-29 Yevgen Muntyan <muntyan@tamu.edu>
* === Released 0.9.4 ===
Corrected a brain dead logic error which led to data loss:
medit did not report a proper error when it could not convert
content to requested encoding (e.g. when trying to save text
with accented characters in ASCII). Thanks to LoneFox.
Updated and corrected documentation.
Fixed recent files menu where underscore in filenames showed
up as mnemonics underline.
Added recent files dialog.
Fixed saving session on logout.
Made open-dialog-follows-doc option apply to Save As too.
Much improved Mac OS X port (which requires much improved Mac OS X
Gtk port from SVN).
Once again fixed document tab icon appearance.
Made tilde expansion work in Find in Files dialog.
Fixed bug in Preferences dialog caused by a buggy Ubuntu Gtk patch.
Worked around freezing when editing a document with very long lines.
Added Open With Default Application to file selector menu.
Made ctags plugin not try to run ctags on a non-existent file.
User data files on windows are now stored in <User>/Application Data
instead of the home folder, medit will move old files on startup.
Fixed win32 bug with saving session file.
Lot of lang files were improved.
Added Dutch translation by Kris Van Bruwaene.
Updated German translation by Christian Dywan.
2008-02-10 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.9.3 ===
Fixed double-click glitch in the file selector.
Made file list remember expanded and collapsed rows.
Implemented Find in Files on windows.
Fixed handling UNC paths on windows.
GtkRecent*, which caused freezing on load and save,
is no longer used.
Made ctags plugin enabled by default.
Fixed deleting folders on windows.
Updated German translation by Christian Dywan.
2008-01-10 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.9.2 ===
Fixed broken windows build.
2008-01-09 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.9.1 ===
Added more editor functions for Lua scripts.
Made building with --disable-nls work again.
Fixed alternating button order in Find dialog; use it
in more dialogs (LoneFox).
Fixed a segfault in user tools preferences.
Small buttons in the notebook and window panes follow
gtk theme.
Notebook tabs no longer scroll on closing document.
Nicer arrow buttons in notebook.
configure doesn't fail to detect pygtk when pycairo-dev
is absent.
Added a setting to ensure trailing newline character
on save.
Emacs-like filename:line strings are now recognized by
default in shell tools output.
File list plugin.
Function list plugin (Christian Dywan).
File selector allows selecting by dragging the mouse
and DND for multiple items.
Window panes configurations is now saved and restored
properly; panes may be re-arranged by DND.
Added color schemes for the terminal.
Fixed the bug when the toolbar didn't pick up default gtk
style.
Fixed all memory leaks found by valgrind.
Updated French translation by Collilieux.
Updated Spanish translation by Arnau Sanchez.
Updated German translation by Christian Dywan.
Updated Chinese translation by Chaosye.
Special thanks to Christian Dywan.
2007-11-29 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.9.0 ===
Replaced MooScript with Lua.
Improved user-defined tools, made it possible to store
tools in separate files instead of creating and editing
them via Preferences dialog.
Added online help.
Rearranged menu items, removed Settings menu.
Added a setting for window title format.
Made Preferences dialog remember its size to make
editing scripts more comfortable.
Fixed the bug with storing clipboard contents on exit.
Fixed files drag'n'drop on windows.
Improved syntax highlighting.
medit now reads meditrc files in data directories, so it's
possible to have pre-set options different from defaults.
Fixed Find in Files and Find File menu items broken on
some systems.
Fixed highlighting current line and behavior of Home/End
keys when line wrapping is enabled.
Fixed entries for language extensions and mime types in the
Preferences dialog.
Added a command-line option to open documents in a new window.
Czech translation by Vlastimil Ott.
Updated German translation by Christian Dywan.
2007-08-07 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.8.10 ===
Fixed numerous memory leaks.
Fixed an issue with indentation when pressing Enter key
on an empty line.
Fixed tooltips on toolbar, once again, now for gtk-2.10.
Added a setting for what directory should be shown in the
Open dialog.
2007-07-31 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.8.9 ===
Russian translation by Andrey Fedoseev.
Spanish translation by Arnau Sanchez.
Added a setting to disable sessions (Joris_M).
Added a setting to draw right margin in text, as in gedit.
Unbroke loading old lang files.
Fixed some bugs in notebook tabs drawing.
Re-added --with-broken-gtk-theme configure option for Suse.
Do not ignore displayed tab width when printing.
Worked around crash with Export as PDF and gtk-2.10.
New and improved syntax highlighting:
c, css, pkgconfig.
2007-07-10 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.8.8 ===
New command-line option --app-name: instances with different names
do not share sessions, and --app-name works as --pid argument when
an instance with given name is already running.
Added hidden setting for width of displayed Tab characters.
Fixed theming bug in the paned widget.
Improved Preferences dialog.
Updated German translation (Christian Dywan).
New and improved syntax highlighting:
ada, awk, c, changelog, cpp, haskell, html, java, lua, m4,
objc, ocl, ruby, scheme, sh.
2007-06-24 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.8.7 ===
Implemented session support.
Use xdg-open to open files from file selector.
Fixed build on darwin.
Added translation for language files.
Changed license of almost everything to LGPL.
2007-06-14 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.8.6 ===
Chinese translation by Chaosye.
German translation by Christian Dywan.
User config and data files are moved into ~/.config, ~/.share, etc.,
according to XDG specification. medit will move old files into new
locations on startup, so transition should be smooth and invisible (Oliwer).
Improved file encodings handling, and fixed some bugs related to it.
Made it use more stock items and icons from icon themes.
Improved paned widget behavior, no more nasty drawing artifacts.
Fixed Find dialog which treated replacement text as a regular
expression.
Made editor recognize "nxml" emacs mode as xml.
freedesktop.org mime type database is used now on windows, so it knows
how to highlight files of common types.
'medit filename' behaves better when another isntance is already running.
Underline character in a filename is no longer treated as mnemonic
underline in the Window menu.
Fixed tab icons background bug (Christian Dywan).
Improved syntax highlighting:
c csharp css desktop fortran gap gtkrc idl java javascript latex m4
ocaml octave pascal perl pkgconfig po ruby scheme sh sql tcl verilog
vhdl xml
New syntax highlighting:
docbook ocaml spec
2007-04-09 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.8.5 ===
Fixed critical win32 bug: editor duplicated line endings on save,
screwing up files and everything (Thomas Gilgin).
Implemented selecting whole lines on click/drag over line numbers
margin (stonecrest).
Made it save user-chosen encodings in Open and Save dialog.
It's now possible to print line numbers.
Version 0.8.4 broke loading files on unix, and was deleted.
2007-04-06 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.8.3 ===
French translation by Collilieux.
Finally made tools written in Python work.
Fixed Stop button in replace confirmation dialog.
Number following colon after filename on command line is treated as line number,
e.g. 'medit /home/user/foo:134'.
File selector fixes:
Use exo-open when running on XFCE.
Correctly determine mime type of backup files and text files.
Executable files do not get passed to gnome-open and alike, so they are not
executed on double-click.
Improved performance and memory consumption.
Improved syntax highlighting: C, C++, po, gtk-doc, Makefile,
2007-02-03 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.8.2 ===
Made medit ask whether to save changes on logout.
Fixed build without libxml2.
Fixed PHP and Java syntax highlighting.
Double-click in file selector now opens text files in the editor,
and uses default applications for the rest of files.
2007-01-20 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.8.1 ===
Added syntax highlighting for pkgconfig, libtool, dpatch, dtd.
Improved highlighting for shell, python, desktop, m4, xml.
Improved compiler and python output views.
Added simple python project type.
Made Alt-<number> shortcuts switch tabs (stonecrest).
All filter settings matching given filename are applied now,
in order they are specified, so it's easy to set settings
for a folder or single glob, and then tweak them for individual
files.
Added character encoding selectors to Open and Save dialogs.
File permissions are now preserved when using Save As.
Input fifo's are created in a separate subdirectory of /tmp,
to pollute it less.
Windows build uses mime types database from freedesktop.org
now.
Implemented folder watching on windows: file selector updates
automatically when folder content changes.
Drag'n'drop in file selector works with Go to Current Doc Folder button.
Added bunch of tools for LaTeX documents.
2006-11-30 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.8.0 ===
Added document bookmarks (Dmytro Savchuk).
"medit" without arguments opens new file if existing process instance
is used (Lontronics).
Open dialog remembers its size (Lontronics).
2006-11-19 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.7.97 ===
Added Print Preview and Export as PDF menu items.
Improved print preview.
Fixed problem with multiple windows on twm (Lontronics).
2006-11-13 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.7.96 ===
Fixed print preview for different page orientations.
Made editor use document font to display line numbers.
2006-11-13 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.7.95 ===
Quick fix release for 0.7.9.
Fixed crash on windows with pygtk older than 2.10.
Got drawing tabs and trailing spaces back.
2006-11-12 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.7.9 ===
Beta version of new 0.8 release.
Syntax highlighting has been replaced with brand new syntax
highlighting from GtkSourceView. It supports million different
languages, and has much better performance.
New features and improvements:
Win32 installer includes GTK.
Implemented print preview; implemented printing with
text styles from the document.
Implemented customizable output filters, for highlighting
errors in commands output and automatic opening appropriate
files.
Copying file in the file selector copies its URI/path
when appropriate.
Added "async" mode for running shell commands: output is
redirected to medit's parent console and medit does not
wait for the command to terminate.
Fixed bugs include:
Problem with new keyboard shortcuts not applied immediately
when set in Configure Shortcuts dialog.
Build errors with gtk-2.6.
Paned widgets can't be covered by document anymore.
Lot of other bugs too.
2006-08-24 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.7.1 ===
Quick-fix release: fixed some build errors,
removed shell unix tools from win32 build.
2006-08-23 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.7.0 ===
New features and impovements:
New and improved user-defined tools.
Much improved Find plugin.
I18n infrastructure is in place (no translations yet).
Reworked plugin system.
Experimental project plugin.
Printing with gtk-2.10.
Made it possible to blacklist certain extensions, so no language
is picked up for them.
Added New File action in file selector.
Made displayed tab width configurable.
Close editor tabs by middle mouse button click (Thomas Gilgin).
Made font selectors show only monospace fonts.
Find Current Word action (Thomas Gilgin).
Improved terminal drawing.
Prettified python console (Geoffrey French).
Disabled active strings and completion in this version, they will
be reenabled and made actually useful in next releases.
Bug fixes include:
Fixed bug with simultaneous dragging icon and reordering tabs in notebook.
On opening files prefer locale encoding to builtin ones (Thomas Gilgin).
Do not try to open special files both on windows and unix.
Fix startup notification protocol handling, so the editor does not steal
focus when using single instance mode and does pop up on correct desktop
when needed.
Color scheme setting applied after opening a document (Thomas Gilgin).
Custom shortcuts did not get saved under certain conditions.
Fixed tab icon dnd which caused input lock in child windows.
Fixed bug in Search/Replace when replacement uses back references.
Store clipboard contents on quit (Thomas Gilgin).
Fixed crash on paste from another application.
Save search history and search options (Thomas Gilgin).
2006-05-26 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.6.99 ===
Added Open With submenu in file selector popup menu.
Fixed bug with per-language settings lost on save.
Added document list menu in editor windows.
Fixed crash on paste from another application.
Improved entry completion behaviour.
Improved python plugin.
Updated printing code for changes in gtk api.
Fixed file selector background bug.
There is a single win32 installer now, and medit picks up python if it's present
on startup: medit is not linked to pythonxx.dll, python support has been moved
into pymo2x plugins.
Improved build infrastructure (Andreas Hanke).
Bug fixes.
2006-05-04 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.6.98 ===
Added printing support for gtk-2.9.
Printing support in gtk is not stable yet, and will likely change
in future, therefore printing in medit must be explicitely enabled by
--enable-printing argument to configure.
Fixed drawing bug when opening big files.
Made window panes save their position after changing it by drag-n-drop.
Build fixes on AMD Linux, other bug fixes.
2006-05-04 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.6.97 ===
medit now uses system pcre library if present; FAM support is disabled.
Allow adding tools into different menus.
Added gnuplot syntax highlighting.
Fixed python output pane: it now jumps to correct line in error
messages, and it uses Stop button.
Added gui for setting per-language settings in Preferences dialog.
Dropping a file into the text area opens file now, instead of pasting uri.
"medit filename" from command line creates new file if the argument is not
an existing file.
2006-04-30 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.6.96 ===
Fixed bugs:
Build problems on AMD64 - David Hough.
Missing #include <time.h> - Nick Treleaven, David Hough.
Problem with hidden toolbar showing up anyway - Andrey Fedoseev.
Missing window icon - Andrey Fedoseev.
2006-04-30 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.6.95 ===
Greatly improved syntax highlighting, zillion fixes.
2006-04-20 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.6.9 ===
User-defined completion, tools, and context menus.
2006-04-09 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.6.8 ===
Finally unbroke windows terminal, and finally fixed
bug with terminal eating 100% of cpu time.
Active strings, user-defined commands:
Added support for python scripts and shell commands.
2006-04-06 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.6.7 ===
Reverted changes in windows terminal.
2006-04-06 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.6.6 ===
Lot of bugs fixed, lot of bugs introduced.
MooEdit:
Made quick search work.
Line ends type is detected automatically, and
used when saving file.
2006-03-29 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.6.5 ===
0.6.4 is broken
2006-03-29 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.6.4 ===
MooEdit:
Implemented printing for gtk-2.10.
MooTerm:
Rewritten drawing.
MooFileView:
Made it work (to some extent) on windows.
2006-03-15 Yevgen Muntyan <muntyan@math.tamu.edu>
* === Released 0.6.3 ===
Added customizable menus, with user-defined actions using MooScript.
MooApp:
Fixed input pipe eating all cpu time.
Use recursive g_remove on windows for removing directories, to avoid
shell api asking user if he wants t remove temporary directory.
Custom About dialog.
MooEdit:
Reenabled force-tag-redraw hack in highlighter, due to GTK bug.
Fixed unreal slowness of highlighting matching brackets.
MooTerm:
Made moo_term_get_selection_bounds() public.
MooFileView:
Unbroke get_parent_folder
Python module:
Made moo module behave like a package.
Made atributes of TermIter and TermTextAttr writable.
Added file-like objects which use g_print* for sys.stdout and sys.stderr.

40
README Normal file
View File

@ -0,0 +1,40 @@
General Information
===================
medit is a text editor.
medit is free software, released under GNU GPL license. See the LICENSE
file in this distribution for details.
The web site is:
http://medit.bitbucket.org/
releases are located at:
http://sourceforge.net/project/showfiles.php?group_id=167563
Installation
============
See INSTALL file in this distribution.
Bug reports and contact
=======================
Report bugs and file feature requests in the medit bug tracker at
http://sourceforge.net/tracker/?group_id=167563&atid=843451 . You can
also send an email to emuntyan@users.sourceforge.net if you don't feel
like using the bug tracker, or have any questions/comments.
Sources
=======
medit sources are tracked using mercurial. You can browse medit source
repository online at http://bitbucket.org/medit/medit/. To check out a
copy of medit repository, install mercurial, and do
hg clone http://bitbucket.org/medit/medit/
This will create a new directory named 'medit' with medit sources inside.
To update them later on, do
hg pull; hg update
in this directory.

48
THANKS Normal file
View File

@ -0,0 +1,48 @@
To Sveta and Max Muntyan,
and to all who contributed, including
Andreas Hanke
Andrey Fedoseev
archxyne
Arnau Sanchez
Chaosye
Christian Dywan
Collilieux
Daniel Butzu
Daniel Poelzleithner
David Hough
Debianer
Denis Koryavov
Dmytro Savchuk
Eulogio Serradilla
Everaldo Coelho
Federico Mena Quintero
Geoffrey French
Jeroen Zwartepoorte
josgalo
Kenneth Prugh
Kris Van Bruwaene
Lasse Makholm
LoneFox
Lontronics
Malete Partner
Marco Barisione
Matthias Clasen
Nick Treleaven
Owen Taylor
Paolo Borelli
Paolo Maggi
Pavel Artyomkin
Philip Hazel
Ryan Anonymous
Scott Wimer
Sebikul
Thomas Gilgin
Tim Janik
Tim-Philipp Müller
Tommi Nieminen
Toshiharu Kudoh
Ulrich Eckhardt
Vlastimil Ott
Yannick Duchêne

363
api/CMakeLists.txt Normal file
View File

@ -0,0 +1,363 @@
SET(docparser_files
parsedocs.py
mdp/__init__.py
mdp/module.py
mdp/docparser.py
mdp/xmlwriter.py
)
SET(gendefs_files
gendefs.py
mpi/__init__.py
mpi/module.py
mpi/defswriter.py
)
SET(genlua_files
genlua.py
mpi/__init__.py
mpi/module.py
mpi/luawriter.py
)
SET(gendocs_files
gendocs.py
gendocbook.py
mpi/__init__.py
mpi/module.py
mpi/docbookwriter.py
)
SET(source_files
../moo/moolua/medit-lua.h
../moo/moolua/medit-lua.cpp
../moo/mooapp/mooappabout.c
../moo/mooapp/mooappabout.h
../moo/mooapp/mooapp-accels.h
../moo/mooapp/mooapp.c
../moo/mooapp/mooapp.h
../moo/mooapp/mooapp-info.h
../moo/mooapp/mooapp-private.h
../moo/mooapp/moohtml.c
../moo/mooapp/moohtml.h
../moo/mooapp/moolinklabel.c
../moo/mooapp/moolinklabel.h
../moo/mooedit/mooedit-accels.h
../moo/mooedit/mooeditaction.c
../moo/mooedit/mooeditaction-factory.c
../moo/mooedit/mooeditaction-factory.h
../moo/mooedit/mooeditaction.h
../moo/mooedit/mooeditbookmark.c
../moo/mooedit/mooeditbookmark.h
../moo/mooedit/mooedit.cpp
../moo/mooedit/mooeditconfig.c
../moo/mooedit/mooeditconfig.h
../moo/mooedit/mooeditdialogs.cpp
../moo/mooedit/mooeditdialogs.h
../moo/mooedit/mooedit-enum-types.c
../moo/mooedit/mooedit-enum-types.h
../moo/mooedit/mooedit-enums.h
../moo/mooedit/mooeditfileinfo.c
../moo/mooedit/mooeditfileinfo.c
../moo/mooedit/mooeditfileinfo.h
../moo/mooedit/mooedit-fileops.cpp
../moo/mooedit/mooedit-fileops.h
../moo/mooedit/mooeditfiltersettings.c
../moo/mooedit/mooeditfiltersettings.h
../moo/mooedit/mooedit.h
../moo/mooedit/mooedithistoryitem.c
../moo/mooedit/mooedithistoryitem.h
../moo/mooedit/mooedit-impl.h
../moo/mooedit/mooeditor.cpp
../moo/mooedit/mooeditor.h
../moo/mooedit/mooeditor-impl.h
../moo/mooedit/mooeditor-private.h
../moo/mooedit/mooeditor-tests.c
../moo/mooedit/mooeditor-tests.h
../moo/mooedit/mooeditprefs.c
../moo/mooedit/mooeditprefs.h
../moo/mooedit/mooeditprefspage.c
../moo/mooedit/mooedit-private.h
../moo/mooedit/mooedit-script.c
../moo/mooedit/mooedit-script.h
../moo/mooedit/mooedittab.c
../moo/mooedit/mooedittab.h
../moo/mooedit/mooedittypes.h
../moo/mooedit/mooeditview.c
../moo/mooedit/mooeditview.h
../moo/mooedit/mooeditview-script.c
../moo/mooedit/mooeditview-script.h
../moo/mooedit/mooeditwindow.c
../moo/mooedit/mooeditwindow.h
../moo/mooedit/mooeditwindow-impl.h
../moo/mooedit/moofold.c
../moo/mooedit/moofold.h
../moo/mooedit/mooindenter.c
../moo/mooedit/mooindenter.h
../moo/mooedit/moolang.c
../moo/mooedit/moolang.h
../moo/mooedit/moolangmgr.c
../moo/mooedit/moolangmgr.h
../moo/mooedit/moolangmgr-private.h
../moo/mooedit/moolang-private.h
../moo/mooedit/moolinebuffer.c
../moo/mooedit/moolinebuffer.h
../moo/mooedit/moolinemark.c
../moo/mooedit/moolinemark.h
../moo/mooedit/mooplugin.c
../moo/mooedit/mooplugin.h
../moo/mooedit/mooplugin-loader.c
../moo/mooedit/mooplugin-loader.h
../moo/mooedit/mooplugin-macro.h
../moo/mooedit/mootextbtree.c
../moo/mooedit/mootextbtree.h
../moo/mooedit/mootextbuffer.c
../moo/mooedit/mootextfind.c
../moo/mooedit/mootextfind.h
../moo/mooedit/mootextiter.h
../moo/mooedit/mootextprint.c
../moo/mooedit/mootextprint.h
../moo/mooedit/mootextprint-private.h
../moo/mooedit/mootext-private.h
../moo/mooedit/mootextsearch.c
../moo/mooedit/mootextsearch.h
../moo/mooedit/mootextsearch-private.h
../moo/mooedit/mootextstylescheme.c
../moo/mooedit/mootextstylescheme.h
../moo/mooedit/mootextview.c
../moo/mooedit/mootextview.h
../moo/mooedit/mootextview-input.c
../moo/mooedit/mootextview-private.h
../moo/moofileview/moobookmarkmgr.c
../moo/moofileview/moobookmarkmgr.h
../moo/moofileview/moobookmarkview.c
../moo/moofileview/moobookmarkview.h
../moo/moofileview/moofile.c
../moo/moofileview/moofileentry.c
../moo/moofileview/moofileentry.h
../moo/moofileview/moofile.h
../moo/moofileview/moofile-private.h
../moo/moofileview/moofilesystem.c
../moo/moofileview/moofilesystem.h
../moo/moofileview/moofileview-accels.h
../moo/moofileview/moofileview-aux.h
../moo/moofileview/moofileview.c
../moo/moofileview/moofileview-dialogs.c
../moo/moofileview/moofileview-dialogs.h
../moo/moofileview/moofileview.h
../moo/moofileview/moofileview-impl.h
../moo/moofileview/moofileview-private.h
../moo/moofileview/moofileview-tools.c
../moo/moofileview/moofileview-tools.h
../moo/moofileview/moofolder.c
../moo/moofileview/moofolder.h
../moo/moofileview/moofoldermodel.c
../moo/moofileview/moofoldermodel.h
../moo/moofileview/moofoldermodel-private.h
../moo/moofileview/moofolder-private.h
../moo/moofileview/mooiconview.c
../moo/moofileview/mooiconview.h
../moo/moofileview/mootreeview.c
../moo/moofileview/mootreeview.h
../moo/mooutils/mooaccelbutton.c
../moo/mooutils/mooaccelbutton.h
../moo/mooutils/mooaccel.c
../moo/mooutils/mooaccel.h
../moo/mooutils/mooaccelprefs.c
../moo/mooutils/mooaccelprefs.h
../moo/mooutils/mooactionbase.c
../moo/mooutils/mooactionbase.h
../moo/mooutils/mooactionbase-private.h
../moo/mooutils/mooaction.c
../moo/mooutils/mooactioncollection.c
../moo/mooutils/mooactioncollection.h
../moo/mooutils/mooactionfactory.c
../moo/mooutils/mooactionfactory.h
../moo/mooutils/mooactiongroup.c
../moo/mooutils/mooactiongroup.h
../moo/mooutils/mooaction.h
../moo/mooutils/mooaction-private.h
../moo/mooutils/mooappinput-common.c
../moo/mooutils/mooappinput.h
../moo/mooutils/mooapp-ipc.c
../moo/mooutils/mooapp-ipc.h
../moo/mooutils/mooarray.h
../moo/mooutils/mooatom.h
../moo/mooutils/moobigpaned.c
../moo/mooutils/moobigpaned.h
../moo/mooutils/mooclosure.c
../moo/mooutils/mooclosure.h
../moo/mooutils/moocombo.c
../moo/mooutils/moocombo.h
../moo/mooutils/moocompat.h
../moo/mooutils/moodialogs.c
../moo/mooutils/moodialogs.h
../moo/mooutils/mooeditops.c
../moo/mooutils/mooeditops.h
../moo/mooutils/mooencodings.c
../moo/mooutils/mooencodings-data.h
../moo/mooutils/mooencodings.h
../moo/mooutils/mooentry.cpp
../moo/mooutils/mooentry.h
../moo/mooutils/moo-environ.h
../moo/mooutils/moofiledialog.c
../moo/mooutils/moofiledialog.h
../moo/mooutils/moofileicon.c
../moo/mooutils/moofileicon.h
../moo/mooutils/moofilewatch.c
../moo/mooutils/moofilewatch.h
../moo/mooutils/moofilewriter.c
../moo/mooutils/moofilewriter.h
../moo/mooutils/moofilewriter-private.h
../moo/mooutils/moofiltermgr.c
../moo/mooutils/moofiltermgr.h
../moo/mooutils/moofontsel.c
../moo/mooutils/moofontsel.h
../moo/mooutils/mooglade.c
../moo/mooutils/mooglade.h
../moo/mooutils/moohelp.c
../moo/mooutils/moohelp.h
../moo/mooutils/moohistorycombo.c
../moo/mooutils/moohistorycombo.h
../moo/mooutils/moohistorylist.c
../moo/mooutils/moohistorylist.h
../moo/mooutils/moohistorymgr.c
../moo/mooutils/moohistorymgr.h
../moo/mooutils/mooi18n.c
../moo/mooutils/mooi18n.h
../moo/mooutils/moolist.h
../moo/mooutils/moomarkup.c
../moo/mooutils/moomarkup.h
../moo/mooutils/moomenuaction.c
../moo/mooutils/moomenuaction.h
../moo/mooutils/moomenu.c
../moo/mooutils/moomenu.h
../moo/mooutils/moomenumgr.c
../moo/mooutils/moomenumgr.h
../moo/mooutils/moomenutoolbutton.c
../moo/mooutils/moomenutoolbutton.h
../moo/mooutils/moo-mime.c
../moo/mooutils/moo-mime.h
../moo/mooutils/moonotebook.c
../moo/mooutils/moonotebook.h
../moo/mooutils/mooonce.h
../moo/mooutils/moopane.c
../moo/mooutils/moopaned.c
../moo/mooutils/moopaned.h
../moo/mooutils/moopane.h
../moo/mooutils/mooprefs.c
../moo/mooutils/mooprefsdialog.c
../moo/mooutils/mooprefsdialog.h
../moo/mooutils/mooprefs.h
../moo/mooutils/mooprefspage.c
../moo/mooutils/mooprefspage.h
../moo/mooutils/moospawn.c
../moo/mooutils/moospawn.h
../moo/mooutils/moostock.c
../moo/mooutils/moostock.h
../moo/mooutils/moo-test-macros.h
../moo/mooutils/moo-test-utils.c
../moo/mooutils/moo-test-utils.h
../moo/mooutils/mootypedecl-macros.h
../moo/mooutils/mootype-macros.h
../moo/mooutils/moouixml.c
../moo/mooutils/moouixml.h
../moo/mooutils/mooundo.c
../moo/mooutils/mooundo.h
../moo/mooutils/mooutils-debug.h
../moo/mooutils/mooutils-enums.c
../moo/mooutils/mooutils-enums.h
../moo/mooutils/mooutils-file.c
../moo/mooutils/mooutils-file.h
../moo/mooutils/mooutils-fs.c
../moo/mooutils/mooutils-fs.h
../moo/mooutils/mooutils-gobject.c
../moo/mooutils/mooutils-gobject.h
../moo/mooutils/mooutils-gobject-private.h
../moo/mooutils/mooutils.h
../moo/mooutils/mooutils-macros.h
../moo/mooutils/mooutils-mem.h
../moo/mooutils/mooutils-messages.h
../moo/mooutils/mooutils-misc.cpp
../moo/mooutils/mooutils-misc.h
../moo/mooutils/mooutils-script.c
../moo/mooutils/mooutils-script.h
../moo/mooutils/mooutils-tests.h
../moo/mooutils/mooutils-thread.cpp
../moo/mooutils/mooutils-thread.h
../moo/mooutils/mooutils-treeview.c
../moo/mooutils/mooutils-treeview.h
../moo/mooutils/mooutils-win32.c
../moo/mooutils/moowin32/mingw/fnmatch.h
../moo/mooutils/moowin32/mingw/netinet/in.h
../moo/mooutils/moowin32/ms/sys/time.h
../moo/mooutils/moowin32/ms/unistd.h
../moo/mooutils/moowindow.c
../moo/mooutils/moowindow.h
../moo/plugins/support/moocmdview.c
../moo/plugins/support/moocmdview.h
../moo/plugins/support/mooeditwindowoutput.c
../moo/plugins/support/mooeditwindowoutput.h
../moo/plugins/support/moolineview.c
../moo/plugins/support/moolineview.h
../moo/plugins/support/moooutputfilter.c
../moo/plugins/support/moooutputfilter.h
../moo/plugins/usertools/moocommand.c
../moo/plugins/usertools/moocommanddisplay.c
../moo/plugins/usertools/moocommanddisplay.h
../moo/plugins/usertools/moocommand.h
../moo/plugins/usertools/moocommand-private.h
../moo/plugins/usertools/moooutputfilterregex.c
../moo/plugins/usertools/moooutputfilterregex.h
../moo/plugins/usertools/moousertools.c
../moo/plugins/usertools/moousertools-enums.c
../moo/plugins/usertools/moousertools-enums.h
../moo/plugins/usertools/moousertools.h
../moo/plugins/usertools/moousertools-prefs.c
../moo/plugins/usertools/moousertools-prefs.h
)
FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/genmooxml.cmake
"EXECUTE_PROCESS(COMMAND ${MOO_PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/parsedocs.py
--source-dir ${CMAKE_SOURCE_DIR}/moo/mooapp
--source-dir ${CMAKE_SOURCE_DIR}/moo/mooedit
--source-dir ${CMAKE_SOURCE_DIR}/moo/moofileview
--source-dir ${CMAKE_SOURCE_DIR}/moo/mooutils
--source-dir ${CMAKE_SOURCE_DIR}/moo/moopython
--source-dir ${CMAKE_SOURCE_DIR}/moo/plugins/usertools
--source-dir ${CMAKE_SOURCE_DIR}/moo/plugins/support
--source-file ${CMAKE_SOURCE_DIR}/moo/moolua/medit-lua.cpp
--source-file ${CMAKE_SOURCE_DIR}/moo/moolua/medit-lua.h
--skip moofontsel.*
--output ${CMAKE_CURRENT_SOURCE_DIR}/moo.xml
RESULT_VARIABLE RESULT)
if(NOT RESULT EQUAL 0)
MESSAGE(FATAL_ERROR \"Error: \${RESULT}\")
endif()
file(WRITE moo.xml.stamp moo.xml.stamp)
")
add_custom_command(OUTPUT moo.xml.stamp
COMMAND ${CMAKE_COMMAND} -P genmooxml.cmake
DEPENDS ${docparser_files} ${source_files} ${CMAKE_CURRENT_BINARY_DIR}/genmooxml.cmake ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt)
LIST(APPEND built_moo_sources moo.xml.stamp)
FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/gengtkxml.cmake
"EXECUTE_PROCESS(COMMAND ${MOO_PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/parsedocs.py
--source-file ${CMAKE_SOURCE_DIR}/moo/moolua/gtk-api.c
--source-file ${CMAKE_SOURCE_DIR}/moo/moolua/gtk-api.h
--module Gtk
--output ${CMAKE_CURRENT_SOURCE_DIR}/gtk.xml
RESULT_VARIABLE RESULT)
if(NOT RESULT EQUAL 0)
MESSAGE(FATAL_ERROR \"Error: \${RESULT}\")
endif()
file(WRITE gtk.xml.stamp gtk.xml.stamp)
")
add_custom_command(OUTPUT gtk.xml.stamp
COMMAND ${CMAKE_COMMAND} -P gengtkxml.cmake
DEPENDS ${docparser_files} ${source_files} ${CMAKE_CURRENT_BINARY_DIR}/gengtkxml.cmake ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt)
LIST(APPEND built_moo_sources gtk.xml.stamp)
add_custom_target(apixml ALL DEPENDS moo.xml.stamp gtk.xml.stamp)

72
api/Makefile.am Normal file
View File

@ -0,0 +1,72 @@
docparser_files = \
parsedocs.py \
mdp/__init__.py \
mdp/module.py \
mdp/docparser.py \
mdp/xmlwriter.py
gendefs_files = \
gendefs.py \
mpi/__init__.py \
mpi/module.py \
mpi/defswriter.py
genlua_files = \
genlua.py \
mpi/__init__.py \
mpi/module.py \
mpi/luawriter.py
gendocs_files = \
gendocs.py \
gendocbook.py \
mpi/__init__.py \
mpi/module.py \
mpi/docbookwriter.py
EXTRA_DIST = \
$(docparser_files) \
$(gendefs_files) \
$(genlua_files) \
$(gendocs_files) \
sourcefiles.mak \
moo.xml \
gtk.xml
BUILT_SOURCES =
if MOO_DEV_MODE
include sourcefiles.mak
BUILT_SOURCES += moo.xml.stamp
moo.xml.stamp: $(docparser_files) $(source_files)
$(AM_V_GEN)$(MOO_PYTHON) $(srcdir)/parsedocs.py \
--source-dir $(top_srcdir)/moo/mooapp \
--source-dir $(top_srcdir)/moo/mooedit \
--source-dir $(top_srcdir)/moo/moofileview \
--source-dir $(top_srcdir)/moo/mooutils \
--source-dir $(top_srcdir)/moo/moopython \
--source-dir $(top_srcdir)/moo/plugins/usertools \
--source-dir $(top_srcdir)/moo/plugins/support \
--source-file $(top_srcdir)/moo/moolua/medit-lua.cpp \
--source-file $(top_srcdir)/moo/moolua/medit-lua.h \
--skip 'moofontsel.*' \
--output moo.xml.tmp
$(AM_V_at)cmp -s moo.xml.tmp $(srcdir)/moo.xml || mv moo.xml.tmp $(srcdir)/moo.xml
$(AM_V_at)rm -f moo.xml.tmp
$(AM_V_at)echo stamp > moo.xml.stamp
BUILT_SOURCES += gtk.xml.stamp
gtk.xml.stamp: $(docparser_files) $(top_srcdir)/moo/moolua/gtk-api.c $(top_srcdir)/moo/moolua/gtk-api.h
$(AM_V_at)$(MKDIR_P) moolua
$(AM_V_GEN)$(MOO_PYTHON) $(srcdir)/parsedocs.py \
--source-file $(top_srcdir)/moo/moolua/gtk-api.c \
--source-file $(top_srcdir)/moo/moolua/gtk-api.h \
--module Gtk \
--output gtk.xml.tmp
$(AM_V_at)cmp -s gtk.xml.tmp $(srcdir)/gtk.xml || mv gtk.xml.tmp $(srcdir)/gtk.xml
$(AM_V_at)rm -f gtk.xml.tmp
$(AM_V_at)echo stamp > gtk.xml.stamp
endif

10
api/gendefs.py Normal file
View File

@ -0,0 +1,10 @@
#! /usr/bin/env python
import sys
from mpi.module import Module
from mpi.defswriter import Writer
for arg in sys.argv[1:]:
mod = Module.from_xml(arg)
Writer(sys.stdout).write(mod)

31
api/gendocbook.py Normal file
View File

@ -0,0 +1,31 @@
#! /usr/bin/env python
import sys
import optparse
from mpi.module import Module
from mpi.docbookwriter import Writer
op = optparse.OptionParser()
op.add_option("--python", action="store_true")
op.add_option("--lua", action="store_true")
op.add_option("--template", action="store")
op.add_option("-i", "--import", action="append", dest="import_modules")
(opts, args) = op.parse_args()
assert len(args) == 1
assert bool(opts.python) + bool(opts.lua) == 1
if opts.python:
mode = 'python'
elif opts.lua:
mode = 'lua'
import_modules = []
if opts.import_modules:
for filename in opts.import_modules:
import_modules.append(Module.from_xml(filename))
mod = Module.from_xml(args[0])
for im in import_modules:
mod.import_module(im)
Writer(mode, opts.template, sys.stdout).write(mod)

22
api/gendocs.py Normal file
View File

@ -0,0 +1,22 @@
#! /usr/bin/env python
import sys
import optparse
from mpi.module import Module
from mpi.texiwriter import Writer
op = optparse.OptionParser()
op.add_option("--python", action="store_true")
op.add_option("--lua", action="store_true")
(opts, args) = op.parse_args()
assert len(args) == 1
assert bool(opts.python) + bool(opts.lua) == 1
if opts.python:
mode = 'python'
elif opts.lua:
mode = 'lua'
mod = Module.from_xml(args[0])
Writer(mode, sys.stdout).write(mod)

36
api/genlua.py Normal file
View File

@ -0,0 +1,36 @@
#! /usr/bin/env python
import os
import sys
import optparse
from mpi.module import Module
from mpi.luawriter import Writer
op = optparse.OptionParser()
op.add_option("-i", "--import", action="append", dest="import_modules")
op.add_option("--include-header", action="append", dest="include_headers")
op.add_option("--output", dest="output")
(opts, args) = op.parse_args()
import_modules = []
if opts.import_modules:
for filename in opts.import_modules:
import_modules.append(Module.from_xml(filename))
if opts.output:
out_file = open(opts.output + '.tmp', 'w')
else:
out_file = sys.stdout
assert len(args) == 1
mod = Module.from_xml(args[0])
for im in import_modules:
mod.import_module(im)
Writer(out_file).write(mod, opts.include_headers)
if opts.output:
out_file.close()
if os.access(opts.output, os.F_OK):
os.remove(opts.output)
os.rename(opts.output + '.tmp', opts.output)

1
api/mdp/__init__.py Normal file
View File

@ -0,0 +1 @@
# empty

691
api/mdp/docparser.py Normal file
View File

@ -0,0 +1,691 @@
import re
import string
import sys
import os
DEBUG = False
class ParseError(RuntimeError):
def __init__(self, message, block=None):
if block:
RuntimeError.__init__(self, '%s in file %s, around line %d' % \
(message, block.filename, block.first_line))
else:
RuntimeError.__init__(self, message)
class DoxBlock(object):
def __init__(self, block):
object.__init__(self)
self.symbol = None
self.annotations = []
self.params = []
self.attributes = []
self.docs = []
self.summary = None
self.__parse(block)
def __parse(self, block):
first_line = True
chunks = []
cur = [None, None, []]
for line in block.lines:
if first_line:
m = re.match(r'([\w\d_.-]+(:+[\w\d_.-]+)*)(:(\s.*)?)?$', line)
if m is None:
raise ParseError('bad id line', block)
cur[0] = m.group(1)
annotations, docs = self.__parse_annotations(m.group(4) or '')
cur[1] = annotations
cur[2] = [docs] if docs else []
elif not line:
if cur[0] is not None:
chunks.append(cur)
cur = [None, None, []]
elif cur[2]:
cur[2].append(line)
else:
m = re.match(r'(@[\w\d_.-]+|Returns|Return value|Since):(.*)$', line)
if m:
if cur[0] or cur[2]:
chunks.append(cur)
cur = [None, None, []]
cur[0] = m.group(1)
annotations, docs = self.__parse_annotations(m.group(2) or '')
cur[1] = annotations
cur[2] = [docs] if docs else []
else:
cur[2].append(line)
first_line = False
if cur[0] or cur[2]:
chunks.append(cur)
self.symbol = chunks[0][0]
self.annotations = chunks[0][1]
self.summary = chunks[0][2]
for chunk in chunks[1:]:
if chunk[0]:
if chunk[0].startswith('@'):
self.params.append(chunk)
else:
self.attributes.append(chunk)
else:
self.docs = chunk[2]
if not self.symbol:
raise ParseError('bad id line', block)
def __parse_annotations(self, text):
annotations = []
ann_start = -1
for i in xrange(len(text)):
c = text[i]
if c in ' \t':
pass
elif c == ':':
if ann_start < 0:
if annotations:
return annotations, text[i+1:].strip()
else:
return None, text
else:
pass
elif c != '(' and ann_start < 0:
if annotations:
raise ParseError('bad annotations')
return None, text
elif c == '(':
if ann_start >= 0:
raise ParseError('( inside ()')
ann_start = i
elif c == ')':
assert ann_start >= 0
if ann_start + 1 < i:
annotations.append(text[ann_start+1:i])
ann_start = -1
if ann_start >= 0:
raise ParseError('unterminated annotation')
return annotations, None
class Block(object):
def __init__(self, lines, filename, first_line, last_line):
object.__init__(self)
self.lines = list(lines)
self.filename = filename
self.first_line = first_line
self.last_line = last_line
class Symbol(object):
def __init__(self, name, annotations, docs, block):
object.__init__(self)
self.name = name
self.annotations = annotations or []
self.docs = docs
self.block = block
class Class(Symbol):
def __init__(self, name, annotations, docs, block):
Symbol.__init__(self, name, annotations, docs, block)
class Boxed(Symbol):
def __init__(self, name, annotations, docs, block):
Symbol.__init__(self, name, annotations, docs, block)
class Pointer(Symbol):
def __init__(self, name, annotations, docs, block):
Symbol.__init__(self, name, annotations, docs, block)
class EnumBase(Symbol):
def __init__(self, name, annotations, docs, values, block):
super(EnumBase, self).__init__(name, annotations, docs, block)
self.values = values
class Enum(EnumBase):
def __init__(self, name, annotations, docs, values, block):
super(Enum, self).__init__(name, annotations, docs, values, block)
class Flags(EnumBase):
def __init__(self, name, annotations, docs, values, block):
super(Flags, self).__init__(name, annotations, docs, values, block)
class EnumValue(object):
def __init__(self, name, annotations=None, docs=None):
object.__init__(self)
self.docs = docs
self.annotations = annotations or []
self.name = name
class FunctionBase(Symbol):
def __init__(self, name, annotations, params, retval, docs, block):
Symbol.__init__(self, name, annotations, docs, block)
self.params = params
self.retval = retval
class Signal(FunctionBase):
def __init__(self, name, annotations, params, retval, docs, block):
FunctionBase.__init__(self, name, annotations, params, retval, docs, block)
class Function(FunctionBase):
def __init__(self, name, annotations, params, retval, docs, block):
FunctionBase.__init__(self, name, annotations, params, retval, docs, block)
class VMethod(Function):
def __init__(self, name, annotations, params, retval, docs, block):
Function.__init__(self, name, annotations, params, retval, docs, block)
class ParamBase(object):
def __init__(self, annotations=[], docs=None):
object.__init__(self)
self.docs = docs
self.type = None
self.annotations = annotations or []
class Param(ParamBase):
def __init__(self, name=None, annotations=None, docs=None):
ParamBase.__init__(self, annotations, docs)
self.name = name
class Retval(ParamBase):
def __init__(self, annotations=None, docs=None):
ParamBase.__init__(self, annotations, docs)
class Parser(object):
def __init__(self):
object.__init__(self)
self.classes = []
self.enums = []
self.functions = []
self.signals = []
self.vmethods = []
self.__symbol_dict = {}
def __split_block(self, block):
chunks = []
current_prefix = None
current_annotations = None
current_text = None
first_line = True
re_id = re.compile(r'([\w\d._-]+:(((\s*\([^()]\)\s*)+):)?')
re_special = re.compile(r'(@[\w\d._-]+|(SECTION|PROPERTY|SIGNAL)-[\w\d._-]+||Since|Returns|Return value):(((\s*\([^()]\)\s*)+):)?')
for line in block.lines:
if first_line:
line = re.sub(r'^SECTION:([\w\d_-]+):?', r'SECTION-\1:', line)
line = re.sub(r'^([\w\d_-]+):([\w\d_-]+):?', r'PROPERTY-\1-\2:', line)
line = re.sub(r'^([\w\d_-]+)::([\w\d_-]+):?', r'SIGNAL-\1-\2:', line)
first_line = False
if not line:
if current_prefix is not None:
chunks.append([current_prefix, current_annotations, current_text])
current_prefix = None
current_annotations = None
current_text = None
elif current_text is not None:
current_text.append(line)
else:
m = re_special.match(line)
if m:
if current_prefix is not None or current_text is not None:
chunks.append([current_prefix, current_annotations, current_text])
current_prefix = None
current_annotations = None
current_text = None
current_prefix = m.group(1)
suffix = m.group(4) or ''
annotations, text = self.__parse_annotations(suffix)
current_annotations = annotations
current_text = [text] if text else []
else:
if current_text is not None:
current_text.append(line)
else:
current_text = [line]
if current_text is not None:
chunks.append([current_prefix, current_annotations, current_text])
return chunks
def __parse_annotations(self, text):
annotations = []
ann_start = -1
for i in xrange(len(text)):
c = text[i]
if c in ' \t':
pass
elif c == ':':
if ann_start < 0:
if annotations:
return annotations, text[i+1:].strip()
else:
return None, text
else:
pass
elif c != '(' and ann_start < 0:
if annotations:
raise ParseError('bad annotations')
return None, text
elif c == '(':
if ann_start >= 0:
raise ParseError('( inside ()')
ann_start = i
elif c == ')':
assert ann_start >= 0
if ann_start + 1 < i:
annotations.append(text[ann_start+1:i])
ann_start = -1
if ann_start >= 0:
raise ParseError('unterminated annotation')
if annotations:
return annotations, None
else:
return None, None
def __parse_function(self, block):
db = DoxBlock(block)
params = []
retval = None
for p in db.params:
params.append(Param(p[0][1:], p[1], p[2]))
for attr in db.attributes:
if attr[0] in ('Returns', 'Return value'):
retval = Retval(attr[1], attr[2])
elif attr[0] in ('Since'):
pass
else:
raise ParseError('unknown attribute %s' % (attr[0],), block)
if '::' in db.symbol:
What = Signal
db.symbol = 'signal:' + db.symbol.replace('_', '-').replace('::', ':')
symbol_list = self.signals
elif ':' in db.symbol:
What = Property
db.symbol = 'property:' + db.symbol.replace('_', '-')
symbol_list = self.properties
else:
What = Function
symbol_list = self.functions
func = What(db.symbol, db.annotations, params, retval, db.docs, block)
func.summary = db.summary
if DEBUG:
print 'func.name:', func.name
if func.name in self.__symbol_dict:
raise ParseError('duplicated symbol %s' % (func.name,), block)
self.__symbol_dict[func.name] = func
symbol_list.append(func)
def __parse_class(self, block):
db = DoxBlock(block)
name = db.symbol
if name.startswith('class:'):
name = name[len('class:'):]
if db.params:
raise ParseError('class params', block)
if db.attributes:
raise ParseError('class attributes', block)
cls = Class(name, db.annotations, db.docs, block)
cls.summary = db.summary
self.classes.append(cls)
def __parse_boxed(self, block):
What = None
db = DoxBlock(block)
name = db.symbol
if name.startswith('boxed:'):
What = Boxed
name = name[len('boxed:'):]
elif name.startswith('pointer:'):
What = Pointer
name = name[len('pointer:'):]
else:
raise ParseError('bad id', block)
if db.params:
raise ParseError('boxed params', block)
if db.attributes:
raise ParseError('boxed attributes', block)
cls = What(name, db.annotations, db.docs, block)
cls.summary = db.summary
self.classes.append(cls)
def __parse_enum_or_flags(self, block, What):
db = DoxBlock(block)
name = db.symbol
prefix = 'enum:' if What is Enum else 'flags:'
if name.startswith(prefix):
name = name[len(prefix):]
if db.attributes:
raise ParseError('enum attributes', block)
values = []
if db.params:
for p in db.params:
values.append(EnumValue(p[0][1:], p[1], p[2]))
enum = What(name, db.annotations, db.docs, values, block)
enum.summary = db.summary
self.enums.append(enum)
def __parse_enum(self, block):
return self.__parse_enum_or_flags(block, Enum)
def __parse_flags(self, block):
return self.__parse_enum_or_flags(block, Flags)
def __parse_block(self, block):
line = block.lines[0]
if line.startswith('class:'):
self.__parse_class(block)
elif line.startswith('boxed:'):
self.__parse_boxed(block)
elif line.startswith('pointer:'):
self.__parse_boxed(block)
elif line.startswith('enum:'):
self.__parse_enum(block)
elif line.startswith('flags:'):
self.__parse_flags(block)
elif line.startswith('SECTION:'):
pass
else:
self.__parse_function(block)
def __add_block(self, block, filename, first_line, last_line):
lines = []
for line in block:
if line.startswith('*'):
line = line[1:].strip()
if line or lines:
lines.append(line)
else:
first_line += 1
i = len(lines) - 1
while i >= 0:
if not lines[i]:
del lines[i]
i -= 1
last_line -= 1
else:
break
if lines:
assert last_line >= first_line
self.__parse_block(Block(lines, filename, first_line, last_line))
def __read_comments(self, filename):
block = None
first_line = 0
line_no = 0
for line in open(filename):
line = line.strip()
if not block:
if line.startswith('/**'):
line = line[3:]
if not line.startswith('*') and not '*/' in line:
block = [line]
first_line = line_no
else:
end = line.find('*/')
if end >= 0:
line = line[:end]
block.append(line)
self.__add_block(block, filename, first_line, line_no)
block = None
else:
block.append(line)
line_no += 1
if block:
raise ParseError('unterminated block in file %s' % (filename,))
def read_files(self, filenames):
sys.stderr.write('parsing gtk-doc comments... ')
sys.stderr.flush()
for f in filenames:
self.__read_comments(f)
sys.stderr.write('done\n')
sys.stderr.write('parsing declarations... ')
sys.stderr.flush()
for f in filenames:
if f.endswith('.h'):
self.__read_declarations(f)
sys.stderr.write('done\n')
# Code copied from h2def.py by Toby D. Reeves <toby@max.rl.plh.af.mil>
def __strip_comments(self, buf):
parts = []
lastpos = 0
while 1:
pos = string.find(buf, '/*', lastpos)
if pos >= 0:
if buf[pos:pos+len('/**vtable:')] == '/**vtable:':
parts.append(buf[lastpos:pos+len('/**vtable:')])
lastpos = pos + len('/**vtable:')
elif buf[pos:pos+len('/**signal:')] == '/**signal:':
parts.append(buf[lastpos:pos+len('/**signal:')])
lastpos = pos + len('/**signal:')
else:
parts.append(buf[lastpos:pos])
pos = string.find(buf, '*/', pos)
if pos >= 0:
lastpos = pos + 2
else:
break
else:
parts.append(buf[lastpos:])
break
return string.join(parts, '')
# Strips the dll API from buffer, for example WEBKIT_API
def __strip_dll_api(self, buf):
pat = re.compile("[A-Z]*_API ")
buf = pat.sub("", buf)
return buf
def __clean_func(self, buf):
"""
Ideally would make buf have a single prototype on each line.
Actually just cuts out a good deal of junk, but leaves lines
where a regex can figure prototypes out.
"""
# bulk comments
buf = self.__strip_comments(buf)
# dll api
buf = self.__strip_dll_api(buf)
# compact continued lines
pat = re.compile(r"""\\\n""", re.MULTILINE)
buf = pat.sub('', buf)
# Preprocess directives
pat = re.compile(r"""^[#].*?$""", re.MULTILINE)
buf = pat.sub('', buf)
#typedefs, stucts, and enums
pat = re.compile(r"""^(typedef|struct|enum)(\s|.|\n)*?;\s*""",
re.MULTILINE)
buf = pat.sub('', buf)
#strip DECLS macros
pat = re.compile(r"""G_(BEGIN|END)_DECLS|(BEGIN|END)_LIBGTOP_DECLS""", re.MULTILINE)
buf = pat.sub('', buf)
#extern "C"
pat = re.compile(r"""^\s*(extern)\s+\"C\"\s+{""", re.MULTILINE)
buf = pat.sub('', buf)
#multiple whitespace
pat = re.compile(r"""\s+""", re.MULTILINE)
buf = pat.sub(' ', buf)
#clean up line ends
pat = re.compile(r""";\s*""", re.MULTILINE)
buf = pat.sub('\n', buf)
buf = buf.lstrip()
#associate *, &, and [] with type instead of variable
#pat = re.compile(r'\s+([*|&]+)\s*(\w+)')
pat = re.compile(r' \s* ([*|&]+) \s* (\w+)', re.VERBOSE)
buf = pat.sub(r'\1 \2', buf)
pat = re.compile(r'\s+ (\w+) \[ \s* \]', re.VERBOSE)
buf = pat.sub(r'[] \1', buf)
buf = string.replace(buf, '/** vtable:', '/**vtable:')
pat = re.compile(r'(\w+) \s* \* \s* \(', re.VERBOSE)
buf = pat.sub(r'\1* (', buf)
# make return types that are const work.
buf = re.sub(r'\s*\*\s*G_CONST_RETURN\s*\*\s*', '** ', buf)
buf = string.replace(buf, 'G_CONST_RETURN ', 'const-')
buf = string.replace(buf, 'const ', 'const-')
#strip GSEAL macros from the middle of function declarations:
pat = re.compile(r"""GSEAL""", re.VERBOSE)
buf = pat.sub('', buf)
return buf
def __read_declarations_in_buf(self, buf, filename):
vproto_pat=re.compile(r"""
/\*\*\s*(?P<what>(vtable|signal)):(?P<vtable>[\w\d_]+)\s*\*\*/\s*
(?P<ret>(-|\w|\&|\*)+\s*) # return type
\s+ # skip whitespace
\(\s*\*\s*(?P<vfunc>\w+)\s*\)
\s*[(] # match the function name until the opening (
\s*(?P<args>.*?)\s*[)] # group the function arguments
""", re.IGNORECASE|re.VERBOSE)
proto_pat=re.compile(r"""
(?P<ret>(-|\w|\&|\*)+\s*) # return type
\s+ # skip whitespace
(?P<func>\w+)\s*[(] # match the function name until the opening (
\s*(?P<args>.*?)\s*[)] # group the function arguments
""", re.IGNORECASE|re.VERBOSE)
arg_split_pat = re.compile("\s*,\s*")
buf = self.__clean_func(buf)
buf = string.split(buf,'\n')
for p in buf:
if not p:
continue
if DEBUG:
print 'matching line', repr(p)
fname = None
vfname = None
is_signal = False
m = proto_pat.match(p)
if m is None:
if DEBUG:
print 'proto_pat not matched'
m = vproto_pat.match(p)
if m is None:
if DEBUG:
print 'vproto_pat not matched'
if p.find('vtable:') >= 0:
print "oops", repr(p)
if p.find('moo_file_enc_new') >= 0:
print '***', repr(p)
continue
else:
vfname = m.group('vfunc')
if m.group('what') == 'signal':
is_signal = True
if DEBUG:
print 'proto_pat matched', repr(m.group(0))
print '+++ ', ('vfunc', 'signal')[is_signal], vfname
else:
if DEBUG:
print 'proto_pat matched', repr(m.group(0))
fname = m.group('func')
ret = m.group('ret')
if ret in ('return', 'else', 'if', 'switch'):
continue
if fname:
func = self.__symbol_dict.get(fname)
if func is None:
continue
if DEBUG:
print 'match:|%s|' % fname
elif not is_signal:
symbol_name = 'vfunc:%s:%s' % (m.group('vtable'), m.group('vfunc'))
func = self.__symbol_dict.get(symbol_name)
if func is None:
func = VMethod(symbol_name, None, None, None, None, None)
self.__symbol_dict[symbol_name] = func
self.vmethods.append(func)
if DEBUG:
print 'match:|%s|' % func.name
else:
symbol_name = ('signal:%s:%s' % (m.group('vtable'), m.group('vfunc'))).replace('_', '-')
func = self.__symbol_dict.get(symbol_name)
if func is None:
func = Signal(symbol_name, None, None, None, None, None)
self.__symbol_dict[symbol_name] = func
self.signals.append(func)
if DEBUG:
print 'match:|%s|' % func.name
args = m.group('args')
args = arg_split_pat.split(args)
for i in range(len(args)):
spaces = string.count(args[i], ' ')
if spaces > 1:
args[i] = string.replace(args[i], ' ', '-', spaces - 1).replace('gchar', 'char')
if ret != 'void':
ret = ret.replace('gchar', 'char')
if func.retval is None:
func.retval = Retval()
if func.retval.type is None:
func.retval.type = ret
if ret in ('char*', 'strv', 'char**'):
func.retval.annotations.insert(0, 'transfer full')
is_varargs = 0
has_args = len(args) > 0
for arg in args:
if arg == '...':
is_varargs = 1
elif arg in ('void', 'void '):
has_args = 0
if DEBUG:
print 'func ', ', '.join([p.name for p in func.params] if func.params else '')
if has_args and not is_varargs:
if func.params is None:
func.params = []
elif func.params:
assert len(func.params) == len(args)
for i in range(len(args)):
if DEBUG:
print 'arg:', args[i]
argtype, argname = string.split(args[i])
if DEBUG:
print argtype, argname
if len(func.params) <= i:
func.params.append(Param())
if func.params[i].name is None:
func.params[i].name = argname
if func.params[i].type is None:
func.params[i].type = argtype
if DEBUG:
print 'func ', ', '.join([p.name for p in func.params])
def __read_declarations(self, filename):
if DEBUG:
print filename
buf = open(filename).read()
self.__read_declarations_in_buf(buf, filename)

631
api/mdp/module.py Normal file
View File

@ -0,0 +1,631 @@
import sys
import re
import mdp.docparser as dparser
DEBUG = False
def split_camel_case_name(name):
comps = []
cur = ''
for c in name:
if c.islower() or not cur:
cur += c
else:
comps.append(cur)
cur = c
if cur:
comps.append(cur)
return comps
def get_class_method_c_name_prefix(cls):
comps = split_camel_case_name(cls)
return '_'.join([c.lower() for c in comps]) + '_'
def strip_class_prefix(name, cls):
prefix = get_class_method_c_name_prefix(cls)
if name.startswith(prefix):
return name[len(prefix):]
else:
return name
def strip_module_prefix(name, mod):
prefix = get_class_method_c_name_prefix(mod)
if name.startswith(prefix):
return name[len(prefix):]
else:
return name
def strip_module_prefix_from_class(name, mod):
mod = mod.lower()
mod = mod[0].upper() + mod[1:]
if name.startswith(mod):
return name[len(mod):]
else:
return name
def make_gtype_id(cls):
comps = split_camel_case_name(cls)
comps = [comps[0]] + ['TYPE'] + comps[1:]
return '_'.join([c.upper() for c in comps])
class Type(object):
def __init__(self, name):
object.__init__(self)
self.name = name
class BasicType(Type):
def __init__(self, name):
Type.__init__(self, name)
class _GTypedType(Type):
def __init__(self, name, short_name, gtype_id, docs):
Type.__init__(self, name)
self.docs = docs
self.methods = []
self.static_methods = []
self.gtype_id = gtype_id
self.short_name = short_name
self.annotations = {}
class EnumBase(_GTypedType):
def __init__(self, name, short_name, gtype_id, docs):
super(EnumBase, self).__init__(name, short_name, gtype_id, docs)
self.values = []
class EnumValue(object):
def __init__(self, name, attributes, docs):
super(EnumValue, self).__init__()
self.name = name
self.attributes = attributes
self.docs = docs
class Enum(EnumBase):
def __init__(self, name, short_name, gtype_id, docs):
super(Enum, self).__init__(name, short_name, gtype_id, docs)
class Flags(EnumBase):
def __init__(self, name, short_name, gtype_id, docs):
super(Flags, self).__init__(name, short_name, gtype_id, docs)
class _InstanceType(_GTypedType):
def __init__(self, name, short_name, gtype_id, docs):
_GTypedType.__init__(self, name, short_name, gtype_id, docs)
self.constructor = None
class Class(_InstanceType):
def __init__(self, name, short_name, parent, gtype_id, docs):
_InstanceType.__init__(self, name, short_name, gtype_id, docs)
self.parent = parent
self.vmethods = []
self.signals = []
class Boxed(_InstanceType):
def __init__(self, name, short_name, gtype_id, docs):
_InstanceType.__init__(self, name, short_name, gtype_id, docs)
class Pointer(_InstanceType):
def __init__(self, name, short_name, gtype_id, docs):
_InstanceType.__init__(self, name, short_name, gtype_id, docs)
class Symbol(object):
def __init__(self, name, c_name, docs):
object.__init__(self)
self.name = name
self.c_name = c_name
self.docs = docs
self.summary = None
self.annotations = {}
class FunctionBase(Symbol):
def __init__(self, name, c_name, params, retval, docs):
Symbol.__init__(self, name, c_name, docs)
self.params = params
self.retval = retval
class Function(FunctionBase):
def __init__(self, name, c_name, params, retval, docs):
FunctionBase.__init__(self, name, c_name, params, retval, docs)
class Method(FunctionBase):
def __init__(self, name, c_name, cls, params, retval, docs):
FunctionBase.__init__(self, name, c_name, params, retval, docs)
self.cls = cls
class StaticMethod(FunctionBase):
def __init__(self, name, c_name, cls, params, retval, docs):
FunctionBase.__init__(self, name, c_name, params, retval, docs)
self.cls = cls
class Constructor(FunctionBase):
def __init__(self, name, c_name, cls, params, retval, docs):
FunctionBase.__init__(self, name, c_name, params, retval, docs)
self.cls = cls
class VMethod(FunctionBase):
def __init__(self, name, cls, params, retval, docs):
FunctionBase.__init__(self, name, name, params, retval, docs)
self.cls = cls
class Signal(FunctionBase):
def __init__(self, name, cls, params, retval, docs):
FunctionBase.__init__(self, name, name, params, retval, docs)
self.cls = cls
class ParamBase(object):
def __init__(self, typ, docs):
object.__init__(self)
self.type = typ
self.docs = docs
self.attributes = {}
self.transfer_mode = None
self.element_type = None
self.array = False
self.array_fixed_len = None
self.array_len_param = None
self.array_zero_terminated = None
class Param(ParamBase):
def __init__(self, name, typ, docs):
ParamBase.__init__(self, typ, docs)
self.name = name
self.out = False
self.caller_allocates = False
self.callee_allocates = False
self.in_ = False
self.inout = False
self.allow_none = False
self.default_value = None
self.scope = 'call'
class Retval(ParamBase):
def __init__(self, typ, docs):
ParamBase.__init__(self, typ, docs)
class Module(object):
def __init__(self, name):
object.__init__(self)
self.name = name
self.classes = []
self.boxed = []
self.__class_dict = {}
self.functions = []
self.__methods = {}
self.__constructors = {}
self.__vmethods = {}
self.__signals = {}
self.types = {}
self.enums = []
def __add_class(self, pcls):
name = pcls.name
short_name = getattr(pcls, 'short_name', strip_module_prefix_from_class(pcls.name, self.name))
gtype_id = getattr(pcls, 'gtype_id', make_gtype_id(pcls.name))
docs = pcls.docs
parent = None
constructable = False
annotations = {}
for a in pcls.annotations:
pieces = a.split()
prefix = pieces[0]
if prefix == 'parent':
assert len(pieces) == 2
parent = pieces[1]
elif prefix == 'constructable':
assert len(pieces) == 1
constructable = True
elif prefix.find('.') >= 0:
annotations[prefix] = ' '.join(pieces[1:])
else:
raise RuntimeError("unknown annotation '%s' in class %s" % (a, name))
cls = Class(name, short_name, parent, gtype_id, docs)
cls.summary = pcls.summary
cls.annotations = annotations
cls.constructable = constructable
self.classes.append(cls)
self.__class_dict[name] = cls
def __add_boxed_or_pointer(self, pcls, What):
name = pcls.name
short_name = getattr(pcls, 'short_name', strip_module_prefix_from_class(pcls.name, self.name))
gtype_id = getattr(pcls, 'gtype_id', make_gtype_id(pcls.name))
docs = pcls.docs
annotations = {}
for a in pcls.annotations:
pieces = a.split()
prefix = pieces[0]
if prefix.find('.') >= 0:
annotations[prefix] = ' '.join(pieces[1:])
else:
raise RuntimeError("unknown annotation '%s' in class %s" % (a, name))
cls = What(name, short_name, gtype_id, docs)
cls.summary = pcls.summary
cls.annotations = annotations
self.boxed.append(cls)
self.__class_dict[name] = cls
def __add_boxed(self, pcls):
self.__add_boxed_or_pointer(pcls, Boxed)
def __add_pointer(self, pcls):
self.__add_boxed_or_pointer(pcls, Pointer)
def __add_enum(self, ptyp):
if DEBUG:
print 'enum', ptyp.name
name = ptyp.name
short_name = getattr(ptyp, 'short_name', strip_module_prefix_from_class(ptyp.name, self.name))
gtype_id = getattr(ptyp, 'gtype_id', make_gtype_id(ptyp.name))
docs = ptyp.docs
annotations = {}
for a in ptyp.annotations:
pieces = a.split()
prefix = pieces[0]
if prefix.find('.') >= 0:
annotations[prefix] = ' '.join(pieces[1:])
else:
raise RuntimeError("unknown annotation '%s' in class %s" % (a, name))
if isinstance(ptyp, dparser.Enum):
enum = Enum(name, short_name, gtype_id, docs)
else:
enum = Flags(name, short_name, gtype_id, docs)
for value in ptyp.values:
attributes = self.__parse_enum_value_annotations(value.annotations)
enum.values.append(EnumValue(value.name, attributes, value.docs))
enum.summary = ptyp.summary
enum.annotations = annotations
self.enums.append(enum)
def __parse_enum_value_annotations(self, annotations):
attributes = {}
for a in annotations:
pieces = a.split()
prefix = pieces[0]
if '.' in prefix[1:-1] and len(pieces) == 2:
attributes[prefix] = pieces[1]
if attributes:
return attributes
else:
return None
def __parse_param_or_retval_annotation(self, annotation, param):
pieces = annotation.split()
prefix = pieces[0]
if prefix == 'transfer':
if len(pieces) > 2:
raise RuntimeError("invalid annotation '%s'" % (a,))
if not pieces[1] in ('none', 'container', 'full'):
raise RuntimeError("invalid annotation '%s'" % (a,))
param.transfer_mode = pieces[1]
return True
if prefix == 'element-type':
if len(pieces) > 3:
raise RuntimeError("invalid annotation '%s'" % (a,))
if len(pieces) == 2:
param.element_type = pieces[1]
else:
param.element_type = pieces[1:]
return True
if prefix == 'array':
if len(pieces) == 1:
param.array = True
return True
if len(pieces) > 2:
raise RuntimeError("invalid annotation '%s'" % (a,))
m = re.match(r'fixed-size\s*=\s*(\d+)$', pieces[1])
if m:
param.array_fixed_size = int(m.group(1))
return True
m = re.match(r'length\s*=\s*(\S+)$', pieces[1])
if m:
param.array_len_param = m.group(1)
return True
m = re.match(r'zero-terminated\s*=\s*(\d+)$', pieces[1])
if m:
param.array_zero_terminated = bool(int(m.group(1)))
return True
raise RuntimeError("invalid annotation '%s'" % (a,))
if prefix == 'type':
if len(pieces) > 2:
raise RuntimeError("invalid annotation '%s'" % (a,))
param.type = pieces[1]
return True
if '.' in prefix[1:-1] and len(pieces) == 2:
param.attributes[prefix] = pieces[1]
return False
def __parse_param_annotation(self, annotation, param):
pieces = annotation.split()
prefix = pieces[0]
if prefix == 'out':
if len(pieces) > 2:
raise RuntimeError("invalid annotation '%s'" % (a,))
if len(pieces) == 1:
param.out = True
return True
if pieces[1] == 'caller-allocates':
param.out = True
param.caller_allocates = True
return True
if pieces[1] == 'callee-allocates':
param.out = True
param.callee_allocates = True
return True
raise RuntimeError("invalid annotation '%s'" % (a,))
if prefix == 'in':
if len(pieces) > 1:
raise RuntimeError("invalid annotation '%s'" % (a,))
param.in_ = True
return True
if prefix == 'inout':
if len(pieces) > 1:
raise RuntimeError("invalid annotation '%s'" % (a,))
param.inout = True
return True
if prefix == 'allow-none':
if len(pieces) > 1:
raise RuntimeError("invalid annotation '%s'" % (a,))
param.allow_none = True
return True
if prefix == 'default':
if len(pieces) != 2:
raise RuntimeError("invalid annotation '%s'" % (a,))
param.default_value = pieces[1]
return True
if prefix == 'scope':
if len(pieces) != 2:
raise RuntimeError("invalid annotation '%s'" % (a,))
if not pieces[1] in ('call', 'async', 'notified'):
raise RuntimeError("invalid annotation '%s'" % (a,))
param.scope = pieces[1]
return True
if '.' in prefix[1:-1] and len(pieces) == 2:
param.attributes[prefix] = pieces[1]
return False
def __parse_retval(self, pretval):
retval = Retval(pretval.type, pretval.docs)
if pretval.annotations:
for a in pretval.annotations:
if not self.__parse_param_or_retval_annotation(a, retval):
raise RuntimeError("invalid annotation '%s'" % (a,))
if not retval.type:
raise RuntimeError('return type missing')
return retval
def __parse_param(self, pp, pfunc):
if DEBUG:
print pp.name, pp.type, pp.docs
param = Param(pp.name, pp.type, pp.docs)
if pp.annotations:
for a in pp.annotations:
if self.__parse_param_or_retval_annotation(a, param):
pass
elif self.__parse_param_annotation(a, param):
pass
else:
raise RuntimeError("in %s: invalid annotation '%s'" % (pfunc.name, a,))
if param.type is None:
raise RuntimeError('in %s: type of param "%s" is missing' % (pfunc.name, param.name))
return param
def __add_vmethod(self, pfunc):
_, cls, name = pfunc.name.split(':')
assert _ == 'vfunc'
params = []
retval = None
docs = pfunc.docs
if pfunc.annotations:
for a in pfunc.annotations:
raise RuntimeError("unknown annotation '%s' in function %s" % (a, name))
if pfunc.params:
for p in pfunc.params:
params.append(self.__parse_param(p, pfunc))
if pfunc.retval:
retval = self.__parse_retval(pfunc.retval)
meth = VMethod(name, cls, params[1:], retval, docs)
this_class_methods = self.__vmethods.get(cls)
if not this_class_methods:
this_class_methods = []
self.__vmethods[cls] = this_class_methods
this_class_methods.append(meth)
def __add_signal(self, pfunc):
_, cls, name = pfunc.name.split(':')
assert _ == 'signal'
params = []
retval = None
docs = pfunc.docs
if pfunc.annotations:
for a in pfunc.annotations:
raise RuntimeError("unknown annotation '%s' in function %s" % (a, name))
if pfunc.params:
for p in pfunc.params:
params.append(self.__parse_param(p, pfunc))
if pfunc.retval:
retval = self.__parse_retval(pfunc.retval)
meth = Signal(name, cls, params[1:], retval, docs)
this_class_signals = self.__signals.get(cls)
if not this_class_signals:
this_class_signals = []
self.__signals[cls] = this_class_signals
this_class_signals.append(meth)
def __add_function(self, pfunc):
name = pfunc.name
c_name = pfunc.name
params = []
retval = None
docs = pfunc.docs
cls = None
constructor_of = None
static_method_of = None
kwargs = False
annotations = {}
if pfunc.annotations:
for a in pfunc.annotations:
pieces = a.split()
prefix = pieces[0]
if prefix == 'constructor-of':
assert len(pieces) == 2
constructor_of = pieces[1]
elif prefix == 'static-method-of':
assert len(pieces) == 2
static_method_of = pieces[1]
elif prefix == 'moo-kwargs':
assert len(pieces) == 1
kwargs = True
elif prefix.find('.') >= 0:
annotations[prefix] = ' '.join(pieces[1:])
else:
raise RuntimeError("unknown annotation '%s' in function %s" % (a, name))
if pfunc.params:
for p in pfunc.params:
params.append(self.__parse_param(p, pfunc))
if pfunc.retval:
retval = self.__parse_retval(pfunc.retval)
if hasattr(pfunc, 'method_of'):
cls = pfunc.method_of
elif static_method_of:
cls = static_method_of
elif constructor_of:
cls = constructor_of
elif params:
m = re.match(r'(const-)?([\w\d_]+)\*', params[0].type)
if m:
cls = m.group(2)
if not self.__class_dict.has_key(cls):
cls = None
if cls:
name = strip_class_prefix(name, cls)
else:
name = strip_module_prefix(name, self.name)
if constructor_of:
func = Constructor(name, c_name, cls, params, retval, docs)
if constructor_of in self.__constructors:
raise RuntimeError('duplicated constructor of class %s' % constructor_of)
self.__constructors[constructor_of] = func
elif cls:
if static_method_of:
func = StaticMethod(name, c_name, cls, params, retval, docs)
else:
func = Method(name, c_name, cls, params[1:], retval, docs)
this_class_methods = self.__methods.get(cls)
if not this_class_methods:
this_class_methods = []
self.__methods[cls] = this_class_methods
this_class_methods.append(func)
else:
func = Function(name, c_name, params, retval, docs)
self.functions.append(func)
func.summary = pfunc.summary
func.annotations = annotations
func.kwargs = kwargs
def init_from_dox(self, blocks):
for b in blocks:
if isinstance(b, dparser.Class):
self.__add_class(b)
elif isinstance(b, dparser.Boxed):
self.__add_boxed(b)
elif isinstance(b, dparser.Pointer):
self.__add_pointer(b)
elif isinstance(b, dparser.Enum) or isinstance(b, dparser.Flags):
self.__add_enum(b)
elif isinstance(b, dparser.Flags):
self.__add_flags(b)
elif isinstance(b, dparser.VMethod):
self.__add_vmethod(b)
elif isinstance(b, dparser.Signal):
self.__add_signal(b)
elif isinstance(b, dparser.Function):
self.__add_function(b)
else:
raise RuntimeError('oops')
instance_types = {}
for cls in self.classes + self.boxed:
if cls.name in instance_types:
raise RuntimeError('duplicated class %s' % (cls.name,))
instance_types[cls.name] = cls
for cls in self.__constructors:
func = self.__constructors[cls]
if not cls in instance_types:
raise RuntimeError('Constructor of unknown class %s' % cls)
else:
cls = instance_types[cls]
if cls.constructor is not None:
raise RuntimeError('duplicated constructor in class %s' % cls)
cls.constructor = func
for cls in self.__methods:
methods = self.__methods[cls]
if not cls in instance_types:
raise RuntimeError('Methods of unknown class %s' % cls)
else:
cls = instance_types[cls]
for m in methods:
m.cls = cls
if isinstance(m, Method):
cls.methods.append(m)
elif isinstance(m, StaticMethod):
cls.static_methods.append(m)
else:
oops()
for cls in self.__vmethods:
methods = self.__vmethods[cls]
if not cls in instance_types:
raise RuntimeError('Virtual methods of unknown class %s' % cls)
else:
cls = instance_types[cls]
for m in methods:
m.cls = cls
cls.vmethods += methods
for cls in self.__signals:
signals = self.__signals[cls]
if not cls in instance_types:
raise RuntimeError('Signals of unknown class %s' % cls)
else:
cls = instance_types[cls]
for s in signals:
s.cls = cls
cls.signals += signals
def format_func(func):
if func.retval and func.retval.type:
s = func.retval.type + ' '
else:
s = 'void '
s += func.name
s += ' ('
for i in range(len(func.params)):
if i != 0:
s += ', '
p = func.params[i]
s += '%s %s' % (p.type, p.name)
s += ')'
return s
if DEBUG:
for cls in self.classes:
print 'class %s' % (cls.name,)
for meth in cls.methods:
print ' %s' % (format_func(meth),)
for func in self.functions:
print format_func(func)

201
api/mdp/xmlwriter.py Normal file
View File

@ -0,0 +1,201 @@
import sys
import xml.etree.ElementTree as etree
import mdp.module as module
class Writer(object):
def __init__(self, out):
object.__init__(self)
self.out = out
self.xml = etree.TreeBuilder()
self.__tag_opened = False
self.__depth = 0
def __start_tag(self, tag, attrs={}):
if self.__tag_opened:
self.xml.data('\n')
if self.__depth > 0:
self.xml.data(' ' * self.__depth)
elm = self.xml.start(tag, attrs)
self.__tag_opened = True
self.__depth += 1
return elm
def __end_tag(self, tag):
if not self.__tag_opened and self.__depth > 1:
self.xml.data(' ' * (self.__depth - 1))
elm = self.xml.end(tag)
self.xml.data('\n')
self.__tag_opened = False
self.__depth -= 1
return elm
def __write_docs(self, docs):
if not docs:
return
self.__start_tag('doc')
docs = ' '.join(docs)
self.xml.data(docs)
self.__end_tag('doc')
def __write_summary(self, summary):
if not summary:
return
self.__start_tag('summary')
if isinstance(summary, list):
assert len(summary) == 1
summary = summary[0]
self.xml.data(summary)
self.__end_tag('summary')
def __write_param_or_retval_annotations(self, param, elm):
for k in param.attributes:
elm.set(k, self.attributes[v])
if param.transfer_mode is not None:
elm.set('transfer_mode', param.transfer_mode)
if param.element_type is not None:
elm.set('element_type', param.element_type)
if param.array:
elm.set('array', '1')
if param.array_fixed_len is not None:
elm.set('array_fixed_len', str(param.array_fixed_len))
if param.array_len_param is not None:
elm.set('array_len_param', param.array_len_param)
if param.array_zero_terminated:
elm.set('array_zero_terminated', '1')
def __write_param_annotations(self, param, elm):
self.__write_param_or_retval_annotations(param, elm)
if param.inout:
elm.set('inout', '1')
elif param.out:
elm.set('out', '1')
if param.caller_allocates:
elm.set('caller_allocates', '1')
elif param.callee_allocates:
elm.set('callee_allocates', '1')
if param.allow_none:
elm.set('allow_none', '1')
if param.default_value is not None:
elm.set('default_value', param.default_value)
if param.scope != 'call':
elm.set('scope', param.scope)
def __write_retval_annotations(self, retval, elm):
self.__write_param_or_retval_annotations(retval, elm)
def __check_type(self, param, func):
if param.type in ('char*', 'const-char*'):
print >>sys.stderr, '*** WARNING: raw type %s used in function %s' % (param.type, func)
def __write_param(self, param, func):
self.__check_type(param, func)
dic = dict(name=param.name, type=param.type)
elm = self.__start_tag('param', dic)
self.__write_param_annotations(param, elm)
self.__write_docs(param.docs)
self.__end_tag('param')
def __write_retval(self, retval, func):
self.__check_type(retval, func)
dic = dict(type=retval.type)
elm = self.__start_tag('retval', dic)
self.__write_retval_annotations(retval, elm)
self.__write_docs(retval.docs)
self.__end_tag('retval')
def __write_class(self, cls):
if not cls.parent and cls.name != 'GObject':
raise RuntimeError('parent missing in class %s' % (cls.name,))
dic = dict(name=cls.name, short_name=cls.short_name, parent=cls.parent or 'none', gtype_id=cls.gtype_id)
for k in cls.annotations:
dic[k] = cls.annotations[k]
if cls.constructable:
dic['constructable'] = '1'
self.__start_tag('class', dic)
self.__write_summary(cls.summary)
self.__write_docs(cls.docs)
if cls.constructor is not None:
self.__write_function(cls.constructor, 'constructor')
for meth in sorted(cls.static_methods, lambda x, y: cmp(x.name, y.name)):
self.__write_function(meth, 'static-method')
for meth in sorted(cls.signals, lambda x, y: cmp(x.name, y.name)):
self.__write_function(meth, 'signal')
for meth in sorted(cls.vmethods, lambda x, y: cmp(x.name, y.name)):
self.__write_function(meth, 'virtual')
for meth in sorted(cls.methods, lambda x, y: cmp(x.name, y.name)):
self.__write_function(meth, 'method')
self.__end_tag('class')
def __write_boxed(self, cls):
dic = dict(name=cls.name, short_name=cls.short_name, gtype_id=cls.gtype_id)
for k in cls.annotations:
dic[k] = cls.annotations[k]
tag = 'boxed' if isinstance(cls, module.Boxed) else 'pointer'
self.__start_tag(tag, dic)
self.__write_summary(cls.summary)
self.__write_docs(cls.docs)
if cls.constructor is not None:
self.__write_function(cls.constructor, 'constructor')
for meth in cls.methods:
self.__write_function(meth, 'method')
self.__end_tag(tag)
def __write_enum(self, enum):
if isinstance(enum, module.Enum):
tag = 'enum'
else:
tag = 'flags'
dic = dict(name=enum.name, short_name=enum.short_name, gtype_id=enum.gtype_id)
for k in enum.annotations:
dic[k] = enum.annotations[k]
self.__start_tag(tag, dic)
for v in enum.values:
dic = dict(name=v.name)
if v.attributes:
dic.update(v.attributes)
elm = self.__start_tag('value', dic)
self.__write_docs(v.docs)
self.__end_tag('value')
self.__write_summary(enum.summary)
self.__write_docs(enum.docs)
self.__end_tag(tag)
def __write_function(self, func, tag):
name=func.name
if tag == 'signal':
name = name.replace('_', '-')
dic = dict(name=name)
if tag != 'virtual' and tag != 'signal':
dic['c_name'] = func.c_name
if getattr(func, 'kwargs', False):
dic['kwargs'] = '1'
for k in func.annotations:
dic[k] = func.annotations[k]
self.__start_tag(tag, dic)
for p in func.params:
self.__write_param(p, func.c_name)
if func.retval:
self.__write_retval(func.retval, func.c_name)
self.__write_summary(func.summary)
self.__write_docs(func.docs)
self.__end_tag(tag)
def write(self, module):
self.__start_tag('module', dict(name=module.name))
for cls in sorted(module.classes, lambda x, y: cmp(x.name, y.name)):
self.__write_class(cls)
for cls in sorted(module.boxed, lambda x, y: cmp(x.name, y.name)):
self.__write_boxed(cls)
for enum in sorted(module.enums, lambda x, y: cmp(x.name, y.name)):
self.__write_enum(enum)
for func in sorted(module.functions, lambda x, y: cmp(x.name, y.name)):
self.__write_function(func, 'function')
self.__end_tag('module')
elm = self.xml.close()
etree.ElementTree(elm).write(self.out)
def write_xml(module, out):
Writer(out).write(module)

1
api/mpi/__init__.py Normal file
View File

@ -0,0 +1 @@
# empty

193
api/mpi/defswriter.py Normal file
View File

@ -0,0 +1,193 @@
from mpi.module import *
def split_camel_case_name(name):
comps = []
cur = ''
for c in name:
if c.islower() or not cur:
cur += c
else:
comps.append(cur)
cur = c
if cur:
comps.append(cur)
return comps
class_template = """\
(define-object %(short_name)s
(in-module "%(module)s")
(parent "%(parent)s")
(c-name "%(name)s")
(gtype-id "%(gtype_id)s")
)
"""
method_start_template = """\
(define-method %(name)s
(of-object "%(class)s")
(c-name "%(c_name)s")
(return-type "%(return_type)s")
"""
vmethod_start_template = """\
(define-virtual %(name)s
(of-object "%(class)s")
(return-type "%(return_type)s")
"""
function_start_template = """\
(define-function %(name)s
(c-name "%(c_name)s")
(return-type "%(return_type)s")
"""
type_template = """\
(define-%(what)s %(short_name)s
(in-module "%(module)s")
(c-name "%(name)s")
(gtype-id "%(gtype_id)s")
)
"""
class Writer(object):
def __init__(self, out):
object.__init__(self)
self.out = out
self.module = None
def __write_class_decl(self, cls):
dic = dict(name=cls.name,
short_name=cls.short_name,
module=self.module.name,
parent=cls.parent,
gtype_id=cls.gtype_id)
self.out.write(class_template % dic)
self.out.write('\n')
def __write_boxed_decl(self, cls):
dic = dict(name=cls.name,
short_name=cls.short_name,
module=self.module.name,
gtype_id=cls.gtype_id,
what='boxed')
self.out.write(type_template % dic)
self.out.write('\n')
def __write_pointer_decl(self, cls):
dic = dict(name=cls.name,
short_name=cls.short_name,
module=self.module.name,
gtype_id=cls.gtype_id,
what='pointer')
self.out.write(type_template % dic)
self.out.write('\n')
def __write_enum_decl(self, cls):
dic = dict(name=cls.name,
short_name=cls.short_name,
module=self.module.name,
gtype_id=cls.gtype_id,
what='enum' if isinstance(cls, Enum) else 'flags')
self.out.write(type_template % dic)
self.out.write('\n')
def __get_pygtk_type_name(self, typ):
if isinstance(typ, InstanceType):
return typ.name + '*'
elif typ.name in ('utf8', 'filename', 'cstring'):
return 'char*'
elif typ.name in ('const-utf8', 'const-filename', 'const-cstring'):
return 'const-char*'
else:
return typ.name
def __write_function_or_method(self, meth, cls):
if meth.retval is None:
return_type = 'none'
else:
return_type = self.__get_pygtk_type_name(meth.retval.type)
dic = dict(name=meth.name, c_name=meth.c_name, return_type=return_type)
if not cls:
self.out.write(function_start_template % dic)
elif isinstance(meth, Constructor):
dic['class'] = cls.name
self.out.write(function_start_template % dic)
self.out.write(' (is-constructor-of %s)\n' % cls.name)
elif isinstance(meth, StaticMethod):
dic['class'] = cls.name
self.out.write(method_start_template % dic)
self.out.write(' (is-static-method #t)\n')
elif isinstance(meth, VMethod):
dic['class'] = cls.name
self.out.write(vmethod_start_template % dic)
else:
dic['class'] = cls.name
self.out.write(method_start_template % dic)
if meth.retval:
if meth.retval.transfer_mode == 'full':
self.out.write(' (caller-owns-return #t)\n')
elif meth.retval.transfer_mode is not None:
raise RuntimeError('do not know how to handle transfer mode %s' % (meth.retval.transfer_mode,))
if meth.params:
self.out.write(' (parameters\n')
for p in meth.params:
self.out.write(' \'("%s" "%s"' % (self.__get_pygtk_type_name(p.type), p.name))
if p.allow_none:
self.out.write(' (null-ok)')
if p.default_value is not None:
self.out.write(' (default "%s")' % (p.default_value,))
self.out.write(')\n')
self.out.write(' )\n')
self.out.write(')\n\n')
def __write_class_method(self, meth, cls):
self.__write_function_or_method(meth, cls)
def __write_static_class_method(self, meth, cls):
self.__write_function_or_method(meth, cls)
def __write_class_methods(self, cls):
self.out.write('; methods of %s\n\n' % cls.name)
if cls.constructor is not None:
self.__write_function_or_method(cls.constructor, cls)
if hasattr(cls, 'constructable') and cls.constructable:
cons = Constructor()
cons.name = '%s__new__' % cls.name
cons.c_name = cons.name
self.__write_function_or_method(cons, cls)
if isinstance(cls, Class):
for meth in cls.vmethods:
self.__write_class_method(meth, cls)
for meth in cls.methods:
self.__write_class_method(meth, cls)
for meth in cls.static_methods:
self.__write_static_class_method(meth, cls)
def __write_function(self, func):
self.__write_function_or_method(func, None)
def write(self, module):
self.module = module
self.out.write('; -*- scheme -*-\n\n')
self.out.write('; classes\n\n')
for cls in module.get_classes():
self.__write_class_decl(cls)
self.out.write('; boxed types\n\n')
for cls in module.get_boxed():
self.__write_boxed_decl(cls)
self.out.write('; pointer types\n\n')
for cls in module.get_pointers():
self.__write_pointer_decl(cls)
self.out.write('; enums and flags\n\n')
for enum in module.get_enums():
self.__write_enum_decl(enum)
for cls in module.get_classes():
self.__write_class_methods(cls)
for cls in module.get_boxed():
self.__write_class_methods(cls)
for cls in module.get_pointers():
self.__write_class_methods(cls)
self.out.write('; functions\n\n')
for func in module.get_functions():
self.__write_function(func)
self.module = None

502
api/mpi/docbookwriter.py Normal file
View File

@ -0,0 +1,502 @@
import StringIO
from mpi.util import *
from mpi.module import *
lua_constants = {
'NULL': '<constant>nil</constant>',
'TRUE': '<constant>true</constant>',
'FALSE': '<constant>false</constant>',
'INDEXBASE': '<constant>1</constant>',
}
python_constants = {
'NULL': '<constant>None</constant>',
'TRUE': '<constant>True</constant>',
'FALSE': '<constant>False</constant>',
'GTK_RESPONSE_OK': '<constant><ulink url="http://library.gnome.org/devel/pygtk/stable/' +
'gtk-constants.html#gtk-response-type-constants">gtk.RESPONSE_OK</ulink></constant>',
'INDEXBASE': '<constant>0</constant>',
}
common_types = {
'gboolean': '<constant>bool</constant>',
'strv': 'list of strings',
}
lua_types = dict(common_types)
lua_types.update({
'index': '<constant>integer index (1-based)</constant>',
'value': '<constant>value</constant>',
'gunichar': '<constant>string</constant>',
'double': '<constant>number</constant>',
'int': '<constant>integer</constant>',
'gint': '<constant>integer</constant>',
'guint': '<constant>integer</constant>',
'gulong': '<constant>integer</constant>',
'const-utf8': '<constant>string</constant>',
'utf8': '<constant>string</constant>',
'const-filename': '<constant>string</constant>',
'filename': '<constant>string</constant>',
'const-cstring': '<constant>string</constant>',
'cstring': '<constant>string</constant>',
})
python_types = dict(common_types)
python_types.update({
'index': '<constant>integer index (0-based)</constant>',
'gunichar': '<constant>str</constant>',
'double': '<constant>float</constant>',
'int': '<constant>int</constant>',
'gint': '<constant>int</constant>',
'guint': '<constant>int</constant>',
'gulong': '<constant>int</constant>',
'const-utf8': '<constant>str</constant>',
'utf8': '<constant>str</constant>',
'const-filename': '<constant>str</constant>',
'filename': '<constant>str</constant>',
'const-cstring': '<constant>str</constant>',
'cstring': '<constant>str</constant>',
})
def format_python_symbol_ref(symbol):
constants = {
}
classes = {
'GFile': '<ulink url="http://library.gnome.org/devel/pygobject/stable/class-giofile.html">gio.File</ulink>',
'GObject': '<ulink url="http://library.gnome.org/devel/pygobject/stable/class-gobject.html">gobject.Object</ulink>',
'GType': 'type',
}
if symbol in constants:
return '<constant>%s</constant>' % constants[symbol]
if symbol in classes:
return '<constant>%s</constant>' % classes[symbol]
if symbol.startswith('Gtk'):
return ('<constant><ulink url="http://library.gnome.org/devel/pygtk/stable/class-' + \
'gtk%s.html">gtk.%s</ulink></constant>') % (symbol[3:].lower(), symbol[3:])
if symbol.startswith('Gdk'):
return '<constant><ulink url="http://library.gnome.org/devel/pygtk/stable/class-' + \
'gdk%s.html">gtk.gdk.%s</ulink></constant>' % (symbol[3:].lower(), symbol[3:])
raise NotImplementedError(symbol)
def split_camel_case_name(name):
comps = []
cur = ''
for c in name:
if c.islower() or not cur:
cur += c
else:
comps.append(cur)
cur = c
if cur:
comps.append(cur)
return comps
def name_all_caps(cls):
return '_'.join([s.upper() for s in split_camel_case_name(cls.name)])
class Writer(object):
def __init__(self, mode, template, out):
super(Writer, self).__init__()
self.file = out
self.out = StringIO.StringIO()
self.mode = mode
self.template = template
if mode == 'python':
self.constants = python_constants
self.builtin_types = python_types
elif mode == 'lua':
self.constants = lua_constants
self.builtin_types = lua_types
else:
oops('unknown mode %s' % mode)
self.section_suffix = ' (%s)' % self.mode.capitalize()
def __format_symbol_ref(self, name):
sym = self.symbols.get(name)
if sym:
if isinstance(sym, EnumValue):
return '<constant><link linkend="%(mode)s.%(parent)s" endterm="%(mode)s.%(symbol)s.title"></link></constant>' % \
dict(symbol=name, mode=self.mode, parent=sym.enum.symbol_id())
elif isinstance(sym, Type):
return '<constant><link linkend="%(mode)s.%(symbol)s">%(name)s</link></constant>' % \
dict(symbol=name, mode=self.mode, name=self.__make_class_name(sym))
elif isinstance(sym, Method):
return '<constant><link linkend="%(mode)s.%(symbol)s">%(Class)s.%(method)s()</link></constant>' % \
dict(symbol=name, mode=self.mode, Class=self.__make_class_name(sym.cls), method=sym.name)
else:
oops(name)
if self.mode == 'python':
return format_python_symbol_ref(name)
else:
raise NotImplementedError(name)
def __string_to_bool(self, s):
if s == '0':
return False
elif s == '1':
return True
else:
oops()
def __check_bind_ann(self, obj):
bind = self.__string_to_bool(obj.annotations.get('moo.' + self.mode, '1'))
if bind:
bind = not self.__string_to_bool(obj.annotations.get('moo.private', '0'))
return bind
def __format_constant(self, value):
if value in self.constants:
return self.constants[value]
try:
i = int(value)
return value
except ValueError:
pass
formatted = self.__format_symbol_ref(value)
if formatted:
return formatted
error("unknown constant '%s'" % value)
return value
def __format_default_value(self, p):
if p.type.name == 'index' and self.mode == 'lua':
return str(int(p.default_value) + 1)
else:
return self.__format_constant(p.default_value)
def __format_doc(self, doc):
text = doc.text
text = re.sub(r'@([\w\d_]+)(?!\{)', r'<parameter>\1</parameter>', text)
text = re.sub(r'%NULL\b', '<constant>%s</constant>' % self.constants['NULL'], text)
text = re.sub(r'%TRUE\b', '<constant>%s</constant>' % self.constants['TRUE'], text)
text = re.sub(r'%FALSE\b', '<constant>%s</constant>' % self.constants['FALSE'], text)
text = re.sub(r'%INDEXBASE\b', '<constant>%s</constant>' % self.constants['INDEXBASE'], text)
text = text.replace(r'<n/>', '')
text = text.replace(r'<nl/>', '\n')
def repl_func(m):
func_id = m.group(1)
symbol = self.symbols.get(func_id)
if not isinstance(symbol, MethodBase) or symbol.cls == self.current_class:
return '<function><link linkend="%(mode)s.%(func_id)s" endterm="%(mode)s.%(func_id)s.title"/></function>' % \
dict(func_id=func_id, mode=self.mode)
else:
return '<function><link linkend="%(mode)s.%(func_id)s">%(Class)s.%(method)s()</link></function>' % \
dict(func_id=func_id, mode=self.mode, Class=self.__make_class_name(symbol.cls), method=symbol.name)
text = re.sub(r'([\w\d_.]+)\(\)', repl_func, text)
def repl_signal(m):
cls = m.group(1)
signal = m.group(2).replace('_', '-')
symbol = 'signal:%s:%s' % (cls, signal)
if self.symbols[cls] != self.current_class:
return '<function><link linkend="%(mode)s.%(symbol)s">%(Class)s.%(signal)s</link></function>' % \
dict(Class=cls, symbol=symbol, mode=self.mode, signal=signal)
else:
return '<function><link linkend="%(mode)s.%(symbol)s">%(signal)s</link></function>' % \
dict(symbol=symbol, mode=self.mode, signal=signal)
text = re.sub(r'([\w\d_-]+)::([\w\d_-]+)', repl_signal, text)
def repl_symbol(m):
symbol = m.group(1)
formatted = self.__format_symbol_ref(symbol)
if not formatted:
raise RuntimeError('unknown symbol %s' % symbol)
return formatted
text = re.sub(r'#([\w\d_]+)', repl_symbol, text)
assert not re.search(r'NULL|TRUE|FALSE', text)
return text
def __make_class_name(self, cls):
return '%s.%s' % (cls.module.name.lower(), cls.short_name)
def __get_obj_name(self, cls):
name = cls.annotations.get('moo.doc-object-name')
if not name:
name = '_'.join([c.lower() for c in split_camel_case_name(cls.name)[1:]])
return name
def __write_function(self, func, cls):
if not self.__check_bind_ann(func):
return
func_params = list(func.params)
if func.has_gerror_return:
func_params = func_params[:-1]
params = []
for p in func_params:
if not self.__check_bind_ann(p.type):
return
if p.default_value is not None:
params.append('%s=%s' % (p.name, self.__format_default_value(p)))
else:
params.append(p.name)
if isinstance(func, Constructor):
if self.mode == 'python':
func_title = cls.short_name + '()'
func_name = cls.short_name
elif self.mode == 'lua':
func_title = 'new' + '()'
func_name = '%s.new' % cls.short_name
else:
oops()
elif isinstance(func, Signal):
if self.mode == 'python':
func_title = 'signal ' + func.name
func_name = func.name
elif self.mode == 'lua':
func_title = 'signal ' + func.name
func_name = func.name
else:
oops()
elif cls is not None:
if self.mode in ('python', 'lua'):
func_title = func.name + '()'
func_name = '%s.%s' % (self.__get_obj_name(cls), func.name) \
if not isinstance(func, StaticMethod) \
else '%s.%s' % (cls.short_name, func.name)
else:
oops()
else:
func_title = func.name + '()'
func_name = '%s.%s' % (self.module.name.lower(), func.name)
params_string = ', '.join(params)
if func.summary:
oops(func_id)
func_id = func.symbol_id()
mode = self.mode
if mode == 'lua' and func.kwargs:
left_paren, right_paren = '{}'
else:
left_paren, right_paren = '()'
self.out.write("""\
<!-- %(func_id)s -->
<sect2 id="%(mode)s.%(func_id)s">
<title id="%(mode)s.%(func_id)s.title">%(func_title)s</title>
<programlisting>%(func_name)s%(left_paren)s%(params_string)s%(right_paren)s</programlisting>
""" % locals())
if func.doc:
self.out.write('<para>%s</para>\n' % self.__format_doc(func.doc))
if func_params:
self.out.write("""\
<variablelist>
<?dbhtml list-presentation="table"?>
<?dbhtml term-separator=" : "?>
""")
for p in func_params:
if p.doc:
docs = doc=self.__format_doc(p.doc)
else:
ptype = p.type.symbol_id()
if ptype.endswith('*'):
ptype = ptype[:-1]
if ptype.startswith('const-'):
ptype = ptype[len('const-'):]
if ptype in self.builtin_types:
docs = self.builtin_types[ptype]
if p.allow_none:
docs = docs + ' or ' + self.__format_constant('NULL')
elif ptype.endswith('Array'):
elmtype = ptype[:-len('Array')]
if elmtype in self.symbols and isinstance(self.symbols[elmtype], InstanceType):
docs = 'list of %s objects' % self.__format_symbol_ref(self.symbols[elmtype].symbol_id())
else:
docs = self.__format_symbol_ref(ptype)
else:
docs = self.__format_symbol_ref(ptype)
if p.allow_none:
docs = docs + ' or ' + self.__format_constant('NULL')
param_dic = dict(param=p.name, doc=docs)
self.out.write("""\
<varlistentry>
<term><parameter>%(param)s</parameter></term>
<listitem><para>%(doc)s</para></listitem>
</varlistentry>
""" % param_dic)
self.out.write('</variablelist>\n')
if func.retval:
retdoc = None
if func.retval.doc:
retdoc = self.__format_doc(func.retval.doc)
else:
rettype = func.retval.type.symbol_id()
if rettype.endswith('*'):
rettype = rettype[:-1]
if rettype in self.builtin_types:
retdoc = self.builtin_types[rettype]
elif rettype.endswith('Array'):
elmtype = rettype[:-len('Array')]
if elmtype in self.symbols and isinstance(self.symbols[elmtype], InstanceType):
retdoc = 'list of %s objects' % self.__format_symbol_ref(self.symbols[elmtype].symbol_id())
else:
retdoc = self.__format_symbol_ref(rettype)
else:
retdoc = self.__format_symbol_ref(rettype)
if retdoc:
self.out.write('<para><parameter>Returns:</parameter> %s</para>\n' % retdoc)
self.out.write('</sect2>\n')
def __write_gobject_constructor(self, cls):
func = Constructor()
self.__write_function(func, cls)
def __write_class(self, cls):
if not self.__check_bind_ann(cls):
return
self.current_class = cls
title = self.__make_class_name(cls)
if cls.summary:
title += ' - ' + cls.summary.text
dic = dict(class_id=cls.symbol_id(), title=title, mode=self.mode)
self.out.write("""\
<!-- %(class_id)s -->
<sect1 id="%(mode)s.%(class_id)s">
<title id="%(mode)s.%(class_id)s.title">%(title)s</title>
""" % dic)
if cls.doc:
self.out.write('<para>%s</para>\n' % self.__format_doc(cls.doc))
if getattr(cls, 'parent', 'none') != 'none':
self.out.write("""\
<programlisting>
%(ParentClass)s
|
+-- %(Class)s
</programlisting>
""" % dict(ParentClass=self.__format_symbol_ref(cls.parent), Class=self.__make_class_name(cls)))
if hasattr(cls, 'signals') and cls.signals:
for signal in cls.signals:
self.__write_function(signal, cls)
if cls.constructor is not None:
self.__write_function(cls.constructor, cls)
if hasattr(cls, 'constructable') and cls.constructable:
self.__write_gobject_constructor(cls)
for meth in cls.static_methods:
self.__write_function(meth, cls)
if isinstance(cls, Class):
if cls.vmethods:
implement_me('virtual methods of %s' % cls.name)
for meth in cls.methods:
self.__write_function(meth, cls)
self.out.write("""\
</sect1>
""" % dic)
self.current_class = None
def __write_enum(self, enum):
if not self.__check_bind_ann(enum):
return
do_write = False
for v in enum.values:
if self.__check_bind_ann(v):
do_write = True
break
if not do_write:
return
title = self.__make_class_name(enum)
if enum.summary:
title += ' - ' + enum.summary.text
dic = dict(title=title,
mode=self.mode,
enum_id=enum.symbol_id())
self.out.write("""\
<!-- %(enum_id)s -->
<sect2 id="%(mode)s.%(enum_id)s">
<title id="%(mode)s.%(enum_id)s.title">%(title)s</title>
""" % dic)
if enum.doc:
self.out.write('<para>%s</para>\n' % self.__format_doc(enum.doc))
self.out.write("""\
<variablelist>
<?dbhtml list-presentation="table"?>
""")
for v in enum.values:
if not self.__check_bind_ann(v):
continue
value_dic = dict(mode=self.mode, enum_id=v.name, value=v.short_name,
doc=self.__format_doc(v.doc) if v.doc else '')
self.out.write("""\
<varlistentry>
<term><constant id="%(mode)s.%(enum_id)s.title">%(value)s</constant></term>
<listitem><para>%(doc)s</para></listitem>
</varlistentry>
""" % value_dic)
self.out.write('</variablelist>\n')
self.out.write('</sect2>\n')
def write(self, module):
self.module = module
self.symbols = module.get_symbols()
self.current_class = None
classes = module.get_classes() + module.get_boxed() + module.get_pointers()
for cls in sorted(classes, lambda cls1, cls2: cmp(cls1.short_name, cls2.short_name)):
self.__write_class(cls)
funcs = []
for f in module.get_functions():
if self.__check_bind_ann(f):
funcs.append(f)
dic = dict(mode=self.mode)
if funcs:
self.out.write("""\
<!-- functions -->
<sect1 id="%(mode)s.functions">
<title>Functions</title>
""" % dic)
for func in funcs:
self.__write_function(func, None)
self.out.write('</sect1>\n')
self.out.write("""\
<!-- enums -->
<sect1 id="%(mode)s.enums">
<title>Enumerations</title>
""" % dic)
for func in module.get_enums():
self.__write_enum(func)
self.out.write('</sect1>\n')
content = self.out.getvalue()
template = open(self.template).read()
self.file.write(template.replace('###GENERATED###', content))
del self.out
del self.module

547
api/mpi/luawriter.py Normal file
View File

@ -0,0 +1,547 @@
import sys
from mpi.module import *
tmpl_file_start = """\
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
%(headers)s
#include "moolua/moo-lua-api-util.h"
void moo_test_coverage_record (const char *lang, const char *function);
"""
tmpl_cfunc_method_start = """\
static int
%(cfunc)s (gpointer pself, G_GNUC_UNUSED lua_State *L, G_GNUC_UNUSED int first_arg)
{
#ifdef MOO_ENABLE_COVERAGE
moo_test_coverage_record ("lua", "%(c_name)s");
#endif
MooLuaCurrentFunc cur_func ("%(current_function)s");
%(check_kwargs)s %(Class)s *self = (%(Class)s*) pself;
"""
tmpl_cfunc_func_start = """\
static int
%(cfunc)s (G_GNUC_UNUSED lua_State *L)
{
#ifdef MOO_ENABLE_COVERAGE
moo_test_coverage_record ("lua", "%(c_name)s");
#endif
MooLuaCurrentFunc cur_func ("%(current_function)s");
%(check_kwargs)s"""
tmpl_register_module_start = """\
static void
%(module)s_lua_api_register (void)
{
static gboolean been_here = FALSE;
if (been_here)
return;
been_here = TRUE;
"""
tmpl_register_one_type_start = """\
MooLuaMethodEntry methods_%(Class)s[] = {
"""
tmpl_register_one_type_end = """\
{ NULL, NULL }
};
moo_lua_register_methods (%(gtype_id)s, methods_%(Class)s);
"""
class ArgHelper(object):
def format_arg(self, allow_none, default_value, arg_name, arg_idx, param_name):
return ''
def c_allow_none(attr):
if attr is True:
return 'TRUE'
elif attr in (False, None):
return 'FALSE'
else:
oops()
class SimpleArgHelper(ArgHelper):
def __init__(self, name, suffix, can_be_null=False):
super(SimpleArgHelper, self).__init__()
self.name = name
self.suffix = suffix
self.can_be_null = can_be_null
def format_arg(self, allow_none, default_value, arg_name, arg_idx, param_name):
dic = dict(type=self.name, arg_name=arg_name, default_value=default_value,
arg_idx=arg_idx, param_name=param_name, suffix=self.suffix,
allow_none=c_allow_none(allow_none))
if self.can_be_null:
if default_value is not None:
return '%(type)s %(arg_name)s = moo_lua_get_arg_%(suffix)s_opt (L, %(arg_idx)s, "%(param_name)s", %(default_value)s, %(allow_none)s);' % dic
else:
return '%(type)s %(arg_name)s = moo_lua_get_arg_%(suffix)s (L, %(arg_idx)s, "%(param_name)s", %(allow_none)s);' % dic
else:
if default_value is not None:
return '%(type)s %(arg_name)s = moo_lua_get_arg_%(suffix)s_opt (L, %(arg_idx)s, "%(param_name)s", %(default_value)s);' % dic
else:
return '%(type)s %(arg_name)s = moo_lua_get_arg_%(suffix)s (L, %(arg_idx)s, "%(param_name)s");' % dic
_arg_helpers = {}
_arg_helpers['int'] = SimpleArgHelper('int', 'int')
_arg_helpers['gint'] = SimpleArgHelper('int', 'int')
_arg_helpers['guint'] = SimpleArgHelper('guint', 'uint')
_arg_helpers['glong'] = SimpleArgHelper('long', 'long')
_arg_helpers['gulong'] = SimpleArgHelper('gulong', 'ulong')
_arg_helpers['gboolean'] = SimpleArgHelper('gboolean', 'bool')
_arg_helpers['index'] = SimpleArgHelper('int', 'index')
_arg_helpers['double'] = SimpleArgHelper('double', 'double')
_arg_helpers['const-char*'] = SimpleArgHelper('const char*', 'string', True)
_arg_helpers['char*'] = SimpleArgHelper('char*', 'string', True)
_arg_helpers['const-utf8'] = SimpleArgHelper('const char*', 'utf8', True)
_arg_helpers['utf8'] = SimpleArgHelper('char*', 'utf8', True)
_arg_helpers['const-filename'] = SimpleArgHelper('const char*', 'filename', True)
_arg_helpers['filename'] = SimpleArgHelper('char*', 'filename', True)
_arg_helpers['const-cstring'] = SimpleArgHelper('const char*', 'string', True)
_arg_helpers['cstring'] = SimpleArgHelper('char*', 'string', True)
def find_arg_helper(param):
return _arg_helpers[param.type.name]
_pod_ret_helpers = {}
_pod_ret_helpers['int'] = ('int', 'int64')
_pod_ret_helpers['uint'] = ('guint', 'uint64')
_pod_ret_helpers['gint'] = ('int', 'int64')
_pod_ret_helpers['guint'] = ('guint', 'uint64')
_pod_ret_helpers['glong'] = ('long', 'int64')
_pod_ret_helpers['gulong'] = ('gulong', 'uint64')
_pod_ret_helpers['gboolean'] = ('gboolean', 'bool')
_pod_ret_helpers['index'] = ('int', 'index')
def find_pod_ret_helper(name):
return _pod_ret_helpers[name]
class Writer(object):
def __init__(self, out):
super(Writer, self).__init__()
self.out = out
def __write_function_param(self, func_body, param, i, meth, cls):
dic = dict(narg=i, gtype_id=param.type.gtype_id, param_name=param.name,
allow_none=c_allow_none(param.allow_none),
default_value=param.default_value,
first_arg='first_arg' if cls else '1',
arg_idx=('first_arg + %d' % (i,)) if cls else ('1 + %d' % (i,)),
TypeName=param.type.name,
)
if meth.kwargs:
func_body.start.append('int arg_idx%(narg)d = %(arg_idx)s;' % dic)
func_body.start.append('if (kwargs)')
func_body.start.append(' arg_idx%(narg)d = moo_lua_get_kwarg (L, %(first_arg)s, %(narg)d + 1, "%(param_name)s");' % dic)
if param.default_value is None:
func_body.start.append('if (arg_idx%(narg)d == MOO_NONEXISTING_INDEX)' % dic)
func_body.start.append(' moo_lua_arg_error (L, 0, "%(param_name)s", "parameter \'%(param_name)s\' missing");' % dic)
dic['arg_idx'] = 'arg_idx%(narg)d' % dic
if param.type.name == 'GtkTextIter':
assert param.default_value is None or param.default_value == 'NULL'
if param.default_value is not None:
dic['get_arg'] = 'moo_lua_get_arg_iter_opt'
else:
dic['get_arg'] = 'moo_lua_get_arg_iter'
if cls.name == 'MooEdit':
dic['buffer'] = 'moo_edit_get_buffer (self)'
else:
dic['buffer'] = 'NULL'
if param.default_value is not None:
func_body.start.append('GtkTextIter arg%(narg)d_iter;' % dic)
func_body.start.append(('GtkTextIter *arg%(narg)d = %(get_arg)s (L, %(arg_idx)s, ' + \
'"%(param_name)s", %(buffer)s, &arg%(narg)d_iter) ? &arg%(narg)d_iter : NULL;') % dic)
else:
func_body.start.append('GtkTextIter arg%(narg)d_iter;' % dic)
func_body.start.append('GtkTextIter *arg%(narg)d = &arg%(narg)d_iter;' % dic)
func_body.start.append('%(get_arg)s (L, %(arg_idx)s, "%(param_name)s", %(buffer)s, &arg%(narg)d_iter);' % dic)
elif param.type.name == 'GdkRectangle':
assert param.default_value is None or param.default_value == 'NULL'
if param.default_value is not None:
dic['get_arg'] = 'moo_lua_get_arg_rect_opt'
else:
dic['get_arg'] = 'moo_lua_get_arg_rect'
if param.default_value is not None:
func_body.start.append('GdkRectangle arg%(narg)d_rect;' % dic)
func_body.start.append(('GdkRectangle *arg%(narg)d = %(get_arg)s (L, %(arg_idx)s, ' + \
'"%(param_name)s", &arg%(narg)d_rect) ? &arg%(narg)d_rect : NULL;') % dic)
else:
func_body.start.append('GdkRectangle arg%(narg)d_rect;' % dic)
func_body.start.append('GdkRectangle *arg%(narg)d = &arg%(narg)d_rect;' % dic)
func_body.start.append('%(get_arg)s (L, %(arg_idx)s, "%(param_name)s", &arg%(narg)d_rect);' % dic)
elif param.type.name == 'SignalClosure*':
assert param.default_value is None
func_body.start.append(('MooLuaSignalClosure *arg%(narg)d = moo_lua_get_arg_signal_closure ' + \
'(L, %(arg_idx)s, "%(param_name)s");') % dic)
func_body.end.append('g_closure_unref ((GClosure*) arg%(narg)d);' % dic)
elif isinstance(param.type, Class) or isinstance(param.type, Boxed) or isinstance(param.type, Pointer):
if param.default_value is not None:
func_body.start.append(('%(TypeName)s *arg%(narg)d = (%(TypeName)s*) ' + \
'moo_lua_get_arg_instance_opt (L, %(arg_idx)s, "%(param_name)s", ' + \
'%(gtype_id)s, %(allow_none)s);') % dic)
else:
func_body.start.append(('%(TypeName)s *arg%(narg)d = (%(TypeName)s*) ' + \
'moo_lua_get_arg_instance (L, %(arg_idx)s, "%(param_name)s", ' + \
'%(gtype_id)s, %(allow_none)s);') % dic)
elif isinstance(param.type, Enum) or isinstance(param.type, Flags):
if param.default_value is not None:
func_body.start.append(('%(TypeName)s arg%(narg)d = (%(TypeName)s) ' + \
'moo_lua_get_arg_enum_opt (L, %(arg_idx)s, "%(param_name)s", ' + \
'%(gtype_id)s, %(default_value)s);') % dic)
else:
func_body.start.append(('%(TypeName)s arg%(narg)d = (%(TypeName)s) ' + \
'moo_lua_get_arg_enum (L, %(arg_idx)s, "%(param_name)s", ' + \
'%(gtype_id)s);') % dic)
elif isinstance(param.type, ArrayType):
assert isinstance(param.type.elm_type, Class)
dic['gtype_id'] = param.type.elm_type.gtype_id
if param.default_value is not None:
func_body.start.append(('%(TypeName)s arg%(narg)d = (%(TypeName)s) ' + \
'moo_lua_get_arg_object_array_opt (L, %(arg_idx)s, "%(param_name)s", ' + \
'%(gtype_id)s);') % dic)
else:
func_body.start.append(('%(TypeName)s arg%(narg)d = (%(TypeName)s) ' + \
'moo_lua_get_arg_object_array (L, %(arg_idx)s, "%(param_name)s", ' + \
'%(gtype_id)s);') % dic)
func_body.end.append('moo_object_array_free ((MooObjectArray*) arg%(narg)d);' % dic)
elif param.type.name == 'strv':
assert param.default_value is None or param.default_value == 'NULL'
if param.default_value is not None:
func_body.start.append(('char **arg%(narg)d = moo_lua_get_arg_strv_opt (L, %(arg_idx)s, "%(param_name)s", %(allow_none)s);') % dic)
else:
func_body.start.append(('char **arg%(narg)d = moo_lua_get_arg_strv (L, %(arg_idx)s, "%(param_name)s", %(allow_none)s);') % dic)
func_body.end.append('g_strfreev (arg%(narg)d);' % dic)
else:
assert param.transfer_mode is None
arg_helper = find_arg_helper(param)
func_body.start.append(arg_helper.format_arg(param.allow_none, param.default_value,
'arg%(narg)d' % dic, '%(arg_idx)s' % dic, param.name))
def __write_function(self, meth, cls, method_cfuncs):
assert not isinstance(meth, VMethod)
bind = meth.annotations.get('moo.lua', '1')
if bind == '0':
return
elif bind != '1':
raise RuntimeError('invalid value %s for moo.lua annotation' % (bind,))
cfunc = meth.annotations.get('moo.lua.cfunc')
if cfunc:
method_cfuncs.append([meth.name, cfunc])
return
is_constructor = isinstance(meth, Constructor)
static_method = isinstance(meth, StaticMethod)
own_return = is_constructor or (meth.retval and meth.retval.transfer_mode == 'full')
params = []
for i in range(len(meth.params)):
p = meth.params[i]
if not p.type.name in _arg_helpers and not isinstance(p.type, ArrayType) and \
not isinstance(p.type, GTypedType) and not isinstance(p.type, GErrorReturnType) and \
not p.type.name in ('SignalClosure*', 'strv'):
raise RuntimeError("cannot write function %s because of '%s' parameter" % (meth.c_name, p.type.name))
if isinstance(p.type, GErrorReturnType):
assert i == len(meth.params) - 1
assert meth.has_gerror_return
else:
params.append(p)
check_kwargs = ''
has_self = cls and not is_constructor and not static_method
if has_self:
first_arg = 'first_arg'
else:
first_arg = '1'
if meth.kwargs:
check_kwargs = ' bool kwargs = moo_lua_check_kwargs (L, %s);\n' % first_arg
dic = dict(name=meth.name, c_name=meth.c_name, check_kwargs=check_kwargs, first_arg=first_arg)
if has_self:
dic['cfunc'] = 'cfunc_%s_%s' % (cls.name, meth.name)
dic['Class'] = cls.name
dic['current_function'] = '%s.%s' % (cls.name, meth.name)
self.out.write(tmpl_cfunc_method_start % dic)
elif static_method:
dic['cfunc'] = 'cfunc_%s_%s' % (cls.name, meth.name)
dic['Class'] = cls.name
dic['current_function'] = '%s.%s' % (cls.name, meth.name)
self.out.write(tmpl_cfunc_func_start % dic)
elif is_constructor:
dic['cfunc'] = 'cfunc_%s_new' % cls.name
dic['Class'] = cls.name
dic['current_function'] = '%s.new' % cls.name
self.out.write(tmpl_cfunc_func_start % dic)
else:
dic['cfunc'] = 'cfunc_%s' % meth.name
dic['current_function'] = meth.name
self.out.write(tmpl_cfunc_func_start % dic)
method_cfuncs.append([meth.name, dic['cfunc']])
class FuncBody:
def __init__(self):
self.start = []
self.end = []
func_body = FuncBody()
func_call = ''
i = 0
for p in params:
self.__write_function_param(func_body, p, i, meth, None if (is_constructor or static_method) else cls)
i += 1
if meth.has_gerror_return:
func_body.start.append('GError *error = NULL;')
if meth.retval:
dic = {'gtype_id': meth.retval.type.gtype_id,
'make_copy': 'FALSE' if own_return else 'TRUE',
}
if isinstance(meth.retval.type, Class):
func_call = 'gpointer ret = '
push_ret = 'moo_lua_push_object (L, (GObject*) ret, %(make_copy)s);' % dic
elif isinstance(meth.retval.type, Boxed):
func_call = 'gpointer ret = '
push_ret = 'moo_lua_push_boxed (L, ret, %(gtype_id)s, %(make_copy)s);' % dic
elif isinstance(meth.retval.type, Pointer):
func_call = 'gpointer ret = '
push_ret = 'moo_lua_push_pointer (L, ret, %(gtype_id)s, %(make_copy)s);' % dic
elif isinstance(meth.retval.type, Enum) or isinstance(meth.retval.type, Flags):
func_call = '%s ret = ' % meth.retval.type.name
push_ret = 'moo_lua_push_int (L, ret);' % dic
elif isinstance(meth.retval.type, ArrayType):
assert isinstance(meth.retval.type.elm_type, Class)
dic['gtype_id'] = meth.retval.type.elm_type.gtype_id
func_call = 'MooObjectArray *ret = (MooObjectArray*) '
push_ret = 'moo_lua_push_object_array (L, ret, %(make_copy)s);' % dic
elif meth.retval.type.name == 'strv':
assert meth.retval.transfer_mode == 'full'
func_call = 'char **ret = '
push_ret = 'moo_lua_push_strv (L, ret);'
elif meth.retval.type.name in ('char*', 'cstring'):
assert meth.retval.transfer_mode == 'full'
func_call = 'char *ret = '
push_ret = 'moo_lua_push_string (L, ret);'
elif meth.retval.type.name == 'utf8':
assert meth.retval.transfer_mode == 'full'
func_call = 'char *ret = '
push_ret = 'moo_lua_push_utf8 (L, ret);'
elif meth.retval.type.name == 'filename':
assert meth.retval.transfer_mode == 'full'
func_call = 'char *ret = '
push_ret = 'moo_lua_push_filename (L, ret);'
elif meth.retval.type.name in ('const-char*', 'const-cstring'):
assert meth.retval.transfer_mode != 'full'
func_call = 'const char *ret = '
push_ret = 'moo_lua_push_string_copy (L, ret);'
elif meth.retval.type.name == 'const-utf8':
assert meth.retval.transfer_mode != 'full'
func_call = 'const char *ret = '
push_ret = 'moo_lua_push_utf8_copy (L, ret);'
elif meth.retval.type.name == 'const-filename':
assert meth.retval.transfer_mode != 'full'
func_call = 'const char *ret = '
push_ret = 'moo_lua_push_filename_copy (L, ret);'
elif meth.retval.type.name == 'gunichar':
func_call = 'gunichar ret = '
push_ret = 'moo_lua_push_gunichar (L, ret);'
else:
typ, suffix = find_pod_ret_helper(meth.retval.type.name)
dic['suffix'] = suffix
func_call = '%s ret = ' % typ
push_ret = 'moo_lua_push_%(suffix)s (L, ret);' % dic
else:
push_ret = '0;'
if not meth.has_gerror_return:
func_body.end.append('return %s' % push_ret)
else:
func_body.end.append('int ret_lua = %s' % push_ret)
func_body.end.append('ret_lua += moo_lua_push_error (L, error);')
func_body.end.append('return ret_lua;')
func_call += '%s (' % meth.c_name
first_arg = True
if cls and not is_constructor and not static_method:
first_arg = False
func_call += 'self'
for i in range(len(params)):
if not first_arg:
func_call += ', '
first_arg = False
func_call += 'arg%d' % i
if meth.has_gerror_return:
func_call += ', &error'
func_call += ');'
for line in func_body.start:
print >>self.out, ' ' + line
print >>self.out, ' ' + func_call
for line in func_body.end:
print >>self.out, ' ' + line
self.out.write('}\n\n')
# if not cls:
# self.out.write(function_start_template % dic)
# elif isinstance(meth, Constructor):
# dic['class'] = cls.name
# self.out.write(function_start_template % dic)
# self.out.write(' (is-constructor-of %s)\n' % cls.name)
# elif isinstance(meth, VMethod):
# dic['class'] = cls.name
# self.out.write(vmethod_start_template % dic)
# else:
# dic['class'] = cls.name
# self.out.write(method_start_template % dic)
# if meth.retval:
# if meth.retval.transfer_mode == 'full':
# self.out.write(' (caller-owns-return #t)\n')
# elif meth.retval.transfer_mode is not None:
# raise RuntimeError('do not know how to handle transfer mode %s' % (meth.retval.transfer_mode,))
# if meth.params:
# self.out.write(' (parameters\n')
# for p in meth.params:
# self.out.write(' \'("%s" "%s"' % (p.type, p.name))
# if p.allow_none:
# self.out.write(' (null-ok)')
# if p.default_value is not None:
# self.out.write(' (default "%s")' % (p.default_value,))
# self.out.write(')\n')
# self.out.write(' )\n')
# self.out.write(')\n\n')
def __write_gobject_constructor(self, name, cls):
dic = dict(func=name, gtype_id=cls.gtype_id)
self.out.write("""\
static void *%(func)s (void)
{
return g_object_new (%(gtype_id)s, (char*) NULL);
}
""" % dic)
def __write_class(self, cls):
bind = cls.annotations.get('moo.lua', '1')
if bind == '0':
return ([], [])
self.out.write('// methods of %s\n\n' % cls.name)
method_cfuncs = []
static_method_cfuncs = []
for meth in cls.methods:
if not isinstance(meth, VMethod):
self.__write_function(meth, cls, method_cfuncs)
for meth in cls.static_methods:
self.__write_function(meth, cls, static_method_cfuncs)
if cls.constructor:
self.__write_function(cls.constructor, cls, static_method_cfuncs)
# if hasattr(cls, 'constructable') and cls.constructable:
# cons = Constructor()
# cons.retval = Retval()
# cons.retval.type = cls
# cons.retval.transfer_mode = 'full'
# cons.name = 'new'
# cons.c_name = '%s__new__' % cls.name
# self.__write_gobject_constructor(cons.c_name, cls)
# self.__write_function(cons, cls, static_method_cfuncs)
return (method_cfuncs, static_method_cfuncs)
def __write_register_module(self, module, all_method_cfuncs):
self.out.write(tmpl_register_module_start % dict(module=module.name.lower()))
for cls in module.get_classes() + module.get_boxed() + module.get_pointers():
method_cfuncs = all_method_cfuncs[cls.name]
if method_cfuncs:
dic = dict(Class=cls.name, gtype_id=cls.gtype_id)
self.out.write(tmpl_register_one_type_start % dic)
for name, cfunc in method_cfuncs:
self.out.write(' { "%s", %s },\n' % (name, cfunc))
self.out.write(tmpl_register_one_type_end % dic)
self.out.write('}\n\n')
def write(self, module, include_headers):
self.module = module
start_dic = dict(headers='')
if include_headers:
start_dic['headers'] = '\n' + '\n'.join(['#include "%s"' % h for h in include_headers]) + '\n'
self.out.write(tmpl_file_start % start_dic)
all_method_cfuncs = {}
all_static_method_cfuncs = {}
for cls in module.get_classes() + module.get_boxed() + module.get_pointers():
method_cfuncs, static_method_cfuncs = self.__write_class(cls)
all_method_cfuncs[cls.name] = method_cfuncs
all_static_method_cfuncs[cls.short_name] = static_method_cfuncs
package_name=module.name.lower()
dic = dict(module=module.name.lower(), package_name=package_name)
all_func_cfuncs = []
# for cls in module.get_classes() + module.get_boxed() + module.get_pointers():
# if cls.constructor:
# self.__write_function(cls.constructor, cls, all_func_cfuncs)
for func in module.get_functions():
self.__write_function(func, None, all_func_cfuncs)
self.out.write('static const luaL_Reg %(module)s_lua_functions[] = {\n' % dic)
for name, cfunc in all_func_cfuncs:
self.out.write(' { "%s", %s },\n' % (name, cfunc))
self.out.write(' { NULL, NULL }\n')
self.out.write('};\n\n')
for cls_name in all_static_method_cfuncs:
cfuncs = all_static_method_cfuncs[cls_name]
if not cfuncs:
continue
self.out.write('static const luaL_Reg %s_lua_functions[] = {\n' % cls_name)
for name, cfunc in cfuncs:
self.out.write(' { "%s", %s },\n' % (name, cfunc))
self.out.write(' { NULL, NULL }\n')
self.out.write('};\n\n')
self.__write_register_module(module, all_method_cfuncs)
self.out.write("""\
void %(module)s_lua_api_add_to_lua (lua_State *L)
{
%(module)s_lua_api_register ();
luaL_register (L, "%(package_name)s", %(module)s_lua_functions);
""" % dic)
for cls_name in all_static_method_cfuncs:
cfuncs = all_static_method_cfuncs[cls_name]
if not cfuncs:
continue
self.out.write(' moo_lua_register_static_methods (L, "%s", "%s", %s_lua_functions);\n' % (package_name, cls_name, cls_name))
self.out.write('\n')
for enum in module.get_enums():
self.out.write(' moo_lua_register_enum (L, "%s", %s, "%s");\n' % (package_name, enum.gtype_id, module.name.upper() + '_'))
self.out.write("}\n")
del self.module

553
api/mpi/module.py Normal file
View File

@ -0,0 +1,553 @@
import re
import sys
import xml.etree.ElementTree as _etree
class Doc(object):
def __init__(self, text):
object.__init__(self)
self.text = text
@staticmethod
def from_xml(elm):
return Doc(elm.text)
def _set_unique_attribute(obj, attr, value):
if getattr(obj, attr) is not None:
raise RuntimeError("duplicated attribute '%s'" % (attr,))
setattr(obj, attr, value)
def _set_unique_attribute_bool(obj, attr, value):
if value.lower() in ('0', 'false', 'no'):
value = False
elif value.lower() in ('1', 'true', 'yes'):
value = True
else:
raise RuntimeError("bad value '%s' for boolean attribute '%s'" % (value, attr))
_set_unique_attribute(obj, attr, value)
class _XmlObject(object):
def __init__(self):
object.__init__(self)
self.doc = None
self.summary = None
self.annotations = {}
self.module = None
@classmethod
def from_xml(cls, module, elm, *args):
obj = cls()
obj.module = module
obj._parse_xml(module, elm, *args)
return obj
def _parse_xml_element(self, module, elm):
if elm.tag in ('doc', 'summary'):
_set_unique_attribute(self, elm.tag, Doc.from_xml(elm))
else:
raise RuntimeError('unknown element %s' % (elm.tag,))
def _parse_attribute(self, attr, value):
if attr.find('.') >= 0:
self.annotations[attr] = value
return True
else:
return False
def _parse_xml(self, module, elm, *args):
for attr, value in elm.items():
if not self._parse_attribute(attr, value):
raise RuntimeError('unknown attribute %s' % (attr,))
for child in elm.getchildren():
self._parse_xml_element(module, child)
class _ParamBase(_XmlObject):
def __init__(self):
_XmlObject.__init__(self)
self.type = None
self.transfer_mode = None
def _parse_attribute(self, attr, value):
if attr in ('type', 'transfer_mode'):
_set_unique_attribute(self, attr, value)
else:
return _XmlObject._parse_attribute(self, attr, value)
return True
class Param(_ParamBase):
def __init__(self):
_ParamBase.__init__(self)
self.name = None
self.default_value = None
self.allow_none = None
def _parse_attribute(self, attr, value):
if attr in ('default_value', 'name'):
_set_unique_attribute(self, attr, value)
elif attr in ('allow_none',):
_set_unique_attribute_bool(self, attr, value)
else:
return _ParamBase._parse_attribute(self, attr, value)
return True
class Retval(_ParamBase):
def __init__(self):
_ParamBase.__init__(self)
class FunctionBase(_XmlObject):
def __init__(self):
_XmlObject.__init__(self)
self.name = None
self.c_name = None
self.retval = None
self.params = []
self.has_gerror_return = False
self.kwargs = None
def _parse_attribute(self, attr, value):
if attr in ('c_name', 'name'):
_set_unique_attribute(self, attr, value)
elif attr in ('kwargs',):
_set_unique_attribute_bool(self, attr, value)
else:
return _XmlObject._parse_attribute(self, attr, value)
return True
def _parse_xml_element(self, module, elm):
if elm.tag == 'retval':
_set_unique_attribute(self, 'retval', Retval.from_xml(module, elm))
elif elm.tag == 'param':
self.params.append(Param.from_xml(module, elm))
else:
_XmlObject._parse_xml_element(self, module, elm)
def _parse_xml(self, module, elm, *args):
_XmlObject._parse_xml(self, module, elm, *args)
if not self.name:
raise RuntimeError('function name missing')
if not self.c_name:
raise RuntimeError('function c_name missing')
class Function(FunctionBase):
def __init__(self):
FunctionBase.__init__(self)
def symbol_id(self):
return self.c_name
class MethodBase(FunctionBase):
def __init__(self):
super(MethodBase, self).__init__()
def _parse_xml(self, module, elm, cls):
super(MethodBase, self)._parse_xml(module, elm, cls)
self.cls = cls
class Constructor(MethodBase):
def __init__(self):
super(Constructor, self).__init__()
def symbol_id(self):
return self.c_name
class StaticMethod(MethodBase):
def __init__(self):
super(StaticMethod, self).__init__()
def symbol_id(self):
return self.c_name
class Method(MethodBase):
def __init__(self):
super(Method, self).__init__()
def symbol_id(self):
return self.c_name
class VMethod(MethodBase):
def __init__(self):
super(VMethod, self).__init__()
self.c_name = "fake"
def symbol_id(self):
return '%s::%s' % (self.cls.name, self.name)
class Signal(MethodBase):
def __init__(self):
super(Signal, self).__init__()
self.c_name = "fake"
def symbol_id(self):
return 'signal:%s:%s' % (self.cls.name, self.name)
class Type(_XmlObject):
def __init__(self):
_XmlObject.__init__(self)
self.name = None
self.c_name = None
self.gtype_id = None
def symbol_id(self):
return self.name
class BasicType(Type):
def __init__(self, name):
Type.__init__(self)
self.name = name
class ArrayType(Type):
def __init__(self, elm_type):
Type.__init__(self)
self.elm_type = elm_type
self.name = '%sArray*' % elm_type.name
self.c_name = '%sArray*' % elm_type.name
class GErrorReturnType(Type):
def __init__(self):
Type.__init__(self)
self.name = 'GError**'
class GTypedType(Type):
def __init__(self):
Type.__init__(self)
self.short_name = None
def _parse_attribute(self, attr, value):
if attr in ('short_name', 'name', 'gtype_id'):
_set_unique_attribute(self, attr, value)
else:
return Type._parse_attribute(self, attr, value)
return True
def _parse_xml(self, module, elm, *args):
Type._parse_xml(self, module, elm, *args)
if self.name is None:
raise RuntimeError('class name missing')
if self.short_name is None:
raise RuntimeError('class short name missing')
if self.gtype_id is None:
raise RuntimeError('class gtype missing')
class EnumValue(_XmlObject):
def __init__(self):
super(EnumValue, self).__init__()
self.name = None
self.short_name = None
self.enum = None
def symbol_id(self):
return self.name
def _parse_attribute(self, attr, value):
if attr in ('name'):
_set_unique_attribute(self, attr, value)
else:
return super(EnumValue, self)._parse_attribute(attr, value)
return True
def _parse_xml(self, module, elm, *args):
super(EnumValue, self)._parse_xml(module, elm, *args)
if self.name is None:
raise RuntimeError('enum value name missing')
if not self.short_name:
self.short_name = self.name
prefix = module.name.upper() + '_'
if self.short_name.startswith(prefix):
self.short_name = self.short_name[len(prefix):]
class EnumBase(GTypedType):
def __init__(self):
super(EnumBase, self).__init__()
self.values = []
self.__value_hash = {}
def _parse_xml_element(self, module, elm):
if elm.tag == 'value':
value = EnumValue.from_xml(module, elm)
assert not value.name in self.__value_hash
self.__value_hash[value.name] = value
value.enum = self
self.values.append(value)
else:
super(EnumBase, self)._parse_xml_element(module, elm)
class Enum(EnumBase):
def __init__(self):
super(Enum, self).__init__()
class Flags(EnumBase):
def __init__(self):
super(Flags, self).__init__()
class InstanceType(GTypedType):
def __init__(self):
GTypedType.__init__(self)
self.constructor = None
self.methods = []
self.static_methods = []
self.__method_hash = {}
def _parse_xml_element(self, module, elm):
if elm.tag == 'method':
meth = Method.from_xml(module, elm, self)
assert not meth.name in self.__method_hash
self.__method_hash[meth.name] = meth
self.methods.append(meth)
elif elm.tag == 'static-method':
meth = StaticMethod.from_xml(module, elm, self)
assert not meth.name in self.__method_hash
self.__method_hash[meth.name] = meth
self.static_methods.append(meth)
elif elm.tag == 'constructor':
assert not self.constructor
self.constructor = Constructor.from_xml(module, elm, self)
else:
GTypedType._parse_xml_element(self, module, elm)
class Pointer(InstanceType):
def __init__(self):
InstanceType.__init__(self)
class Boxed(InstanceType):
def __init__(self):
InstanceType.__init__(self)
class Class(InstanceType):
def __init__(self):
InstanceType.__init__(self)
self.parent = None
self.vmethods = []
self.signals = []
self.constructable = None
self.__vmethod_hash = {}
self.__signal_hash = {}
def _parse_attribute(self, attr, value):
if attr in ('parent'):
_set_unique_attribute(self, attr, value)
elif attr in ('constructable'):
_set_unique_attribute_bool(self, attr, value)
else:
return InstanceType._parse_attribute(self, attr, value)
return True
def _parse_xml_element(self, module, elm):
if elm.tag == 'virtual':
meth = VMethod.from_xml(module, elm, self)
assert not meth.name in self.__vmethod_hash
self.__vmethod_hash[meth.name] = meth
self.vmethods.append(meth)
elif elm.tag == 'signal':
meth = Signal.from_xml(module, elm, self)
assert not meth.name in self.__signal_hash
self.__signal_hash[meth.name] = meth
self.signals.append(meth)
else:
InstanceType._parse_xml_element(self, module, elm)
def _parse_xml(self, module, elm, *args):
InstanceType._parse_xml(self, module, elm, *args)
if self.parent is None:
raise RuntimeError('class parent name missing')
if self.constructable and self.constructor:
raise RuntimeError('both constructor and constructable attributes present')
class Module(object):
def __init__(self):
object.__init__(self)
self.name = None
self.__classes = []
self.__boxed = []
self.__pointers = []
self.__enums = []
self.__class_hash = {}
self.__functions = []
self.__function_hash = {}
self.__import_modules = []
self.__parsing_done = False
self.__types = {}
self.__symbols = {}
def __add_type(self, typ):
if typ.name in self.__class_hash:
raise RuntimeError('duplicated type %s' % typ.name)
self.__class_hash[typ.name] = typ
def __finish_type(self, typ):
if isinstance(typ, Type):
return typ
if typ in self.__types:
return self.__types[typ]
if typ == 'GError**':
return GErrorReturnType()
m = re.match(r'(const-)?([\w\d_]+)\*', typ)
if m:
name = m.group(2)
if name in self.__types:
obj_type = self.__types[name]
if isinstance(obj_type, InstanceType):
return obj_type
m = re.match(r'Array<([\w\d_]+)>\*', typ)
if m:
elm_type = self.__finish_type(m.group(1))
return ArrayType(elm_type)
m = re.match(r'([\w\d_]+)Array\*', typ)
if m:
elm_type = self.__finish_type(m.group(1))
return ArrayType(elm_type)
return BasicType(typ)
def __finish_parsing_method(self, meth, typ):
sym_id = meth.symbol_id()
if self.__symbols.get(sym_id):
raise RuntimeError('duplicate symbol %s' % sym_id)
self.__symbols[sym_id] = meth
for p in meth.params:
p.type = self.__finish_type(p.type)
if meth.retval:
meth.retval.type = self.__finish_type(meth.retval.type)
meth.has_gerror_return = False
if meth.params and isinstance(meth.params[-1].type, GErrorReturnType):
meth.has_gerror_return = True
if meth.kwargs:
params = list(meth.params)
pos_args = []
kw_args = []
if meth.has_gerror_return:
params = params[:-1]
seen_kwarg = False
for p in params:
if p.default_value is not None:
seen_kwarg = True
elif seen_kwarg:
raise RuntimeError('in %s: parameter without a default value follows a kwarg one' % sym_id)
if p.default_value is not None:
kw_args.append(p)
else:
pos_args.append(p)
def __finish_parsing_type(self, typ):
if hasattr(typ, 'constructor') and typ.constructor is not None:
self.__finish_parsing_method(typ.constructor, typ)
for meth in typ.static_methods:
self.__finish_parsing_method(meth, typ)
for meth in typ.methods:
self.__finish_parsing_method(meth, typ)
if hasattr(typ, 'vmethods'):
for meth in typ.vmethods:
self.__finish_parsing_method(meth, typ)
if hasattr(typ, 'signals'):
for meth in typ.signals:
self.__finish_parsing_method(meth, typ)
def __finish_parsing_enum(self, typ):
for v in typ.values:
sym_id = v.symbol_id()
if self.__symbols.get(sym_id):
raise RuntimeError('duplicate symbol %s' % sym_id)
self.__symbols[sym_id] = v
def __add_type_symbol(self, typ):
sym_id = typ.symbol_id()
if self.__symbols.get(sym_id):
raise RuntimeError('duplicate symbol %s' % sym_id)
self.__symbols[sym_id] = typ
def __finish_parsing(self):
if self.__parsing_done:
return
for typ in self.__classes + self.__boxed + self.__pointers + self.__enums:
self.__add_type_symbol(typ)
self.__types[typ.name] = typ
for module in self.__import_modules:
for typ in module.get_classes() + module.get_boxed() + \
module.get_pointers() + module.get_enums():
self.__types[typ.name] = typ
for sym in module.__symbols:
if self.__symbols.get(sym):
raise RuntimeError('duplicate symbol %s' % sym)
self.__symbols[sym] = module.__symbols[sym]
for typ in self.__classes + self.__boxed + self.__pointers:
self.__finish_parsing_type(typ)
for typ in self.__enums:
self.__finish_parsing_enum(typ)
for func in self.__functions:
self.__finish_parsing_method(func, None)
self.__parsing_done = True
def get_classes(self):
self.__finish_parsing()
return list(self.__classes)
def get_boxed(self):
self.__finish_parsing()
return list(self.__boxed)
def get_pointers(self):
self.__finish_parsing()
return list(self.__pointers)
def get_enums(self):
self.__finish_parsing()
return list(self.__enums)
def get_functions(self):
self.__finish_parsing()
return list(self.__functions)
def get_symbols(self):
self.__finish_parsing()
return dict(self.__symbols)
def __parse_module_entry(self, elm):
if elm.tag == 'class':
cls = Class.from_xml(self, elm)
self.__add_type(cls)
self.__classes.append(cls)
elif elm.tag == 'boxed':
cls = Boxed.from_xml(self, elm)
self.__add_type(cls)
self.__boxed.append(cls)
elif elm.tag == 'pointer':
cls = Pointer.from_xml(self, elm)
self.__add_type(cls)
self.__pointers.append(cls)
elif elm.tag == 'enum':
enum = Enum.from_xml(self, elm)
self.__add_type(enum)
self.__enums.append(enum)
elif elm.tag == 'flags':
enum = Flags.from_xml(self, elm)
self.__add_type(enum)
self.__enums.append(enum)
elif elm.tag == 'function':
func = Function.from_xml(self, elm)
assert not func.name in self.__function_hash
self.__function_hash[func.name] = func
self.__functions.append(func)
else:
raise RuntimeError('unknown element %s' % (elm.tag,))
def import_module(self, mod):
self.__import_modules.append(mod)
@staticmethod
def from_xml(filename):
mod = Module()
xml = _etree.ElementTree()
xml.parse(filename)
root = xml.getroot()
assert root.tag == 'module'
mod.name = root.get('name')
assert mod.name is not None
for elm in root.getchildren():
mod.__parse_module_entry(elm)
return mod

12
api/mpi/util.py Normal file
View File

@ -0,0 +1,12 @@
import sys
__all__ = [ 'implement_me', 'oops', 'warning' ]
def implement_me(what):
print >> sys.stderr, 'implement me: %s' % what
def oops(message=None):
raise RuntimeError(message)
def warning(message):
print >>sys.stderr, "WARNING:", message

65
api/parsedocs.py Normal file
View File

@ -0,0 +1,65 @@
#! /usr/bin/env python
import os
import re
import sys
import optparse
import fnmatch
import filecmp
from mdp.docparser import Parser
from mdp.module import Module
import mdp.xmlwriter
def read_files(files, opts):
p = Parser()
p.read_files(files)
mod = Module('Moo' if not opts.module else opts.module)
mod.init_from_dox(p.classes + p.enums + p.functions + p.vmethods + p.signals)
return mod
def parse_args():
op = optparse.OptionParser()
op.add_option("--source-dir", dest="source_dirs", action="append",
help="parse source files from DIR", metavar="DIR")
op.add_option("--source-file", dest="source_files", action="append",
help="parse source file FILE", metavar="FILE")
op.add_option("--skip", dest="skip_globs", action="append",
help="skip files which match pattern PAT", metavar="PAT")
op.add_option("--output", dest="output", action="store",
help="write result to FILE", metavar="FILE")
op.add_option("--module", dest="module", action="store",
help="generate module MOD", metavar="MOD")
(opts, args) = op.parse_args()
if args:
op.error("too many arguments")
source_files = []
if opts.source_files:
source_files += [os.path.abspath(f) for f in opts.source_files]
skip_pat = None
if opts.skip_globs:
skip_pat = re.compile('|'.join([fnmatch.translate(g) for g in opts.skip_globs]))
if opts.source_dirs:
for source_dir in opts.source_dirs:
for root, dirs, files in os.walk(source_dir):
for f in files:
if f.endswith('.c') or f.endswith('.cpp') or f.endswith('.h'):
if skip_pat is None or not skip_pat.match(f):
source_files.append(os.path.join(root, f))
if not source_files:
op.error("no input files")
return opts, source_files
opts, files = parse_args()
mod = read_files(files, opts)
tmp_file = opts.output + '.tmp'
with open(tmp_file, 'w') as out:
mdp.xmlwriter.write_xml(mod, out)
if not os.path.exists(opts.output):
os.rename(tmp_file, opts.output)
elif filecmp.cmp(tmp_file, opts.output):
os.remove(tmp_file)
else:
os.remove(opts.output)
os.rename(tmp_file, opts.output)

286
api/sourcefiles.mak Normal file
View File

@ -0,0 +1,286 @@
source_files = \
../moo/moolua/medit-lua.h\
../moo/moolua/medit-lua.cpp\
../moo/mooapp/mooappabout.cpp\
../moo/mooapp/mooappabout.h\
../moo/mooapp/mooapp-accels.h\
../moo/mooapp/mooapp.cpp\
../moo/mooapp/mooapp.h\
../moo/mooapp/mooapp-info.h\
../moo/mooapp/mooapp-private.h\
../moo/mooapp/moohtml.cpp\
../moo/mooapp/moohtml.h\
../moo/mooapp/moolinklabel.cpp\
../moo/mooapp/moolinklabel.h\
../moo/mooedit/mooedit-accels.h\
../moo/mooedit/mooeditaction.cpp\
../moo/mooedit/mooeditaction-factory.cpp\
../moo/mooedit/mooeditaction-factory.h\
../moo/mooedit/mooeditaction.h\
../moo/mooedit/mooeditbookmark.cpp\
../moo/mooedit/mooeditbookmark.h\
../moo/mooedit/mooedit.cpp\
../moo/mooedit/mooeditconfig.cpp\
../moo/mooedit/mooeditconfig.h\
../moo/mooedit/mooeditdialogs.cpp\
../moo/mooedit/mooeditdialogs.h\
../moo/mooedit/mooedit-enum-types.c\
../moo/mooedit/mooedit-enum-types.h\
../moo/mooedit/mooedit-enums.h\
../moo/mooedit/mooeditfileinfo.cpp\
../moo/mooedit/mooeditfileinfo.h\
../moo/mooedit/mooedit-fileops.cpp\
../moo/mooedit/mooedit-fileops.h\
../moo/mooedit/mooeditfiltersettings.cpp\
../moo/mooedit/mooeditfiltersettings.h\
../moo/mooedit/mooedit.h\
../moo/mooedit/mooedithistoryitem.cpp\
../moo/mooedit/mooedithistoryitem.h\
../moo/mooedit/mooedit-impl.h\
../moo/mooedit/mooeditor.cpp\
../moo/mooedit/mooeditor.h\
../moo/mooedit/mooeditor-impl.h\
../moo/mooedit/mooeditor-private.h\
../moo/mooedit/mooeditor-tests.cpp\
../moo/mooedit/mooeditor-tests.h\
../moo/mooedit/mooeditprefs.cpp\
../moo/mooedit/mooeditprefs.h\
../moo/mooedit/mooeditprefspage.cpp\
../moo/mooedit/mooedit-private.h\
../moo/mooedit/mooedit-script.cpp\
../moo/mooedit/mooedit-script.h\
../moo/mooedit/mooedittab.cpp\
../moo/mooedit/mooedittab.h\
../moo/mooedit/mooedittypes.h\
../moo/mooedit/mooeditview.cpp\
../moo/mooedit/mooeditview.h\
../moo/mooedit/mooeditview-script.cpp\
../moo/mooedit/mooeditview-script.h\
../moo/mooedit/mooeditwindow.cpp\
../moo/mooedit/mooeditwindow.h\
../moo/mooedit/mooeditwindow-impl.h\
../moo/mooedit/moofold.cpp\
../moo/mooedit/moofold.h\
../moo/mooedit/mooindenter.cpp\
../moo/mooedit/mooindenter.h\
../moo/mooedit/moolang.cpp\
../moo/mooedit/moolang.h\
../moo/mooedit/moolangmgr.cpp\
../moo/mooedit/moolangmgr.h\
../moo/mooedit/moolangmgr-private.h\
../moo/mooedit/moolang-private.h\
../moo/mooedit/moolinebuffer.c\
../moo/mooedit/moolinebuffer.h\
../moo/mooedit/moolinemark.c\
../moo/mooedit/moolinemark.h\
../moo/mooedit/mooplugin.c\
../moo/mooedit/mooplugin.h\
../moo/mooedit/mooplugin-loader.c\
../moo/mooedit/mooplugin-loader.h\
../moo/mooedit/mooplugin-macro.h\
../moo/mooedit/mootextbtree.c\
../moo/mooedit/mootextbtree.h\
../moo/mooedit/mootextbuffer.c\
../moo/mooedit/mootextfind.c\
../moo/mooedit/mootextfind.h\
../moo/mooedit/mootextiter.h\
../moo/mooedit/mootextprint.c\
../moo/mooedit/mootextprint.h\
../moo/mooedit/mootextprint-private.h\
../moo/mooedit/mootext-private.h\
../moo/mooedit/mootextsearch.c\
../moo/mooedit/mootextsearch.h\
../moo/mooedit/mootextsearch-private.h\
../moo/mooedit/mootextstylescheme.c\
../moo/mooedit/mootextstylescheme.h\
../moo/mooedit/mootextview.c\
../moo/mooedit/mootextview.h\
../moo/mooedit/mootextview-input.c\
../moo/mooedit/mootextview-private.h\
../moo/moofileview/moobookmarkmgr.c\
../moo/moofileview/moobookmarkmgr.h\
../moo/moofileview/moobookmarkview.c\
../moo/moofileview/moobookmarkview.h\
../moo/moofileview/moofile.c\
../moo/moofileview/moofileentry.c\
../moo/moofileview/moofileentry.h\
../moo/moofileview/moofile.h\
../moo/moofileview/moofile-private.h\
../moo/moofileview/moofilesystem.c\
../moo/moofileview/moofilesystem.h\
../moo/moofileview/moofileview-accels.h\
../moo/moofileview/moofileview-aux.h\
../moo/moofileview/moofileview.c\
../moo/moofileview/moofileview-dialogs.c\
../moo/moofileview/moofileview-dialogs.h\
../moo/moofileview/moofileview.h\
../moo/moofileview/moofileview-impl.h\
../moo/moofileview/moofileview-private.h\
../moo/moofileview/moofileview-tools.c\
../moo/moofileview/moofileview-tools.h\
../moo/moofileview/moofolder.c\
../moo/moofileview/moofolder.h\
../moo/moofileview/moofoldermodel.c\
../moo/moofileview/moofoldermodel.h\
../moo/moofileview/moofoldermodel-private.h\
../moo/moofileview/moofolder-private.h\
../moo/moofileview/mooiconview.c\
../moo/moofileview/mooiconview.h\
../moo/moofileview/mootreeview.c\
../moo/moofileview/mootreeview.h\
../moo/mooutils/mooaccelbutton.c\
../moo/mooutils/mooaccelbutton.h\
../moo/mooutils/mooaccel.cpp\
../moo/mooutils/mooaccel.h\
../moo/mooutils/mooaccelprefs.c\
../moo/mooutils/mooaccelprefs.h\
../moo/mooutils/mooactionbase.c\
../moo/mooutils/mooactionbase.h\
../moo/mooutils/mooactionbase-private.h\
../moo/mooutils/mooaction.c\
../moo/mooutils/mooactioncollection.c\
../moo/mooutils/mooactioncollection.h\
../moo/mooutils/mooactionfactory.c\
../moo/mooutils/mooactionfactory.h\
../moo/mooutils/mooactiongroup.c\
../moo/mooutils/mooactiongroup.h\
../moo/mooutils/mooaction.h\
../moo/mooutils/mooaction-private.h\
../moo/mooutils/mooappinput-common.c\
../moo/mooutils/mooappinput.h\
../moo/mooutils/mooapp-ipc.c\
../moo/mooutils/mooapp-ipc.h\
../moo/mooutils/mooarray.h\
../moo/mooutils/mooatom.h\
../moo/mooutils/moobigpaned.c\
../moo/mooutils/moobigpaned.h\
../moo/mooutils/mooclosure.c\
../moo/mooutils/mooclosure.h\
../moo/mooutils/moocombo.c\
../moo/mooutils/moocombo.h\
../moo/mooutils/moocompat.h\
../moo/mooutils/moodialogs.c\
../moo/mooutils/moodialogs.h\
../moo/mooutils/mooeditops.c\
../moo/mooutils/mooeditops.h\
../moo/mooutils/mooencodings.c\
../moo/mooutils/mooencodings-data.h\
../moo/mooutils/mooencodings.h\
../moo/mooutils/mooentry.cpp\
../moo/mooutils/mooentry.h\
../moo/mooutils/moo-environ.h\
../moo/mooutils/moofiledialog.c\
../moo/mooutils/moofiledialog.h\
../moo/mooutils/moofileicon.c\
../moo/mooutils/moofileicon.h\
../moo/mooutils/moofilewatch.c\
../moo/mooutils/moofilewatch.h\
../moo/mooutils/moofilewriter.cpp\
../moo/mooutils/moofilewriter.h\
../moo/mooutils/moofilewriter-private.h\
../moo/mooutils/moofiltermgr.c\
../moo/mooutils/moofiltermgr.h\
../moo/mooutils/moofontsel.c\
../moo/mooutils/moofontsel.h\
../moo/mooutils/mooglade.c\
../moo/mooutils/mooglade.h\
../moo/mooutils/moohelp.c\
../moo/mooutils/moohelp.h\
../moo/mooutils/moohistorycombo.c\
../moo/mooutils/moohistorycombo.h\
../moo/mooutils/moohistorylist.c\
../moo/mooutils/moohistorylist.h\
../moo/mooutils/moohistorymgr.c\
../moo/mooutils/moohistorymgr.h\
../moo/mooutils/mooi18n.cpp\
../moo/mooutils/mooi18n.h\
../moo/mooutils/moolist.h\
../moo/mooutils/moomarkup.c\
../moo/mooutils/moomarkup.h\
../moo/mooutils/moomenuaction.c\
../moo/mooutils/moomenuaction.h\
../moo/mooutils/moomenu.c\
../moo/mooutils/moomenu.h\
../moo/mooutils/moomenumgr.c\
../moo/mooutils/moomenumgr.h\
../moo/mooutils/moomenutoolbutton.c\
../moo/mooutils/moomenutoolbutton.h\
../moo/mooutils/moo-mime.c\
../moo/mooutils/moo-mime.h\
../moo/mooutils/moonotebook.c\
../moo/mooutils/moonotebook.h\
../moo/mooutils/mooonce.h\
../moo/mooutils/moopane.c\
../moo/mooutils/moopaned.c\
../moo/mooutils/moopaned.h\
../moo/mooutils/moopane.h\
../moo/mooutils/mooprefs.c\
../moo/mooutils/mooprefsdialog.c\
../moo/mooutils/mooprefsdialog.h\
../moo/mooutils/mooprefs.h\
../moo/mooutils/mooprefspage.c\
../moo/mooutils/mooprefspage.h\
../moo/mooutils/moospawn.c\
../moo/mooutils/moospawn.h\
../moo/mooutils/moostock.c\
../moo/mooutils/moostock.h\
../moo/mooutils/moo-test-macros.h\
../moo/mooutils/moo-test-utils.cpp\
../moo/mooutils/moo-test-utils.h\
../moo/mooutils/mootypedecl-macros.h\
../moo/mooutils/mootype-macros.h\
../moo/mooutils/moouixml.c\
../moo/mooutils/moouixml.h\
../moo/mooutils/mooundo.c\
../moo/mooutils/mooundo.h\
../moo/mooutils/mooutils-debug.h\
../moo/mooutils/mooutils-enums.c\
../moo/mooutils/mooutils-enums.h\
../moo/mooutils/mooutils-file.c\
../moo/mooutils/mooutils-file.h\
../moo/mooutils/mooutils-fs.cpp\
../moo/mooutils/mooutils-fs.h\
../moo/mooutils/mooutils-gobject.cpp\
../moo/mooutils/mooutils-gobject.h\
../moo/mooutils/mooutils-gobject-private.h\
../moo/mooutils/mooutils.h\
../moo/mooutils/mooutils-macros.h\
../moo/mooutils/mooutils-mem.h\
../moo/mooutils/mooutils-messages.h\
../moo/mooutils/mooutils-misc.cpp\
../moo/mooutils/mooutils-misc.h\
../moo/mooutils/mooutils-script.c\
../moo/mooutils/mooutils-script.h\
../moo/mooutils/mooutils-tests.h\
../moo/mooutils/mooutils-thread.cpp\
../moo/mooutils/mooutils-thread.h\
../moo/mooutils/mooutils-treeview.c\
../moo/mooutils/mooutils-treeview.h\
../moo/mooutils/mooutils-win32.cpp\
../moo/mooutils/moowin32/mingw/fnmatch.h\
../moo/mooutils/moowin32/mingw/netinet/in.h\
../moo/mooutils/moowin32/ms/sys/time.h\
../moo/mooutils/moowin32/ms/unistd.h\
../moo/mooutils/moowindow.c\
../moo/mooutils/moowindow.h\
../moo/plugins/support/moocmdview.cpp\
../moo/plugins/support/moocmdview.h\
../moo/plugins/support/mooeditwindowoutput.cpp\
../moo/plugins/support/mooeditwindowoutput.h\
../moo/plugins/support/moolineview.cpp\
../moo/plugins/support/moolineview.h\
../moo/plugins/support/moooutputfilter.cpp\
../moo/plugins/support/moooutputfilter.h\
../moo/plugins/usertools/moocommand.cpp\
../moo/plugins/usertools/moocommanddisplay.cpp\
../moo/plugins/usertools/moocommanddisplay.h\
../moo/plugins/usertools/moocommand.h\
../moo/plugins/usertools/moocommand-private.h\
../moo/plugins/usertools/moooutputfilterregex.cpp\
../moo/plugins/usertools/moooutputfilterregex.h\
../moo/plugins/usertools/moousertools.cpp\
../moo/plugins/usertools/moousertools-enums.cpp\
../moo/plugins/usertools/moousertools-enums.h\
../moo/plugins/usertools/moousertools.h\
../moo/plugins/usertools/moousertools-prefs.cpp\
../moo/plugins/usertools/moousertools-prefs.h

39
autogen.sh Executable file
View File

@ -0,0 +1,39 @@
#!/bin/sh
[ -z "$ACLOCAL" ] && ACLOCAL=aclocal
[ -z "$AUTOCONF" ] && AUTOCONF=autoconf
[ -z "$AUTOHEADER" ] && AUTOHEADER=autoheader
[ -z "$AUTOMAKE" ] && AUTOMAKE=automake
[ -z "$LIBTOOLIZE" ] && LIBTOOLIZE=libtoolize
workingdir=`pwd`
rel_srcdir=`dirname "$0"`
srcdir=`cd "$rel_srcdir" && pwd`
cd "$srcdir"
run_cmd() {
echo "$@"
"$@" || exit $!
}
run_cmd $LIBTOOLIZE --copy --force
run_cmd $ACLOCAL --force -I m4 $ACLOCAL_FLAGS
run_cmd $AUTOCONF --force
run_cmd $AUTOHEADER --force
run_cmd $AUTOMAKE --add-missing --copy --force-missing
cd $workingdir
run_configure=true
configure_args="--enable-dev-mode"
if [ "$1" ]; then
:
else
echo "Done. Run '$rel_srcdir/configure --enable-dev-mode' to configure and then 'make' to build"
run_configure=false
fi
if $run_configure; then
run_cmd $rel_srcdir/configure $configure_args "$@"
fi

22
checkle.py Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env python
import os
import sys
import subprocess
files = subprocess.Popen(['hg', 'log', '-r', 'tip', '--template', '{files}'],
stdout=subprocess.PIPE).communicate()[0].split()
status = 0
for name in files:
if not os.path.exists(name) or name.startswith('medit/data') or \
name.endswith('.icns') or name.endswith('.png'):
continue
f = open(name, 'rb')
if '\r' in f.read():
print >> sys.stderr, "%s contains \\r character" % (name,)
status = 1
f.close()
sys.exit(status)

View File

@ -0,0 +1,222 @@
# Function for setting up precompiled headers. Usage:
#
# add_library/executable(target
# pchheader.c pchheader.cpp pchheader.h)
#
# add_precompiled_header(target pchheader.h
# [FORCEINCLUDE]
# [SOURCE_C pchheader.c]
# [SOURCE_CXX pchheader.cpp])
#
# Options:
#
# FORCEINCLUDE: Add compiler flags to automatically include the
# pchheader.h from every source file. Works with both GCC and
# MSVC. This is recommended.
#
# SOURCE_C/CXX: Specifies the .c/.cpp source file that includes
# pchheader.h for generating the pre-compiled header
# output. Defaults to pchheader.c. Only required for MSVC.
#
# Caveats:
#
# * Its not currently possible to use the same precompiled-header in
# more than a single target in the same directory (No way to set
# the source file properties differently for each target).
#
# * MSVC: A source file with the same name as the header must exist
# and be included in the target (E.g. header.cpp). Name of file
# can be changed using the SOURCE_CXX/SOURCE_C options.
#
# License:
#
# Copyright (C) 2009-2013 Lars Christensen <larsch@belunktum.dk>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the 'Software') deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
include(CMakeParseArguments)
macro(combine_arguments _variable)
set(_result "")
foreach(_element ${${_variable}})
set(_result "${_result} \"${_element}\"")
endforeach()
string(STRIP "${_result}" _result)
set(${_variable} "${_result}")
endmacro()
function(export_all_flags _filename)
set(_include_directories "$<TARGET_PROPERTY:${_target},INCLUDE_DIRECTORIES>")
set(_compile_definitions "$<TARGET_PROPERTY:${_target},COMPILE_DEFINITIONS>")
set(_compile_flags "$<TARGET_PROPERTY:${_target},COMPILE_FLAGS>")
set(_compile_options "$<TARGET_PROPERTY:${_target},COMPILE_OPTIONS>")
set(_include_directories "$<$<BOOL:${_include_directories}>:-I$<JOIN:${_include_directories},\n-I>\n>")
set(_compile_definitions "$<$<BOOL:${_compile_definitions}>:-D$<JOIN:${_compile_definitions},\n-D>\n>")
set(_compile_flags "$<$<BOOL:${_compile_flags}>:$<JOIN:${_compile_flags},\n>\n>")
set(_compile_options "$<$<BOOL:${_compile_options}>:$<JOIN:${_compile_options},\n>\n>")
file(GENERATE OUTPUT "${_filename}" CONTENT "${_compile_definitions}${_include_directories}${_compile_flags}${_compile_options}\n")
endfunction()
function(add_precompiled_header _target _input)
cmake_parse_arguments(_PCH "FORCEINCLUDE" "SOURCE_CXX:SOURCE_C" "" ${ARGN})
get_filename_component(_input_we ${_input} NAME_WE)
if(NOT _PCH_SOURCE_CXX)
set(_PCH_SOURCE_CXX "${_input_we}.cpp")
endif()
if(NOT _PCH_SOURCE_C)
set(_PCH_SOURCE_C "${_input_we}.c")
endif()
if(MSVC)
set(_cxx_path "${CMAKE_CFG_INTDIR}/${_target}_cxx_pch")
set(_c_path "${CMAKE_CFG_INTDIR}/${_target}_c_pch")
make_directory("${_cxx_path}")
make_directory("${_c_path}")
set(_pch_cxx_header "${_cxx_path}/${_input}")
set(_pch_cxx_pch "${_cxx_path}/${_input_we}.pch")
set(_pch_c_header "${_c_path}/${_input}")
set(_pch_c_pch "${_c_path}/${_input_we}.pch")
get_target_property(sources ${_target} SOURCES)
foreach(_source ${sources})
set(_pch_compile_flags "")
if(_source MATCHES \\.\(cc|cxx|cpp|c\)$)
if(_source MATCHES \\.\(cpp|cxx|cc\)$)
set(_pch_header "${_input}")
set(_pch "${_pch_cxx_pch}")
else()
set(_pch_header "${_input}")
set(_pch "${_pch_c_pch}")
endif()
if(_source STREQUAL "${_PCH_SOURCE_CXX}")
set(_pch_compile_flags "${_pch_compile_flags} \"/Fp${_pch_cxx_pch}\" /Yc${_input}")
set(_pch_source_cxx_found TRUE)
elseif(_source STREQUAL "${_PCH_SOURCE_C}")
set(_pch_compile_flags "${_pch_compile_flags} \"/Fp${_pch_c_pch}\" /Yc${_input}")
set(_pch_source_c_found TRUE)
else()
if(_source MATCHES \\.\(cpp|cxx|cc\)$)
set(_pch_compile_flags "${_pch_compile_flags} \"/Fp${_pch_cxx_pch}\" /Yu${_input}")
set(_pch_source_cxx_needed TRUE)
else()
set(_pch_compile_flags "${_pch_compile_flags} \"/Fp${_pch_c_pch}\" /Yu${_input}")
set(_pch_source_c_needed TRUE)
endif()
if(_PCH_FORCEINCLUDE)
set(_pch_compile_flags "${_pch_compile_flags} /FI${_input}")
endif(_PCH_FORCEINCLUDE)
endif()
get_source_file_property(_object_depends "${_source}" OBJECT_DEPENDS)
if(NOT _object_depends)
set(_object_depends)
endif()
if(_PCH_FORCEINCLUDE)
if(_source MATCHES \\.\(cc|cxx|cpp\)$)
list(APPEND _object_depends "${_pch_header}")
else()
list(APPEND _object_depends "${_pch_header}")
endif()
endif()
set_source_files_properties(${_source} PROPERTIES
COMPILE_FLAGS "${_pch_compile_flags}"
OBJECT_DEPENDS "${_object_depends}")
endif()
endforeach()
if(_pch_source_cxx_needed AND NOT _pch_source_cxx_found)
message(FATAL_ERROR "A source file ${_PCH_SOURCE_CXX} for ${_input} is required for MSVC builds. Can be set with the SOURCE_CXX option.")
endif()
if(_pch_source_c_needed AND NOT _pch_source_c_found)
message(FATAL_ERROR "A source file ${_PCH_SOURCE_C} for ${_input} is required for MSVC builds. Can be set with the SOURCE_C option.")
endif()
endif(MSVC)
if(CMAKE_COMPILER_IS_GNUCXX)
get_filename_component(_name ${_input} NAME)
set(_pch_header "${CMAKE_CURRENT_SOURCE_DIR}/${_input}")
set(_pch_binary_dir "${CMAKE_CURRENT_BINARY_DIR}/${_target}_pch")
set(_pchfile "${_pch_binary_dir}/${_input}")
set(_outdir "${CMAKE_CURRENT_BINARY_DIR}/${_target}_pch/${_name}.gch")
make_directory(${_outdir})
set(_output_cxx "${_outdir}/.c++")
set(_output_c "${_outdir}/.c")
set(_pch_flags_file "${_pch_binary_dir}/compile_flags.rsp")
export_all_flags("${_pch_flags_file}")
set(_compiler_FLAGS "@${_pch_flags_file}")
add_custom_command(
OUTPUT "${_pchfile}"
COMMAND "${CMAKE_COMMAND}" -E copy "${_pch_header}" "${_pchfile}"
DEPENDS "${_pch_header}"
COMMENT "Updating ${_name}")
add_custom_command(
OUTPUT "${_output_cxx}"
COMMAND "${CMAKE_CXX_COMPILER}" ${_compiler_FLAGS} -x c++-header -o "${_output_cxx}" "${_pchfile}"
DEPENDS "${_pchfile}" "${_pch_flags_file}"
COMMENT "Precompiling ${_name} for ${_target} (C++)")
add_custom_command(
OUTPUT "${_output_c}"
COMMAND "${CMAKE_C_COMPILER}" ${_compiler_FLAGS} -x c-header -o "${_output_c}" "${_pchfile}"
DEPENDS "${_pchfile}" "${_pch_flags_file}"
COMMENT "Precompiling ${_name} for ${_target} (C)")
get_property(_sources TARGET ${_target} PROPERTY SOURCES)
foreach(_source ${_sources})
set(_pch_compile_flags "")
if(_source MATCHES \\.\(cc|cxx|cpp|c\)$)
get_source_file_property(_pch_compile_flags "${_source}" COMPILE_FLAGS)
if(NOT _pch_compile_flags)
set(_pch_compile_flags)
endif()
separate_arguments(_pch_compile_flags)
list(APPEND _pch_compile_flags -Winvalid-pch)
if(_PCH_FORCEINCLUDE)
list(APPEND _pch_compile_flags -include "${_pchfile}")
else(_PCH_FORCEINCLUDE)
list(APPEND _pch_compile_flags "-I${_pch_binary_dir}")
endif(_PCH_FORCEINCLUDE)
get_source_file_property(_object_depends "${_source}" OBJECT_DEPENDS)
if(NOT _object_depends)
set(_object_depends)
endif()
list(APPEND _object_depends "${_pchfile}")
if(_source MATCHES \\.\(cc|cxx|cpp\)$)
list(APPEND _object_depends "${_output_cxx}")
else()
list(APPEND _object_depends "${_output_c}")
endif()
combine_arguments(_pch_compile_flags)
message("${_source}" ${_pch_compile_flags})
set_source_files_properties(${_source} PROPERTIES
COMPILE_FLAGS "${_pch_compile_flags}"
OBJECT_DEPENDS "${_object_depends}")
endif()
endforeach()
endif(CMAKE_COMPILER_IS_GNUCXX)
endfunction()

50
config-cmake.h.in Normal file
View File

@ -0,0 +1,50 @@
#pragma once
#define MOO_PACKAGE_NAME "@MOO_PACKAGE_NAME@"
#define MOO_WEBSITE "@MOO_WEBSITE@"
#define MOO_WEB_CONTACT "@MOO_WEB_CONTACT@"
#define MOO_EMAIL "@MOO_EMAIL@"
#define MOO_COPYRIGHT "@MOO_COPYRIGHT@"
#define PACKAGE_BUGREPORT "@MOO_EMAIL@"
#define GETTEXT_PACKAGE "@GETTEXT_PACKAGE@"
#define MOO_PREFS_XML_FILE_NAME "@MOO_PREFS_XML_FILE_NAME@"
#define MOO_STATE_XML_FILE_NAME "@MOO_STATE_XML_FILE_NAME@"
#define MOO_NAMED_SESSION_XML_FILE_NAME "@MOO_NAMED_SESSION_XML_FILE_NAME@"
#define MOO_SESSION_XML_FILE_NAME "@MOO_SESSION_XML_FILE_NAME@"
#define MEDIT_PORTABLE_DATA_DIR "@MEDIT_PORTABLE_DATA_DIR@"
#define MEDIT_PORTABLE_CACHE_DIR "@MEDIT_PORTABLE_CACHE_DIR@"
#define MEDIT_PORTABLE_MAGIC_FILE_NAME "@MEDIT_PORTABLE_MAGIC_FILE_NAME@"
#define MOO_VERSION "@MOO_VERSION@"
#define MOO_DISPLAY_VERSION "@MOO_DISPLAY_VERSION@"
#define MOO_MAJOR_VERSION @MOO_MAJOR_VERSION@
#define MOO_MICRO_VERSION @MOO_MICRO_VERSION@
#define MOO_MINOR_VERSION @MOO_MINOR_VERSION@
#define MOO_MODULE_MAJOR_VERSION @MOO_MODULE_MAJOR_VERSION@
#define MOO_MODULE_MINOR_VERSION @MOO_MODULE_MINOR_VERSION@
#cmakedefine MOO_BUILD_FROM_MINGW 1
#cmakedefine MOO_BUILD_FROM_MSVC 1
#cmakedefine MOO_BUILD_CTAGS 1
#cmakedefine MOO_ENABLE_COVERAGE 1
#cmakedefine MOO_ENABLE_PYTHON 1
#cmakedefine MOO_BROKEN_GTK_THEME 1
#cmakedefine MOO_NEED_GETTIMEOFDAY 1
#cmakedefine ENABLE_NLS 1
#cmakedefine HAVE_BIND_TEXTDOMAIN_CODESET 1
#cmakedefine HAVE_GETC_UNLOCKED 1
#cmakedefine HAVE_MMAP 1
#cmakedefine HAVE_UNISTD_H 1
#cmakedefine HAVE_SYS_UTSNAME_H 1
#cmakedefine HAVE_SIGNAL_H 1
#cmakedefine HAVE_SYS_WAIT_H 1
#define MOO_CONFIG_H_INCLUDED 1
#include <moo-config.h>

235
configure.ac Normal file
View File

@ -0,0 +1,235 @@
m4_define([_moo_major_version_],[1])
m4_define([_moo_minor_version_],[2])
m4_define([_moo_micro_version_],[90])
m4_define([_moo_version_suffix_],[devel])
m4_define([_moo_module_major_version_],[2])
m4_define([_moo_module_minor_version_],[0])
m4_define([_moo_version_],[_moo_major_version_._moo_minor_version_._moo_micro_version_])
m4_if(_moo_version_suffix_,[],
[m4_define([_moo_display_version_],[_moo_version_])],
[m4_define([_moo_display_version_],[_moo_version_-_moo_version_suffix_])])
m4_define([_moo_website_],[http://mooedit.sourceforge.net/])
m4_define([_moo_web_contact_],[http://mooedit.sourceforge.net/contact.html])
m4_define([_moo_email_],[emuntyan@users.sourceforge.net])
m4_define([_moo_copyright_],[2004-2014 Yevgen Muntyan <_moo_email_>])
AC_PREREQ([2.68])
AC_INIT([medit],[_moo_display_version_],[_moo_email_])
AC_USE_SYSTEM_EXTENSIONS
AC_CONFIG_MACRO_DIR([m4])
AC_SUBST(ACLOCAL_FLAGS)
AM_INIT_AUTOMAKE([1.11 foreign dist-bzip2 no-dist-gzip subdir-objects])
AM_SILENT_RULES([yes])
LT_INIT([disable-shared])
# AC_PROG_RANLIB
AC_SUBST(MOO_MAJOR_VERSION,_moo_major_version_)
AC_SUBST(MOO_MINOR_VERSION,_moo_minor_version_)
AC_SUBST(MOO_MICRO_VERSION,_moo_micro_version_)
AC_SUBST(MOO_MODULE_MAJOR_VERSION,_moo_module_major_version_)
AC_SUBST(MOO_MODULE_MINOR_VERSION,_moo_module_minor_version_)
AC_SUBST(MOO_VERSION,_moo_version_)
AC_SUBST(MOO_DISPLAY_VERSION,"_moo_display_version_")
AC_SUBST(MOO_EMAIL,"_moo_email_")
AC_SUBST(MOO_WEBSITE,"_moo_website_")
AC_SUBST(MOO_WEB_CONTACT,"_moo_web_contact_")
AC_SUBST(MOO_COPYRIGHT,"_moo_copyright_")
# keep in sync with po/maintain
AC_SUBST(MOO_PACKAGE_NAME,"medit-1")
MOO_PREFS_XML_FILE_NAME="prefs.xml"
MOO_STATE_XML_FILE_NAME="state.xml"
MOO_NAMED_SESSION_XML_FILE_NAME="session-%s.xml"
MOO_SESSION_XML_FILE_NAME="session.xml"
MEDIT_PORTABLE_MAGIC_FILE_NAME="medit-portable"
MEDIT_PORTABLE_DATA_DIR="medit-portable-data"
MEDIT_PORTABLE_CACHE_DIR="medit-portable-cache"
AC_SUBST(MEDIT_PORTABLE_MAGIC_FILE_NAME,$MEDIT_PORTABLE_MAGIC_FILE_NAME)
AC_SUBST(GETTEXT_PACKAGE,$MOO_PACKAGE_NAME)
AC_SUBST(GETTEXT_PACKAGE_GSV,"$MOO_PACKAGE_NAME-gsv")
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE",[GETTEXT_PACKAGE])
MOO_INTL
AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL
AC_PROG_MKDIR_P
AM_PROG_CC_C_O
AC_ARG_VAR([WINDRES], [windres])
AC_CHECK_TOOL(WINDRES, windres, :)
AC_ARG_VAR([MOO_PYTHON], [Python executable, required to run build scripts])
AC_CHECK_PROGS(MOO_PYTHON, [python2 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 python], [none])
if test "x$MOO_PYTHON" = "x"; then
AC_MSG_ERROR([Python not found, it is required for the build])
fi
MOO_AC_FLAGS
AM_MAINTAINER_MODE([enable])
AC_CHECK_PROG([TXT2TAGS], txt2tags, txt2tags)
if test x$MOO_DEV_MODE = "xyes" -a "x$TXT2TAGS" = "x"; then
AC_MSG_ERROR([txt2tags not found])
fi
AC_CHECK_PROG([XSLTPROC], xsltproc, xsltproc)
if test x$MOO_DEV_MODE = "xyes" -a "x$XSLTPROC" = "x"; then
AC_MSG_ERROR([xsltproc not found])
fi
AC_DEFINE_UNQUOTED(MOO_CONFIG_H_INCLUDED, 1, MOO_CONFIG_H_INCLUDED)
AC_CONFIG_HEADERS([config.h])
AH_TOP([#ifndef __CONFIG_H__
#define __CONFIG_H__])
AH_BOTTOM([#include <moo-config.h>
#endif // __CONFIG_H__])
MOO_LT_LIB_M
AC_DEFINE_UNQUOTED(MOO_VERSION,["$MOO_VERSION"],[MOO_VERSION])
AC_DEFINE_UNQUOTED(MOO_DISPLAY_VERSION,["$MOO_DISPLAY_VERSION"],[MOO_DISPLAY_VERSION])
AC_DEFINE_UNQUOTED(MOO_MAJOR_VERSION,[$MOO_MAJOR_VERSION],[MOO_MAJOR_VERSION])
AC_DEFINE_UNQUOTED(MOO_MICRO_VERSION,[$MOO_MICRO_VERSION],[MOO_MICRO_VERSION])
AC_DEFINE_UNQUOTED(MOO_MINOR_VERSION,[$MOO_MINOR_VERSION],[MOO_MINOR_VERSION])
AC_DEFINE_UNQUOTED(MOO_MODULE_MAJOR_VERSION,[$MOO_MODULE_MAJOR_VERSION],[MOO_MODULE_MAJOR_VERSION])
AC_DEFINE_UNQUOTED(MOO_MODULE_MINOR_VERSION,[$MOO_MODULE_MINOR_VERSION],[MOO_MODULE_MINOR_VERSION])
AC_DEFINE_UNQUOTED(MOO_EMAIL,["$MOO_EMAIL"],MOO_EMAIL)
AC_DEFINE_UNQUOTED(PACKAGE_BUGREPORT,["$PACKAGE_BUGREPORT"],PACKAGE_BUGREPORT)
AC_DEFINE_UNQUOTED(MOO_COPYRIGHT,["$MOO_COPYRIGHT"],MOO_COPYRIGHT)
AC_DEFINE_UNQUOTED(MOO_WEBSITE,["$MOO_WEBSITE"],MOO_WEBSITE)
AC_DEFINE_UNQUOTED(MOO_WEB_CONTACT,["$MOO_WEB_CONTACT"],MOO_WEB_CONTACT)
MOO_AC_CHECK_OS
MOO_AC_PYTHON
MOO_BUILD_APP=true
MOO_BUILD_MODULE=false
AC_ARG_ENABLE(moo-module,
AS_HELP_STRING([--enable-moo-module],[build standalone python module instead of medit, default NO (you must also use --enable-shared with this option)]),[
if test "$enable_moo_module" = "yes"; then
MOO_BUILD_APP=false
MOO_BUILD_MODULE=true
fi
])
if $MOO_BUILD_MODULE; then
if ! $MOO_ENABLE_PYTHON; then
AC_MSG_ERROR([Python bindings are not enabled, can't build python module])
elif test "$enable_shared" != "yes"; then
AC_MSG_ERROR([Python module can't be built without --enable-shared option])
fi
fi
AM_CONDITIONAL(MOO_BUILD_APP, [$MOO_BUILD_APP])
AM_CONDITIONAL(MOO_BUILD_MODULE, [$MOO_BUILD_MODULE])
AC_SUBST(MOO_TOP_SRCDIR,`cd $srcdir && pwd`)
if test x"$MOO_TOP_SRCDIR" = x"`pwd`"; then
AC_SUBST(MOO_CP_TO_SRCDIR,true)
AC_SUBST(MOO_MV_TO_SRCDIR,true)
else
AC_SUBST(MOO_CP_TO_SRCDIR,cp)
AC_SUBST(MOO_MV_TO_SRCDIR,mv)
fi
AM_CONDITIONAL(MOO_BUILD_CTAGS, [$MOO_OS_UNIX])
if $MOO_OS_UNIX; then
AC_DEFINE(MOO_BUILD_CTAGS, 1, [build ctags plugin])
fi
AC_ARG_ENABLE(coverage,
AS_HELP_STRING([--enable-coverage],[check test coverage]),[
MOO_ENABLE_COVERAGE="$enable_coverage"
],[
MOO_ENABLE_COVERAGE="no"
])
AM_CONDITIONAL(MOO_ENABLE_COVERAGE, test "x$MOO_ENABLE_COVERAGE" = "xyes")
if test "x$MOO_ENABLE_COVERAGE" = "xyes"; then
AC_DEFINE(MOO_ENABLE_COVERAGE, 1, [enable code coverage testing])
fi
if $MOO_OS_WIN32; then
_moo_cygwin=false
if test "$OSTYPE" = "cygwin"; then
_moo_cygwin=true
fi
if $_moo_cygwin; then
MEDIT_INNO_COMPILER='"/cygdrive/c/Program Files (x86)/Inno Setup 5/ISCC.exe"'
elif test -d $HOME/.wine/drive_c/windows/syswow64 -o -d "/cygdrive/c/Program Files (x86)"; then
MEDIT_INNO_COMPILER='wine "c:\\program files (x86)\\inno setup 5\\ISCC.exe"'
else
MEDIT_INNO_COMPILER='wine "c:\\program files\\inno setup 5\\ISCC.exe"'
fi
AC_MSG_CHECKING([Inno compiler])
AC_MSG_RESULT([$MEDIT_INNO_COMPILER])
_moo_win32_config=release
if test "$MOO_DEBUG_ENABLED" = "yes"; then
_moo_win32_config="debug"
fi
if test -n "$mgwconfig"; then
_moo_win32_config="$mgwconfig"
fi
AC_ARG_VAR([MOO_WIN32_CONFIG], [$_moo_win32_config])
AC_MSG_CHECKING([Win32 build configuration])
AC_MSG_RESULT([$MOO_WIN32_CONFIG])
AC_SUBST(MEDIT_WIN32_APP_UID,"7F9F899F-EE8A-47F0-9981-8C525AF78E4D")
if $_moo_cygwin; then
AC_SUBST(MEDIT_INNO_TOP_SRCDIR,"`cygpath -m $MOO_TOP_SRCDIR`")
_moo_this_dir=`pwd`
AC_SUBST(MEDIT_INNO_TOP_BUILDDIR,"`cygpath -m $_moo_this_dir`")
AC_SUBST(MEDIT_INNO_INSTDIR,"`cygpath -m $prefix`")
else
AC_SUBST(MEDIT_INNO_TOP_SRCDIR,"Z:$MOO_TOP_SRCDIR")
AC_SUBST(MEDIT_INNO_TOP_BUILDDIR,"Z:`pwd`")
AC_SUBST(MEDIT_INNO_INSTDIR,"Z:`cd $prefix && pwd`")
fi
AC_MSG_CHECKING([MEDIT_INNO_TOP_SRCDIR])
AC_MSG_RESULT([$MEDIT_INNO_TOP_SRCDIR])
AC_MSG_CHECKING([MEDIT_INNO_TOP_BUILDDIR])
AC_MSG_RESULT([$MEDIT_INNO_TOP_BUILDDIR])
AC_MSG_CHECKING([MEDIT_INNO_INSTDIR])
AC_MSG_RESULT([$MEDIT_INNO_INSTDIR])
AC_SUBST(MEDIT_INNO_COMPILER)
MEDIT_INNO_INSTALLER_SUFFIX=""
if test -n "$MOO_WIN32_CONFIG" -a "$MOO_WIN32_CONFIG" != "release"; then
MEDIT_INNO_INSTALLER_SUFFIX="-$MOO_WIN32_CONFIG"
fi
AC_SUBST(MEDIT_SETUP_NAME, "medit-$MOO_DISPLAY_VERSION$MEDIT_INNO_INSTALLER_SUFFIX")
AC_MSG_CHECKING([Win32 setup name])
AC_MSG_RESULT([$MEDIT_SETUP_NAME])
fi
AC_ARG_ENABLE(install-hooks,
AS_HELP_STRING([--enable-install-hooks],[run gtk-update-icon-cache during 'make install']),[
MOO_ENABLE_INSTALL_HOOKS="$enable_install_hooks"
],[
if $MOO_BUILD_APP; then
MOO_ENABLE_INSTALL_HOOKS="yes"
else
MOO_ENABLE_INSTALL_HOOKS="no"
fi
])
AM_CONDITIONAL(MOO_ENABLE_INSTALL_HOOKS, test "x$MOO_ENABLE_INSTALL_HOOKS" = "xyes")
AC_CONFIG_FILES([
Makefile
api/Makefile
doc/Makefile
moo/Makefile
po/Makefile
po-gsv/Makefile
])
AC_OUTPUT

153
doc/Makefile.am Normal file
View File

@ -0,0 +1,153 @@
BUILT_SOURCES =
if MOO_DEV_MODE
$(srcdir)/built/medit-defines.ent: medit-defines.ent.in $(top_builddir)/config.status
$(AM_V_GEN)cd $(top_builddir) && ./config.status --silent --file=doc/medit-defines.ent
$(AM_V_at)$(MKDIR_P) $(srcdir)/built
$(AM_V_at)mv medit-defines.ent $(srcdir)/built/
gendocbook_files = \
$(top_srcdir)/api/gendocbook.py \
$(top_srcdir)/api/mpi/__init__.py \
$(top_srcdir)/api/mpi/module.py \
$(top_srcdir)/api/mpi/docbookwriter.py
script_docbook_sources = \
built/medit-defines.ent \
built/script-python.docbook \
built/script-lua.docbook \
built/script-lua-gtk.docbook
$(srcdir)/built/script-python.docbook: $(gendocbook_files) script-python.tmpl.docbook $(top_srcdir)/api/moo.xml
$(AM_V_at)$(MKDIR_P) $(srcdir)/built
$(AM_V_GEN)$(MOO_PYTHON) $(top_srcdir)/api/gendocbook.py \
--python --template $(srcdir)/script-python.tmpl.docbook \
$(top_srcdir)/api/moo.xml > script-python.docbook.tmp && \
mv script-python.docbook.tmp $(srcdir)/built/script-python.docbook
$(srcdir)/built/script-lua.docbook: $(gendocbook_files) script-lua.tmpl.docbook $(top_srcdir)/api/moo.xml $(top_srcdir)/api/gtk.xml
$(AM_V_at)$(MKDIR_P) $(srcdir)/built
$(AM_V_GEN)$(MOO_PYTHON) $(top_srcdir)/api/gendocbook.py \
--lua --template $(srcdir)/script-lua.tmpl.docbook \
--import $(top_srcdir)/api/gtk.xml \
$(top_srcdir)/api/moo.xml > script-lua.docbook.tmp && \
mv script-lua.docbook.tmp $(srcdir)/built/script-lua.docbook
$(srcdir)/built/script-lua-gtk.docbook: $(gendocbook_files) script-lua-gtk.tmpl.docbook $(top_srcdir)/api/gtk.xml
$(AM_V_at)$(MKDIR_P) $(srcdir)/built
$(AM_V_GEN)$(MOO_PYTHON) $(top_srcdir)/api/gendocbook.py \
--lua --template $(srcdir)/script-lua-gtk.tmpl.docbook \
$(top_srcdir)/api/gtk.xml > script-lua-gtk.docbook.tmp && \
mv script-lua-gtk.docbook.tmp $(srcdir)/built/script-lua-gtk.docbook
# $(srcdir)/help/script-python.html: built/script-python.docbook built/medit-defines.ent script.xsl
# $(AM_V_at)$(MKDIR_P) $(srcdir)/help/
# $(AM_V_GEN)$(XSLTPROC) --output script-python.html.tmp \
# $(srcdir)/script.xsl $(srcdir)/built/script-python.docbook \
# && mv script-python.html.tmp $(srcdir)/help/script-python.html
#
# $(srcdir)/help/script-lua.html: built/script-lua.docbook built/medit-defines.ent script.xsl
# $(AM_V_at)$(MKDIR_P) $(srcdir)/help/
# $(AM_V_GEN)$(XSLTPROC) --output script-lua.html.tmp \
# $(srcdir)/script.xsl $(srcdir)/built/script-lua.docbook \
# && mv script-lua.html.tmp $(srcdir)/help/script-lua.html
#
# $(srcdir)/help/script-lua-gtk.html: built/script-lua-gtk.docbook built/medit-defines.ent script.xsl
# $(AM_V_at)$(MKDIR_P) $(srcdir)/help/
# $(AM_V_GEN)$(XSLTPROC) --output script-lua-gtk.html.tmp \
# $(srcdir)/script.xsl $(srcdir)/built/script-lua-gtk.docbook \
# && mv script-lua-gtk.html.tmp $(srcdir)/help/script-lua-gtk.html
$(srcdir)/help/script/index.html: $(script_docbook_sources) script-book.xsl
$(AM_V_GEN)cd $(srcdir) && $(XSLTPROC) --xinclude script-book.xsl script.docbook
$(srcdir)/help/medit.css: medit.css
$(AM_V_at)$(MKDIR_P) $(srcdir)/help/
$(AM_V_GEN)cp $(srcdir)/medit.css $(srcdir)/help/
$(srcdir)/built/lgpl.no-fancy-chars: $(top_srcdir)/COPYING
$(AM_V_at)$(MKDIR_P) $(srcdir)/built
tr -d '\014' < $(top_srcdir)/COPYING > lgpl.no-fancy-chars.tmp && \
mv lgpl.no-fancy-chars.tmp $(srcdir)/built/lgpl.no-fancy-chars
docbook_files = \
medit.docbook \
prefs.docbook \
regex.docbook \
user-tools.docbook \
license.docbook
docbook_sources = \
$(docbook_files) \
built/lgpl.no-fancy-chars \
built/medit-defines.ent
$(srcdir)/help/index.html: $(docbook_sources) medit.xsl medit-common.xsl
$(AM_V_GEN)cd $(srcdir) && $(XSLTPROC) --xinclude medit.xsl medit.docbook
$(srcdir)/help/help.html: $(docbook_sources) medit-single.xsl medit-common.xsl
$(AM_V_at)$(MKDIR_P) $(srcdir)/help/
$(AM_V_GEN)$(XSLTPROC) --xinclude --output help.html.tmp $(srcdir)/medit-single.xsl $(srcdir)/medit.docbook && \
mv help.html.tmp $(srcdir)/help/help.html
toc.xml: $(docbook_sources)
$(AM_V_GEN)$(XSLTPROC) --output toc.xml --xinclude \
--stringparam chunk.first.sections 1 \
http://docbook.sourceforge.net/release/xsl/current/html/maketoc.xsl $(srcdir)/medit.docbook
moo-help-sections.h.stamp: $(docbook_files) toc.xml genhelpsectionsh.py
$(AM_V_at)$(MKDIR_P) $(srcdir)/built
$(AM_V_GEN)$(MOO_PYTHON) $(srcdir)/genhelpsectionsh.py --toc=toc.xml --srcdir=$(srcdir) $(docbook_files) > moo-help-sections.h.tmp
$(AM_V_at)cmp -s moo-help-sections.h.tmp $(srcdir)/built/moo-help-sections.h || \
mv moo-help-sections.h.tmp $(srcdir)/built/moo-help-sections.h
$(AM_V_at)rm -f moo-help-sections.h.tmp
$(AM_V_at)echo stamp > moo-help-sections.h.stamp
png_files = prefs-file-filters.png prefs-file-selector.png
dest_png_files = $(addprefix $(srcdir)/help/img/,$(png_files))
$(srcdir)/help/img/%.png: img/%.png
$(AM_V_at)$(MKDIR_P) $(srcdir)/help/img/
$(AM_V_GEN)cp $(srcdir)/img/$*.png $(srcdir)/help/img/
all-am: doc
doc: \
$(srcdir)/help/index.html \
$(srcdir)/help/help.html \
$(srcdir)/help/script/index.html \
$(srcdir)/help/medit.css \
$(srcdir)/built/medit.1 \
$(dest_png_files) \
moo-help-sections.h.stamp
$(srcdir)/built/man-medit.t2t: man-medit.t2t.in $(top_builddir)/config.status
$(AM_V_at)$(MKDIR_P) $(srcdir)/built
$(AM_V_GEN)cd $(top_builddir) && ./config.status --silent --file=doc/man-medit.t2t
$(AM_V_at)mv man-medit.t2t $(srcdir)/built/man-medit.t2t
$(srcdir)/built/medit.1: built/man-medit.t2t
$(AM_V_GEN)$(TXT2TAGS) --target=man --outfile=- $(srcdir)/built/man-medit.t2t | grep -v "cmdline: txt2tags" \
> medit.1.tmp && mv medit.1.tmp $(srcdir)/built/medit.1
endif
EXTRA_DIST = help built/moo-help-sections.h built/medit.1
install-data-local:
$(MKDIR_P) $(DESTDIR)$(MOO_HELP_DIR)/img $(DESTDIR)$(MOO_HELP_DIR)/script
cd $(srcdir) && $(INSTALL_DATA) help/*.html help/*.css $(DESTDIR)$(MOO_HELP_DIR)
cd $(srcdir) && $(INSTALL_DATA) help/script/*.html $(DESTDIR)$(MOO_HELP_DIR)/script
cd $(srcdir) && $(INSTALL_DATA) help/img/*.png $(DESTDIR)$(MOO_HELP_DIR)/img
uninstall-local:
rm -f $(DESTDIR)$(MOO_HELP_DIR)/*.html \
$(DESTDIR)$(MOO_HELP_DIR)/*.css \
$(DESTDIR)$(MOO_HELP_DIR)/script/*.html \
$(DESTDIR)$(MOO_HELP_DIR)/img/*.png
if MOO_OS_UNIX
if MOO_BUILD_APP
dist_man_MANS = built/medit.1
endif MOO_BUILD_APP
endif MOO_OS_UNIX

71
doc/genhelpsectionsh.py Normal file
View File

@ -0,0 +1,71 @@
#! /usr/bin/env python
import os
import re
import sys
import optparse
op = optparse.OptionParser()
op.add_option("--toc", action="store")
op.add_option("--srcdir", action="store")
(opts, args) = op.parse_args()
srcdir = opts.srcdir or '.'
def resolve_filename(filename):
if os.path.exists(filename):
return filename
fullname = os.path.join(srcdir, filename)
if os.path.exists(fullname):
return fullname
raise RuntimeError('could not find file %s' % filename)
def parse_toc(filename):
filename = resolve_filename(filename)
dic = {}
for line in open(filename):
m = re.search(r'<tocentry linkend="([\w\d_.-]+)"><\?dbhtml filename="([\w\d_.-]+)"\?>', line)
if m:
dic[m.group(1)] = m.group(2)
return dic
def parse_docbook(filename):
filename = resolve_filename(filename)
dic = {}
for line in open(filename):
m = re.search(r'id\s*=\s*"([\w\d_.-]+)"\s+moo.helpsection\s*=\s*"([\w\d_.-]+)"', line)
if m:
dic[m.group(2)] = m.group(1)
else:
m = re.search(r'moo.helpsection\s*=\s*"([\w\d_.-]+)"\s+id\s*=\s*"([\w\d_.-]+)"', line)
if m:
dic[m.group(1)] = m.group(2)
return dic
map_id_to_html = parse_toc(opts.toc)
map_hsection_to_id = {}
for f in args:
map_hsection_to_id.update(parse_docbook(f))
map_hsection_to_html = {
'PREFS_ACCELS': 'index.html',
'DIALOG_REPLACE': 'index.html',
'DIALOG_FIND': 'index.html',
'FILE_SELECTOR': 'index.html',
'DIALOG_FIND_FILE': 'index.html',
'DIALOG_FIND_IN_FILES': 'index.html',
}
for section in map_hsection_to_id:
map_hsection_to_html[section] = os.path.basename(map_id_to_html[map_hsection_to_id[section]])
map_hsection_to_html['PREFS_PLUGINS'] = map_hsection_to_html['PREFS_DIALOG']
map_hsection_to_html['PREFS_VIEW'] = map_hsection_to_html['PREFS_DIALOG']
print '#ifndef MOO_HELP_SECTIONS_H'
print '#define MOO_HELP_SECTIONS_H'
print ''
for section in sorted(map_hsection_to_html.keys()):
print '#define HELP_SECTION_%s "%s"' % (section, map_hsection_to_html[section])
print ''
print '#endif /* MOO_HELP_SECTIONS_H */'

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

87
doc/license.docbook Normal file
View File

@ -0,0 +1,87 @@
<?xml version="1.0"?>
<!DOCTYPE chapter [
<!ENTITY % medit-defines SYSTEM "built/medit-defines.ent">
%medit-defines;
]>
<chapter id="chapter-license" moo.helpsection="APP_LICENSE">
<title>License</title>
<para>
&medit; as a whole is distributed under the terms of the GNU General
Public License, version 2, but most of its code is released under the
GNU Lesser General Public License. Full text of these licenses, as well
as licenses and acknowledgements for third-party software incorporated
in &medit;, can be found in this section.
</para>
<sect1 id="section-license-gpl">
<title>GNU General Public License</title>
<literallayout>
<xi:include href="../COPYING.GPL" parse="text" xmlns:xi="http://www.w3.org/2001/XInclude"/>
</literallayout>
</sect1>
<sect1 id="section-license-lgpl">
<title>GNU Lesser General Public License</title>
<literallayout>
<xi:include href="built/lgpl.no-fancy-chars" parse="text" xmlns:xi="http://www.w3.org/2001/XInclude"/>
</literallayout>
</sect1>
<sect1 id="section-license-lua">
<title>Lua License</title>
<literallayout>
<xi:include href="../moo/moolua/lua/COPYRIGHT" parse="text" xmlns:xi="http://www.w3.org/2001/XInclude"/>
</literallayout>
</sect1>
<sect1 id="section-license-lfs">
<title>LuaFileSystem License</title>
<literallayout>
LuaFileSystem - File System Library for Lua
Copyright 2003-2007 PUC-Rio
http://www.keplerproject.org/luafilesystem
LuaFileSystem is a Lua library developed to complement the set of functions
related to file systems offered by the standard Lua distribution. LuaFileSystem
offers a portable way to access the underlying directory structure and file
attributes. LuaFileSystem is free software and uses the same license as Lua 5.1
Current version is 1.2.1.
</literallayout>
</sect1>
<sect1 id="section-license-xdg-utils">
<title>xdg-utils License</title>
<literallayout>
Copyright 2006, Kevin Krammer &lt;kevin.krammer@gmx.at&gt;
Copyright 2006, Jeremy White &lt;jwhite@codeweavers.com&gt;
LICENSE:
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
</literallayout>
</sect1>
</chapter>

99
doc/man-medit.t2t.in Normal file
View File

@ -0,0 +1,99 @@
MEDIT
September 2010
%!encoding: UTF-8
= NAME =
medit - text editor
= SYNOPSIS =
**medit** [//OPTION//]... [//FILES//]
= DESCRIPTION =
**medit** is a text editor.
= OPTIONS =
: **-n**, **--new-app**
run new instance of **medit**. By default **medit** opens //FILES//
(or creates a new document if none are given) in an existing instance
of application
: **-s**, **--use-session**[=//yes|no//]
load and save session. By default **medit** does it when **-n** is not used.
If this option is not given on command line then medit uses the corresponding
preferences setting.
: **--pid** //PID//
use existing instance with process id //PID//.
: **--app-name** //NAME//
use instance name //NAME//. If an instance with this name is already running,
then it will send files given on the command line to that instance and exit.
: **-e**, **--encoding** //ENCODING//
use provided character encoding to open the file
: **-l**, **--line** //LINE//
open file and position cursor on line //LINE//. Alternatively
line number may be specified with filename, e.g.
medit foo.txt:12
: **-r**, **--reload**
automatically reload opened file if it was modified on disk by another program.
: **-w**, **--new-window**
open file in a new window.
: **-t**, **--new-tab**
open file in a new tab.
: **--log-file** //FILE//
write debug output into //FILE//. This option is only useful on Windows.
: **--log-window**
show debug output in a log window. This option is only useful on Windows.
: **--debug** //DOMAINS//
enable debug output for //DOMAINS// (if **medit** was compiled with
--enable-debug option).
: **--geometry** //WIDTHxHEIGHT//
: **--geometry** //WIDTHxHEIGHT+X+Y//
default window size and position.
: **-h**, **--help**
show summary of options.
: **-v**, **--version**
show program version.
: //FILES//
list of files to open. Filenames may include line numbers after colon,
e.g. /tmp/file.txt:200. Trailing colon is ignored.
= ENVIRONMENT VARIABLES =
: MEDIT_PID
if set, it is used as --pid argument. When medit spawns a process (e.g. a DVI viewer) it sets
MEDIT_PID to its own process id, so the child process may in turn simply use 'medit filename'
to open a file (e.g. for inverse DVI search).
= CONTACT =
@MOO_WEB_CONTACT@
= AUTHOR =
Written and maintained by Yevgen Muntyan <@MOO_EMAIL@>

8
doc/medit-common.xsl Normal file
View File

@ -0,0 +1,8 @@
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="html.stylesheet" select="'medit.css'"/>
<xsl:output method="html" indent="yes"/>
<xsl:param name="chunker.output.indent" select="'yes'"/>
</xsl:stylesheet>

6
doc/medit-defines.ent.in Normal file
View File

@ -0,0 +1,6 @@
<!-- -%- lang:none -%- -->
<!ENTITY medit "<application>medit</application>">
<!ENTITY medit-version "@MOO_DISPLAY_VERSION@">
<!ENTITY medit-user-data-dir-unix "<filename>$HOME/.local/share/medit-1/</filename>">
<!ENTITY medit-prefs-xml-unix "<filename>$HOME/.local/share/medit-1/prefs.xml</filename>">
<!ENTITY medit-user-tools-dir-unix "<filename>$HOME/.local/share/medit-1/tools/</filename>">

9
doc/medit-single.xsl Normal file
View File

@ -0,0 +1,9 @@
<?xml version='1.0'?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"/>
<xsl:import href="medit-common.xsl"/>
</xsl:stylesheet>

141
doc/medit.css Normal file
View File

@ -0,0 +1,141 @@
.variablelist
{
padding: 4px;
margin-left: 3em;
}
.variablelist td:first-child
{
vertical-align: top;
}
.programlisting
{
/* tango:sky blue 0/1 */
background: #e6f3ff;
/* border: solid 1px #729fcf;*/
/* padding: 0.5em;*/
font-family: monospace;
white-space: pre;
/* background: #F4F4F4;*/
border: solid 1px #C5C5C5;
padding: 0.25em;
margin: 0.5em;
}
.code
{
font-family: monospace;
white-space: pre;
background: #e6f3ff;
/* background: #F4F4F4;*/
/* border: solid 1px #C5C5C5;*/
padding: 0.1em;
/* margin: 0.5em;*/
}
div.table table
{
border-collapse: collapse;
border-spacing: 0px;
/* tango:aluminium 3 */
border: solid 1px #babdb6;
}
div.table table td, div.table table th
{
/* tango:aluminium 3 */
border: solid 1px #babdb6;
padding: 3px;
vertical-align: top;
}
div.table table th
{
/* tango:aluminium 2 */
background-color: #d3d7cf;
}
hr
{
/* tango:aluminium 3 */
color: #babdb6;
background: #babdb6;
border: none 0px;
height: 1px;
clear: both;
}
.warning
{
/* tango:orange 0/1 */
background: #ffeed9;
border-color: #ffb04f;
}
.note
{
/* tango:chameleon 0/0.5 */
background: #d8ffb2;
border-color: #abf562;
}
.note, .warning
{
padding: 0.5em;
border-width: 1px;
border-style: solid;
}
.note h3, .warning h3
{
margin-top: 0.0em
}
/*.note p, .warning p
{
margin-bottom: 0.0em
}*/
/* blob links */
h2 .extralinks, h3 .extralinks
{
float: right;
/* tango:aluminium 3 */
color: #babdb6;
font-size: 80%;
font-weight: normal;
}
.annotation
{
/* tango:aluminium 5 */
color: #555753;
font-size: 80%;
font-weight: normal;
}
.listing_frame {
/* tango:sky blue 1 */
border: solid 1px #729fcf;
padding: 0px;
}
.listing_lines, .listing_code {
margin-top: 0px;
margin-bottom: 0px;
padding: 0.5em;
}
.listing_lines {
/* tango:sky blue 0.5 */
background: #a6c5e3;
/* tango:aluminium 6 */
color: #2e3436;
}
.listing_code {
/* tango:sky blue 0 */
background: #e6f3ff;
}
.listing_code .programlisting {
/* override from previous */
border: none 0px;
padding: 0px;
}
.listing_lines pre, .listing_code pre {
margin: 0px;
}

19
doc/medit.docbook Normal file
View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" ?><!-- -%- indent-width:1 -%- -->
<!DOCTYPE book [
<!ENTITY % medit-defines SYSTEM "built/medit-defines.ent">
%medit-defines;
]>
<book id="medit-manual">
<bookinfo>
<title>&medit; manual</title>
<date>12/26/2010</date>
<releaseinfo>&medit-version;</releaseinfo>
</bookinfo>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="prefs.docbook"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="regex.docbook"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="user-tools.docbook"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="license.docbook"/>
</book>

12
doc/medit.xsl Normal file
View File

@ -0,0 +1,12 @@
<?xml version='1.0'?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/chunk.xsl"/>
<xsl:import href="medit-common.xsl"/>
<xsl:param name="base.dir" select="'help/'"/>
<xsl:param name="chunk.first.sections" select="'1'"/>
</xsl:stylesheet>

441
doc/prefs.docbook Normal file
View File

@ -0,0 +1,441 @@
<?xml version="1.0"?><!-- -%- indent-width:2 -%- -->
<!DOCTYPE chapter [
<!ENTITY % medit-defines SYSTEM "built/medit-defines.ent">
%medit-defines;
]>
<chapter id="chapter-prefs">
<title>Preferences</title>
<sect1 id="section-prefs-dialog" moo.helpsection="PREFS_DIALOG">
<title>Preferences dialog</title>
<para>
<guilabel>Preferences</guilabel> provides access to almost all &medit; settings.
Some settings are not available here, see <xref linkend="section-prefs-xml"/>.
</para>
<para>
<guilabel>Preferences</guilabel> dialog has several tabs:
<variablelist>
<varlistentry>
<term><guilabel>General</guilabel></term>
<listitem>Contains settings which didn't find place in other sections, see
<xref linkend="section-prefs-general"/>.</listitem>
</varlistentry>
<varlistentry>
<term><guilabel>View</guilabel></term>
<listitem>Contains settings which control how &medit; displays text.</listitem>
</varlistentry>
<varlistentry>
<term><guilabel>File</guilabel></term>
<listitem>Contains settings which control how &medit; saves and loads files, see
<xref linkend="section-prefs-file"/>.</listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Languages</guilabel></term>
<listitem>See <xref linkend="section-prefs-langs"/>.</listitem>
</varlistentry>
<varlistentry>
<term><guilabel>File Filters</guilabel></term>
<listitem>See <xref linkend="section-prefs-file-filters"/>.</listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Plugins</guilabel></term>
<listitem>Displays information about available plugings and allows to disable/enable them.</listitem>
</varlistentry>
<varlistentry>
<term><guilabel>File Selector</guilabel></term>
<listitem>Contains File Selector settings, see <xref linkend="section-prefs-file-selector"/>.</listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Tools</guilabel></term>
<listitem>User-defined tools, see <xref linkend="section-prefs-user-tools"/>.</listitem>
</varlistentry>
</variablelist>
</para>
</sect1>
<sect1 id="section-prefs-general" moo.helpsection="PREFS_GENERAL">
<title><guilabel>General</guilabel> tab</title>
<variablelist>
<varlistentry>
<term><parameter>Smart Home and End</parameter></term>
<listitem>If checked, <keycap>Home</keycap> key moves cursor to first non-whitespace character
on the line on first <keycap>Home</keycap> key press, and moves cursor to the first character on the line
on second key press. Analogously <keycap>End</keycap> key moves cursor past last non-whitespace character
on the line, and then past last character on next key press.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>Enable auto indentation</parameter></term>
<listitem>If checked, pressing <keycap>Enter</keycap> key inserts line end character and
whitespace to indent next line according to indentation settings.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>Do not use tabs for indentation</parameter></term>
<listitem>If checked, spaces are used for indentation instead of tab character.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>Tab key indents</parameter></term>
<listitem>If checked, <keycap>Tab</keycap> key inserts whitespace characters according
to indentation settings to indent text at cursor. Otherwise <keycap>Tab</keycap> key
only inserts single tab character.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>Tab width</parameter></term>
<listitem>Displayed width of tab character in spaces. By default it is
<constant>8</constant>.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>Indent width</parameter></term>
<listitem>Number of spaces inserted by single <keycap>Tab</keycap> key press. If tabs are
used for indentation then <keycap>Tab</keycap> key inserts spaces until line indent is
multiple of tab width, then it replaces spaces with tabs (if indent width is a multiple
of tab width then only tab characters are used.)</listitem>
</varlistentry>
</variablelist>
</sect1>
<sect1 id="section-prefs-file" moo.helpsection="PREFS_FILE">
<title><guilabel>File</guilabel> tab</title>
<variablelist>
<varlistentry>
<term><parameter>Encodings to autodetect</parameter></term>
<listitem><para>This entry contains comma-separated list of encodings used when
loading files if encoding is not specified in the <guilabel>Open</guilabel>.
&medit; tries every encoding from the list one by one and stops when file
content is valid text in this encoding. <code>LOCALE</code> denotes encoding
from current locale.
</para></listitem>
</varlistentry>
<varlistentry>
<term><parameter>Encoding for new files</parameter></term>
<listitem><para>This is default encoding to save new files. For every document
its encoding on disk can be changed using Encoding submenu of Document menu.
</para></listitem>
</varlistentry>
<varlistentry>
<term><parameter>Remove trailing spaces</parameter></term>
<listitem><para>If checked, trailing whitespace characters are removed from each
line of the document on save.
</para></listitem>
</varlistentry>
<varlistentry>
<term><parameter>Ensure trailing newline</parameter></term>
<listitem><para>If checked, new line character will be added to document on save
if it doesn't end with one.
</para></listitem>
</varlistentry>
<varlistentry>
<term><parameter>Make backups</parameter></term>
<listitem><para>If checked, old file contents will be moved to backup file on
save.</para></listitem>
</varlistentry>
<varlistentry>
<term><parameter>Enable session support</parameter></term>
<listitem><para>If checked, &medit; will remember open documents on exit and restore
them next time it's launched.</para></listitem>
</varlistentry>
<varlistentry>
<term><parameter>Open and Save As dialogs show current document folder</parameter></term>
<listitem><para>If checked, Open and Save As dialogs will show folder of the current document.
Otherwise they will show last used folder.</para></listitem>
</varlistentry>
</variablelist>
</sect1>
<sect1 id="section-prefs-langs" moo.helpsection="PREFS_LANGS">
<title><guilabel>Languages</guilabel> tab</title>
<para>
<guilabel>Languages and files</guilabel> tab allows customizing
how syntax highlighting language and editing options are chosen
depending on the document filename, as well as setting editing options for
all documents which use given language and choosing file patterns and mime types
for which the given language should be used.
</para>
<para>
Here you can set editing options on per-language basis, as well as define
for which file patterns and mime types given language should be used.
<variablelist>
<varlistentry>
<term><guilabel>Language</guilabel> combo box</term>
<listitem><para>
Choose the language you want to customize. Settings for <code>None</code> will apply to
documents for which no syntax highlighting language was chosen.
</para></listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Mime types</guilabel></term>
<listitem><para>
Selected language will be used for files with these mime types, unless the language
is chosen based on the filename or overridden in the <guilabel>File filters tab</guilabel> section.
</para></listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Extensions</guilabel></term>
<listitem><para>
Selected language will be used for files whose filenames match these patterns,
unless overridden in the <guilabel>File filters tab</guilabel> section.
</para></listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Options</guilabel></term>
<listitem><para>
Default editing options to use in documents which use the given language. These
options can be overridden using <guilabel>File filters tab</guilabel> section, and options set
in the file text have a higher priority as well. See <xref linkend="section-editing-options"/>
for format of this entry content.
</para></listitem>
</varlistentry>
</variablelist>
</para>
</sect1>
<sect1 id="section-prefs-file-filters" moo.helpsection="PREFS_FILTERS">
<title>File filters tab</title>
<para>
<guilabel>File filters tab</guilabel> section allows to customize editing options,
as well as syntax highlighting language, on per-document basis using regular
expressions which are matched against the document filename (globs can also be
used, see below). Full file paths are used, so one can have per-directory settings.
</para>
<para>
The filters are applied in the order they appear in the list, one by one. All filters
are applied to every file, so several filters may affect options in the same file. In
this way one can set some options for a set of files or a directory, then set or modify
some additional options for certain files in that set, etc.
</para>
<para>
To add a filter, use <guilabel>New</guilabel> button. Click the filter in the list to
select it, then click the <guilabel>Filter</guilabel> or <guilabel>Options</guilabel>
part of it to edit. Use <guilabel>Delete</guilabel> button to delete a filter,
and <guilabel>Up</guilabel> and <guilabel>Down</guilabel> buttons to change the order in
which they are applied.
</para>
<para>
<guilabel>Filter</guilabel> field contains a regular expression matched agains the
document filename. If it is found in the filename,
then the options from the <guilabel>Options</guilabel> field are applied to the
document. Example:
<programlisting>projects/moo/</programlisting>
</para>
<para>
Use dollar if you need to match ends of filenames, e.g. "<code>\.doc$</code>" will work as
"<code>*.doc</code>" pattern.
</para>
<para>
Alternatively it can be
a comma-separated list of globs prefixed with "<code>globs:</code>" or a list
of language ids prefixed with "<code>langs:</code>", e.g.
<programlisting>globs:*.c,*.h</programlisting>
or
<programlisting>langs:c,c++</programlisting>
</para>
<para>
<guilabel>Options</guilabel> field contains the options, in format described in
<xref linkend="section-editing-options"/>.
</para>
<informalexample>
<graphic fileref="img/prefs-file-filters.png" align="center"/>
</informalexample>
</sect1>
<sect1 id="section-prefs-file-selector" moo.helpsection="PREFS_FILE_SELECTOR">
<title><guilabel>File Selector</guilabel> tab</title>
<para>
<guilabel>File Selector</guilabel> tab in the <guilabel>Preferences</guilabel>
dialog allows to define custom commands which are available in
<guimenu>Open With</guimenu> submenu of context menu in File Selector. By default
this submenu contains single item <guimenuitem>Default Application</guimenuitem>
which opens selected file with default application as configured in the system.
Here you can add additional commands and set whether they should be available
only for given file patterns or syntax highlighting languages.
</para>
<para>
Use <guilabel>New</guilabel> button to create new command, <guilabel>Delete</guilabel>
button to delete selected command, and <guilabel>Up</guilabel> and <guilabel>Down</guilabel>
to change relative order of the commands, they will appear in the menu in the same order
as in this list.
</para>
<para>
The following entries set the command properties:
<variablelist>
<?dbhtml list-presentation="table"?>
<!-- <?dbhtml term-separator=" : "?>-->
<varlistentry>
<term><parameter>Name</parameter></term>
<listitem>Menu item label for this command.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>Command</parameter></term>
<listitem>Shell command to execute when the menu item is activated. <code>%f</code> will
be replaced with full path of the selected file; if more than one file is selected then
the command will be executed for each file one by one. If <parameter>command</parameter>
contains <code>%F</code> and several files are selected then <code>%F</code> will be
replaced with the space-separated list of paths of all selected files. If a single file
is selected then <code>%f</code> and <code>%F</code> behave in the same way.
Example: <code>firefox %f</code>, <code>glade %F</code></listitem>
</varlistentry>
<varlistentry>
<term><parameter>Extensions</parameter></term>
<listitem>Semicolon-separated list of file patterns to define for which files this command
is available, e.g. <code>*.c;*.h</code>. Use <code>*</code> if the command should
be available for all files.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>Mime types</parameter></term>
<listitem>Semicolon-separated list of mime types to define for which files this command
is available, e.g. <code>application/docbook+xml;application/x-glade</code>. Leave it empty
if <parameter>Extensions</parameter> entry defines whether the command should be enabled.</listitem>
</varlistentry>
</variablelist>
</para>
<informalexample>
<graphic fileref="img/prefs-file-selector.png" align="center"/>
</informalexample>
</sect1>
<sect1 id="section-editing-options">
<title>Options for editing text</title>
<para>
&medit; has some editing options which can be set in the document text,
or in the <guilabel>Preferences</guilabel> dialog for sets of files or for given syntax
highlighting language.
</para>
<para>
To set the options in the document text, place the following on the first,
second or the last line of the document:
<programlisting>
-%- <parameter>options</parameter> -%-
</programlisting>
where <parameter>options</parameter> is the option string
<programlisting>
<parameter>key</parameter>: <parameter>value</parameter>; <parameter>key</parameter>: <parameter>value</parameter>; ...
</programlisting>
(the latter is the format used also in the <guilabel>Preferences</guilabel> dialog).
</para>
<para>
For example, the following might be the first line in a C file:
<programlisting>
/* -%- indent-width: 2; use-tabs: yes; strip: yes -%- */
</programlisting>
</para>
<para>
Values can be strings, integers, or booleans.
</para>
<para>
Booleans are <code>yes</code>, <code>no</code>, <code>true</code>, <code>false</code>, <code>1</code>, <code>0</code>.
</para>
<para>
If a string value contains <code>:</code> character, then the following syntax may be used:
<code><parameter>key</parameter>=/<parameter>value</parameter>/</code>. Any character may be used instead of slash (and it
must not occur in the <parameter>value</parameter>). Example: <code>word-chars=@-/:@</code>
</para>
<para>
The following options are available:
<variablelist>
<?dbhtml list-presentation="table"?>
<?dbhtml term-separator=" : "?>
<varlistentry>
<term><code>lang</code></term>
<listitem><para>syntax highlighting language to use in this document. Special value <code>none</code> will
turn off syntax highlighting in this document.</para></listitem>
</varlistentry>
<varlistentry>
<term><code>strip</code></term>
<listitem><para>a boolean value, whether trailing whitespace should be removed from the document on save.</para></listitem>
</varlistentry>
<varlistentry>
<term><code>add-newline</code></term>
<listitem><para>a boolean value, whether the editor should ensure that saved files have a trailing new line character.</para></listitem>
</varlistentry>
<varlistentry>
<term><code>indent-width</code></term>
<listitem><para>an integer specifying indentation offset used when the Tab key is pressed to indent text.</para></listitem>
</varlistentry>
<varlistentry>
<term><code>tab-width</code></term>
<listitem><para>displayed width of the tab character. Note that this is <emphasis>not</emphasis> the same as
<code>indent-width</code>.</para></listitem>
</varlistentry>
<varlistentry>
<term><code>use-tabs</code></term>
<listitem><para>whether tab character should be used for indentation.</para></listitem>
</varlistentry>
</variablelist>
</para>
<para>
&medit; tries to understand modelines of Vim, Emacs, and Kate text editors, so chances are it will correctly
pick up the conventional settings from source files.
</para>
</sect1>
<sect1 id="section-prefs-xml">
<title>Preferences files</title>
<para>
&medit; preferences are stored in &medit-prefs-xml-unix; file.
It is an XML file which may be edited to set preferences which have not found
their place in the <guilabel>Preferences</guilabel> dialog.
</para>
<note>
<para>
&medit; reads the preferences file on startup and writes it whenever <guilabel>OK</guilabel>
or <guilabel>Apply</guilabel> button is clicked in the <guilabel>Preferences</guilabel> dialog. Therefore, if you
modify the preferences file, your changes may be overwritten, and they not take
effect until you restart &medit;.
</para>
</note>
<para>
The following "hidden" settings are available:
<variablelist>
<?dbhtml term-separator=" : "?>
<varlistentry>
<term><parameter>Editor/window_title</parameter></term>
<listitem><para>Format of the window title. It is a string which may
contain format sequences, which are percent sign followed by a character:
<variablelist>
<?dbhtml list-presentation="table"?>
<?dbhtml term-separator=" : "?>
<varlistentry>
<term><code>%a</code></term>
<listitem>application name</listitem>
</varlistentry>
<varlistentry>
<term><code>%b</code></term>
<listitem>current document basename</listitem>
</varlistentry>
<varlistentry>
<term><code>%f</code></term>
<listitem>full path of the current document</listitem>
</varlistentry>
<varlistentry>
<term><code>%u</code></term>
<listitem>URI of the current document</listitem>
</varlistentry>
<varlistentry>
<term><code>%s</code></term>
<listitem>the status of the current document, e.g. "<code> [modified]</code>". It is prefixed
with a space, so that "<code>%b%s</code>" produces a nice string</listitem>
</varlistentry>
<varlistentry>
<term><code>%%</code></term>
<listitem>the percent character</listitem>
</varlistentry>
</variablelist>
Default value is "<code>%a - %f%s</code>" which produces something like "<code>medit - /home/user/file [modified]</code>".
</para></listitem>
</varlistentry>
<varlistentry>
<term><parameter>Editor/window_title_no_doc</parameter></term>
<listitem><para>same as <parameter>Editor/window_title</parameter>, used when no document is open.
Default value is "<code>%a</code>".</para></listitem>
</varlistentry>
</variablelist>
</para>
</sect1>
</chapter>

23
doc/regex.docbook Normal file
View File

@ -0,0 +1,23 @@
<?xml version="1.0"?>
<!DOCTYPE chapter [
<!ENTITY % medit-defines SYSTEM "built/medit-defines.ent">
%medit-defines;
]>
<chapter id="chapter-regex">
<title>Regular expressions</title>
<para>
&medit; uses regular expressions functionality provided by Glib, which in turn uses
<ulink url="http://pcre.org/">PCRE</ulink> library. See
<ulink url="http://library.gnome.org/devel/glib/stable/glib-regex-syntax.html">Glib manual</ulink>
for complete description of regular expression syntax.
</para>
<para>
Regular expression searches in a document text are limited to single lines, unless the
search pattern includes newline character. For example, pattern "<code>.*</code>" will match every
line in the document, pattern "<code>.*\n.*</code>" will match pairs of consecutive lines. This means
that it is mostly impossible to perform searches for text which spawns multiple lines.
</para>
</chapter>

34
doc/script-book.xsl Normal file
View File

@ -0,0 +1,34 @@
<?xml version='1.0'?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/chunk.xsl"/>
<xsl:param name="html.stylesheet" select="'../medit.css'"/>
<xsl:output method="html" indent="yes"/>
<xsl:param name="chunker.output.indent" select="'yes'"/>
<xsl:param name="base.dir" select="'help/script/'"/>
<xsl:param name="chunk.first.sections" select="'1'"/>
<xsl:param name="toc.section.depth" select="1"/>
<xsl:param name="generate.section.toc.level" select="1"/>
<!--<xsl:param name="variablelist.as.table" select="1"/>-->
<!-- <xsl:template match="sect1">
<xsl:if test="preceding-sibling::sect1">
<hr/>
</xsl:if>
<xsl:apply-imports/>
</xsl:template>-->
<xsl:template match="sect2">
<xsl:if test="preceding-sibling::sect2">
<hr/>
</xsl:if>
<xsl:apply-imports/>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE chapter [
<!ENTITY % medit-defines SYSTEM "medit-defines.ent">
%medit-defines;
]>
<chapter id="chapter-script-lua-gtk">
<?dbhtml filename="lua-gtk.html"?>
<title>Gtk API for Lua scripts</title>
<sect1>
<title>Introduction</title>
<para>Lua scripts running in &medit; have a limited access to
<ulink url="http://www.gtk.org/">Gtk</ulink> functionality
exposed through <code>gtk</code> package in addition to functions in
<link linkend="chapter-script-lua"><code>moo</code> package</link>.
It is not a goal to provide complete Lua bindings for Gtk,
and it is not a goal to enable creating UI in Lua scripts.
If there is a demand, &medit; might bind more Gtk functionality,
but so far Lua in &medit; is supposed to be lean and mean
scripting language which is always available. Use Python if
you need more functionality.</para>
<para>
Notations used in this manual are described
<link linkend="section-script-lua-notations">here</link>.
</para>
</sect1>
###GENERATED###
</chapter>

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE article [
<!ENTITY % medit-defines SYSTEM "medit-defines.ent">
%medit-defines;
]>
<chapter id="chapter-script-lua">
<?dbhtml filename="lua-moo.html"?>
<title>&medit; Lua API</title>
<sect1 id="section-script-lua-introduction">
<title>Introduction</title>
<para>Lua scripts running in &medit; have access to its
functionality through the <code>moo</code> package.</para>
<warning>
Functions which are not documented here may or may not work differently in
the future and they may disappear without notice. Contact the author if you
need functions which are not present here.
</warning>
</sect1>
<sect1 id="section-script-lua-object-model">
<title>&medit; object model</title>
<para>&medit; uses a very simple object model where its objects are
represented as user data in Lua and methods are provided via metatable
shared by all objects of all "classes". Method dispatch is dynamic,
i.e. metatable does not contain functions which correspond to methods,
and <code>obj:method</code> returns a function object which knows which
method on which object it is going to call.</para>
<para>This manual lists and talks about "classes", but it is merely
to avoid complicated terminology. When we say that an object belongs
to or is an instance of a class <code>Foo</code>, it just means that
it has methods listed in manual section for class <code>Foo</code>
and methods of parent classes, if any.</para>
<note>
To call a method, you can use both <code>obj:method(args)</code>
and <code>obj.method(args)</code>.
</note>
</sect1>
<sect1 id="section-script-lua-notations">
<title>Notations</title>
<para>This manual uses the following conventions:</para>
<variablelist>
<varlistentry>
<term>Optional parameters</term>
<listitem>
<programlisting>func(arg1=val1, arg2=val, arg3=val3)</programlisting>
<code><parameter>arg</parameter>=val</code> means that
parameter <parameter>arg</parameter> is optional, and function receives
value <code>val</code> if it's missing. Not all parameters are necessarily
optional. For example, <programlisting>insert_text(text, where=nil)</programlisting>
means that <parameter>text</parameter> may not be missing or <constant>nil</constant>
(unless documentation says otherwise), and <parameter>where</parameter> is optional.
</listitem>
</varlistentry>
<varlistentry>
<term>Keyword parameters</term>
<listitem>
<programlisting>func{arg1, arg2, kwarg1=kwval1, kwarg2=kwval2}</programlisting>
This means that function can be called in an alternative way: actual parameters are
taken from the single table parameter, which must be a dictionary with keys
<parameter>kwarg1</parameter>, <parameter>kwarg2</parameter>, etc., and whose array part
must contain exactly as many values as there are non-optional arguments. Similarly
to regular parameters, <code><parameter>kwarg</parameter>=kwval</code> means that
<parameter>kwarg</parameter> is optional. For example, above function can be called
as follows.
<programlisting>
<!-- -->func{1, 2, kwarg1='foo'} -- equivalent to func(1, 2, 'foo')
<!-- -->func{3, 4, kwarg2='bar'} -- equivalent to func(3, 4, kwval1, 'bar')
<!-- -->func{5, 6, kwarg2='baz', kwarg1='bud', } -- equivalent to func(5, 6, 'bud', 'baz')</programlisting>
This is similar to Python keyword arguments (with the difference that keyword arguments
may be used only if function is documented to support them).
</listitem>
</varlistentry>
</variablelist>
</sect1>
###GENERATED###
</chapter>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE chapter [
<!ENTITY % medit-defines SYSTEM "medit-defines.ent">
%medit-defines;
]>
<chapter id="chapter-script-python">
<?dbhtml filename="python-moo.html"?>
<title>&medit; Python API</title>
<sect1>
<title>Introduction</title>
<para>When compiled with Python support, &medit; uses
<ulink url="http://www.pygtk.org/">PyGtk</ulink>. Its functionality is
exposed through <code>moo</code> module. You can use built-in Python console
available from <guimenu>Tools</guimenu> menu to experiment with &medit; API.</para>
<note>
Classes and functions documented here are guaranteed to work as long as you
follow the rules from their documentation (most often there are no special
rules, but for some functions you may or may not use named arguments, etc.)
</note>
<warning>
<code>moo</code> module has more classes and functions than documented here,
but undocumented classes and functions may or may not work differently in
the future and they may disappear without notice. Contact the author if you
need functions which are not present here.
</warning>
</sect1>
###GENERATED###
</chapter>

18
doc/script.docbook Normal file
View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?><!-- -%- indent-width:1 -%- -->
<!DOCTYPE book [
<!ENTITY % medit-defines SYSTEM "built/medit-defines.ent">
%medit-defines;
]>
<book id="medit-scripting-manual">
<bookinfo>
<title>&medit; scripting manual</title>
<date>1/22/2011</date>
<releaseinfo>&medit-version;</releaseinfo>
</bookinfo>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="built/script-lua.docbook"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="built/script-lua-gtk.docbook"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="built/script-python.docbook"/>
</book>

26
doc/script.xsl Normal file
View File

@ -0,0 +1,26 @@
<?xml version='1.0'?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"/>
<xsl:param name="html.stylesheet" select="'medit.css'"/>
<xsl:output method="html" indent="yes"/>
<!--<xsl:param name="variablelist.as.table" select="1"/>-->
<xsl:template match="sect1">
<xsl:if test="preceding-sibling::sect1">
<hr/>
</xsl:if>
<xsl:apply-imports/>
</xsl:template>
<!-- <xsl:template match="sect2">
<xsl:if test="preceding-sibling::sect2">
<hr/>
</xsl:if>
<xsl:apply-imports/>
</xsl:template>-->
</xsl:stylesheet>

406
doc/user-tools.docbook Normal file
View File

@ -0,0 +1,406 @@
<?xml version="1.0"?><!-- -%- indent-width:2 -%- -->
<!DOCTYPE chapter [
<!ENTITY % medit-defines SYSTEM "built/medit-defines.ent">
%medit-defines;
]>
<chapter id="chapter-user-tools" moo.helpsection="USER_TOOLS">
<title>User-defined tools</title>
<para>
&medit; allows extending its functionality with user-defined
<parameter>tools</parameter>. It can be a Lua script or a Python script (if &medit; has been
built with Python support) which are executed inside &medit;,
or a shell script which can use the text of the open document as
its input and/or output.
</para>
<para>
There are some predefined tools which you can use as
an example or to modify to suit your needs.
</para>
<sect1 id="section-prefs-user-tools" moo.helpsection="PREFS_USER_TOOLS">
<title>Managing tools in <guilabel>Preferences</guilabel> dialog</title>
<para>
To create a new tool or to modify existing ones, open
<guilabel>Preferences</guilabel> dialog and select <guilabel>Tools</guilabel> in the list on the left.
</para>
<para>
Select the tool in the list or click the <guibutton>New</guibutton>
button to create a new one. To modify the order in which tools
appear in the <guimenu>Tools</guimenu> menu (or in the document
context menu), use <guibutton>Up</guibutton> and <guibutton>Down</guibutton> buttons. To rename a tool,
click its name in the list to select it and then click again to
edit the name. Use the <guibutton>Delete</guibutton> button to delete a tool.
</para>
<para>
The following controls are available to modify tools:
<itemizedlist>
<listitem>
<para>
<parameter><guilabel>Files</guilabel></parameter> entry specifies for which files the tool is going to be available. It can
contain the following:
<itemizedlist>
<listitem>a comma-separated list of file patterns, e.g. <programlisting><code>*.c,*.h</code></programlisting></listitem>
<listitem>a comma-separated list of languages prefixed with "<code>langs:</code>", e.g.
<programlisting><code>langs: c, c++, objc</code></programlisting></listitem>
<listitem>a regular expression matching document filename prefixed with "<code>regex:</code>", e.g. the above
pattern list may be written as <programlisting><code>regex:\.[ch]$</code></programlisting></listitem>
</itemizedlist>
</para>
<para>Empty entry means that the tool will be available for all documents.</para>
</listitem>
<listitem>
<parameter><guilabel>Requires</guilabel></parameter> combo box specifies whether the tool should be
enabled depending on current document.
<variablelist>
<?dbhtml list-presentation="table"?>
<!-- <?dbhtml term-separator=" : "?>-->
<varlistentry>
<term><parameter>Nothing</parameter></term>
<listitem>the tool is enabled regardless whether there is an open document.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>Document</parameter></term>
<listitem>the tool is enabled only if there is an open document. For example, if the tool manipulates
current document text, then it needs a document to be there.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>File on disk</parameter></term>
<listitem>the tool is enabled only if current document is saved on disk (i.e. it is not "Untitled").
For example, to compile a TeX file, it needs to be saved first.</listitem>
</varlistentry>
</variablelist>
</listitem>
<listitem>
<parameter><guilabel>Save</guilabel></parameter> combo box specifies what should be saved every time
before the command is executed.
<variablelist>
<?dbhtml list-presentation="table"?>
<!-- <?dbhtml term-separator=" : "?>-->
<varlistentry>
<term><parameter>Nothing</parameter></term>
<listitem>nothing will be saved.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>Current document</parameter></term>
<listitem>current document will be automatically saved. For example, you probably want to save currrent
document before compiling it with latex.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>All documents</parameter></term>
<listitem>all open documents will be automatically saved. For example, if the tool builds a C project, then
you probably want to save all open files before running make.</listitem>
</varlistentry>
</variablelist>
</listitem>
<listitem>
<parameter><guilabel>Type</guilabel></parameter> combo specifies the type of the tool: a Python script, a
Lua script, or a shell script.
</listitem>
<listitem>
<guilabel>Code</guilabel> text field contains script or shell command text. See
<xref linkend="section-user-tools-shell"/>, <xref linkend="section-user-tools-lua"/>,
<xref linkend="section-user-tools-python"/> for details on what can be here.
</listitem>
</itemizedlist>
</para>
</sect1>
<sect1 id="section-storing-tools-in-files">
<title>Storing tools in files</title>
<para>
It is possible to create tools without using the <guilabel>Preferences</guilabel> dialog,
they can be stored in files in <filename>tools</filename> subfolder of the &medit; data
folders (or <filename>tools-context</filename> for tools which appear in the document context
menu). In particular, on Unix systems you can place files into &medit-user-tools-dir-unix; folder.
</para>
<para>
Names of the files in the <filename>tools</filename> folder are used as their menu item
labels, after stripping first three characters, so you can use trhee-character
prefix to affect the order of the menu items, e.g. you can have <filename>00-Do Something</filename>,
<filename>01-Another tool</filename> files to have them in that order in the menu. The files
may be of three types:
<itemizedlist>
<listitem>files with extension "<filename>.py</filename>", they will be used
as Python scripts;</listitem>
<listitem>files with extension "<filename>.lua</filename>", they will be used
as Lua scripts;</listitem>
<listitem>executable files, they will be executed in the same way
as shell commands.</listitem>
</itemizedlist>
</para>
<para>
Note that files with <filename>.py</filename> and <filename>.lua</filename> extensions will be
executed inside &medit; process; if you want to use them as regular scripts, then just remove the
extension.
</para>
<para>
To set parameters for a tool, place them on the first or the second line of the file in
the following format:
<programlisting>
!! <parameter>key</parameter>=<parameter>value</parameter>; <parameter>key</parameter>=<parameter>value</parameter>; ... !!
</programlisting>
</para>
<para>
<parameter>key</parameter> may be one of the following:
<variablelist>
<?dbhtml list-presentation="table"?>
<varlistentry>
<term><code>position</code></term>
<listitem>it can be <code>start</code> or <code>end</code>, and it defines whether the menu item
will be located at the start or at the end of the menu.</listitem>
</varlistentry>
<varlistentry>
<term><code>id</code></term>
<listitem>the tool identificator.</listitem>
</varlistentry>
<varlistentry>
<term><code>name</code></term>
<listitem>the tool name, i.e. the label used in the menu item. Overrides the file name.</listitem>
</varlistentry>
<varlistentry>
<term><code>accel</code></term>
<listitem>default keyboard accelerator used to invoke this tool.</listitem>
</varlistentry>
<varlistentry>
<term><code>menu</code></term>
<listitem>the menu to place this tool into. By default tools are located in the <guimenu>Tools</guimenu> menu,
but they can be as well put into any other menu.</listitem>
</varlistentry>
<varlistentry>
<term><code>langs</code></term>
<listitem>comma-separated list of languages for which this tool will be enabled.</listitem>
</varlistentry>
<varlistentry>
<term><code>file-filter</code></term>
<listitem>defines for which files this tool will be enabled. The value has the same format as
in the <guilabel>Preferences</guilabel> dialog.</listitem>
</varlistentry>
<varlistentry>
<term><code>options</code></term>
<listitem>this corresponds to Requires and Save controls in the <guilabel>Preferences</guilabel> dialog. It is a
comma-separated list of the following:
<variablelist>
<?dbhtml list-presentation="table"?>
<varlistentry>
<term><code>need-doc</code></term>
<listitem>tool will be enabled only if there is an open document.</listitem>
</varlistentry>
<varlistentry>
<term><code>need-file</code></term>
<listitem>tool will be enabled only if current document is saved on disk (i.e. it is not "Untitled").</listitem>
</varlistentry>
<varlistentry>
<term><code>need-save</code></term>
<listitem>current document will be automatically saved before the command is executed.</listitem>
</varlistentry>
<varlistentry>
<term><code>need-save-all</code></term>
<listitem>all open documents will be automatically saved before the command is executed.</listitem>
</varlistentry>
</variablelist>
</listitem>
</varlistentry>
</variablelist>
</para>
<para>
In addition to these, you can set input and output options for executable files (see <xref linkend="section-user-tools-shell"/>
for the meaning of these options):
<variablelist>
<?dbhtml list-presentation="table"?>
<varlistentry>
<term><code>input</code></term>
<listitem><code>none</code>, <code>lines</code>, <code>selection</code>, or <code>doc</code>.</listitem>
</varlistentry>
<varlistentry>
<term><code>output</code></term>
<listitem><code>none</code>, <code>async</code>, <code>pane</code>, <code>insert</code>, or <code>new-doc</code>.</listitem>
</varlistentry>
<varlistentry>
<term><code>filter</code></term>
<listitem>output filter name.</listitem>
</varlistentry>
</variablelist>
</para>
</sect1>
<sect1 id="section-user-tools-shell">
<title>Shell scripts</title>
<para>
Shell script user tools execute command entered in the <guilabel>Command</guilabel>
text field using default user shell on Unix systems or <command>cmd.exe</command> on Windows.
</para>
<para>
Its input and output are specified by the following controls:
<itemizedlist>
<listitem>
<parameter><guilabel>Input</guilabel></parameter> entry specifies what text from the document should be passed to the command.
The text is passed via command's standard input, except for <parameter>Document copy</parameter> case.
<variablelist>
<?dbhtml list-presentation="table"?>
<varlistentry>
<term><parameter>None</parameter></term>
<listitem>no input text.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>Selected lines</parameter></term>
<listitem>the lines containing selection or the line containing the cursor in
case when no text is selected.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>Selection</parameter></term>
<listitem>exact selected text. This will be different from <parameter>Selected lines</parameter>
if selection does not span whole lines of the document, for instance if it is a single word.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>Whole document</parameter></term>
<listitem>whole document contents.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>Document copy</parameter></term>
<listitem>document contents will be saved to a temporary file and the file path will be stored
in <envar>INPUT_FILE</envar> environment variable. No text will be passed to the command via standard
input.</listitem>
</varlistentry>
</variablelist>
</listitem>
<listitem>
<parameter><guilabel>Output</guilabel></parameter> entry specifies how the standard output of the command should be redirected.
<variablelist>
<?dbhtml list-presentation="table"?>
<varlistentry>
<term><parameter>None</parameter></term>
<listitem>the command output will be discarded.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>None, asynchronous</parameter></term>
<listitem>the command output will be discarded, and the command will be executed in background.
Use this if you need to launch some external program like a web browser.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>Output pane</parameter></term>
<listitem>the command output will be displayed in an output pane. This is useful for running programs
like compilers, where you want to see the output.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>Insert into the document</parameter></term>
<listitem>output will be inserted into the current document at the cursor position. It will replace the
text used as an input, if any.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>New document</parameter></term>
<listitem>new document will be created and the command output will be inserted into it.</listitem>
</varlistentry>
</variablelist>
</listitem>
<listitem>
<parameter><guilabel>Filter</guilabel></parameter> combo. If the output pane is used, then it can be passed through a
<parameter>filter</parameter>: the filter can match filenames and line numbers, so when you click
the text in the output pane it will open the corresponding file. This is used for compilers and
similar commands, which output locations of errors in processed files.
</listitem>
</itemizedlist>
</para>
<para>
Shell script user tools have a number of environment variables set.
<envar>APP_PID</envar> variable is set so that opening a file in the same instance
of &medit; is as simple as <code>medit filename</code> (on the other hand, you will
have to use command line options if you need to run a new &medit; instance). The
following environment variables are set when scripts are executed:
<variablelist>
<?dbhtml list-presentation="table"?>
<!-- <?dbhtml term-separator=" : "?>-->
<varlistentry>
<term><envar>APP_PID</envar></term>
<listitem>current process id.</listitem>
</varlistentry>
<varlistentry>
<term><envar>DOC</envar></term>
<listitem>document basename ("<filename>file.c</filename>" for file <filename>/home/user/file.c</filename>).</listitem>
</varlistentry>
<varlistentry>
<term><envar>DOC_DIR</envar></term>
<listitem>document directory ("<filename>/home/user</filename>" for file <filename>/home/user/file.c</filename>). Full file path is
<filename><envar>$DOC_DIR</envar>/<envar>$DOC</envar></filename>.</listitem>
</varlistentry>
<varlistentry>
<term><envar>DOC_BASE</envar></term>
<listitem>basename without extension ("<filename>file</filename>" for file <filename>/home/user/file.c</filename>).</listitem>
</varlistentry>
<varlistentry>
<term><envar>DOC_EXT</envar></term>
<listitem>document filename extension including the period ("<filename>.c</filename>" for file
<filename>/home/user/file.c</filename>). Basename is always
<filename><envar>$DOC_BASE</envar><envar>$DOC_EXT</envar></filename>.</listitem>
</varlistentry>
<varlistentry>
<term><envar>DOC_PATH</envar></term>
<listitem>full document path.</listitem>
</varlistentry>
<varlistentry>
<term><envar>LINE</envar></term>
<listitem><constant>1</constant>-based number of the line containing cursor.
For example, if cursor is at the first line then <envar>LINE</envar> will be
set to <constant>1</constant>.</listitem>
</varlistentry>
<varlistentry>
<term><envar>LINE0</envar></term>
<listitem><constant>0</constant>-based number of the line containing cursor.
For example, if cursor is at the first line then <envar>LINE0</envar> will be
set to <constant>0</constant>.</listitem>
</varlistentry>
<varlistentry>
<term><envar>DATA_DIR</envar></term>
<listitem>user data directory (&medit-user-data-dir-unix; on Unix systems).</listitem>
</varlistentry>
<varlistentry>
<term><envar>INPUT_FILE</envar></term>
<listitem>if <parameter>input</parameter> was set to "Document copy" then this is set to
full path of the temporary file containing document text.</listitem>
</varlistentry>
</variablelist>
</para>
<para>
Additionally, all shell commands which run inside &medit; will have
<filename><envar>DATA_DIR</envar>/scripts</filename>
directories in <envar>$PATH</envar>, so you may place some &medit;-specific programs
or scripts into <filename><envar>DATA_DIR</envar>/scripts/</filename> to be used from shell script tools.
</para>
</sect1>
<sect1 id="section-user-tools-lua">
<title>Lua scripts</title>
<para>
<ulink url="script/lua-moo.html">Medit API for Lua scripts</ulink>.
</para>
<para>
<ulink url="script/lua-gtk.html">Gtk API for Lua scripts</ulink>.
</para>
</sect1>
<sect1 id="section-user-tools-python">
<title>Python scripts</title>
<para>
<ulink url="script/python-moo.html">Medit API for Python scripts</ulink>.
</para>
</sect1>
</chapter>

19
getoutput.py Normal file
View File

@ -0,0 +1,19 @@
import subprocess
import sys
import os
#print "Output file:", sys.argv[1]
#print "Working dir:", os.getcwd()
#print "Executing command:", sys.argv[2:]
output = subprocess.check_output(sys.argv[2:], stdin=None, shell=False, universal_newlines=False)
output = output.replace('\r\n', '\n').replace('\r', '\n')
filename = sys.argv[1]
tmp = filename + '.tmp'
if not os.path.exists(os.path.dirname(tmp)):
os.makedirs(os.path.dirname(tmp))
with open(tmp, 'w') as f:
f.write(output)
if os.path.exists(filename):
os.remove(filename)
os.rename(tmp, filename)

7
hgrc Normal file
View File

@ -0,0 +1,7 @@
[paths]
default = ssh://hg@bitbucket.org/medit/medit
[hooks]
# Reject commits which would introduce windows-style text" files
pretxncommit.crlf = python:hgext.win32text.forbidcrlf
pretxncommit.glade = tools/checkglade

269
m4/moo-flags.m4 Normal file
View File

@ -0,0 +1,269 @@
AC_DEFUN([_MOO_AC_CHECK_C_COMPILER_OPTIONS],[
AC_LANG_PUSH([C])
for opt in $1; do
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $opt"
if test "x$MOO_STRICT_MODE" = "xyes"; then
CFLAGS="-Werror $CFLAGS"
fi
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[MOO_CFLAGS="$MOO_CFLAGS $opt"],[:])
CFLAGS="$save_CFLAGS"
done
AC_LANG_POP([C])
])
AC_DEFUN([_MOO_AC_CHECK_CXX_COMPILER_OPTIONS],[
AC_LANG_PUSH([C++])
for opt in $1; do
save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $opt"
if test "x$MOO_STRICT_MODE" = "xyes"; then
CXXFLAGS="-Werror $CXXFLAGS"
fi
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[MOO_CXXFLAGS="$MOO_CXXFLAGS $opt"],[:])
CXXFLAGS="$save_CXXFLAGS"
done
AC_LANG_POP([C++])
])
# _MOO_AC_CHECK_COMPILER_OPTIONS(options)
AC_DEFUN([_MOO_AC_CHECK_COMPILER_OPTIONS],[
_MOO_AC_CHECK_C_COMPILER_OPTIONS([$1])
_MOO_AC_CHECK_CXX_COMPILER_OPTIONS([$1])
])
AC_DEFUN([MOO_COMPILER],[
# icc pretends to be gcc or configure thinks it's gcc, but icc doesn't
# error on unknown options, so just don't try gcc options with icc
MOO_ICC=false
MOO_GCC=false
if test "$CC" = "icc"; then
MOO_ICC=true
elif test "x$GCC" = "xyes"; then
MOO_GCC=true
fi
])
##############################################################################
# MOO_AC_DEBUG()
#
AC_DEFUN_ONCE([MOO_AC_DEBUG],[
MOO_DEBUG_ENABLED="no"
AC_ARG_ENABLE(debug,
AS_HELP_STRING([--enable-debug],[enable debug options (default = NO)]),[
if test "$enableval" = "xno"; then
MOO_DEBUG_ENABLED="no"
else
MOO_DEBUG_ENABLED="yes"
fi
],[
MOO_DEBUG_ENABLED="no"
])
AM_CONDITIONAL(MOO_DEBUG_ENABLED, test x$MOO_DEBUG_ENABLED = "xyes")
AC_ARG_ENABLE(dev-mode,
AS_HELP_STRING([--enable-dev-mode],[dev-mode (default = NO, unless --enable-debug is used)]),[
if test "$enableval" = "xno"; then
MOO_DEV_MODE="no"
else
MOO_DEV_MODE="yes"
fi
],[
MOO_DEV_MODE="$MOO_DEBUG_ENABLED"
])
AM_CONDITIONAL(MOO_DEV_MODE, test x$MOO_DEV_MODE = "xyes")
AC_ARG_ENABLE(strict,
AS_HELP_STRING([--enable-strict],[enable all warnings and -Werror (default = NO)]),[
if test "$enableval" = "xno"; then
MOO_STRICT_MODE="no"
else
MOO_STRICT_MODE="yes"
fi
],[
MOO_STRICT_MODE="no"
])
AM_CONDITIONAL(MOO_STRICT_MODE, test x$MOO_STRICT_MODE = "xyes")
MOO_COMPILER
_MOO_AC_CHECK_COMPILER_OPTIONS([dnl
-Wall -Wextra -fexceptions -fno-strict-aliasing dnl
-Wno-missing-field-initializers dnl
-Wno-format-y2k -Wno-overlength-strings dnl
-Wno-deprecated-declarations dnl
])
_MOO_AC_CHECK_CXX_COMPILER_OPTIONS([dnl
-std=c++11 -fno-rtti dnl
])
if test "x$MOO_DEBUG_ENABLED" = "xyes"; then
_MOO_AC_CHECK_COMPILER_OPTIONS([-ftrapv])
else
_MOO_AC_CHECK_CXX_COMPILER_OPTIONS([-fno-enforce-eh-specs])
fi
if test "x$MOO_STRICT_MODE" = "xyes"; then
if $MOO_GCC; then
MOO_CFLAGS="$MOO_CFLAGS -Werror"
MOO_CXXFLAGS="$MOO_CXXFLAGS -Werror"
fi
_MOO_AC_CHECK_COMPILER_OPTIONS([dnl
-Wpointer-arith -Wsign-compare -Wreturn-type dnl
-Wwrite-strings -Wmissing-format-attribute dnl
-Wdisabled-optimization -Wendif-labels dnl
-Wvla -Winit-self dnl
])
# -Wlogical-op triggers warning in strchr() when compiled with optimizations
if test "x$MOO_DEBUG_ENABLED" = "xyes"; then
_MOO_AC_CHECK_COMPILER_OPTIONS([-Wlogical-op])
else
_MOO_AC_CHECK_COMPILER_OPTIONS([-Wuninitialized])
fi
_MOO_AC_CHECK_C_COMPILER_OPTIONS([dnl
-Wmissing-prototypes -Wnested-externs -Wnolong-long dnl
])
_MOO_AC_CHECK_CXX_COMPILER_OPTIONS([dnl
-fno-nonansi-builtins -fno-gnu-keywords dnl
-Wctor-dtor-privacy -Wabi -Wstrict-null-sentinel dnl
-Woverloaded-virtual -Wsign-promo -Wnon-virtual-dtor dnl
-Wno-long-long dnl
])
fi
# m4_foreach([wname],[unused, sign-compare, write-strings],[dnl
# m4_define([_moo_WNAME],[MOO_W_NO_[]m4_bpatsubst(m4_toupper(wname),-,_)])
# _moo_WNAME=
# _MOO_AC_CHECK_COMPILER_OPTIONS(_moo_WNAME,[-Wno-wname])
# AC_SUBST(_moo_WNAME)
# m4_undefine([_moo_WNAME])
# ])
if test "x$MOO_DEBUG_ENABLED" = "xyes"; then
MOO_CPPFLAGS="$MOO_CPPFLAGS -DENABLE_DEBUG -DENABLE_PROFILE -DG_ENABLE_DEBUG dnl
-DG_ENABLE_PROFILE -DMOO_DEBUG -DDEBUG"
else
MOO_CPPFLAGS="$MOO_CPPFLAGS -DNDEBUG=1 -DG_DISABLE_CAST_CHECKS -DG_DISABLE_ASSERT"
fi
])
##############################################################################
# MOO_AC_SET_DIRS
#
AC_DEFUN_ONCE([MOO_AC_SET_DIRS],[
if test "x$MOO_PACKAGE_NAME" = x; then
AC_MSG_ERROR([MOO_PACKAGE_NAME not set])
fi
AC_SUBST(MOO_PACKAGE_NAME)
AC_DEFINE_UNQUOTED([MOO_PACKAGE_NAME], "$MOO_PACKAGE_NAME", [data goes into /usr/share/$MOO_PACKAGE_NAME, etc.])
AC_SUBST(MOO_DATA_DIR, "${datadir}/$MOO_PACKAGE_NAME")
AC_SUBST(MOO_LIB_DIR, "${libdir}/$MOO_PACKAGE_NAME")
AC_SUBST(MOO_DOC_DIR, "${datadir}/doc/$MOO_PACKAGE_NAME")
AC_SUBST(MOO_HELP_DIR, "${MOO_DOC_DIR}/help")
AC_SUBST(MOO_TEXT_LANG_FILES_DIR, "${MOO_DATA_DIR}/language-specs")
AC_DEFINE_UNQUOTED([MOO_PREFS_XML_FILE_NAME], "$MOO_PREFS_XML_FILE_NAME", [prefs.xml])
AC_DEFINE_UNQUOTED([MOO_STATE_XML_FILE_NAME], "$MOO_STATE_XML_FILE_NAME", [state.xml])
AC_DEFINE_UNQUOTED([MOO_SESSION_XML_FILE_NAME], "$MOO_SESSION_XML_FILE_NAME", [session.xml])
AC_DEFINE_UNQUOTED([MOO_NAMED_SESSION_XML_FILE_NAME], "$MOO_NAMED_SESSION_XML_FILE_NAME", [session-%s.xml])
AC_DEFINE_UNQUOTED([MEDIT_PORTABLE_MAGIC_FILE_NAME], "$MEDIT_PORTABLE_MAGIC_FILE_NAME", [file which enables portable mode])
AC_DEFINE_UNQUOTED([MEDIT_PORTABLE_DATA_DIR], "$MEDIT_PORTABLE_DATA_DIR", [prefs files are saved in this directory])
AC_DEFINE_UNQUOTED([MEDIT_PORTABLE_CACHE_DIR], "$MEDIT_PORTABLE_CACHE_DIR", [cache files are saved in this directory])
AC_SUBST(MOO_PYTHON_PLUGIN_DIR, "${MOO_DATA_DIR}/plugins")
AC_SUBST(MOO_PYTHON_LIB_DIR, "${MOO_DATA_DIR}/python")
])
##############################################################################
# MOO_AC_FLAGS(moo_top_dir)
#
AC_DEFUN_ONCE([MOO_AC_FLAGS],[
AC_REQUIRE([MOO_AC_CHECK_OS])
AC_REQUIRE([MOO_AC_SET_DIRS])
MOO_PKG_CHECK_GTK_VERSIONS
MOO_AC_DEBUG
AC_CHECK_FUNCS_ONCE(getc_unlocked)
AC_CHECK_HEADERS(unistd.h sys/utsname.h signal.h sys/wait.h)
AC_CHECK_FUNCS(mmap)
moo_top_src_dir=`cd $srcdir && pwd`
MOO_CFLAGS="$MOO_CFLAGS $GTK_CFLAGS"
MOO_CXXFLAGS="$MOO_CXXFLAGS $GTK_CFLAGS"
MOO_CPPFLAGS="$MOO_CPPFLAGS -I$moo_top_src_dir/moo -DXDG_PREFIX=_moo_edit_xdg -DG_LOG_DOMAIN=\\\"Moo\\\""
MOO_LIBS="$MOO_LIBS $GTK_LIBS $GTHREAD_LIBS $GMODULE_LIBS $LIBM"
if test "x$MOO_STRICT_MODE" != "xyes"; then
# G_DISABLE_DEPRECATED (or rather lack of it) is not respected anymore. Glib wants you
# to define it; if you don't, then you got to jump through additional hoops in order to
# really not disable deprecated stuff.
MOO_CPPFLAGS="$MOO_CPPFLAGS -DGLIB_DISABLE_DEPRECATION_WARNINGS=1"
else
#MOO_CPPFLAGS="$MOO_CPPFLAGS -DG_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED"
#MOO_CPPFLAGS="$MOO_CPPFLAGS -DGSEAL_ENABLE"
#MOO_CPPFLAGS="$MOO_CPPFLAGS -DGTK_DISABLE_SINGLE_INCLUDES"
true
fi
if $GDK_X11; then
_moo_x_pkgs=
m4_foreach([_pkg_],[x11, xext, xrender, ice, sm],[
PKG_CHECK_EXISTS(_pkg_,[_moo_x_pkgs="$_moo_x_pkgs _pkg_"],[:])
])
if test -n "$_moo_x_pkgs"; then
PKG_CHECK_MODULES(X,[$_moo_x_pkgs])
MOO_CFLAGS="$MOO_CFLAGS $X_CFLAGS"
MOO_CXXFLAGS="$MOO_CXXFLAGS $X_CFLAGS"
MOO_LIBS="$MOO_LIBS $X_LIBS"
fi
fi
if $MOO_OS_WIN32; then
MOO_CPPFLAGS="$MOO_CPPFLAGS -DUNICODE -D_UNICODE -DSTRICT -DWIN32_LEAN_AND_MEAN -I$moo_top_src_dir/moo/mooutils/moowin32/mingw"
# work around bug in i586-mingw32msvc-gcc-4.2.1-sjlj
# it defines __STRICT_ANSI__ for some reason and that
# breaks compilation:
# /usr/lib/gcc/i586-mingw32msvc/4.2.1-sjlj/include/c++/cwchar:164: error: ::swprintf has not been declared
# /usr/lib/gcc/i586-mingw32msvc/4.2.1-sjlj/include/c++/cwchar:171: error: ::vswprintf has not been declared
MOO_CPPFLAGS="$MOO_CPPFLAGS -U__STRICT_ANSI__"
MOO_LIBS="$MOO_LIBS -lmooglib"
fi
if $MOO_OS_UNIX; then
MOO_CPPFLAGS="$MOO_CPPFLAGS -DMOO_DATA_DIR=\\\"${MOO_DATA_DIR}\\\" -DMOO_LIB_DIR=\\\"${MOO_LIB_DIR}\\\""
MOO_CPPFLAGS="$MOO_CPPFLAGS -DMOO_LOCALE_DIR=\\\"${localedir}\\\" -DMOO_HELP_DIR=\\\"${MOO_HELP_DIR}\\\""
fi
MOO_CFLAGS="$MOO_CFLAGS $XML_CFLAGS"
MOO_CXXFLAGS="$MOO_CXXFLAGS $XML_CFLAGS"
MOO_LIBS="$MOO_LIBS $XML_LIBS"
AC_SUBST(MOO_CPPFLAGS)
AC_SUBST(MOO_CFLAGS)
AC_SUBST(MOO_CXXFLAGS)
AC_SUBST(MOO_LIBS)
# MOO_INI_IN_IN_RULE='%.ini.desktop.in: %.ini.desktop.in.in $(top_builddir)/config.status ; cd $(top_builddir) && $(SHELL) ./config.status --file=$(subdir)/[$]@'
# MOO_INI_IN_RULE='%.ini: %.ini.in $(top_builddir)/config.status ; cd $(top_builddir) && $(SHELL) ./config.status --file=$(subdir)/[$]@'
# MOO_WIN32_RC_RULE='%.res: %.rc.in $(top_builddir)/config.status ; cd $(top_builddir) && $(SHELL) ./config.status --file=$(subdir)/[$]*.rc && cd $(subdir) && $(WINDRES) -i [$]*.rc --input-format=rc -o [$]@ -O coff && rm [$]*.rc'
# AC_SUBST(MOO_INI_IN_IN_RULE)
# AC_SUBST(MOO_INI_IN_RULE)
# AC_SUBST(MOO_WIN32_RC_RULE)
# MOO_XML2H='$(top_srcdir)/moo/mooutils/xml2h.sh'
# MOO_GLADE_SUBDIR_RULE='%-glade.h: glade/%.glade $(MOO_XML2H) ; $(SHELL) $(top_srcdir)/moo/mooutils/xml2h.sh `basename "[$]*" | sed -e "s/-/_/"`_glade_xml [$]< > [$]@.tmp && mv [$]@.tmp [$]@'
# MOO_GLADE_RULE='%-glade.h: %.glade $(MOO_XML2H) ; $(SHELL) $(top_srcdir)/moo/mooutils/xml2h.sh `basename "[$]*" | sed -e "s/-/_/"`_glade_xml [$]< > [$]@.tmp && mv [$]@.tmp [$]@'
# AC_SUBST(MOO_XML2H)
# AC_SUBST(MOO_GLADE_SUBDIR_RULE)
# AC_SUBST(MOO_GLADE_RULE)
])

100
m4/moo-gtk.m4 Normal file
View File

@ -0,0 +1,100 @@
##############################################################################
# _MOO_SPLIT_VERSION(NAME,version)
#
AC_DEFUN([_MOO_SPLIT_VERSION],[AC_REQUIRE([LT_AC_PROG_SED])
$1[]_VERSION="$2"
$1[]_MAJOR_VERSION=`echo "$2" | $SED 's/\([[^.]][[^.]]*\).*/\1/'`
$1[]_MINOR_VERSION=`echo "$2" | $SED 's/[[^.]][[^.]]*.\([[^.]][[^.]]*\).*/\1/'`
$1[]_MICRO_VERSION=`echo "$2" | $SED 's/[[^.]][[^.]]*.[[^.]][[^.]]*.\(.*\)/\1/'`
])
##############################################################################
# _MOO_SPLIT_VERSION_PKG(PKG_NAME,pkg-name)
#
AC_DEFUN([_MOO_SPLIT_VERSION_PKG],[
AC_MSG_CHECKING($1 version)
_moo_ac_version=`$PKG_CONFIG --modversion $2`
_MOO_SPLIT_VERSION([$1],[$_moo_ac_version])
AC_MSG_RESULT($[]$1[]_MAJOR_VERSION.$[]$1[]_MINOR_VERSION.$[]$1[]_MICRO_VERSION)
])
##############################################################################
# MOO_CHECK_MINOR_VERSION(PKG_NAME,pkg-name,versions)
#
AC_DEFUN([MOO_CHECK_MINOR_VERSION],[
_MOO_SPLIT_VERSION_PKG($1,$2)
m4_foreach([num],[$3],
[AM_CONDITIONAL($1[]_2_[]num, test $[]$1[]_MINOR_VERSION -ge num)
if test $[]$1[]_MINOR_VERSION -ge num; then
$1[]_2_[]num=yes
fi
])
])
##############################################################################
# _MOO_CHECK_BROKEN_GTK_THEME
#
AC_DEFUN([_MOO_CHECK_BROKEN_GTK_THEME],[
AC_ARG_WITH([broken-gtk-theme], AS_HELP_STRING([--with-broken-gtk-theme],[Work around bug in gtk theme (Suse 9 has one)]), [
if test x$with_broken_gtk_theme = "xyes"; then
MOO_BROKEN_GTK_THEME="yes"
fi
])
if test x$MOO_BROKEN_GTK_THEME = xyes; then
AC_MSG_NOTICE([Broken gtk theme])
AC_DEFINE(MOO_BROKEN_GTK_THEME, 1, [broken gtk theme])
fi
])
##############################################################################
# MOO_PKG_CHECK_GTK_VERSIONS
#
AC_DEFUN_ONCE([MOO_PKG_CHECK_GTK_VERSIONS],[
AC_REQUIRE([MOO_AC_CHECK_OS])
PKG_CHECK_MODULES(GTK, gtk+-2.0)
PKG_CHECK_MODULES(GLIB, glib-2.0)
PKG_CHECK_MODULES(GTHREAD, gthread-2.0)
PKG_CHECK_MODULES(GMODULE, gmodule-2.0)
# PKG_CHECK_MODULES(GDK, gdk-2.0)
MOO_CHECK_MINOR_VERSION(GLIB, glib-2.0, [32])
PKG_CHECK_MODULES(XML, libxml-2.0)
_MOO_CHECK_BROKEN_GTK_THEME
gdk_target=`$PKG_CONFIG --variable=target gdk-2.0`
GDK_X11=false
GDK_WIN32=false
GDK_QUARTZ=false
case $gdk_target in
x11)
GDK_X11=true
;;
quartz)
GDK_QUARTZ=true
;;
win32)
GDK_WIN32=true
;;
esac
AM_CONDITIONAL(GDK_X11, $GDK_X11)
AM_CONDITIONAL(GDK_WIN32, $GDK_WIN32)
AM_CONDITIONAL(GDK_QUARTZ, $GDK_QUARTZ)
AC_SUBST(GLIB_GENMARSHAL, `$PKG_CONFIG --variable=glib_genmarshal glib-2.0`)
AC_SUBST(GLIB_MKENUMS, `$PKG_CONFIG --variable=glib_mkenums glib-2.0`)
AC_ARG_VAR([GDK_PIXBUF_CSOURCE], [gdk-pixbuf-csource])
AC_CHECK_TOOL(GDK_PIXBUF_CSOURCE, gdk-pixbuf-csource, [:])
if test "$GDK_PIXBUF_CSOURCE" = ":"; then
AC_MSG_ERROR([gdk-pixbuf-csource not found])
fi
])

32
m4/moo-intltool.m4 Normal file
View File

@ -0,0 +1,32 @@
AC_DEFUN([_MOO_INTLTOOL],[
AC_PATH_PROG(INTLTOOL_UPDATE, [intltool-update])
AC_PATH_PROG(INTLTOOL_MERGE, [intltool-merge])
AC_PATH_PROG(INTLTOOL_EXTRACT, [intltool-extract])
if test -z "$INTLTOOL_UPDATE" -o -z "$INTLTOOL_MERGE" -o -z "$INTLTOOL_EXTRACT"; then
AC_MSG_ERROR([The intltool scripts were not found. Please install intltool or use --disable-nls to ignore.])
fi
AC_SUBST(MOO_INTLTOOL_INI_DEPS,'$(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po)')
AC_SUBST(MOO_INTLTOOL_INI_CMD,'$(AM''_V_GEN)LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@')
])
AC_DEFUN([_MOO_INTLTOOL_NO_NLS],[
AC_SUBST(MOO_INTLTOOL_INI_DEPS,'')
AC_SUBST(MOO_INTLTOOL_INI_CMD,'$(AM''_V_GEN)sed -e "s/^_//g" $< > [$]@.tmp && mv [$]@.tmp [$]@')
])
AC_DEFUN([MOO_INTL],[
AM_GLIB_GNU_GETTEXT
AC_ARG_ENABLE([nls],AS_HELP_STRING([--disable-nls],[do not use Native Language Support]),[
ENABLE_NLS=$enableval
],[
ENABLE_NLS=yes
])
AC_SUBST([ENABLE_NLS])
if test "$ENABLE_NLS" = "yes"; then
_MOO_INTLTOOL
AC_DEFINE(ENABLE_NLS, 1)
else
_MOO_INTLTOOL_NO_NLS
fi
AC_SUBST(MOO_PO_SUBDIRS_RULE,'$(top_srcdir)/po-gsv/Makefile.am: $(top_srcdir)/po/Makefile.am ; sed -e "s/GETTEXT_PACKAGE/GETTEXT_PACKAGE_GSV/g" $(top_srcdir)/po/Makefile.am > $(top_srcdir)/po-gsv/Makefile.am.tmp && mv $(top_srcdir)/po-gsv/Makefile.am.tmp $(top_srcdir)/po-gsv/Makefile.am')
])

64
m4/moo-os.m4 Normal file
View File

@ -0,0 +1,64 @@
AC_DEFUN([MOO_AC_CHECK_OS],[
AC_REQUIRE([AC_CANONICAL_HOST])
m4_define([_moo_oses_],[CYGWIN WIN32 MINGW DARWIN UNIX FREEBSD BSD LINUX FDO])
m4_foreach_w([_moo_os_],_moo_oses_,[dnl
MOO_OS_[]_moo_os_=false
])
case $host in
*-*-mingw32*)
MOO_OS_WIN32=true
MOO_OS_NAME="Win32"
;;
*-*-cygwin*)
MOO_OS_CYGWIN=true
MOO_OS_NAME="CygWin"
;;
*-*-darwin*)
MOO_OS_DARWIN=true
MOO_OS_NAME="Darwin"
;;
*-*-freebsd*)
MOO_OS_FREEBSD=true
MOO_OS_NAME="FreeBSD"
;;
*-*-linux*)
MOO_OS_LINUX=true
MOO_OS_NAME="Linux"
;;
*)
MOO_OS_UNIX=true
MOO_OS_NAME="Unix"
;;
esac
if $MOO_OS_WIN32; then : ; else MOO_OS_UNIX=true; fi
if $MOO_OS_DARWIN; then MOO_OS_BSD=true; fi
if $MOO_OS_FREEBSD; then MOO_OS_BSD=true; fi
m4_foreach_w([_moo_os_],_moo_oses_,[dnl
AM_CONDITIONAL(MOO_OS_[]_moo_os_,[$MOO_OS_[]_moo_os_])
])
])
# LT_LIB_M macro from libtool.m4
AC_DEFUN([MOO_LT_LIB_M],
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
LIBM=
case $host in
*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
# These system don't have libm, or don't need it
;;
*-ncr-sysv4.3*)
AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
;;
*)
AC_CHECK_LIB(m, cos, LIBM="-lm")
;;
esac
AC_SUBST([LIBM])
])# LT_LIB_M

57
m4/moo-pygtk.m4 Normal file
View File

@ -0,0 +1,57 @@
##############################################################################
# MOO_AC_PYTHON()
#
AC_DEFUN_ONCE([MOO_AC_PYTHON],[
AC_REQUIRE([MOO_AC_CHECK_OS])
MOO_ENABLE_PYTHON=true
_moo_want_python="auto"
_moo_python_version=2.2
AC_ARG_WITH([python],AS_HELP_STRING([--with-python],[whether to compile python support (default = YES)]),[
if test "x$with_python" = "xno"; then
MOO_ENABLE_PYTHON=false
elif test "x$with_python" = "xyes"; then
_moo_want_python="yes"
_moo_python_version="2.2"
else
_moo_want_python="yes"
_moo_python_version="$with_python"
fi
])
if $MOO_ENABLE_PYTHON; then
MOO_ENABLE_PYTHON=false
MOO_AC_CHECK_PYTHON($_moo_python_version,[
PKG_CHECK_MODULES(PYGTK,pygtk-2.0 >= 2.6.0,[
MOO_ENABLE_PYTHON=true
],[:])
])
if $MOO_ENABLE_PYTHON; then
AC_SUBST([PYGTK_DEFS_DIR],[`$PKG_CONFIG --variable=defsdir pygtk-2.0`])
AC_SUBST([PYGOBJECT_DEFS_DIR],[`$PKG_CONFIG --variable=defsdir pygobject-2.0`])
fi
if $MOO_ENABLE_PYTHON; then
AC_MSG_NOTICE([compiling python support])
elif test "x$_moo_want_python" = "xyes"; then
AC_MSG_ERROR([python support requested but python cannot be used])
elif test "x$_moo_want_python" = "xauto"; then
AC_MSG_WARN([disabled python support])
else
AC_MSG_NOTICE([disabled python support])
fi
fi
AM_CONDITIONAL(MOO_ENABLE_PYTHON, $MOO_ENABLE_PYTHON)
if $MOO_ENABLE_PYTHON; then
AC_DEFINE(MOO_ENABLE_PYTHON, 1, [build python bindings and plugin])
fi
if $MOO_ENABLE_PYTHON; then
MOO_CFLAGS="$MOO_CFLAGS $PYGTK_CFLAGS $PYTHON_INCLUDES"
MOO_CXXFLAGS="$MOO_CXXFLAGS $PYGTK_CFLAGS $PYTHON_INCLUDES"
MOO_LIBS="$MOO_LIBS $PYGTK_LIBS $PYTHON_LIBS"
fi
])

147
m4/moo-python.m4 Normal file
View File

@ -0,0 +1,147 @@
##############################################################################
# _MOO_AC_PYTHON_DEVEL(action-if-found,action-if-not-found)
# checks python headers and libs. it's
# http://www.gnu.org/software/ac-archive/htmldoc/ac_python_devel.html,
# modified to allow actions if-found/if-not-found
#
AC_DEFUN([_MOO_AC_PYTHON_DEVEL],[
python_found=no
if test "$cross_compiling" = yes; then
test -z "$PYTHON_INCLUDES" || python_found=yes
else
# Check for distutils first
AC_MSG_CHECKING([for the distutils Python package])
$PYTHON -c "import distutils" 2>/dev/null
if test $? -eq 0; then
python_found=yes
AC_MSG_RESULT([yes])
else
python_found=no
AC_MSG_RESULT([no])
AC_MSG_WARN([cannot import Python module "distutils".
Please check your Python installation.])
fi
fi
# Check for Python include path
# if PYTHON_INCLUDES is set, do not do anything
if test $python_found = yes; then
AC_MSG_CHECKING([for Python include path])
if test -z "$PYTHON_INCLUDES"; then
python_path=`$PYTHON -c "import distutils.sysconfig; \
print distutils.sysconfig.get_python_inc();"`
if test -n "${python_path}"; then
python_path="-I$python_path"
fi
PYTHON_INCLUDES=$python_path
fi
AC_MSG_RESULT([$PYTHON_INCLUDES])
AC_SUBST([PYTHON_INCLUDES])
fi
# Check for Python linker flags
# if PYTHON_LIBS is set, do not do anything
if test $python_found = yes; then
AC_MSG_CHECKING([Python linker flags])
if test "x$PYTHON_LIBS" = "x"; then
# (makes two attempts to ensure we've got a version number
# from the interpreter)
py_version=`$PYTHON -c "from distutils.sysconfig import *; \
from string import join; \
print join(get_config_vars('VERSION'))"`
if test "x$py_version" = "x[None]"; then
if test "x$PYTHON_VERSION" != "x"; then
py_version=$PYTHON_VERSION
else
py_version=`$PYTHON -c "import sys; \
print sys.version[[:3]]"`
fi
fi
PYTHON_LIBS=`$PYTHON -c "from distutils.sysconfig import *; \
from string import join; \
print '-L' + PREFIX + '/lib', \
'-lpython';"`$py_version
fi
AC_MSG_RESULT([$PYTHON_LIBS])
AC_SUBST([PYTHON_LIBS])
fi
if test $python_found = yes; then
m4_if([$1],[],[:],[$1])
else
m4_if([$2],[],[:],[$2])
fi
])
##############################################################################
# MOO_AC_CHECK_PYTHON_NATIVE(min-version,action-if-found,action-if-not-found)
# checks python stuff when building for unix
#
AC_DEFUN([MOO_AC_CHECK_PYTHON_NATIVE],[
m4_define_default([_AM_PYTHON_INTERPRETER_LIST],[python2 python2.7 python2.6 python])
AM_PATH_PYTHON([$1],[
_MOO_AC_PYTHON_DEVEL([
python_found=yes
],[
AC_MSG_WARN([Found python interpreter but no development headers or libraries])
python_found=no
])
],[
python_found=no
])
if test x$python_found = xyes; then
m4_if([$2],[],[:],[$2])
else
PYTHON_INCLUDES=""
PYTHON_LIBS=""
m4_if([$3],[],[:],[$3])
fi
])
AC_DEFUN([MOO_AM_PYTHON_DEVEL_CROSS_MINGW],[
if test x"$PYTHON_INCLUDES" = x -o x"$PYTHON_LIBS" = x -o x"$PYTHON_VERSION" = x; then
AC_MSG_ERROR([The following variables must be set: PYTHON_INCLUDES, PYTHON_LIBS, PYTHON_VERSION])
fi
AC_ARG_VAR([PYTHON_INCLUDES], [python preprocessor flags])
AC_ARG_VAR([PYTHON_LIBS], [python linker flags])
AC_ARG_VAR([PYTHON_VERSION], [python version])
AC_SUBST(PYTHON_INCLUDES)
AC_SUBST(PYTHON_LIBS)
AC_MSG_CHECKING([for Python include path])
AC_MSG_RESULT([$PYTHON_INCLUDES])
AC_MSG_CHECKING([for Python linker flags])
AC_MSG_RESULT([$PYTHON_LIBS])
AC_SUBST([PYTHON_VERSION],[$PYTHON_VERSION])
AC_SUBST([PYTHON_PREFIX], ['${prefix}'])
AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}'])
AC_SUBST([PYTHON_PLATFORM], [nt])
AC_SUBST([pythondir], [$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages])
AC_SUBST([pyexecdir], [$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages])
$1
])
##############################################################################
# MOO_AC_CHECK_PYTHON(min-version,action-if-found,action-if-not-found)
# checks for python, python includes and libs
#
AC_DEFUN([MOO_AC_CHECK_PYTHON],[
AC_REQUIRE([MOO_AC_CHECK_OS])
if test "$cross_compiling" = yes -a "$MOO_OS_WIN32" = true; then
MOO_AM_PYTHON_DEVEL_CROSS_MINGW([$2],[$3])
else
MOO_AC_CHECK_PYTHON_NATIVE([$1],[$2],[$3])
fi
])

199
moo/CMakeLists.txt Normal file
View File

@ -0,0 +1,199 @@
FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/genmarshals_h.cmake
"EXECUTE_PROCESS(COMMAND ${GLIB_GENMARSHAL} --prefix=_moo_marshal --header ${CMAKE_CURRENT_SOURCE_DIR}/marshals.list
RESULT_VARIABLE result
OUTPUT_VARIABLE output
ERROR_VARIABLE error
OUTPUT_FILE marshals.h.tmp)
if(NOT result EQUAL 0)
MESSAGE(FATAL_ERROR \"Error generating marshals.h: \${output} \${error}\")
endif()
file(RENAME marshals.h.tmp marshals.h)
")
add_custom_command(OUTPUT marshals.h
COMMAND ${CMAKE_COMMAND} -P genmarshals_h.cmake
MAIN_DEPENDENCY marshals.list)
LIST(APPEND built_moo_sources marshals.h)
macro(ADD_GXML input)
string(REPLACE ".glade" "-gxml.h" _gxml_output "${input}")
string(REPLACE "/glade/" "/" _gxml_output "${_gxml_output}")
#message(STATUS "_gxml_output: ${_gxml_output}")
add_custom_command(OUTPUT ${_gxml_output}
COMMAND ${MOO_PYTHON} ${CMAKE_SOURCE_DIR}/tools/glade2c.py --output=${_gxml_output} ${CMAKE_CURRENT_SOURCE_DIR}/${input}
MAIN_DEPENDENCY ${input}
DEPENDS ${CMAKE_SOURCE_DIR}/tools/glade2c.py
COMMENT "Generating ${_gxml_output} from ${input}")
list(APPEND built_moo_sources ${_gxml_output})
endmacro(ADD_GXML)
macro(XML2H _xml2h_input _xml2h_output _xml2h_variable)
add_custom_command(OUTPUT ${_xml2h_output}
COMMAND ${MOO_PYTHON} ${CMAKE_SOURCE_DIR}/tools/xml2h.py ${CMAKE_CURRENT_SOURCE_DIR}/${_xml2h_input} ${_xml2h_output} ${_xml2h_variable}
MAIN_DEPENDENCY ${_xml2h_input}
DEPENDS ${CMAKE_SOURCE_DIR}/tools/xml2h.py
COMMENT "Generating ${_xml2h_output} from ${_xml2h_input}")
list(APPEND built_moo_sources ${_xml2h_output})
endmacro(XML2H)
macro(ADD_UI input)
string(REPLACE ".xml" "-ui.h" _ui_output "${input}")
# message(STATUS "_ui_output: ${_ui_output}")
string(REGEX REPLACE ".*/([^/]*)\\.xml" "\\1" _ui_variable "${input}")
XML2H(${input} ${_ui_output} ${_ui_variable}_ui_xml)
endmacro(ADD_UI)
file(MAKE_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}/mooapp
${CMAKE_CURRENT_BINARY_DIR}/mooedit
${CMAKE_CURRENT_BINARY_DIR}/moofileview
${CMAKE_CURRENT_BINARY_DIR}/mooutils
${CMAKE_CURRENT_BINARY_DIR}/moolua
${CMAKE_CURRENT_BINARY_DIR}/plugins/usertools
${CMAKE_CURRENT_BINARY_DIR}/medit-app
)
include(xdgmime/xdgmime.cmake)
include(moocpp/moocpp.cmake)
include(mooutils/mooutils.cmake)
include(mooedit/mooedit.cmake)
include(moofileview/moofileview.cmake)
include(gtksourceview/gtksourceview.cmake)
if(NOT MOO_OS_WIN32)
include(eggsmclient/eggsmclient.cmake)
endif()
include(mooapp/mooapp.cmake)
include(moolua/moolua.cmake)
if(MOO_ENABLE_PYTHON)
include(moopython/moopython.cmake)
endif()
include(plugins/plugins.cmake)
include(medit-app/medit-app.cmake)
SET(MEDIT_SOURCES
CMakeLists.txt
${moo_sources}
${built_moo_sources}
)
macro(ADD_MODULE name)
string(REPLACE "-" "_" _escaped_name "${name}")
source_group(${name} FILES ${${_escaped_name}_sources} ${${_escaped_name}_extra_files})
source_group(${name}\\generated FILES ${built_${_escaped_name}_sources})
#source_group(${name} FILES ${${_escaped_name}_sources} ${${_escaped_name}_extra_files})
#source_group(${name}\\generated FILES ${built_${_escaped_name}_sources})
LIST(APPEND MEDIT_SOURCES ${${_escaped_name}_sources} ${built_${_escaped_name}_sources})
LIST(APPEND MEDIT_EXTRA_DIST ${${_escaped_name}_extra_dist} ${${_escaped_name}_extra_files})
endmacro(ADD_MODULE)
ADD_MODULE(xdgmime)
ADD_MODULE(eggsmclient)
ADD_MODULE(gtksourceview)
ADD_MODULE(moocpp)
ADD_MODULE(mooutils)
ADD_MODULE(moofileview)
ADD_MODULE(mooedit)
ADD_MODULE(mooapp)
ADD_MODULE(plugins)
ADD_MODULE(moolua)
if(MOO_ENABLE_PYTHON)
ADD_MODULE(moopython)
endif()
ADD_MODULE(medit-app)
if(WIN32)
include_directories(${PROJECT_SOURCE_DIR}/moo/mooutils/moowin32/ms)
endif()
include_directories(
${PROJECT_BINARY_DIR}
${GTK_INCLUDE_DIRS}
${LIBXML2_INCLUDE_DIRS}
)
link_directories(${GTK_LIBRARY_DIRS} ${GMODULE_LIBRARY_DIRS})
source_group(misc REGULAR_EXPRESSION .*)
source_group("generated\\sources" REGULAR_EXPRESSION ".*\\.c(pp)?$")
source_group("generated\\headers" REGULAR_EXPRESSION ".*\\.h$")
source_group("misc\\glade" REGULAR_EXPRESSION ".*\\.glade$")
set(MOO_USE_PCH ${WIN32})
if(MOO_USE_PCH)
set(MEDIT_PCH_SOURCES
moo-pch.c
moo-pch.cpp
moo-pch.h
)
endif()
add_executable(medit WIN32
${MEDIT_SOURCES}
${MEDIT_PCH_SOURCES}
)
if(MOO_USE_PCH)
add_precompiled_header(medit
moo-pch.h
FORCEINCLUDE
SOURCE_C moo-pch.c
SOURCE_CXX moo-pch.cpp)
endif()
if(MOO_BUILD_FROM_MINGW)
LIST(APPEND MEDIT_LIBS libmooglib-0)
endif()
target_link_libraries(medit
${GTK_LIBRARIES}
${GMODULE_LIBRARIES}
${LIBXML2_LIBRARIES}
${XLIB_LIBRARIES}
#${LIBM}
${PYTHON_LIBRARY}
${moo_libadd}
${MEDIT_LIBS}
)
install(TARGETS medit RUNTIME DESTINATION bin)
if(MOO_BUILD_FROM_MINGW)
# xxx this is wrong, doing it temporarily so it doesn't install python lib every time
if(NOT EXISTS "${MOO_GTK_DIST_DIR}/bin/libglib-2.0-0.dll")
install(DIRECTORY ${MOO_GTK_DIST_DIR}/bin DESTINATION ${CMAKE_INSTALL_PREFIX})
install(DIRECTORY ${MOO_GTK_DIST_DIR}/etc DESTINATION ${CMAKE_INSTALL_PREFIX})
install(DIRECTORY ${MOO_GTK_DIST_DIR}/lib DESTINATION ${CMAKE_INSTALL_PREFIX})
install(DIRECTORY ${MOO_GTK_DIST_DIR}/share DESTINATION ${CMAKE_INSTALL_PREFIX})
endif()
#install(DIRECTORY ${CMAKE_SOURCE_DIR}/plat/win32/gtk-win/extra/medit-data/bin DESTINATION ${CMAKE_INSTALL_PREFIX})
#install(DIRECTORY ${CMAKE_SOURCE_DIR}/plat/win32/gtk-win/extra/medit-data/etc DESTINATION ${CMAKE_INSTALL_PREFIX})
endif()
# zzz
# if MOO_OS_UNIX
# desktopdir = $(datadir)/applications
# desktop_DATA = medit-app/medit.desktop
# medit-app/medit.desktop: medit-app/medit.desktop.in @MOO_INTLTOOL_INI_DEPS@
# $(AM_V_at)$(MKDIR_P) medit-app
# @MOO_INTLTOOL_INI_CMD@
# CLEANFILES += medit-app/medit.desktop
# endif MOO_OS_UNIX
# zzz
# iconthemedir = $(datadir)/icons/hicolor/48x48/apps
# icontheme_DATA = mooutils/pixmaps/medit.png
# if MOO_ENABLE_INSTALL_HOOKS
# update_icon_cache = gtk-update-icon-cache -f -t $(DESTDIR)$(datadir)/icons/hicolor
# install-data-hook: install-data-hook-gtk-icon-cache
# install-data-hook-gtk-icon-cache:
# @if echo "Updating icon cache" && $(update_icon_cache); then
# echo "Done.";
# else
# echo "*** GTK icon cache not updated. After install, run this:";\
# echo $(update_icon_cache);
# fi
# uninstall-hook: uninstall-data-hook-gtk-icon-cache
# uninstall-data-hook-gtk-icon-cache:
# @if echo "Updating icon cache" && $(update_icon_cache); then echo "Done."; else echo "Failed."; fi
# endif
# zzz include medit-module/Makefile.incl

97
moo/Makefile.am Normal file
View File

@ -0,0 +1,97 @@
EXTRA_DIST =
BUILT_SOURCES =
CLEANFILES =
bin_PROGRAMS =
noinst_LIBRARIES =
AM_CPPFLAGS = $(MOO_CPPFLAGS) -I$(top_srcdir)/doc/built -Imooutils/glade
AM_CFLAGS = $(MOO_CFLAGS)
AM_CXXFLAGS = $(MOO_CXXFLAGS)
moo_sources =
built_moo_sources =
moo_libadd =
plugins_sources =
built_plugins_sources =
moo_srcdir = $(srcdir)
moo_builddir = .
moo_sources += moo-config.h
moo_sources += \
mooglib/moo-glib.h \
mooglib/moo-stat.h \
mooglib/moo-time.h
EXTRA_DIST += \
mooglib/moo-glib.cpp
if !MOO_OS_WIN32
moo_sources += mooglib/moo-glib.cpp
endif
EXTRA_DIST += marshals.list
built_moo_sources += marshals.h
marshals.h: marshals.list
$(AM_V_GEN)$(GLIB_GENMARSHAL) --prefix=_moo_marshal --header $(srcdir)/marshals.list > marshals.h.tmp \
&& mv marshals.h.tmp marshals.h
include mooedit/Makefile.incl
include xdgmime/Makefile.incl
include mooutils/Makefile.incl
include moofileview/Makefile.incl
include gtksourceview/Makefile.incl
include eggsmclient/Makefile.incl
include mooapp/Makefile.incl
include moolua/Makefile.incl
include moopython/Makefile.incl
include plugins/Makefile.incl
include medit-app/Makefile.incl
include medit-module/Makefile.incl
include moocpp/Makefile.incl
BUILT_SOURCES += $(built_moo_sources) $(built_plugins_sources)
CLEANFILES += $(built_moo_sources) $(built_plugins_sources)
test:
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) test
# glade/%-gxml.h: glade/%.glade $(top_srcdir)/tools/glade2c.py
# $(MKDIR_P) glade
# $(MOO_PYTHON) $(top_srcdir)/tools/glade2c.py $< > $@.tmp && mv $@.tmp $@
mooutils/%-gxml.h: mooutils/glade/%.glade $(top_srcdir)/tools/glade2c.py
$(AM_V_at) $(MKDIR_P) `dirname $@`
$(AM_V_GEN)$(MOO_PYTHON) $(top_srcdir)/tools/glade2c.py $< > $@.tmp && mv $@.tmp $@
moofileview/%-gxml.h: moofileview/glade/%.glade $(top_srcdir)/tools/glade2c.py
$(AM_V_at) $(MKDIR_P) `dirname $@`
$(AM_V_GEN)$(MOO_PYTHON) $(top_srcdir)/tools/glade2c.py $< > $@.tmp && mv $@.tmp $@
mooedit/%-gxml.h: mooedit/glade/%.glade $(top_srcdir)/tools/glade2c.py
$(AM_V_at) $(MKDIR_P) `dirname $@`
$(AM_V_GEN)$(MOO_PYTHON) $(top_srcdir)/tools/glade2c.py $< > $@.tmp && mv $@.tmp $@
mooapp/%-gxml.h: mooapp/glade/%.glade $(top_srcdir)/tools/glade2c.py
$(AM_V_at) $(MKDIR_P) `dirname $@`
$(AM_V_GEN)$(MOO_PYTHON) $(top_srcdir)/tools/glade2c.py $< > $@.tmp && mv $@.tmp $@
plugins/%-gxml.h: plugins/glade/%.glade $(top_srcdir)/tools/glade2c.py
$(AM_V_at) $(MKDIR_P) `dirname $@`
$(AM_V_GEN)$(MOO_PYTHON) $(top_srcdir)/tools/glade2c.py $< > $@.tmp && mv $@.tmp $@
plugins/usertools/%-gxml.h: plugins/usertools/glade/%.glade $(top_srcdir)/tools/glade2c.py
$(AM_V_at) $(MKDIR_P) `dirname $@`
$(AM_V_GEN)$(MOO_PYTHON) $(top_srcdir)/tools/glade2c.py $< > $@.tmp && mv $@.tmp $@
# %-ui.h: %.xml $(top_srcdir)/tools/xml2h.py
# $(AM_V_GEN)$(MOO_PYTHON) $(top_srcdir)/tools/xml2h.py $< $@.tmp $*_ui_xml && mv $@.tmp $@
moofileview/%-ui.h: moofileview/%.xml $(top_srcdir)/tools/xml2h.py
$(AM_V_at) $(MKDIR_P) `dirname $@`
$(AM_V_GEN)$(MOO_PYTHON) $(top_srcdir)/tools/xml2h.py $< $@.tmp $*_ui_xml && mv $@.tmp $@
mooedit/%-ui.h: mooedit/%.xml $(top_srcdir)/tools/xml2h.py
$(AM_V_at) $(MKDIR_P) `dirname $@`
$(AM_V_GEN)$(MOO_PYTHON) $(top_srcdir)/tools/xml2h.py $< $@.tmp $*_ui_xml && mv $@.tmp $@

View File

@ -0,0 +1,18 @@
moo_sources += \
eggsmclient/eggsmclient.c \
eggsmclient/eggsmclient.h \
eggsmclient/eggsmclient-mangle.h \
eggsmclient/eggsmclient-private.h
if MOO_OS_WIN32
moo_sources += eggsmclient/eggsmclient-win32.c
else !MOO_OS_WIN32
if MOO_OS_DARWIN
moo_sources += eggsmclient/eggsmclient-dummy.c
else !MOO_OS_DARWIN
AM_CFLAGS += -DEGG_SM_CLIENT_BACKEND_XSMP
moo_sources += eggsmclient/eggsmclient-xsmp.c eggsmclient/eggdesktopfile.h eggsmclient/eggdesktopfile.c
endif !MOO_OS_DARWIN
endif !MOO_OS_WIN32
# -%- strip:true -%-

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,163 @@
/* eggdesktopfile.h - Freedesktop.Org Desktop Files
* Copyright (C) 2007 Novell, Inc.
*
* 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 of
* the License, or (at your option) any later version.
*
* 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; see the file COPYING.LIB. If not,
* write to the Free Software Foundation, Inc., 59 Temple Place -
* Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __EGG_DESKTOP_FILE_H__
#define __EGG_DESKTOP_FILE_H__
#include <mooglib/moo-glib.h>
G_BEGIN_DECLS
typedef struct EggDesktopFile EggDesktopFile;
typedef enum {
EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED,
EGG_DESKTOP_FILE_TYPE_APPLICATION,
EGG_DESKTOP_FILE_TYPE_LINK,
EGG_DESKTOP_FILE_TYPE_DIRECTORY
} EggDesktopFileType;
EggDesktopFile *egg_desktop_file_new (const char *desktop_file_path,
GError **error);
EggDesktopFile *egg_desktop_file_new_from_data_dirs (const char *desktop_file_path,
GError **error);
EggDesktopFile *egg_desktop_file_new_from_dirs (const char *desktop_file_path,
const char **search_dirs,
GError **error);
EggDesktopFile *egg_desktop_file_new_from_key_file (GKeyFile *key_file,
const char *source,
GError **error);
void egg_desktop_file_free (EggDesktopFile *desktop_file);
const char *egg_desktop_file_get_source (EggDesktopFile *desktop_file);
EggDesktopFileType egg_desktop_file_get_desktop_file_type (EggDesktopFile *desktop_file);
const char *egg_desktop_file_get_name (EggDesktopFile *desktop_file);
const char *egg_desktop_file_get_icon (EggDesktopFile *desktop_file);
gboolean egg_desktop_file_can_launch (EggDesktopFile *desktop_file,
const char *desktop_environment);
gboolean egg_desktop_file_accepts_documents (EggDesktopFile *desktop_file);
gboolean egg_desktop_file_accepts_multiple (EggDesktopFile *desktop_file);
gboolean egg_desktop_file_accepts_uris (EggDesktopFile *desktop_file);
char *egg_desktop_file_parse_exec (EggDesktopFile *desktop_file,
GSList *documents,
GError **error);
gboolean egg_desktop_file_launch (EggDesktopFile *desktop_file,
GSList *documents,
GError **error,
...) G_GNUC_NULL_TERMINATED;
typedef enum {
EGG_DESKTOP_FILE_LAUNCH_CLEARENV = 1,
EGG_DESKTOP_FILE_LAUNCH_PUTENV,
EGG_DESKTOP_FILE_LAUNCH_SCREEN,
EGG_DESKTOP_FILE_LAUNCH_WORKSPACE,
EGG_DESKTOP_FILE_LAUNCH_DIRECTORY,
EGG_DESKTOP_FILE_LAUNCH_TIME,
EGG_DESKTOP_FILE_LAUNCH_FLAGS,
EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC,
EGG_DESKTOP_FILE_LAUNCH_RETURN_PID,
EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE,
EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE,
EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE,
EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID
} EggDesktopFileLaunchOption;
/* Standard Keys */
#define EGG_DESKTOP_FILE_GROUP "Desktop Entry"
#define EGG_DESKTOP_FILE_KEY_TYPE "Type"
#define EGG_DESKTOP_FILE_KEY_VERSION "Version"
#define EGG_DESKTOP_FILE_KEY_NAME "Name"
#define EGG_DESKTOP_FILE_KEY_GENERIC_NAME "GenericName"
#define EGG_DESKTOP_FILE_KEY_NO_DISPLAY "NoDisplay"
#define EGG_DESKTOP_FILE_KEY_COMMENT "Comment"
#define EGG_DESKTOP_FILE_KEY_ICON "Icon"
#define EGG_DESKTOP_FILE_KEY_HIDDEN "Hidden"
#define EGG_DESKTOP_FILE_KEY_ONLY_SHOW_IN "OnlyShowIn"
#define EGG_DESKTOP_FILE_KEY_NOT_SHOW_IN "NotShowIn"
#define EGG_DESKTOP_FILE_KEY_TRY_EXEC "TryExec"
#define EGG_DESKTOP_FILE_KEY_EXEC "Exec"
#define EGG_DESKTOP_FILE_KEY_PATH "Path"
#define EGG_DESKTOP_FILE_KEY_TERMINAL "Terminal"
#define EGG_DESKTOP_FILE_KEY_MIME_TYPE "MimeType"
#define EGG_DESKTOP_FILE_KEY_CATEGORIES "Categories"
#define EGG_DESKTOP_FILE_KEY_STARTUP_NOTIFY "StartupNotify"
#define EGG_DESKTOP_FILE_KEY_STARTUP_WM_CLASS "StartupWMClass"
#define EGG_DESKTOP_FILE_KEY_URL "URL"
/* Accessors */
gboolean egg_desktop_file_has_key (EggDesktopFile *desktop_file,
const char *key,
GError **error);
char *egg_desktop_file_get_string (EggDesktopFile *desktop_file,
const char *key,
GError **error) G_GNUC_MALLOC;
char *egg_desktop_file_get_locale_string (EggDesktopFile *desktop_file,
const char *key,
const char *locale,
GError **error) G_GNUC_MALLOC;
gboolean egg_desktop_file_get_boolean (EggDesktopFile *desktop_file,
const char *key,
GError **error);
double egg_desktop_file_get_numeric (EggDesktopFile *desktop_file,
const char *key,
GError **error);
int egg_desktop_file_get_integer (EggDesktopFile *desktop_file,
const char *key,
GError **error);
char **egg_desktop_file_get_string_list (EggDesktopFile *desktop_file,
const char *key,
gsize *length,
GError **error) G_GNUC_MALLOC;
char **egg_desktop_file_get_locale_string_list (EggDesktopFile *desktop_file,
const char *key,
const char *locale,
gsize *length,
GError **error) G_GNUC_MALLOC;
/* Errors */
#define EGG_DESKTOP_FILE_ERROR egg_desktop_file_error_quark()
GQuark egg_desktop_file_error_quark (void);
typedef enum {
EGG_DESKTOP_FILE_ERROR_INVALID,
EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE,
EGG_DESKTOP_FILE_ERROR_UNRECOGNIZED_OPTION
} EggDesktopFileError;
/* Global application desktop file */
void egg_set_desktop_file (const char *desktop_file_path);
void egg_set_desktop_file_without_defaults (const char *desktop_file_path);
EggDesktopFile *egg_get_desktop_file (void);
G_END_DECLS
#endif /* __EGG_DESKTOP_FILE_H__ */

View File

@ -0,0 +1,297 @@
/*
* Copyright (C) 2008 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
#include "config.h"
#include "eggsmclient.h"
#include "eggsmclient-private.h"
#include "eggdesktopfile.h"
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <gdk/gdk.h>
#include <dbus/dbus-glib.h>
#define GSM_DBUS_NAME "org.gnome.SessionManager"
#define GSM_DBUS_PATH "/org/gnome/SessionManager"
#define GSM_DBUS_INTERFACE "org.gnome.SessionManager"
#define GSM_CLIENT_PRIVATE_DBUS_INTERFACE "org.gnome.SessionManager.ClientPrivate"
#define GSM_CLIENT_DBUS_INTERFACE "org.gnome.SessionManager.Client"
#define EGG_TYPE_SM_CLIENT_DBUS (egg_sm_client_dbus_get_type ())
#define EGG_SM_CLIENT_DBUS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_DBUS, EggSMClientDBus))
#define EGG_SM_CLIENT_DBUS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT_DBUS, EggSMClientDBusClass))
#define EGG_IS_SM_CLIENT_DBUS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT_DBUS))
#define EGG_IS_SM_CLIENT_DBUS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT_DBUS))
#define EGG_SM_CLIENT_DBUS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT_DBUS, EggSMClientDBusClass))
typedef struct _EggSMClientDBus EggSMClientDBus;
typedef struct _EggSMClientDBusClass EggSMClientDBusClass;
struct _EggSMClientDBus
{
EggSMClient parent;
DBusGConnection *conn;
DBusGProxy *sm_proxy, *client_proxy;
char *client_path;
};
struct _EggSMClientDBusClass
{
EggSMClientClass parent_class;
};
static void sm_client_dbus_startup (EggSMClient *client,
const char *client_id);
static void sm_client_dbus_will_quit (EggSMClient *client,
gboolean will_quit);
static gboolean sm_client_dbus_end_session (EggSMClient *client,
EggSMClientEndStyle style,
gboolean request_confirmation);
static void dbus_client_query_end_session (DBusGProxy *proxy,
guint flags,
gpointer smclient);
static void dbus_client_end_session (DBusGProxy *proxy,
guint flags,
gpointer smclient);
static void dbus_client_cancel_end_session (DBusGProxy *proxy,
gpointer smclient);
static void dbus_client_stop (DBusGProxy *proxy,
gpointer smclient);
G_DEFINE_TYPE (EggSMClientDBus, egg_sm_client_dbus, EGG_TYPE_SM_CLIENT)
static void
egg_sm_client_dbus_init (EggSMClientDBus *dbus)
{
;
}
static void
egg_sm_client_dbus_class_init (EggSMClientDBusClass *klass)
{
EggSMClientClass *sm_client_class = EGG_SM_CLIENT_CLASS (klass);
sm_client_class->startup = sm_client_dbus_startup;
sm_client_class->will_quit = sm_client_dbus_will_quit;
sm_client_class->end_session = sm_client_dbus_end_session;
}
EggSMClient *
egg_sm_client_dbus_new (void)
{
DBusGConnection *conn;
DBusGProxy *proxy;
EggSMClientDBus *dbus;
conn = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
if (!conn)
return NULL;
proxy = dbus_g_proxy_new_for_name (conn, GSM_DBUS_NAME, GSM_DBUS_PATH,
GSM_DBUS_INTERFACE);
if (!proxy)
{
g_object_unref (conn);
return NULL;
}
dbus = g_object_new (EGG_TYPE_SM_CLIENT_DBUS, NULL);
dbus->conn = conn;
dbus->sm_proxy = proxy;
return (EggSMClient *)dbus;
}
static void
sm_client_dbus_startup (EggSMClient *client,
const char *client_id)
{
EggSMClientDBus *dbus = (EggSMClientDBus *)client;
GError *error = NULL;
char *client_path, *ret_client_id;
DBusGProxy *client_public;
if (!dbus_g_proxy_call (dbus->sm_proxy, "RegisterClient", &error,
G_TYPE_STRING, g_get_prgname (),
G_TYPE_STRING, client_id,
G_TYPE_INVALID,
DBUS_TYPE_G_OBJECT_PATH, &client_path,
G_TYPE_INVALID))
{
g_warning ("Failed to register client: %s", error->message);
g_error_free (error);
return;
}
g_debug ("Client registered with session manager: %s", client_path);
dbus->client_proxy = dbus_g_proxy_new_for_name (dbus->conn, GSM_DBUS_NAME,
client_path,
GSM_CLIENT_PRIVATE_DBUS_INTERFACE);
dbus_g_proxy_add_signal (dbus->client_proxy, "QueryEndSession",
G_TYPE_UINT,
G_TYPE_INVALID);
dbus_g_proxy_connect_signal (dbus->client_proxy, "QueryEndSession",
G_CALLBACK (dbus_client_query_end_session),
dbus, NULL);
dbus_g_proxy_add_signal (dbus->client_proxy, "EndSession",
G_TYPE_UINT,
G_TYPE_INVALID);
dbus_g_proxy_connect_signal (dbus->client_proxy, "EndSession",
G_CALLBACK (dbus_client_end_session),
dbus, NULL);
dbus_g_proxy_add_signal (dbus->client_proxy, "CancelEndSession",
G_TYPE_INVALID);
dbus_g_proxy_connect_signal (dbus->client_proxy, "CancelEndSession",
G_CALLBACK (dbus_client_cancel_end_session),
dbus, NULL);
dbus_g_proxy_add_signal (dbus->client_proxy, "Stop",
G_TYPE_INVALID);
dbus_g_proxy_connect_signal (dbus->client_proxy, "Stop",
G_CALLBACK (dbus_client_stop),
dbus, NULL);
client_public = dbus_g_proxy_new_for_name (dbus->conn, GSM_DBUS_NAME,
client_path,
GSM_CLIENT_DBUS_INTERFACE);
if (dbus_g_proxy_call (client_public, "GetStartupId", &error,
G_TYPE_INVALID,
G_TYPE_STRING, &ret_client_id,
G_TYPE_INVALID))
{
gdk_threads_enter ();
#if !GTK_CHECK_VERSION(2,23,3) && !GTK_CHECK_VERSION(3,0,0)
gdk_set_sm_client_id (ret_client_id);
#else
gdk_x11_set_sm_client_id (ret_client_id);
#endif
gdk_threads_leave ();
g_debug ("Got client ID \"%s\"", ret_client_id);
g_free (ret_client_id);
}
else
{
g_warning ("Could not get client id: %s", error->message);
g_error_free (error);
}
g_object_unref (client_public);
}
static void
sm_client_dbus_shutdown (EggSMClient *client)
{
EggSMClientDBus *dbus = EGG_SM_CLIENT_DBUS (client);
GError *error = NULL;
if (!dbus_g_proxy_call (dbus->sm_proxy, "UnregisterClient", &error,
DBUS_TYPE_G_OBJECT_PATH, dbus->client_path,
G_TYPE_INVALID,
G_TYPE_INVALID))
{
g_warning ("Failed to unregister client: %s", error->message);
g_error_free (error);
return;
}
g_free (dbus->client_path);
dbus->client_path = NULL;
g_object_unref (dbus->client_proxy);
dbus->client_proxy = NULL;
}
static void
dbus_client_query_end_session (DBusGProxy *proxy,
guint flags,
gpointer smclient)
{
egg_sm_client_quit_requested (smclient);
}
static void
sm_client_dbus_will_quit (EggSMClient *client,
gboolean will_quit)
{
EggSMClientDBus *dbus = (EggSMClientDBus *)client;
g_return_if_fail (dbus->client_proxy != NULL);
dbus_g_proxy_call (dbus->client_proxy, "EndSessionResponse", NULL,
G_TYPE_BOOLEAN, will_quit,
G_TYPE_STRING, NULL,
G_TYPE_INVALID,
G_TYPE_INVALID);
}
static void
dbus_client_end_session (DBusGProxy *proxy,
guint flags,
gpointer smclient)
{
sm_client_dbus_will_quit (smclient, TRUE);
sm_client_dbus_shutdown (smclient);
egg_sm_client_quit (smclient);
}
static void
dbus_client_cancel_end_session (DBusGProxy *proxy,
gpointer smclient)
{
egg_sm_client_quit_cancelled (smclient);
}
static void
dbus_client_stop (DBusGProxy *proxy,
gpointer smclient)
{
sm_client_dbus_shutdown (smclient);
egg_sm_client_quit (smclient);
}
static gboolean
sm_client_dbus_end_session (EggSMClient *client,
EggSMClientEndStyle style,
gboolean request_confirmation)
{
EggSMClientDBus *dbus = (EggSMClientDBus *)client;
if (style == EGG_SM_CLIENT_END_SESSION_DEFAULT ||
style == EGG_SM_CLIENT_LOGOUT)
{
return dbus_g_proxy_call (dbus->sm_proxy, "Logout", NULL,
G_TYPE_UINT, request_confirmation ? 0 : 1,
G_TYPE_INVALID,
G_TYPE_INVALID);
}
else
{
return dbus_g_proxy_call (dbus->sm_proxy, "Shutdown", NULL,
G_TYPE_INVALID,
G_TYPE_INVALID);
}
}

View File

@ -0,0 +1,37 @@
#include "config.h"
#include "eggsmclient-private.h"
#define EGG_TYPE_SM_CLIENT_DUMMY (egg_sm_client_dummy_get_type ())
#define EGG_SM_CLIENT_DUMMY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_DUMMY, EggSMClientDummy))
#define EGG_SM_CLIENT_DUMMY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT_DUMMY, EggSMClientDummyClass))
#define EGG_IS_SM_CLIENT_DUMMY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT_DUMMY))
#define EGG_IS_SM_CLIENT_DUMMY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT_DUMMY))
#define EGG_SM_CLIENT_DUMMY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT_DUMMY, EggSMClientDummyClass))
typedef EggSMClient EggSMClientDummy;
typedef EggSMClientClass EggSMClientDummyClass;
G_DEFINE_TYPE (EggSMClientDummy, egg_sm_client_dummy, EGG_TYPE_SM_CLIENT)
static void
egg_sm_client_dummy_init (G_GNUC_UNUSED EggSMClientDummy *client)
{
}
static void
sm_client_dummy_startup (G_GNUC_UNUSED EggSMClient *client,
G_GNUC_UNUSED const char *client_id)
{
}
static void
egg_sm_client_dummy_class_init (EggSMClientDummyClass *klass)
{
klass->startup = sm_client_dummy_startup;
}
EggSMClient *
egg_sm_client_dummy_new (void)
{
return g_object_new (EGG_TYPE_SM_CLIENT_DUMMY, NULL);
}

View File

@ -0,0 +1,31 @@
#ifndef EGG_SM_CLIENT_MANGLE_H
#define EGG_SM_CLIENT_MANGLE_H
#define egg_sm_client_xsmp_get_type _moo_egg_sm_client_xsmp_get_type
#define egg_sm_client_win32_get_type _moo_egg_sm_client_win32_get_type
#define egg_sm_client_osx_get_type _moo_egg_sm_client_osx_get_type
#define egg_sm_client_get_type _moo_egg_sm_client_get_type
#define egg_sm_client_get_option_group _moo_egg_sm_client_get_option_group
#define egg_sm_client_register _moo_egg_sm_client_register
#define egg_sm_client_get _moo_egg_sm_client_get
#define egg_sm_client_is_resumed _moo_egg_sm_client_is_resumed
#define egg_sm_client_get_state_dir _moo_egg_sm_client_get_state_dir
#define egg_sm_client_get_config_prefix _moo_egg_sm_client_get_config_prefix
#define egg_sm_client_set_restart_command _moo_egg_sm_client_set_restart_command
#define egg_sm_client_will_quit _moo_egg_sm_client_will_quit
#define egg_sm_client_end_session _moo_egg_sm_client_end_session
#define egg_sm_client_save_state _moo_egg_sm_client_save_state
#define egg_sm_client_quit_requested _moo_egg_sm_client_quit_requested
#define egg_sm_client_quit_cancelled _moo_egg_sm_client_quit_cancelled
#define egg_sm_client_quit _moo_egg_sm_client_quit
#define egg_sm_client_xsmp_new _moo_egg_sm_client_xsmp_new
#define egg_sm_client_dbus_new _moo_egg_sm_client_dbus_new
#define egg_sm_client_win32_new _moo_egg_sm_client_win32_new
#define egg_sm_client_osx_new _moo_egg_sm_client_osx_new
#define egg_sm_client_dummy_new _moo_egg_sm_client_dummy_new
#define egg_sm_client_get_mode _moo_egg_sm_client_get_mode
#define egg_sm_client_get_state_file _moo_egg_sm_client_get_state_file
#define egg_sm_client_set_mode _moo_egg_sm_client_set_mode
#endif /* EGG_SM_CLIENT_MANGLE_H */

View File

@ -0,0 +1,235 @@
/*
* Copyright (C) 2007 Novell, Inc.
* Copyright (C) 2008 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
/* EggSMClientOSX
*
* For details on the OS X logout process, see:
* http://developer.apple.com/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/BootProcess.html#//apple_ref/doc/uid/20002130-114618
*
* EggSMClientOSX registers for the kAEQuitApplication AppleEvent; the
* handler we register (quit_requested()) will be invoked from inside
* the quartz event-handling code (specifically, from inside
* [NSApplication nextEventMatchingMask]) when an AppleEvent arrives.
* We use AESuspendTheCurrentEvent() and AEResumeTheCurrentEvent() to
* allow asynchronous / non-main-loop-reentering processing of the
* quit request. (These are part of the Carbon framework; it doesn't
* seem to be possible to handle AppleEvents asynchronously from
* Cocoa.)
*/
#include "config.h"
#include "eggsmclient-private.h"
#include <mooglib/moo-glib.h>
#include <Carbon/Carbon.h>
#include <CoreServices/CoreServices.h>
#define EGG_TYPE_SM_CLIENT_OSX (egg_sm_client_osx_get_type ())
#define EGG_SM_CLIENT_OSX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_OSX, EggSMClientOSX))
#define EGG_SM_CLIENT_OSX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT_OSX, EggSMClientOSXClass))
#define EGG_IS_SM_CLIENT_OSX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT_OSX))
#define EGG_IS_SM_CLIENT_OSX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT_OSX))
#define EGG_SM_CLIENT_OSX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT_OSX, EggSMClientOSXClass))
typedef struct _EggSMClientOSX EggSMClientOSX;
typedef struct _EggSMClientOSXClass EggSMClientOSXClass;
struct _EggSMClientOSX {
EggSMClient parent;
AppleEvent quit_event, quit_reply;
gboolean quit_requested, quitting;
};
struct _EggSMClientOSXClass
{
EggSMClientClass parent_class;
};
static void sm_client_osx_startup (EggSMClient *client,
const char *client_id);
static void sm_client_osx_will_quit (EggSMClient *client,
gboolean will_quit);
static gboolean sm_client_osx_end_session (EggSMClient *client,
EggSMClientEndStyle style,
gboolean request_confirmation);
static pascal OSErr quit_requested (const AppleEvent *, AppleEvent *, long);
G_DEFINE_TYPE (EggSMClientOSX, egg_sm_client_osx, EGG_TYPE_SM_CLIENT)
static void
egg_sm_client_osx_init (EggSMClientOSX *osx)
{
;
}
static void
egg_sm_client_osx_class_init (EggSMClientOSXClass *klass)
{
EggSMClientClass *sm_client_class = EGG_SM_CLIENT_CLASS (klass);
sm_client_class->startup = sm_client_osx_startup;
sm_client_class->will_quit = sm_client_osx_will_quit;
sm_client_class->end_session = sm_client_osx_end_session;
}
EggSMClient *
egg_sm_client_osx_new (void)
{
return g_object_new (EGG_TYPE_SM_CLIENT_OSX, NULL);
}
static void
sm_client_osx_startup (EggSMClient *client,
const char *client_id)
{
AEInstallEventHandler (kCoreEventClass, kAEQuitApplication,
NewAEEventHandlerUPP (quit_requested),
(long)GPOINTER_TO_SIZE (client), false);
}
static gboolean
idle_quit_requested (gpointer client)
{
egg_sm_client_quit_requested (client);
return FALSE;
}
static pascal OSErr
quit_requested (const AppleEvent *aevt, AppleEvent *reply, long refcon)
{
EggSMClient *client = GSIZE_TO_POINTER ((gsize)refcon);
EggSMClientOSX *osx = GSIZE_TO_POINTER ((gsize)refcon);
g_return_val_if_fail (!osx->quit_requested, userCanceledErr);
/* FIXME AEInteractWithUser? */
osx->quit_requested = TRUE;
AEDuplicateDesc (aevt, &osx->quit_event);
AEDuplicateDesc (reply, &osx->quit_reply);
AESuspendTheCurrentEvent (aevt);
/* Don't emit the "quit_requested" signal immediately, since we're
* called from a weird point in the guts of gdkeventloop-quartz.c
*/
g_idle_add (idle_quit_requested, client);
return noErr;
}
static pascal OSErr
quit_requested_resumed (const AppleEvent *aevt, AppleEvent *reply, long refcon)
{
EggSMClientOSX *osx = GSIZE_TO_POINTER ((gsize)refcon);
osx->quit_requested = FALSE;
return osx->quitting ? noErr : userCanceledErr;
}
static gboolean
idle_will_quit (gpointer client)
{
EggSMClientOSX *osx = (EggSMClientOSX *)client;
/* Resume the event with a new handler that will return a value to
* the system.
*/
AEResumeTheCurrentEvent (&osx->quit_event, &osx->quit_reply,
NewAEEventHandlerUPP (quit_requested_resumed),
(long)GPOINTER_TO_SIZE (client));
AEDisposeDesc (&osx->quit_event);
AEDisposeDesc (&osx->quit_reply);
if (osx->quitting)
egg_sm_client_quit (client);
return FALSE;
}
static void
sm_client_osx_will_quit (EggSMClient *client,
gboolean will_quit)
{
EggSMClientOSX *osx = (EggSMClientOSX *)client;
g_return_if_fail (osx->quit_requested);
osx->quitting = will_quit;
/* Finish in an idle handler since the caller might have called
* egg_sm_client_will_quit() from inside the "quit_requested" signal
* handler, but may not expect the "quit" signal to arrive during
* the _will_quit() call.
*/
g_idle_add (idle_will_quit, client);
}
static gboolean
sm_client_osx_end_session (EggSMClient *client,
EggSMClientEndStyle style,
gboolean request_confirmation)
{
static const ProcessSerialNumber loginwindow_psn = { 0, kSystemProcess };
AppleEvent event = { typeNull, NULL }, reply = { typeNull, NULL };
AEAddressDesc target;
AEEventID id;
OSErr err;
switch (style)
{
case EGG_SM_CLIENT_END_SESSION_DEFAULT:
case EGG_SM_CLIENT_LOGOUT:
id = request_confirmation ? kAELogOut : kAEReallyLogOut;
break;
case EGG_SM_CLIENT_REBOOT:
id = request_confirmation ? kAEShowRestartDialog : kAERestart;
break;
case EGG_SM_CLIENT_SHUTDOWN:
id = request_confirmation ? kAEShowShutdownDialog : kAEShutDown;
break;
}
err = AECreateDesc (typeProcessSerialNumber, &loginwindow_psn,
sizeof (loginwindow_psn), &target);
if (err != noErr)
{
g_warning ("Could not create descriptor for loginwindow: %d", err);
return FALSE;
}
err = AECreateAppleEvent (kCoreEventClass, id, &target,
kAutoGenerateReturnID, kAnyTransactionID,
&event);
AEDisposeDesc (&target);
if (err != noErr)
{
g_warning ("Could not create logout AppleEvent: %d", err);
return FALSE;
}
err = AESend (&event, &reply, kAENoReply, kAENormalPriority,
kAEDefaultTimeout, NULL, NULL);
AEDisposeDesc (&event);
if (err == noErr)
AEDisposeDesc (&reply);
return err == noErr;
}

View File

@ -0,0 +1,66 @@
/* eggsmclient-private.h
* Copyright (C) 2007 Novell, Inc.
*
* 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 of the License, or (at your option) any later version.
*
* 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.
*/
#ifndef __EGG_SM_CLIENT_PRIVATE_H__
#define __EGG_SM_CLIENT_PRIVATE_H__
#include <gtk/gtk.h>
#if !GTK_CHECK_VERSION(2,91,7) && !GTK_CHECK_VERSION(3,0,0)
/* GTK+ 3 includes this automatically */
#include <gdkconfig.h>
#endif
#include "eggsmclient.h"
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "EggSMClient"
#if __GNUC__ >= 4
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
G_BEGIN_DECLS
GKeyFile *egg_sm_client_save_state (EggSMClient *client);
void egg_sm_client_quit_requested (EggSMClient *client);
void egg_sm_client_quit_cancelled (EggSMClient *client);
void egg_sm_client_quit (EggSMClient *client);
#if defined (GDK_WINDOWING_X11)
# ifdef EGG_SM_CLIENT_BACKEND_XSMP
GType egg_sm_client_xsmp_get_type (void);
EggSMClient *egg_sm_client_xsmp_new (void);
# endif
# ifdef EGG_SM_CLIENT_BACKEND_DBUS
GType egg_sm_client_dbus_get_type (void);
EggSMClient *egg_sm_client_dbus_new (void);
# endif
#elif defined (GDK_WINDOWING_WIN32)
GType egg_sm_client_win32_get_type (void);
EggSMClient *egg_sm_client_win32_new (void);
#elif defined (GDK_WINDOWING_QUARTZ)
GType egg_sm_client_osx_get_type (void);
EggSMClient *egg_sm_client_osx_new (void);
#endif
G_END_DECLS
#endif /* __EGG_SM_CLIENT_PRIVATE_H__ */

View File

@ -0,0 +1,351 @@
/*
* Copyright (C) 2007 Novell, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
/* EggSMClientWin32
*
* For details on the Windows XP logout process, see:
* http://msdn.microsoft.com/en-us/library/aa376876.aspx.
*
* Vista adds some new APIs which EggSMClient does not make use of; see
* http://msdn.microsoft.com/en-us/library/ms700677(VS.85).aspx
*
* When shutting down, Windows sends every top-level window a
* WM_QUERYENDSESSION event, which the application must respond to
* synchronously, saying whether or not it will quit. To avoid main
* loop re-entrancy problems (and to avoid having to muck about too
* much with the guts of the gdk-win32 main loop), we watch for this
* event in a separate thread, which then signals the main thread and
* waits for the main thread to handle the event. Since we don't want
* to require g_thread_init() to be called, we do this all using
* Windows-specific thread methods.
*
* After the application handles the WM_QUERYENDSESSION event,
* Windows then sends it a WM_ENDSESSION event with a TRUE or FALSE
* parameter indicating whether the session is or is not actually
* going to end now. We handle this from the other thread as well.
*
* As mentioned above, Vista introduces several additional new APIs
* that don't fit into the (current) EggSMClient API. Windows also has
* an entirely separate shutdown-notification scheme for non-GUI apps,
* which we also don't handle here.
*/
#include "config.h"
#include "eggsmclient-private.h"
#include <gdk/gdk.h>
#include <windows.h>
#include <process.h>
#define EGG_TYPE_SM_CLIENT_WIN32 (egg_sm_client_win32_get_type ())
#define EGG_SM_CLIENT_WIN32(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_WIN32, EggSMClientWin32))
#define EGG_SM_CLIENT_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT_WIN32, EggSMClientWin32Class))
#define EGG_IS_SM_CLIENT_WIN32(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT_WIN32))
#define EGG_IS_SM_CLIENT_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT_WIN32))
#define EGG_SM_CLIENT_WIN32_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT_WIN32, EggSMClientWin32Class))
typedef struct _EggSMClientWin32 EggSMClientWin32;
typedef struct _EggSMClientWin32Class EggSMClientWin32Class;
struct _EggSMClientWin32 {
EggSMClient parent;
HANDLE message_event, response_event;
volatile GSourceFunc event;
volatile gboolean will_quit;
};
struct _EggSMClientWin32Class
{
EggSMClientClass parent_class;
};
static void sm_client_win32_startup (EggSMClient *client,
const char *client_id);
static void sm_client_win32_will_quit (EggSMClient *client,
gboolean will_quit);
static gboolean sm_client_win32_end_session (EggSMClient *client,
EggSMClientEndStyle style,
gboolean request_confirmation);
static GSource *g_win32_handle_source_add (HANDLE handle, GSourceFunc callback,
gpointer user_data);
static gboolean got_message (gpointer user_data);
static void sm_client_thread (gpointer data);
G_DEFINE_TYPE (EggSMClientWin32, egg_sm_client_win32, EGG_TYPE_SM_CLIENT)
static void
egg_sm_client_win32_init (EggSMClientWin32 *win32)
{
;
}
static void
egg_sm_client_win32_class_init (EggSMClientWin32Class *klass)
{
EggSMClientClass *sm_client_class = EGG_SM_CLIENT_CLASS (klass);
sm_client_class->startup = sm_client_win32_startup;
sm_client_class->will_quit = sm_client_win32_will_quit;
sm_client_class->end_session = sm_client_win32_end_session;
}
EggSMClient *
egg_sm_client_win32_new (void)
{
return g_object_new (EGG_TYPE_SM_CLIENT_WIN32, NULL);
}
static void
sm_client_win32_startup (EggSMClient *client,
const char *client_id)
{
EggSMClientWin32 *win32 = (EggSMClientWin32 *)client;
win32->message_event = CreateEvent (NULL, FALSE, FALSE, NULL);
win32->response_event = CreateEvent (NULL, FALSE, FALSE, NULL);
g_win32_handle_source_add (win32->message_event, got_message, win32);
_beginthread (sm_client_thread, 0, client);
}
static void
sm_client_win32_will_quit (EggSMClient *client,
gboolean will_quit)
{
EggSMClientWin32 *win32 = (EggSMClientWin32 *)client;
win32->will_quit = will_quit;
SetEvent (win32->response_event);
}
static gboolean
sm_client_win32_end_session (EggSMClient *client,
EggSMClientEndStyle style,
gboolean request_confirmation)
{
UINT uFlags = EWX_LOGOFF;
switch (style)
{
case EGG_SM_CLIENT_END_SESSION_DEFAULT:
case EGG_SM_CLIENT_LOGOUT:
uFlags = EWX_LOGOFF;
break;
case EGG_SM_CLIENT_REBOOT:
uFlags = EWX_REBOOT;
break;
case EGG_SM_CLIENT_SHUTDOWN:
uFlags = EWX_POWEROFF;
break;
}
/* There's no way to make ExitWindowsEx() show a logout dialog, so
* we ignore @request_confirmation.
*/
#ifdef SHTDN_REASON_FLAG_PLANNED
ExitWindowsEx (uFlags, SHTDN_REASON_FLAG_PLANNED);
#else
ExitWindowsEx (uFlags, 0);
#endif
return TRUE;
}
/* callbacks from logout-listener thread */
static gboolean
emit_quit_requested (gpointer smclient)
{
gdk_threads_enter ();
egg_sm_client_quit_requested (smclient);
gdk_threads_leave ();
return FALSE;
}
static gboolean
emit_quit (gpointer smclient)
{
EggSMClientWin32 *win32 = smclient;
gdk_threads_enter ();
egg_sm_client_quit (smclient);
gdk_threads_leave ();
SetEvent (win32->response_event);
return FALSE;
}
static gboolean
emit_quit_cancelled (gpointer smclient)
{
EggSMClientWin32 *win32 = smclient;
gdk_threads_enter ();
egg_sm_client_quit_cancelled (smclient);
gdk_threads_leave ();
SetEvent (win32->response_event);
return FALSE;
}
static gboolean
got_message (gpointer smclient)
{
EggSMClientWin32 *win32 = smclient;
win32->event (win32);
return TRUE;
}
/* Windows HANDLE GSource */
typedef struct {
GSource source;
GPollFD pollfd;
} GWin32HandleSource;
static gboolean
g_win32_handle_source_prepare (GSource *source, gint *timeout)
{
*timeout = -1;
return FALSE;
}
static gboolean
g_win32_handle_source_check (GSource *source)
{
GWin32HandleSource *hsource = (GWin32HandleSource *)source;
return hsource->pollfd.revents;
}
static gboolean
g_win32_handle_source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data)
{
return (*callback) (user_data);
}
static void
g_win32_handle_source_finalize (GSource *source)
{
;
}
GSourceFuncs g_win32_handle_source_funcs = {
g_win32_handle_source_prepare,
g_win32_handle_source_check,
g_win32_handle_source_dispatch,
g_win32_handle_source_finalize
};
static GSource *
g_win32_handle_source_add (HANDLE handle, GSourceFunc callback, gpointer user_data)
{
GWin32HandleSource *hsource;
GSource *source;
source = g_source_new (&g_win32_handle_source_funcs, sizeof (GWin32HandleSource));
hsource = (GWin32HandleSource *)source;
hsource->pollfd.fd = (int)handle;
hsource->pollfd.events = G_IO_IN;
hsource->pollfd.revents = 0;
g_source_add_poll (source, &hsource->pollfd);
g_source_set_callback (source, callback, user_data, NULL);
g_source_attach (source, NULL);
return source;
}
/* logout-listener thread */
static LRESULT CALLBACK
sm_client_win32_window_procedure (HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
EggSMClientWin32 *win32 =
(EggSMClientWin32 *)GetWindowLongPtr (hwnd, GWLP_USERDATA);
switch (message)
{
case WM_QUERYENDSESSION:
win32->event = emit_quit_requested;
SetEvent (win32->message_event);
WaitForSingleObject (win32->response_event, INFINITE);
return win32->will_quit;
case WM_ENDSESSION:
if (wParam)
{
/* The session is ending */
win32->event = emit_quit;
}
else
{
/* Nope, the session *isn't* ending */
win32->event = emit_quit_cancelled;
}
SetEvent (win32->message_event);
WaitForSingleObject (win32->response_event, INFINITE);
return 0;
default:
return DefWindowProc (hwnd, message, wParam, lParam);
}
}
static void
sm_client_thread (gpointer smclient)
{
HINSTANCE instance;
WNDCLASSEXW wcl;
ATOM klass;
HWND window;
MSG msg;
instance = GetModuleHandle (NULL);
memset (&wcl, 0, sizeof (WNDCLASSEX));
wcl.cbSize = sizeof (WNDCLASSEX);
wcl.lpfnWndProc = sm_client_win32_window_procedure;
wcl.hInstance = instance;
wcl.lpszClassName = L"EggSmClientWindow";
klass = RegisterClassEx (&wcl);
window = CreateWindowEx (0, MAKEINTRESOURCE (klass),
L"EggSmClientWindow", 0,
10, 10, 50, 50, GetDesktopWindow (),
NULL, instance, NULL);
SetWindowLongPtr (window, GWLP_USERDATA, (LONG_PTR)smclient);
/* main loop */
while (GetMessage (&msg, NULL, 0, 0))
DispatchMessage (&msg);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,604 @@
/*
* Copyright (C) 2007 Novell, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
#include "config.h"
#include <string.h>
#include <glib/gi18n.h>
#include "eggsmclient.h"
#include "eggsmclient-private.h"
static void egg_sm_client_debug_handler (const char *log_domain,
GLogLevelFlags log_level,
const char *message,
gpointer user_data);
enum {
SAVE_STATE,
QUIT_REQUESTED,
QUIT_CANCELLED,
QUIT,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
struct _EggSMClientPrivate {
GKeyFile *state_file;
};
#define EGG_SM_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), EGG_TYPE_SM_CLIENT, EggSMClientPrivate))
G_DEFINE_TYPE (EggSMClient, egg_sm_client, G_TYPE_OBJECT)
static EggSMClient *global_client;
static EggSMClientMode global_client_mode = EGG_SM_CLIENT_MODE_NORMAL;
static void
egg_sm_client_init (EggSMClient *client)
{
;
}
static void
egg_sm_client_class_init (EggSMClientClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (EggSMClientPrivate));
/**
* EggSMClient::save_state:
* @client: the client
* @state_file: a #GKeyFile to save state information into
*
* Emitted when the session manager has requested that the
* application save information about its current state. The
* application should save its state into @state_file, and then the
* session manager may then restart the application in a future
* session and tell it to initialize itself from that state.
*
* You should not save any data into @state_file's "start group"
* (ie, the %NULL group). Instead, applications should save their
* data into groups with names that start with the application name,
* and libraries that connect to this signal should save their data
* into groups with names that start with the library name.
*
* Alternatively, rather than (or in addition to) using @state_file,
* the application can save its state by calling
* egg_sm_client_set_restart_command() during the processing of this
* signal (eg, to include a list of files to open).
**/
signals[SAVE_STATE] =
g_signal_new ("save_state",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EggSMClientClass, save_state),
NULL, NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE,
1, G_TYPE_POINTER);
/**
* EggSMClient::quit_requested:
* @client: the client
*
* Emitted when the session manager requests that the application
* exit (generally because the user is logging out). The application
* should decide whether or not it is willing to quit (perhaps after
* asking the user what to do with documents that have unsaved
* changes) and then call egg_sm_client_will_quit(), passing %TRUE
* or %FALSE to give its answer to the session manager. (It does not
* need to give an answer before returning from the signal handler;
* it can interact with the user asynchronously and then give its
* answer later on.) If the application does not connect to this
* signal, then #EggSMClient will automatically return %TRUE on its
* behalf.
*
* The application should not save its session state as part of
* handling this signal; if the user has requested that the session
* be saved when logging out, then ::save_state will be emitted
* separately.
*
* If the application agrees to quit, it should then wait for either
* the ::quit_cancelled or ::quit signals to be emitted.
**/
signals[QUIT_REQUESTED] =
g_signal_new ("quit_requested",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EggSMClientClass, quit_requested),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
/**
* EggSMClient::quit_cancelled:
* @client: the client
*
* Emitted when the session manager decides to cancel a logout after
* the application has already agreed to quit. After receiving this
* signal, the application can go back to what it was doing before
* receiving the ::quit_requested signal.
**/
signals[QUIT_CANCELLED] =
g_signal_new ("quit_cancelled",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EggSMClientClass, quit_cancelled),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
/**
* EggSMClient::quit:
* @client: the client
*
* Emitted when the session manager wants the application to quit
* (generally because the user is logging out). The application
* should exit as soon as possible after receiving this signal; if
* it does not, the session manager may choose to forcibly kill it.
*
* Normally a GUI application would only be sent a ::quit if it
* agreed to quit in response to a ::quit_requested signal. However,
* this is not guaranteed; in some situations the session manager
* may decide to end the session without giving applications a
* chance to object.
**/
signals[QUIT] =
g_signal_new ("quit",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EggSMClientClass, quit),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
}
static gboolean sm_client_disable = FALSE;
static char *sm_client_state_file = NULL;
static char *sm_client_id = NULL;
static char *sm_config_prefix = NULL;
static gboolean
sm_client_post_parse_func (GOptionContext *context,
GOptionGroup *group,
gpointer data,
GError **error)
{
EggSMClient *client = egg_sm_client_get ();
if (sm_client_id == NULL)
{
const gchar *desktop_autostart_id;
desktop_autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID");
if (desktop_autostart_id != NULL)
sm_client_id = g_strdup (desktop_autostart_id);
}
/* Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to
* use the same client id. */
g_unsetenv ("DESKTOP_AUTOSTART_ID");
if (global_client_mode != EGG_SM_CLIENT_MODE_DISABLED &&
EGG_SM_CLIENT_GET_CLASS (client)->startup)
EGG_SM_CLIENT_GET_CLASS (client)->startup (client, sm_client_id);
return TRUE;
}
/**
* egg_sm_client_get_option_group:
*
* Creates a %GOptionGroup containing the session-management-related
* options. You should add this group to the application's
* %GOptionContext if you want to use #EggSMClient.
*
* Return value: the %GOptionGroup
**/
GOptionGroup *
egg_sm_client_get_option_group (void)
{
const GOptionEntry entries[] = {
{ "sm-client-disable", 0, 0,
G_OPTION_ARG_NONE, &sm_client_disable,
N_("Disable connection to session manager"), NULL },
{ "sm-client-state-file", 0, 0,
G_OPTION_ARG_FILENAME, &sm_client_state_file,
N_("Specify file containing saved configuration"), N_("FILE") },
{ "sm-client-id", 0, 0,
G_OPTION_ARG_STRING, &sm_client_id,
N_("Specify session management ID"), N_("ID") },
/* GnomeClient compatibility option */
{ "sm-disable", 0, G_OPTION_FLAG_HIDDEN,
G_OPTION_ARG_NONE, &sm_client_disable,
NULL, NULL },
/* GnomeClient compatibility option. This is a dummy option that only
* exists so that sessions saved by apps with GnomeClient can be restored
* later when they've switched to EggSMClient. See bug #575308.
*/
{ "sm-config-prefix", 0, G_OPTION_FLAG_HIDDEN,
G_OPTION_ARG_STRING, &sm_config_prefix,
NULL, NULL },
{ NULL }
};
GOptionGroup *group;
/* Use our own debug handler for the "EggSMClient" domain. */
g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,
egg_sm_client_debug_handler, NULL);
group = g_option_group_new ("sm-client",
_("Session management options:"),
_("Show session management options"),
NULL, NULL);
g_option_group_add_entries (group, entries);
g_option_group_set_parse_hooks (group, NULL, sm_client_post_parse_func);
return group;
}
/**
* egg_sm_client_set_mode:
* @mode: an #EggSMClient mode
*
* Sets the "mode" of #EggSMClient as follows:
*
* %EGG_SM_CLIENT_MODE_DISABLED: Session management is completely
* disabled, until the mode is changed again. The application will
* not even connect to the session manager. (egg_sm_client_get()
* will still return an #EggSMClient object.)
*
* %EGG_SM_CLIENT_MODE_NO_RESTART: The application will connect to
* the session manager (and thus will receive notification when the
* user is logging out, etc), but will request to not be
* automatically restarted with saved state in future sessions.
*
* %EGG_SM_CLIENT_MODE_NORMAL: The default. #EggSMCLient will
* function normally.
*
* This must be called before the application's main loop begins and
* before any call to egg_sm_client_get(), unless the mode was set
* earlier to %EGG_SM_CLIENT_MODE_DISABLED and this call enables
* session management. Note that option parsing will call
* egg_sm_client_get().
**/
void
egg_sm_client_set_mode (EggSMClientMode mode)
{
EggSMClientMode old_mode = global_client_mode;
g_return_if_fail (global_client == NULL || global_client_mode == EGG_SM_CLIENT_MODE_DISABLED);
g_return_if_fail (!(global_client != NULL && mode == EGG_SM_CLIENT_MODE_DISABLED));
global_client_mode = mode;
if (global_client != NULL && old_mode == EGG_SM_CLIENT_MODE_DISABLED)
{
if (EGG_SM_CLIENT_GET_CLASS (global_client)->startup)
EGG_SM_CLIENT_GET_CLASS (global_client)->startup (global_client, sm_client_id);
}
}
/**
* egg_sm_client_get_mode:
*
* Gets the global #EggSMClientMode. See egg_sm_client_set_mode()
* for details.
*
* Return value: the global #EggSMClientMode
**/
EggSMClientMode
egg_sm_client_get_mode (void)
{
return global_client_mode;
}
/**
* egg_sm_client_get:
*
* Returns the master #EggSMClient for the application.
*
* On platforms that support saved sessions (ie, POSIX/X11), the
* application will only request to be restarted by the session
* manager if you call egg_set_desktop_file() to set an application
* desktop file. In particular, if the desktop file contains the key
* "X
*
* Return value: the master #EggSMClient.
**/
EggSMClient *
egg_sm_client_get (void)
{
if (!global_client)
{
if (!sm_client_disable)
{
#if defined (GDK_WINDOWING_WIN32)
global_client = egg_sm_client_win32_new ();
#elif defined (GDK_WINDOWING_QUARTZ)
global_client = egg_sm_client_osx_new ();
#else
/* If both D-Bus and XSMP are compiled in, try XSMP first
* (since it supports state saving) and fall back to D-Bus
* if XSMP isn't available.
*/
# ifdef EGG_SM_CLIENT_BACKEND_XSMP
global_client = egg_sm_client_xsmp_new ();
# endif
# ifdef EGG_SM_CLIENT_BACKEND_DBUS
if (!global_client)
global_client = egg_sm_client_dbus_new ();
# endif
#endif
}
/* Fallback: create a dummy client, so that callers don't have
* to worry about a %NULL return value.
*/
if (!global_client)
global_client = g_object_new (EGG_TYPE_SM_CLIENT, NULL);
}
return global_client;
}
/**
* egg_sm_client_is_resumed:
* @client: the client
*
* Checks whether or not the current session has been resumed from
* a previous saved session. If so, the application should call
* egg_sm_client_get_state_file() and restore its state from the
* returned #GKeyFile.
*
* Return value: %TRUE if the session has been resumed
**/
gboolean
egg_sm_client_is_resumed (EggSMClient *client)
{
g_return_val_if_fail (client == global_client, FALSE);
return sm_client_state_file != NULL;
}
/**
* egg_sm_client_get_state_file:
* @client: the client
*
* If the application was resumed by the session manager, this will
* return the #GKeyFile containing its state from the previous
* session.
*
* Note that other libraries and #EggSMClient itself may also store
* state in the key file, so if you call egg_sm_client_get_groups(),
* on it, the return value will likely include groups that you did not
* put there yourself. (It is also not guaranteed that the first
* group created by the application will still be the "start group"
* when it is resumed.)
*
* Return value: the #GKeyFile containing the application's earlier
* state, or %NULL on error. You should not free this key file; it
* is owned by @client.
**/
GKeyFile *
egg_sm_client_get_state_file (EggSMClient *client)
{
EggSMClientPrivate *priv = EGG_SM_CLIENT_GET_PRIVATE (client);
char *state_file_path;
GError *err = NULL;
g_return_val_if_fail (client == global_client, NULL);
if (!sm_client_state_file)
return NULL;
if (priv->state_file)
return priv->state_file;
if (!strncmp (sm_client_state_file, "file://", 7))
state_file_path = g_filename_from_uri (sm_client_state_file, NULL, NULL);
else
state_file_path = g_strdup (sm_client_state_file);
priv->state_file = g_key_file_new ();
if (!g_key_file_load_from_file (priv->state_file, state_file_path, 0, &err))
{
g_warning ("Could not load SM state file '%s': %s",
sm_client_state_file, err->message);
g_clear_error (&err);
g_key_file_free (priv->state_file);
priv->state_file = NULL;
}
g_free (state_file_path);
return priv->state_file;
}
/**
* egg_sm_client_set_restart_command:
* @client: the client
* @argc: the length of @argv
* @argv: argument vector
*
* Sets the command used to restart @client if it does not have a
* .desktop file that can be used to find its restart command.
*
* This can also be used when handling the ::save_state signal, to
* save the current state via an updated command line. (Eg, providing
* a list of filenames to open when the application is resumed.)
**/
void
egg_sm_client_set_restart_command (EggSMClient *client,
int argc,
const char **argv)
{
g_return_if_fail (EGG_IS_SM_CLIENT (client));
if (EGG_SM_CLIENT_GET_CLASS (client)->set_restart_command)
EGG_SM_CLIENT_GET_CLASS (client)->set_restart_command (client, argc, argv);
}
/**
* egg_sm_client_will_quit:
* @client: the client
* @will_quit: whether or not the application is willing to quit
*
* This MUST be called in response to the ::quit_requested signal, to
* indicate whether or not the application is willing to quit. The
* application may call it either directly from the signal handler, or
* at some later point (eg, after asynchronously interacting with the
* user).
*
* If the application does not connect to ::quit_requested,
* #EggSMClient will call this method on its behalf (passing %TRUE
* for @will_quit).
*
* After calling this method, the application should wait to receive
* either ::quit_cancelled or ::quit.
**/
void
egg_sm_client_will_quit (EggSMClient *client,
gboolean will_quit)
{
g_return_if_fail (EGG_IS_SM_CLIENT (client));
if (EGG_SM_CLIENT_GET_CLASS (client)->will_quit)
EGG_SM_CLIENT_GET_CLASS (client)->will_quit (client, will_quit);
}
/**
* egg_sm_client_end_session:
* @style: a hint at how to end the session
* @request_confirmation: whether or not the user should get a chance
* to confirm the action
*
* Requests that the session manager end the current session. @style
* indicates how the session should be ended, and
* @request_confirmation indicates whether or not the user should be
* given a chance to confirm the logout/reboot/shutdown. Both of these
* flags are merely hints though; the session manager may choose to
* ignore them.
*
* Return value: %TRUE if the request was sent; %FALSE if it could not
* be (eg, because it could not connect to the session manager).
**/
gboolean
egg_sm_client_end_session (EggSMClientEndStyle style,
gboolean request_confirmation)
{
EggSMClient *client = egg_sm_client_get ();
g_return_val_if_fail (EGG_IS_SM_CLIENT (client), FALSE);
if (EGG_SM_CLIENT_GET_CLASS (client)->end_session)
{
return EGG_SM_CLIENT_GET_CLASS (client)->end_session (client, style,
request_confirmation);
}
else
return FALSE;
}
/* Signal-emitting callbacks from platform-specific code */
GKeyFile *
egg_sm_client_save_state (EggSMClient *client)
{
GKeyFile *state_file;
char *group;
g_return_val_if_fail (client == global_client, NULL);
state_file = g_key_file_new ();
g_debug ("Emitting save_state");
g_signal_emit (client, signals[SAVE_STATE], 0, state_file);
g_debug ("Done emitting save_state");
group = g_key_file_get_start_group (state_file);
if (group)
{
g_free (group);
return state_file;
}
else
{
g_key_file_free (state_file);
return NULL;
}
}
void
egg_sm_client_quit_requested (EggSMClient *client)
{
g_return_if_fail (client == global_client);
if (!g_signal_has_handler_pending (client, signals[QUIT_REQUESTED], 0, FALSE))
{
g_debug ("Not emitting quit_requested because no one is listening");
egg_sm_client_will_quit (client, TRUE);
return;
}
g_debug ("Emitting quit_requested");
g_signal_emit (client, signals[QUIT_REQUESTED], 0);
g_debug ("Done emitting quit_requested");
}
void
egg_sm_client_quit_cancelled (EggSMClient *client)
{
g_return_if_fail (client == global_client);
g_debug ("Emitting quit_cancelled");
g_signal_emit (client, signals[QUIT_CANCELLED], 0);
g_debug ("Done emitting quit_cancelled");
}
void
egg_sm_client_quit (EggSMClient *client)
{
g_return_if_fail (client == global_client);
g_debug ("Emitting quit");
g_signal_emit (client, signals[QUIT], 0);
g_debug ("Done emitting quit");
/* FIXME: should we just call gtk_main_quit() here? */
}
static void
egg_sm_client_debug_handler (const char *log_domain,
GLogLevelFlags log_level,
const char *message,
gpointer user_data)
{
static int debug = -1;
if (debug < 0)
debug = (g_getenv ("EGG_SM_CLIENT_DEBUG") != NULL);
if (debug)
g_log_default_handler (log_domain, log_level, message, NULL);
}

View File

@ -0,0 +1,26 @@
SET(eggsmclient_sources
eggsmclient/eggsmclient.cmake
eggsmclient/eggsmclient.c
eggsmclient/eggsmclient.h
eggsmclient/eggsmclient-mangle.h
eggsmclient/eggsmclient-private.h
)
SET(eggsmclient_extra_dist
eggsmclient/eggsmclient-win32.c
eggsmclient/eggsmclient-dummy.c
eggsmclient/eggsmclient-xsmp.c
eggsmclient/eggdesktopfile.h
eggsmclient/eggdesktopfile.c
)
if(MOO_OS_WIN32)
LIST(APPEND eggsmclient_sources eggsmclient/eggsmclient-win32.c)
elseif(MOO_OS_DARWIN)
LIST(APPEND eggsmclient_sources eggsmclient/eggsmclient-dummy.c)
else(MOO_OS_WIN32)
add_definitions(-DEGG_SM_CLIENT_BACKEND_XSMP)
LIST(APPEND eggsmclient_sources eggsmclient/eggsmclient-xsmp.c eggsmclient/eggdesktopfile.h eggsmclient/eggdesktopfile.c)
endif(MOO_OS_WIN32)
# -%- strip:true -%-

View File

@ -0,0 +1,118 @@
/* eggsmclient.h
* Copyright (C) 2007 Novell, Inc.
*
* 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 of the License, or (at your option) any later version.
*
* 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.
*/
#ifndef __EGG_SM_CLIENT_H__
#define __EGG_SM_CLIENT_H__
#include <glib-object.h>
#include "eggsmclient-mangle.h"
G_BEGIN_DECLS
#define EGG_TYPE_SM_CLIENT (egg_sm_client_get_type ())
#define EGG_SM_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT, EggSMClient))
#define EGG_SM_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT, EggSMClientClass))
#define EGG_IS_SM_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT))
#define EGG_IS_SM_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT))
#define EGG_SM_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT, EggSMClientClass))
typedef struct _EggSMClient EggSMClient;
typedef struct _EggSMClientClass EggSMClientClass;
typedef struct _EggSMClientPrivate EggSMClientPrivate;
typedef enum {
EGG_SM_CLIENT_END_SESSION_DEFAULT,
EGG_SM_CLIENT_LOGOUT,
EGG_SM_CLIENT_REBOOT,
EGG_SM_CLIENT_SHUTDOWN
} EggSMClientEndStyle;
typedef enum {
EGG_SM_CLIENT_MODE_DISABLED,
EGG_SM_CLIENT_MODE_NO_RESTART,
EGG_SM_CLIENT_MODE_NORMAL
} EggSMClientMode;
struct _EggSMClient
{
GObject parent;
};
struct _EggSMClientClass
{
GObjectClass parent_class;
/* signals */
void (*save_state) (EggSMClient *client,
GKeyFile *state_file);
void (*quit_requested) (EggSMClient *client);
void (*quit_cancelled) (EggSMClient *client);
void (*quit) (EggSMClient *client);
/* virtual methods */
void (*startup) (EggSMClient *client,
const char *client_id);
void (*set_restart_command) (EggSMClient *client,
int argc,
const char **argv);
void (*will_quit) (EggSMClient *client,
gboolean will_quit);
gboolean (*end_session) (EggSMClient *client,
EggSMClientEndStyle style,
gboolean request_confirmation);
/* Padding for future expansion */
void (*_egg_reserved1) (void);
void (*_egg_reserved2) (void);
void (*_egg_reserved3) (void);
void (*_egg_reserved4) (void);
};
GType egg_sm_client_get_type (void) G_GNUC_CONST;
GOptionGroup *egg_sm_client_get_option_group (void);
/* Initialization */
void egg_sm_client_set_mode (EggSMClientMode mode);
EggSMClientMode egg_sm_client_get_mode (void);
EggSMClient *egg_sm_client_get (void);
/* Resuming a saved session */
gboolean egg_sm_client_is_resumed (EggSMClient *client);
GKeyFile *egg_sm_client_get_state_file (EggSMClient *client);
/* Alternate means of saving state */
void egg_sm_client_set_restart_command (EggSMClient *client,
int argc,
const char **argv);
/* Handling "quit_requested" signal */
void egg_sm_client_will_quit (EggSMClient *client,
gboolean will_quit);
/* Initiate a logout/reboot/shutdown */
gboolean egg_sm_client_end_session (EggSMClientEndStyle style,
gboolean request_confirmation);
G_END_DECLS
#endif /* __EGG_SM_CLIENT_H__ */

View File

@ -0,0 +1,32 @@
moo_sources += \
gtksourceview/gtksourcecontextengine.c \
gtksourceview/gtksourcecontextengine.h \
gtksourceview/gtksourceengine.c \
gtksourceview/gtksourceengine.h \
gtksourceview/gtksourceiter.c \
gtksourceview/gtksourceiter.h \
gtksourceview/gtksourcelanguage-parser-1.c \
gtksourceview/gtksourcelanguage-parser-2.c \
gtksourceview/gtksourcelanguage-private.h \
gtksourceview/gtksourcelanguage.c \
gtksourceview/gtksourcelanguage.h \
gtksourceview/gtksourcelanguagemanager.c \
gtksourceview/gtksourcelanguagemanager.h \
gtksourceview/gtksourcestyle-private.h \
gtksourceview/gtksourcestyle.c \
gtksourceview/gtksourcestyle.h \
gtksourceview/gtksourcestylescheme.c \
gtksourceview/gtksourcestylescheme.h \
gtksourceview/gtksourcestyleschememanager.c \
gtksourceview/gtksourcestyleschememanager.h \
gtksourceview/gtksourceview-utils.c \
gtksourceview/gtksourceview-utils.h \
gtksourceview/gtktextregion.c \
gtksourceview/gtktextregion.h \
gtksourceview/gtksourceview-i18n.h \
gtksourceview/gtksourceview-marshal.h \
gtksourceview/gtksourceview-api.h \
gtksourceview/gtksourcebuffer.h \
gtksourceview/gtksourceview.h
# -%- strip:true -%-

View File

@ -0,0 +1 @@
#include "mooutils/moocompat.h"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,124 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
* gtksourcecontextengine.h
*
* Copyright (C) 2003 - Gustavo Giráldez
* Copyright (C) 2005 - Marco Barisione, Emanuele Aina
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
#ifndef __GTK_SOURCE_CONTEXT_ENGINE_H__
#define __GTK_SOURCE_CONTEXT_ENGINE_H__
#include <gtksourceview/gtksourceengine.h>
#include <gtksourceview/gtksourcelanguage.h>
G_BEGIN_DECLS
#define GTK_TYPE_SOURCE_CONTEXT_ENGINE (_gtk_source_context_engine_get_type ())
#define GTK_SOURCE_CONTEXT_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SOURCE_CONTEXT_ENGINE, GtkSourceContextEngine))
#define GTK_SOURCE_CONTEXT_ENGINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SOURCE_CONTEXT_ENGINE, GtkSourceContextEngineClass))
#define GTK_IS_SOURCE_CONTEXT_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SOURCE_CONTEXT_ENGINE))
#define GTK_IS_SOURCE_CONTEXT_ENGINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SOURCE_CONTEXT_ENGINE))
#define GTK_SOURCE_CONTEXT_ENGINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SOURCE_CONTEXT_ENGINE, GtkSourceContextEngineClass))
typedef struct _GtkSourceContextData GtkSourceContextData;
typedef struct _GtkSourceContextReplace GtkSourceContextReplace;
typedef struct _GtkSourceContextEngine GtkSourceContextEngine;
typedef struct _GtkSourceContextEngineClass GtkSourceContextEngineClass;
typedef struct _GtkSourceContextEnginePrivate GtkSourceContextEnginePrivate;
struct _GtkSourceContextEngine
{
GtkSourceEngine parent_instance;
/*< private >*/
GtkSourceContextEnginePrivate *priv;
};
struct _GtkSourceContextEngineClass
{
GtkSourceEngineClass parent_class;
};
typedef enum {
GTK_SOURCE_CONTEXT_EXTEND_PARENT = 1 << 0,
GTK_SOURCE_CONTEXT_END_PARENT = 1 << 1,
GTK_SOURCE_CONTEXT_END_AT_LINE_END = 1 << 2,
GTK_SOURCE_CONTEXT_FIRST_LINE_ONLY = 1 << 3,
GTK_SOURCE_CONTEXT_ONCE_ONLY = 1 << 4,
GTK_SOURCE_CONTEXT_STYLE_INSIDE = 1 << 5
} GtkSourceContextFlags;
typedef enum {
GTK_SOURCE_CONTEXT_IGNORE_STYLE = 1 << 0,
GTK_SOURCE_CONTEXT_OVERRIDE_STYLE = 1 << 1,
GTK_SOURCE_CONTEXT_REF_ORIGINAL = 1 << 2
} GtkSourceContextRefOptions;
GType _gtk_source_context_engine_get_type (void) G_GNUC_CONST;
GtkSourceContextData *_gtk_source_context_data_new (GtkSourceLanguage *lang);
GtkSourceContextData *_gtk_source_context_data_ref (GtkSourceContextData *data);
void _gtk_source_context_data_unref (GtkSourceContextData *data);
GtkSourceContextEngine *_gtk_source_context_engine_new (GtkSourceContextData *data);
gboolean _gtk_source_context_data_define_context
(GtkSourceContextData *data,
const gchar *id,
const gchar *parent_id,
const gchar *match_regex,
const gchar *start_regex,
const gchar *end_regex,
const gchar *style,
GtkSourceContextFlags flags,
GError **error);
gboolean _gtk_source_context_data_add_sub_pattern
(GtkSourceContextData *data,
const gchar *id,
const gchar *parent_id,
const gchar *name,
const gchar *where,
const gchar *style,
GError **error);
gboolean _gtk_source_context_data_add_ref (GtkSourceContextData *data,
const gchar *parent_id,
const gchar *ref_id,
GtkSourceContextRefOptions options,
const gchar *style,
gboolean all,
GError **error);
GtkSourceContextReplace *
_gtk_source_context_replace_new (const gchar *to_replace_id,
const gchar *replace_with_id);
void _gtk_source_context_replace_free (GtkSourceContextReplace *repl);
gboolean _gtk_source_context_data_finish_parse (GtkSourceContextData *data,
GList *overrides,
GError **error);
/* Only for lang files version 1, do not use it */
void _gtk_source_context_data_set_escape_char
(GtkSourceContextData *data,
gunichar esc_char);
G_END_DECLS
#endif /* __GTK_SOURCE_CONTEXT_ENGINE_H__ */

View File

@ -0,0 +1,106 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
*
* gtksourceengine.c - Abstract base class for highlighting engines
*
* Copyright (C) 2003 - Gustavo Giráldez
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "gtksourcebuffer.h"
#include "gtksourceengine.h"
G_DEFINE_TYPE (GtkSourceEngine, _gtk_source_engine, G_TYPE_OBJECT)
static void
_gtk_source_engine_class_init (GtkSourceEngineClass *klass)
{
klass->attach_buffer = NULL;
}
static void
_gtk_source_engine_init (G_GNUC_UNUSED GtkSourceEngine *engine)
{
}
void
_gtk_source_engine_attach_buffer (GtkSourceEngine *engine,
GtkTextBuffer *buffer)
{
g_return_if_fail (GTK_IS_SOURCE_ENGINE (engine));
g_return_if_fail (GTK_SOURCE_ENGINE_GET_CLASS (engine)->attach_buffer != NULL);
GTK_SOURCE_ENGINE_GET_CLASS (engine)->attach_buffer (engine, buffer);
}
void
_gtk_source_engine_text_inserted (GtkSourceEngine *engine,
gint start_offset,
gint end_offset)
{
g_return_if_fail (GTK_IS_SOURCE_ENGINE (engine));
g_return_if_fail (GTK_SOURCE_ENGINE_GET_CLASS (engine)->text_inserted != NULL);
GTK_SOURCE_ENGINE_GET_CLASS (engine)->text_inserted (engine,
start_offset,
end_offset);
}
void
_gtk_source_engine_text_deleted (GtkSourceEngine *engine,
gint offset,
gint length)
{
g_return_if_fail (GTK_IS_SOURCE_ENGINE (engine));
g_return_if_fail (GTK_SOURCE_ENGINE_GET_CLASS (engine)->text_deleted != NULL);
GTK_SOURCE_ENGINE_GET_CLASS (engine)->text_deleted (engine,
offset,
length);
}
void
_gtk_source_engine_update_highlight (GtkSourceEngine *engine,
const GtkTextIter *start,
const GtkTextIter *end,
gboolean synchronous)
{
g_return_if_fail (GTK_IS_SOURCE_ENGINE (engine));
g_return_if_fail (start != NULL && end != NULL);
g_return_if_fail (GTK_SOURCE_ENGINE_GET_CLASS (engine)->update_highlight != NULL);
GTK_SOURCE_ENGINE_GET_CLASS (engine)->update_highlight (engine,
start,
end,
synchronous);
}
void
_gtk_source_engine_set_style_scheme (GtkSourceEngine *engine,
GtkSourceStyleScheme *scheme)
{
g_return_if_fail (GTK_IS_SOURCE_ENGINE (engine));
g_return_if_fail (GTK_IS_SOURCE_STYLE_SCHEME (scheme));
g_return_if_fail (GTK_SOURCE_ENGINE_GET_CLASS (engine)->set_style_scheme != NULL);
GTK_SOURCE_ENGINE_GET_CLASS (engine)->set_style_scheme (engine, scheme);
}

View File

@ -0,0 +1,87 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
*
* gtksourceengine.h - Abstract base class for highlighting engines
*
* Copyright (C) 2003 - Gustavo Giráldez
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
#ifndef __GTK_SOURCE_ENGINE_H__
#define __GTK_SOURCE_ENGINE_H__
#include <gtk/gtk.h>
#include <gtksourceview/gtksourcestylescheme.h>
G_BEGIN_DECLS
#define GTK_TYPE_SOURCE_ENGINE (_gtk_source_engine_get_type ())
#define GTK_SOURCE_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SOURCE_ENGINE, GtkSourceEngine))
#define GTK_SOURCE_ENGINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SOURCE_ENGINE, GtkSourceEngineClass))
#define GTK_IS_SOURCE_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SOURCE_ENGINE))
#define GTK_IS_SOURCE_ENGINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SOURCE_ENGINE))
#define GTK_SOURCE_ENGINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SOURCE_ENGINE, GtkSourceEngineClass))
typedef struct _GtkSourceEngine GtkSourceEngine;
typedef struct _GtkSourceEngineClass GtkSourceEngineClass;
struct _GtkSourceEngine
{
GObject parent_instance;
};
struct _GtkSourceEngineClass
{
GObjectClass parent_class;
void (* attach_buffer) (GtkSourceEngine *engine,
GtkTextBuffer *buffer);
void (* text_inserted) (GtkSourceEngine *engine,
gint start_offset,
gint end_offset);
void (* text_deleted) (GtkSourceEngine *engine,
gint offset,
gint length);
void (* update_highlight) (GtkSourceEngine *engine,
const GtkTextIter *start,
const GtkTextIter *end,
gboolean synchronous);
void (* set_style_scheme) (GtkSourceEngine *engine,
GtkSourceStyleScheme *scheme);
};
GType _gtk_source_engine_get_type (void) G_GNUC_CONST;
void _gtk_source_engine_attach_buffer (GtkSourceEngine *engine,
GtkTextBuffer *buffer);
void _gtk_source_engine_text_inserted (GtkSourceEngine *engine,
gint start_offset,
gint end_offset);
void _gtk_source_engine_text_deleted (GtkSourceEngine *engine,
gint offset,
gint length);
void _gtk_source_engine_update_highlight (GtkSourceEngine *engine,
const GtkTextIter *start,
const GtkTextIter *end,
gboolean synchronous);
void _gtk_source_engine_set_style_scheme (GtkSourceEngine *engine,
GtkSourceStyleScheme *scheme);
G_END_DECLS
#endif /* __GTK_SOURCE_ENGINE_H__ */

View File

@ -0,0 +1,801 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
* gtksourceiter.h
*
* Copyright (C) 2000 - 2005 Paolo Maggi
* Copyright (C) 2002, 2003 Jeroen Zwartepoorte
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
/*
* Parts of this file are copied from the gedit and glimmer project.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include "gtksourceiter.h"
#define GTK_TEXT_UNKNOWN_CHAR 0xFFFC
#if GLIB_CHECK_VERSION(2,30,0) && !defined(G_UNICODE_COMBINING_MARK)
#define G_UNICODE_COMBINING_MARK G_UNICODE_SPACING_MARK
#endif
/* this function acts like g_utf8_offset_to_pointer() except that if it finds a
* decomposable character it consumes the decomposition length from the given
* offset. So it's useful when the offset was calculated for the normalized
* version of str, but we need a pointer to str itself. */
static const gchar *
pointer_from_offset_skipping_decomp (const gchar *str, gint offset)
{
gchar *casefold, *normal;
const gchar *p, *q;
p = str;
while (offset > 0)
{
q = g_utf8_next_char (p);
casefold = g_utf8_casefold (p, q - p);
normal = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
offset -= g_utf8_strlen (normal, -1);
g_free (casefold);
g_free (normal);
p = q;
}
return p;
}
static gboolean
exact_prefix_cmp (const gchar *string,
const gchar *prefix,
guint prefix_len)
{
GUnicodeType type;
if (strncmp (string, prefix, prefix_len) != 0)
return FALSE;
if (string[prefix_len] == '\0')
return TRUE;
type = g_unichar_type (g_utf8_get_char (string + prefix_len));
/* If string contains prefix, check that prefix is not followed
* by a unicode mark symbol, e.g. that trailing 'a' in prefix
* is not part of two-char a-with-hat symbol in string. */
return type != G_UNICODE_COMBINING_MARK &&
type != G_UNICODE_ENCLOSING_MARK &&
type != G_UNICODE_NON_SPACING_MARK;
}
static const gchar *
utf8_strcasestr (const gchar *haystack, const gchar *needle)
{
gsize needle_len;
gsize haystack_len;
const gchar *ret = NULL;
gchar *p;
gchar *casefold;
gchar *caseless_haystack;
gint i;
g_return_val_if_fail (haystack != NULL, NULL);
g_return_val_if_fail (needle != NULL, NULL);
casefold = g_utf8_casefold (haystack, -1);
caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
g_free (casefold);
needle_len = g_utf8_strlen (needle, -1);
haystack_len = g_utf8_strlen (caseless_haystack, -1);
if (needle_len == 0)
{
ret = (gchar *)haystack;
goto finally_1;
}
if (haystack_len < needle_len)
{
ret = NULL;
goto finally_1;
}
p = (gchar*)caseless_haystack;
needle_len = strlen (needle);
i = 0;
while (*p)
{
if (exact_prefix_cmp (p, needle, needle_len))
{
ret = pointer_from_offset_skipping_decomp (haystack, i);
goto finally_1;
}
p = g_utf8_next_char (p);
i++;
}
finally_1:
g_free (caseless_haystack);
return ret;
}
static const gchar *
utf8_strrcasestr (const gchar *haystack, const gchar *needle)
{
gsize needle_len;
gsize haystack_len;
const gchar *ret = NULL;
gchar *p;
gchar *casefold;
gchar *caseless_haystack;
gint i;
g_return_val_if_fail (haystack != NULL, NULL);
g_return_val_if_fail (needle != NULL, NULL);
casefold = g_utf8_casefold (haystack, -1);
caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
g_free (casefold);
needle_len = g_utf8_strlen (needle, -1);
haystack_len = g_utf8_strlen (caseless_haystack, -1);
if (needle_len == 0)
{
ret = (gchar *)haystack;
goto finally_1;
}
if (haystack_len < needle_len)
{
ret = NULL;
goto finally_1;
}
i = haystack_len - needle_len;
p = g_utf8_offset_to_pointer (caseless_haystack, i);
needle_len = strlen (needle);
while (p >= caseless_haystack)
{
if (exact_prefix_cmp (p, needle, needle_len))
{
ret = pointer_from_offset_skipping_decomp (haystack, i);
goto finally_1;
}
p = g_utf8_prev_char (p);
i--;
}
finally_1:
g_free (caseless_haystack);
return ret;
}
static gboolean
utf8_caselessnmatch (const char *s1, const char *s2,
gssize n1, gssize n2)
{
gchar *casefold;
gchar *normalized_s1;
gchar *normalized_s2;
gssize len_s1;
gssize len_s2;
gboolean ret = FALSE;
g_return_val_if_fail (s1 != NULL, FALSE);
g_return_val_if_fail (s2 != NULL, FALSE);
g_return_val_if_fail (n1 > 0, FALSE);
g_return_val_if_fail (n2 > 0, FALSE);
casefold = g_utf8_casefold (s1, n1);
normalized_s1 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
g_free (casefold);
casefold = g_utf8_casefold (s2, n2);
normalized_s2 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
g_free (casefold);
len_s1 = strlen (normalized_s1);
len_s2 = strlen (normalized_s2);
if (len_s1 < len_s2)
goto finally_2;
ret = (strncmp (normalized_s1, normalized_s2, len_s2) == 0);
finally_2:
g_free (normalized_s1);
g_free (normalized_s2);
return ret;
}
/* FIXME: total horror */
static gboolean
char_is_invisible (const GtkTextIter *iter)
{
GSList *tags;
gboolean invisible = FALSE;
tags = gtk_text_iter_get_tags (iter);
while (tags)
{
gboolean this_invisible, invisible_set;
g_object_get (tags->data, "invisible", &this_invisible,
"invisible-set", &invisible_set, NULL);
if (invisible_set)
invisible = this_invisible;
tags = g_slist_delete_link (tags, tags);
}
return invisible;
}
static void
forward_chars_with_skipping (GtkTextIter *iter,
gint count,
gboolean skip_invisible,
gboolean skip_nontext,
gboolean skip_decomp)
{
gint i;
g_return_if_fail (count >= 0);
i = count;
while (i > 0)
{
gboolean ignored = FALSE;
/* minimal workaround to avoid the infinite loop of bug #168247.
* It doesn't fix the problemjust the symptom...
*/
if (gtk_text_iter_is_end (iter))
return;
if (skip_nontext && gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
ignored = TRUE;
/* FIXME: char_is_invisible() gets list of tags for each char there,
and checks every tag. It doesn't sound like a good idea. */
if (!ignored && skip_invisible && char_is_invisible (iter))
ignored = TRUE;
if (!ignored && skip_decomp)
{
/* being UTF8 correct sucks; this accounts for extra
offsets coming from canonical decompositions of
UTF8 characters (e.g. accented characters) which
g_utf8_normalize() performs */
gchar *normal;
gchar *casefold;
gchar buffer[6];
gint buffer_len;
buffer_len = g_unichar_to_utf8 (gtk_text_iter_get_char (iter), buffer);
casefold = g_utf8_casefold (buffer, buffer_len);
normal = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
i -= (g_utf8_strlen (normal, -1) - 1);
g_free (normal);
g_free (casefold);
}
gtk_text_iter_forward_char (iter);
if (!ignored)
--i;
}
}
static gboolean
lines_match (const GtkTextIter *start,
const gchar **lines,
gboolean visible_only,
gboolean slice,
GtkTextIter *match_start,
GtkTextIter *match_end)
{
GtkTextIter next;
gchar *line_text;
const gchar *found;
gint offset;
if (*lines == NULL || **lines == '\0')
{
if (match_start)
*match_start = *start;
if (match_end)
*match_end = *start;
return TRUE;
}
next = *start;
gtk_text_iter_forward_line (&next);
/* No more text in buffer, but *lines is nonempty */
if (gtk_text_iter_equal (start, &next))
return FALSE;
if (slice)
{
if (visible_only)
line_text = gtk_text_iter_get_visible_slice (start, &next);
else
line_text = gtk_text_iter_get_slice (start, &next);
}
else
{
if (visible_only)
line_text = gtk_text_iter_get_visible_text (start, &next);
else
line_text = gtk_text_iter_get_text (start, &next);
}
if (match_start) /* if this is the first line we're matching */
{
found = utf8_strcasestr (line_text, *lines);
}
else
{
/* If it's not the first line, we have to match from the
* start of the line.
*/
if (utf8_caselessnmatch (line_text, *lines, strlen (line_text),
strlen (*lines)))
found = line_text;
else
found = NULL;
}
if (found == NULL)
{
g_free (line_text);
return FALSE;
}
/* Get offset to start of search string */
offset = g_utf8_strlen (line_text, found - line_text);
next = *start;
/* If match start needs to be returned, set it to the
* start of the search string.
*/
forward_chars_with_skipping (&next, offset, visible_only, !slice, FALSE);
if (match_start)
{
*match_start = next;
}
/* Go to end of search string */
forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1), visible_only, !slice, TRUE);
g_free (line_text);
++lines;
if (match_end)
*match_end = next;
/* pass NULL for match_start, since we don't need to find the
* start again.
*/
return lines_match (&next, lines, visible_only, slice, NULL, match_end);
}
static gboolean
backward_lines_match (const GtkTextIter *start,
const gchar **lines,
gboolean visible_only,
gboolean slice,
GtkTextIter *match_start,
GtkTextIter *match_end)
{
GtkTextIter line, next;
gchar *line_text;
const gchar *found;
gint offset;
if (*lines == NULL || **lines == '\0')
{
if (match_start)
*match_start = *start;
if (match_end)
*match_end = *start;
return TRUE;
}
line = next = *start;
if (gtk_text_iter_get_line_offset (&next) == 0)
{
if (!gtk_text_iter_backward_line (&next))
return FALSE;
}
else
gtk_text_iter_set_line_offset (&next, 0);
if (slice)
{
if (visible_only)
line_text = gtk_text_iter_get_visible_slice (&next, &line);
else
line_text = gtk_text_iter_get_slice (&next, &line);
}
else
{
if (visible_only)
line_text = gtk_text_iter_get_visible_text (&next, &line);
else
line_text = gtk_text_iter_get_text (&next, &line);
}
if (match_start) /* if this is the first line we're matching */
{
found = utf8_strrcasestr (line_text, *lines);
}
else
{
/* If it's not the first line, we have to match from the
* start of the line.
*/
if (utf8_caselessnmatch (line_text, *lines, strlen (line_text),
strlen (*lines)))
found = line_text;
else
found = NULL;
}
if (found == NULL)
{
g_free (line_text);
return FALSE;
}
/* Get offset to start of search string */
offset = g_utf8_strlen (line_text, found - line_text);
forward_chars_with_skipping (&next, offset, visible_only, !slice, FALSE);
/* If match start needs to be returned, set it to the
* start of the search string.
*/
if (match_start)
{
*match_start = next;
}
/* Go to end of search string */
forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1), visible_only, !slice, TRUE);
g_free (line_text);
++lines;
if (match_end)
*match_end = next;
/* try to match the rest of the lines forward, passing NULL
* for match_start so lines_match will try to match the entire
* line */
return lines_match (&next, lines, visible_only,
slice, NULL, match_end);
}
/* strsplit () that retains the delimiter as part of the string. */
static gchar **
breakup_string (const char *string,
const char *delimiter,
gint max_tokens)
{
GSList *string_list = NULL, *slist;
gchar **str_array, *s, *casefold, *new_string;
guint i, n = 1;
g_return_val_if_fail (string != NULL, NULL);
g_return_val_if_fail (delimiter != NULL, NULL);
if (max_tokens < 1)
max_tokens = G_MAXINT;
s = strstr (string, delimiter);
if (s)
{
gsize delimiter_len = strlen (delimiter);
do
{
guint len;
len = s - string + delimiter_len;
new_string = g_new (gchar, len + 1);
strncpy (new_string, string, len);
new_string[len] = 0;
casefold = g_utf8_casefold (new_string, -1);
g_free (new_string);
new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
g_free (casefold);
string_list = g_slist_prepend (string_list, new_string);
n++;
string = s + delimiter_len;
s = strstr (string, delimiter);
} while (--max_tokens && s);
}
if (*string)
{
n++;
casefold = g_utf8_casefold (string, -1);
new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
g_free (casefold);
string_list = g_slist_prepend (string_list, new_string);
}
str_array = g_new (gchar*, n);
i = n - 1;
str_array[i--] = NULL;
for (slist = string_list; slist; slist = slist->next)
str_array[i--] = slist->data;
g_slist_free (string_list);
return str_array;
}
/**
* gtk_source_iter_forward_search:
* @iter: start of search.
* @str: a search string.
* @flags: flags affecting how the search is done.
* @match_start: return location for start of match, or %%NULL.
* @match_end: return location for end of match, or %%NULL.
* @limit: bound for the search, or %%NULL for the end of the buffer.
*
* Searches forward for @str. Any match is returned by setting
* @match_start to the first character of the match and @match_end to the
* first character after the match. The search will not continue past
* @limit. Note that a search is a linear or O(n) operation, so you
* may wish to use @limit to avoid locking up your UI on large
* buffers.
*
* If the #GTK_SOURCE_SEARCH_VISIBLE_ONLY flag is present, the match may
* have invisible text interspersed in @str. i.e. @str will be a
* possibly-noncontiguous subsequence of the matched range. similarly,
* if you specify #GTK_SOURCE_SEARCH_TEXT_ONLY, the match may have
* pixbufs or child widgets mixed inside the matched range. If these
* flags are not given, the match must be exact; the special 0xFFFC
* character in @str will match embedded pixbufs or child widgets.
* If you specify the #GTK_SOURCE_SEARCH_CASE_INSENSITIVE flag, the text will
* be matched regardless of what case it is in.
*
* Same as gtk_text_iter_forward_search(), but supports case insensitive
* searching.
*
* Return value: whether a match was found.
**/
gboolean
gtk_source_iter_forward_search (const GtkTextIter *iter,
const gchar *str,
GtkSourceSearchFlags flags,
GtkTextIter *match_start,
GtkTextIter *match_end,
const GtkTextIter *limit)
{
gchar **lines = NULL;
GtkTextIter match;
gboolean retval = FALSE;
GtkTextIter search;
gboolean visible_only;
gboolean slice;
g_return_val_if_fail (iter != NULL, FALSE);
g_return_val_if_fail (str != NULL, FALSE);
if ((flags & GTK_SOURCE_SEARCH_CASE_INSENSITIVE) == 0)
return gtk_text_iter_forward_search (iter, str, flags,
match_start, match_end,
limit);
if (limit && gtk_text_iter_compare (iter, limit) >= 0)
return FALSE;
if (*str == '\0')
{
/* If we can move one char, return the empty string there */
match = *iter;
if (gtk_text_iter_forward_char (&match))
{
if (limit && gtk_text_iter_equal (&match, limit))
return FALSE;
if (match_start)
*match_start = match;
if (match_end)
*match_end = match;
return TRUE;
}
else
{
return FALSE;
}
}
visible_only = (flags & GTK_SOURCE_SEARCH_VISIBLE_ONLY) != 0;
slice = (flags & GTK_SOURCE_SEARCH_TEXT_ONLY) == 0;
/* locate all lines */
lines = breakup_string (str, "\n", -1);
search = *iter;
do
{
/* This loop has an inefficient worst-case, where
* gtk_text_iter_get_text () is called repeatedly on
* a single line.
*/
GtkTextIter end;
if (limit && gtk_text_iter_compare (&search, limit) >= 0)
break;
if (lines_match (&search, (const gchar**)lines,
visible_only, slice, &match, &end))
{
if (limit == NULL ||
(limit && gtk_text_iter_compare (&end, limit) <= 0))
{
retval = TRUE;
if (match_start)
*match_start = match;
if (match_end)
*match_end = end;
}
break;
}
} while (gtk_text_iter_forward_line (&search));
g_strfreev ((gchar**)lines);
return retval;
}
/**
* gtk_source_iter_backward_search:
* @iter: a #GtkTextIter where the search begins.
* @str: search string.
* @flags: bitmask of flags affecting the search.
* @match_start: return location for start of match, or %%NULL.
* @match_end: return location for end of match, or %%NULL.
* @limit: location of last possible @match_start, or %%NULL for start of buffer.
*
* Same as gtk_text_iter_backward_search(), but supports case insensitive
* searching.
*
* Return value: whether a match was found.
**/
gboolean
gtk_source_iter_backward_search (const GtkTextIter *iter,
const gchar *str,
GtkSourceSearchFlags flags,
GtkTextIter *match_start,
GtkTextIter *match_end,
const GtkTextIter *limit)
{
gchar **lines = NULL;
GtkTextIter match;
gboolean retval = FALSE;
GtkTextIter search;
gboolean visible_only;
gboolean slice;
g_return_val_if_fail (iter != NULL, FALSE);
g_return_val_if_fail (str != NULL, FALSE);
if ((flags & GTK_SOURCE_SEARCH_CASE_INSENSITIVE) == 0)
return gtk_text_iter_backward_search (iter, str, flags,
match_start, match_end,
limit);
if (limit && gtk_text_iter_compare (iter, limit) <= 0)
return FALSE;
if (*str == '\0')
{
/* If we can move one char, return the empty string there */
match = *iter;
if (gtk_text_iter_backward_char (&match))
{
if (limit && gtk_text_iter_equal (&match, limit))
return FALSE;
if (match_start)
*match_start = match;
if (match_end)
*match_end = match;
return TRUE;
}
else
{
return FALSE;
}
}
visible_only = (flags & GTK_SOURCE_SEARCH_VISIBLE_ONLY) != 0;
slice = (flags & GTK_SOURCE_SEARCH_TEXT_ONLY) == 0;
/* locate all lines */
lines = breakup_string (str, "\n", -1);
search = *iter;
while (TRUE)
{
/* This loop has an inefficient worst-case, where
* gtk_text_iter_get_text () is called repeatedly on
* a single line.
*/
GtkTextIter end;
if (limit && gtk_text_iter_compare (&search, limit) <= 0)
break;
if (backward_lines_match (&search, (const gchar**)lines,
visible_only, slice, &match, &end))
{
if (limit == NULL || (limit &&
gtk_text_iter_compare (&end, limit) > 0))
{
retval = TRUE;
if (match_start)
*match_start = match;
if (match_end)
*match_end = end;
}
break;
}
if (gtk_text_iter_get_line_offset (&search) == 0)
{
if (!gtk_text_iter_backward_line (&search))
break;
}
else
{
gtk_text_iter_set_line_offset (&search, 0);
}
}
g_strfreev ((gchar**)lines);
return retval;
}
/*
* gtk_source_iter_find_matching_bracket is implemented in gtksourcebuffer.c
*/

View File

@ -0,0 +1,53 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
* gtksourceiter.h
*
* Copyright (C) 2000, 2002 Paolo Maggi
* Copyright (C) 2002, 2003 Jeroen Zwartepoorte
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
#ifndef __GTK_SOURCE_ITER_H__
#define __GTK_SOURCE_ITER_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
typedef enum
{
GTK_SOURCE_SEARCH_VISIBLE_ONLY = 1 << 0,
GTK_SOURCE_SEARCH_TEXT_ONLY = 1 << 1,
GTK_SOURCE_SEARCH_CASE_INSENSITIVE = 1 << 2
/* Possible future plans: SEARCH_REGEXP */
} GtkSourceSearchFlags;
gboolean gtk_source_iter_forward_search (const GtkTextIter *iter,
const gchar *str,
GtkSourceSearchFlags flags,
GtkTextIter *match_start,
GtkTextIter *match_end,
const GtkTextIter *limit);
gboolean gtk_source_iter_backward_search (const GtkTextIter *iter,
const gchar *str,
GtkSourceSearchFlags flags,
GtkTextIter *match_start,
GtkTextIter *match_end,
const GtkTextIter *limit);
G_END_DECLS
#endif /* __GTK_SOURCE_ITER_H__ */

View File

@ -0,0 +1,793 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
* gtksourcelanguage-parser-ver1.c
* Language specification parser for 1.0 version .lang files
*
* Copyright (C) 2003 - Paolo Maggi <paolo.maggi@polito.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <libxml/parser.h>
#include "gtksourceview-i18n.h"
#include "gtksourcebuffer.h"
#include "gtksourcelanguage.h"
#include "gtksourcelanguage-private.h"
static gchar *
fix_pattern (const gchar *pattern,
gboolean *end_at_line_end)
{
char *slash;
if (pattern == NULL)
return NULL;
slash = strchr (pattern, '/');
if (slash != NULL)
{
GString *str;
str = g_string_new_len (pattern, slash - pattern);
g_string_append (str, "\\/");
pattern = slash + 1;
while ((slash = strchr (pattern, '/')) != NULL)
{
g_string_append_len (str, pattern, slash - pattern);
g_string_append (str, "\\/");
pattern = slash + 1;
}
if (g_str_has_suffix (pattern, "\\n"))
g_string_append_len (str, pattern, strlen(pattern) - 2);
else
g_string_append (str, pattern);
return g_string_free (str, FALSE);
}
else if (g_str_has_suffix (pattern, "\\n"))
{
if (end_at_line_end)
*end_at_line_end = TRUE;
return g_strndup (pattern, strlen (pattern) - 2);
}
else
{
return g_strdup (pattern);
}
}
static gboolean
ctx_data_add_simple_pattern (GtkSourceContextData *ctx_data,
GtkSourceLanguage *language,
const gchar *id,
const gchar *style,
const gchar *pattern)
{
gboolean result;
gchar *real_id, *root_id, *fixed;
GError *error = NULL;
g_return_val_if_fail (id != NULL, FALSE);
root_id = g_strdup_printf ("%s:%s", language->priv->id, language->priv->id);
real_id = g_strdup_printf ("%s:%s", language->priv->id, id);
fixed = fix_pattern (pattern, NULL);
result = _gtk_source_context_data_define_context (ctx_data, real_id,
root_id,
fixed, NULL, NULL,
style,
GTK_SOURCE_CONTEXT_EXTEND_PARENT |
GTK_SOURCE_CONTEXT_END_AT_LINE_END,
&error);
if (error != NULL)
{
g_warning ("%s", error->message);
g_error_free (error);
}
g_free (fixed);
g_free (real_id);
g_free (root_id);
return result;
}
static gboolean
ctx_data_add_syntax_pattern (GtkSourceContextData *ctx_data,
GtkSourceLanguage *language,
const gchar *id,
const gchar *style,
const gchar *pattern_start,
const gchar *pattern_end,
gboolean end_at_line_end)
{
gboolean result;
gchar *real_id, *root_id;
gchar *fixed_start, *fixed_end;
GError *error = NULL;
GtkSourceContextFlags flags = GTK_SOURCE_CONTEXT_EXTEND_PARENT;
g_return_val_if_fail (id != NULL, FALSE);
root_id = g_strdup_printf ("%s:%s", language->priv->id, language->priv->id);
real_id = g_strdup_printf ("%s:%s", language->priv->id, id);
fixed_start = fix_pattern (pattern_start, &end_at_line_end);
fixed_end = fix_pattern (pattern_end, &end_at_line_end);
if (end_at_line_end)
flags |= GTK_SOURCE_CONTEXT_END_AT_LINE_END;
result = _gtk_source_context_data_define_context (ctx_data, real_id, root_id,
NULL,
pattern_start,
pattern_end,
style,
flags,
&error);
if (error != NULL)
{
g_warning ("%s", error->message);
g_error_free (error);
}
g_free (real_id);
g_free (root_id);
g_free (fixed_start);
g_free (fixed_end);
return result;
}
static gchar *
build_keyword_list (const GSList *keywords,
gboolean case_sensitive,
gboolean match_empty_string_at_beginning,
gboolean match_empty_string_at_end,
const gchar *beginning_regex,
const gchar *end_regex)
{
GString *str;
g_return_val_if_fail (keywords != NULL, NULL);
str = g_string_new ("");
if (keywords != NULL)
{
if (match_empty_string_at_beginning)
g_string_append (str, "\\b");
if (beginning_regex != NULL)
g_string_append (str, beginning_regex);
if (case_sensitive)
g_string_append (str, "(?:");
else
g_string_append (str, "(?i:");
/* TODO Make sure pcre can handle big lists, and split lists if necessary.
* See #110991 */
while (keywords != NULL)
{
g_string_append (str, (gchar*) keywords->data);
keywords = g_slist_next (keywords);
if (keywords != NULL)
g_string_append (str, "|");
}
g_string_append (str, ")");
if (end_regex != NULL)
g_string_append (str, end_regex);
if (match_empty_string_at_end)
g_string_append (str, "\\b");
}
return g_string_free (str, FALSE);
}
static void
parseLineComment (xmlNodePtr cur,
gchar *id,
xmlChar *style,
GtkSourceContextData *ctx_data,
GtkSourceLanguage *language)
{
xmlNodePtr child;
child = cur->xmlChildrenNode;
if ((child != NULL) && !xmlStrcmp (child->name, (const xmlChar *)"start-regex"))
{
xmlChar *start_regex;
start_regex = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
ctx_data_add_syntax_pattern (ctx_data, language, id,
(gchar*) style,
(gchar*) start_regex,
NULL, TRUE);
xmlFree (start_regex);
}
else
{
g_warning ("Missing start-regex in tag 'line-comment' (%s, line %ld)",
child->doc->name, xmlGetLineNo (child));
}
}
static void
parseBlockComment (xmlNodePtr cur,
gchar *id,
xmlChar *style,
GtkSourceContextData *ctx_data,
GtkSourceLanguage *language)
{
xmlChar *start_regex = NULL;
xmlChar *end_regex = NULL;
xmlNodePtr child;
child = cur->xmlChildrenNode;
while (child != NULL)
{
if (!xmlStrcmp (child->name, (const xmlChar *)"start-regex"))
{
start_regex = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
}
else
if (!xmlStrcmp (child->name, (const xmlChar *)"end-regex"))
{
end_regex = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
}
child = child->next;
}
if (start_regex == NULL)
{
g_warning ("Missing start-regex in tag 'block-comment' (%s, line %ld)",
child->doc->name, xmlGetLineNo (cur));
return;
}
if (end_regex == NULL)
{
xmlFree (start_regex);
g_warning ("Missing end-regex in tag 'block-comment' (%s, line %ld)",
child->doc->name, xmlGetLineNo (cur));
return;
}
ctx_data_add_syntax_pattern (ctx_data, language, id,
(gchar*) style,
(gchar*) start_regex,
(gchar*) end_regex,
FALSE);
xmlFree (start_regex);
xmlFree (end_regex);
}
static void
parseString (xmlNodePtr cur,
gchar *id,
xmlChar *style,
GtkSourceContextData *ctx_data,
GtkSourceLanguage *language)
{
xmlChar *start_regex = NULL;
xmlChar *end_regex = NULL;
xmlChar *prop = NULL;
gboolean end_at_line_end = TRUE;
xmlNodePtr child;
prop = xmlGetProp (cur, BAD_CAST "end-at-line-end");
if (prop != NULL)
{
if (!xmlStrcasecmp (prop, (const xmlChar *)"TRUE") ||
!xmlStrcmp (prop, (const xmlChar *)"1"))
end_at_line_end = TRUE;
else
end_at_line_end = FALSE;
xmlFree (prop);
}
child = cur->xmlChildrenNode;
while (child != NULL)
{
if (!xmlStrcmp (child->name, (const xmlChar *)"start-regex"))
{
start_regex = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
}
else
if (!xmlStrcmp (child->name, (const xmlChar *)"end-regex"))
{
end_regex = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
}
child = child->next;
}
if (start_regex == NULL)
{
g_warning ("Missing start-regex in tag 'string' (%s, line %ld)",
child->doc->name, xmlGetLineNo (cur));
return;
}
if (end_regex == NULL)
{
xmlFree (start_regex);
g_warning ("Missing end-regex in tag 'string' (%s, line %ld)",
child->doc->name, xmlGetLineNo (cur));
return;
}
ctx_data_add_syntax_pattern (ctx_data, language, id,
(gchar*) style,
(gchar*) start_regex,
(gchar*) end_regex,
end_at_line_end);
xmlFree (start_regex);
xmlFree (end_regex);
}
static void
parseKeywordList (xmlNodePtr cur,
gchar *id,
xmlChar *style,
GtkSourceContextData *ctx_data,
GtkSourceLanguage *language)
{
gboolean case_sensitive = TRUE;
gboolean match_empty_string_at_beginning = TRUE;
gboolean match_empty_string_at_end = TRUE;
gchar *beginning_regex = NULL;
gchar *end_regex = NULL;
GSList *list = NULL;
gchar *regex;
xmlChar *prop;
xmlNodePtr child;
prop = xmlGetProp (cur, BAD_CAST "case-sensitive");
if (prop != NULL)
{
if (!xmlStrcasecmp (prop, (const xmlChar *)"TRUE") ||
!xmlStrcmp (prop, (const xmlChar *)"1"))
case_sensitive = TRUE;
else
case_sensitive = FALSE;
xmlFree (prop);
}
prop = xmlGetProp (cur, BAD_CAST "match-empty-string-at-beginning");
if (prop != NULL)
{
if (!xmlStrcasecmp (prop, (const xmlChar *)"TRUE") ||
!xmlStrcmp (prop, (const xmlChar *)"1"))
match_empty_string_at_beginning = TRUE;
else
match_empty_string_at_beginning = FALSE;
xmlFree (prop);
}
prop = xmlGetProp (cur, BAD_CAST "match-empty-string-at-end");
if (prop != NULL)
{
if (!xmlStrcasecmp (prop, (const xmlChar *)"TRUE") ||
!xmlStrcmp (prop, (const xmlChar *)"1"))
match_empty_string_at_end = TRUE;
else
match_empty_string_at_end = FALSE;
xmlFree (prop);
}
prop = xmlGetProp (cur, BAD_CAST "beginning-regex");
if (prop != NULL)
{
beginning_regex = g_strdup ((gchar *)prop);
xmlFree (prop);
}
prop = xmlGetProp (cur, BAD_CAST "end-regex");
if (prop != NULL)
{
end_regex = g_strdup ((gchar *)prop);
xmlFree (prop);
}
child = cur->xmlChildrenNode;
while (child != NULL)
{
if (!xmlStrcmp (child->name, BAD_CAST "keyword"))
{
xmlChar *keyword;
keyword = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
list = g_slist_prepend (list, keyword);
}
child = child->next;
}
list = g_slist_reverse (list);
if (list == NULL)
{
g_warning ("No keywords in tag 'keyword-list' (%s, line %ld)",
child->doc->name, xmlGetLineNo (cur));
g_free (beginning_regex),
g_free (end_regex);
return;
}
regex = build_keyword_list (list,
case_sensitive,
match_empty_string_at_beginning,
match_empty_string_at_end,
beginning_regex,
end_regex);
g_free (beginning_regex),
g_free (end_regex);
g_slist_foreach (list, (GFunc) xmlFree, NULL);
g_slist_free (list);
ctx_data_add_simple_pattern (ctx_data, language, id, (gchar*) style, regex);
g_free (regex);
}
static void
parsePatternItem (xmlNodePtr cur,
gchar *id,
xmlChar *style,
GtkSourceContextData *ctx_data,
GtkSourceLanguage *language)
{
xmlNodePtr child;
child = cur->xmlChildrenNode;
if ((child != NULL) && !xmlStrcmp (child->name, (const xmlChar *)"regex"))
{
xmlChar *regex;
regex = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
ctx_data_add_simple_pattern (ctx_data, language, id,
(gchar*) style,
(gchar*) regex);
xmlFree (regex);
}
else
{
g_warning ("Missing regex in tag 'pattern-item' (%s, line %ld)",
child->doc->name, xmlGetLineNo (child));
}
}
static void
parseSyntaxItem (xmlNodePtr cur,
const gchar *id,
xmlChar *style,
GtkSourceContextData *ctx_data,
GtkSourceLanguage *language)
{
xmlChar *start_regex = NULL;
xmlChar *end_regex = NULL;
xmlNodePtr child;
child = cur->xmlChildrenNode;
while (child != NULL)
{
if (!xmlStrcmp (child->name, (const xmlChar *)"start-regex"))
{
start_regex = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
}
else
if (!xmlStrcmp (child->name, (const xmlChar *)"end-regex"))
{
end_regex = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
}
child = child->next;
}
if (start_regex == NULL)
{
g_warning ("Missing start-regex in tag 'syntax-item' (%s, line %ld)",
child->doc->name, xmlGetLineNo (cur));
return;
}
if (end_regex == NULL)
{
xmlFree (start_regex);
g_warning ("Missing end-regex in tag 'syntax-item' (%s, line %ld)",
child->doc->name, xmlGetLineNo (cur));
return;
}
ctx_data_add_syntax_pattern (ctx_data, language, id,
(gchar*) style,
(gchar*) start_regex,
(gchar*) end_regex,
FALSE);
xmlFree (start_regex);
xmlFree (end_regex);
}
static void
parseTag (GtkSourceLanguage *language,
xmlNodePtr cur,
GtkSourceContextData *ctx_data)
{
xmlChar *name;
xmlChar *style;
xmlChar *id;
name = xmlGetProp (cur, BAD_CAST "_name");
if (name == NULL)
{
name = xmlGetProp (cur, BAD_CAST "name");
id = xmlStrdup (name);
}
else
{
gchar *tmp1 = _gtk_source_language_translate_string (language, (gchar*) name);
xmlChar *tmp2 = xmlStrdup (BAD_CAST tmp1);
id = name;
name = tmp2;
g_free (tmp1);
}
if (name == NULL)
{
return;
}
style = xmlGetProp (cur, BAD_CAST "style");
if (!xmlStrcmp (cur->name, (const xmlChar*) "line-comment"))
{
parseLineComment (cur, (gchar*) id, style, ctx_data, language);
}
else if (!xmlStrcmp (cur->name, (const xmlChar*) "block-comment"))
{
parseBlockComment (cur, (gchar*) id, style, ctx_data, language);
}
else if (!xmlStrcmp (cur->name, (const xmlChar*) "string"))
{
parseString (cur, (gchar*) id, style, ctx_data, language);
}
else if (!xmlStrcmp (cur->name, (const xmlChar*) "keyword-list"))
{
parseKeywordList (cur, (gchar*) id, style, ctx_data, language);
}
else if (!xmlStrcmp (cur->name, (const xmlChar*) "pattern-item"))
{
parsePatternItem (cur, (gchar*) id, style, ctx_data, language);
}
else if (!xmlStrcmp (cur->name, (const xmlChar*) "syntax-item"))
{
parseSyntaxItem (cur, (gchar*) id, style, ctx_data, language);
}
else
{
g_print ("Unknown tag: %s\n", cur->name);
}
xmlFree (name);
xmlFree (style);
xmlFree (id);
}
static gboolean
define_root_context (GtkSourceContextData *ctx_data,
GtkSourceLanguage *language)
{
gboolean result;
gchar *id;
GError *error = NULL;
g_return_val_if_fail (language->priv->id != NULL, FALSE);
id = g_strdup_printf ("%s:%s", language->priv->id, language->priv->id);
result = _gtk_source_context_data_define_context (ctx_data, id,
NULL, NULL, NULL, NULL,
NULL,
GTK_SOURCE_CONTEXT_EXTEND_PARENT,
&error);
if (error != NULL)
{
g_warning ("%s", error->message);
g_error_free (error);
}
g_free (id);
return result;
}
gboolean
_gtk_source_language_file_parse_version1 (GtkSourceLanguage *language,
GtkSourceContextData *ctx_data)
{
xmlDocPtr doc;
xmlNodePtr cur;
GMappedFile *mf;
gunichar esc_char = 0;
xmlChar *lang_version = NULL;
xmlKeepBlanksDefault (0);
mf = g_mapped_file_new (language->priv->lang_file_name, FALSE, NULL);
if (mf == NULL)
{
doc = NULL;
}
else
{
doc = xmlParseMemory (g_mapped_file_get_contents (mf),
g_mapped_file_get_length (mf));
g_mapped_file_unref (mf);
}
if (doc == NULL)
{
g_warning ("Impossible to parse file '%s'",
language->priv->lang_file_name);
return FALSE;
}
cur = xmlDocGetRootElement (doc);
if (cur == NULL)
{
g_warning ("The lang file '%s' is empty",
language->priv->lang_file_name);
goto error;
}
if (xmlStrcmp (cur->name, (const xmlChar *) "language") != 0)
{
g_warning ("File '%s' is of the wrong type",
language->priv->lang_file_name);
goto error;
}
lang_version = xmlGetProp (cur, BAD_CAST "version");
if (lang_version == NULL || strcmp ("1.0", (char*) lang_version) != 0)
{
if (lang_version != NULL)
g_warning ("Wrong language version '%s' in file '%s', expected '%s'",
(char*) lang_version, language->priv->lang_file_name, "1.0");
else
g_warning ("Language version missing in file '%s'",
language->priv->lang_file_name);
goto error;
}
if (!define_root_context (ctx_data, language))
{
g_warning ("Could not create root context for file '%s'",
language->priv->lang_file_name);
goto error;
}
/* FIXME: check that the language name, version, etc. are the
* right ones - Paolo */
cur = xmlDocGetRootElement (doc);
cur = cur->xmlChildrenNode;
g_return_val_if_fail (cur != NULL, FALSE);
while (cur != NULL)
{
if (!xmlStrcmp (cur->name, (const xmlChar *)"escape-char"))
{
xmlChar *escape;
escape = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
esc_char = g_utf8_get_char_validated ((gchar*) escape, -1);
if (esc_char == (gunichar) -1 || esc_char == (gunichar) -2)
{
g_warning ("Invalid (non UTF8) escape character in file '%s'",
language->priv->lang_file_name);
esc_char = 0;
}
xmlFree (escape);
}
else
{
parseTag (language, cur, ctx_data);
}
cur = cur->next;
}
if (esc_char != 0)
_gtk_source_context_data_set_escape_char (ctx_data, esc_char);
_gtk_source_context_data_finish_parse (ctx_data, NULL, NULL);
_gtk_source_language_define_language_styles (language);
xmlFreeDoc (doc);
xmlFree (lang_version);
return TRUE;
error:
if (doc)
xmlFreeDoc (doc);
xmlFree (lang_version);
return FALSE;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,94 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
* gtksourcelanguage-private.h
*
* Copyright (C) 2003 - Paolo Maggi <paolo.maggi@polito.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
#ifndef __GTK_SOURCE_LANGUAGE_PRIVATE_H__
#define __GTK_SOURCE_LANGUAGE_PRIVATE_H__
#include <mooglib/moo-glib.h>
#include "gtksourcecontextengine.h"
#include "gtksourcelanguagemanager.h"
G_BEGIN_DECLS
#define GTK_SOURCE_LANGUAGE_VERSION_1_0 100
#define GTK_SOURCE_LANGUAGE_VERSION_2_0 200
typedef struct _GtkSourceStyleInfo GtkSourceStyleInfo;
struct _GtkSourceStyleInfo
{
gchar *name;
gchar *map_to;
};
struct _GtkSourceLanguagePrivate
{
gchar *lang_file_name;
gchar *translation_domain;
gchar *id;
gchar *name;
gchar *section;
/* Maps ids to GtkSourceStyleInfo objects */
/* Names of styles defined in other lang files are not stored */
GHashTable *styles;
gboolean styles_loaded;
gint version;
gboolean hidden;
GHashTable *properties;
GtkSourceLanguageManager *language_manager;
GtkSourceContextData *ctx_data;
};
GtkSourceLanguage *_gtk_source_language_new_from_file (const gchar *filename,
GtkSourceLanguageManager *lm);
GtkSourceLanguageManager *_gtk_source_language_get_language_manager (GtkSourceLanguage *language);
const gchar *_gtk_source_language_manager_get_rng_file (GtkSourceLanguageManager *lm);
gchar *_gtk_source_language_translate_string (GtkSourceLanguage *language,
const gchar *string);
void _gtk_source_language_define_language_styles (GtkSourceLanguage *language);
gboolean _gtk_source_language_file_parse_version1 (GtkSourceLanguage *language,
GtkSourceContextData *ctx_data);
gboolean _gtk_source_language_file_parse_version2 (GtkSourceLanguage *language,
GtkSourceContextData *ctx_data);
GtkSourceEngine *_gtk_source_language_create_engine (GtkSourceLanguage *language);
/* Utility functions for GtkSourceStyleInfo */
GtkSourceStyleInfo *_gtk_source_style_info_new (const gchar *name,
const gchar *map_to);
GtkSourceStyleInfo *_gtk_source_style_info_copy (GtkSourceStyleInfo *info);
void _gtk_source_style_info_free (GtkSourceStyleInfo *info);
G_END_DECLS
#endif /* __GTK_SOURCE_LANGUAGE_PRIVATE_H__ */

View File

@ -0,0 +1,906 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
* gtksourcelanguage.c
*
* Copyright (C) 2003 - Paolo Maggi <paolo.maggi@polito.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef G_OS_WIN32
#include <io.h>
#endif
#include <string.h>
#include <fcntl.h>
#include <libxml/xmlreader.h>
#include <mooglib/moo-glib.h>
#include "gtksourceview-i18n.h"
#include "gtksourcelanguage-private.h"
#include "gtksourcelanguage.h"
#include "gtksourceview-marshal.h"
#define DEFAULT_SECTION _("Others")
/* Properties */
enum {
PROP_0,
PROP_ID,
PROP_NAME,
PROP_SECTION,
PROP_HIDDEN
};
G_DEFINE_TYPE (GtkSourceLanguage, gtk_source_language, G_TYPE_OBJECT)
static GtkSourceLanguage *process_language_node (xmlTextReaderPtr reader,
const gchar *filename);
static gboolean force_styles (GtkSourceLanguage *language);
GtkSourceLanguage *
_gtk_source_language_new_from_file (const gchar *filename,
GtkSourceLanguageManager *lm)
{
GtkSourceLanguage *lang = NULL;
xmlTextReaderPtr reader = NULL;
gint ret;
g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (lm != NULL, NULL);
reader = xmlReaderForFile (filename, NULL, 0);
if (reader != NULL)
{
ret = xmlTextReaderRead (reader);
while (ret == 1)
{
if (xmlTextReaderNodeType (reader) == 1)
{
xmlChar *name;
name = xmlTextReaderName (reader);
if (xmlStrcmp (name, BAD_CAST "language") == 0)
{
lang = process_language_node (reader, filename);
ret = 0;
}
xmlFree (name);
}
if (ret == 1)
ret = xmlTextReaderRead (reader);
}
xmlFreeTextReader (reader);
if (ret != 0)
{
g_warning("Failed to parse '%s'", filename);
return NULL;
}
}
else
{
g_warning("Unable to open '%s'", filename);
}
if (lang != NULL)
{
lang->priv->language_manager = lm;
g_object_add_weak_pointer (G_OBJECT (lm),
(gpointer) &lang->priv->language_manager);
}
return lang;
}
static void
gtk_source_language_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkSourceLanguage *language;
g_return_if_fail (GTK_IS_SOURCE_LANGUAGE (object));
language = GTK_SOURCE_LANGUAGE (object);
switch (prop_id)
{
case PROP_ID:
g_value_set_string (value, language->priv->id);
break;
case PROP_NAME:
g_value_set_string (value, language->priv->name);
break;
case PROP_SECTION:
g_value_set_string (value, language->priv->section);
break;
case PROP_HIDDEN:
g_value_set_boolean (value, language->priv->hidden);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_source_language_dispose (GObject *object)
{
GtkSourceLanguage *lang;
lang = GTK_SOURCE_LANGUAGE (object);
if (lang->priv->language_manager != NULL)
{
g_object_remove_weak_pointer (G_OBJECT (lang->priv->language_manager),
(gpointer) &lang->priv->language_manager);
lang->priv->language_manager = NULL;
}
G_OBJECT_CLASS (gtk_source_language_parent_class)->dispose (object);
}
static void
gtk_source_language_finalize (GObject *object)
{
GtkSourceLanguage *lang;
lang = GTK_SOURCE_LANGUAGE (object);
if (lang->priv->ctx_data != NULL)
g_critical ("context data not freed in gtk_source_language_finalize");
g_free (lang->priv->lang_file_name);
g_free (lang->priv->translation_domain);
g_free (lang->priv->name);
g_free (lang->priv->section);
g_free (lang->priv->id);
g_hash_table_destroy (lang->priv->properties);
g_hash_table_destroy (lang->priv->styles);
G_OBJECT_CLASS (gtk_source_language_parent_class)->finalize (object);
}
static void
gtk_source_language_class_init (GtkSourceLanguageClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = gtk_source_language_get_property;
object_class->dispose = gtk_source_language_dispose;
object_class->finalize = gtk_source_language_finalize;
g_object_class_install_property (object_class,
PROP_ID,
g_param_spec_string ("id",
_("Language id"),
_("Language id"),
NULL,
G_PARAM_READABLE));
g_object_class_install_property (object_class,
PROP_NAME,
g_param_spec_string ("name",
_("Language name"),
_("Language name"),
NULL,
G_PARAM_READABLE));
g_object_class_install_property (object_class,
PROP_SECTION,
g_param_spec_string ("section",
_("Language section"),
_("Language section"),
NULL,
G_PARAM_READABLE));
g_object_class_install_property (object_class,
PROP_HIDDEN,
g_param_spec_boolean ("hidden",
_("Hidden"),
_("Whether the language should be hidden from the user"),
FALSE,
G_PARAM_READABLE));
g_type_class_add_private (object_class, sizeof(GtkSourceLanguagePrivate));
}
static void
gtk_source_language_init (GtkSourceLanguage *lang)
{
lang->priv = G_TYPE_INSTANCE_GET_PRIVATE (lang, GTK_TYPE_SOURCE_LANGUAGE,
GtkSourceLanguagePrivate);
lang->priv->styles = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
(GDestroyNotify)_gtk_source_style_info_free);
lang->priv->properties = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
}
static gboolean
string_to_bool (const gchar *string)
{
if (!g_ascii_strcasecmp (string, "yes") ||
!g_ascii_strcasecmp (string, "true") ||
!g_ascii_strcasecmp (string, "1"))
return TRUE;
else if (!g_ascii_strcasecmp (string, "no") ||
!g_ascii_strcasecmp (string, "false") ||
!g_ascii_strcasecmp (string, "0"))
return FALSE;
else
g_return_val_if_reached (FALSE);
}
static void
process_properties (xmlTextReaderPtr reader,
GtkSourceLanguage *language)
{
xmlNodePtr child;
xmlNodePtr node = NULL;
while (node == NULL && xmlTextReaderRead (reader) == 1)
{
xmlChar *name;
if (xmlTextReaderNodeType (reader) != 1)
continue;
name = xmlTextReaderName (reader);
if (xmlStrcmp (name, BAD_CAST "metadata") != 0)
{
xmlFree (name);
continue;
}
xmlFree (name);
node = xmlTextReaderExpand (reader);
if (node == NULL)
return;
}
if (node == NULL)
return;
for (child = node->children; child != NULL; child = child->next)
{
xmlChar *name;
xmlChar *content;
if (child->type != XML_ELEMENT_NODE ||
xmlStrcmp (child->name, BAD_CAST "property") != 0)
continue;
name = xmlGetProp (child, BAD_CAST "name");
content = xmlNodeGetContent (child);
if (name != NULL && content != NULL)
g_hash_table_insert (language->priv->properties,
g_strdup ((gchar *) name),
g_strdup ((gchar *) content));
xmlFree (name);
xmlFree (content);
}
}
static GtkSourceLanguage *
process_language_node (xmlTextReaderPtr reader, const gchar *filename)
{
xmlChar *version;
xmlChar *tmp;
xmlChar *untranslated_name;
GtkSourceLanguage *lang;
lang = g_object_new (GTK_TYPE_SOURCE_LANGUAGE, NULL);
lang->priv->lang_file_name = g_strdup (filename);
tmp = xmlTextReaderGetAttribute (reader, BAD_CAST "translation-domain");
lang->priv->translation_domain = g_strdup ((gchar*) tmp);
xmlFree (tmp);
tmp = xmlTextReaderGetAttribute (reader, BAD_CAST "hidden");
if (tmp != NULL)
lang->priv->hidden = string_to_bool ((gchar*) tmp);
else
lang->priv->hidden = FALSE;
xmlFree (tmp);
tmp = xmlTextReaderGetAttribute (reader, BAD_CAST "mimetypes");
if (tmp != NULL)
g_hash_table_insert (lang->priv->properties,
g_strdup ("mimetypes"),
g_strdup ((char*) tmp));
xmlFree (tmp);
tmp = xmlTextReaderGetAttribute (reader, BAD_CAST "globs");
if (tmp != NULL)
g_hash_table_insert (lang->priv->properties,
g_strdup ("globs"),
g_strdup ((char*) tmp));
xmlFree (tmp);
tmp = xmlTextReaderGetAttribute (reader, BAD_CAST "_name");
if (tmp == NULL)
{
tmp = xmlTextReaderGetAttribute (reader, BAD_CAST "name");
if (tmp == NULL)
{
g_warning ("Impossible to get language name from file '%s'",
filename);
g_object_unref (lang);
return NULL;
}
lang->priv->name = g_strdup ((char*) tmp);
untranslated_name = tmp;
}
else
{
lang->priv->name = _gtk_source_language_translate_string (lang, (gchar*) tmp);
untranslated_name = tmp;
}
tmp = xmlTextReaderGetAttribute (reader, BAD_CAST "id");
if (tmp != NULL)
{
lang->priv->id = g_ascii_strdown ((gchar*) tmp, -1);
}
else
{
lang->priv->id = g_ascii_strdown ((gchar*) untranslated_name, -1);
}
xmlFree (tmp);
xmlFree (untranslated_name);
tmp = xmlTextReaderGetAttribute (reader, BAD_CAST "_section");
if (tmp == NULL)
{
tmp = xmlTextReaderGetAttribute (reader, BAD_CAST "section");
if (tmp == NULL)
lang->priv->section = g_strdup (DEFAULT_SECTION);
else
lang->priv->section = g_strdup ((gchar *) tmp);
xmlFree (tmp);
}
else
{
lang->priv->section = _gtk_source_language_translate_string (lang, (gchar*) tmp);
xmlFree (tmp);
}
version = xmlTextReaderGetAttribute (reader, BAD_CAST "version");
if (version == NULL)
{
g_warning ("Impossible to get version number from file '%s'",
filename);
g_object_unref (lang);
return NULL;
}
if (xmlStrcmp (version , BAD_CAST "1.0") == 0)
{
lang->priv->version = GTK_SOURCE_LANGUAGE_VERSION_1_0;
}
else if (xmlStrcmp (version, BAD_CAST "2.0") == 0)
{
lang->priv->version = GTK_SOURCE_LANGUAGE_VERSION_2_0;
}
else
{
g_warning ("Unsupported language spec version '%s' in file '%s'",
(gchar*) version, filename);
xmlFree (version);
g_object_unref (lang);
return NULL;
}
xmlFree (version);
if (lang->priv->version == GTK_SOURCE_LANGUAGE_VERSION_2_0)
process_properties (reader, lang);
return lang;
}
gchar *
_gtk_source_language_translate_string (GtkSourceLanguage *language,
const gchar *string)
{
g_return_val_if_fail (string != NULL, NULL);
return GD_(language->priv->translation_domain, string);
}
/**
* gtk_source_language_get_id:
* @language: a #GtkSourceLanguage.
*
* Returns the ID of the language. The ID is not locale-dependent.
*
* Returns: the ID of @language.
* The returned string is owned by @language and should not be freed
* or modified.
**/
const gchar *
gtk_source_language_get_id (GtkSourceLanguage *language)
{
g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE (language), NULL);
g_return_val_if_fail (language->priv->id != NULL, NULL);
return language->priv->id;
}
/**
* gtk_source_language_get_name:
* @language: a #GtkSourceLanguage.
*
* Returns the localized name of the language.
*
* Returns: the name of @language.
* The returned string is owned by @language and should not be freed
* or modified.
**/
const gchar *
gtk_source_language_get_name (GtkSourceLanguage *language)
{
g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE (language), NULL);
g_return_val_if_fail (language->priv->name != NULL, NULL);
return language->priv->name;
}
/**
* gtk_source_language_get_section:
* @language: a #GtkSourceLanguage.
*
* Returns the localized section of the language.
* Each language belong to a section (ex. HTML belogs to the
* Markup section).
*
* Returns: the section of @language.
* The returned string is owned by @language and should not be freed
* or modified.
**/
const gchar *
gtk_source_language_get_section (GtkSourceLanguage *language)
{
g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE (language), NULL);
g_return_val_if_fail (language->priv->section != NULL, NULL);
return language->priv->section;
}
/**
* gtk_source_language_get_hidden:
* @language: a #GtkSourceLanguage
*
* Returns whether the language should be hidden from the user.
*
* Returns: TRUE if the language should be hidden, FALSE otherwise.
*/
gboolean
gtk_source_language_get_hidden (GtkSourceLanguage *language)
{
g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE (language), FALSE);
return language->priv->hidden;
}
/**
* gtk_source_language_get_metadata:
* @language: a #GtkSourceLanguage.
* @name: metadata property name.
*
* Returns: value of property @name stored in the metadata of @language
* or %NULL if language doesn't contain that metadata property.
* The returned string is owned by @language and should not be freed
* or modified.
**/
const gchar *
gtk_source_language_get_metadata (GtkSourceLanguage *language,
const gchar *name)
{
g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE (language), NULL);
g_return_val_if_fail (name != NULL, NULL);
return g_hash_table_lookup (language->priv->properties, name);
}
/**
* gtk_source_language_get_mime_types:
* @language: a #GtkSourceLanguage.
*
* Returns the mime types associated to this language. This is just
* an utility wrapper around gtk_source_language_get_metadata() to
* retrieve the "mimetypes" metadata property and split it into an
* array.
*
* Returns: a newly-allocated %NULL terminated array containing
* the mime types or %NULL if no mime types are found.
* The returned array must be freed with g_strfreev().
**/
gchar **
gtk_source_language_get_mime_types (GtkSourceLanguage *language)
{
const gchar *mimetypes;
g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE (language), NULL);
mimetypes = gtk_source_language_get_metadata (language, "mimetypes");
if (mimetypes == NULL)
return NULL;
return g_strsplit (mimetypes, ";", 0);
}
/**
* gtk_source_language_get_globs:
* @language: a #GtkSourceLanguage.
*
* Returns the globs associated to this language. This is just
* an utility wrapper around gtk_source_language_get_metadata() to
* retrieve the "globs" metadata property and split it into an array.
*
* Returns: a newly-allocated %NULL terminated array containing
* the globs or %NULL if no globs are found.
* The returned array must be freed with g_strfreev().
**/
gchar **
gtk_source_language_get_globs (GtkSourceLanguage *language)
{
const gchar *globs;
g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE (language), NULL);
globs = gtk_source_language_get_metadata (language, "globs");
if (globs == NULL)
return NULL;
return g_strsplit (globs, ";", 0);
}
/**
* _gtk_source_language_get_language_manager:
* @language: a #GtkSourceLanguage.
*
* Returns: #GtkSourceLanguageManager for @language.
**/
GtkSourceLanguageManager *
_gtk_source_language_get_language_manager (GtkSourceLanguage *language)
{
g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE (language), NULL);
g_return_val_if_fail (language->priv->id != NULL, NULL);
return language->priv->language_manager;
}
/* Highlighting engine creation ------------------------------------------ */
static void
copy_style_info (const char *style_id,
GtkSourceStyleInfo *info,
GHashTable *dest)
{
g_hash_table_insert (dest, g_strdup (style_id),
_gtk_source_style_info_copy (info));
}
void
_gtk_source_language_define_language_styles (GtkSourceLanguage *lang)
{
static const gchar *alias[][2] = {
{"Base-N Integer", "def:base-n-integer"},
{"Character", "def:character"},
{"Comment", "def:comment"},
{"Function", "def:function"},
{"Decimal", "def:decimal"},
{"Floating Point", "def:floating-point"},
{"Keyword", "def:keyword"},
{"Preprocessor", "def:preprocessor"},
{"String", "def:string"},
{"Specials", "def:specials"},
{"Data Type", "def:type"},
{NULL, NULL}};
gint i = 0;
GtkSourceLanguageManager *lm;
GtkSourceLanguage *def_lang;
while (alias[i][0] != NULL)
{
GtkSourceStyleInfo *info;
info = _gtk_source_style_info_new (alias[i][0], alias[i][1]);
g_hash_table_insert (lang->priv->styles,
g_strdup (alias[i][0]),
info);
++i;
}
/* We translate String to def:string, but def:string is mapped-to
* def:constant in def.lang, so we got to take style mappings from def.lang */
lm = _gtk_source_language_get_language_manager (lang);
def_lang = gtk_source_language_manager_get_language (lm, "def");
if (def_lang != NULL)
{
force_styles (def_lang);
g_hash_table_foreach (def_lang->priv->styles,
(GHFunc) copy_style_info,
lang->priv->styles);
}
}
/* returns new reference, which _must_ be unref'ed */
static GtkSourceContextData *
gtk_source_language_parse_file (GtkSourceLanguage *language)
{
if (language->priv->ctx_data == NULL)
{
gboolean success = FALSE;
GtkSourceContextData *ctx_data;
if (language->priv->language_manager == NULL)
{
g_critical ("_gtk_source_language_create_engine() is called after "
"language manager was finalized");
}
else
{
ctx_data = _gtk_source_context_data_new (language);
switch (language->priv->version)
{
case GTK_SOURCE_LANGUAGE_VERSION_1_0:
success = _gtk_source_language_file_parse_version1 (language, ctx_data);
break;
case GTK_SOURCE_LANGUAGE_VERSION_2_0:
success = _gtk_source_language_file_parse_version2 (language, ctx_data);
break;
}
if (!success)
_gtk_source_context_data_unref (ctx_data);
else
language->priv->ctx_data = ctx_data;
}
}
else
{
_gtk_source_context_data_ref (language->priv->ctx_data);
}
return language->priv->ctx_data;
}
GtkSourceEngine *
_gtk_source_language_create_engine (GtkSourceLanguage *language)
{
GtkSourceContextEngine *ce = NULL;
GtkSourceContextData *ctx_data;
ctx_data = gtk_source_language_parse_file (language);
if (ctx_data != NULL)
{
ce = _gtk_source_context_engine_new (ctx_data);
_gtk_source_context_data_unref (ctx_data);
}
return ce ? GTK_SOURCE_ENGINE (ce) : NULL;
}
typedef struct _AddStyleIdData AddStyleIdData;
struct _AddStyleIdData
{
gchar *language_id;
GPtrArray *ids_array;
};
static void
add_style_id (gchar *id, G_GNUC_UNUSED gpointer value, AddStyleIdData *data)
{
if (g_str_has_prefix (id, data->language_id))
g_ptr_array_add (data->ids_array, g_strdup (id));
}
static gchar **
get_style_ids (GtkSourceLanguage *language)
{
GPtrArray *ids_array;
AddStyleIdData data;
g_return_val_if_fail (language->priv->styles != NULL, NULL);
ids_array = g_ptr_array_new ();
data.language_id = g_strdup_printf ("%s:", language->priv->id);
data.ids_array = ids_array;
g_hash_table_foreach (language->priv->styles,
(GHFunc) add_style_id,
&data);
g_free (data.language_id);
if (ids_array->len == 0)
{
/* No style defined in this language */
g_ptr_array_free (ids_array, TRUE);
return NULL;
}
else
{
/* Terminate the array with NULL */
g_ptr_array_add (ids_array, NULL);
return (gchar **)g_ptr_array_free (ids_array, FALSE);
}
}
static gboolean
force_styles (GtkSourceLanguage *language)
{
/* To be sure to have the list of styles we need to parse lang file
* as if we were to create an engine. In the future we can improve
* this by parsing styles only.
*/
if (!language->priv->styles_loaded && language->priv->ctx_data == NULL)
{
GtkSourceContextData *ctx_data;
ctx_data = gtk_source_language_parse_file (language);
if (ctx_data == NULL)
return FALSE;
language->priv->styles_loaded = TRUE;
_gtk_source_context_data_unref (ctx_data);
}
return TRUE;
}
/**
* gtk_source_language_get_style_ids:
* @language: a #GtkSourceLanguage
*
* Returns the ids of the styles defined by this @language.
*
* Returns: a %NULL terminated array containing
* ids of the styles defined by this @language or %NULL if no style is
* defined. The returned array must be freed with g_strfreev().
*/
gchar **
gtk_source_language_get_style_ids (GtkSourceLanguage *language)
{
g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE (language), NULL);
g_return_val_if_fail (language->priv->id != NULL, NULL);
if (!force_styles (language))
return NULL;
return get_style_ids (language);
}
static GtkSourceStyleInfo *
get_style_info (GtkSourceLanguage *language, const char *style_id)
{
GtkSourceStyleInfo *info;
if (!force_styles (language))
return NULL;
g_return_val_if_fail (language->priv->styles != NULL, NULL);
info = g_hash_table_lookup (language->priv->styles, style_id);
return info;
}
/**
* gtk_source_language_get_style_name:
* @language: a #GtkSourceLanguage
* @style_id: a style ID
*
* Returns the name of the style with ID @style_id defined by this @language.
*
* Returns: the name of the style with ID @style_id defined by this @language or
* %NULL if the style has no name or there is no style with ID @style_id defined
* by this @language. The returned string is owned by the @language and must
* not be modified.
*/
const char *
gtk_source_language_get_style_name (GtkSourceLanguage *language,
const char *style_id)
{
GtkSourceStyleInfo *info;
g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE (language), NULL);
g_return_val_if_fail (language->priv->id != NULL, NULL);
g_return_val_if_fail (style_id != NULL, NULL);
info = get_style_info (language, style_id);
if (info == NULL)
return NULL;
return info->name;
}
/* Utility functions for GtkSourceStyleInfo */
GtkSourceStyleInfo *
_gtk_source_style_info_new (const gchar *name, const gchar *map_to)
{
GtkSourceStyleInfo *info = g_new0 (GtkSourceStyleInfo, 1);
info->name = g_strdup (name);
info->map_to = g_strdup (map_to);
return info;
}
GtkSourceStyleInfo *
_gtk_source_style_info_copy (GtkSourceStyleInfo *info)
{
g_return_val_if_fail (info != NULL, NULL);
return _gtk_source_style_info_new (info->name, info->map_to);
}
void
_gtk_source_style_info_free (GtkSourceStyleInfo *info)
{
if (info == NULL)
return;
g_free (info->name);
g_free (info->map_to);
g_free (info);
}

View File

@ -0,0 +1,83 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
* gtksourcelanguage.h
*
* Copyright (C) 2003 - Paolo Maggi <paolo.maggi@polito.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
#ifndef __GTK_SOURCE_LANGUAGE_H__
#define __GTK_SOURCE_LANGUAGE_H__
#include <mooglib/moo-glib.h>
#include <glib-object.h>
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GTK_TYPE_SOURCE_LANGUAGE (gtk_source_language_get_type ())
#define GTK_SOURCE_LANGUAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_SOURCE_LANGUAGE, GtkSourceLanguage))
#define GTK_SOURCE_LANGUAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_SOURCE_LANGUAGE, GtkSourceLanguageClass))
#define GTK_IS_SOURCE_LANGUAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_SOURCE_LANGUAGE))
#define GTK_IS_SOURCE_LANGUAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SOURCE_LANGUAGE))
#define GTK_SOURCE_LANGUAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SOURCE_LANGUAGE, GtkSourceLanguageClass))
typedef struct _GtkSourceLanguage GtkSourceLanguage;
typedef struct _GtkSourceLanguageClass GtkSourceLanguageClass;
typedef struct _GtkSourceLanguagePrivate GtkSourceLanguagePrivate;
struct _GtkSourceLanguage
{
GObject parent_instance;
GtkSourceLanguagePrivate *priv;
};
struct _GtkSourceLanguageClass
{
GObjectClass parent_class;
/* Padding for future expansion */
void (*_gtk_source_reserved1) (void);
void (*_gtk_source_reserved2) (void);
};
GType gtk_source_language_get_type (void) G_GNUC_CONST;
const gchar *gtk_source_language_get_id (GtkSourceLanguage *language);
const gchar *gtk_source_language_get_name (GtkSourceLanguage *language);
const gchar *gtk_source_language_get_section (GtkSourceLanguage *language);
gboolean gtk_source_language_get_hidden (GtkSourceLanguage *language);
const gchar *gtk_source_language_get_metadata (GtkSourceLanguage *language,
const gchar *name);
gchar **gtk_source_language_get_mime_types (GtkSourceLanguage *language);
gchar **gtk_source_language_get_globs (GtkSourceLanguage *language);
gchar **gtk_source_language_get_style_ids (GtkSourceLanguage *language);
const char *gtk_source_language_get_style_name (GtkSourceLanguage *language,
const char *style_id);
G_END_DECLS
#endif /* __GTK_SOURCE_LANGUAGE_H__ */

View File

@ -0,0 +1,409 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
* gtksourcelanguagemanager.c
*
* Copyright (C) 2003-2007 - Paolo Maggi <paolo.maggi@polito.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include "gtksourceview-i18n.h"
#include "gtksourcelanguage-private.h"
#include "gtksourcelanguage.h"
#include "gtksourceview-utils.h"
#define RNG_SCHEMA_FILE "language2.rng"
#define LANGUAGE_DIR "language-specs"
#define LANG_FILE_SUFFIX ".lang"
enum {
PROP_0,
PROP_SEARCH_PATH,
PROP_LANGUAGE_IDS
};
struct _GtkSourceLanguageManagerPrivate
{
GHashTable *language_ids;
gchar **lang_dirs;
gchar *rng_file;
gchar **ids; /* Cache the IDs of the available languages */
};
G_DEFINE_TYPE (GtkSourceLanguageManager, gtk_source_language_manager, G_TYPE_OBJECT)
static void
gtk_source_language_manager_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkSourceLanguageManager *lm;
lm = GTK_SOURCE_LANGUAGE_MANAGER (object);
switch (prop_id)
{
case PROP_SEARCH_PATH:
gtk_source_language_manager_set_search_path (lm, g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_source_language_manager_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkSourceLanguageManager *lm;
lm = GTK_SOURCE_LANGUAGE_MANAGER (object);
switch (prop_id)
{
case PROP_SEARCH_PATH:
g_value_set_boxed (value, gtk_source_language_manager_get_search_path (lm));
break;
case PROP_LANGUAGE_IDS:
g_value_set_boxed (value, gtk_source_language_manager_get_language_ids (lm));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_source_language_manager_finalize (GObject *object)
{
GtkSourceLanguageManager *lm;
lm = GTK_SOURCE_LANGUAGE_MANAGER (object);
if (lm->priv->language_ids)
g_hash_table_destroy (lm->priv->language_ids);
g_strfreev (lm->priv->ids);
g_strfreev (lm->priv->lang_dirs);
g_free (lm->priv->rng_file);
G_OBJECT_CLASS (gtk_source_language_manager_parent_class)->finalize (object);
}
static void
gtk_source_language_manager_class_init (GtkSourceLanguageManagerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_source_language_manager_finalize;
object_class->set_property = gtk_source_language_manager_set_property;
object_class->get_property = gtk_source_language_manager_get_property;
g_object_class_install_property (object_class,
PROP_SEARCH_PATH,
g_param_spec_boxed ("search-path",
_("Language specification directories"),
_("List of directories where the "
"language specification files (.lang) "
"are located"),
G_TYPE_STRV,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_LANGUAGE_IDS,
g_param_spec_boxed ("language-ids",
_("Language ids"),
_("List of the ids of the available "
"languages"),
G_TYPE_STRV,
G_PARAM_READABLE));
g_type_class_add_private (object_class, sizeof(GtkSourceLanguageManagerPrivate));
}
static void
gtk_source_language_manager_init (GtkSourceLanguageManager *lm)
{
lm->priv = G_TYPE_INSTANCE_GET_PRIVATE (lm, GTK_TYPE_SOURCE_LANGUAGE_MANAGER,
GtkSourceLanguageManagerPrivate);
lm->priv->language_ids = NULL;
lm->priv->ids = NULL;
lm->priv->lang_dirs = NULL;
lm->priv->rng_file = NULL;
}
/**
* gtk_source_language_manager_new:
*
* Creates a new language manager. If you do not need more than one language
* manager or a private language manager instance then use
* gtk_source_language_manager_get_default() instead.
*
* Returns: a #GtkSourceLanguageManager.
*/
GtkSourceLanguageManager *
gtk_source_language_manager_new (void)
{
return g_object_new (GTK_TYPE_SOURCE_LANGUAGE_MANAGER, NULL);
}
/**
* gtk_source_language_manager_get_default:
*
* Returns the default #GtkSourceLanguageManager instance.
*
* Returns: a #GtkSourceLanguageManager. Return value is owned
* by GtkSourceView library and must not be unref'ed.
*/
GtkSourceLanguageManager *
gtk_source_language_manager_get_default (void)
{
static GtkSourceLanguageManager *instance;
if (instance == NULL)
{
instance = gtk_source_language_manager_new ();
g_object_add_weak_pointer (G_OBJECT (instance),
(gpointer) &instance);
}
return instance;
}
static void
notify_search_path (GtkSourceLanguageManager *mgr)
{
g_object_notify (G_OBJECT (mgr), "search-path");
g_object_notify (G_OBJECT (mgr), "language-ids");
}
/**
* gtk_source_language_manager_set_search_path:
* @lm: a #GtkSourceLanguageManager.
* @dirs: a %NULL-terminated array of strings or %NULL.
*
* Sets the list of directories where the @lm looks for
* language files.
* If @dirs is %NULL, the search path is reset to default.
*
* <note>
* <para>
* At the moment this function can be called only before the
* language files are loaded for the first time. In practice
* to set a custom search path for a #GtkSourceLanguageManager,
* you have to call this function right after creating it.
* </para>
* </note>
*/
void
gtk_source_language_manager_set_search_path (GtkSourceLanguageManager *lm,
gchar **dirs)
{
gchar **tmp;
g_return_if_fail (GTK_IS_SOURCE_LANGUAGE_MANAGER (lm));
/* Search path cannot be changed in the list of available languages
* as been already computed */
g_return_if_fail (lm->priv->ids == NULL);
tmp = lm->priv->lang_dirs;
if (dirs == NULL)
lm->priv->lang_dirs = _gtk_source_view_get_default_dirs (LANGUAGE_DIR);
else
lm->priv->lang_dirs = g_strdupv (dirs);
g_strfreev (tmp);
notify_search_path (lm);
}
/**
* gtk_source_language_manager_get_search_path:
* @lm: a #GtkSourceLanguageManager.
*
* Gets the list directories where @lm looks for language files.
*
* Returns: %NULL-terminated array containg a list of language files directories.
* The array is owned by @lm and must not be modified.
*/
const gchar* const *
gtk_source_language_manager_get_search_path (GtkSourceLanguageManager *lm)
{
g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE_MANAGER (lm), NULL);
if (lm->priv->lang_dirs == NULL)
lm->priv->lang_dirs = _gtk_source_view_get_default_dirs (LANGUAGE_DIR);
return (const gchar * const *)lm->priv->lang_dirs;
}
/**
* _gtk_source_language_manager_get_rng_file:
* @lm: a #GtkSourceLanguageManager.
*
* Returns location of the RNG schema file for lang files version 2.
*
* Returns: path to RNG file. It belongs to %lm and must not be freed or modified.
*/
const char *
_gtk_source_language_manager_get_rng_file (GtkSourceLanguageManager *lm)
{
g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE_MANAGER (lm), NULL);
if (lm->priv->rng_file == NULL)
{
const gchar * const *dirs;
for (dirs = gtk_source_language_manager_get_search_path (lm);
dirs != NULL && *dirs != NULL;
++dirs)
{
gchar *file;
file = g_build_filename (*dirs, RNG_SCHEMA_FILE, NULL);
if (g_file_test (file, G_FILE_TEST_EXISTS))
{
lm->priv->rng_file = file;
break;
}
g_free (file);
}
}
return lm->priv->rng_file;
}
static void
ensure_languages (GtkSourceLanguageManager *lm)
{
GSList *filenames, *l;
GPtrArray *ids_array = NULL;
if (lm->priv->language_ids != NULL)
return;
lm->priv->language_ids = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
filenames = _gtk_source_view_get_file_list ((gchar **)gtk_source_language_manager_get_search_path (lm),
LANG_FILE_SUFFIX,
FALSE);
for (l = filenames; l != NULL; l = l->next)
{
GtkSourceLanguage *lang;
gchar *filename;
filename = l->data;
lang = _gtk_source_language_new_from_file (filename, lm);
if (lang == NULL)
{
g_warning ("Error reading language specification file '%s'", filename);
continue;
}
if (g_hash_table_lookup (lm->priv->language_ids, lang->priv->id) == NULL)
{
g_hash_table_insert (lm->priv->language_ids,
g_strdup (lang->priv->id),
lang);
if (ids_array == NULL)
ids_array = g_ptr_array_new ();
g_ptr_array_add (ids_array, g_strdup (lang->priv->id));
}
else
{
g_object_unref (lang);
}
}
if (ids_array != NULL)
{
/* Ensure the array is NULL terminated */
g_ptr_array_add (ids_array, NULL);
lm->priv->ids = (gchar **)g_ptr_array_free (ids_array, FALSE);
}
g_slist_foreach (filenames, (GFunc) g_free, NULL);
g_slist_free (filenames);
}
/**
* gtk_source_language_manager_get_language_ids:
* @lm: a #GtkSourceLanguageManager
*
* Returns the ids of the available languages.
*
* Returns: a %NULL-terminated array of string containing the ids of the
* available languages or %NULL if no language is available. The array
* is owned by @lm and must not be modified.
*/
const gchar* const *
gtk_source_language_manager_get_language_ids (GtkSourceLanguageManager *lm)
{
g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE_MANAGER (lm), NULL);
ensure_languages (lm);
return (const gchar * const *)lm->priv->ids;
}
/**
* gtk_source_language_manager_get_language:
* @lm: a #GtkSourceLanguageManager.
* @id: a language id.
*
* Gets the #GtkSourceLanguage identified by the given @id in the language
* manager.
*
* Returns: a #GtkSourceLanguage, or %NULL if there is no language
* identified by the given @id. Return value is owned by @lm and should not
* be freed.
*/
GtkSourceLanguage *
gtk_source_language_manager_get_language (GtkSourceLanguageManager *lm,
const gchar *id)
{
g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE_MANAGER (lm), NULL);
g_return_val_if_fail (id != NULL, NULL);
ensure_languages (lm);
return g_hash_table_lookup (lm->priv->language_ids, id);
}

View File

@ -0,0 +1,81 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
* gtksourcelanguagemanager.h
*
* Copyright (C) 2003 - Paolo Maggi <paolo.maggi@polito.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
#ifndef __GTK_SOURCE_LANGUAGE_MANAGER_H__
#define __GTK_SOURCE_LANGUAGE_MANAGER_H__
#include <gtksourceview/gtksourcelanguage.h>
G_BEGIN_DECLS
#define GTK_TYPE_SOURCE_LANGUAGE_MANAGER (gtk_source_language_manager_get_type ())
#define GTK_SOURCE_LANGUAGE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_SOURCE_LANGUAGE_MANAGER, GtkSourceLanguageManager))
#define GTK_SOURCE_LANGUAGE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_SOURCE_LANGUAGE_MANAGER, GtkSourceLanguageManagerClass))
#define GTK_IS_SOURCE_LANGUAGE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_SOURCE_LANGUAGE_MANAGER))
#define GTK_IS_SOURCE_LANGUAGE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SOURCE_LANGUAGE_MANAGER))
#define GTK_SOURCE_LANGUAGE_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_SOURCE_LANGUAGE_MANAGER, GtkSourceLanguageManagerClass))
typedef struct _GtkSourceLanguageManager GtkSourceLanguageManager;
typedef struct _GtkSourceLanguageManagerClass GtkSourceLanguageManagerClass;
typedef struct _GtkSourceLanguageManagerPrivate GtkSourceLanguageManagerPrivate;
struct _GtkSourceLanguageManager
{
GObject parent_instance;
GtkSourceLanguageManagerPrivate *priv;
};
struct _GtkSourceLanguageManagerClass
{
GObjectClass parent_class;
/* Padding for future expansion */
void (*_gtk_source_reserved1) (void);
void (*_gtk_source_reserved2) (void);
void (*_gtk_source_reserved3) (void);
void (*_gtk_source_reserved4) (void);
};
GType gtk_source_language_manager_get_type (void) G_GNUC_CONST;
GtkSourceLanguageManager *gtk_source_language_manager_new (void);
GtkSourceLanguageManager *gtk_source_language_manager_get_default (void);
const gchar* const *
gtk_source_language_manager_get_search_path (GtkSourceLanguageManager *lm);
void gtk_source_language_manager_set_search_path (GtkSourceLanguageManager *lm,
gchar **dirs);
const gchar* const *
gtk_source_language_manager_get_language_ids (GtkSourceLanguageManager *lm);
GtkSourceLanguage *gtk_source_language_manager_get_language (GtkSourceLanguageManager *lm,
const gchar *id);
G_END_DECLS
#endif /* __GTK_SOURCE_LANGUAGE_MANAGER_H__ */

View File

@ -0,0 +1,65 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
* gtksourcestyle-private.h
*
* Copyright (C) 2003 - Paolo Maggi <paolo.maggi@polito.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
#ifndef __GTK_SOURCE_STYLE_PRIVATE_H__
#define __GTK_SOURCE_STYLE_PRIVATE_H__
#include "gtksourcestyle.h"
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GTK_SOURCE_STYLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SOURCE_STYLE, GtkSourceStyleClass))
#define GTK_IS_SOURCE_STYLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SOURCE_STYLE))
#define GTK_SOURCE_STYLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SOURCE_STYLE, GtkSourceStyleClass))
enum {
GTK_SOURCE_STYLE_USE_LINE_BACKGROUND = 1 << 0, /*< nick=use_line_background >*/
GTK_SOURCE_STYLE_USE_BACKGROUND = 1 << 1, /*< nick=use_background >*/
GTK_SOURCE_STYLE_USE_FOREGROUND = 1 << 2, /*< nick=use_foreground >*/
GTK_SOURCE_STYLE_USE_ITALIC = 1 << 3, /*< nick=use_italic >*/
GTK_SOURCE_STYLE_USE_BOLD = 1 << 4, /*< nick=use_bold >*/
GTK_SOURCE_STYLE_USE_UNDERLINE = 1 << 5, /*< nick=use_underline >*/
GTK_SOURCE_STYLE_USE_STRIKETHROUGH = 1 << 6 /*< nick=use_strikethrough >*/
};
struct _GtkSourceStyle
{
GObject base_instance;
/* foreground and background are strings interned with
* with g_intern_string(), so we don't need to copy/free
* them. */
const gchar *foreground;
const gchar *background;
const gchar *line_background;
guint italic : 1;
guint bold : 1;
guint underline : 1;
guint strikethrough : 1;
guint mask : 12;
};
void _gtk_source_style_apply (const GtkSourceStyle *style,
GtkTextTag *tag);
G_END_DECLS
#endif /* __GTK_SOURCE_STYLE_PRIVATE_H__ */

View File

@ -0,0 +1,447 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
* gtksourcestyle.c
*
* Copyright (C) 2003 - Paolo Maggi <paolo.maggi@polito.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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 "gtksourcestyle-private.h"
#include "gtksourceview-i18n.h"
static void gtk_source_style_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void gtk_source_style_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
typedef GObjectClass GtkSourceStyleClass;
G_DEFINE_TYPE (GtkSourceStyle, gtk_source_style, G_TYPE_OBJECT)
enum {
PROP_0,
PROP_LINE_BACKGROUND,
PROP_LINE_BACKGROUND_SET,
PROP_BACKGROUND,
PROP_BACKGROUND_SET,
PROP_FOREGROUND,
PROP_FOREGROUND_SET,
PROP_BOLD,
PROP_BOLD_SET,
PROP_ITALIC,
PROP_ITALIC_SET,
PROP_UNDERLINE,
PROP_UNDERLINE_SET,
PROP_STRIKETHROUGH,
PROP_STRIKETHROUGH_SET
};
static void
gtk_source_style_class_init (GtkSourceStyleClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = gtk_source_style_set_property;
object_class->get_property = gtk_source_style_get_property;
/* All properties are CONSTRUCT_ONLY so we can safely return references
* from style_scheme_get_style(). But style scheme is of course cheating
* and sets everything after construction (but nobody can notice it). */
g_object_class_install_property (object_class,
PROP_LINE_BACKGROUND,
g_param_spec_string ("line-background",
_("Line background"),
_("Line background color"),
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_BACKGROUND,
g_param_spec_string ("background",
_("Background"),
_("Background color"),
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_FOREGROUND,
g_param_spec_string ("foreground",
_("Foreground"),
_("Foreground color"),
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_BOLD,
g_param_spec_boolean ("bold",
_("Bold"),
_("Bold"),
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_ITALIC,
g_param_spec_boolean ("italic",
_("Italic"),
_("Italic"),
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_UNDERLINE,
g_param_spec_boolean ("underline",
_("Underline"),
_("Underline"),
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_STRIKETHROUGH,
g_param_spec_boolean ("strikethrough",
_("Strikethrough"),
_("Strikethrough"),
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_LINE_BACKGROUND_SET,
g_param_spec_boolean ("line-background-set",
_("Line background set"),
_("Whether line background color is set"),
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_FOREGROUND_SET,
g_param_spec_boolean ("foreground-set",
_("Foreground set"),
_("Whether foreground color is set"),
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_BACKGROUND_SET,
g_param_spec_boolean ("background-set",
_("Background set"),
_("Whether background color is set"),
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_BOLD_SET,
g_param_spec_boolean ("bold-set",
_("Bold set"),
_("Whether bold attribute is set"),
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_ITALIC_SET,
g_param_spec_boolean ("italic-set",
_("Italic set"),
_("Whether italic attribute is set"),
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_UNDERLINE_SET,
g_param_spec_boolean ("underline-set",
_("Underline set"),
_("Whether underline attribute is set"),
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_STRIKETHROUGH_SET,
g_param_spec_boolean ("strikethrough-set",
_("Strikethrough set"),
_("Whether strikethrough attribute is set"),
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}
static void
gtk_source_style_init (GtkSourceStyle *style)
{
style->foreground = NULL;
style->background = NULL;
style->line_background = NULL;
}
#define SET_MASK(style,name) (style)->mask |= (GTK_SOURCE_STYLE_USE_##name)
#define UNSET_MASK(style,name) (style)->mask &= (GTK_SOURCE_STYLE_USE_##name)
#define MODIFY_MASK(style,value,name) \
G_STMT_START { \
if (g_value_get_boolean (value)) \
SET_MASK (style, name); \
else \
UNSET_MASK (style, name); \
} G_STMT_END
#define GET_MASK(style,value,name) \
g_value_set_boolean (value, ((style)->mask & GTK_SOURCE_STYLE_USE_##name) != 0)
static void
gtk_source_style_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkSourceStyle *style = GTK_SOURCE_STYLE (object);
const gchar *string;
switch (prop_id)
{
case PROP_FOREGROUND:
string = g_value_get_string (value);
if (string != NULL)
{
style->foreground = g_intern_string (string);
SET_MASK (style, FOREGROUND);
}
else
{
style->foreground = NULL;
UNSET_MASK (style, FOREGROUND);
}
break;
case PROP_BACKGROUND:
string = g_value_get_string (value);
if (string != NULL)
{
style->background = g_intern_string (string);
SET_MASK (style, BACKGROUND);
}
else
{
style->background = NULL;
UNSET_MASK (style, BACKGROUND);
}
break;
case PROP_LINE_BACKGROUND:
string = g_value_get_string (value);
if (string != NULL)
{
style->line_background = g_intern_string (string);
SET_MASK (style, LINE_BACKGROUND);
}
else
{
style->line_background = NULL;
UNSET_MASK (style, LINE_BACKGROUND);
}
break;
case PROP_BOLD:
style->bold = g_value_get_boolean (value) != 0;
SET_MASK (style, BOLD);
break;
case PROP_ITALIC:
style->italic = g_value_get_boolean (value) != 0;
SET_MASK (style, ITALIC);
break;
case PROP_UNDERLINE:
style->underline = g_value_get_boolean (value) != 0;
SET_MASK (style, UNDERLINE);
break;
case PROP_STRIKETHROUGH:
style->strikethrough = g_value_get_boolean (value) != 0;
SET_MASK (style, STRIKETHROUGH);
break;
case PROP_FOREGROUND_SET:
MODIFY_MASK (style, value, FOREGROUND);
break;
case PROP_BACKGROUND_SET:
MODIFY_MASK (style, value, BACKGROUND);
break;
case PROP_LINE_BACKGROUND_SET:
MODIFY_MASK (style, value, LINE_BACKGROUND);
break;
case PROP_BOLD_SET:
MODIFY_MASK (style, value, BOLD);
break;
case PROP_ITALIC_SET:
MODIFY_MASK (style, value, ITALIC);
break;
case PROP_UNDERLINE_SET:
MODIFY_MASK (style, value, UNDERLINE);
break;
case PROP_STRIKETHROUGH_SET:
MODIFY_MASK (style, value, STRIKETHROUGH);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_source_style_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkSourceStyle *style = GTK_SOURCE_STYLE (object);
switch (prop_id)
{
case PROP_FOREGROUND:
g_value_set_string (value, style->foreground);
break;
case PROP_BACKGROUND:
g_value_set_string (value, style->background);
break;
case PROP_LINE_BACKGROUND:
g_value_set_string (value, style->line_background);
break;
case PROP_BOLD:
g_value_set_boolean (value, style->bold);
break;
case PROP_ITALIC:
g_value_set_boolean (value, style->italic);
break;
case PROP_UNDERLINE:
g_value_set_boolean (value, style->underline);
break;
case PROP_STRIKETHROUGH:
g_value_set_boolean (value, style->strikethrough);
break;
case PROP_FOREGROUND_SET:
GET_MASK (style, value, FOREGROUND);
break;
case PROP_BACKGROUND_SET:
GET_MASK (style, value, BACKGROUND);
break;
case PROP_LINE_BACKGROUND_SET:
GET_MASK (style, value, LINE_BACKGROUND);
break;
case PROP_BOLD_SET:
GET_MASK (style, value, BOLD);
break;
case PROP_ITALIC_SET:
GET_MASK (style, value, ITALIC);
break;
case PROP_UNDERLINE_SET:
GET_MASK (style, value, UNDERLINE);
break;
case PROP_STRIKETHROUGH_SET:
GET_MASK (style, value, STRIKETHROUGH);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/**
* gtk_source_style_copy:
* @style: a #GtkSourceStyle structure to copy.
*
* Creates a copy of @style, that is a new #GtkSourceStyle instance which
* has the same attributes set.
*
* Returns: copy of @style, call g_object_unref() when you are done with it.
*
* Since: 2.0
*/
GtkSourceStyle *
gtk_source_style_copy (const GtkSourceStyle *style)
{
GtkSourceStyle *copy;
g_return_val_if_fail (style != NULL, NULL);
copy = g_object_new (GTK_TYPE_SOURCE_STYLE, NULL);
copy->foreground = style->foreground;
copy->background = style->background;
copy->line_background = style->line_background;
copy->italic = style->italic;
copy->bold = style->bold;
copy->underline = style->underline;
copy->strikethrough = style->strikethrough;
copy->mask = style->mask;
return copy;
}
/**
* _gtk_source_style_apply:
* @style: a #GtkSourceStyle to apply.
* @tag: a #GtkTextTag to apply styles to.
*
* Applies text styles set in @style if it's not %NULL, or
* unsets style fields in @tag set with _gtk_source_style_apply()
* if @style is %NULL. Note that it does not touch fields which
* are not set in @style. To reset everything use @style == %NULL.
*
* Since: 2.0
*/
void
_gtk_source_style_apply (const GtkSourceStyle *style,
GtkTextTag *tag)
{
g_return_if_fail (GTK_IS_TEXT_TAG (tag));
if (style != NULL)
{
g_object_freeze_notify (G_OBJECT (tag));
if (style->mask & GTK_SOURCE_STYLE_USE_BACKGROUND)
g_object_set (tag, "background", style->background, NULL);
if (style->mask & GTK_SOURCE_STYLE_USE_FOREGROUND)
g_object_set (tag, "foreground", style->foreground, NULL);
if (style->mask & GTK_SOURCE_STYLE_USE_LINE_BACKGROUND)
g_object_set (tag, "paragraph-background", style->line_background, NULL);
if (style->mask & GTK_SOURCE_STYLE_USE_ITALIC)
g_object_set (tag, "style", style->italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL, NULL);
if (style->mask & GTK_SOURCE_STYLE_USE_BOLD)
g_object_set (tag, "weight", style->bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, NULL);
if (style->mask & GTK_SOURCE_STYLE_USE_UNDERLINE)
g_object_set (tag, "underline", style->underline ? PANGO_UNDERLINE_SINGLE : PANGO_UNDERLINE_NONE, NULL);
if (style->mask & GTK_SOURCE_STYLE_USE_STRIKETHROUGH)
g_object_set (tag, "strikethrough", style->strikethrough != 0, NULL);
g_object_thaw_notify (G_OBJECT (tag));
}
else
{
g_object_set (tag,
"background-set", FALSE,
"foreground-set", FALSE,
"paragraph-background-set", FALSE,
"style-set", FALSE,
"weight-set", FALSE,
"underline-set", FALSE,
"strikethrough-set", FALSE,
NULL);
}
}

View File

@ -0,0 +1,41 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
* gtksourcestyle.h
*
* Copyright (C) 2003 - Paolo Maggi <paolo.maggi@polito.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
#ifndef __GTK_SOURCE_STYLE_H__
#define __GTK_SOURCE_STYLE_H__
#include <glib-object.h>
G_BEGIN_DECLS
#define GTK_TYPE_SOURCE_STYLE (gtk_source_style_get_type ())
#define GTK_SOURCE_STYLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SOURCE_STYLE, GtkSourceStyle))
#define GTK_IS_SOURCE_STYLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SOURCE_STYLE))
typedef struct _GtkSourceStyle GtkSourceStyle;
GType gtk_source_style_get_type (void) G_GNUC_CONST;
GtkSourceStyle *gtk_source_style_copy (const GtkSourceStyle *style);
G_END_DECLS
#endif /* __GTK_SOURCE_STYLE_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,88 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
* gtksourcestylescheme.h
*
* Copyright (C) 2003 - Paolo Maggi <paolo.maggi@polito.it>
*
* 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, or (at your option) any later version.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __GTK_SOURCE_STYLE_SCHEME_H__
#define __GTK_SOURCE_STYLE_SCHEME_H__
#include <gtk/gtk.h>
#include <gtksourceview/gtksourcestyle.h>
G_BEGIN_DECLS
#define GTK_TYPE_SOURCE_STYLE_SCHEME (gtk_source_style_scheme_get_type ())
#define GTK_SOURCE_STYLE_SCHEME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SOURCE_STYLE_SCHEME, GtkSourceStyleScheme))
#define GTK_SOURCE_STYLE_SCHEME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SOURCE_STYLE_SCHEME, GtkSourceStyleSchemeClass))
#define GTK_IS_SOURCE_STYLE_SCHEME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SOURCE_STYLE_SCHEME))
#define GTK_IS_SOURCE_STYLE_SCHEME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SOURCE_STYLE_SCHEME))
#define GTK_SOURCE_STYLE_SCHEME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SOURCE_STYLE_SCHEME, GtkSourceStyleSchemeClass))
typedef struct _GtkSourceStyleScheme GtkSourceStyleScheme;
typedef struct _GtkSourceStyleSchemePrivate GtkSourceStyleSchemePrivate;
typedef struct _GtkSourceStyleSchemeClass GtkSourceStyleSchemeClass;
struct _GtkSourceStyleScheme
{
GObject base;
GtkSourceStyleSchemePrivate *priv;
};
struct _GtkSourceStyleSchemeClass
{
GObjectClass base_class;
/* Padding for future expansion */
void (*_gtk_source_reserved1) (void);
void (*_gtk_source_reserved2) (void);
};
GType gtk_source_style_scheme_get_type (void) G_GNUC_CONST;
GtkSourceStyleScheme *_gtk_source_style_scheme_new (const gchar *id,
const gchar *name);
const gchar *gtk_source_style_scheme_get_id (GtkSourceStyleScheme *scheme);
const gchar *gtk_source_style_scheme_get_name (GtkSourceStyleScheme *scheme);
const gchar *gtk_source_style_scheme_get_description(GtkSourceStyleScheme *scheme);
const gchar* const * gtk_source_style_scheme_get_authors (GtkSourceStyleScheme *scheme);
const gchar *gtk_source_style_scheme_get_filename (GtkSourceStyleScheme *scheme);
GtkSourceStyle *gtk_source_style_scheme_get_style (GtkSourceStyleScheme *scheme,
const gchar *style_id);
GtkSourceStyleScheme *_gtk_source_style_scheme_new_from_file (const gchar *filename);
GtkSourceStyleScheme *_gtk_source_style_scheme_get_default (void);
const gchar *_gtk_source_style_scheme_get_parent_id (GtkSourceStyleScheme *scheme);
void _gtk_source_style_scheme_set_parent (GtkSourceStyleScheme *scheme,
GtkSourceStyleScheme *parent_scheme);
/* private */
void _gtk_source_style_scheme_apply (GtkSourceStyleScheme *scheme,
GtkWidget *widget);
GtkSourceStyle *_gtk_source_style_scheme_get_matching_brackets_style
(GtkSourceStyleScheme *scheme);
GtkSourceStyle *_gtk_source_style_scheme_get_right_margin_style
(GtkSourceStyleScheme *scheme);
gboolean _gtk_source_style_scheme_get_current_line_color
(GtkSourceStyleScheme *scheme,
GdkColor *color);
G_END_DECLS
#endif /* __GTK_SOURCE_STYLE_SCHEME_H__ */

View File

@ -0,0 +1,577 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
* gtksourcestyleschememanager.c
*
* Copyright (C) 2003-2007 - Paolo Maggi <paolo@gnome.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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 "gtksourcestyleschememanager.h"
#include "gtksourceview-marshal.h"
#include "gtksourceview-i18n.h"
#include "gtksourceview-utils.h"
#include <string.h>
#define SCHEME_FILE_SUFFIX ".xml"
#define STYLES_DIR "styles"
struct _GtkSourceStyleSchemeManagerPrivate
{
GHashTable *schemes_hash;
gchar **search_path;
gboolean need_reload;
gchar **ids; /* Cache the IDs of the available schemes */
};
enum {
PROP_0,
PROP_SEARCH_PATH,
PROP_SCHEME_IDS
};
G_DEFINE_TYPE (GtkSourceStyleSchemeManager, gtk_source_style_scheme_manager, G_TYPE_OBJECT)
static void
gtk_source_style_scheme_manager_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkSourceStyleSchemeManager *sm;
sm = GTK_SOURCE_STYLE_SCHEME_MANAGER (object);
switch (prop_id)
{
case PROP_SEARCH_PATH:
gtk_source_style_scheme_manager_set_search_path
(sm, g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
prop_id,
pspec);
break;
}
}
static void
gtk_source_style_scheme_manager_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkSourceStyleSchemeManager *sm;
sm = GTK_SOURCE_STYLE_SCHEME_MANAGER (object);
switch (prop_id)
{
case PROP_SEARCH_PATH:
g_value_set_boxed (value,
gtk_source_style_scheme_manager_get_search_path (sm));
break;
case PROP_SCHEME_IDS:
g_value_set_boxed (value,
gtk_source_style_scheme_manager_get_scheme_ids (sm));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
prop_id,
pspec);
break;
}
}
static void
free_schemes (GtkSourceStyleSchemeManager *mgr)
{
if (mgr->priv->schemes_hash != NULL)
{
g_hash_table_destroy (mgr->priv->schemes_hash);
mgr->priv->schemes_hash = NULL;
}
g_strfreev (mgr->priv->ids);
mgr->priv->ids = NULL;
}
static void
gtk_source_style_scheme_manager_finalize (GObject *object)
{
GtkSourceStyleSchemeManager *mgr;
mgr = GTK_SOURCE_STYLE_SCHEME_MANAGER (object);
free_schemes (mgr);
g_strfreev (mgr->priv->search_path);
G_OBJECT_CLASS (gtk_source_style_scheme_manager_parent_class)->finalize (object);
}
static void
gtk_source_style_scheme_manager_class_init (GtkSourceStyleSchemeManagerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_source_style_scheme_manager_finalize;
object_class->set_property = gtk_source_style_scheme_manager_set_property;
object_class->get_property = gtk_source_style_scheme_manager_get_property;
g_object_class_install_property (object_class,
PROP_SEARCH_PATH,
g_param_spec_boxed ("search-path",
_("Style scheme search path"),
_("List of directories and files where the "
"style schemes are located"),
G_TYPE_STRV,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_SCHEME_IDS,
g_param_spec_boxed ("scheme-ids",
_("Scheme ids"),
_("List of the ids of the available "
"style schemes"),
G_TYPE_STRV,
G_PARAM_READABLE));
g_type_class_add_private (object_class, sizeof(GtkSourceStyleSchemeManagerPrivate));
}
static void
gtk_source_style_scheme_manager_init (GtkSourceStyleSchemeManager *mgr)
{
mgr->priv = G_TYPE_INSTANCE_GET_PRIVATE (mgr,
GTK_TYPE_SOURCE_STYLE_SCHEME_MANAGER,
GtkSourceStyleSchemeManagerPrivate);
mgr->priv->schemes_hash = NULL;
mgr->priv->ids = NULL;
mgr->priv->search_path = NULL;
mgr->priv->need_reload = TRUE;
}
/**
* gtk_source_style_scheme_manager_new:
*
* Creates a new style manager. If you do not need more than one style
* manager then use gtk_source_style_scheme_manager_get_default() instead.
*
* Returns: a #GtkSourceStyleSchemeManager.
*/
GtkSourceStyleSchemeManager *
gtk_source_style_scheme_manager_new (void)
{
return g_object_new (GTK_TYPE_SOURCE_STYLE_SCHEME_MANAGER, NULL);
}
/**
* gtk_source_style_scheme_manager_get_default:
*
* Returns the default #GtkSourceStyleSchemeManager instance.
*
* Returns: a #GtkSourceStyleSchemeManager. Return value is owned
* by GtkSourceView library and must not be unref'ed.
*/
GtkSourceStyleSchemeManager *
gtk_source_style_scheme_manager_get_default (void)
{
static GtkSourceStyleSchemeManager *instance;
if (instance == NULL)
{
instance = gtk_source_style_scheme_manager_new ();
g_object_add_weak_pointer (G_OBJECT (instance),
(gpointer) &instance);
}
return instance;
}
static GSList *
ids_list_remove (GSList *ids, const gchar *id, gboolean free_data)
{
GSList *o = g_slist_find_custom (ids, id, (GCompareFunc) strcmp);
if (o != NULL)
{
if (free_data)
g_free (o->data);
ids = g_slist_delete_link (ids, o);
}
return ids;
}
static gboolean
build_reference_chain (GtkSourceStyleScheme *scheme,
GHashTable *hash,
GSList **ret)
{
GSList *chain;
gboolean retval = TRUE;
chain = g_slist_prepend (NULL, scheme);
while (TRUE)
{
GtkSourceStyleScheme *parent_scheme;
const gchar *parent_id;
parent_id = _gtk_source_style_scheme_get_parent_id (scheme);
if (parent_id == NULL)
break;
parent_scheme = g_hash_table_lookup (hash, parent_id);
if (parent_scheme == NULL)
{
g_warning ("Unknown parent scheme '%s' in scheme '%s'",
parent_id, gtk_source_style_scheme_get_id (scheme));
retval = FALSE;
break;
}
else if (g_slist_find (chain, parent_scheme) != NULL)
{
g_warning ("Reference cycle in scheme '%s'", parent_id);
retval = FALSE;
break;
}
else
{
_gtk_source_style_scheme_set_parent (scheme, parent_scheme);
}
chain = g_slist_prepend (chain, parent_scheme);
scheme = parent_scheme;
}
*ret = chain;
return retval;
}
static GSList *
check_parents (GSList *ids,
GHashTable *hash)
{
GSList *to_check;
to_check = g_slist_copy (ids);
while (to_check != NULL)
{
GSList *chain;
gboolean valid;
GtkSourceStyleScheme *scheme_to_check;
scheme_to_check = g_hash_table_lookup (hash, to_check->data);
g_return_val_if_fail (scheme_to_check != NULL, NULL);
valid = build_reference_chain (scheme_to_check, hash, &chain);
while (chain != NULL)
{
const gchar *id;
GtkSourceStyleScheme *scheme = chain->data;
id = gtk_source_style_scheme_get_id (scheme);
to_check = ids_list_remove (to_check, id, FALSE);
if (!valid)
{
ids = ids_list_remove (ids, id, TRUE);
g_hash_table_remove (hash, id);
}
chain = g_slist_delete_link (chain, chain);
}
}
return ids;
}
static gchar **
slist_to_strv (GSList *list)
{
gchar **res;
guint i = 0;
res = g_new (gchar *, g_slist_length (list) + 1);
for ( ; list != NULL; list = list->next)
{
res[i] = list->data;
++i;
}
res[i] = NULL;
return res;
}
static void
reload_if_needed (GtkSourceStyleSchemeManager *mgr)
{
GSList *ids = NULL;
GSList *files;
GSList *l;
GHashTable *schemes_hash;
if (!mgr->priv->need_reload)
return;
schemes_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
files = _gtk_source_view_get_file_list ((gchar **)gtk_source_style_scheme_manager_get_search_path (mgr),
SCHEME_FILE_SUFFIX,
FALSE);
for (l = files; l != NULL; l = l->next)
{
GtkSourceStyleScheme *scheme;
gchar *filename;
filename = l->data;
scheme = _gtk_source_style_scheme_new_from_file (filename);
if (scheme != NULL)
{
const gchar *id = gtk_source_style_scheme_get_id (scheme);
GtkSourceStyleScheme *old;
old = g_hash_table_lookup (schemes_hash, id);
if (old != NULL)
ids = ids_list_remove (ids, id, TRUE);
ids = g_slist_prepend (ids, g_strdup (id));
g_hash_table_insert (schemes_hash, g_strdup (id), scheme);
}
}
ids = check_parents (ids, schemes_hash);
g_slist_foreach (files, (GFunc) g_free, NULL);
g_slist_free (files);
free_schemes (mgr);
mgr->priv->need_reload = FALSE;
mgr->priv->schemes_hash = schemes_hash;
mgr->priv->ids = slist_to_strv (ids);
g_slist_free (ids); /* slist_to_strv trasfer the onwnership of the strings
to the string array */
}
static void
notify_search_path (GtkSourceStyleSchemeManager *mgr)
{
mgr->priv->need_reload = TRUE;
g_object_notify (G_OBJECT (mgr), "search-path");
g_object_notify (G_OBJECT (mgr), "scheme-ids");
}
/**
* gtk_source_style_scheme_manager_set_search_path:
* @manager: a #GtkSourceStyleSchemeManager.
* @path: a %NULL-terminated array of strings or %NULL.
*
* Sets the list of directories where the @manager looks for
* style scheme files.
* If @dirs is %NULL, the search path is reset to default.
*/
void
gtk_source_style_scheme_manager_set_search_path (GtkSourceStyleSchemeManager *manager,
gchar **path)
{
gchar **tmp;
g_return_if_fail (GTK_IS_SOURCE_STYLE_SCHEME_MANAGER (manager));
tmp = manager->priv->search_path;
if (path == NULL)
manager->priv->search_path = _gtk_source_view_get_default_dirs (STYLES_DIR);
else
manager->priv->search_path = g_strdupv (path);
g_strfreev (tmp);
notify_search_path (manager);
}
/**
* gtk_source_style_scheme_manager_append_search_path:
* @manager: a #GtkSourceStyleSchemeManager.
* @path: a directory or a filename.
*
* Appends @path to the list of directories where the @manager looks for
* style scheme files.
* See gtk_source_style_scheme_manager_set_search_path() for details.
*/
void
gtk_source_style_scheme_manager_append_search_path (GtkSourceStyleSchemeManager *manager,
const gchar *path)
{
guint len = 0;
g_return_if_fail (GTK_IS_SOURCE_STYLE_SCHEME_MANAGER (manager));
g_return_if_fail (path != NULL);
if (manager->priv->search_path == NULL)
manager->priv->search_path = _gtk_source_view_get_default_dirs (STYLES_DIR);
g_return_if_fail (manager->priv->search_path != NULL);
len = g_strv_length (manager->priv->search_path);
manager->priv->search_path = g_renew (gchar *,
manager->priv->search_path,
len + 2); /* old path + new entry + NULL */
manager->priv->search_path[len] = g_strdup (path);
manager->priv->search_path[len + 1] = NULL;
notify_search_path (manager);
}
/**
* gtk_source_style_scheme_manager_prepend_search_path:
* @manager: a #GtkSourceStyleSchemeManager.
* @path: a directory or a filename.
*
* Prepends @path to the list of directories where the @manager looks
* for style scheme files.
* See gtk_source_style_scheme_manager_set_search_path() for details.
*/
void
gtk_source_style_scheme_manager_prepend_search_path (GtkSourceStyleSchemeManager *manager,
const gchar *path)
{
guint len = 0;
gchar **new_search_path;
g_return_if_fail (GTK_IS_SOURCE_STYLE_SCHEME_MANAGER (manager));
g_return_if_fail (path != NULL);
if (manager->priv->search_path == NULL)
manager->priv->search_path = _gtk_source_view_get_default_dirs (STYLES_DIR);
g_return_if_fail (manager->priv->search_path != NULL);
len = g_strv_length (manager->priv->search_path);
new_search_path = g_new (gchar *, len + 2);
new_search_path[0] = g_strdup (path);
memcpy (new_search_path + 1, manager->priv->search_path, (len + 1) * sizeof (gchar*));
g_free (manager->priv->search_path);
manager->priv->search_path = new_search_path;
notify_search_path (manager);
}
/**
* gtk_source_style_scheme_manager_get_search_path:
* @manager: a #GtkSourceStyleSchemeManager.
*
* Returns the current search path for the @manager.
* See gtk_source_style_scheme_manager_set_search_path() for details.
*
* Returns: a NULL-terminated array of string containing the search path.
* The array is owned by the @manager and must not be modified.
*/
const gchar* const *
gtk_source_style_scheme_manager_get_search_path (GtkSourceStyleSchemeManager *manager)
{
g_return_val_if_fail (GTK_IS_SOURCE_STYLE_SCHEME_MANAGER (manager), NULL);
if (manager->priv->search_path == NULL)
manager->priv->search_path = _gtk_source_view_get_default_dirs (STYLES_DIR);
return (const gchar * const *)manager->priv->search_path;
}
/**
* gtk_source_style_scheme_manager_force_rescan:
* @manager: a #GtkSourceStyleSchemeManager
*
* Mark any currently cached information about the available style scehems
* as invalid. All the available style schemes will be reloaded next time
* the @manager is accessed.
*/
void
gtk_source_style_scheme_manager_force_rescan (GtkSourceStyleSchemeManager *manager)
{
manager->priv->need_reload = TRUE;
g_object_notify (G_OBJECT (manager), "scheme-ids");
}
/**
* gtk_source_style_scheme_manager_get_scheme_ids:
* @manager: a #GtkSourceStyleSchemeManager
*
* Returns the ids of the available style schemes.
*
* Returns: a %NULL-terminated array of string containing the ids of the
* available style schemes or %NULL if no style scheme is available. The array
* is owned by the @manager and must not be modified.
*/
const gchar* const *
gtk_source_style_scheme_manager_get_scheme_ids (GtkSourceStyleSchemeManager *manager)
{
g_return_val_if_fail (GTK_IS_SOURCE_STYLE_SCHEME_MANAGER (manager), NULL);
reload_if_needed (manager);
return (const gchar * const *)manager->priv->ids;
}
/**
* gtk_source_style_scheme_manager_get_scheme:
* @manager: a #GtkSourceStyleSchemeManager
* @scheme_id: style scheme id to find
*
* Looks up style scheme by id.
*
* Returns: a #GtkSourceStyleScheme object. Returned value is owned by
* @manager and must not be unref'ed.
*/
GtkSourceStyleScheme *
gtk_source_style_scheme_manager_get_scheme (GtkSourceStyleSchemeManager *manager,
const gchar *scheme_id)
{
g_return_val_if_fail (GTK_IS_SOURCE_STYLE_SCHEME_MANAGER (manager), NULL);
g_return_val_if_fail (scheme_id != NULL, NULL);
reload_if_needed (manager);
return g_hash_table_lookup (manager->priv->schemes_hash, scheme_id);
}

View File

@ -0,0 +1,90 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
* gtksourcestyleschememanager.h
*
* Copyright (C) 2003-2007 - Paolo Maggi <paolo.maggi@polito.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
#ifndef __GTK_SOURCE_STYLE_SCHEME_MANAGER_H__
#define __GTK_SOURCE_STYLE_SCHEME_MANAGER_H__
#include <gtksourceview/gtksourcestylescheme.h>
G_BEGIN_DECLS
#define GTK_TYPE_SOURCE_STYLE_SCHEME_MANAGER (gtk_source_style_scheme_manager_get_type ())
#define GTK_SOURCE_STYLE_SCHEME_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_SOURCE_STYLE_SCHEME_MANAGER, GtkSourceStyleSchemeManager))
#define GTK_SOURCE_STYLE_SCHEME_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_SOURCE_STYLE_SCHEME_MANAGER, GtkSourceStyleSchemeManagerClass))
#define GTK_IS_SOURCE_STYLE_SCHEME_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_SOURCE_STYLE_SCHEME_MANAGER))
#define GTK_IS_SOURCE_STYLE_SCHEME_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SOURCE_STYLE_SCHEME_MANAGER))
#define GTK_SOURCE_STYLE_SCHEME_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_SOURCE_STYLE_SCHEME_MANAGER, GtkSourceStyleSchemeManagerClass))
typedef struct _GtkSourceStyleSchemeManager GtkSourceStyleSchemeManager;
typedef struct _GtkSourceStyleSchemeManagerClass GtkSourceStyleSchemeManagerClass;
typedef struct _GtkSourceStyleSchemeManagerPrivate GtkSourceStyleSchemeManagerPrivate;
struct _GtkSourceStyleSchemeManager
{
GObject parent;
GtkSourceStyleSchemeManagerPrivate *priv;
};
struct _GtkSourceStyleSchemeManagerClass
{
GObjectClass parent_class;
/* Padding for future expansion */
void (*_gtk_source_reserved1) (void);
void (*_gtk_source_reserved2) (void);
void (*_gtk_source_reserved3) (void);
void (*_gtk_source_reserved4) (void);
};
GType gtk_source_style_scheme_manager_get_type (void) G_GNUC_CONST;
GtkSourceStyleSchemeManager *
gtk_source_style_scheme_manager_new (void);
GtkSourceStyleSchemeManager *
gtk_source_style_scheme_manager_get_default (void);
void gtk_source_style_scheme_manager_set_search_path (GtkSourceStyleSchemeManager *manager,
gchar **path);
void gtk_source_style_scheme_manager_append_search_path (GtkSourceStyleSchemeManager *manager,
const gchar *path);
void gtk_source_style_scheme_manager_prepend_search_path (GtkSourceStyleSchemeManager *manager,
const gchar *path);
const gchar* const *
gtk_source_style_scheme_manager_get_search_path (GtkSourceStyleSchemeManager *manager);
void gtk_source_style_scheme_manager_force_rescan (GtkSourceStyleSchemeManager *manager);
const gchar* const *
gtk_source_style_scheme_manager_get_scheme_ids (GtkSourceStyleSchemeManager *manager);
GtkSourceStyleScheme *gtk_source_style_scheme_manager_get_scheme (GtkSourceStyleSchemeManager *manager,
const gchar *scheme_id);
G_END_DECLS
#endif /* __GTK_SOURCE_STYLE_SCHEME_MANAGER_H__ */

Some files were not shown because too many files have changed in this diff Show More