summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS3
-rw-r--r--COPYING339
-rw-r--r--COPYING.LIB481
-rw-r--r--ChangeLog1
-rw-r--r--HACKING31
-rw-r--r--MAINTAINERS12
-rw-r--r--Makefile.am36
-rw-r--r--NEWS1
-rw-r--r--README44
-rw-r--r--aclocal.m42177
-rwxr-xr-xautogen.sh25
-rw-r--r--config.h.in83
-rwxr-xr-xconfig.sub1705
-rw-r--r--configure.ac171
-rwxr-xr-xdepcomp630
-rw-r--r--desktop-directories/Makefile.am37
-rw-r--r--desktop-directories/mate-audio-video.directory.in5
-rw-r--r--desktop-directories/mate-development.directory.in5
-rw-r--r--desktop-directories/mate-education.directory.in4
-rw-r--r--desktop-directories/mate-game.directory.in5
-rw-r--r--desktop-directories/mate-graphics.directory.in5
-rw-r--r--desktop-directories/mate-hardware.directory.in5
-rw-r--r--desktop-directories/mate-internet-and-network.directory.in5
-rw-r--r--desktop-directories/mate-look-and-feel.directory.in5
-rw-r--r--desktop-directories/mate-menu-applications.directory.in5
-rw-r--r--desktop-directories/mate-menu-system.directory.in5
-rw-r--r--desktop-directories/mate-network.directory.in5
-rw-r--r--desktop-directories/mate-office.directory.in5
-rw-r--r--desktop-directories/mate-other.directory.in5
-rw-r--r--desktop-directories/mate-personal.directory.in6
-rw-r--r--desktop-directories/mate-settings-system.directory.in5
-rw-r--r--desktop-directories/mate-settings.directory.in5
-rw-r--r--desktop-directories/mate-system-tools.directory.in5
-rw-r--r--desktop-directories/mate-system.directory.in5
-rw-r--r--desktop-directories/mate-utility-accessibility.directory.in5
-rw-r--r--desktop-directories/mate-utility.directory.in5
-rw-r--r--distro/archlinux/PKGBUILD29
-rw-r--r--distro/archlinux/menus.patch25
-rwxr-xr-xdistro/ubuntu/build27
-rwxr-xr-xinstall-sh520
-rw-r--r--layout/Makefile.am9
-rw-r--r--layout/mate-applications.menu154
-rw-r--r--layout/mate-settings.menu57
-rw-r--r--libmenu/Makefile.am78
-rw-r--r--libmenu/canonicalize.c326
-rw-r--r--libmenu/canonicalize.h38
-rw-r--r--libmenu/desktop-entries.c816
-rw-r--r--libmenu/desktop-entries.h90
-rw-r--r--libmenu/entry-directories.c1105
-rw-r--r--libmenu/entry-directories.h67
-rw-r--r--libmenu/libmate-menu-uninstalled.pc.in11
-rw-r--r--libmenu/libmate-menu.pc.in11
-rw-r--r--libmenu/matemenu-tree.c4520
-rw-r--r--libmenu/matemenu-tree.h135
-rw-r--r--libmenu/menu-layout.c2359
-rw-r--r--libmenu/menu-layout.h161
-rw-r--r--libmenu/menu-monitor.c440
-rw-r--r--libmenu/menu-monitor.h70
-rw-r--r--libmenu/menu-util.c436
-rw-r--r--libmenu/menu-util.h59
-rw-r--r--m4/intltool.m4216
-rw-r--r--m4/ltsugar.m4123
-rw-r--r--m4/python.m486
-rwxr-xr-xmissing376
-rwxr-xr-xmkinstalldirs162
-rw-r--r--po/LINGUAS100
-rw-r--r--po/POTFILES.in28
-rw-r--r--po/POTFILES.skip3
-rw-r--r--po/af.po258
-rw-r--r--po/an.po211
-rw-r--r--po/ar.po270
-rw-r--r--po/as.po277
-rw-r--r--po/ast.po265
-rw-r--r--po/be.po269
-rw-r--r--po/[email protected]275
-rw-r--r--po/bg.po272
-rw-r--r--po/bn.po301
-rw-r--r--po/bn_IN.po280
-rw-r--r--po/br.po266
-rw-r--r--po/ca.po272
-rw-r--r--po/[email protected]272
-rw-r--r--po/crh.po271
-rw-r--r--po/cs.po269
-rw-r--r--po/cy.po231
-rw-r--r--po/da.po284
-rw-r--r--po/de.po273
-rw-r--r--po/dv.po260
-rw-r--r--po/dz.po275
-rw-r--r--po/el.po255
-rw-r--r--po/[email protected]211
-rw-r--r--po/en_CA.po232
-rw-r--r--po/en_GB.po283
-rw-r--r--po/eo.po315
-rw-r--r--po/es.po281
-rw-r--r--po/et.po219
-rw-r--r--po/eu.po269
-rw-r--r--po/fa.po272
-rw-r--r--po/fi.po282
-rw-r--r--po/fr.po274
-rw-r--r--po/fur.po270
-rw-r--r--po/fy.po269
-rw-r--r--po/ga.po267
-rw-r--r--po/gl.po272
-rw-r--r--po/gn.po218
-rw-r--r--po/gu.po270
-rw-r--r--po/gv.po279
-rw-r--r--po/ha.po272
-rw-r--r--po/he.po276
-rw-r--r--po/hi.po277
-rw-r--r--po/hr.po271
-rw-r--r--po/hu.po268
-rw-r--r--po/hy.po266
-rw-r--r--po/id.po217
-rw-r--r--po/ig.po270
-rw-r--r--po/io.po267
-rw-r--r--po/is.po268
-rw-r--r--po/it.po267
-rw-r--r--po/ja.po263
-rw-r--r--po/ka.po238
-rw-r--r--po/kk.po255
-rw-r--r--po/kn.po256
-rw-r--r--po/ko.po268
-rw-r--r--po/ku.po285
-rw-r--r--po/ky.po227
-rw-r--r--po/lt.po280
-rw-r--r--po/lv.po261
-rw-r--r--po/mai.po272
-rw-r--r--po/mg.po237
-rw-r--r--po/mk.po277
-rw-r--r--po/ml.po269
-rw-r--r--po/mn.po273
-rw-r--r--po/mr.po274
-rw-r--r--po/ms.po2260
-rw-r--r--po/nb.po266
-rw-r--r--po/nds.po268
-rw-r--r--po/ne.po275
-rw-r--r--po/nl.po281
-rw-r--r--po/nn.po275
-rw-r--r--po/oc.po266
-rw-r--r--po/or.po274
-rw-r--r--po/pa.po275
-rw-r--r--po/pl.po280
-rw-r--r--po/ps.po259
-rw-r--r--po/pt.po282
-rw-r--r--po/pt_BR.po316
-rw-r--r--po/ro.po269
-rw-r--r--po/ru.po274
-rw-r--r--po/rw.po150
-rw-r--r--po/si.po271
-rw-r--r--po/sk.po213
-rw-r--r--po/sl.po274
-rw-r--r--po/sq.po278
-rw-r--r--po/sr.po287
-rw-r--r--po/[email protected]287
-rw-r--r--po/sv.po310
-rw-r--r--po/ta.po276
-rw-r--r--po/te.po270
-rw-r--r--po/th.po281
-rw-r--r--po/tr.po276
-rw-r--r--po/ug.po297
-rw-r--r--po/uk.po281
-rw-r--r--po/[email protected]270
-rw-r--r--po/vi.po279
-rw-r--r--po/xh.po127
-rw-r--r--po/yo.po270
-rw-r--r--po/zh_CN.po268
-rw-r--r--po/zh_HK.po279
-rw-r--r--po/zh_TW.po279
-rwxr-xr-xpy-compile146
-rw-r--r--python/Makefile.am20
-rw-r--r--python/matemenu.c1948
-rw-r--r--util/Makefile.am31
-rw-r--r--util/mate-menus-ls.py94
-rw-r--r--util/test-menu-spec.c225
174 files changed, 49563 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..e0deab2
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,3 @@
+Mark McLoughlin <[email protected]>
+Havoc Pennington <[email protected]>
+Vincent Untz <[email protected]>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/COPYING
@@ -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.
diff --git a/COPYING.LIB b/COPYING.LIB
new file mode 100644
index 0000000..5bc8fb2
--- /dev/null
+++ b/COPYING.LIB
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 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.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ 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 Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, 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 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 a program 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.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, 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 companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ 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, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+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 compile 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) 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.
+
+ c) 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.
+
+ d) 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 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.
+
+ 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 to
+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 Library 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 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., 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!
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1 @@
+
diff --git a/HACKING b/HACKING
new file mode 100644
index 0000000..5a7b611
--- /dev/null
+++ b/HACKING
@@ -0,0 +1,31 @@
+Hacking on mate-menus
+======================
+
+ + The development occurs in git:
+
+ http://git.gnome.org/browse/mate-menus
+
+ For information on how to access MATE git please read:
+
+ http://live.gnome.org/Git
+
+ + Please send patches as bug reports in MATE Bugzilla:
+
+ https://bugzilla.gnome.org/ (product mate-menus)
+
+ Your patch should be in unified diff form (the -u option to GNU
+ diff). See also:
+
+ http://live.gnome.org/MateLove/SubmittingPatches
+
+ + Please try and send a patch against a recent version of this package.
+ Patches against git master are most preferable.
+
+ + Don't commit any but the most trivial patches without approval.
+
+ + Exceptions to this are:
+
+ - Translators may commit basic i18n related patches to the build
+ setup.
+ - Build sheriff are welcome - in accordance with the relevant build
+ sheriff constraints.
diff --git a/MAINTAINERS b/MAINTAINERS
new file mode 100644
index 0000000..cc6c441
--- /dev/null
+++ b/MAINTAINERS
@@ -0,0 +1,12 @@
+Currently active maintainers
+----------------------------
+
+Vincent Untz
+Userid: vuntz
+
+Non-active maintainers, who have a good understanding of the code
+-----------------------------------------------------------------
+
+#Mark McLoughlin
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..d68b88f
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,36 @@
+SUBDIRS = libmenu desktop-directories layout util po
+
+if HAVE_PYTHON
+SUBDIRS += python
+endif
+
+ACLOCAL_AMFLAGS = -I m4
+
+DISTCHECK_CONFIGURE_FLAGS = --enable-introspection --enable-python
+
+EXTRA_DIST = \
+ HACKING \
+ MAINTAINERS
+
+MAINTAINERCLEANFILES = \
+ $(srcdir)/INSTALL \
+ $(srcdir)/aclocal.m4 \
+ $(srcdir)/config.guess \
+ $(srcdir)/config.h.in \
+ $(srcdir)/config.sub \
+ $(srcdir)/depcomp \
+ $(srcdir)/install-sh \
+ $(srcdir)/ltmain.sh \
+ $(srcdir)/missing \
+ $(srcdir)/mkinstalldirs \
+ $(srcdir)/py-compile \
+ `find "$(srcdir)" -type f -name Makefile.in -print` \
+ $(srcdir)/configure \
+ $(srcdir)/m4/intltool.m4 \
+ $(srcdir)/m4/libtool.m4 \
+ $(srcdir)/m4/ltoptions.m4 \
+ $(srcdir)/m4/ltsugar.m4 \
+ $(srcdir)/m4/ltversion.m4 \
+ $(srcdir)/m4/lt~obsolete.m4
+
+-include $(top_srcdir)/git.mk
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/NEWS
@@ -0,0 +1 @@
+
diff --git a/README b/README
new file mode 100644
index 0000000..332e2c6
--- /dev/null
+++ b/README
@@ -0,0 +1,44 @@
+mate-menus
+===========
+
+mate-menus contains the libmate-menu library, the layout configuration
+files for the MATE menu, as well as a simple menu editor.
+
+The libmate-menu library implements the "Desktop Menu Specification"
+from freedesktop.org:
+
+ http://freedesktop.org/wiki/Specifications/menu-spec
+ http://specifications.freedesktop.org/menu-spec/menu-spec-latest.html
+
+You may download updates to the package from:
+
+ http://download.gnome.org/sources/mate-menus/
+
+To discuss mate-menus, you may use the desktop-devel-list mailing list:
+
+ http://mail.gnome.org/mailman/listinfo/desktop-devel-list
+
+
+Installation
+============
+
+See the file 'INSTALL'. If you are not using a released version of
+mate-menus (for example, if you checked out the code from git), you
+first need to run './autogen.sh'.
+
+
+How to report bugs
+==================
+
+Bugs should be reported to the MATE bug tracking system:
+
+ https://bugzilla.gnome.org/ (product mate-menus)
+
+You will need to create an account for yourself.
+
+Please read the following page on how to prepare a useful bug report:
+
+ https://bugzilla.gnome.org/page.cgi?id=bug-writing.html
+
+Please read the HACKING file for information on where to send changes or
+bugfixes for this package.
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..0f90350
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,2177 @@
+# generated automatically by aclocal 1.11.1 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],,
+[m4_warning([this file was generated for autoconf 2.68.
+You have another version of autoconf. It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically `autoreconf'.])])
+
+# Copyright (C) 1995-2002 Free Software Foundation, Inc.
+# Copyright (C) 2001-2003,2004 Red Hat, Inc.
+#
+# This file is free software, distributed under the terms of the GNU
+# General Public License. As a special exception to the GNU General
+# Public License, this file may be distributed as part of a program
+# that contains a configuration script generated by Autoconf, under
+# the same distribution terms as the rest of that program.
+#
+# This file can be copied and used freely without restrictions. It can
+# be used in projects which are not available under the GNU Public License
+# but which still want to provide support for the GNU gettext functionality.
+#
+# Macro to add for using GNU gettext.
+# Ulrich Drepper <[email protected]>, 1995, 1996
+#
+# Modified to never use included libintl.
+# Owen Taylor <[email protected]>, 12/15/1998
+#
+# Major rework to remove unused code
+# Owen Taylor <[email protected]>, 12/11/2002
+#
+# Added better handling of ALL_LINGUAS from GNU gettext version
+# written by Bruno Haible, Owen Taylor <otaylor.redhat.com> 5/30/3002
+#
+# Modified to require ngettext
+# Matthias Clasen <[email protected]> 08/06/2004
+#
+# We need this here as well, since someone might use autoconf-2.5x
+# to configure GLib then an older version to configure a package
+# using AM_GLIB_GNU_GETTEXT
+AC_PREREQ(2.53)
+
+dnl
+dnl We go to great lengths to make sure that aclocal won't
+dnl try to pull in the installed version of these macros
+dnl when running aclocal in the glib directory.
+dnl
+m4_copy([AC_DEFUN],[glib_DEFUN])
+m4_copy([AC_REQUIRE],[glib_REQUIRE])
+dnl
+dnl At the end, if we're not within glib, we'll define the public
+dnl definitions in terms of our private definitions.
+dnl
+
+# GLIB_LC_MESSAGES
+#--------------------
+glib_DEFUN([GLIB_LC_MESSAGES],
+ [AC_CHECK_HEADERS([locale.h])
+ if test $ac_cv_header_locale_h = yes; then
+ AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES,
+ [AC_TRY_LINK([#include <locale.h>], [return LC_MESSAGES],
+ am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)])
+ if test $am_cv_val_LC_MESSAGES = yes; then
+ AC_DEFINE(HAVE_LC_MESSAGES, 1,
+ [Define if your <locale.h> file defines LC_MESSAGES.])
+ fi
+ fi])
+
+# GLIB_PATH_PROG_WITH_TEST
+#----------------------------
+dnl GLIB_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR,
+dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]])
+glib_DEFUN([GLIB_PATH_PROG_WITH_TEST],
+[# Extract the first word of "$2", so it can be a program name with args.
+set dummy $2; ac_word=[$]2
+AC_MSG_CHECKING([for $ac_word])
+AC_CACHE_VAL(ac_cv_path_$1,
+[case "[$]$1" in
+ /*)
+ ac_cv_path_$1="[$]$1" # Let the user override the test with a path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in ifelse([$5], , $PATH, [$5]); do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if [$3]; then
+ ac_cv_path_$1="$ac_dir/$ac_word"
+ break
+ fi
+ fi
+ done
+ IFS="$ac_save_ifs"
+dnl If no 4th arg is given, leave the cache variable unset,
+dnl so AC_PATH_PROGS will keep looking.
+ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4"
+])dnl
+ ;;
+esac])dnl
+$1="$ac_cv_path_$1"
+if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then
+ AC_MSG_RESULT([$]$1)
+else
+ AC_MSG_RESULT(no)
+fi
+AC_SUBST($1)dnl
+])
+
+# GLIB_WITH_NLS
+#-----------------
+glib_DEFUN([GLIB_WITH_NLS],
+ dnl NLS is obligatory
+ [USE_NLS=yes
+ AC_SUBST(USE_NLS)
+
+ gt_cv_have_gettext=no
+
+ CATOBJEXT=NONE
+ XGETTEXT=:
+ INTLLIBS=
+
+ AC_CHECK_HEADER(libintl.h,
+ [gt_cv_func_dgettext_libintl="no"
+ libintl_extra_libs=""
+
+ #
+ # First check in libc
+ #
+ AC_CACHE_CHECK([for ngettext in libc], gt_cv_func_ngettext_libc,
+ [AC_TRY_LINK([
+#include <libintl.h>
+],
+ [return !ngettext ("","", 1)],
+ gt_cv_func_ngettext_libc=yes,
+ gt_cv_func_ngettext_libc=no)
+ ])
+
+ if test "$gt_cv_func_ngettext_libc" = "yes" ; then
+ AC_CACHE_CHECK([for dgettext in libc], gt_cv_func_dgettext_libc,
+ [AC_TRY_LINK([
+#include <libintl.h>
+],
+ [return !dgettext ("","")],
+ gt_cv_func_dgettext_libc=yes,
+ gt_cv_func_dgettext_libc=no)
+ ])
+ fi
+
+ if test "$gt_cv_func_ngettext_libc" = "yes" ; then
+ AC_CHECK_FUNCS(bind_textdomain_codeset)
+ fi
+
+ #
+ # If we don't have everything we want, check in libintl
+ #
+ if test "$gt_cv_func_dgettext_libc" != "yes" \
+ || test "$gt_cv_func_ngettext_libc" != "yes" \
+ || test "$ac_cv_func_bind_textdomain_codeset" != "yes" ; then
+
+ AC_CHECK_LIB(intl, bindtextdomain,
+ [AC_CHECK_LIB(intl, ngettext,
+ [AC_CHECK_LIB(intl, dgettext,
+ gt_cv_func_dgettext_libintl=yes)])])
+
+ if test "$gt_cv_func_dgettext_libintl" != "yes" ; then
+ AC_MSG_CHECKING([if -liconv is needed to use gettext])
+ AC_MSG_RESULT([])
+ AC_CHECK_LIB(intl, ngettext,
+ [AC_CHECK_LIB(intl, dcgettext,
+ [gt_cv_func_dgettext_libintl=yes
+ libintl_extra_libs=-liconv],
+ :,-liconv)],
+ :,-liconv)
+ fi
+
+ #
+ # If we found libintl, then check in it for bind_textdomain_codeset();
+ # we'll prefer libc if neither have bind_textdomain_codeset(),
+ # and both have dgettext and ngettext
+ #
+ if test "$gt_cv_func_dgettext_libintl" = "yes" ; then
+ glib_save_LIBS="$LIBS"
+ LIBS="$LIBS -lintl $libintl_extra_libs"
+ unset ac_cv_func_bind_textdomain_codeset
+ AC_CHECK_FUNCS(bind_textdomain_codeset)
+ LIBS="$glib_save_LIBS"
+
+ if test "$ac_cv_func_bind_textdomain_codeset" = "yes" ; then
+ gt_cv_func_dgettext_libc=no
+ else
+ if test "$gt_cv_func_dgettext_libc" = "yes" \
+ && test "$gt_cv_func_ngettext_libc" = "yes"; then
+ gt_cv_func_dgettext_libintl=no
+ fi
+ fi
+ fi
+ fi
+
+ if test "$gt_cv_func_dgettext_libc" = "yes" \
+ || test "$gt_cv_func_dgettext_libintl" = "yes"; then
+ gt_cv_have_gettext=yes
+ fi
+
+ if test "$gt_cv_func_dgettext_libintl" = "yes"; then
+ INTLLIBS="-lintl $libintl_extra_libs"
+ fi
+
+ if test "$gt_cv_have_gettext" = "yes"; then
+ AC_DEFINE(HAVE_GETTEXT,1,
+ [Define if the GNU gettext() function is already present or preinstalled.])
+ GLIB_PATH_PROG_WITH_TEST(MSGFMT, msgfmt,
+ [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no)dnl
+ if test "$MSGFMT" != "no"; then
+ glib_save_LIBS="$LIBS"
+ LIBS="$LIBS $INTLLIBS"
+ AC_CHECK_FUNCS(dcgettext)
+ MSGFMT_OPTS=
+ AC_MSG_CHECKING([if msgfmt accepts -c])
+ GLIB_RUN_PROG([$MSGFMT -c -o /dev/null],[
+msgid ""
+msgstr ""
+"Content-Type: text/plain; charset=UTF-8\n"
+"Project-Id-Version: test 1.0\n"
+"PO-Revision-Date: 2007-02-15 12:01+0100\n"
+"Last-Translator: test <[email protected]>\n"
+"Language-Team: C <[email protected]>\n"
+"MIME-Version: 1.0\n"
+"Content-Transfer-Encoding: 8bit\n"
+], [MSGFMT_OPTS=-c; AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])])
+ AC_SUBST(MSGFMT_OPTS)
+ AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT)
+ GLIB_PATH_PROG_WITH_TEST(XGETTEXT, xgettext,
+ [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :)
+ AC_TRY_LINK(, [extern int _nl_msg_cat_cntr;
+ return _nl_msg_cat_cntr],
+ [CATOBJEXT=.gmo
+ DATADIRNAME=share],
+ [case $host in
+ *-*-solaris*)
+ dnl On Solaris, if bind_textdomain_codeset is in libc,
+ dnl GNU format message catalog is always supported,
+ dnl since both are added to the libc all together.
+ dnl Hence, we'd like to go with DATADIRNAME=share and
+ dnl and CATOBJEXT=.gmo in this case.
+ AC_CHECK_FUNC(bind_textdomain_codeset,
+ [CATOBJEXT=.gmo
+ DATADIRNAME=share],
+ [CATOBJEXT=.mo
+ DATADIRNAME=lib])
+ ;;
+ *-*-openbsd*)
+ CATOBJEXT=.mo
+ DATADIRNAME=share
+ ;;
+ *)
+ CATOBJEXT=.mo
+ DATADIRNAME=lib
+ ;;
+ esac])
+ LIBS="$glib_save_LIBS"
+ INSTOBJEXT=.mo
+ else
+ gt_cv_have_gettext=no
+ fi
+ fi
+ ])
+
+ if test "$gt_cv_have_gettext" = "yes" ; then
+ AC_DEFINE(ENABLE_NLS, 1,
+ [always defined to indicate that i18n is enabled])
+ fi
+
+ dnl Test whether we really found GNU xgettext.
+ if test "$XGETTEXT" != ":"; then
+ dnl If it is not GNU xgettext we define it as : so that the
+ dnl Makefiles still can work.
+ if $XGETTEXT --omit-header /dev/null 2> /dev/null; then
+ : ;
+ else
+ AC_MSG_RESULT(
+ [found xgettext program is not GNU xgettext; ignore it])
+ XGETTEXT=":"
+ fi
+ fi
+
+ # We need to process the po/ directory.
+ POSUB=po
+
+ AC_OUTPUT_COMMANDS(
+ [case "$CONFIG_FILES" in *po/Makefile.in*)
+ sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile
+ esac])
+
+ dnl These rules are solely for the distribution goal. While doing this
+ dnl we only have to keep exactly one list of the available catalogs
+ dnl in configure.ac.
+ for lang in $ALL_LINGUAS; do
+ GMOFILES="$GMOFILES $lang.gmo"
+ POFILES="$POFILES $lang.po"
+ done
+
+ dnl Make all variables we use known to autoconf.
+ AC_SUBST(CATALOGS)
+ AC_SUBST(CATOBJEXT)
+ AC_SUBST(DATADIRNAME)
+ AC_SUBST(GMOFILES)
+ AC_SUBST(INSTOBJEXT)
+ AC_SUBST(INTLLIBS)
+ AC_SUBST(PO_IN_DATADIR_TRUE)
+ AC_SUBST(PO_IN_DATADIR_FALSE)
+ AC_SUBST(POFILES)
+ AC_SUBST(POSUB)
+ ])
+
+# AM_GLIB_GNU_GETTEXT
+# -------------------
+# Do checks necessary for use of gettext. If a suitable implementation
+# of gettext is found in either in libintl or in the C library,
+# it will set INTLLIBS to the libraries needed for use of gettext
+# and AC_DEFINE() HAVE_GETTEXT and ENABLE_NLS. (The shell variable
+# gt_cv_have_gettext will be set to "yes".) It will also call AC_SUBST()
+# on various variables needed by the Makefile.in.in installed by
+# glib-gettextize.
+dnl
+glib_DEFUN([GLIB_GNU_GETTEXT],
+ [AC_REQUIRE([AC_PROG_CC])dnl
+ AC_REQUIRE([AC_HEADER_STDC])dnl
+
+ GLIB_LC_MESSAGES
+ GLIB_WITH_NLS
+
+ if test "$gt_cv_have_gettext" = "yes"; then
+ if test "x$ALL_LINGUAS" = "x"; then
+ LINGUAS=
+ else
+ AC_MSG_CHECKING(for catalogs to be installed)
+ NEW_LINGUAS=
+ for presentlang in $ALL_LINGUAS; do
+ useit=no
+ if test "%UNSET%" != "${LINGUAS-%UNSET%}"; then
+ desiredlanguages="$LINGUAS"
+ else
+ desiredlanguages="$ALL_LINGUAS"
+ fi
+ for desiredlang in $desiredlanguages; do
+ # Use the presentlang catalog if desiredlang is
+ # a. equal to presentlang, or
+ # b. a variant of presentlang (because in this case,
+ # presentlang can be used as a fallback for messages
+ # which are not translated in the desiredlang catalog).
+ case "$desiredlang" in
+ "$presentlang"*) useit=yes;;
+ esac
+ done
+ if test $useit = yes; then
+ NEW_LINGUAS="$NEW_LINGUAS $presentlang"
+ fi
+ done
+ LINGUAS=$NEW_LINGUAS
+ AC_MSG_RESULT($LINGUAS)
+ fi
+
+ dnl Construct list of names of catalog files to be constructed.
+ if test -n "$LINGUAS"; then
+ for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done
+ fi
+ fi
+
+ dnl If the AC_CONFIG_AUX_DIR macro for autoconf is used we possibly
+ dnl find the mkinstalldirs script in another subdir but ($top_srcdir).
+ dnl Try to locate is.
+ MKINSTALLDIRS=
+ if test -n "$ac_aux_dir"; then
+ MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs"
+ fi
+ if test -z "$MKINSTALLDIRS"; then
+ MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs"
+ fi
+ AC_SUBST(MKINSTALLDIRS)
+
+ dnl Generate list of files to be processed by xgettext which will
+ dnl be included in po/Makefile.
+ test -d po || mkdir po
+ if test "x$srcdir" != "x."; then
+ if test "x`echo $srcdir | sed '[email protected]/.*@@'`" = "x"; then
+ posrcprefix="$srcdir/"
+ else
+ posrcprefix="../$srcdir/"
+ fi
+ else
+ posrcprefix="../"
+ fi
+ rm -f po/POTFILES
+ sed -e "/^#/d" -e "/^\$/d" -e "s,.*, $posrcprefix& \\\\," -e "\$s/\(.*\) \\\\/\1/" \
+ < $srcdir/po/POTFILES.in > po/POTFILES
+ ])
+
+# AM_GLIB_DEFINE_LOCALEDIR(VARIABLE)
+# -------------------------------
+# Define VARIABLE to the location where catalog files will
+# be installed by po/Makefile.
+glib_DEFUN([GLIB_DEFINE_LOCALEDIR],
+[glib_REQUIRE([GLIB_GNU_GETTEXT])dnl
+glib_save_prefix="$prefix"
+glib_save_exec_prefix="$exec_prefix"
+glib_save_datarootdir="$datarootdir"
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+test "x$exec_prefix" = xNONE && exec_prefix=$prefix
+datarootdir=`eval echo "${datarootdir}"`
+if test "x$CATOBJEXT" = "x.mo" ; then
+ localedir=`eval echo "${libdir}/locale"`
+else
+ localedir=`eval echo "${datadir}/locale"`
+fi
+prefix="$glib_save_prefix"
+exec_prefix="$glib_save_exec_prefix"
+datarootdir="$glib_save_datarootdir"
+AC_DEFINE_UNQUOTED($1, "$localedir",
+ [Define the location where the catalogs will be installed])
+])
+
+dnl
+dnl Now the definitions that aclocal will find
+dnl
+ifdef(glib_configure_ac,[],[
+AC_DEFUN([AM_GLIB_GNU_GETTEXT],[GLIB_GNU_GETTEXT([email protected])])
+AC_DEFUN([AM_GLIB_DEFINE_LOCALEDIR],[GLIB_DEFINE_LOCALEDIR([email protected])])
+])dnl
+
+# GLIB_RUN_PROG(PROGRAM, TEST-FILE, [ACTION-IF-PASS], [ACTION-IF-FAIL])
+#
+# Create a temporary file with TEST-FILE as its contents and pass the
+# file name to PROGRAM. Perform ACTION-IF-PASS if PROGRAM exits with
+# 0 and perform ACTION-IF-FAIL for any other exit status.
+AC_DEFUN([GLIB_RUN_PROG],
+[cat >conftest.foo <<_ACEOF
+$2
+_ACEOF
+if AC_RUN_LOG([$1 conftest.foo]); then
+ m4_ifval([$3], [$3], [:])
+m4_ifvaln([$4], [else $4])dnl
+echo "$as_me: failed input was:" >&AS_MESSAGE_LOG_FD
+sed 's/^/| /' conftest.foo >&AS_MESSAGE_LOG_FD
+fi])
+
+
+dnl -*- mode: autoconf -*-
+dnl Copyright 2009 Johan Dahlin
+dnl
+dnl This file is free software; the author(s) gives unlimited
+dnl permission to copy and/or distribute it, with or without
+dnl modifications, as long as this notice is preserved.
+dnl
+
+# serial 1
+
+m4_define([_GOBJECT_INTROSPECTION_CHECK_INTERNAL],
+[
+ AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first
+ AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first
+ AC_BEFORE([LT_INIT],[$0])dnl setup libtool first
+
+ dnl enable/disable introspection
+ m4_if([$2], [require],
+ [dnl
+ enable_introspection=yes
+ ],[dnl
+ AC_ARG_ENABLE(introspection,
+ AS_HELP_STRING([--enable-introspection[[email protected]<:@no/auto/[email protected]:>@]],
+ [Enable introspection for this build]),,
+ [enable_introspection=auto])
+ ])dnl
+
+ AC_MSG_CHECKING([for gobject-introspection])
+
+ dnl presence/version checking
+ AS_CASE([$enable_introspection],
+ [no], [dnl
+ found_introspection="no (disabled, use --enable-introspection to enable)"
+ ],dnl
+ [yes],[dnl
+ PKG_CHECK_EXISTS([gobject-introspection-1.0],,
+ AC_MSG_ERROR([gobject-introspection-1.0 is not installed]))
+ PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1],
+ found_introspection=yes,
+ AC_MSG_ERROR([You need to have gobject-introspection >= $1 installed to build AC_PACKAGE_NAME]))
+ ],dnl
+ [auto],[dnl
+ PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1], found_introspection=yes, found_introspection=no)
+ ],dnl
+ [dnl
+ AC_MSG_ERROR([invalid argument passed to --enable-introspection, should be one of @<:@no/auto/[email protected]:>@])
+ ])dnl
+
+ AC_MSG_RESULT([$found_introspection])
+
+ INTROSPECTION_SCANNER=
+ INTROSPECTION_COMPILER=
+ INTROSPECTION_GENERATE=
+ INTROSPECTION_GIRDIR=
+ INTROSPECTION_TYPELIBDIR=
+ if test "x$found_introspection" = "xyes"; then
+ INTROSPECTION_SCANNER=`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0`
+ INTROSPECTION_COMPILER=`$PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0`
+ INTROSPECTION_GENERATE=`$PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0`
+ INTROSPECTION_GIRDIR=`$PKG_CONFIG --variable=girdir gobject-introspection-1.0`
+ INTROSPECTION_TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)"
+ INTROSPECTION_CFLAGS=`$PKG_CONFIG --cflags gobject-introspection-1.0`
+ INTROSPECTION_LIBS=`$PKG_CONFIG --libs gobject-introspection-1.0`
+ INTROSPECTION_MAKEFILE=`$PKG_CONFIG --variable=datadir gobject-introspection-1.0`/gobject-introspection-1.0/Makefile.introspection
+ fi
+ AC_SUBST(INTROSPECTION_SCANNER)
+ AC_SUBST(INTROSPECTION_COMPILER)
+ AC_SUBST(INTROSPECTION_GENERATE)
+ AC_SUBST(INTROSPECTION_GIRDIR)
+ AC_SUBST(INTROSPECTION_TYPELIBDIR)
+ AC_SUBST(INTROSPECTION_CFLAGS)
+ AC_SUBST(INTROSPECTION_LIBS)
+ AC_SUBST(INTROSPECTION_MAKEFILE)
+
+ AM_CONDITIONAL(HAVE_INTROSPECTION, test "x$found_introspection" = "xyes")
+])
+
+
+dnl Usage:
+dnl GOBJECT_INTROSPECTION_CHECK([minimum-g-i-version])
+
+AC_DEFUN([GOBJECT_INTROSPECTION_CHECK],
+[
+ _GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1])
+])
+
+dnl Usage:
+dnl GOBJECT_INTROSPECTION_REQUIRE([minimum-g-i-version])
+
+
+AC_DEFUN([GOBJECT_INTROSPECTION_REQUIRE],
+[
+ _GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1], [require])
+])
+
+# mate-common.m4
+#
+
+dnl MATE_COMMON_INIT
+
+AC_DEFUN([MATE_COMMON_INIT],
+[
+ dnl this macro should come after AC_CONFIG_MACRO_DIR
+ AC_BEFORE([AC_CONFIG_MACRO_DIR], [$0])
+
+ dnl ensure that when the Automake generated makefile calls aclocal,
+ dnl it honours the $ACLOCAL_FLAGS environment variable
+ ACLOCAL_AMFLAGS="\${ACLOCAL_FLAGS}"
+ if test -n "$ac_macro_dir"; then
+ ACLOCAL_AMFLAGS="-I $ac_macro_dir $ACLOCAL_AMFLAGS"
+ fi
+
+ AC_SUBST([ACLOCAL_AMFLAGS])
+])
+
+AC_DEFUN([MATE_DEBUG_CHECK],
+[
+ AC_ARG_ENABLE([debug],
+ AC_HELP_STRING([--enable-debug],
+ [turn on debugging]),,
+ [enable_debug=no])
+
+ if test x$enable_debug = xyes ; then
+ AC_DEFINE(MATE_ENABLE_DEBUG, 1,
+ [Enable additional debugging at the expense of performance and size])
+ fi
+])
+
+dnl MATE_MAINTAINER_MODE_DEFINES ()
+dnl define DISABLE_DEPRECATED
+dnl
+AC_DEFUN([MATE_MAINTAINER_MODE_DEFINES],
+[
+ AC_REQUIRE([AM_MAINTAINER_MODE])
+
+ DISABLE_DEPRECATED=""
+ if test $USE_MAINTAINER_MODE = yes; then
+ DOMAINS="G ATK PANGO GDK GDK_PIXBUF GTK MATECONF MATECOMPONENT MATECOMPONENT_UI MATE LIBGLADE VTE MATE_VFS WNCK LIBSOUP"
+ for DOMAIN in $DOMAINS; do
+ DISABLE_DEPRECATED="$DISABLE_DEPRECATED -D${DOMAIN}_DISABLE_DEPRECATED -D${DOMAIN}_DISABLE_SINGLE_INCLUDES"
+ done
+ fi
+
+ AC_SUBST(DISABLE_DEPRECATED)
+])
+
+dnl MATE_COMPILE_WARNINGS
+dnl Turn on many useful compiler warnings
+dnl For now, only works on GCC
+AC_DEFUN([MATE_COMPILE_WARNINGS],[
+ dnl ******************************
+ dnl More compiler warnings
+ dnl ******************************
+
+ AC_ARG_ENABLE(compile-warnings,
+ AC_HELP_STRING([[email protected]<:@no/minimum/yes/maximum/[email protected]:>@],
+ [Turn on compiler warnings]),,
+ [enable_compile_warnings="m4_default([$1],[yes])"])
+
+ warnCFLAGS=
+ if test "x$GCC" != xyes; then
+ enable_compile_warnings=no
+ fi
+
+ warning_flags=
+ realsave_CFLAGS="$CFLAGS"
+
+ case "$enable_compile_warnings" in
+ no)
+ warning_flags=
+ ;;
+ minimum)
+ warning_flags="-Wall"
+ ;;
+ yes)
+ warning_flags="-Wall -Wmissing-prototypes"
+ ;;
+ maximum|error)
+ warning_flags="-Wall -Wmissing-prototypes -Wnested-externs -Wpointer-arith"
+ CFLAGS="$warning_flags $CFLAGS"
+ for option in -Wno-sign-compare; do
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $option"
+ AC_MSG_CHECKING([whether gcc understands $option])
+ AC_TRY_COMPILE([], [],
+ has_option=yes,
+ has_option=no,)
+ CFLAGS="$SAVE_CFLAGS"
+ AC_MSG_RESULT($has_option)
+ if test $has_option = yes; then
+ warning_flags="$warning_flags $option"
+ fi
+ unset has_option
+ unset SAVE_CFLAGS
+ done
+ unset option
+ if test "$enable_compile_warnings" = "error" ; then
+ warning_flags="$warning_flags -Werror"
+ fi
+ ;;
+ *)
+ AC_MSG_ERROR(Unknown argument '$enable_compile_warnings' to --enable-compile-warnings)
+ ;;
+ esac
+ CFLAGS="$realsave_CFLAGS"
+ AC_MSG_CHECKING(what warning flags to pass to the C compiler)
+ AC_MSG_RESULT($warning_flags)
+
+ AC_ARG_ENABLE(iso-c,
+ AC_HELP_STRING([--enable-iso-c],
+ [Try to warn if code is not ISO C ]),,
+ [enable_iso_c=no])
+
+ AC_MSG_CHECKING(what language compliance flags to pass to the C compiler)
+ complCFLAGS=
+ if test "x$enable_iso_c" != "xno"; then
+ if test "x$GCC" = "xyes"; then
+ case " $CFLAGS " in
+ *[\ \ ]-ansi[\ \ ]*) ;;
+ *) complCFLAGS="$complCFLAGS -ansi" ;;
+ esac
+ case " $CFLAGS " in
+ *[\ \ ]-pedantic[\ \ ]*) ;;
+ *) complCFLAGS="$complCFLAGS -pedantic" ;;
+ esac
+ fi
+ fi
+ AC_MSG_RESULT($complCFLAGS)
+
+ WARN_CFLAGS="$warning_flags $complCFLAGS"
+ AC_SUBST(WARN_CFLAGS)
+])
+
+dnl For C++, do basically the same thing.
+
+AC_DEFUN([MATE_CXX_WARNINGS],[
+ AC_ARG_ENABLE(cxx-warnings,
+ AC_HELP_STRING([[email protected]<:@no/minimum/[email protected]:>@]
+ [Turn on compiler warnings.]),,
+ [enable_cxx_warnings="m4_default([$1],[minimum])"])
+
+ AC_MSG_CHECKING(what warning flags to pass to the C++ compiler)
+ warnCXXFLAGS=
+ if test "x$GXX" != xyes; then
+ enable_cxx_warnings=no
+ fi
+ if test "x$enable_cxx_warnings" != "xno"; then
+ if test "x$GXX" = "xyes"; then
+ case " $CXXFLAGS " in
+ *[\ \ ]-Wall[\ \ ]*) ;;
+ *) warnCXXFLAGS="-Wall -Wno-unused" ;;
+ esac
+
+ ## -W is not all that useful. And it cannot be controlled
+ ## with individual -Wno-xxx flags, unlike -Wall
+ if test "x$enable_cxx_warnings" = "xyes"; then
+ warnCXXFLAGS="$warnCXXFLAGS -Wshadow -Woverloaded-virtual"
+ fi
+ fi
+ fi
+ AC_MSG_RESULT($warnCXXFLAGS)
+
+ AC_ARG_ENABLE(iso-cxx,
+ AC_HELP_STRING([--enable-iso-cxx],
+ [Try to warn if code is not ISO C++ ]),,
+ [enable_iso_cxx=no])
+
+ AC_MSG_CHECKING(what language compliance flags to pass to the C++ compiler)
+ complCXXFLAGS=
+ if test "x$enable_iso_cxx" != "xno"; then
+ if test "x$GXX" = "xyes"; then
+ case " $CXXFLAGS " in
+ *[\ \ ]-ansi[\ \ ]*) ;;
+ *) complCXXFLAGS="$complCXXFLAGS -ansi" ;;
+ esac
+
+ case " $CXXFLAGS " in
+ *[\ \ ]-pedantic[\ \ ]*) ;;
+ *) complCXXFLAGS="$complCXXFLAGS -pedantic" ;;
+ esac
+ fi
+ fi
+ AC_MSG_RESULT($complCXXFLAGS)
+
+ WARN_CXXFLAGS="$CXXFLAGS $warnCXXFLAGS $complCXXFLAGS"
+ AC_SUBST(WARN_CXXFLAGS)
+])
+
+# nls.m4 serial 5 (gettext-0.18)
+dnl Copyright (C) 1995-2003, 2005-2006, 2008-2010 Free Software Foundation,
+dnl Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+dnl Authors:
+dnl Ulrich Drepper <[email protected]>, 1995-2000.
+dnl Bruno Haible <[email protected]>, 2000-2003.
+
+AC_PREREQ([2.50])
+
+AC_DEFUN([AM_NLS],
+[
+ AC_MSG_CHECKING([whether NLS is requested])
+ dnl Default is enabled NLS
+ AC_ARG_ENABLE([nls],
+ [ --disable-nls do not use Native Language Support],
+ USE_NLS=$enableval, USE_NLS=yes)
+ AC_MSG_RESULT([$USE_NLS])
+ AC_SUBST([USE_NLS])
+])
+
+# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
+# serial 1 (pkg-config-0.24)
+#
+# Copyright © 2004 Scott James Remnant <[email protected]>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
+# ----------------------------------
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
+m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
+AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
+AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=m4_default([$1], [0.9.0])
+ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ PKG_CONFIG=""
+ fi
+fi[]dnl
+])# PKG_PROG_PKG_CONFIG
+
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# Check to see whether a particular set of modules exists. Similar
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
+#
+# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+# only at the first occurence in configure.ac, so if the first place
+# it's called might be skipped (such as if it is within an "if", you
+# have to call PKG_CHECK_EXISTS manually
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+ m4_default([$2], [:])
+m4_ifvaln([$3], [else
+ $3])dnl
+fi])
+
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+# ---------------------------------------------
+m4_define([_PKG_CONFIG],
+[if test -n "$$1"; then
+ pkg_cv_[]$1="$$1"
+ elif test -n "$PKG_CONFIG"; then
+ PKG_CHECK_EXISTS([$3],
+ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes ],
+ [pkg_failed=yes])
+ else
+ pkg_failed=untried
+fi[]dnl
+])# _PKG_CONFIG
+
+# _PKG_SHORT_ERRORS_SUPPORTED
+# -----------------------------
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi[]dnl
+])# _PKG_SHORT_ERRORS_SUPPORTED
+
+
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+# [ACTION-IF-NOT-FOUND])
+#
+#
+# Note that if there is a possibility the first call to
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+#
+#
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+ AC_MSG_RESULT([no])
+ _PKG_SHORT_ERRORS_SUPPORTED
+ if test $_pkg_short_errors_supported = yes; then
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
+ else
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+ m4_default([$4], [AC_MSG_ERROR(
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT])[]dnl
+ ])
+elif test $pkg_failed = untried; then
+ AC_MSG_RESULT([no])
+ m4_default([$4], [AC_MSG_FAILURE(
+[The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
+ ])
+else
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+ AC_MSG_RESULT([yes])
+ $3
+fi[]dnl
+])# PKG_CHECK_MODULES
+
+# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.11'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version. Point them to the right macro.
+m4_if([$1], [1.11.1], [],
+ [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too. Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.11.1])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# AM_AUX_DIR_EXPAND -*- Autoconf -*-
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is `.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 9
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ(2.52)dnl
+ ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 10
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
+ [$1], CXX, [depcc="$CXX" am_compiler_list=],
+ [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], UPC, [depcc="$UPC" am_compiler_list=],
+ [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ am__universal=false
+ m4_case([$1], [CC],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac],
+ [CXX],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac])
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvisualcpp | msvcmsys)
+ # This compiler won't grok `-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE(dependency-tracking,
+[ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+#serial 5
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+ # Autoconf 2.62 quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ case $CONFIG_FILES in
+ *\'*) eval set x "$CONFIG_FILES" ;;
+ *) set x $CONFIG_FILES ;;
+ esac
+ shift
+ for mf
+ do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`AS_DIRNAME("$mf")`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`AS_DIRNAME(["$file"])`
+ AS_MKDIR_P([$dirpart/$fdir])
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+ done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled. FIXME. This creates each `.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 8
+
+# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS.
+AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS([email protected])])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2008, 2009 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 16
+
+# This macro actually does too much. Some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.62])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,,
+ [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AM_PROG_MKDIR_P])dnl
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES(CC)],
+ [define([AC_PROG_CC],
+ defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES(CXX)],
+ [define([AC_PROG_CXX],
+ defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+ [_AM_DEPENDENCIES(OBJC)],
+ [define([AC_PROG_OBJC],
+ defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl
+])
+_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl
+dnl The `parallel-tests' driver may need to know about EXEEXT, so add the
+dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro
+dnl is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+ [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+])
+
+dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+AC_SUBST(install_sh)])
+
+# Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot. For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
+# From Jim Meyering
+
+# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_MAINTAINER_MODE([DEFAULT-MODE])
+# ----------------------------------
+# Control maintainer-specific portions of Makefiles.
+# Default is to disable them, unless `enable' is passed literally.
+# For symmetry, `disable' may be passed as well. Anyway, the user
+# can override the default with the --enable/--disable switch.
+AC_DEFUN([AM_MAINTAINER_MODE],
+[m4_case(m4_default([$1], [disable]),
+ [enable], [m4_define([am_maintainer_other], [disable])],
+ [disable], [m4_define([am_maintainer_other], [enable])],
+ [m4_define([am_maintainer_other], [enable])
+ m4_warn([syntax], [unexpected argument to [email protected]&[email protected]_MAINTAINER_MODE: $1])])
+AC_MSG_CHECKING([whether to am_maintainer_other maintainer-specific portions of Makefiles])
+ dnl maintainer-mode's default is 'disable' unless 'enable' is passed
+ AC_ARG_ENABLE([maintainer-mode],
+[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer],
+ [USE_MAINTAINER_MODE=$enableval],
+ [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
+ AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+ AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
+ MAINT=$MAINTAINER_MODE_TRUE
+ AC_SUBST([MAINT])dnl
+]
+)
+
+AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from `make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+ am__include=include
+ am__quote=
+ _am_result=GNU
+ ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ case `$am_make -s -f confmf 2> /dev/null` in #(
+ *the\ am__doit\ target*)
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ ;;
+ esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 6
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_MKDIR_P
+# ---------------
+# Check for `mkdir -p'.
+AC_DEFUN([AM_PROG_MKDIR_P],
+[AC_PREREQ([2.60])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P,
+dnl while keeping a definition of mkdir_p for backward compatibility.
+dnl @[email protected] is magic: AC_OUTPUT adjusts its value for each Makefile.
+dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of
+dnl Makefile.ins that do not define MKDIR_P, so we do our own
+dnl adjustment using top_builddir (which is defined more often than
+dnl MKDIR_P).
+AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl
+case $mkdir_p in
+ [[\\/$]]* | ?:[[\\/]]*) ;;
+ */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# ------------------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ----------------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+# ---------------------------------------------------------------------------
+# Adds support for distributing Python modules and packages. To
+# install modules, copy them to $(pythondir), using the python_PYTHON
+# automake variable. To install a package with the same name as the
+# automake package, install to $(pkgpythondir), or use the
+# pkgpython_PYTHON automake variable.
+#
+# The variables $(pyexecdir) and $(pkgpyexecdir) are provided as
+# locations to install python extension modules (shared libraries).
+# Another macro is required to find the appropriate flags to compile
+# extension modules.
+#
+# If your package is configured with a different prefix to python,
+# users will have to add the install directory to the PYTHONPATH
+# environment variable, or create a .pth file (see the python
+# documentation for details).
+#
+# If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will
+# cause an error if the version of python installed on the system
+# doesn't meet the requirement. MINIMUM-VERSION should consist of
+# numbers and dots only.
+AC_DEFUN([AM_PATH_PYTHON],
+ [
+ dnl Find a Python interpreter. Python versions prior to 2.0 are not
+ dnl supported. (2.0 was released on October 16, 2000).
+ m4_define_default([_AM_PYTHON_INTERPRETER_LIST],
+ [python python2 python3 python3.0 python2.5 python2.4 python2.3 python2.2 dnl
+python2.1 python2.0])
+
+ m4_if([$1],[],[
+ dnl No version check is needed.
+ # Find any Python interpreter.
+ if test -z "$PYTHON"; then
+ AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :)
+ fi
+ am_display_PYTHON=python
+ ], [
+ dnl A version check is needed.
+ if test -n "$PYTHON"; then
+ # If the user set $PYTHON, use it and don't search something else.
+ AC_MSG_CHECKING([whether $PYTHON version >= $1])
+ AM_PYTHON_CHECK_VERSION([$PYTHON], [$1],
+ [AC_MSG_RESULT(yes)],
+ [AC_MSG_ERROR(too old)])
+ am_display_PYTHON=$PYTHON
+ else
+ # Otherwise, try each interpreter until we find one that satisfies
+ # VERSION.
+ AC_CACHE_CHECK([for a Python interpreter with version >= $1],
+ [am_cv_pathless_PYTHON],[
+ for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do
+ test "$am_cv_pathless_PYTHON" = none && break
+ AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break])
+ done])
+ # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON.
+ if test "$am_cv_pathless_PYTHON" = none; then
+ PYTHON=:
+ else
+ AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON])
+ fi
+ am_display_PYTHON=$am_cv_pathless_PYTHON
+ fi
+ ])
+
+ if test "$PYTHON" = :; then
+ dnl Run any user-specified action, or abort.
+ m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])])
+ else
+
+ dnl Query Python for its version number. Getting [:3] seems to be
+ dnl the best way to do this; it's what "site.py" does in the standard
+ dnl library.
+
+ AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
+ [am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`])
+ AC_SUBST([PYTHON_VERSION], [$am_cv_python_version])
+
+ dnl Use the values of $prefix and $exec_prefix for the corresponding
+ dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made
+ dnl distinct variables so they can be overridden if need be. However,
+ dnl general consensus is that you shouldn't need this ability.
+
+ AC_SUBST([PYTHON_PREFIX], ['${prefix}'])
+ AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}'])
+
+ dnl At times (like when building shared libraries) you may want
+ dnl to know which OS platform Python thinks this is.
+
+ AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform],
+ [am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`])
+ AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform])
+
+
+ dnl Set up 4 directories:
+
+ dnl pythondir -- where to install python scripts. This is the
+ dnl site-packages directory, not the python standard library
+ dnl directory like in previous automake betas. This behavior
+ dnl is more consistent with lispdir.m4 for example.
+ dnl Query distutils for this directory. distutils does not exist in
+ dnl Python 1.5, so we fall back to the hardcoded directory if it
+ dnl doesn't work.
+ AC_CACHE_CHECK([for $am_display_PYTHON script directory],
+ [am_cv_python_pythondir],
+ [if test "x$prefix" = xNONE
+ then
+ am_py_prefix=$ac_default_prefix
+ else
+ am_py_prefix=$prefix
+ fi
+ am_cv_python_pythondir=`$PYTHON -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_lib(0,0,prefix='$am_py_prefix'))" 2>/dev/null ||
+ echo "$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages"`
+ case $am_cv_python_pythondir in
+ $am_py_prefix*)
+ am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
+ am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"`
+ ;;
+ *)
+ case $am_py_prefix in
+ /usr|/System*) ;;
+ *)
+ am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages
+ ;;
+ esac
+ ;;
+ esac
+ ])
+ AC_SUBST([pythondir], [$am_cv_python_pythondir])
+
+ dnl pkgpythondir -- $PACKAGE directory under pythondir. Was
+ dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
+ dnl more consistent with the rest of automake.
+
+ AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE])
+
+ dnl pyexecdir -- directory for installing python extension modules
+ dnl (shared libraries)
+ dnl Query distutils for this directory. distutils does not exist in
+ dnl Python 1.5, so we fall back to the hardcoded directory if it
+ dnl doesn't work.
+ AC_CACHE_CHECK([for $am_display_PYTHON extension module directory],
+ [am_cv_python_pyexecdir],
+ [if test "x$exec_prefix" = xNONE
+ then
+ am_py_exec_prefix=$am_py_prefix
+ else
+ am_py_exec_prefix=$exec_prefix
+ fi
+ am_cv_python_pyexecdir=`$PYTHON -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_lib(1,0,prefix='$am_py_exec_prefix'))" 2>/dev/null ||
+ echo "$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages"`
+ case $am_cv_python_pyexecdir in
+ $am_py_exec_prefix*)
+ am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
+ am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"`
+ ;;
+ *)
+ case $am_py_exec_prefix in
+ /usr|/System*) ;;
+ *)
+ am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages
+ ;;
+ esac
+ ;;
+ esac
+ ])
+ AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir])
+
+ dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE)
+
+ AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE])
+
+ dnl Run any user-specified action.
+ $2
+ fi
+
+])
+
+
+# AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
+# ---------------------------------------------------------------------------
+# Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION.
+# Run ACTION-IF-FALSE otherwise.
+# This test uses sys.hexversion instead of the string equivalent (first
+# word of sys.version), in order to cope with versions such as 2.2c1.
+# This supports Python 2.0 or higher. (2.0 was released on October 16, 2000).
+AC_DEFUN([AM_PYTHON_CHECK_VERSION],
+ [prog="import sys
+# split strings by '.' and convert to numeric. Append some zeros
+# because we need at least 4 digits for the hex conversion.
+# map returns an iterator in Python 3.0 and a list in 2.x
+minver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]]
+minverhex = 0
+# xrange is not present in Python 3.0 and range returns an iterator
+for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]]
+sys.exit(sys.hexversion < minverhex)"
+ AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_RUN_LOG(COMMAND)
+# -------------------
+# Run COMMAND, save the exit status in ac_status, and log it.
+# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
+AC_DEFUN([AM_RUN_LOG],
+[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
+ ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ (exit $ac_status); }])
+
+# Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[[\\\"\#\$\&\'\`$am_lf]]*)
+ AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+ *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*)
+ AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);;
+esac
+
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+alias in your environment])
+ fi
+
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT(yes)])
+
+# Copyright (C) 2009 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 1
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# (`yes' being less verbose, `no' or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules],
+[ --enable-silent-rules less verbose build output (undo: `make V=1')
+ --disable-silent-rules verbose build output (undo: `make V=0')])
+case $enable_silent_rules in
+yes) AM_DEFAULT_VERBOSITY=0;;
+no) AM_DEFAULT_VERBOSITY=1;;
+*) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor `install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in `make install-strip', and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006, 2008 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @[email protected] in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([email protected])])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of `v7', `ustar', or `pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.
+AM_MISSING_PROG([AMTAR], [tar])
+m4_if([$1], [v7],
+ [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
+ [m4_case([$1], [ustar],, [pax],,
+ [m4_fatal([Unknown tar format])])
+AC_MSG_CHECKING([how to create a $1 tar archive])
+# Loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+_am_tools=${am_cv_prog_tar_$1-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+for _am_tool in $_am_tools
+do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar;
+ do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+done
+rm -rf conftest.dir
+
+AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([m4/intltool.m4])
+m4_include([m4/libtool.m4])
+m4_include([m4/ltoptions.m4])
+m4_include([m4/ltsugar.m4])
+m4_include([m4/ltversion.m4])
+m4_include([m4/lt~obsolete.m4])
+m4_include([m4/python.m4])
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..688ffa7
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+PKG_NAME="mate-menus"
+
+(test -f $srcdir/configure.ac) || {
+ echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
+ echo " top-level $PKG_NAME directory"
+ exit 1
+}
+
+which mate-autogen.sh || {
+ echo "You need to install mate-common from the MATE Git"
+ exit 1
+}
+
+REQUIRED_AUTOMAKE_VERSION=1.9
+USE_MATE2_MACROS=1
+USE_COMMON_DOC_BUILD=yes
+
+. mate-autogen.sh
+
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..834846d
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,83 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* always defined to indicate that i18n is enabled */
+#undef ENABLE_NLS
+
+/* Name of default gettext domain */
+#undef GETTEXT_PACKAGE
+
+/* Define to 1 if you have the `bind_textdomain_codeset' function. */
+#undef HAVE_BIND_TEXTDOMAIN_CODESET
+
+/* Define to 1 if you have the `dcgettext' function. */
+#undef HAVE_DCGETTEXT
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define if the GNU gettext() function is already present or preinstalled. */
+#undef HAVE_GETTEXT
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define if your <locale.h> file defines LC_MESSAGES. */
+#undef HAVE_LC_MESSAGES
+
+/* Define to 1 if you have the <locale.h> header file. */
+#undef HAVE_LOCALE_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#undef LT_OBJDIR
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
diff --git a/config.sub b/config.sub
new file mode 100755
index 0000000..2a55a50
--- /dev/null
+++ b/config.sub
@@ -0,0 +1,1705 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+# Free Software Foundation, Inc.
+
+timestamp='2009-11-20'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file 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.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <[email protected]>. Submit a context
+# diff and a properly formatted GNU ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <[email protected]>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+ kopensolaris*-gnu* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray | -microblaze)
+ os=
+ basic_machine=$1
+ ;;
+ -bluegene*)
+ os=-cnk
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+ | bfin \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fido | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | lm32 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | mcore | mep | metag \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nios | nios2 \
+ | ns16k | ns32k \
+ | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | rx \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu | strongarm \
+ | tahoe | thumb | tic4x | tic80 | tron \
+ | ubicom32 \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+ | z8k | z80)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12 | picochip)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | lm32-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64octeon-* | mips64octeonel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64r5900-* | mips64r5900el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nios-* | nios2-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* | rx-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \
+ | tron-* \
+ | ubicom32-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+ | xstormy16-* | xtensa*-* \
+ | ymp-* \
+ | z8k-* | z80-*)
+ ;;
+ # Recognize the basic CPU types without company name, with glob match.
+ xtensa*)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ os=-aros
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=-linux
+ ;;
+ blackfin-*)
+ basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ bluegene*)
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16)
+ basic_machine=cr16-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ os=-dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ os=-linux
+ ;;
+ m68knommu-*)
+ basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ microblaze)
+ basic_machine=microblaze-xilinx
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ os=-mingw32ce
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ os=-linux
+ ;;
+ parisc-*)
+ basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tic55x | c55x*)
+ basic_machine=tic55x-unknown
+ os=-coff
+ ;;
+ tic6x | c6x*)
+ basic_machine=tic6x-unknown
+ os=-coff
+ ;;
+ tile*)
+ basic_machine=tile-unknown
+ os=-linux-gnu
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ z80-*-coff)
+ basic_machine=z80-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -auroraux)
+ os=-auroraux
+ ;;
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+ | -sym* | -kopensolaris* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* | -aros* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* | -cegcc* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -dicos*)
+ os=-dicos
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mep-*)
+ os=-elf
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -cnk*|-aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..8460876
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,171 @@
+AC_PREREQ(2.62)
+
+AC_INIT([mate-menus], [2011.11.16], [https://github.com/perberos/mate-desktop-environment])
+AC_CONFIG_SRCDIR(libmenu/matemenu-tree.h)
+
+AM_INIT_AUTOMAKE([1.9 foreign no-dist-gzip dist-bzip2])
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+AC_CONFIG_MACRO_DIR([m4])
+AM_CONFIG_HEADER(config.h)
+
+AM_MAINTAINER_MODE
+MATE_MAINTAINER_MODE_DEFINES
+
+# Before making a release, the LT_VERSION string should be modified.
+# The string is of the form C:R:A.
+# - If interfaces have been changed or added, but binary compatibility has
+# been preserved, change to C+1:0:A+1
+# - If binary compatibility has been broken (eg removed or changed interfaces)
+# change to C+1:0:0
+# - If the interface is the same as the previous version, change to C:R+1:A
+
+LIB_MENU_LT_VERSION=6:9:4
+AC_SUBST(LIB_MENU_LT_VERSION)
+
+GETTEXT_PACKAGE=mate-menus
+AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Name of default gettext domain])
+AC_SUBST(GETTEXT_PACKAGE)
+
+AM_GLIB_GNU_GETTEXT
+
+IT_PROG_INTLTOOL([0.40.0])
+
+AC_ISC_POSIX
+AC_PROG_CC
+AC_STDC_HEADERS
+AC_ARG_PROGRAM
+AC_LIBTOOL_WIN32_DLL
+AM_PROG_LIBTOOL
+
+dnl make sure we keep ACLOCAL_FLAGS around for maintainer builds to work
+AC_SUBST(ACLOCAL_AMFLAGS, "$ACLOCAL_FLAGS")
+
+PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.6.0 gio-2.0 >= 2.15.2)
+AC_SUBST(GLIB_CFLAGS)
+AC_SUBST(GLIB_LIBS)
+
+MATE_COMPILE_WARNINGS(yes)
+
+AC_ARG_ENABLE(deprecation_flags,
+ [AC_HELP_STRING([--enable-deprecation-flags],
+ [use *_DISABLE_DEPRECATED flags @<:@[email protected]:>@])],,
+ [enable_deprecation_flags=no])
+
+if test "x$enable_deprecation_flags" = "xyes"; then
+ DISABLE_DEPRECATED_CFLAGS=$DISABLE_DEPRECATED
+ AC_SUBST(DISABLE_DEPRECATED_CFLAGS)
+fi
+
+dnl --enable-debug=(yes|minimum|no)
+AC_ARG_ENABLE(debug,
+ [AC_HELP_STRING([--enable-debug],
+ [turn on debugging @<:@[email protected]:>@])],,
+ [enable_debug=minimum])
+if test "$enable_debug" = "yes"; then
+ DEBUG_CFLAGS="-DG_ENABLE_DEBUG"
+else
+ if test "x$enable_debug" = "xno"; then
+ DEBUG_CFLAGS="-DG_DISABLE_ASSERT -DG_DISABLE_CHECKS"
+ else
+ DEBUG_CFLAGS=""
+ # make sure we have the right string for the configure summary
+ enable_debug="minimum"
+ fi
+fi
+AC_SUBST(DEBUG_CFLAGS)
+
+AC_ARG_ENABLE(python,
+ [AC_HELP_STRING([--enable-python],
+ [build python bindings @<:@[email protected]:>@])],
+ [enable_deprecations=$enableval],
+ [enable_deprecations=auto])
+
+# Detect if we can build Python bindings (need python and python headers)
+if test "x$enable_python" = "xno" ; then
+ have_python=no
+else
+ AC_MSG_NOTICE([Checking to see if we can build Python bindings])
+ have_python=no
+ AM_PATH_PYTHON(2.3)
+
+ if test "x$PYTHON" = "x" ; then
+ AC_MSG_WARN([Python not found])
+ else
+ AM_CHECK_PYTHON_HEADERS(have_python_headers=yes, have_python_headers=no)
+ if test "x$have_python_headers" = "xyes" ; then
+ have_python=yes
+ fi
+ fi
+
+ if test "x$have_python" = "xno" ; then
+ if test "x$enable_python" = "xyes" ; then
+ AC_MSG_ERROR([Building python explicitly requested, but can't build python bindings])
+ else
+ AC_MSG_WARN([Couldn't find the Python headers, not building Python bindings])
+ fi
+ fi
+fi
+
+AM_CONDITIONAL(HAVE_PYTHON, test x$have_python = xyes)
+
+# Because of the way Python implements polymorphism, we get the following warning:
+# "warning: dereferencing type-punned pointer will break strict-aliasing rules"
+# -fno-strict-aliasing (as used in Python build) switches warnings off
+NO_STRICT_ALIASING_CFLAGS=""
+if test "x$GCC" = "xyes" ; then
+ AC_MSG_CHECKING(whether $CC accepts -fno-strict-aliasing)
+ ac_save_cc="$CC"
+ CC="$CC -fno-strict-aliasing"
+ AC_TRY_RUN([int main() { return 0; }],
+ ac_cv_no_strict_aliasing_ok=yes,
+ ac_cv_no_strict_aliasing_ok=no,
+ ac_cv_no_strict_aliasing_ok=no)
+ CC="$ac_save_cc"
+ AC_MSG_RESULT($ac_cv_no_strict_aliasing_ok)
+ if test "x$ac_cv_no_strict_aliasing_ok" = "xyes" ; then
+ NO_STRICT_ALIASING_CFLAGS="-fno-strict-aliasing"
+ fi
+fi
+AC_SUBST(NO_STRICT_ALIASING_CFLAGS)
+
+GOBJECT_INTROSPECTION_CHECK([0.6.7])
+
+AC_OUTPUT([
+Makefile
+libmenu/Makefile
+libmenu/libmate-menu.pc
+libmenu/libmate-menu-uninstalled.pc
+layout/Makefile
+desktop-directories/Makefile
+util/Makefile
+python/Makefile
+po/Makefile.in
+])
+
+dnl ---------------------------------------------------------------------------
+dnl - Show summary
+dnl ---------------------------------------------------------------------------
+
+echo "
+ mate-menus $VERSION
+ `echo mate-menus $VERSION | sed "s/./=/g"`
+
+ prefix: ${prefix}
+ exec_prefix: ${exec_prefix}
+ libdir: ${libdir}
+ bindir: ${bindir}
+ sbindir: ${sbindir}
+ sysconfdir: ${sysconfdir}
+ localstatedir: ${localstatedir}
+ datadir: ${datadir}
+ source code location: ${srcdir}
+ compiler: ${CC}
+ cflags: ${CFLAGS}
+ Maintainer mode: ${USE_MAINTAINER_MODE}
+ Use *_DISABLE_DEPRECATED: ${enable_deprecation_flags}
+
+ Turn on debugging: ${enable_debug}
+ Build python bindings: ${have_python}
+ Build introspection support: ${found_introspection}
+
+"
diff --git a/depcomp b/depcomp
new file mode 100755
index 0000000..df8eea7
--- /dev/null
+++ b/depcomp
@@ -0,0 +1,630 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2009-04-28.21; # UTC
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 Free
+# Software Foundation, Inc.
+
+# 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, 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, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <[email protected]>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+ depmode Dependency tracking mode.
+ source Source file read by `PROGRAMS ARGS'.
+ object Object file output by `PROGRAMS ARGS'.
+ DEPDIR directory where to store dependencies.
+ depfile Dependency file to output.
+ tmpdepfile Temporary file to use when outputing dependencies.
+ libtool Whether libtool is used (yes/no).
+
+Report bugs to <[email protected]>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "depcomp $scriptversion"
+ exit $?
+ ;;
+esac
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+ # This is just like msvisualcpp but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u="sed s,\\\\\\\\,/,g"
+ depmode=msvisualcpp
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am. Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+ for arg
+ do
+ case $arg in
+ -c) set fnord "[email protected]" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+ *) set fnord "[email protected]" "$arg" ;;
+ esac
+ shift # fnord
+ shift # $arg
+ done
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "[email protected]" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+ tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'. On the theory
+## that the space means something, we add a space to the output as
+## well.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "[email protected]" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "[email protected]" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like `#:fec' to the end of the
+ # dependency line.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+ tr '
+' ' ' >> "$depfile"
+ echo >> "$depfile"
+
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts `$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$base.u
+ tmpdepfile3=$dir.libs/$base.u
+ else
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$dir$base.u
+ tmpdepfile3=$dir$base.u
+ fi
+ stat=$?
+
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ # Each line is of the form `foo.o: dependent.h'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a tab and a space in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+icc)
+ # Intel's C compiler understands `-MD -MF file'. However on
+ # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+ # ICC 7.0 will fill foo.d with something like
+ # foo.o: sub/foo.c
+ # foo.o: sub/foo.h
+ # which is wrong. We want:
+ # sub/foo.o: sub/foo.c
+ # sub/foo.o: sub/foo.h
+ # sub/foo.c:
+ # sub/foo.h:
+ # ICC 7.1 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using \ :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+
+ "[email protected]" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
+ sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp2)
+ # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+ # compilers, which have integrated preprocessors. The correct option
+ # to use with these is +Maked; it writes dependencies to a file named
+ # 'foo.d', which lands next to the object file, wherever that
+ # happens to be.
+ # Much of this is similar to the tru64 case; see comments there.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir.libs/$base.d
+ "[email protected]" -Wc,+Maked
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
+ # Add `dependent.h:' lines.
+ sed -ne '2,${
+ s/^ *//
+ s/ \\*$//
+ s/$/:/
+ p
+ }' "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile" "$tmpdepfile2"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in `foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+ if test "$libtool" = yes; then
+ # With Tru64 cc, shared objects can also be used to make a
+ # static library. This mechanism is used in libtool 1.4 series to
+ # handle both shared and static libraries in a single compilation.
+ # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
+ #
+ # With libtool 1.5 this exception was removed, and libtool now
+ # generates 2 separate objects for the 2 libraries. These two
+ # compilations output dependencies in $dir.libs/$base.o.d and
+ # in $dir$base.o.d. We have to check for both files, because
+ # one of the two compilations can be disabled. We should prefer
+ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+ # automatically cleaned when .libs/ is deleted, while ignoring
+ # the former would cause a distcleancheck panic.
+ tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4
+ tmpdepfile2=$dir$base.o.d # libtool 1.5
+ tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5
+ tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504
+ "[email protected]" -Wc,-MD
+ else
+ tmpdepfile1=$dir$base.o.d
+ tmpdepfile2=$dir$base.d
+ tmpdepfile3=$dir$base.d
+ tmpdepfile4=$dir$base.d
+ fi
+
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a tab and a space in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "[email protected]" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "[email protected]" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for `:'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+ "[email protected]" $dashmflag |
+ sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "[email protected]" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no eat=no
+ for arg
+ do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ if test $eat = yes; then
+ eat=no
+ continue
+ fi
+ case "$arg" in
+ -D*|-I*)
+ set fnord "[email protected]" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -arch)
+ eat=yes ;;
+ -*|$object)
+ ;;
+ *)
+ set fnord "[email protected]" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix=`echo "$object" | sed 's/^.*\././'`
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "[email protected]"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "[email protected]" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "[email protected]" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+ sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "[email protected]" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "[email protected]"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "[email protected]" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "[email protected]" -E 2>/dev/null |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
+ echo " " >> "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvcmsys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+none)
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/desktop-directories/Makefile.am b/desktop-directories/Makefile.am
new file mode 100644
index 0000000..4bcc63c
--- /dev/null
+++ b/desktop-directories/Makefile.am
@@ -0,0 +1,37 @@
+directorydir = $(datadir)/mate/desktop-directories
+
+# Should be moved to mate-control-center:
+directory_in_controlcenterfiles = \
+ mate-hardware.directory.in \
+ mate-internet-and-network.directory.in \
+ mate-look-and-feel.directory.in \
+ mate-personal.directory.in \
+ mate-system.directory.in
+
+directory_in_files = \
+ mate-audio-video.directory.in \
+ mate-development.directory.in \
+ mate-education.directory.in \
+ mate-game.directory.in \
+ mate-graphics.directory.in \
+ mate-network.directory.in \
+ mate-office.directory.in \
+ mate-settings.directory.in \
+ mate-settings-system.directory.in \
+ mate-system-tools.directory.in \
+ mate-utility.directory.in \
+ mate-utility-accessibility.directory.in \
+ mate-other.directory.in \
+ mate-menu-applications.directory.in \
+ mate-menu-system.directory.in \
+ $(directory_in_controlcenterfiles)
+
+directory_DATA = $(directory_in_files:.directory.in=.directory)
+
+
+EXTRA_DIST= $(directory_in_files)
+
+DISTCLEANFILES = $(directory_DATA)
+
+-include $(top_srcdir)/git.mk
diff --git a/desktop-directories/mate-audio-video.directory.in b/desktop-directories/mate-audio-video.directory.in
new file mode 100644
index 0000000..966fda1
--- /dev/null
+++ b/desktop-directories/mate-audio-video.directory.in
@@ -0,0 +1,5 @@
+[Desktop Entry]
+_Name=Sound & Video
+_Comment=Multimedia menu
+Icon=applications-multimedia
+Type=Directory
diff --git a/desktop-directories/mate-development.directory.in b/desktop-directories/mate-development.directory.in
new file mode 100644
index 0000000..d7e9de9
--- /dev/null
+++ b/desktop-directories/mate-development.directory.in
@@ -0,0 +1,5 @@
+[Desktop Entry]
+_Name=Programming
+_Comment=Tools for software development
+Icon=applications-development
+Type=Directory
diff --git a/desktop-directories/mate-education.directory.in b/desktop-directories/mate-education.directory.in
new file mode 100644
index 0000000..689168a
--- /dev/null
+++ b/desktop-directories/mate-education.directory.in
@@ -0,0 +1,4 @@
+[Desktop Entry]
+_Name=Education
+Icon=applications-science
+Type=Directory
diff --git a/desktop-directories/mate-game.directory.in b/desktop-directories/mate-game.directory.in
new file mode 100644
index 0000000..610bbd8
--- /dev/null
+++ b/desktop-directories/mate-game.directory.in
@@ -0,0 +1,5 @@
+[Desktop Entry]
+_Name=Games
+_Comment=Games and amusements
+Icon=applications-games
+Type=Directory
diff --git a/desktop-directories/mate-graphics.directory.in b/desktop-directories/mate-graphics.directory.in
new file mode 100644
index 0000000..d2b4bb6
--- /dev/null
+++ b/desktop-directories/mate-graphics.directory.in
@@ -0,0 +1,5 @@
+[Desktop Entry]
+_Name=Graphics
+_Comment=Graphics applications
+Icon=applications-graphics
+Type=Directory
diff --git a/desktop-directories/mate-hardware.directory.in b/desktop-directories/mate-hardware.directory.in
new file mode 100644
index 0000000..e80430e
--- /dev/null
+++ b/desktop-directories/mate-hardware.directory.in
@@ -0,0 +1,5 @@
+[Desktop Entry]
+_Name=Hardware
+_Comment=Settings for several hardware devices
+Icon=preferences-desktop-peripherals
+Type=Directory
diff --git a/desktop-directories/mate-internet-and-network.directory.in b/desktop-directories/mate-internet-and-network.directory.in
new file mode 100644
index 0000000..a37586f
--- /dev/null
+++ b/desktop-directories/mate-internet-and-network.directory.in
@@ -0,0 +1,5 @@
+[Desktop Entry]
+_Name=Internet and Network
+_Comment=Network-related settings
+Icon=preferences-system-network
+Type=Directory
diff --git a/desktop-directories/mate-look-and-feel.directory.in b/desktop-directories/mate-look-and-feel.directory.in
new file mode 100644
index 0000000..ad8b187
--- /dev/null
+++ b/desktop-directories/mate-look-and-feel.directory.in
@@ -0,0 +1,5 @@
+[Desktop Entry]
+_Name=Look and Feel
+_Comment=Settings controlling the desktop appearance and behavior
+Icon=preferences-desktop
+Type=Directory
diff --git a/desktop-directories/mate-menu-applications.directory.in b/desktop-directories/mate-menu-applications.directory.in
new file mode 100644
index 0000000..d4106cb
--- /dev/null
+++ b/desktop-directories/mate-menu-applications.directory.in
@@ -0,0 +1,5 @@
+[Desktop Entry]
+_Name=Applications
+_Comment=Applications
+Icon=applications-other
+Type=Directory
diff --git a/desktop-directories/mate-menu-system.directory.in b/desktop-directories/mate-menu-system.directory.in
new file mode 100644
index 0000000..643f042
--- /dev/null
+++ b/desktop-directories/mate-menu-system.directory.in
@@ -0,0 +1,5 @@
+[Desktop Entry]
+_Name=System
+_Comment=Personal preferences and administration settings
+Icon=preferences-other
+Type=Directory
diff --git a/desktop-directories/mate-network.directory.in b/desktop-directories/mate-network.directory.in
new file mode 100644
index 0000000..bc88bee
--- /dev/null
+++ b/desktop-directories/mate-network.directory.in
@@ -0,0 +1,5 @@
+[Desktop Entry]
+_Name=Internet
+_Comment=Programs for Internet access such as web and email
+Icon=applications-internet
+Type=Directory
diff --git a/desktop-directories/mate-office.directory.in b/desktop-directories/mate-office.directory.in
new file mode 100644
index 0000000..d6c8d9e
--- /dev/null
+++ b/desktop-directories/mate-office.directory.in
@@ -0,0 +1,5 @@
+[Desktop Entry]
+_Name=Office
+_Comment=Office Applications
+Icon=applications-office
+Type=Directory
diff --git a/desktop-directories/mate-other.directory.in b/desktop-directories/mate-other.directory.in
new file mode 100644
index 0000000..898d406
--- /dev/null
+++ b/desktop-directories/mate-other.directory.in
@@ -0,0 +1,5 @@
+[Desktop Entry]
+_Name=Other
+_Comment=Applications that did not fit in other categories
+Icon=applications-other
+Type=Directory
diff --git a/desktop-directories/mate-personal.directory.in b/desktop-directories/mate-personal.directory.in
new file mode 100644
index 0000000..9f11595
--- /dev/null
+++ b/desktop-directories/mate-personal.directory.in
@@ -0,0 +1,6 @@
+[Desktop Entry]
+# Translators: this is Personal as in "Personal settings"
+_Name=Personal
+_Comment=Personal settings
+Icon=preferences-desktop-personal
+Type=Directory
diff --git a/desktop-directories/mate-settings-system.directory.in b/desktop-directories/mate-settings-system.directory.in
new file mode 100644
index 0000000..5dbb708
--- /dev/null
+++ b/desktop-directories/mate-settings-system.directory.in
@@ -0,0 +1,5 @@
+[Desktop Entry]
+Type=Directory
+_Name=Administration
+_Comment=Change system-wide settings (affects all users)
+Icon=preferences-system
diff --git a/desktop-directories/mate-settings.directory.in b/desktop-directories/mate-settings.directory.in
new file mode 100644
index 0000000..7c663a6
--- /dev/null
+++ b/desktop-directories/mate-settings.directory.in
@@ -0,0 +1,5 @@
+[Desktop Entry]
+_Name=Preferences
+_Comment=Personal preferences
+Icon=preferences-desktop
+Type=Directory
diff --git a/desktop-directories/mate-system-tools.directory.in b/desktop-directories/mate-system-tools.directory.in
new file mode 100644
index 0000000..d1d85be
--- /dev/null
+++ b/desktop-directories/mate-system-tools.directory.in
@@ -0,0 +1,5 @@
+[Desktop Entry]
+_Name=System Tools
+_Comment=System configuration and monitoring
+Icon=applications-system
+Type=Directory
diff --git a/desktop-directories/mate-system.directory.in b/desktop-directories/mate-system.directory.in
new file mode 100644
index 0000000..9de63bf
--- /dev/null
+++ b/desktop-directories/mate-system.directory.in
@@ -0,0 +1,5 @@
+[Desktop Entry]
+_Name=System
+_Comment=System settings
+Icon=preferences-system
+Type=Directory
diff --git a/desktop-directories/mate-utility-accessibility.directory.in b/desktop-directories/mate-utility-accessibility.directory.in
new file mode 100644
index 0000000..358b3a9
--- /dev/null
+++ b/desktop-directories/mate-utility-accessibility.directory.in
@@ -0,0 +1,5 @@
+[Desktop Entry]
+_Name=Universal Access
+_Comment=Universal Access Settings
+Type=Directory
+Icon=preferences-desktop-accessibility
diff --git a/desktop-directories/mate-utility.directory.in b/desktop-directories/mate-utility.directory.in
new file mode 100644
index 0000000..0edeeef
--- /dev/null
+++ b/desktop-directories/mate-utility.directory.in
@@ -0,0 +1,5 @@
+[Desktop Entry]
+_Name=Accessories
+_Comment=Desktop accessories
+Icon=applications-accessories
+Type=Directory
diff --git a/distro/archlinux/PKGBUILD b/distro/archlinux/PKGBUILD
new file mode 100644
index 0000000..56ff5ff
--- /dev/null
+++ b/distro/archlinux/PKGBUILD
@@ -0,0 +1,29 @@
+pkgname=mate-menus
+pkgver=2011.11.16
+pkgrel=1
+pkgdesc="MATE menu specifications"
+arch=('i686' 'x86_64')
+license=('GPL')
+depends=('glib2' 'python2')
+makedepends=('intltool' 'gobject-introspection')
+options=('!emptydirs' '!libtool')
+source=(http://sourceforge.net/projects/matede/files/${pkgver}/${pkgname}.tar.gz/download)
+sha256sums=('c9ab6dec9b0157bbd3cd7618839fbbf30d6ddcee231c14e46cd267c2b56601d4')
+url="http://matsusoft.com.ar/projects"
+groups=('mate')
+
+build() {
+ cd "${srcdir}/${pkgname}"
+ PYTHON=/usr/bin/python2 ./autogen.sh \
+ --prefix=/usr \
+ --sysconfdir=/etc \
+ --localstatedir=/var \
+ --enable-python \
+ --disable-static || return 1
+ make || return 1
+}
+
+package() {
+ cd "${srcdir}/${pkgname}"
+ make DESTDIR="${pkgdir}" install || return 1
+}
diff --git a/distro/archlinux/menus.patch b/distro/archlinux/menus.patch
new file mode 100644
index 0000000..413d33c
--- /dev/null
+++ b/distro/archlinux/menus.patch
@@ -0,0 +1,25 @@
+--- layout/applications.menu 2005-06-28 10:16:39.000000000 +0200
++++ layout/applications.menu 2005-09-12 23:21:20.000000000 +0200
[email protected]@ -7,7 +7,6 @@
+ <Directory>Applications.directory</Directory>
+
+ <!-- Scan legacy dirs first, as later items take priority -->
+- <KDELegacyDirs/>
+ <LegacyDir>/etc/X11/applnk</LegacyDir>
+ <LegacyDir>/usr/share/mate/apps</LegacyDir>
+
[email protected]@ -18,6 +17,14 @@
+ <!-- Read in overrides and child menus from applications-merged/ -->
+ <DefaultMergeDirs/>
+
++ <!-- Archlinux submenu -->
++ <Menu>
++ <Name>Archlinux</Name>
++ <Directory>Archlinux.directory</Directory>
++ <Include>
++ <Category>Archlinux</Category>
++ </Include>
++ </Menu> <!-- End Archlinux -->
+ <!-- Accessories submenu -->
+ <Menu>
+ <Name>Accessories</Name>
diff --git a/distro/ubuntu/build b/distro/ubuntu/build
new file mode 100755
index 0000000..4f14709
--- /dev/null
+++ b/distro/ubuntu/build
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+# fill it
+pkgname=mate-menus
+pkgver=2011.10.29
+pkgrel=1
+pkgdesc="MATE menu specifications"
+#depends="glib2, python2"
+# editar esta funcion!
+build() {
+ cd $pkgsrc
+ # descomprimir
+ tar xvzf download
+ # entramos a la carpeta
+ cd ${pkgname}
+
+ #patch -Np0 -i "$srcdir/menus.patch"
+
+ ./configure \
+ --prefix=/usr --sysconfdir=/etc \
+ --localstatedir=/var --disable-static
+ make
+ make DESTDIR="${pkgdir}" install
+}
+
+# esto incluye la parte que se repite en la mayoria de los builds
+. /usr/share/mate-doc-utils/mate-debian.sh
diff --git a/install-sh b/install-sh
new file mode 100755
index 0000000..6781b98
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,520 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2009-04-28.21; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# 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
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" "" $nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit=${DOITPROG-}
+if test -z "$doit"; then
+ doit_exec=exec
+else
+ doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_glob='?'
+initialize_posix_glob='
+ test "$posix_glob" != "?" || {
+ if (set -f) 2>/dev/null; then
+ posix_glob=
+ else
+ posix_glob=:
+ fi
+ }
+'
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+no_target_directory=
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+ --help display this help and exit.
+ --version display version info and exit.
+
+ -c (ignored)
+ -C install only if different (preserve the last data modification time)
+ -d create directories instead of installing files.
+ -g GROUP $chgrpprog installed files to GROUP.
+ -m MODE $chmodprog installed files to MODE.
+ -o USER $chownprog installed files to USER.
+ -s $stripprog installed files.
+ -t DIRECTORY install into DIRECTORY.
+ -T report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+ RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+ case $1 in
+ -c) ;;
+
+ -C) copy_on_change=true;;
+
+ -d) dir_arg=true;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) mode=$2
+ case $mode in
+ *' '* | *' '* | *'
+'* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
+
+ -o) chowncmd="$chownprog $2"
+ shift;;
+
+ -s) stripcmd=$stripprog;;
+
+ -t) dst_arg=$2
+ shift;;
+
+ -T) no_target_directory=true;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ --) shift
+ break;;
+
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
+
+ *) break;;
+ esac
+ shift
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+ # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ # Otherwise, the last argument is the destination. Remove it from [email protected]
+ for arg
+ do
+ if test -n "$dst_arg"; then
+ # [email protected] is not empty: it contains at least $arg.
+ set fnord "[email protected]" "$dst_arg"
+ shift # fnord
+ fi
+ shift # arg
+ dst_arg=$arg
+ done
+fi
+
+if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call `install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+if test -z "$dir_arg"; then
+ trap '(exit $?); exit' 1 2 13 15
+
+ # Set umask so as not to create temps with too-generous modes.
+ # However, 'strip' requires both read and write access to temps.
+ case $mode in
+ # Optimize common cases.
+ *644) cp_umask=133;;
+ *755) cp_umask=22;;
+
+ *[0-7])
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw='% 200'
+ fi
+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+ *)
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw=,u+rw
+ fi
+ cp_umask=$mode$u_plus_rw;;
+ esac
+fi
+
+for src
+do
+ # Protect names starting with `-'.
+ case $src in
+ -*) src=./$src;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dst_arg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+
+ dst=$dst_arg
+ # Protect names starting with `-'.
+ case $dst in
+ -*) dst=./$dst;;
+ esac
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test -n "$no_target_directory"; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dst=$dstdir/`basename "$src"`
+ dstdir_status=0
+ else
+ # Prefer dirname, but fall back on a substitute if dirname fails.
+ dstdir=`
+ (dirname "$dst") 2>/dev/null ||
+ expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$dst" : 'X\(//\)[^/]' \| \
+ X"$dst" : 'X\(//\)$' \| \
+ X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+ echo X"$dst" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'
+ `
+
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ # Create intermediate dirs using mode 755 as modified by the umask.
+ # This is like FreeBSD 'install' as of 1997-10-28.
+ umask=`umask`
+ case $stripcmd.$umask in
+ # Optimize common cases.
+ *[2367][2367]) mkdir_umask=$umask;;
+ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+ *[0-7])
+ mkdir_umask=`expr $umask + 22 \
+ - $umask % 100 % 40 + $umask % 20 \
+ - $umask % 10 % 4 + $umask % 2
+ `;;
+ *) mkdir_umask=$umask,go-w;;
+ esac
+
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ case $umask in
+ *[123567][0-7][0-7])
+ # POSIX mkdir -p sets u+wx bits regardless of umask, which
+ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+ ;;
+ *)
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+ if (umask $mkdir_umask &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writeable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ ls_ld_tmpdir=`ls -ld "$tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/d" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+ fi
+ trap '' 0;;
+ esac;;
+ esac
+
+ if
+ $posix_mkdir && (
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ )
+ then :
+ else
+
+ # The umask is ridiculous, or mkdir does not conform to POSIX,
+ # or it failed possibly due to a race condition. Create the
+ # directory the slow way, step by step, checking for races as we go.
+
+ case $dstdir in
+ /*) prefix='/';;
+ -*) prefix='./';;
+ *) prefix='';;
+ esac
+
+ eval "$initialize_posix_glob"
+
+ oIFS=$IFS
+ IFS=/
+ $posix_glob set -f
+ set fnord $dstdir
+ shift
+ $posix_glob set +f
+ IFS=$oIFS
+
+ prefixes=
+
+ for d
+ do
+ test -z "$d" && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask=$mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
+ done
+
+ if test -n "$prefixes"; then
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
+ fi
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+ # If -C, don't bother to copy if it wouldn't change the file.
+ if $copy_on_change &&
+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+
+ eval "$initialize_posix_glob" &&
+ $posix_glob set -f &&
+ set X $old && old=:$2:$4:$5:$6 &&
+ set X $new && new=:$2:$4:$5:$6 &&
+ $posix_glob set +f &&
+
+ test "$old" = "$new" &&
+ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+ then
+ rm -f "$dsttmp"
+ else
+ # Rename the file to the real destination.
+ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+ {
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ test ! -f "$dst" ||
+ $doit $rmcmd -f "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+ } ||
+ { echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ fi || exit 1
+
+ trap '' 0
+ fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/layout/Makefile.am b/layout/Makefile.am
new file mode 100644
index 0000000..f6ab8e6
--- /dev/null
+++ b/layout/Makefile.am
@@ -0,0 +1,9 @@
+menudir = $(sysconfdir)/xdg/menus
+
+menu_DATA = \
+ mate-applications.menu \
+ mate-settings.menu
+
+EXTRA_DIST= $(menu_DATA)
+
+-include $(top_srcdir)/git.mk
diff --git a/layout/mate-applications.menu b/layout/mate-applications.menu
new file mode 100644
index 0000000..2b917cc
--- /dev/null
+++ b/layout/mate-applications.menu
@@ -0,0 +1,154 @@
+<!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN"
+ "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd">
+
+<Menu>
+
+ <Name>Applications</Name>
+ <Directory>mate-menu-applications.directory</Directory>
+
+ <!-- Scan legacy dirs first, as later items take priority -->
+ <KDELegacyDirs/>
+ <LegacyDir>/etc/X11/applnk</LegacyDir>
+ <LegacyDir>/usr/share/mate/apps</LegacyDir>
+
+ <!-- Read standard .directory and .desktop file locations -->
+ <DefaultAppDirs/>
+ <DefaultDirectoryDirs/>
+
+ <!-- Read in overrides and child menus from applications-merged/ -->
+ <DefaultMergeDirs/>
+
+ <!-- Accessories submenu -->
+ <Menu>
+ <Name>Accessories</Name>
+ <Directory>mate-utility.directory</Directory>
+ <Include>
+ <And>
+ <Category>Utility</Category>
+ <!-- Accessibility spec must have either the Utility or Settings
+ category, and we display an accessibility submenu already for
+ the ones that do not have Settings, so don't display accessibility
+ applications here -->
+ <Not><Category>Accessibility</Category></Not>
+ <Not><Category>System</Category></Not>
+ </And>
+ </Include>
+ </Menu> <!-- End Accessories -->
+
+ <!-- Accessibility submenu -->
+ <Menu>
+ <Name>Universal Access</Name>
+ <Directory>mate-utility-accessibility.directory</Directory>
+ <Include>
+ <And>
+ <Category>Accessibility</Category>
+ <Not><Category>Settings</Category></Not>
+ </And>
+ </Include>
+ </Menu> <!-- End Accessibility -->
+
+ <!-- Development Tools -->
+ <Menu>
+ <Name>Development</Name>
+ <Directory>mate-development.directory</Directory>
+ <Include>
+ <And>
+ <Category>Development</Category>
+ </And>
+ <Filename>emacs.desktop</Filename>
+ </Include>
+ </Menu> <!-- End Development Tools -->
+
+ <!-- Education -->
+ <Menu>
+ <Name>Education</Name>
+ <Directory>mate-education.directory</Directory>
+ <Include>
+ <And>
+ <Category>Education</Category>
+ </And>
+ </Include>
+ </Menu> <!-- End Education -->
+
+ <!-- Games -->
+ <Menu>
+ <Name>Games</Name>
+ <Directory>mate-game.directory</Directory>
+ <Include>
+ <And>
+ <Category>Game</Category>
+ </And>
+ </Include>
+ </Menu> <!-- End Games -->
+
+ <!-- Graphics -->
+ <Menu>
+ <Name>Graphics</Name>
+ <Directory>mate-graphics.directory</Directory>
+ <Include>
+ <And>
+ <Category>Graphics</Category>
+ </And>
+ </Include>
+ </Menu> <!-- End Graphics -->
+
+ <!-- Internet -->
+ <Menu>
+ <Name>Internet</Name>
+ <Directory>mate-network.directory</Directory>
+ <Include>
+ <And>
+ <Category>Network</Category>
+ </And>
+ </Include>
+ </Menu> <!-- End Internet -->
+
+ <!-- Multimedia -->
+ <Menu>
+ <Name>Multimedia</Name>
+ <Directory>mate-audio-video.directory</Directory>
+ <Include>
+ <And>
+ <Category>AudioVideo</Category>
+ </And>
+ </Include>
+ </Menu> <!-- End Multimedia -->
+
+ <!-- Office -->
+ <Menu>
+ <Name>Office</Name>
+ <Directory>mate-office.directory</Directory>
+ <Include>
+ <And>
+ <Category>Office</Category>
+ </And>
+ </Include>
+ </Menu> <!-- End Office -->
+
+ <!-- System Tools-->
+ <Menu>
+ <Name>System</Name>
+ <Directory>mate-system-tools.directory</Directory>
+ <Include>
+ <And>
+ <Category>System</Category>
+ <Not><Category>Settings</Category></Not>
+ </And>
+ </Include>
+ </Menu> <!-- End System Tools -->
+
+ <!-- Other -->
+ <Menu>
+ <Name>Other</Name>
+ <Directory>mate-other.directory</Directory>
+ <OnlyUnallocated/>
+ <Include>
+ <And>
+ <Not><Category>Core</Category></Not>
+ <Not><Category>Settings</Category></Not>
+ <Not><Category>Screensaver</Category></Not>
+ </And>
+ </Include>
+ </Menu> <!-- End Other -->
+
+</Menu> <!-- End Applications -->
diff --git a/layout/mate-settings.menu b/layout/mate-settings.menu
new file mode 100644
index 0000000..18b7e17
--- /dev/null
+++ b/layout/mate-settings.menu
@@ -0,0 +1,57 @@
+<!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN"
+ "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd">
+
+<Menu>
+
+ <Name>Desktop</Name>
+ <Directory>mate-menu-system.directory</Directory>
+
+ <!-- Read standard .directory and .desktop file locations -->
+ <DefaultAppDirs/>
+ <DefaultDirectoryDirs/>
+
+ <!-- Read in overrides and child menus from applications-merged/ -->
+ <DefaultMergeDirs/>
+
+ <!-- Add a link to the control center -->
+ <Include>
+ <Filename>matecc.desktop</Filename>
+ </Include>
+
+ <!-- Merge in these other files as submenus -->
+ <Menu>
+ <Name>Preferences</Name>
+ <Directory>mate-settings.directory</Directory>
+ <Include>
+ <And>
+ <Category>Settings</Category>
+ <Not>
+ <Or>
+ <Category>System</Category>
+ <Filename>matecc.desktop</Filename>
+ </Or>
+ </Not>
+ </And>
+ </Include>
+ </Menu>
+
+ <!-- System Settings -->
+ <Menu>
+ <Name>Administration</Name>
+ <Directory>mate-settings-system.directory</Directory>
+ <Include>
+ <And>
+ <Category>Settings</Category>
+ <Category>System</Category>
+ </And>
+ </Include>
+ </Menu> <!-- End System Settings -->
+
+ <Layout>
+ <Menuname>Preferences</Menuname>
+ <Menuname>Administration</Menuname>
+ <Merge type="menus"/>
+ <Merge type="files"/>
+ </Layout>
+
+</Menu> <!-- End Settings -->
diff --git a/libmenu/Makefile.am b/libmenu/Makefile.am
new file mode 100644
index 0000000..3d06096
--- /dev/null
+++ b/libmenu/Makefile.am
@@ -0,0 +1,78 @@
+lib_LTLIBRARIES = libmate-menu.la
+
+AM_CPPFLAGS = \
+ $(GLIB_CFLAGS) \
+ -DMATEMENU_I_KNOW_THIS_IS_UNSTABLE \
+ $(DISABLE_DEPRECATED_CFLAGS) \
+ $(DEBUG_CFLAGS)
+
+AM_CFLAGS = $(WARN_CFLAGS)
+
+libmate_menu_includedir = $(includedir)/mate-menus
+libmate_menu_include_HEADERS = \
+ matemenu-tree.h
+
+libmate_menu_sources = \
+ canonicalize.c \
+ desktop-entries.c \
+ entry-directories.c \
+ matemenu-tree.c \
+ menu-layout.c \
+ menu-monitor.c \
+ menu-util.c
+
+libmate_menu_la_SOURCES = \
+ $(libmate_menu_sources) \
+ canonicalize.h \
+ desktop-entries.h \
+ entry-directories.h \
+ matemenu-tree.h \
+ menu-layout.h \
+ menu-monitor.h \
+ menu-util.h
+
+libmate_menu_la_LIBADD = \
+ $(GLIB_LIBS)
+
+libmate_menu_la_LDFLAGS = \
+ -version-info $(LIB_MENU_LT_VERSION) \
+ -no-undefined \
+ -export-symbols-regex matemenu_tree
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libmate-menu.pc
+
+EXTRA_DIST = \
+ libmate-menu.pc.in \
+ libmate-menu-uninstalled.pc.in
+
+CLEANFILES =
+
+# Introspection
+-include $(INTROSPECTION_MAKEFILE)
+INTROSPECTION_GIRS =
+INTROSPECTION_SCANNER_ARGS = --warn-all --add-include-path=$(srcdir)
+INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
+
+if HAVE_INTROSPECTION
+# Note: we only include the headers here so far because there's no gtk-doc at all anyway
+introspection_sources = $(libmate_menu_include_HEADERS)
+
+MateMenu-2.0.gir: libmate-menu.la
+MateMenu_2_0_gir_INCLUDES = GObject-2.0
+MateMenu_2_0_gir_CFLAGS = $(AM_CPPFLAGS)
+MateMenu_2_0_gir_LIBS = libmate-menu.la
+MateMenu_2_0_gir_SCANNERFLAGS = --pkg-export=libmate-menu
+MateMenu_2_0_gir_FILES = $(addprefix $(srcdir)/,$(introspection_sources))
+INTROSPECTION_GIRS += MateMenu-2.0.gir
+
+girdir = $(INTROSPECTION_GIRDIR)
+gir_DATA = $(INTROSPECTION_GIRS)
+
+typelibdir = $(INTROSPECTION_TYPELIBDIR)
+typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
+
+CLEANFILES += $(gir_DATA) $(typelib_DATA)
+endif
+
+-include $(top_srcdir)/git.mk
diff --git a/libmenu/canonicalize.c b/libmenu/canonicalize.c
new file mode 100644
index 0000000..82082e9
--- /dev/null
+++ b/libmenu/canonicalize.c
@@ -0,0 +1,326 @@
+/* Return the canonical absolute name of a given file.
+ * Copyright (C) 1996-2001, 2002 Free Software Foundation, Inc.
+ * This file is part of the GNU C Library.
+ *
+ * Copyright (C) 2002 Red Hat, Inc. (trivial port to GLib)
+ *
+ * The GNU C 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.
+ *
+ * The GNU C 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 the GNU C Library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA.
+ */
+
+#include <config.h>
+
+#include "canonicalize.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stddef.h>
+
+/* Return the canonical absolute name of file NAME. A canonical name
+ does not contain any `.', `..' components nor any repeated path
+ separators ('/') or symlinks. All path components must exist. If
+ RESOLVED is null, the result is malloc'd; otherwise, if the
+ canonical name is PATH_MAX chars or more, returns null with `errno'
+ set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars,
+ returns the name in RESOLVED. If the name cannot be resolved and
+ RESOLVED is non-NULL, it contains the path of the first component
+ that cannot be resolved. If the path can be resolved, RESOLVED
+ holds the same value as the value returned. */
+
+static char* menu_realpath(const char* name, char* resolved)
+{
+ char* rpath = NULL;
+ char* dest = NULL;
+ char* extra_buf = NULL;
+ const char* start;
+ const char* end;
+ const char* rpath_limit;
+ long int path_max;
+ int num_links = 0;
+
+ if (name == NULL)
+ {
+ /* As per Single Unix Specification V2 we must return an error if
+ * either parameter is a null pointer. We extend this to allow
+ * the RESOLVED parameter to be NULL in case the we are expected to
+ * allocate the room for the return value. */
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (name[0] == '\0')
+ {
+ /* As per Single Unix Specification V2 we must return an error if
+ * the name argument points to an empty string. */
+ errno = ENOENT;
+ return NULL;
+ }
+
+ #ifdef PATH_MAX
+ path_max = PATH_MAX;
+ #else
+ path_max = pathconf(name, _PC_PATH_MAX);
+
+ if (path_max <= 0)
+ {
+ path_max = 1024;
+ }
+ #endif
+
+ rpath = resolved ? g_alloca(path_max) : g_malloc(path_max);
+ rpath_limit = rpath + path_max;
+
+ if (name[0] != G_DIR_SEPARATOR)
+ {
+ if (!getcwd(rpath, path_max))
+ {
+ rpath[0] = '\0';
+ goto error;
+ }
+
+ dest = strchr(rpath, '\0');
+ }
+ else
+ {
+ rpath[0] = G_DIR_SEPARATOR;
+ dest = rpath + 1;
+ }
+
+ for (start = end = name; *start; start = end)
+ {
+ struct stat st;
+ int n;
+
+ /* Skip sequence of multiple path-separators. */
+ while (*start == G_DIR_SEPARATOR)
+ {
+ ++start;
+ }
+
+ /* Find end of path component. */
+ for (end = start; *end && *end != G_DIR_SEPARATOR; ++end)
+ {
+ /* Nothing. */;
+ }
+
+ if (end - start == 0)
+ {
+ break;
+ }
+ else if (end - start == 1 && start[0] == '.')
+ {
+ /* nothing */;
+ }
+ else if (end - start == 2 && start[0] == '.' && start[1] == '.')
+ {
+ /* Back up to previous component, ignore if at root already. */
+ if (dest > rpath + 1)
+ {
+ while ((--dest)[-1] != G_DIR_SEPARATOR)
+ {
+ /* Nothing. */;
+ }
+ }
+ }
+ else
+ {
+ size_t new_size;
+
+ if (dest[-1] != G_DIR_SEPARATOR)
+ {
+ *dest++ = G_DIR_SEPARATOR;
+ }
+
+ if (dest + (end - start) >= rpath_limit)
+ {
+ char* new_rpath;
+ ptrdiff_t dest_offset = dest - rpath;
+
+ if (resolved)
+ {
+ #ifdef ENAMETOOLONG
+ errno = ENAMETOOLONG;
+ #else
+ /* Uh... just pick something */
+ errno = EINVAL;
+ #endif
+
+ if (dest > rpath + 1)
+ {
+ dest--;
+ }
+
+ *dest = '\0';
+ goto error;
+ }
+
+ new_size = rpath_limit - rpath;
+
+ if (end - start + 1 > path_max)
+ {
+ new_size += end - start + 1;
+ }
+ else
+ {
+ new_size += path_max;
+ }
+
+ new_rpath = (char*) realloc(rpath, new_size);
+
+ if (new_rpath == NULL)
+ {
+ goto error;
+ }
+
+ rpath = new_rpath;
+ rpath_limit = rpath + new_size;
+
+ dest = rpath + dest_offset;
+ }
+
+ memcpy(dest, start, end - start);
+ dest = dest + (end - start);
+ *dest = '\0';
+
+ if (stat(rpath, &st) < 0)
+ {
+ goto error;
+ }
+
+ if (S_ISLNK(st.st_mode))
+ {
+ char* buf = alloca(path_max);
+ size_t len;
+
+ if (++num_links > MAXSYMLINKS)
+ {
+ errno = ELOOP;
+ goto error;
+ }
+
+ n = readlink(rpath, buf, path_max);
+
+ if (n < 0)
+ {
+ goto error;
+ }
+
+ buf[n] = '\0';
+
+
+
+ if (!extra_buf)
+ {
+ extra_buf = g_alloca(path_max);
+ }
+
+ len = strlen(end);
+
+ if ((long int) (n + len) >= path_max)
+ {
+ #ifdef ENAMETOOLONG
+ errno = ENAMETOOLONG;
+ #else
+ /* Uh... just pick something */
+ errno = EINVAL;
+ #endif
+
+ goto error;
+ }
+
+ /* Careful here, end may be a pointer into extra_buf... */
+ g_memmove(&extra_buf[n], end, len + 1);
+ name = end = memcpy(extra_buf, buf, n);
+
+ if (buf[0] == G_DIR_SEPARATOR)
+ {
+ dest = rpath + 1; /* It's an absolute symlink */
+ }
+ else
+ {
+ /* Back up to previous component, ignore if at root already: */
+ if (dest > rpath + 1)
+ {
+ while ((--dest)[-1] != G_DIR_SEPARATOR)
+ {
+ /* Nothing. */;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (dest > rpath + 1 && dest[-1] == G_DIR_SEPARATOR)
+ {
+ --dest;
+ }
+
+ *dest = '\0';
+
+ return resolved ? memcpy(resolved, rpath, dest - rpath + 1) : rpath;
+
+ error:
+
+ if (resolved)
+ {
+ strcpy(resolved, rpath);
+ }
+ else
+ {
+ g_free(rpath);
+ }
+
+ return NULL;
+}
+
+char* menu_canonicalize_file_name(const char* name, gboolean allow_missing_basename)
+{
+ char* retval;
+
+ retval = menu_realpath(name, NULL);
+
+ /* We could avoid some system calls by using the second
+ * argument to realpath() instead of doing realpath
+ * all over again, but who cares really. we'll see if
+ * it's ever in a profile.
+ */
+ if (allow_missing_basename && retval == NULL)
+ {
+ char* dirname;
+ char* canonical_dirname;
+
+ dirname = g_path_get_dirname(name);
+ canonical_dirname = menu_realpath(dirname, NULL);
+ g_free(dirname);
+
+ if (canonical_dirname)
+ {
+ char* basename;
+
+ basename = g_path_get_basename(name);
+ retval = g_build_filename(canonical_dirname, basename, NULL);
+ g_free(basename);
+ g_free(canonical_dirname);
+ }
+ }
+
+ return retval;
+}
diff --git a/libmenu/canonicalize.h b/libmenu/canonicalize.h
new file mode 100644
index 0000000..b5deddc
--- /dev/null
+++ b/libmenu/canonicalize.h
@@ -0,0 +1,38 @@
+/* Return the canonical absolute name of a given file.
+ * Copyright (C) 1996-2001, 2002 Free Software Foundation, Inc.
+ * This file is part of the GNU C Library.
+ *
+ * Copyright (C) 2002 Red Hat, Inc. (trivial port to GLib)
+ *
+ * The GNU C 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.
+ *
+ * The GNU C 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 the GNU C Library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA.
+ */
+
+#ifndef G_CANONICALIZE_H
+#define G_CANONICALIZE_H
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+char* menu_canonicalize_file_name(const char* name, gboolean allow_missing_basename);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* G_CANONICALIZE_H */
diff --git a/libmenu/desktop-entries.c b/libmenu/desktop-entries.c
new file mode 100644
index 0000000..9488bde
--- /dev/null
+++ b/libmenu/desktop-entries.c
@@ -0,0 +1,816 @@
+/*
+ * Copyright (C) 2002 - 2004 Red Hat, 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.
+ */
+
+#include <config.h>
+
+#include "desktop-entries.h"
+
+#include <string.h>
+
+#include "menu-util.h"
+
+#define DESKTOP_ENTRY_GROUP "Desktop Entry"
+#define KDE_DESKTOP_ENTRY_GROUP "KDE Desktop Entry"
+
+enum {
+ DESKTOP_ENTRY_NO_DISPLAY = 1 << 0,
+ DESKTOP_ENTRY_HIDDEN = 1 << 1,
+ DESKTOP_ENTRY_SHOW_IN_MATE = 1 << 2,
+ DESKTOP_ENTRY_TRYEXEC_FAILED = 1 << 3
+};
+
+struct DesktopEntry {
+ char* path;
+ char* basename;
+
+ GQuark* categories;
+
+ char* name;
+ char* generic_name;
+ char* full_name;
+ char* comment;
+ char* icon;
+ char* exec;
+ gboolean terminal;
+
+ guint type: 2;
+ guint flags: 4;
+ guint refcount: 24;
+};
+
+struct DesktopEntrySet {
+ int refcount;
+ GHashTable* hash;
+};
+
+/*
+ * Desktop entries
+ */
+
+static guint get_flags_from_key_file(DesktopEntry* entry, GKeyFile* key_file, const char* desktop_entry_group)
+{
+ GError *error;
+ char **strv;
+ gboolean no_display;
+ gboolean hidden;
+ gboolean show_in_mate;
+ gboolean tryexec_failed;
+ char *tryexec;
+ guint flags;
+ int i;
+
+ error = NULL;
+ no_display = g_key_file_get_boolean (key_file,
+ desktop_entry_group,
+ "NoDisplay",
+ &error);
+ if (error)
+ {
+ no_display = FALSE;
+ g_error_free (error);
+ }
+
+ error = NULL;
+ hidden = g_key_file_get_boolean (key_file,
+ desktop_entry_group,
+ "Hidden",
+ &error);
+ if (error)
+ {
+ hidden = FALSE;
+ g_error_free (error);
+ }
+
+ show_in_mate = TRUE;
+ strv = g_key_file_get_string_list (key_file,
+ desktop_entry_group,
+ "OnlyShowIn",
+ NULL,
+ NULL);
+ if (strv)
+ {
+ show_in_mate = FALSE;
+ for (i = 0; strv[i]; i++)
+ {
+ if (!strcmp (strv[i], "MATE"))
+ {
+ show_in_mate = TRUE;
+ break;
+ }
+ }
+ }
+ else
+ {
+ strv = g_key_file_get_string_list (key_file,
+ desktop_entry_group,
+ "NotShowIn",
+ NULL,
+ NULL);
+ if (strv)
+ {
+ show_in_mate = TRUE;
+ for (i = 0; strv[i]; i++)
+ {
+ if (!strcmp (strv[i], "MATE"))
+ {
+ show_in_mate = FALSE;
+ }
+ }
+ }
+ }
+ g_strfreev (strv);
+
+ tryexec_failed = FALSE;
+ tryexec = g_key_file_get_string (key_file,
+ desktop_entry_group,
+ "TryExec",
+ NULL);
+ if (tryexec)
+ {
+ char *path;
+
+ path = g_find_program_in_path (g_strstrip (tryexec));
+
+ tryexec_failed = (path == NULL);
+
+ g_free (path);
+ g_free (tryexec);
+ }
+
+ flags = 0;
+ if (no_display)
+ flags |= DESKTOP_ENTRY_NO_DISPLAY;
+ if (hidden)
+ flags |= DESKTOP_ENTRY_HIDDEN;
+ if (show_in_mate)
+ flags |= DESKTOP_ENTRY_SHOW_IN_MATE;
+ if (tryexec_failed)
+ flags |= DESKTOP_ENTRY_TRYEXEC_FAILED;
+
+ return flags;
+}
+
+static GQuark* get_categories_from_key_file (DesktopEntry* entry, GKeyFile* key_file, const char* desktop_entry_group)
+{
+ GQuark *retval;
+ char **strv;
+ gsize len;
+ int i;
+
+ strv = g_key_file_get_string_list (key_file,
+ desktop_entry_group,
+ "Categories",
+ &len,
+ NULL);
+ if (!strv)
+ return NULL;
+
+ retval = g_new0 (GQuark, len + 1);
+
+ for (i = 0; strv[i]; i++)
+ retval[i] = g_quark_from_string (strv[i]);
+
+ g_strfreev (strv);
+
+ return retval;
+}
+
+static DesktopEntry* desktop_entry_load(DesktopEntry* entry)
+{
+ DesktopEntry *retval = NULL;
+ GKeyFile *key_file;
+ GError *error;
+ const char *desktop_entry_group;
+ char *name_str;
+ char *type_str;
+
+ key_file = g_key_file_new ();
+
+ error = NULL;
+ if (!g_key_file_load_from_file (key_file, entry->path, 0, &error))
+ {
+ menu_verbose ("Failed to load \"%s\": %s\n",
+ entry->path, error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ if (g_key_file_has_group (key_file, DESKTOP_ENTRY_GROUP))
+ {
+ desktop_entry_group = DESKTOP_ENTRY_GROUP;
+ }
+ else
+ {
+ menu_verbose ("\"%s\" contains no \"" DESKTOP_ENTRY_GROUP "\" group\n",
+ entry->path);
+
+ if (g_key_file_has_group (key_file, KDE_DESKTOP_ENTRY_GROUP))
+ {
+ desktop_entry_group = KDE_DESKTOP_ENTRY_GROUP;
+ menu_verbose ("\"%s\" contains deprecated \"" KDE_DESKTOP_ENTRY_GROUP "\" group\n",
+ entry->path);
+ }
+ else
+ {
+ goto out;
+ }
+ }
+
+ if (!g_key_file_has_key (key_file, desktop_entry_group, "Name", NULL))
+ {
+ menu_verbose ("\"%s\" contains no \"Name\" key\n", entry->path);
+ goto out;
+ }
+
+ name_str = g_key_file_get_locale_string (key_file, desktop_entry_group, "Name", NULL, NULL);
+ if (!name_str)
+ {
+ menu_verbose ("\"%s\" contains an invalid \"Name\" key\n", entry->path);
+ goto out;
+ }
+
+ g_free (name_str);
+
+ type_str = g_key_file_get_string (key_file, desktop_entry_group, "Type", NULL);
+ if (!type_str)
+ {
+ menu_verbose ("\"%s\" contains no \"Type\" key\n", entry->path);
+ goto out;
+ }
+
+ if ((entry->type == DESKTOP_ENTRY_DESKTOP && strcmp (type_str, "Application") != 0) ||
+ (entry->type == DESKTOP_ENTRY_DIRECTORY && strcmp (type_str, "Directory") != 0))
+ {
+ menu_verbose ("\"%s\" does not contain the correct \"Type\" value\n", entry->path);
+ g_free (type_str);
+ goto out;
+ }
+
+ g_free (type_str);
+
+ if (entry->type == DESKTOP_ENTRY_DESKTOP &&
+ !g_key_file_has_key (key_file, desktop_entry_group, "Exec", NULL))
+ {
+ menu_verbose ("\"%s\" does not contain an \"Exec\" key\n", entry->path);
+ goto out;
+ }
+
+ retval = entry;
+
+#define GET_LOCALE_STRING(n) g_key_file_get_locale_string (key_file, desktop_entry_group, (n), NULL, NULL)
+
+ retval->name = GET_LOCALE_STRING ("Name");
+ retval->generic_name = GET_LOCALE_STRING ("GenericName");
+ retval->full_name = GET_LOCALE_STRING ("X-MATE-FullName");
+ retval->comment = GET_LOCALE_STRING ("Comment");
+ retval->icon = GET_LOCALE_STRING ("Icon");
+ retval->flags = get_flags_from_key_file (retval, key_file, desktop_entry_group);
+ retval->categories = get_categories_from_key_file (retval, key_file, desktop_entry_group);
+
+ if (entry->type == DESKTOP_ENTRY_DESKTOP)
+ {
+ retval->exec = g_key_file_get_string (key_file, desktop_entry_group, "Exec", NULL);
+ retval->terminal = g_key_file_get_boolean (key_file, desktop_entry_group, "Terminal", NULL);
+ }
+
+#undef GET_LOCALE_STRING
+
+ menu_verbose ("Desktop entry \"%s\" (%s, %s, %s, %s, %s) flags: NoDisplay=%s, Hidden=%s, ShowInMATE=%s, TryExecFailed=%s\n",
+ retval->basename,
+ retval->name,
+ retval->generic_name ? retval->generic_name : "(null)",
+ retval->full_name ? retval->full_name : "(null)",
+ retval->comment ? retval->comment : "(null)",
+ retval->icon ? retval->icon : "(null)",
+ retval->flags & DESKTOP_ENTRY_NO_DISPLAY ? "(true)" : "(false)",
+ retval->flags & DESKTOP_ENTRY_HIDDEN ? "(true)" : "(false)",
+ retval->flags & DESKTOP_ENTRY_SHOW_IN_MATE ? "(true)" : "(false)",
+ retval->flags & DESKTOP_ENTRY_TRYEXEC_FAILED ? "(true)" : "(false)");
+
+ out:
+ g_key_file_free (key_file);
+
+ if (!retval)
+ desktop_entry_unref (entry);
+
+ return retval;
+}
+
+DesktopEntry* desktop_entry_new(const char* path)
+{
+ DesktopEntryType type;
+ DesktopEntry *retval;
+
+ menu_verbose ("Loading desktop entry \"%s\"\n", path);
+
+ if (g_str_has_suffix (path, ".desktop"))
+ {
+ type = DESKTOP_ENTRY_DESKTOP;
+ }
+ else if (g_str_has_suffix (path, ".directory"))
+ {
+ type = DESKTOP_ENTRY_DIRECTORY;
+ }
+ else
+ {
+ menu_verbose ("Unknown desktop entry suffix in \"%s\"\n",
+ path);
+ return NULL;
+ }
+
+ retval = g_new0 (DesktopEntry, 1);
+
+ retval->refcount = 1;
+ retval->type = type;
+ retval->basename = g_path_get_basename (path);
+ retval->path = g_strdup (path);
+
+ return desktop_entry_load (retval);
+}
+
+DesktopEntry* desktop_entry_reload(DesktopEntry* entry)
+{
+ g_return_val_if_fail (entry != NULL, NULL);
+
+ menu_verbose ("Re-loading desktop entry \"%s\"\n", entry->path);
+
+ g_free (entry->categories);
+ entry->categories = NULL;
+
+ g_free (entry->name);
+ entry->name = NULL;
+
+ g_free (entry->generic_name);
+ entry->generic_name = NULL;
+
+ g_free (entry->full_name);
+ entry->full_name = NULL;
+
+ g_free (entry->comment);
+ entry->comment = NULL;
+
+ g_free (entry->icon);
+ entry->icon = NULL;
+
+ g_free (entry->exec);
+ entry->exec = NULL;
+
+ entry->terminal = 0;
+ entry->flags = 0;
+
+ return desktop_entry_load (entry);
+}
+
+DesktopEntry* desktop_entry_ref(DesktopEntry* entry)
+{
+ g_return_val_if_fail (entry != NULL, NULL);
+ g_return_val_if_fail (entry->refcount > 0, NULL);
+
+ entry->refcount += 1;
+
+ return entry;
+}
+
+DesktopEntry* desktop_entry_copy(DesktopEntry* entry)
+{
+ DesktopEntry *retval;
+ int i;
+
+ menu_verbose ("Copying desktop entry \"%s\"\n",
+ entry->basename);
+
+ retval = g_new0 (DesktopEntry, 1);
+
+ retval->refcount = 1;
+ retval->type = entry->type;
+ retval->basename = g_strdup (entry->basename);
+ retval->path = g_strdup (entry->path);
+ retval->name = g_strdup (entry->name);
+ retval->generic_name = g_strdup (entry->generic_name);
+ retval->full_name = g_strdup (entry->full_name);
+ retval->comment = g_strdup (entry->comment);
+ retval->icon = g_strdup (entry->icon);
+ retval->exec = g_strdup (entry->exec);
+ retval->terminal = entry->terminal;
+ retval->flags = entry->flags;
+
+ i = 0;
+ if (entry->categories != NULL)
+ {
+ for (; entry->categories[i]; i++);
+ }
+
+ retval->categories = g_new0 (GQuark, i + 1);
+
+ i = 0;
+ if (entry->categories != NULL)
+ {
+ for (; entry->categories[i]; i++)
+ retval->categories[i] = entry->categories[i];
+ }
+
+ return retval;
+}
+
+void desktop_entry_unref(DesktopEntry* entry)
+{
+ g_return_if_fail (entry != NULL);
+ g_return_if_fail (entry->refcount > 0);
+
+ entry->refcount -= 1;
+ if (entry->refcount == 0)
+ {
+ g_free (entry->categories);
+ entry->categories = NULL;
+
+ g_free (entry->name);
+ entry->name = NULL;
+
+ g_free (entry->generic_name);
+ entry->generic_name = NULL;
+
+ g_free (entry->full_name);
+ entry->full_name = NULL;
+
+ g_free (entry->comment);
+ entry->comment = NULL;
+
+ g_free (entry->icon);
+ entry->icon = NULL;
+
+ g_free (entry->exec);
+ entry->exec = NULL;
+
+ g_free (entry->basename);
+ entry->basename = NULL;
+
+ g_free (entry->path);
+ entry->path = NULL;
+
+ g_free (entry);
+ }
+}
+
+DesktopEntryType desktop_entry_get_type(DesktopEntry* entry)
+{
+ return entry->type;
+}
+
+const char* desktop_entry_get_path(DesktopEntry* entry)
+{
+ return entry->path;
+}
+
+const char *
+desktop_entry_get_basename (DesktopEntry *entry)
+{
+ return entry->basename;
+}
+
+const char* desktop_entry_get_name(DesktopEntry* entry)
+{
+ return entry->name;
+}
+
+const char* desktop_entry_get_generic_name(DesktopEntry* entry)
+{
+ return entry->generic_name;
+}
+
+const char* desktop_entry_get_full_name(DesktopEntry* entry)
+{
+ return entry->full_name;
+}
+
+const char* desktop_entry_get_comment(DesktopEntry* entry)
+{
+ return entry->comment;
+}
+
+const char* desktop_entry_get_icon(DesktopEntry* entry)
+{
+ return entry->icon;
+}
+
+const char* desktop_entry_get_exec(DesktopEntry* entry)
+{
+ return entry->exec;
+}
+
+gboolean desktop_entry_get_launch_in_terminal(DesktopEntry* entry)
+{
+ return entry->terminal;
+}
+
+gboolean desktop_entry_get_hidden(DesktopEntry* entry)
+{
+ return (entry->flags & DESKTOP_ENTRY_HIDDEN) != 0;
+}
+
+gboolean desktop_entry_get_no_display(DesktopEntry* entry)
+{
+ return (entry->flags & DESKTOP_ENTRY_NO_DISPLAY) != 0;
+}
+
+gboolean desktop_entry_get_show_in_mate(DesktopEntry* entry)
+{
+ return (entry->flags & DESKTOP_ENTRY_SHOW_IN_MATE) != 0;
+}
+
+gboolean desktop_entry_get_tryexec_failed(DesktopEntry* entry)
+{
+ return (entry->flags & DESKTOP_ENTRY_TRYEXEC_FAILED) != 0;
+}
+
+gboolean desktop_entry_has_categories(DesktopEntry* entry)
+{
+ return (entry->categories != NULL && entry->categories[0] != 0);
+}
+
+gboolean desktop_entry_has_category(DesktopEntry* entry, const char* category)
+{
+ GQuark quark;
+ int i;
+
+ if (entry->categories == NULL)
+ return FALSE;
+
+ if (!(quark = g_quark_try_string (category)))
+ return FALSE;
+
+ for (i = 0; entry->categories[i]; i++)
+ {
+ if (quark == entry->categories[i])
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void desktop_entry_add_legacy_category(DesktopEntry* entry)
+{
+ GQuark *categories;
+ int i;
+
+ menu_verbose ("Adding Legacy category to \"%s\"\n",
+ entry->basename);
+
+ i = 0;
+ if (entry->categories != NULL)
+ {
+ for (; entry->categories[i]; i++);
+ }
+
+ categories = g_new0 (GQuark, i + 2);
+
+ i = 0;
+ if (entry->categories != NULL)
+ {
+ for (; entry->categories[i]; i++)
+ categories[i] = entry->categories[i];
+ }
+
+ categories[i] = g_quark_from_string ("Legacy");
+
+ g_free (entry->categories);
+ entry->categories = categories;
+}
+
+/*
+ * Entry sets
+ */
+
+DesktopEntrySet* desktop_entry_set_new(void)
+{
+ DesktopEntrySet *set;
+
+ set = g_new0 (DesktopEntrySet, 1);
+ set->refcount = 1;
+
+ menu_verbose (" New entry set %p\n", set);
+
+ return set;
+}
+
+DesktopEntrySet* desktop_entry_set_ref(DesktopEntrySet* set)
+{
+ g_return_val_if_fail (set != NULL, NULL);
+ g_return_val_if_fail (set->refcount > 0, NULL);
+
+ set->refcount += 1;
+
+ return set;
+}
+
+void desktop_entry_set_unref(DesktopEntrySet* set)
+{
+ g_return_if_fail (set != NULL);
+ g_return_if_fail (set->refcount > 0);
+
+ set->refcount -= 1;
+ if (set->refcount == 0)
+ {
+ menu_verbose (" Deleting entry set %p\n", set);
+
+ if (set->hash)
+ g_hash_table_destroy (set->hash);
+ set->hash = NULL;
+
+ g_free (set);
+ }
+}
+
+void desktop_entry_set_add_entry(DesktopEntrySet* set, DesktopEntry* entry, const char* file_id)
+{
+ menu_verbose (" Adding to set %p entry %s\n", set, file_id);
+
+ if (set->hash == NULL)
+ {
+ set->hash = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) desktop_entry_unref);
+ }
+
+ g_hash_table_replace (set->hash,
+ g_strdup (file_id),
+ desktop_entry_ref (entry));
+}
+
+DesktopEntry* desktop_entry_set_lookup(DesktopEntrySet* set, const char* file_id)
+{
+ if (set->hash == NULL)
+ return NULL;
+
+ return g_hash_table_lookup (set->hash, file_id);
+}
+
+typedef struct {
+ DesktopEntrySetForeachFunc func;
+ gpointer user_data;
+} EntryHashForeachData;
+
+static void entry_hash_foreach(const char* file_id, DesktopEntry* entry, EntryHashForeachData* fd)
+{
+ fd->func(file_id, entry, fd->user_data);
+}
+
+void desktop_entry_set_foreach(DesktopEntrySet* set, DesktopEntrySetForeachFunc func, gpointer user_data)
+{
+ g_return_if_fail (set != NULL);
+ g_return_if_fail (func != NULL);
+
+ if (set->hash != NULL)
+ {
+ EntryHashForeachData fd;
+
+ fd.func = func;
+ fd.user_data = user_data;
+
+ g_hash_table_foreach (set->hash,
+ (GHFunc) entry_hash_foreach,
+ &fd);
+ }
+}
+
+static void desktop_entry_set_clear(DesktopEntrySet* set)
+{
+ menu_verbose (" Clearing set %p\n", set);
+
+ if (set->hash != NULL)
+ {
+ g_hash_table_destroy (set->hash);
+ set->hash = NULL;
+ }
+}
+
+int desktop_entry_set_get_count(DesktopEntrySet* set)
+{
+ if (set->hash == NULL)
+ return 0;
+
+ return g_hash_table_size (set->hash);
+}
+
+static void union_foreach(const char* file_id, DesktopEntry* entry, DesktopEntrySet* set)
+{
+ /* we are iterating over "with" adding anything not
+ * already in "set". We unconditionally overwrite
+ * the stuff in "set" because we can assume
+ * two entries with the same name are equivalent.
+ */
+ desktop_entry_set_add_entry(set, entry, file_id);
+}
+
+void desktop_entry_set_union(DesktopEntrySet* set, DesktopEntrySet* with)
+{
+ menu_verbose (" Union of %p and %p\n", set, with);
+
+ if (desktop_entry_set_get_count (with) == 0)
+ return; /* A fast simple case */
+
+ g_hash_table_foreach (with->hash,
+ (GHFunc) union_foreach,
+ set);
+}
+
+typedef struct {
+ DesktopEntrySet *set;
+ DesktopEntrySet *with;
+} IntersectData;
+
+static gboolean intersect_foreach_remove(const char* file_id, DesktopEntry* entry, IntersectData* id)
+{
+ /* Remove everything in "set" which is not in "with" */
+
+ if (g_hash_table_lookup (id->with->hash, file_id) != NULL)
+ return FALSE;
+
+ menu_verbose (" Removing from %p entry %s\n", id->set, file_id);
+
+ return TRUE; /* return TRUE to remove */
+}
+
+void desktop_entry_set_intersection(DesktopEntrySet* set, DesktopEntrySet* with)
+{
+ IntersectData id;
+
+ menu_verbose (" Intersection of %p and %p\n", set, with);
+
+ if (desktop_entry_set_get_count (set) == 0 ||
+ desktop_entry_set_get_count (with) == 0)
+ {
+ /* A fast simple case */
+ desktop_entry_set_clear (set);
+ return;
+ }
+
+ id.set = set;
+ id.with = with;
+
+ g_hash_table_foreach_remove (set->hash,
+ (GHRFunc) intersect_foreach_remove,
+ &id);
+}
+
+typedef struct {
+ DesktopEntrySet *set;
+ DesktopEntrySet *other;
+} SubtractData;
+
+static gboolean subtract_foreach_remove(const char* file_id, DesktopEntry* entry, SubtractData* sd)
+{
+ /* Remove everything in "set" which is not in "other" */
+
+ if (g_hash_table_lookup (sd->other->hash, file_id) == NULL)
+ return FALSE;
+
+ menu_verbose (" Removing from %p entry %s\n", sd->set, file_id);
+
+ return TRUE; /* return TRUE to remove */
+}
+
+void desktop_entry_set_subtract(DesktopEntrySet* set, DesktopEntrySet* other)
+{
+ SubtractData sd;
+
+ menu_verbose (" Subtract from %p set %p\n", set, other);
+
+ if (desktop_entry_set_get_count (set) == 0 ||
+ desktop_entry_set_get_count (other) == 0)
+ return; /* A fast simple case */
+
+ sd.set = set;
+ sd.other = other;
+
+ g_hash_table_foreach_remove (set->hash,
+ (GHRFunc) subtract_foreach_remove,
+ &sd);
+}
+
+void desktop_entry_set_swap_contents(DesktopEntrySet* a, DesktopEntrySet* b)
+{
+ GHashTable *tmp;
+
+ menu_verbose (" Swap contents of %p and %p\n", a, b);
+
+ tmp = a->hash;
+ a->hash = b->hash;
+ b->hash = tmp;
+}
diff --git a/libmenu/desktop-entries.h b/libmenu/desktop-entries.h
new file mode 100644
index 0000000..19d9abd
--- /dev/null
+++ b/libmenu/desktop-entries.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2002 - 2004 Red Hat, 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 __DESKTOP_ENTRIES_H__
+#define __DESKTOP_ENTRIES_H__
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ DESKTOP_ENTRY_INVALID = 0,
+ DESKTOP_ENTRY_DESKTOP,
+ DESKTOP_ENTRY_DIRECTORY
+} DesktopEntryType;
+
+typedef struct DesktopEntry DesktopEntry;
+
+DesktopEntry* desktop_entry_new(const char* path);
+
+DesktopEntry* desktop_entry_ref(DesktopEntry* entry);
+DesktopEntry* desktop_entry_copy(DesktopEntry* entry);
+DesktopEntry* desktop_entry_reload(DesktopEntry* entry);
+void desktop_entry_unref(DesktopEntry* entry);
+
+DesktopEntryType desktop_entry_get_type(DesktopEntry* entry);
+const char* desktop_entry_get_path(DesktopEntry* entry);
+const char* desktop_entry_get_basename(DesktopEntry* entry);
+
+const char* desktop_entry_get_name(DesktopEntry* entry);
+const char* desktop_entry_get_generic_name(DesktopEntry* entry);
+const char* desktop_entry_get_full_name(DesktopEntry* entry);
+const char* desktop_entry_get_comment(DesktopEntry* entry);
+const char* desktop_entry_get_icon(DesktopEntry* entry);
+const char* desktop_entry_get_exec(DesktopEntry* entry);
+gboolean desktop_entry_get_launch_in_terminal(DesktopEntry* entry);
+
+gboolean desktop_entry_get_hidden(DesktopEntry* entry);
+gboolean desktop_entry_get_no_display(DesktopEntry* entry);
+gboolean desktop_entry_get_show_in_mate(DesktopEntry* entry);
+gboolean desktop_entry_get_tryexec_failed(DesktopEntry* entry);
+
+gboolean desktop_entry_has_categories(DesktopEntry* entry);
+gboolean desktop_entry_has_category(DesktopEntry* entry, const char* category);
+
+void desktop_entry_add_legacy_category(DesktopEntry* src);
+
+
+typedef struct DesktopEntrySet DesktopEntrySet;
+
+DesktopEntrySet* desktop_entry_set_new(void);
+DesktopEntrySet* desktop_entry_set_ref(DesktopEntrySet* set);
+void desktop_entry_set_unref(DesktopEntrySet* set);
+
+void desktop_entry_set_add_entry(DesktopEntrySet* set, DesktopEntry* entry, const char* file_id);
+DesktopEntry* desktop_entry_set_lookup(DesktopEntrySet* set, const char* file_id);
+int desktop_entry_set_get_count(DesktopEntrySet* set);
+
+void desktop_entry_set_union(DesktopEntrySet* set, DesktopEntrySet* with);
+void desktop_entry_set_intersection(DesktopEntrySet* set, DesktopEntrySet* with);
+void desktop_entry_set_subtract(DesktopEntrySet* set, DesktopEntrySet* other);
+void desktop_entry_set_swap_contents(DesktopEntrySet* a, DesktopEntrySet* b);
+
+typedef void (*DesktopEntrySetForeachFunc) (const char* file_id, DesktopEntry* entry, gpointer user_data);
+
+void desktop_entry_set_foreach(DesktopEntrySet* set, DesktopEntrySetForeachFunc func, gpointer user_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DESKTOP_ENTRIES_H__ */
diff --git a/libmenu/entry-directories.c b/libmenu/entry-directories.c
new file mode 100644
index 0000000..a442a65
--- /dev/null
+++ b/libmenu/entry-directories.c
@@ -0,0 +1,1105 @@
+/*
+ * Copyright (C) 2002 - 2004 Red Hat, 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.
+ */
+
+#include <config.h>
+
+#include "entry-directories.h"
+
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "menu-util.h"
+#include "menu-monitor.h"
+#include "canonicalize.h"
+
+typedef struct CachedDir CachedDir;
+typedef struct CachedDirMonitor CachedDirMonitor;
+
+struct EntryDirectory {
+ CachedDir* dir;
+ char* legacy_prefix;
+
+ guint entry_type: 2;
+ guint is_legacy: 1;
+ guint refcount: 24;
+};
+
+struct EntryDirectoryList {
+ int refcount;
+ int length;
+ GList* dirs;
+};
+
+struct CachedDir {
+ CachedDir* parent;
+ char* name;
+
+ GSList* entries;
+ GSList* subdirs;
+
+ MenuMonitor* dir_monitor;
+ GSList* monitors;
+
+ guint have_read_entries: 1;
+ guint deleted: 1;
+
+ guint references: 28;
+};
+
+struct CachedDirMonitor {
+ EntryDirectory* ed;
+ EntryDirectoryChangedFunc callback;
+ gpointer user_data;
+};
+
+static void cached_dir_free(CachedDir* dir);
+static gboolean cached_dir_load_entries_recursive(CachedDir* dir, const char* dirname);
+
+static void handle_cached_dir_changed(MenuMonitor* monitor, MenuMonitorEvent event, const char* path, CachedDir* dir);
+
+/*
+ * Entry directory cache
+ */
+
+static CachedDir* dir_cache = NULL;
+
+static CachedDir* cached_dir_new(const char *name)
+{
+ CachedDir* dir;
+
+ dir = g_new0(CachedDir, 1);
+
+ dir->name = g_strdup(name);
+
+ return dir;
+}
+
+static void cached_dir_free(CachedDir* dir)
+{
+ if (dir->dir_monitor)
+ {
+ menu_monitor_remove_notify (dir->dir_monitor,
+ (MenuMonitorNotifyFunc) handle_cached_dir_changed,
+ dir);
+ menu_monitor_unref (dir->dir_monitor);
+ dir->dir_monitor = NULL;
+ }
+
+ g_slist_foreach (dir->monitors, (GFunc) g_free, NULL);
+ g_slist_free (dir->monitors);
+ dir->monitors = NULL;
+
+ g_slist_foreach (dir->entries,
+ (GFunc) desktop_entry_unref,
+ NULL);
+ g_slist_free (dir->entries);
+ dir->entries = NULL;
+
+ g_slist_foreach (dir->subdirs,
+ (GFunc) cached_dir_free,
+ NULL);
+ g_slist_free (dir->subdirs);
+ dir->subdirs = NULL;
+
+ g_free (dir->name);
+ g_free (dir);
+}
+
+static inline CachedDir* find_subdir(CachedDir* dir, const char* subdir)
+{
+ GSList *tmp;
+
+ tmp = dir->subdirs;
+ while (tmp != NULL)
+ {
+ CachedDir *sub = tmp->data;
+
+ if (strcmp (sub->name, subdir) == 0)
+ return sub;
+
+ tmp = tmp->next;
+ }
+
+ return NULL;
+}
+
+static DesktopEntry* find_entry(CachedDir* dir, const char* basename)
+{
+ GSList *tmp;
+
+ tmp = dir->entries;
+ while (tmp != NULL)
+ {
+ if (strcmp (desktop_entry_get_basename (tmp->data), basename) == 0)
+ return tmp->data;
+
+ tmp = tmp->next;
+ }
+
+ return NULL;
+}
+
+static DesktopEntry* cached_dir_find_relative_path(CachedDir* dir, const char* relative_path)
+{
+ DesktopEntry *retval = NULL;
+ char **split;
+ int i;
+
+ split = g_strsplit (relative_path, "/", -1);
+
+ i = 0;
+ while (split[i] != NULL)
+ {
+ if (split[i + 1] != NULL)
+ {
+ if ((dir = find_subdir (dir, split[i])) == NULL)
+ break;
+ }
+ else
+ {
+ retval = find_entry (dir, split[i]);
+ break;
+ }
+
+ ++i;
+ }
+
+ g_strfreev (split);
+
+ return retval;
+}
+
+static CachedDir* cached_dir_lookup(const char* canonical)
+{
+ CachedDir *dir;
+ char **split;
+ int i;
+
+ if (dir_cache == NULL)
+ dir_cache = cached_dir_new ("/");
+ dir = dir_cache;
+
+ g_assert (canonical != NULL && canonical[0] == G_DIR_SEPARATOR);
+
+ menu_verbose ("Looking up cached dir \"%s\"\n", canonical);
+
+ split = g_strsplit (canonical + 1, "/", -1);
+
+ i = 0;
+ while (split[i] != NULL)
+ {
+ CachedDir *subdir;
+
+ if ((subdir = find_subdir (dir, split[i])) == NULL)
+ {
+ subdir = cached_dir_new (split[i]);
+ dir->subdirs = g_slist_prepend (dir->subdirs, subdir);
+ subdir->parent = dir;
+ }
+
+ dir = subdir;
+
+ ++i;
+ }
+
+ g_strfreev (split);
+
+ g_assert (dir != NULL);
+
+ return dir;
+}
+
+static gboolean cached_dir_add_entry(CachedDir* dir, const char* basename, const char* path)
+{
+ DesktopEntry *entry;
+
+ entry = desktop_entry_new (path);
+ if (entry == NULL)
+ return FALSE;
+
+ dir->entries = g_slist_prepend (dir->entries, entry);
+
+ return TRUE;
+}
+
+static gboolean cached_dir_update_entry(CachedDir* dir, const char* basename, const char* path)
+{
+ GSList *tmp;
+
+ tmp = dir->entries;
+ while (tmp != NULL)
+ {
+ if (strcmp (desktop_entry_get_basename (tmp->data), basename) == 0)
+ {
+ if (!desktop_entry_reload (tmp->data))
+ {
+ dir->entries = g_slist_delete_link (dir->entries, tmp);
+ }
+
+ return TRUE;
+ }
+
+ tmp = tmp->next;
+ }
+
+ return cached_dir_add_entry (dir, basename, path);
+}
+
+static gboolean cached_dir_remove_entry(CachedDir* dir, const char* basename)
+{
+ GSList *tmp;
+
+ tmp = dir->entries;
+ while (tmp != NULL)
+ {
+ if (strcmp (desktop_entry_get_basename (tmp->data), basename) == 0)
+ {
+ desktop_entry_unref (tmp->data);
+ dir->entries = g_slist_delete_link (dir->entries, tmp);
+ return TRUE;
+ }
+
+ tmp = tmp->next;
+ }
+
+ return FALSE;
+}
+
+static gboolean cached_dir_add_subdir(CachedDir* dir, const char* basename, const char* path)
+{
+ CachedDir *subdir;
+
+ subdir = find_subdir (dir, basename);
+
+ if (subdir != NULL)
+ {
+ subdir->deleted = FALSE;
+ return TRUE;
+ }
+
+ subdir = cached_dir_new (basename);
+
+ if (!cached_dir_load_entries_recursive (subdir, path))
+ {
+ cached_dir_free (subdir);
+ return FALSE;
+ }
+
+ menu_verbose ("Caching dir \"%s\"\n", basename);
+
+ subdir->parent = dir;
+ dir->subdirs = g_slist_prepend (dir->subdirs, subdir);
+
+ return TRUE;
+}
+
+static gboolean cached_dir_remove_subdir(CachedDir* dir, const char* basename)
+{
+ CachedDir *subdir;
+
+ subdir = find_subdir (dir, basename);
+
+ if (subdir != NULL)
+ {
+ subdir->deleted = TRUE;
+
+ if (subdir->references == 0)
+ {
+ cached_dir_free (subdir);
+ dir->subdirs = g_slist_remove (dir->subdirs, subdir);
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void cached_dir_invoke_monitors(CachedDir* dir)
+{
+ GSList *tmp;
+
+ tmp = dir->monitors;
+ while (tmp != NULL)
+ {
+ CachedDirMonitor *monitor = tmp->data;
+ GSList *next = tmp->next;
+
+ monitor->callback (monitor->ed, monitor->user_data);
+
+ tmp = next;
+ }
+
+ if (dir->parent)
+ {
+ cached_dir_invoke_monitors (dir->parent);
+ }
+}
+
+static void handle_cached_dir_changed (MenuMonitor* monitor, MenuMonitorEvent event, const char* path, CachedDir* dir)
+{
+ gboolean handled = FALSE;
+ char *basename;
+ char *dirname;
+
+ menu_verbose ("'%s' notified of '%s' %s - invalidating cache\n",
+ dir->name,
+ path,
+ event == MENU_MONITOR_EVENT_CREATED ? ("created") :
+ event == MENU_MONITOR_EVENT_DELETED ? ("deleted") : ("changed"));
+
+ dirname = g_path_get_dirname (path);
+ basename = g_path_get_basename (path);
+
+ dir = cached_dir_lookup (dirname);
+
+ if (g_str_has_suffix (basename, ".desktop") ||
+ g_str_has_suffix (basename, ".directory"))
+ {
+ switch (event)
+ {
+ case MENU_MONITOR_EVENT_CREATED:
+ case MENU_MONITOR_EVENT_CHANGED:
+ handled = cached_dir_update_entry (dir, basename, path);
+ break;
+
+ case MENU_MONITOR_EVENT_DELETED:
+ handled = cached_dir_remove_entry (dir, basename);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+ else /* Try recursing */
+ {
+ switch (event)
+ {
+ case MENU_MONITOR_EVENT_CREATED:
+ handled = cached_dir_add_subdir (dir, basename, path);
+ break;
+
+ case MENU_MONITOR_EVENT_CHANGED:
+ break;
+
+ case MENU_MONITOR_EVENT_DELETED:
+ handled = cached_dir_remove_subdir (dir, basename);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+
+ g_free (basename);
+ g_free (dirname);
+
+ if (handled)
+ {
+ /* CHANGED events don't change the set of desktop entries */
+ if (event == MENU_MONITOR_EVENT_CREATED || event == MENU_MONITOR_EVENT_DELETED)
+ {
+ _entry_directory_list_empty_desktop_cache ();
+ }
+
+ cached_dir_invoke_monitors (dir);
+ }
+}
+
+static void cached_dir_ensure_monitor(CachedDir* dir, const char* dirname)
+{
+ if (dir->dir_monitor == NULL)
+ {
+ dir->dir_monitor = menu_get_directory_monitor (dirname);
+ menu_monitor_add_notify (dir->dir_monitor,
+ (MenuMonitorNotifyFunc) handle_cached_dir_changed,
+ dir);
+ }
+}
+
+static gboolean cached_dir_load_entries_recursive(CachedDir* dir, const char* dirname)
+{
+ DIR *dp;
+ struct dirent *dent;
+ GString *fullpath;
+ gsize fullpath_len;
+
+ g_assert (dir != NULL);
+
+ if (dir->have_read_entries)
+ return TRUE;
+
+ menu_verbose ("Attempting to read entries from %s (full path %s)\n",
+ dir->name, dirname);
+
+ dp = opendir (dirname);
+ if (dp == NULL)
+ {
+ menu_verbose ("Unable to list directory \"%s\"\n",
+ dirname);
+ return FALSE;
+ }
+
+ cached_dir_ensure_monitor (dir, dirname);
+
+ fullpath = g_string_new (dirname);
+ if (fullpath->str[fullpath->len - 1] != G_DIR_SEPARATOR)
+ g_string_append_c (fullpath, G_DIR_SEPARATOR);
+
+ fullpath_len = fullpath->len;
+
+ while ((dent = readdir (dp)) != NULL)
+ {
+ /* ignore . and .. */
+ if (dent->d_name[0] == '.' &&
+ (dent->d_name[1] == '\0' ||
+ (dent->d_name[1] == '.' &&
+ dent->d_name[2] == '\0')))
+ continue;
+
+ g_string_append (fullpath, dent->d_name);
+
+ if (g_str_has_suffix (dent->d_name, ".desktop") ||
+ g_str_has_suffix (dent->d_name, ".directory"))
+ {
+ cached_dir_add_entry (dir, dent->d_name, fullpath->str);
+ }
+ else /* Try recursing */
+ {
+ cached_dir_add_subdir (dir, dent->d_name, fullpath->str);
+ }
+
+ g_string_truncate (fullpath, fullpath_len);
+ }
+
+ closedir (dp);
+
+ g_string_free (fullpath, TRUE);
+
+ dir->have_read_entries = TRUE;
+
+ return TRUE;
+}
+
+static void cached_dir_add_monitor(CachedDir* dir, EntryDirectory* ed, EntryDirectoryChangedFunc callback, gpointer user_data)
+{
+ CachedDirMonitor *monitor;
+ GSList *tmp;
+
+ tmp = dir->monitors;
+ while (tmp != NULL)
+ {
+ monitor = tmp->data;
+
+ if (monitor->ed == ed &&
+ monitor->callback == callback &&
+ monitor->user_data == user_data)
+ break;
+
+ tmp = tmp->next;
+ }
+
+ if (tmp == NULL)
+ {
+ monitor = g_new0 (CachedDirMonitor, 1);
+ monitor->ed = ed;
+ monitor->callback = callback;
+ monitor->user_data = user_data;
+
+ dir->monitors = g_slist_append (dir->monitors, monitor);
+ }
+}
+
+static void cached_dir_remove_monitor(CachedDir* dir, EntryDirectory* ed, EntryDirectoryChangedFunc callback, gpointer user_data)
+{
+ GSList *tmp;
+
+ tmp = dir->monitors;
+ while (tmp != NULL)
+ {
+ CachedDirMonitor *monitor = tmp->data;
+ GSList *next = tmp->next;
+
+ if (monitor->ed == ed &&
+ monitor->callback == callback &&
+ monitor->user_data == user_data)
+ {
+ dir->monitors = g_slist_delete_link (dir->monitors, tmp);
+ g_free (monitor);
+ }
+
+ tmp = next;
+ }
+}
+
+static void cached_dir_add_reference(CachedDir* dir)
+{
+ dir->references++;
+
+ if (dir->parent != NULL)
+ {
+ cached_dir_add_reference (dir->parent);
+ }
+}
+
+static void cached_dir_remove_reference(CachedDir* dir)
+{
+ CachedDir *parent;
+
+ parent = dir->parent;
+
+ if (--dir->references == 0 && dir->deleted)
+ {
+ if (dir->parent != NULL)
+ {
+ GSList *tmp;
+
+ tmp = parent->subdirs;
+ while (tmp != NULL)
+ {
+ CachedDir *subdir = tmp->data;
+
+ if (!strcmp (subdir->name, dir->name))
+ {
+ parent->subdirs = g_slist_delete_link (parent->subdirs, tmp);
+ break;
+ }
+
+ tmp = tmp->next;
+ }
+ }
+
+ cached_dir_free (dir);
+ }
+
+ if (parent != NULL)
+ {
+ cached_dir_remove_reference (parent);
+ }
+}
+
+/*
+ * Entry directories
+ */
+
+static EntryDirectory* entry_directory_new_full(DesktopEntryType entry_type, const char* path, gboolean is_legacy, const char* legacy_prefix)
+{
+ EntryDirectory *ed;
+ char *canonical;
+
+ menu_verbose ("Loading entry directory \"%s\" (legacy %s)\n",
+ path,
+ is_legacy ? "<yes>" : "<no>");
+
+ canonical = menu_canonicalize_file_name (path, FALSE);
+ if (canonical == NULL)
+ {
+ menu_verbose ("Failed to canonicalize \"%s\": %s\n",
+ path, g_strerror (errno));
+ return NULL;
+ }
+
+ ed = g_new0 (EntryDirectory, 1);
+
+ ed->dir = cached_dir_lookup (canonical);
+ g_assert (ed->dir != NULL);
+
+ cached_dir_add_reference (ed->dir);
+ cached_dir_load_entries_recursive (ed->dir, canonical);
+
+ ed->legacy_prefix = g_strdup (legacy_prefix);
+ ed->entry_type = entry_type;
+ ed->is_legacy = is_legacy != FALSE;
+ ed->refcount = 1;
+
+ g_free (canonical);
+
+ return ed;
+}
+
+EntryDirectory* entry_directory_new(DesktopEntryType entry_type, const char* path)
+{
+ return entry_directory_new_full (entry_type, path, FALSE, NULL);
+}
+
+EntryDirectory* entry_directory_new_legacy(DesktopEntryType entry_type, const char* path, const char* legacy_prefix)
+{
+ return entry_directory_new_full(entry_type, path, TRUE, legacy_prefix);
+}
+
+EntryDirectory* entry_directory_ref(EntryDirectory* ed)
+{
+ g_return_val_if_fail(ed != NULL, NULL);
+ g_return_val_if_fail(ed->refcount > 0, NULL);
+
+ ed->refcount++;
+
+ return ed;
+}
+
+void entry_directory_unref(EntryDirectory* ed)
+{
+ g_return_if_fail (ed != NULL);
+ g_return_if_fail (ed->refcount > 0);
+
+ if (--ed->refcount == 0)
+ {
+ cached_dir_remove_reference (ed->dir);
+
+ ed->dir = NULL;
+ ed->entry_type = DESKTOP_ENTRY_INVALID;
+ ed->is_legacy = FALSE;
+
+ g_free (ed->legacy_prefix);
+ ed->legacy_prefix = NULL;
+
+ g_free (ed);
+ }
+}
+
+static void entry_directory_add_monitor(EntryDirectory* ed, EntryDirectoryChangedFunc callback, gpointer user_data)
+{
+ cached_dir_add_monitor (ed->dir, ed, callback, user_data);
+}
+
+static void entry_directory_remove_monitor(EntryDirectory* ed, EntryDirectoryChangedFunc callback, gpointer user_data)
+{
+ cached_dir_remove_monitor (ed->dir, ed, callback, user_data);
+}
+
+static DesktopEntry* entry_directory_get_directory(EntryDirectory* ed, const char* relative_path)
+{
+ DesktopEntry *entry;
+
+ if (ed->entry_type != DESKTOP_ENTRY_DIRECTORY)
+ return NULL;
+
+ entry = cached_dir_find_relative_path (ed->dir, relative_path);
+ if (entry == NULL || desktop_entry_get_type (entry) != DESKTOP_ENTRY_DIRECTORY)
+ return NULL;
+
+ return desktop_entry_ref (entry);
+}
+
+static char* get_desktop_file_id_from_path(EntryDirectory* ed, DesktopEntryType entry_type, const char* relative_path)
+{
+ char *retval;
+
+ retval = NULL;
+
+ if (entry_type == DESKTOP_ENTRY_DESKTOP)
+ {
+ if (!ed->is_legacy)
+ {
+ retval = g_strdelimit (g_strdup (relative_path), "/", '-');
+ }
+ else
+ {
+ char *basename;
+
+ basename = g_path_get_basename (relative_path);
+
+ if (ed->legacy_prefix)
+ {
+ retval = g_strjoin ("-", ed->legacy_prefix, basename, NULL);
+ g_free (basename);
+ }
+ else
+ {
+ retval = basename;
+ }
+ }
+ }
+ else
+ {
+ retval = g_strdup (relative_path);
+ }
+
+ return retval;
+}
+
+typedef gboolean (*EntryDirectoryForeachFunc) (EntryDirectory* ed, DesktopEntry* entry, const char* file_id, DesktopEntrySet* set, gpointer user_data);
+
+static gboolean entry_directory_foreach_recursive(EntryDirectory* ed, CachedDir* cd, GString* relative_path, EntryDirectoryForeachFunc func, DesktopEntrySet* set, gpointer user_data)
+{
+ GSList *tmp;
+ int relative_path_len;
+
+ if (cd->deleted)
+ return TRUE;
+
+ relative_path_len = relative_path->len;
+
+ tmp = cd->entries;
+ while (tmp != NULL)
+ {
+ DesktopEntry *entry = tmp->data;
+
+ if (desktop_entry_get_type (entry) == ed->entry_type)
+ {
+ gboolean ret;
+ char *file_id;
+
+ g_string_append (relative_path,
+ desktop_entry_get_basename (entry));
+
+ file_id = get_desktop_file_id_from_path (ed,
+ ed->entry_type,
+ relative_path->str);
+
+ ret = func (ed, entry, file_id, set, user_data);
+
+ g_free (file_id);
+
+ g_string_truncate (relative_path, relative_path_len);
+
+ if (!ret)
+ return FALSE;
+ }
+
+ tmp = tmp->next;
+ }
+
+ tmp = cd->subdirs;
+ while (tmp != NULL)
+ {
+ CachedDir *subdir = tmp->data;
+
+ g_string_append (relative_path, subdir->name);
+ g_string_append_c (relative_path, G_DIR_SEPARATOR);
+
+ if (!entry_directory_foreach_recursive (ed,
+ subdir,
+ relative_path,
+ func,
+ set,
+ user_data))
+ return FALSE;
+
+ g_string_truncate (relative_path, relative_path_len);
+
+ tmp = tmp->next;
+ }
+
+ return TRUE;
+}
+
+static void entry_directory_foreach(EntryDirectory* ed, EntryDirectoryForeachFunc func, DesktopEntrySet* set, gpointer user_data)
+{
+ GString *path;
+
+ path = g_string_new (NULL);
+
+ entry_directory_foreach_recursive (ed,
+ ed->dir,
+ path,
+ func,
+ set,
+ user_data);
+
+ g_string_free (path, TRUE);
+}
+
+void entry_directory_get_flat_contents(EntryDirectory* ed, DesktopEntrySet* desktop_entries, DesktopEntrySet* directory_entries, GSList** subdirs)
+{
+ GSList *tmp;
+
+ if (subdirs)
+ *subdirs = NULL;
+
+ tmp = ed->dir->entries;
+ while (tmp != NULL)
+ {
+ DesktopEntry *entry = tmp->data;
+ const char *basename;
+
+ basename = desktop_entry_get_basename (entry);
+
+ if (desktop_entries &&
+ desktop_entry_get_type (entry) == DESKTOP_ENTRY_DESKTOP)
+ {
+ char *file_id;
+
+ file_id = get_desktop_file_id_from_path (ed,
+ DESKTOP_ENTRY_DESKTOP,
+ basename);
+
+ desktop_entry_set_add_entry (desktop_entries,
+ entry,
+ file_id);
+
+ g_free (file_id);
+ }
+
+ if (directory_entries &&
+ desktop_entry_get_type (entry) == DESKTOP_ENTRY_DIRECTORY)
+ {
+ desktop_entry_set_add_entry (directory_entries,
+ entry,
+ basename);
+ }
+
+ tmp = tmp->next;
+ }
+
+ if (subdirs)
+ {
+ tmp = ed->dir->subdirs;
+ while (tmp != NULL)
+ {
+ CachedDir *cd = tmp->data;
+
+ if (!cd->deleted)
+ {
+ *subdirs = g_slist_prepend (*subdirs, g_strdup (cd->name));
+ }
+
+ tmp = tmp->next;
+ }
+ }
+
+ if (subdirs)
+ *subdirs = g_slist_reverse (*subdirs);
+}
+
+/*
+ * Entry directory lists
+ */
+
+EntryDirectoryList* entry_directory_list_new(void)
+{
+ EntryDirectoryList *list;
+
+ list = g_new0 (EntryDirectoryList, 1);
+
+ list->refcount = 1;
+ list->dirs = NULL;
+ list->length = 0;
+
+ return list;
+}
+
+EntryDirectoryList* entry_directory_list_ref(EntryDirectoryList* list)
+{
+ g_return_val_if_fail (list != NULL, NULL);
+ g_return_val_if_fail (list->refcount > 0, NULL);
+
+ list->refcount += 1;
+
+ return list;
+}
+
+void entry_directory_list_unref(EntryDirectoryList* list)
+{
+ g_return_if_fail (list != NULL);
+ g_return_if_fail (list->refcount > 0);
+
+ list->refcount -= 1;
+ if (list->refcount == 0)
+ {
+ g_list_foreach (list->dirs, (GFunc) entry_directory_unref, NULL);
+ g_list_free (list->dirs);
+ list->dirs = NULL;
+ list->length = 0;
+ g_free (list);
+ }
+}
+
+void entry_directory_list_prepend(EntryDirectoryList* list, EntryDirectory* ed)
+{
+ list->length += 1;
+ list->dirs = g_list_prepend (list->dirs,
+ entry_directory_ref (ed));
+}
+
+int entry_directory_list_get_length(EntryDirectoryList* list)
+{
+ return list->length;
+}
+
+void entry_directory_list_append_list(EntryDirectoryList* list, EntryDirectoryList* to_append)
+{
+ GList *tmp;
+ GList *new_dirs = NULL;
+
+ if (to_append->length == 0)
+ return;
+
+ tmp = to_append->dirs;
+ while (tmp != NULL)
+ {
+ list->length += 1;
+ new_dirs = g_list_prepend (new_dirs,
+ entry_directory_ref (tmp->data));
+
+ tmp = tmp->next;
+ }
+
+ new_dirs = g_list_reverse (new_dirs);
+ list->dirs = g_list_concat (list->dirs, new_dirs);
+}
+
+DesktopEntry* entry_directory_list_get_directory(EntryDirectoryList *list, const char* relative_path)
+{
+ DesktopEntry *retval = NULL;
+ GList *tmp;
+
+ tmp = list->dirs;
+ while (tmp != NULL)
+ {
+ if ((retval = entry_directory_get_directory (tmp->data, relative_path)) != NULL)
+ break;
+
+ tmp = tmp->next;
+ }
+
+ return retval;
+}
+
+gboolean _entry_directory_list_compare(const EntryDirectoryList* a, const EntryDirectoryList* b)
+{
+ GList *al, *bl;
+
+ if (a == NULL && b == NULL)
+ return TRUE;
+
+ if ((a == NULL || b == NULL))
+ return FALSE;
+
+ if (a->length != b->length)
+ return FALSE;
+
+ al = a->dirs; bl = b->dirs;
+ while (al && bl && al->data == bl->data)
+ {
+ al = al->next;
+ bl = bl->next;
+ }
+
+ return (al == NULL && bl == NULL);
+}
+
+static gboolean get_all_func(EntryDirectory* ed, DesktopEntry* entry, const char* file_id, DesktopEntrySet* set, gpointer user_data)
+{
+ if (ed->is_legacy && !desktop_entry_has_categories (entry))
+ {
+ entry = desktop_entry_copy (entry);
+ desktop_entry_add_legacy_category (entry);
+ }
+ else
+ {
+ entry = desktop_entry_ref (entry);
+ }
+
+ desktop_entry_set_add_entry (set, entry, file_id);
+ desktop_entry_unref (entry);
+
+ return TRUE;
+}
+
+static DesktopEntrySet* entry_directory_last_set = NULL;
+static EntryDirectoryList* entry_directory_last_list = NULL;
+
+void _entry_directory_list_empty_desktop_cache(void)
+{
+ if (entry_directory_last_set != NULL)
+ desktop_entry_set_unref (entry_directory_last_set);
+ entry_directory_last_set = NULL;
+
+ if (entry_directory_last_list != NULL)
+ entry_directory_list_unref (entry_directory_last_list);
+ entry_directory_last_list = NULL;
+}
+
+DesktopEntrySet* _entry_directory_list_get_all_desktops(EntryDirectoryList* list)
+{
+ GList *tmp;
+ DesktopEntrySet *set;
+
+ /* The only tricky thing here is that desktop files later
+ * in the search list with the same relative path
+ * are "hidden" by desktop files earlier in the path,
+ * so we have to do the earlier files first causing
+ * the later files to replace the earlier files
+ * in the DesktopEntrySet
+ *
+ * We go from the end of the list so we can just
+ * g_hash_table_replace and not have to do two
+ * hash lookups (check for existing entry, then insert new
+ * entry)
+ */
+
+ /* This method is -extremely- slow, so we have a simple
+ one-entry cache here */
+ if (_entry_directory_list_compare (list, entry_directory_last_list))
+ {
+ menu_verbose (" Hit desktop list (%p) cache\n", list);
+ return desktop_entry_set_ref (entry_directory_last_set);
+ }
+
+ if (entry_directory_last_set != NULL)
+ desktop_entry_set_unref (entry_directory_last_set);
+ if (entry_directory_last_list != NULL)
+ entry_directory_list_unref (entry_directory_last_list);
+
+ set = desktop_entry_set_new ();
+ menu_verbose (" Storing all of list %p in set %p\n",
+ list, set);
+
+ tmp = g_list_last (list->dirs);
+ while (tmp != NULL)
+ {
+ entry_directory_foreach (tmp->data, get_all_func, set, NULL);
+
+ tmp = tmp->prev;
+ }
+
+ entry_directory_last_list = entry_directory_list_ref (list);
+ entry_directory_last_set = desktop_entry_set_ref (set);
+
+ return set;
+}
+
+void entry_directory_list_add_monitors(EntryDirectoryList* list, EntryDirectoryChangedFunc callback, gpointer user_data)
+{
+ GList *tmp;
+
+ tmp = list->dirs;
+ while (tmp != NULL)
+ {
+ entry_directory_add_monitor (tmp->data, callback, user_data);
+ tmp = tmp->next;
+ }
+}
+
+void entry_directory_list_remove_monitors(EntryDirectoryList* list, EntryDirectoryChangedFunc callback, gpointer user_data)
+{
+ GList *tmp;
+
+ tmp = list->dirs;
+ while (tmp != NULL)
+ {
+ entry_directory_remove_monitor (tmp->data, callback, user_data);
+ tmp = tmp->next;
+ }
+}
diff --git a/libmenu/entry-directories.h b/libmenu/entry-directories.h
new file mode 100644
index 0000000..3cc4d9b
--- /dev/null
+++ b/libmenu/entry-directories.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2002 - 2004 Red Hat, 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 __ENTRY_DIRECTORIES_H__
+#define __ENTRY_DIRECTORIES_H__
+
+#include <glib.h>
+#include "desktop-entries.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct EntryDirectory EntryDirectory;
+
+typedef void (*EntryDirectoryChangedFunc) (EntryDirectory* ed, gpointer user_data);
+
+EntryDirectory* entry_directory_new(DesktopEntryType entry_type, const char* path);
+EntryDirectory* entry_directory_new_legacy(DesktopEntryType entry_type, const char* path, const char* legacy_prefix);
+
+EntryDirectory* entry_directory_ref(EntryDirectory* ed);
+void entry_directory_unref(EntryDirectory* ed);
+
+void entry_directory_get_flat_contents(EntryDirectory* ed, DesktopEntrySet* desktop_entries, DesktopEntrySet* directory_entries, GSList** subdirs);
+
+
+typedef struct EntryDirectoryList EntryDirectoryList;
+
+EntryDirectoryList* entry_directory_list_new(void);
+EntryDirectoryList* entry_directory_list_ref(EntryDirectoryList* list);
+void entry_directory_list_unref(EntryDirectoryList* list);
+
+int entry_directory_list_get_length(EntryDirectoryList* list);
+gboolean _entry_directory_list_compare(const EntryDirectoryList* a, const EntryDirectoryList* b);
+
+void entry_directory_list_prepend(EntryDirectoryList* list, EntryDirectory* ed);
+void entry_directory_list_append_list(EntryDirectoryList* list, EntryDirectoryList* to_append);
+
+void entry_directory_list_add_monitors(EntryDirectoryList* list, EntryDirectoryChangedFunc callback, gpointer user_data);
+void entry_directory_list_remove_monitors(EntryDirectoryList* list, EntryDirectoryChangedFunc callback, gpointer user_data);
+
+DesktopEntry* entry_directory_list_get_directory (EntryDirectoryList* list, const char* relative_path);
+
+DesktopEntrySet* _entry_directory_list_get_all_desktops(EntryDirectoryList* list);
+void _entry_directory_list_empty_desktop_cache(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ENTRY_DIRECTORIES_H__ */
diff --git a/libmenu/libmate-menu-uninstalled.pc.in b/libmenu/libmate-menu-uninstalled.pc.in
new file mode 100644
index 0000000..e0b0496
--- /dev/null
+++ b/libmenu/libmate-menu-uninstalled.pc.in
@@ -0,0 +1,11 @@
+
+Name: libmate-menu
+Description: Desktop Menu Specification Implementation
+Requires: glib-2.0
+Libs: ${pc_top_builddir}/${pcfiledir}/libmate-menu.la
+Cflags: -I${pc_top_builddir}/${pcfiledir}
diff --git a/libmenu/libmate-menu.pc.in b/libmenu/libmate-menu.pc.in
new file mode 100644
index 0000000..ab593d2
--- /dev/null
+++ b/libmenu/libmate-menu.pc.in
@@ -0,0 +1,11 @@
+
+Name: libmate-menu
+Description: Desktop Menu Specification Implementation
+Requires: glib-2.0
+Libs: -L${libdir} -lmate-menu
+Cflags: -I${includedir}/mate-menus
diff --git a/libmenu/matemenu-tree.c b/libmenu/matemenu-tree.c
new file mode 100644
index 0000000..683eb55
--- /dev/null
+++ b/libmenu/matemenu-tree.c
@@ -0,0 +1,4520 @@
+/*
+ * Copyright (C) 2003, 2004 Red Hat, 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.
+ */
+
+#include <config.h>
+
+#include "matemenu-tree.h"
+
+#include <string.h>
+#include <errno.h>
+
+#include "menu-layout.h"
+#include "menu-monitor.h"
+#include "menu-util.h"
+#include "canonicalize.h"
+
+/*
+ * FIXME: it might be useful to be able to construct a menu
+ * tree from a traditional directory based menu hierarchy
+ * too.
+ */
+
+typedef enum
+{
+ MATEMENU_TREE_ABSOLUTE = 0,
+ MATEMENU_TREE_BASENAME = 1
+} MateMenuTreeType;
+
+struct MateMenuTree
+{
+ MateMenuTreeType type;
+ guint refcount;
+
+ char *basename;
+ char *absolute_path;
+ char *canonical_path;
+
+ MateMenuTreeFlags flags;
+ MateMenuTreeSortKey sort_key;
+
+ GSList *menu_file_monitors;
+
+ MenuLayoutNode *layout;
+ MateMenuTreeDirectory *root;
+
+ GSList *monitors;
+
+ gpointer user_data;
+ GDestroyNotify dnotify;
+
+ guint canonical : 1;
+};
+
+typedef struct
+{
+ MateMenuTreeChangedFunc callback;
+ gpointer user_data;
+} MateMenuTreeMonitor;
+
+struct MateMenuTreeItem
+{
+ MateMenuTreeItemType type;
+
+ MateMenuTreeDirectory *parent;
+
+ gpointer user_data;
+ GDestroyNotify dnotify;
+
+ guint refcount;
+};
+
+struct MateMenuTreeDirectory
+{
+ MateMenuTreeItem item;
+
+ DesktopEntry *directory_entry;
+ char *name;
+
+ GSList *entries;
+ GSList *subdirs;
+
+ MenuLayoutValues default_layout_values;
+ GSList *default_layout_info;
+ GSList *layout_info;
+ GSList *contents;
+
+ guint only_unallocated : 1;
+ guint is_root : 1;
+ guint is_nodisplay : 1;
+ guint layout_pending_separator : 1;
+ guint preprocessed : 1;
+
+ /* 16 bits should be more than enough; G_MAXUINT16 means no inline header */
+ guint will_inline_header : 16;
+};
+
+typedef struct
+{
+ MateMenuTreeDirectory directory;
+
+ MateMenuTree *tree;
+} MateMenuTreeDirectoryRoot;
+
+struct MateMenuTreeEntry
+{
+ MateMenuTreeItem item;
+
+ DesktopEntry *desktop_entry;
+ char *desktop_file_id;
+
+ guint is_excluded : 1;
+ guint is_nodisplay : 1;
+};
+
+struct MateMenuTreeSeparator
+{
+ MateMenuTreeItem item;
+};
+
+struct MateMenuTreeHeader
+{
+ MateMenuTreeItem item;
+
+ MateMenuTreeDirectory *directory;
+};
+
+struct MateMenuTreeAlias
+{
+ MateMenuTreeItem item;
+
+ MateMenuTreeDirectory *directory;
+ MateMenuTreeItem *aliased_item;
+};
+
+static MateMenuTree *matemenu_tree_new (MateMenuTreeType type,
+ const char *menu_file,
+ gboolean canonical,
+ MateMenuTreeFlags flags);
+static void matemenu_tree_load_layout (MateMenuTree *tree);
+static void matemenu_tree_force_reload (MateMenuTree *tree);
+static void matemenu_tree_build_from_layout (MateMenuTree *tree);
+static void matemenu_tree_force_rebuild (MateMenuTree *tree);
+static void matemenu_tree_resolve_files (MateMenuTree *tree,
+ GHashTable *loaded_menu_files,
+ MenuLayoutNode *layout);
+static void matemenu_tree_force_recanonicalize (MateMenuTree *tree);
+static void matemenu_tree_invoke_monitors (MateMenuTree *tree);
+
+static void matemenu_tree_item_unref_and_unset_parent (gpointer itemp);
+
+/*
+ * The idea is that we cache the menu tree for either a given
+ * menu basename or an absolute menu path.
+ * If no files exist in $XDG_DATA_DIRS for the basename or the
+ * absolute path doesn't exist we just return (and cache) the
+ * empty menu tree.
+ * We also add a file monitor for the basename in each dir in
+ * $XDG_DATA_DIRS, or the absolute path to the menu file, and
+ * re-compute if there are any changes.
+ */
+
+static GHashTable *matemenu_tree_cache = NULL;
+
+static inline char *
+get_cache_key (MateMenuTree *tree,
+ MateMenuTreeFlags flags)
+{
+ const char *tree_name;
+
+ switch (tree->type)
+ {
+ case MATEMENU_TREE_ABSOLUTE:
+ tree_name = tree->canonical ? tree->canonical_path : tree->absolute_path;
+ break;
+
+ case MATEMENU_TREE_BASENAME:
+ tree_name = tree->basename;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return g_strdup_printf ("%s:0x%x", tree_name, flags);
+}
+
+static void
+matemenu_tree_add_to_cache (MateMenuTree *tree,
+ MateMenuTreeFlags flags)
+{
+ char *cache_key;
+
+ if (matemenu_tree_cache == NULL)
+ {
+ matemenu_tree_cache =
+ g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ }
+
+ cache_key = get_cache_key (tree, flags);
+
+ menu_verbose ("Adding menu tree to cache: %s\n", cache_key);
+
+ g_hash_table_replace (matemenu_tree_cache, cache_key, tree);
+}
+
+static void
+matemenu_tree_remove_from_cache (MateMenuTree *tree,
+ MateMenuTreeFlags flags)
+{
+ char *cache_key;
+
+ cache_key = get_cache_key (tree, flags);
+
+ menu_verbose ("Removing menu tree from cache: %s\n", cache_key);
+
+ g_hash_table_remove (matemenu_tree_cache, cache_key);
+
+ g_free (cache_key);
+
+ if (g_hash_table_size (matemenu_tree_cache) == 0)
+ {
+ g_hash_table_destroy (matemenu_tree_cache);
+ matemenu_tree_cache = NULL;
+
+ _entry_directory_list_empty_desktop_cache ();
+ }
+}
+
+static MateMenuTree *
+matemenu_tree_lookup_from_cache (const char *tree_name,
+ MateMenuTreeFlags flags)
+{
+ MateMenuTree *retval;
+ char *cache_key;
+
+ if (matemenu_tree_cache == NULL)
+ return NULL;
+
+ cache_key = g_strdup_printf ("%s:0x%x", tree_name, flags);
+
+ menu_verbose ("Looking up '%s' from menu cache\n", cache_key);
+
+ retval = g_hash_table_lookup (matemenu_tree_cache, cache_key);
+
+ g_free (cache_key);
+
+ return retval ? matemenu_tree_ref (retval) : NULL;
+}
+
+typedef enum
+{
+ MENU_FILE_MONITOR_INVALID = 0,
+ MENU_FILE_MONITOR_FILE,
+ MENU_FILE_MONITOR_NONEXISTENT_FILE,
+ MENU_FILE_MONITOR_DIRECTORY
+} MenuFileMonitorType;
+
+typedef struct
+{
+ MenuFileMonitorType type;
+ MenuMonitor *monitor;
+} MenuFileMonitor;
+
+static void
+handle_nonexistent_menu_file_changed (MenuMonitor *monitor,
+ MenuMonitorEvent event,
+ const char *path,
+ MateMenuTree *tree)
+{
+ if (event == MENU_MONITOR_EVENT_CHANGED ||
+ event == MENU_MONITOR_EVENT_CREATED)
+ {
+ menu_verbose ("\"%s\" %s, marking tree for recanonicalization\n",
+ path,
+ event == MENU_MONITOR_EVENT_CREATED ? "created" : "changed");
+
+ matemenu_tree_force_recanonicalize (tree);
+ matemenu_tree_invoke_monitors (tree);
+ }
+}
+
+static void
+handle_menu_file_changed (MenuMonitor *monitor,
+ MenuMonitorEvent event,
+ const char *path,
+ MateMenuTree *tree)
+{
+ menu_verbose ("\"%s\" %s, marking tree for recanicalization\n",
+ path,
+ event == MENU_MONITOR_EVENT_CREATED ? "created" :
+ event == MENU_MONITOR_EVENT_CHANGED ? "changed" : "deleted");
+
+ matemenu_tree_force_recanonicalize (tree);
+ matemenu_tree_invoke_monitors (tree);
+}
+
+static void
+handle_menu_file_directory_changed (MenuMonitor *monitor,
+ MenuMonitorEvent event,
+ const char *path,
+ MateMenuTree *tree)
+{
+ if (!g_str_has_suffix (path, ".menu"))
+ return;
+
+ menu_verbose ("\"%s\" %s, marking tree for recanicalization\n",
+ path,
+ event == MENU_MONITOR_EVENT_CREATED ? "created" :
+ event == MENU_MONITOR_EVENT_CHANGED ? "changed" : "deleted");
+
+ matemenu_tree_force_recanonicalize (tree);
+ matemenu_tree_invoke_monitors (tree);
+}
+
+static void
+matemenu_tree_add_menu_file_monitor (MateMenuTree *tree,
+ const char *path,
+ MenuFileMonitorType type)
+{
+ MenuFileMonitor *monitor;
+
+ monitor = g_new0 (MenuFileMonitor, 1);
+
+ monitor->type = type;
+
+ switch (type)
+ {
+ case MENU_FILE_MONITOR_FILE:
+ menu_verbose ("Adding a menu file monitor for \"%s\"\n", path);
+
+ monitor->monitor = menu_get_file_monitor (path);
+ menu_monitor_add_notify (monitor->monitor,
+ (MenuMonitorNotifyFunc) handle_menu_file_changed,
+ tree);
+ break;
+
+ case MENU_FILE_MONITOR_NONEXISTENT_FILE:
+ menu_verbose ("Adding a menu file monitor for non-existent \"%s\"\n", path);
+
+ monitor->monitor = menu_get_file_monitor (path);
+ menu_monitor_add_notify (monitor->monitor,
+ (MenuMonitorNotifyFunc) handle_nonexistent_menu_file_changed,
+ tree);
+ break;
+
+ case MENU_FILE_MONITOR_DIRECTORY:
+ menu_verbose ("Adding a menu directory monitor for \"%s\"\n", path);
+
+ monitor->monitor = menu_get_directory_monitor (path);
+ menu_monitor_add_notify (monitor->monitor,
+ (MenuMonitorNotifyFunc) handle_menu_file_directory_changed,
+ tree);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ tree->menu_file_monitors = g_slist_prepend (tree->menu_file_monitors, monitor);
+}
+
+static void
+remove_menu_file_monitor (MenuFileMonitor *monitor,
+ MateMenuTree *tree)
+{
+ switch (monitor->type)
+ {
+ case MENU_FILE_MONITOR_FILE:
+ menu_monitor_remove_notify (monitor->monitor,
+ (MenuMonitorNotifyFunc) handle_menu_file_changed,
+ tree);
+ break;
+
+ case MENU_FILE_MONITOR_NONEXISTENT_FILE:
+ menu_monitor_remove_notify (monitor->monitor,
+ (MenuMonitorNotifyFunc) handle_nonexistent_menu_file_changed,
+ tree);
+ break;
+
+ case MENU_FILE_MONITOR_DIRECTORY:
+ menu_monitor_remove_notify (monitor->monitor,
+ (MenuMonitorNotifyFunc) handle_menu_file_directory_changed,
+ tree);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ menu_monitor_unref (monitor->monitor);
+ monitor->monitor = NULL;
+
+ monitor->type = MENU_FILE_MONITOR_INVALID;
+
+ g_free (monitor);
+}
+
+static void
+matemenu_tree_remove_menu_file_monitors (MateMenuTree *tree)
+{
+ menu_verbose ("Removing all menu file monitors\n");
+
+ g_slist_foreach (tree->menu_file_monitors,
+ (GFunc) remove_menu_file_monitor,
+ tree);
+ g_slist_free (tree->menu_file_monitors);
+ tree->menu_file_monitors = NULL;
+}
+
+static MateMenuTree *
+matemenu_tree_lookup_absolute (const char *absolute,
+ MateMenuTreeFlags flags)
+{
+ MateMenuTree *tree;
+ gboolean canonical;
+ const char *canonical_path;
+ char *freeme;
+
+ menu_verbose ("Looking up absolute path in tree cache: \"%s\"\n", absolute);
+
+ if ((tree = matemenu_tree_lookup_from_cache (absolute, flags)) != NULL)
+ return tree;
+
+ canonical = TRUE;
+ canonical_path = freeme = menu_canonicalize_file_name (absolute, FALSE);
+ if (canonical_path == NULL)
+ {
+ menu_verbose ("Failed to canonicalize absolute menu path \"%s\": %s\n",
+ absolute, g_strerror (errno));
+ canonical = FALSE;
+ canonical_path = absolute;
+ }
+
+ if ((tree = matemenu_tree_lookup_from_cache (canonical_path, flags)) != NULL)
+ return tree;
+
+ tree = matemenu_tree_new (MATEMENU_TREE_ABSOLUTE, canonical_path, canonical, flags);
+
+ g_free (freeme);
+
+ return tree;
+}
+
+static MateMenuTree *
+matemenu_tree_lookup_basename (const char *basename,
+ MateMenuTreeFlags flags)
+{
+ MateMenuTree *tree;
+
+ menu_verbose ("Looking up menu file in tree cache: \"%s\"\n", basename);
+
+ if ((tree = matemenu_tree_lookup_from_cache (basename, flags)) != NULL)
+ return tree;
+
+ return matemenu_tree_new (MATEMENU_TREE_BASENAME, basename, FALSE, flags);
+}
+
+static gboolean
+canonicalize_basename_with_config_dir (MateMenuTree *tree,
+ const char *basename,
+ const char *config_dir)
+{
+ char *path;
+
+ path = g_build_filename (config_dir, "menus", basename, NULL);
+
+ tree->canonical_path = menu_canonicalize_file_name (path, FALSE);
+ if (tree->canonical_path)
+ {
+ tree->canonical = TRUE;
+ matemenu_tree_add_menu_file_monitor (tree,
+ tree->canonical_path,
+ MENU_FILE_MONITOR_FILE);
+ }
+ else
+ {
+ matemenu_tree_add_menu_file_monitor (tree,
+ path,
+ MENU_FILE_MONITOR_NONEXISTENT_FILE);
+ }
+
+ g_free (path);
+
+ return tree->canonical;
+}
+
+static void
+canonicalize_basename (MateMenuTree *tree,
+ const char *basename)
+{
+ if (!canonicalize_basename_with_config_dir (tree,
+ basename,
+ g_get_user_config_dir ()))
+ {
+ const char * const *system_config_dirs;
+ int i;
+
+ system_config_dirs = g_get_system_config_dirs ();
+
+ i = 0;
+ while (system_config_dirs[i] != NULL)
+ {
+ if (canonicalize_basename_with_config_dir (tree,
+ basename,
+ system_config_dirs[i]))
+ break;
+
+ ++i;
+ }
+ }
+}
+
+static gboolean matemenu_tree_canonicalize_path(MateMenuTree* tree)
+{
+ if (tree->canonical)
+ return TRUE;
+
+ g_assert(tree->canonical_path == NULL);
+
+ if (tree->type == MATEMENU_TREE_BASENAME)
+ {
+ matemenu_tree_remove_menu_file_monitors (tree);
+
+ if (strcmp(tree->basename, "mate-applications.menu") == 0 && g_getenv("XDG_MENU_PREFIX"))
+ {
+ char* prefixed_basename;
+ prefixed_basename = g_strdup_printf("%s%s", g_getenv("XDG_MENU_PREFIX"), tree->basename);
+ canonicalize_basename(tree, prefixed_basename);
+ g_free(prefixed_basename);
+ }
+
+ if (!tree->canonical)
+ canonicalize_basename(tree, tree->basename);
+
+ if (tree->canonical)
+ menu_verbose("Successfully looked up menu_file for \"%s\": %s\n", tree->basename, tree->canonical_path);
+ else
+ menu_verbose("Failed to look up menu_file for \"%s\"\n", tree->basename);
+ }
+ else /* if (tree->type == MATEMENU_TREE_ABSOLUTE) */
+ {
+ tree->canonical_path = menu_canonicalize_file_name(tree->absolute_path, FALSE);
+
+ if (tree->canonical_path != NULL)
+ {
+ menu_verbose("Successfully looked up menu_file for \"%s\": %s\n", tree->absolute_path, tree->canonical_path);
+
+ /*
+ * Replace the cache entry with the canonicalized version
+ */
+ matemenu_tree_remove_from_cache (tree, tree->flags);
+
+ matemenu_tree_remove_menu_file_monitors(tree);
+ matemenu_tree_add_menu_file_monitor(tree, tree->canonical_path, MENU_FILE_MONITOR_FILE);
+
+ tree->canonical = TRUE;
+
+ matemenu_tree_add_to_cache (tree, tree->flags);
+ }
+ else
+ {
+ menu_verbose("Failed to look up menu_file for \"%s\"\n", tree->absolute_path);
+ }
+ }
+
+ return tree->canonical;
+}
+
+static void
+matemenu_tree_force_recanonicalize (MateMenuTree *tree)
+{
+ matemenu_tree_remove_menu_file_monitors (tree);
+
+ if (tree->canonical)
+ {
+ matemenu_tree_force_reload (tree);
+
+ g_free (tree->canonical_path);
+ tree->canonical_path = NULL;
+
+ tree->canonical = FALSE;
+ }
+}
+
+MateMenuTree* matemenu_tree_lookup(const char* menu_file, MateMenuTreeFlags flags)
+{
+ MateMenuTree *retval;
+
+ g_return_val_if_fail (menu_file != NULL, NULL);
+
+ flags &= MATEMENU_TREE_FLAGS_MASK;
+
+ if (g_path_is_absolute (menu_file))
+ retval = matemenu_tree_lookup_absolute (menu_file, flags);
+ else
+ retval = matemenu_tree_lookup_basename (menu_file, flags);
+
+ g_assert (retval != NULL);
+
+ return retval;
+}
+
+static MateMenuTree *
+matemenu_tree_new (MateMenuTreeType type,
+ const char *menu_file,
+ gboolean canonical,
+ MateMenuTreeFlags flags)
+{
+ MateMenuTree *tree;
+
+ tree = g_new0 (MateMenuTree, 1);
+
+ tree->type = type;
+ tree->flags = flags;
+ tree->refcount = 1;
+
+ tree->sort_key = MATEMENU_TREE_SORT_NAME;
+
+ if (tree->type == MATEMENU_TREE_BASENAME)
+ {
+ g_assert (canonical == FALSE);
+ tree->basename = g_strdup (menu_file);
+ }
+ else
+ {
+ tree->canonical = canonical != FALSE;
+ tree->absolute_path = g_strdup (menu_file);
+
+ if (tree->canonical)
+ {
+ tree->canonical_path = g_strdup (menu_file);
+ matemenu_tree_add_menu_file_monitor (tree,
+ tree->canonical_path,
+ MENU_FILE_MONITOR_FILE);
+ }
+ else
+ {
+ matemenu_tree_add_menu_file_monitor (tree,
+ tree->absolute_path,
+ MENU_FILE_MONITOR_NONEXISTENT_FILE);
+ }
+ }
+
+ matemenu_tree_add_to_cache (tree, tree->flags);
+
+ return tree;
+}
+
+MateMenuTree *
+matemenu_tree_ref (MateMenuTree *tree)
+{
+ g_return_val_if_fail (tree != NULL, NULL);
+ g_return_val_if_fail (tree->refcount > 0, NULL);
+
+ tree->refcount++;
+
+ return tree;
+}
+
+void
+matemenu_tree_unref (MateMenuTree *tree)
+{
+ g_return_if_fail (tree != NULL);
+ g_return_if_fail (tree->refcount >= 1);
+
+ if (--tree->refcount > 0)
+ return;
+
+ if (tree->dnotify)
+ tree->dnotify (tree->user_data);
+ tree->user_data = NULL;
+ tree->dnotify = NULL;
+
+ matemenu_tree_remove_from_cache (tree, tree->flags);
+
+ matemenu_tree_force_recanonicalize (tree);
+
+ if (tree->basename != NULL)
+ g_free (tree->basename);
+ tree->basename = NULL;
+
+ if (tree->absolute_path != NULL)
+ g_free (tree->absolute_path);
+ tree->absolute_path = NULL;
+
+ g_slist_foreach (tree->monitors, (GFunc) g_free, NULL);
+ g_slist_free (tree->monitors);
+ tree->monitors = NULL;
+
+ g_free (tree);
+}
+
+void
+matemenu_tree_set_user_data (MateMenuTree *tree,
+ gpointer user_data,
+ GDestroyNotify dnotify)
+{
+ g_return_if_fail (tree != NULL);
+
+ if (tree->dnotify != NULL)
+ tree->dnotify (tree->user_data);
+
+ tree->dnotify = dnotify;
+ tree->user_data = user_data;
+}
+
+gpointer
+matemenu_tree_get_user_data (MateMenuTree *tree)
+{
+ g_return_val_if_fail (tree != NULL, NULL);
+
+ return tree->user_data;
+}
+
+const char *
+matemenu_tree_get_menu_file (MateMenuTree *tree)
+{
+ /* FIXME: this is horribly ugly. But it's done to keep the API. Would be bad
+ * to break the API only for a "const char *" => "char *" change. The other
+ * alternative is to leak the memory, which is bad too. */
+ static char *ugly_result_cache = NULL;
+
+ g_return_val_if_fail (tree != NULL, NULL);
+
+ /* we need to canonicalize the path so we actually find out the real menu
+ * file that is being used -- and take into account XDG_MENU_PREFIX */
+ if (!matemenu_tree_canonicalize_path (tree))
+ return NULL;
+
+ if (ugly_result_cache != NULL)
+ {
+ g_free (ugly_result_cache);
+ ugly_result_cache = NULL;
+ }
+
+ if (tree->type == MATEMENU_TREE_BASENAME)
+ {
+ ugly_result_cache = g_path_get_basename (tree->canonical_path);
+ return ugly_result_cache;
+ }
+ else
+ return tree->absolute_path;
+}
+
+MateMenuTreeDirectory *
+matemenu_tree_get_root_directory (MateMenuTree *tree)
+{
+ g_return_val_if_fail (tree != NULL, NULL);
+
+ if (!tree->root)
+ {
+ matemenu_tree_build_from_layout (tree);
+
+ if (!tree->root)
+ return NULL;
+ }
+
+ return matemenu_tree_item_ref (tree->root);
+}
+
+static MateMenuTreeDirectory *
+find_path (MateMenuTreeDirectory *directory,
+ const char *path)
+{
+ const char *name;
+ char *slash;
+ char *freeme;
+ GSList *tmp;
+
+ while (path[0] == G_DIR_SEPARATOR) path++;
+
+ if (path[0] == '\0')
+ return directory;
+
+ freeme = NULL;
+ slash = strchr (path, G_DIR_SEPARATOR);
+ if (slash)
+ {
+ name = freeme = g_strndup (path, slash - path);
+ path = slash + 1;
+ }
+ else
+ {
+ name = path;
+ path = NULL;
+ }
+
+ tmp = directory->contents;
+ while (tmp != NULL)
+ {
+ MateMenuTreeItem *item = tmp->data;
+
+ if (matemenu_tree_item_get_type (item) != MATEMENU_TREE_ITEM_DIRECTORY)
+ {
+ tmp = tmp->next;
+ continue;
+ }
+
+ if (!strcmp (name, MATEMENU_TREE_DIRECTORY (item)->name))
+ {
+ g_free (freeme);
+
+ if (path)
+ return find_path (MATEMENU_TREE_DIRECTORY (item), path);
+ else
+ return MATEMENU_TREE_DIRECTORY (item);
+ }
+
+ tmp = tmp->next;
+ }
+
+ g_free (freeme);
+
+ return NULL;
+}
+
+MateMenuTreeDirectory *
+matemenu_tree_get_directory_from_path (MateMenuTree *tree,
+ const char *path)
+{
+ MateMenuTreeDirectory *root;
+ MateMenuTreeDirectory *directory;
+
+ g_return_val_if_fail (tree != NULL, NULL);
+ g_return_val_if_fail (path != NULL, NULL);
+
+ if (path[0] != G_DIR_SEPARATOR)
+ return NULL;
+
+ if (!(root = matemenu_tree_get_root_directory (tree)))
+ return NULL;
+
+ directory = find_path (root, path);
+
+ matemenu_tree_item_unref (root);
+
+ return directory ? matemenu_tree_item_ref (directory) : NULL;
+}
+
+MateMenuTreeSortKey
+matemenu_tree_get_sort_key (MateMenuTree *tree)
+{
+ g_return_val_if_fail (tree != NULL, MATEMENU_TREE_SORT_NAME);
+ g_return_val_if_fail (tree->refcount > 0, MATEMENU_TREE_SORT_NAME);
+
+ return tree->sort_key;
+}
+
+void
+matemenu_tree_set_sort_key (MateMenuTree *tree,
+ MateMenuTreeSortKey sort_key)
+{
+ g_return_if_fail (tree != NULL);
+ g_return_if_fail (tree->refcount > 0);
+ g_return_if_fail (sort_key >= MATEMENU_TREE_SORT_FIRST);
+ g_return_if_fail (sort_key <= MATEMENU_TREE_SORT_LAST);
+
+ if (sort_key == tree->sort_key)
+ return;
+
+ tree->sort_key = sort_key;
+ matemenu_tree_force_rebuild (tree);
+}
+
+void
+matemenu_tree_add_monitor (MateMenuTree *tree,
+ MateMenuTreeChangedFunc callback,
+ gpointer user_data)
+{
+ MateMenuTreeMonitor *monitor;
+ GSList *tmp;
+
+ g_return_if_fail (tree != NULL);
+ g_return_if_fail (callback != NULL);
+
+ tmp = tree->monitors;
+ while (tmp != NULL)
+ {
+ monitor = tmp->data;
+
+ if (monitor->callback == callback &&
+ monitor->user_data == user_data)
+ break;
+
+ tmp = tmp->next;
+ }
+
+ if (tmp == NULL)
+ {
+ monitor = g_new0 (MateMenuTreeMonitor, 1);
+
+ monitor->callback = callback;
+ monitor->user_data = user_data;
+
+ tree->monitors = g_slist_append (tree->monitors, monitor);
+ }
+}
+
+void
+matemenu_tree_remove_monitor (MateMenuTree *tree,
+ MateMenuTreeChangedFunc callback,
+ gpointer user_data)
+{
+ GSList *tmp;
+
+ g_return_if_fail (tree != NULL);
+ g_return_if_fail (callback != NULL);
+
+ tmp = tree->monitors;
+ while (tmp != NULL)
+ {
+ MateMenuTreeMonitor *monitor = tmp->data;
+ GSList *next = tmp->next;
+
+ if (monitor->callback == callback &&
+ monitor->user_data == user_data)
+ {
+ tree->monitors = g_slist_delete_link (tree->monitors, tmp);
+ g_free (monitor);
+ }
+
+ tmp = next;
+ }
+}
+
+static void
+matemenu_tree_invoke_monitors (MateMenuTree *tree)
+{
+ GSList *tmp;
+
+ tmp = tree->monitors;
+ while (tmp != NULL)
+ {
+ MateMenuTreeMonitor *monitor = tmp->data;
+ GSList *next = tmp->next;
+
+ monitor->callback (tree, monitor->user_data);
+
+ tmp = next;
+ }
+}
+
+MateMenuTreeItemType
+matemenu_tree_item_get_type (MateMenuTreeItem *item)
+{
+ g_return_val_if_fail (item != NULL, 0);
+
+ return item->type;
+}
+
+MateMenuTreeDirectory *
+matemenu_tree_item_get_parent (MateMenuTreeItem *item)
+{
+ g_return_val_if_fail (item != NULL, NULL);
+
+ return item->parent ? matemenu_tree_item_ref (item->parent) : NULL;
+}
+
+static void
+matemenu_tree_item_set_parent (MateMenuTreeItem *item,
+ MateMenuTreeDirectory *parent)
+{
+ g_return_if_fail (item != NULL);
+
+ item->parent = parent;
+}
+
+GSList *
+matemenu_tree_directory_get_contents (MateMenuTreeDirectory *directory)
+{
+ GSList *retval;
+ GSList *tmp;
+
+ g_return_val_if_fail (directory != NULL, NULL);
+
+ retval = NULL;
+
+ tmp = directory->contents;
+ while (tmp != NULL)
+ {
+ retval = g_slist_prepend (retval,
+ matemenu_tree_item_ref (tmp->data));
+
+ tmp = tmp->next;
+ }
+
+ return g_slist_reverse (retval);
+}
+
+const char *
+matemenu_tree_directory_get_name (MateMenuTreeDirectory *directory)
+{
+ g_return_val_if_fail (directory != NULL, NULL);
+
+ if (!directory->directory_entry)
+ return directory->name;
+
+ return desktop_entry_get_name (directory->directory_entry);
+}
+
+const char *
+matemenu_tree_directory_get_comment (MateMenuTreeDirectory *directory)
+{
+ g_return_val_if_fail (directory != NULL, NULL);
+
+ if (!directory->directory_entry)
+ return NULL;
+
+ return desktop_entry_get_comment (directory->directory_entry);
+}
+
+const char* matemenu_tree_directory_get_icon(MateMenuTreeDirectory* directory)
+{
+ g_return_val_if_fail(directory != NULL, NULL);
+
+ if (!directory->directory_entry)
+ return NULL;
+
+ return desktop_entry_get_icon(directory->directory_entry);
+}
+
+const char *
+matemenu_tree_directory_get_desktop_file_path (MateMenuTreeDirectory *directory)
+{
+ g_return_val_if_fail (directory != NULL, NULL);
+
+ if (!directory->directory_entry)
+ return NULL;
+
+ return desktop_entry_get_path (directory->directory_entry);
+}
+
+const char *
+matemenu_tree_directory_get_menu_id (MateMenuTreeDirectory *directory)
+{
+ g_return_val_if_fail (directory != NULL, NULL);
+
+ return directory->name;
+}
+
+static void
+matemenu_tree_directory_set_tree (MateMenuTreeDirectory *directory,
+ MateMenuTree *tree)
+{
+ MateMenuTreeDirectoryRoot *root;
+
+ g_assert (directory != NULL);
+ g_assert (directory->is_root);
+
+ root = (MateMenuTreeDirectoryRoot *) directory;
+
+ root->tree = tree;
+}
+
+MateMenuTree *
+matemenu_tree_directory_get_tree (MateMenuTreeDirectory *directory)
+{
+ MateMenuTreeDirectoryRoot *root;
+
+ g_return_val_if_fail (directory != NULL, NULL);
+
+ while (MATEMENU_TREE_ITEM (directory)->parent != NULL)
+ directory = MATEMENU_TREE_DIRECTORY (MATEMENU_TREE_ITEM (directory)->parent);
+
+ if (!directory->is_root)
+ return NULL;
+
+ root = (MateMenuTreeDirectoryRoot *) directory;
+
+ if (root->tree)
+ matemenu_tree_ref (root->tree);
+
+ return root->tree;
+}
+
+gboolean
+matemenu_tree_directory_get_is_nodisplay (MateMenuTreeDirectory *directory)
+{
+ g_return_val_if_fail (directory != NULL, FALSE);
+
+ return directory->is_nodisplay;
+}
+
+static void
+append_directory_path (MateMenuTreeDirectory *directory,
+ GString *path)
+{
+
+ if (!directory->item.parent)
+ {
+ g_string_append_c (path, G_DIR_SEPARATOR);
+ return;
+ }
+
+ append_directory_path (directory->item.parent, path);
+
+ g_string_append (path, directory->name);
+ g_string_append_c (path, G_DIR_SEPARATOR);
+}
+
+char *
+matemenu_tree_directory_make_path (MateMenuTreeDirectory *directory,
+ MateMenuTreeEntry *entry)
+{
+ GString *path;
+
+ g_return_val_if_fail (directory != NULL, NULL);
+
+ path = g_string_new (NULL);
+
+ append_directory_path (directory, path);
+
+ if (entry != NULL)
+ g_string_append (path,
+ desktop_entry_get_basename (entry->desktop_entry));
+
+ return g_string_free (path, FALSE);
+}
+
+const char *
+matemenu_tree_entry_get_name (MateMenuTreeEntry *entry)
+{
+ g_return_val_if_fail (entry != NULL, NULL);
+
+ return desktop_entry_get_name (entry->desktop_entry);
+}
+
+const char *
+matemenu_tree_entry_get_generic_name (MateMenuTreeEntry *entry)
+{
+ g_return_val_if_fail (entry != NULL, NULL);
+
+ return desktop_entry_get_generic_name (entry->desktop_entry);
+}
+
+const char *
+matemenu_tree_entry_get_display_name (MateMenuTreeEntry *entry)
+{
+ const char *display_name;
+
+ g_return_val_if_fail (entry != NULL, NULL);
+
+ display_name = desktop_entry_get_full_name (entry->desktop_entry);
+ if (!display_name || display_name[0] == '\0')
+ display_name = desktop_entry_get_name (entry->desktop_entry);
+
+ return display_name;
+}
+
+const char *
+matemenu_tree_entry_get_comment (MateMenuTreeEntry *entry)
+{
+ g_return_val_if_fail (entry != NULL, NULL);
+
+ return desktop_entry_get_comment (entry->desktop_entry);
+}
+
+const char* matemenu_tree_entry_get_icon(MateMenuTreeEntry *entry)
+{
+ g_return_val_if_fail (entry != NULL, NULL);
+
+ return desktop_entry_get_icon(entry->desktop_entry);
+}
+
+const char* matemenu_tree_entry_get_exec(MateMenuTreeEntry* entry)
+{
+ g_return_val_if_fail(entry != NULL, NULL);
+
+ return desktop_entry_get_exec(entry->desktop_entry);
+}
+
+gboolean matemenu_tree_entry_get_launch_in_terminal(MateMenuTreeEntry* entry)
+{
+ g_return_val_if_fail(entry != NULL, FALSE);
+
+ return desktop_entry_get_launch_in_terminal(entry->desktop_entry);
+}
+
+const char* matemenu_tree_entry_get_desktop_file_path(MateMenuTreeEntry* entry)
+{
+ g_return_val_if_fail(entry != NULL, NULL);
+
+ return desktop_entry_get_path(entry->desktop_entry);
+}
+
+const char* matemenu_tree_entry_get_desktop_file_id(MateMenuTreeEntry* entry)
+{
+ g_return_val_if_fail(entry != NULL, NULL);
+
+ return entry->desktop_file_id;
+}
+
+gboolean matemenu_tree_entry_get_is_excluded(MateMenuTreeEntry* entry)
+{
+ g_return_val_if_fail(entry != NULL, FALSE);
+
+ return entry->is_excluded;
+}
+
+gboolean matemenu_tree_entry_get_is_nodisplay(MateMenuTreeEntry* entry)
+{
+ g_return_val_if_fail(entry != NULL, FALSE);
+
+ return entry->is_nodisplay;
+}
+
+MateMenuTreeDirectory* matemenu_tree_header_get_directory(MateMenuTreeHeader* header)
+{
+ g_return_val_if_fail (header != NULL, NULL);
+
+ return matemenu_tree_item_ref(header->directory);
+}
+
+MateMenuTreeDirectory* matemenu_tree_alias_get_directory(MateMenuTreeAlias* alias)
+{
+ g_return_val_if_fail (alias != NULL, NULL);
+
+ return matemenu_tree_item_ref(alias->directory);
+}
+
+MateMenuTreeItem *
+matemenu_tree_alias_get_item (MateMenuTreeAlias *alias)
+{
+ g_return_val_if_fail (alias != NULL, NULL);
+
+ return matemenu_tree_item_ref (alias->aliased_item);
+}
+
+static MateMenuTreeDirectory *
+matemenu_tree_directory_new (MateMenuTreeDirectory *parent,
+ const char *name,
+ gboolean is_root)
+{
+ MateMenuTreeDirectory *retval;
+
+ if (!is_root)
+ {
+ retval = g_new0 (MateMenuTreeDirectory, 1);
+ }
+ else
+ {
+ MateMenuTreeDirectoryRoot *root;
+
+ root = g_new0 (MateMenuTreeDirectoryRoot, 1);
+
+ retval = MATEMENU_TREE_DIRECTORY (root);
+
+ retval->is_root = TRUE;
+ }
+
+
+ retval->item.type = MATEMENU_TREE_ITEM_DIRECTORY;
+ retval->item.parent = parent;
+ retval->item.refcount = 1;
+
+ retval->name = g_strdup (name);
+ retval->directory_entry = NULL;
+ retval->entries = NULL;
+ retval->subdirs = NULL;
+ retval->default_layout_info = NULL;
+ retval->layout_info = NULL;
+ retval->contents = NULL;
+ retval->only_unallocated = FALSE;
+ retval->is_nodisplay = FALSE;
+ retval->layout_pending_separator = FALSE;
+ retval->preprocessed = FALSE;
+ retval->will_inline_header = G_MAXUINT16;
+
+ retval->default_layout_values.mask = MENU_LAYOUT_VALUES_NONE;
+ retval->default_layout_values.show_empty = FALSE;
+ retval->default_layout_values.inline_menus = FALSE;
+ retval->default_layout_values.inline_limit = 4;
+ retval->default_layout_values.inline_header = FALSE;
+ retval->default_layout_values.inline_alias = FALSE;
+
+ return retval;
+}
+
+static void
+matemenu_tree_directory_finalize (MateMenuTreeDirectory *directory)
+{
+ g_assert (directory->item.refcount == 0);
+
+ g_slist_foreach (directory->contents,
+ (GFunc) matemenu_tree_item_unref_and_unset_parent,
+ NULL);
+ g_slist_free (directory->contents);
+ directory->contents = NULL;
+
+ g_slist_foreach (directory->default_layout_info,
+ (GFunc) menu_layout_node_unref,
+ NULL);
+ g_slist_free (directory->default_layout_info);
+ directory->default_layout_info = NULL;
+
+ g_slist_foreach (directory->layout_info,
+ (GFunc) menu_layout_node_unref,
+ NULL);
+ g_slist_free (directory->layout_info);
+ directory->layout_info = NULL;
+
+ g_slist_foreach (directory->subdirs,
+ (GFunc) matemenu_tree_item_unref_and_unset_parent,
+ NULL);
+ g_slist_free (directory->subdirs);
+ directory->subdirs = NULL;
+
+ g_slist_foreach (directory->entries,
+ (GFunc) matemenu_tree_item_unref_and_unset_parent,
+ NULL);
+ g_slist_free (directory->entries);
+ directory->entries = NULL;
+
+ if (directory->directory_entry)
+ desktop_entry_unref (directory->directory_entry);
+ directory->directory_entry = NULL;
+
+ g_free (directory->name);
+ directory->name = NULL;
+}
+
+static MateMenuTreeSeparator *
+matemenu_tree_separator_new (MateMenuTreeDirectory *parent)
+{
+ MateMenuTreeSeparator *retval;
+
+ retval = g_new0 (MateMenuTreeSeparator, 1);
+
+ retval->item.type = MATEMENU_TREE_ITEM_SEPARATOR;
+ retval->item.parent = parent;
+ retval->item.refcount = 1;
+
+ return retval;
+}
+
+static MateMenuTreeHeader *
+matemenu_tree_header_new (MateMenuTreeDirectory *parent,
+ MateMenuTreeDirectory *directory)
+{
+ MateMenuTreeHeader *retval;
+
+ retval = g_new0 (MateMenuTreeHeader, 1);
+
+ retval->item.type = MATEMENU_TREE_ITEM_HEADER;
+ retval->item.parent = parent;
+ retval->item.refcount = 1;
+
+ retval->directory = matemenu_tree_item_ref (directory);
+
+ matemenu_tree_item_set_parent (MATEMENU_TREE_ITEM (retval->directory), NULL);
+
+ return retval;
+}
+
+static void
+matemenu_tree_header_finalize (MateMenuTreeHeader *header)
+{
+ g_assert (header->item.refcount == 0);
+
+ if (header->directory != NULL)
+ matemenu_tree_item_unref (header->directory);
+ header->directory = NULL;
+}
+
+static MateMenuTreeAlias *
+matemenu_tree_alias_new (MateMenuTreeDirectory *parent,
+ MateMenuTreeDirectory *directory,
+ MateMenuTreeItem *item)
+{
+ MateMenuTreeAlias *retval;
+
+ retval = g_new0 (MateMenuTreeAlias, 1);
+
+ retval->item.type = MATEMENU_TREE_ITEM_ALIAS;
+ retval->item.parent = parent;
+ retval->item.refcount = 1;
+
+ retval->directory = matemenu_tree_item_ref (directory);
+ if (item->type != MATEMENU_TREE_ITEM_ALIAS)
+ retval->aliased_item = matemenu_tree_item_ref (item);
+ else
+ retval->aliased_item = matemenu_tree_item_ref (matemenu_tree_alias_get_item (MATEMENU_TREE_ALIAS (item)));
+
+ matemenu_tree_item_set_parent (MATEMENU_TREE_ITEM (retval->directory), NULL);
+ matemenu_tree_item_set_parent (retval->aliased_item, NULL);
+
+ return retval;
+}
+
+static void
+matemenu_tree_alias_finalize (MateMenuTreeAlias *alias)
+{
+ g_assert (alias->item.refcount == 0);
+
+ if (alias->directory != NULL)
+ matemenu_tree_item_unref (alias->directory);
+ alias->directory = NULL;
+
+ if (alias->aliased_item != NULL)
+ matemenu_tree_item_unref (alias->aliased_item);
+ alias->aliased_item = NULL;
+}
+
+static MateMenuTreeEntry *
+matemenu_tree_entry_new (MateMenuTreeDirectory *parent,
+ DesktopEntry *desktop_entry,
+ const char *desktop_file_id,
+ gboolean is_excluded,
+ gboolean is_nodisplay)
+{
+ MateMenuTreeEntry *retval;
+
+ retval = g_new0 (MateMenuTreeEntry, 1);
+
+ retval->item.type = MATEMENU_TREE_ITEM_ENTRY;
+ retval->item.parent = parent;
+ retval->item.refcount = 1;
+
+ retval->desktop_entry = desktop_entry_ref (desktop_entry);
+ retval->desktop_file_id = g_strdup (desktop_file_id);
+ retval->is_excluded = is_excluded != FALSE;
+ retval->is_nodisplay = is_nodisplay != FALSE;
+
+ return retval;
+}
+
+static void
+matemenu_tree_entry_finalize (MateMenuTreeEntry *entry)
+{
+ g_assert (entry->item.refcount == 0);
+
+ g_free (entry->desktop_file_id);
+ entry->desktop_file_id = NULL;
+
+ if (entry->desktop_entry)
+ desktop_entry_unref (entry->desktop_entry);
+ entry->desktop_entry = NULL;
+}
+
+static int
+matemenu_tree_entry_compare_by_id (MateMenuTreeItem *a,
+ MateMenuTreeItem *b)
+{
+ if (a->type == MATEMENU_TREE_ITEM_ALIAS)
+ a = MATEMENU_TREE_ALIAS (a)->aliased_item;
+
+ if (b->type == MATEMENU_TREE_ITEM_ALIAS)
+ b = MATEMENU_TREE_ALIAS (b)->aliased_item;
+
+ return strcmp (MATEMENU_TREE_ENTRY (a)->desktop_file_id,
+ MATEMENU_TREE_ENTRY (b)->desktop_file_id);
+}
+
+gpointer matemenu_tree_item_ref(gpointer itemp)
+{
+ MateMenuTreeItem* item = (MateMenuTreeItem*) itemp;
+
+ g_return_val_if_fail(item != NULL, NULL);
+ g_return_val_if_fail(item->refcount > 0, NULL);
+
+ item->refcount++;
+
+ return item;
+}
+
+void
+matemenu_tree_item_unref (gpointer itemp)
+{
+ MateMenuTreeItem *item;
+
+ item = (MateMenuTreeItem *) itemp;
+
+ g_return_if_fail (item != NULL);
+ g_return_if_fail (item->refcount > 0);
+
+ if (--item->refcount == 0)
+ {
+ switch (item->type)
+ {
+ case MATEMENU_TREE_ITEM_DIRECTORY:
+ matemenu_tree_directory_finalize (MATEMENU_TREE_DIRECTORY (item));
+ break;
+
+ case MATEMENU_TREE_ITEM_ENTRY:
+ matemenu_tree_entry_finalize (MATEMENU_TREE_ENTRY (item));
+ break;
+
+ case MATEMENU_TREE_ITEM_SEPARATOR:
+ break;
+
+ case MATEMENU_TREE_ITEM_HEADER:
+ matemenu_tree_header_finalize (MATEMENU_TREE_HEADER (item));
+ break;
+
+ case MATEMENU_TREE_ITEM_ALIAS:
+ matemenu_tree_alias_finalize (MATEMENU_TREE_ALIAS (item));
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ if (item->dnotify)
+ item->dnotify (item->user_data);
+ item->user_data = NULL;
+ item->dnotify = NULL;
+
+ item->parent = NULL;
+
+ g_free (item);
+ }
+}
+
+static void
+matemenu_tree_item_unref_and_unset_parent (gpointer itemp)
+{
+ MateMenuTreeItem *item;
+
+ item = (MateMenuTreeItem *) itemp;
+
+ g_return_if_fail (item != NULL);
+
+ matemenu_tree_item_set_parent (item, NULL);
+ matemenu_tree_item_unref (item);
+}
+
+void
+matemenu_tree_item_set_user_data (MateMenuTreeItem *item,
+ gpointer user_data,
+ GDestroyNotify dnotify)
+{
+ g_return_if_fail (item != NULL);
+
+ if (item->dnotify != NULL)
+ item->dnotify (item->user_data);
+
+ item->dnotify = dnotify;
+ item->user_data = user_data;
+}
+
+gpointer
+matemenu_tree_item_get_user_data (MateMenuTreeItem *item)
+{
+ g_return_val_if_fail (item != NULL, NULL);
+
+ return item->user_data;
+}
+
+static inline const char *
+matemenu_tree_item_compare_get_name_helper (MateMenuTreeItem *item,
+ MateMenuTreeSortKey sort_key)
+{
+ const char *name;
+
+ name = NULL;
+
+ switch (item->type)
+ {
+ case MATEMENU_TREE_ITEM_DIRECTORY:
+ if (MATEMENU_TREE_DIRECTORY (item)->directory_entry)
+ name = desktop_entry_get_name (MATEMENU_TREE_DIRECTORY (item)->directory_entry);
+ else
+ name = MATEMENU_TREE_DIRECTORY (item)->name;
+ break;
+
+ case MATEMENU_TREE_ITEM_ENTRY:
+ switch (sort_key)
+ {
+ case MATEMENU_TREE_SORT_NAME:
+ name = desktop_entry_get_name (MATEMENU_TREE_ENTRY (item)->desktop_entry);
+ break;
+ case MATEMENU_TREE_SORT_DISPLAY_NAME:
+ name = matemenu_tree_entry_get_display_name (MATEMENU_TREE_ENTRY (item));
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ break;
+
+ case MATEMENU_TREE_ITEM_ALIAS:
+ {
+ MateMenuTreeItem *dir;
+ dir = MATEMENU_TREE_ITEM (MATEMENU_TREE_ALIAS (item)->directory);
+ name = matemenu_tree_item_compare_get_name_helper (dir, sort_key);
+ }
+ break;
+
+ case MATEMENU_TREE_ITEM_SEPARATOR:
+ case MATEMENU_TREE_ITEM_HEADER:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return name;
+}
+
+static int
+matemenu_tree_item_compare (MateMenuTreeItem *a,
+ MateMenuTreeItem *b,
+ gpointer sort_key_p)
+{
+ const char *name_a;
+ const char *name_b;
+ MateMenuTreeSortKey sort_key;
+
+ sort_key = GPOINTER_TO_INT (sort_key_p);
+
+ name_a = matemenu_tree_item_compare_get_name_helper (a, sort_key);
+ name_b = matemenu_tree_item_compare_get_name_helper (b, sort_key);
+
+ return g_utf8_collate (name_a, name_b);
+}
+
+static MenuLayoutNode *
+find_menu_child (MenuLayoutNode *layout)
+{
+ MenuLayoutNode *child;
+
+ child = menu_layout_node_get_children (layout);
+ while (child && menu_layout_node_get_type (child) != MENU_LAYOUT_NODE_MENU)
+ child = menu_layout_node_get_next (child);
+
+ return child;
+}
+
+static void
+merge_resolved_children (MateMenuTree *tree,
+ GHashTable *loaded_menu_files,
+ MenuLayoutNode *where,
+ MenuLayoutNode *from)
+{
+ MenuLayoutNode *insert_after;
+ MenuLayoutNode *menu_child;
+ MenuLayoutNode *from_child;
+
+ matemenu_tree_resolve_files (tree, loaded_menu_files, from);
+
+ insert_after = where;
+ g_assert (menu_layout_node_get_type (insert_after) != MENU_LAYOUT_NODE_ROOT);
+ g_assert (menu_layout_node_get_parent (insert_after) != NULL);
+
+ /* skip root node */
+ menu_child = find_menu_child (from);
+ g_assert (menu_child != NULL);
+ g_assert (menu_layout_node_get_type (menu_child) == MENU_LAYOUT_NODE_MENU);
+
+ /* merge children of toplevel <Menu> */
+ from_child = menu_layout_node_get_children (menu_child);
+ while (from_child != NULL)
+ {
+ MenuLayoutNode *next;
+
+ next = menu_layout_node_get_next (from_child);
+
+ menu_verbose ("Merging ");
+ menu_debug_print_layout (from_child, FALSE);
+ menu_verbose (" after ");
+ menu_debug_print_layout (insert_after, FALSE);
+
+ switch (menu_layout_node_get_type (from_child))
+ {
+ case MENU_LAYOUT_NODE_NAME:
+ menu_layout_node_unlink (from_child); /* delete this */
+ break;
+
+ default:
+ menu_layout_node_steal (from_child);
+ menu_layout_node_insert_after (insert_after, from_child);
+ menu_layout_node_unref (from_child);
+
+ insert_after = from_child;
+ break;
+ }
+
+ from_child = next;
+ }
+}
+
+static gboolean
+load_merge_file (MateMenuTree *tree,
+ GHashTable *loaded_menu_files,
+ const char *filename,
+ gboolean is_canonical,
+ gboolean add_monitor,
+ MenuLayoutNode *where)
+{
+ MenuLayoutNode *to_merge;
+ const char *canonical;
+ char *freeme;
+ gboolean retval;
+
+ freeme = NULL;
+ retval = FALSE;
+
+ if (!is_canonical)
+ {
+ canonical = freeme = menu_canonicalize_file_name (filename, FALSE);
+ if (canonical == NULL)
+ {
+ if (add_monitor)
+ matemenu_tree_add_menu_file_monitor (tree,
+ filename,
+ MENU_FILE_MONITOR_NONEXISTENT_FILE);
+
+ menu_verbose ("Failed to canonicalize merge file path \"%s\": %s\n",
+ filename, g_strerror (errno));
+ goto out;
+ }
+ }
+ else
+ {
+ canonical = filename;
+ }
+
+ if (g_hash_table_lookup (loaded_menu_files, canonical) != NULL)
+ {
+ g_warning ("Not loading \"%s\": recursive loop detected in .menu files",
+ canonical);
+ retval = TRUE;
+ goto out;
+ }
+
+ menu_verbose ("Merging file \"%s\"\n", canonical);
+
+ to_merge = menu_layout_load (canonical, NULL, NULL);
+ if (to_merge == NULL)
+ {
+ menu_verbose ("No menu for file \"%s\" found when merging\n",
+ canonical);
+ goto out;
+ }
+
+ retval = TRUE;
+
+ g_hash_table_insert (loaded_menu_files, (char *) canonical, GUINT_TO_POINTER (TRUE));
+
+ if (add_monitor)
+ matemenu_tree_add_menu_file_monitor (tree,
+ canonical,
+ MENU_FILE_MONITOR_FILE);
+
+ merge_resolved_children (tree, loaded_menu_files, where, to_merge);
+
+ g_hash_table_remove (loaded_menu_files, canonical);
+
+ menu_layout_node_unref (to_merge);
+
+ out:
+ if (freeme)
+ g_free (freeme);
+
+ return retval;
+}
+
+static gboolean
+load_merge_file_with_config_dir (MateMenuTree *tree,
+ GHashTable *loaded_menu_files,
+ const char *menu_file,
+ const char *config_dir,
+ MenuLayoutNode *where)
+{
+ char *merge_file;
+ gboolean loaded;
+
+ loaded = FALSE;
+
+ merge_file = g_build_filename (config_dir, "menus", menu_file, NULL);
+
+ if (load_merge_file (tree, loaded_menu_files, merge_file, FALSE, TRUE, where))
+ loaded = TRUE;
+
+ g_free (merge_file);
+
+ return loaded;
+}
+
+static gboolean
+compare_basedir_to_config_dir (const char *canonical_basedir,
+ const char *config_dir)
+{
+ char *dirname;
+ char *canonical_menus_dir;
+ gboolean retval;
+
+ menu_verbose ("Checking to see if basedir '%s' is in '%s'\n",
+ canonical_basedir, config_dir);
+
+ dirname = g_build_filename (config_dir, "menus", NULL);
+
+ retval = FALSE;
+
+ canonical_menus_dir = menu_canonicalize_file_name (dirname, FALSE);
+ if (canonical_menus_dir != NULL &&
+ strcmp (canonical_basedir, canonical_menus_dir) == 0)
+ {
+ retval = TRUE;
+ }
+
+ g_free (canonical_menus_dir);
+ g_free (dirname);
+
+ return retval;
+}
+
+static gboolean
+load_parent_merge_file_from_basename (MateMenuTree *tree,
+ GHashTable *loaded_menu_files,
+ MenuLayoutNode *layout,
+ const char *menu_file,
+ const char *canonical_basedir)
+{
+ gboolean found_basedir;
+ const char * const *system_config_dirs;
+ int i;
+
+ /* We're not interested in menu files that are in directories which are not a
+ * parent of the base directory of this menu file */
+ found_basedir = compare_basedir_to_config_dir (canonical_basedir,
+ g_get_user_config_dir ());
+
+ system_config_dirs = g_get_system_config_dirs ();
+
+ i = 0;
+ while (system_config_dirs[i] != NULL)
+ {
+ if (!found_basedir)
+ {
+ found_basedir = compare_basedir_to_config_dir (canonical_basedir,
+ system_config_dirs[i]);
+ }
+ else
+ {
+ menu_verbose ("Looking for parent menu file '%s' in '%s'\n",
+ menu_file, system_config_dirs[i]);
+
+ if (load_merge_file_with_config_dir (tree,
+ loaded_menu_files,
+ menu_file,
+ system_config_dirs[i],
+ layout))
+ {
+ break;
+ }
+ }
+
+ ++i;
+ }
+
+ return system_config_dirs[i] != NULL;
+}
+
+static gboolean load_parent_merge_file(MateMenuTree* tree, GHashTable* loaded_menu_files, MenuLayoutNode* layout)
+{
+ MenuLayoutNode* root;
+ const char* basedir;
+ const char* menu_name;
+ char* canonical_basedir;
+ char* menu_file;
+ gboolean found;
+
+ root = menu_layout_node_get_root(layout);
+
+ basedir = menu_layout_node_root_get_basedir(root);
+ menu_name = menu_layout_node_root_get_name(root);
+
+ canonical_basedir = menu_canonicalize_file_name(basedir, FALSE);
+
+ if (canonical_basedir == NULL)
+ {
+ menu_verbose("Menu basedir '%s' no longer exists, not merging parent\n", basedir);
+ return FALSE;
+ }
+
+ found = FALSE;
+ menu_file = g_strconcat(menu_name, ".menu", NULL);
+
+ if (strcmp(menu_file, "mate-applications.menu") == 0 && g_getenv("XDG_MENU_PREFIX"))
+ {
+ char* prefixed_basename;
+ prefixed_basename = g_strdup_printf("%s%s", g_getenv("XDG_MENU_PREFIX"), menu_file);
+ found = load_parent_merge_file_from_basename(tree, loaded_menu_files, layout, prefixed_basename, canonical_basedir);
+ g_free(prefixed_basename);
+ }
+
+ if (!found)
+ {
+ found = load_parent_merge_file_from_basename(tree, loaded_menu_files, layout, menu_file, canonical_basedir);
+ }
+
+ g_free(menu_file);
+ g_free(canonical_basedir);
+
+ return found;
+}
+
+static void
+load_merge_dir (MateMenuTree *tree,
+ GHashTable *loaded_menu_files,
+ const char *dirname,
+ MenuLayoutNode *where)
+{
+ GDir *dir;
+ const char *menu_file;
+
+ menu_verbose ("Loading merge dir \"%s\"\n", dirname);
+
+ matemenu_tree_add_menu_file_monitor (tree,
+ dirname,
+ MENU_FILE_MONITOR_DIRECTORY);
+
+ if ((dir = g_dir_open (dirname, 0, NULL)) == NULL)
+ return;
+
+ while ((menu_file = g_dir_read_name (dir)))
+ {
+ if (g_str_has_suffix (menu_file, ".menu"))
+ {
+ char *full_path;
+
+ full_path = g_build_filename (dirname, menu_file, NULL);
+
+ load_merge_file (tree, loaded_menu_files, full_path, TRUE, FALSE, where);
+
+ g_free (full_path);
+ }
+ }
+
+ g_dir_close (dir);
+}
+
+static void
+load_merge_dir_with_config_dir (MateMenuTree *tree,
+ GHashTable *loaded_menu_files,
+ const char *config_dir,
+ const char *dirname,
+ MenuLayoutNode *where)
+{
+ char *path;
+
+ path = g_build_filename (config_dir, "menus", dirname, NULL);
+
+ load_merge_dir (tree, loaded_menu_files, path, where);
+
+ g_free (path);
+}
+
+static void
+resolve_merge_file (MateMenuTree *tree,
+ GHashTable *loaded_menu_files,
+ MenuLayoutNode *layout)
+{
+ char *filename;
+
+ if (menu_layout_node_merge_file_get_type (layout) == MENU_MERGE_FILE_TYPE_PARENT)
+ {
+ if (load_parent_merge_file (tree, loaded_menu_files, layout))
+ return;
+ }
+
+ filename = menu_layout_node_get_content_as_path (layout);
+ if (filename == NULL)
+ {
+ menu_verbose ("didn't get node content as a path, not merging file\n");
+ }
+ else
+ {
+ load_merge_file (tree, loaded_menu_files, filename, FALSE, TRUE, layout);
+
+ g_free (filename);
+ }
+
+ /* remove the now-replaced node */
+ menu_layout_node_unlink (layout);
+}
+
+static void
+resolve_merge_dir (MateMenuTree *tree,
+ GHashTable *loaded_menu_files,
+ MenuLayoutNode *layout)
+{
+ char *path;
+
+ path = menu_layout_node_get_content_as_path (layout);
+ if (path == NULL)
+ {
+ menu_verbose ("didn't get layout node content as a path, not merging dir\n");
+ }
+ else
+ {
+ load_merge_dir (tree, loaded_menu_files, path, layout);
+
+ g_free (path);
+ }
+
+ /* remove the now-replaced node */
+ menu_layout_node_unlink (layout);
+}
+
+static MenuLayoutNode *
+add_app_dir (MateMenuTree *tree,
+ MenuLayoutNode *before,
+ const char *data_dir)
+{
+ MenuLayoutNode *tmp;
+ char *dirname;
+
+ tmp = menu_layout_node_new (MENU_LAYOUT_NODE_APP_DIR);
+ dirname = g_build_filename (data_dir, "applications", NULL);
+ menu_layout_node_set_content (tmp, dirname);
+ menu_layout_node_insert_before (before, tmp);
+ menu_layout_node_unref (before);
+
+ menu_verbose ("Adding <AppDir>%s</AppDir> in <DefaultAppDirs/>\n",
+ dirname);
+
+ g_free (dirname);
+
+ return tmp;
+}
+
+static void
+resolve_default_app_dirs (MateMenuTree *tree,
+ MenuLayoutNode *layout)
+{
+ MenuLayoutNode *before;
+ const char * const *system_data_dirs;
+ int i;
+
+ system_data_dirs = g_get_system_data_dirs ();
+
+ before = add_app_dir (tree,
+ menu_layout_node_ref (layout),
+ g_get_user_data_dir ());
+
+ i = 0;
+ while (system_data_dirs[i] != NULL)
+ {
+ before = add_app_dir (tree, before, system_data_dirs[i]);
+
+ ++i;
+ }
+
+ menu_layout_node_unref (before);
+
+ /* remove the now-replaced node */
+ menu_layout_node_unlink (layout);
+}
+
+static MenuLayoutNode* add_directory_dir(MateMenuTree* tree, MenuLayoutNode* before, const char* data_dir)
+{
+ MenuLayoutNode* tmp;
+ char* dirname;
+
+ tmp = menu_layout_node_new(MENU_LAYOUT_NODE_DIRECTORY_DIR);
+ dirname = g_build_filename(data_dir, "desktop-directories", NULL);
+ menu_layout_node_set_content(tmp, dirname);
+ menu_layout_node_insert_before(before, tmp);
+ menu_layout_node_unref(before);
+
+ menu_verbose("Adding <DirectoryDir>%s</DirectoryDir> in <DefaultDirectoryDirs/>\n", dirname);
+
+ g_free(dirname);
+
+ return tmp;
+}
+
+static void
+resolve_default_directory_dirs (MateMenuTree *tree,
+ MenuLayoutNode *layout)
+{
+ MenuLayoutNode *before;
+ const char * const *system_data_dirs;
+ int i;
+
+ system_data_dirs = g_get_system_data_dirs ();
+
+ before = add_directory_dir (tree,
+ menu_layout_node_ref (layout),
+ g_get_user_data_dir ());
+
+ i = 0;
+ while (system_data_dirs[i] != NULL)
+ {
+ before = add_directory_dir (tree, before, system_data_dirs[i]);
+
+ ++i;
+ }
+
+ menu_layout_node_unref (before);
+
+ /* remove the now-replaced node */
+ menu_layout_node_unlink (layout);
+}
+
+static void
+resolve_default_merge_dirs (MateMenuTree *tree,
+ GHashTable *loaded_menu_files,
+ MenuLayoutNode *layout)
+{
+ MenuLayoutNode *root;
+ const char *menu_name;
+ char *merge_name;
+ const char * const *system_config_dirs;
+ int i;
+
+ root = menu_layout_node_get_root (layout);
+ menu_name = menu_layout_node_root_get_name (root);
+
+ merge_name = g_strconcat (menu_name, "-merged", NULL);
+
+ system_config_dirs = g_get_system_config_dirs ();
+
+ /* Merge in reverse order */
+ i = 0;
+ while (system_config_dirs[i] != NULL) i++;
+ while (i > 0)
+ {
+ i--;
+ load_merge_dir_with_config_dir (tree,
+ loaded_menu_files,
+ system_config_dirs[i],
+ merge_name,
+ layout);
+ }
+
+ load_merge_dir_with_config_dir (tree,
+ loaded_menu_files,
+ g_get_user_config_dir (),
+ merge_name,
+ layout);
+
+ g_free (merge_name);
+
+ /* remove the now-replaced node */
+ menu_layout_node_unlink (layout);
+}
+
+static void
+add_filename_include (const char *desktop_file_id,
+ DesktopEntry *entry,
+ MenuLayoutNode *include)
+{
+ if (!desktop_entry_has_categories (entry))
+ {
+ MenuLayoutNode *node;
+
+ node = menu_layout_node_new (MENU_LAYOUT_NODE_FILENAME);
+ menu_layout_node_set_content (node, desktop_file_id);
+
+ menu_layout_node_append_child (include, node);
+ menu_layout_node_unref (node);
+ }
+}
+
+static void
+is_dot_directory (const char *basename,
+ DesktopEntry *entry,
+ gboolean *has_dot_directory)
+{
+ if (!strcmp (basename, ".directory"))
+ *has_dot_directory = TRUE;
+}
+
+static gboolean
+add_menu_for_legacy_dir (MenuLayoutNode *parent,
+ const char *legacy_dir,
+ const char *relative_path,
+ const char *legacy_prefix,
+ const char *menu_name)
+{
+ EntryDirectory *ed;
+ DesktopEntrySet *desktop_entries;
+ DesktopEntrySet *directory_entries;
+ GSList *subdirs;
+ gboolean menu_added;
+ gboolean has_dot_directory;
+
+ ed = entry_directory_new_legacy (DESKTOP_ENTRY_INVALID, legacy_dir, legacy_prefix);
+ if (!ed)
+ return FALSE;
+
+ subdirs = NULL;
+ desktop_entries = desktop_entry_set_new ();
+ directory_entries = desktop_entry_set_new ();
+
+ entry_directory_get_flat_contents (ed,
+ desktop_entries,
+ directory_entries,
+ &subdirs);
+ entry_directory_unref (ed);
+
+ has_dot_directory = FALSE;
+ desktop_entry_set_foreach (directory_entries,
+ (DesktopEntrySetForeachFunc) is_dot_directory,
+ &has_dot_directory);
+ desktop_entry_set_unref (directory_entries);
+
+ menu_added = FALSE;
+ if (desktop_entry_set_get_count (desktop_entries) > 0 || subdirs)
+ {
+ MenuLayoutNode *menu;
+ MenuLayoutNode *node;
+ GString *subdir_path;
+ GString *subdir_relative;
+ GSList *tmp;
+ int legacy_dir_len;
+ int relative_path_len;
+
+ menu = menu_layout_node_new (MENU_LAYOUT_NODE_MENU);
+ menu_layout_node_append_child (parent, menu);
+
+ menu_added = TRUE;
+
+ g_assert (menu_name != NULL);
+
+ node = menu_layout_node_new (MENU_LAYOUT_NODE_NAME);
+ menu_layout_node_set_content (node, menu_name);
+ menu_layout_node_append_child (menu, node);
+ menu_layout_node_unref (node);
+
+ if (has_dot_directory)
+ {
+ node = menu_layout_node_new (MENU_LAYOUT_NODE_DIRECTORY);
+ if (relative_path != NULL)
+ {
+ char *directory_entry_path;
+
+ directory_entry_path = g_strdup_printf ("%s/.directory", relative_path);
+ menu_layout_node_set_content (node, directory_entry_path);
+ g_free (directory_entry_path);
+ }
+ else
+ {
+ menu_layout_node_set_content (node, ".directory");
+ }
+ menu_layout_node_append_child (menu, node);
+ menu_layout_node_unref (node);
+ }
+
+ if (desktop_entry_set_get_count (desktop_entries) > 0)
+ {
+ MenuLayoutNode *include;
+
+ include = menu_layout_node_new (MENU_LAYOUT_NODE_INCLUDE);
+ menu_layout_node_append_child (menu, include);
+
+ desktop_entry_set_foreach (desktop_entries,
+ (DesktopEntrySetForeachFunc) add_filename_include,
+ include);
+
+ menu_layout_node_unref (include);
+ }
+
+ subdir_path = g_string_new (legacy_dir);
+ legacy_dir_len = strlen (legacy_dir);
+
+ subdir_relative = g_string_new (relative_path);
+ relative_path_len = relative_path ? strlen (relative_path) : 0;
+
+ tmp = subdirs;
+ while (tmp != NULL)
+ {
+ const char *subdir = tmp->data;
+
+ g_string_append_c (subdir_path, G_DIR_SEPARATOR);
+ g_string_append (subdir_path, subdir);
+
+ if (relative_path_len)
+ {
+ g_string_append_c (subdir_relative, G_DIR_SEPARATOR);
+ }
+ g_string_append (subdir_relative, subdir);
+
+ add_menu_for_legacy_dir (menu,
+ subdir_path->str,
+ subdir_relative->str,
+ legacy_prefix,
+ subdir);
+
+ g_string_truncate (subdir_relative, relative_path_len);
+ g_string_truncate (subdir_path, legacy_dir_len);
+
+ tmp = tmp->next;
+ }
+
+ g_string_free (subdir_path, TRUE);
+ g_string_free (subdir_relative, TRUE);
+
+ menu_layout_node_unref (menu);
+ }
+
+ desktop_entry_set_unref (desktop_entries);
+
+ g_slist_foreach (subdirs, (GFunc) g_free, NULL);
+ g_slist_free (subdirs);
+
+ return menu_added;
+}
+
+static void
+resolve_legacy_dir (MateMenuTree *tree,
+ GHashTable *loaded_menu_files,
+ MenuLayoutNode *legacy)
+{
+ MenuLayoutNode *to_merge;
+ MenuLayoutNode *menu;
+
+ to_merge = menu_layout_node_new (MENU_LAYOUT_NODE_ROOT);
+
+ menu = menu_layout_node_get_parent (legacy);
+ g_assert (menu_layout_node_get_type (menu) == MENU_LAYOUT_NODE_MENU);
+
+ if (add_menu_for_legacy_dir (to_merge,
+ menu_layout_node_get_content (legacy),
+ NULL,
+ menu_layout_node_legacy_dir_get_prefix (legacy),
+ menu_layout_node_menu_get_name (menu)))
+ {
+ merge_resolved_children (tree, loaded_menu_files, legacy, to_merge);
+ }
+
+ menu_layout_node_unref (to_merge);
+}
+
+static MenuLayoutNode *
+add_legacy_dir (MateMenuTree *tree,
+ GHashTable *loaded_menu_files,
+ MenuLayoutNode *before,
+ const char *data_dir)
+{
+ MenuLayoutNode *legacy;
+ char *dirname;
+
+ dirname = g_build_filename (data_dir, "applnk", NULL);
+
+ legacy = menu_layout_node_new (MENU_LAYOUT_NODE_LEGACY_DIR);
+ menu_layout_node_set_content (legacy, dirname);
+ menu_layout_node_legacy_dir_set_prefix (legacy, "kde");
+ menu_layout_node_insert_before (before, legacy);
+ menu_layout_node_unref (before);
+
+ menu_verbose ("Adding <LegacyDir>%s</LegacyDir> in <KDELegacyDirs/>\n",
+ dirname);
+
+ resolve_legacy_dir (tree, loaded_menu_files, legacy);
+
+ g_free (dirname);
+
+ return legacy;
+}
+
+static void
+resolve_kde_legacy_dirs (MateMenuTree *tree,
+ GHashTable *loaded_menu_files,
+ MenuLayoutNode *layout)
+{
+ MenuLayoutNode *before;
+ const char * const *system_data_dirs;
+ int i;
+
+ system_data_dirs = g_get_system_data_dirs ();
+
+ before = add_legacy_dir (tree,
+ loaded_menu_files,
+ menu_layout_node_ref (layout),
+ g_get_user_data_dir ());
+
+ i = 0;
+ while (system_data_dirs[i] != NULL)
+ {
+ before = add_legacy_dir (tree, loaded_menu_files, before, system_data_dirs[i]);
+
+ ++i;
+ }
+
+ menu_layout_node_unref (before);
+
+ /* remove the now-replaced node */
+ menu_layout_node_unlink (layout);
+}
+
+static void
+matemenu_tree_resolve_files (MateMenuTree *tree,
+ GHashTable *loaded_menu_files,
+ MenuLayoutNode *layout)
+{
+ MenuLayoutNode *child;
+
+ menu_verbose ("Resolving files in: ");
+ menu_debug_print_layout (layout, TRUE);
+
+ switch (menu_layout_node_get_type (layout))
+ {
+ case MENU_LAYOUT_NODE_MERGE_FILE:
+ resolve_merge_file (tree, loaded_menu_files, layout);
+ break;
+
+ case MENU_LAYOUT_NODE_MERGE_DIR:
+ resolve_merge_dir (tree, loaded_menu_files, layout);
+ break;
+
+ case MENU_LAYOUT_NODE_DEFAULT_APP_DIRS:
+ resolve_default_app_dirs (tree, layout);
+ break;
+
+ case MENU_LAYOUT_NODE_DEFAULT_DIRECTORY_DIRS:
+ resolve_default_directory_dirs (tree, layout);
+ break;
+
+ case MENU_LAYOUT_NODE_DEFAULT_MERGE_DIRS:
+ resolve_default_merge_dirs (tree, loaded_menu_files, layout);
+ break;
+
+ case MENU_LAYOUT_NODE_LEGACY_DIR:
+ resolve_legacy_dir (tree, loaded_menu_files, layout);
+ break;
+
+ case MENU_LAYOUT_NODE_KDE_LEGACY_DIRS:
+ resolve_kde_legacy_dirs (tree, loaded_menu_files, layout);
+ break;
+
+ case MENU_LAYOUT_NODE_PASSTHROUGH:
+ /* Just get rid of these, we don't need the memory usage */
+ menu_layout_node_unlink (layout);
+ break;
+
+ default:
+ /* Recurse */
+ child = menu_layout_node_get_children (layout);
+ while (child != NULL)
+ {
+ MenuLayoutNode *next = menu_layout_node_get_next (child);
+
+ matemenu_tree_resolve_files (tree, loaded_menu_files, child);
+
+ child = next;
+ }
+ break;
+ }
+}
+
+static void
+move_children (MenuLayoutNode *from,
+ MenuLayoutNode *to)
+{
+ MenuLayoutNode *from_child;
+ MenuLayoutNode *insert_before;
+
+ insert_before = menu_layout_node_get_children (to);
+ from_child = menu_layout_node_get_children (from);
+
+ while (from_child != NULL)
+ {
+ MenuLayoutNode *next;
+
+ next = menu_layout_node_get_next (from_child);
+
+ menu_layout_node_steal (from_child);
+
+ if (menu_layout_node_get_type (from_child) == MENU_LAYOUT_NODE_NAME)
+ {
+ ; /* just drop the Name in the old <Menu> */
+ }
+ else if (insert_before)
+ {
+ menu_layout_node_insert_before (insert_before, from_child);
+ g_assert (menu_layout_node_get_next (from_child) == insert_before);
+ }
+ else
+ {
+ menu_layout_node_append_child (to, from_child);
+ }
+
+ menu_layout_node_unref (from_child);
+
+ from_child = next;
+ }
+}
+
+static int
+null_safe_strcmp (const char *a,
+ const char *b)
+{
+ if (a == NULL && b == NULL)
+ return 0;
+ else if (a == NULL)
+ return -1;
+ else if (b == NULL)
+ return 1;
+ else
+ return strcmp (a, b);
+}
+
+static int
+node_compare_func (const void *a,
+ const void *b)
+{
+ MenuLayoutNode *node_a = (MenuLayoutNode*) a;
+ MenuLayoutNode *node_b = (MenuLayoutNode*) b;
+ MenuLayoutNodeType t_a = menu_layout_node_get_type (node_a);
+ MenuLayoutNodeType t_b = menu_layout_node_get_type (node_b);
+
+ if (t_a < t_b)
+ return -1;
+ else if (t_a > t_b)
+ return 1;
+ else
+ {
+ const char *c_a = menu_layout_node_get_content (node_a);
+ const char *c_b = menu_layout_node_get_content (node_b);
+
+ return null_safe_strcmp (c_a, c_b);
+ }
+}
+
+static int
+node_menu_compare_func (const void *a,
+ const void *b)
+{
+ MenuLayoutNode *node_a = (MenuLayoutNode*) a;
+ MenuLayoutNode *node_b = (MenuLayoutNode*) b;
+ MenuLayoutNode *parent_a = menu_layout_node_get_parent (node_a);
+ MenuLayoutNode *parent_b = menu_layout_node_get_parent (node_b);
+
+ if (parent_a < parent_b)
+ return -1;
+ else if (parent_a > parent_b)
+ return 1;
+ else
+ return null_safe_strcmp (menu_layout_node_menu_get_name (node_a),
+ menu_layout_node_menu_get_name (node_b));
+}
+
+static void
+matemenu_tree_strip_duplicate_children (MateMenuTree *tree,
+ MenuLayoutNode *layout)
+{
+ MenuLayoutNode *child;
+ GSList *simple_nodes;
+ GSList *menu_layout_nodes;
+ GSList *prev;
+ GSList *tmp;
+
+ /* to strip dups, we find all the child nodes where
+ * we want to kill dups, sort them,
+ * then nuke the adjacent nodes that are equal
+ */
+
+ simple_nodes = NULL;
+ menu_layout_nodes = NULL;
+
+ child = menu_layout_node_get_children (layout);
+ while (child != NULL)
+ {
+ switch (menu_layout_node_get_type (child))
+ {
+ /* These are dups if their content is the same */
+ case MENU_LAYOUT_NODE_APP_DIR:
+ case MENU_LAYOUT_NODE_DIRECTORY_DIR:
+ case MENU_LAYOUT_NODE_DIRECTORY:
+ simple_nodes = g_slist_prepend (simple_nodes, child);
+ break;
+
+ /* These have to be merged in a more complicated way,
+ * and then recursed
+ */
+ case MENU_LAYOUT_NODE_MENU:
+ menu_layout_nodes = g_slist_prepend (menu_layout_nodes, child);
+ break;
+
+ default:
+ break;
+ }
+
+ child = menu_layout_node_get_next (child);
+ }
+
+ /* Note that the lists are all backward. So we want to keep
+ * the items that are earlier in the list, because they were
+ * later in the file
+ */
+
+ /* stable sort the simple nodes */
+ simple_nodes = g_slist_sort (simple_nodes,
+ node_compare_func);
+
+ prev = NULL;
+ tmp = simple_nodes;
+ while (tmp != NULL)
+ {
+ GSList *next = tmp->next;
+
+ if (prev)
+ {
+ MenuLayoutNode *p = prev->data;
+ MenuLayoutNode *n = tmp->data;
+
+ if (node_compare_func (p, n) == 0)
+ {
+ /* nuke it! */
+ menu_layout_node_unlink (n);
+ simple_nodes = g_slist_delete_link (simple_nodes, tmp);
+ tmp = prev;
+ }
+ }
+
+ prev = tmp;
+ tmp = next;
+ }
+
+ g_slist_free (simple_nodes);
+ simple_nodes = NULL;
+
+ /* stable sort the menu nodes (the sort includes the
+ * parents of the nodes in the comparison). Remember
+ * the list is backward.
+ */
+ menu_layout_nodes = g_slist_sort (menu_layout_nodes,
+ node_menu_compare_func);
+
+ prev = NULL;
+ tmp = menu_layout_nodes;
+ while (tmp != NULL)
+ {
+ GSList *next = tmp->next;
+
+ if (prev)
+ {
+ MenuLayoutNode *p = prev->data;
+ MenuLayoutNode *n = tmp->data;
+
+ if (node_menu_compare_func (p, n) == 0)
+ {
+ /* Move children of first menu to the start of second
+ * menu and nuke the first menu
+ */
+ move_children (n, p);
+ menu_layout_node_unlink (n);
+ menu_layout_nodes = g_slist_delete_link (menu_layout_nodes, tmp);
+ tmp = prev;
+ }
+ }
+
+ prev = tmp;
+ tmp = next;
+ }
+
+ g_slist_free (menu_layout_nodes);
+ menu_layout_nodes = NULL;
+
+ /* Recursively clean up all children */
+ child = menu_layout_node_get_children (layout);
+ while (child != NULL)
+ {
+ if (menu_layout_node_get_type (child) == MENU_LAYOUT_NODE_MENU)
+ matemenu_tree_strip_duplicate_children (tree, child);
+
+ child = menu_layout_node_get_next (child);
+ }
+}
+
+static MenuLayoutNode *
+find_submenu (MenuLayoutNode *layout,
+ const char *path,
+ gboolean create_if_not_found)
+{
+ MenuLayoutNode *child;
+ const char *slash;
+ const char *next_path;
+ char *name;
+
+ menu_verbose (" (splitting \"%s\")\n", path);
+
+ if (path[0] == '\0' || path[0] == G_DIR_SEPARATOR)
+ return NULL;
+
+ slash = strchr (path, G_DIR_SEPARATOR);
+ if (slash != NULL)
+ {
+ name = g_strndup (path, slash - path);
+ next_path = slash + 1;
+ if (*next_path == '\0')
+ next_path = NULL;
+ }
+ else
+ {
+ name = g_strdup (path);
+ next_path = NULL;
+ }
+
+ child = menu_layout_node_get_children (layout);
+ while (child != NULL)
+ {
+ switch (menu_layout_node_get_type (child))
+ {
+ case MENU_LAYOUT_NODE_MENU:
+ {
+ if (strcmp (name, menu_layout_node_menu_get_name (child)) == 0)
+ {
+ menu_verbose ("MenuNode %p found for path component \"%s\"\n",
+ child, name);
+
+ g_free (name);
+
+ if (!next_path)
+ {
+ menu_verbose (" Found menu node %p parent is %p\n",
+ child, layout);
+ return child;
+ }
+
+ return find_submenu (child, next_path, create_if_not_found);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ child = menu_layout_node_get_next (child);
+ }
+
+ if (create_if_not_found)
+ {
+ MenuLayoutNode *name_node;
+
+ child = menu_layout_node_new (MENU_LAYOUT_NODE_MENU);
+ menu_layout_node_append_child (layout, child);
+
+ name_node = menu_layout_node_new (MENU_LAYOUT_NODE_NAME);
+ menu_layout_node_set_content (name_node, name);
+ menu_layout_node_append_child (child, name_node);
+ menu_layout_node_unref (name_node);
+
+ menu_verbose (" Created menu node %p parent is %p\n",
+ child, layout);
+
+ menu_layout_node_unref (child);
+ g_free (name);
+
+ if (!next_path)
+ return child;
+
+ return find_submenu (child, next_path, create_if_not_found);
+ }
+ else
+ {
+ g_free (name);
+ return NULL;
+ }
+}
+
+/* To call this you first have to strip duplicate children once,
+ * otherwise when you move a menu Foo to Bar then you may only
+ * move one of Foo, not all the merged Foo.
+ */
+static void
+matemenu_tree_execute_moves (MateMenuTree *tree,
+ MenuLayoutNode *layout,
+ gboolean *need_remove_dups_p)
+{
+ MenuLayoutNode *child;
+ gboolean need_remove_dups;
+ GSList *move_nodes;
+ GSList *tmp;
+
+ need_remove_dups = FALSE;
+
+ move_nodes = NULL;
+
+ child = menu_layout_node_get_children (layout);
+ while (child != NULL)
+ {
+ switch (menu_layout_node_get_type (child))
+ {
+ case MENU_LAYOUT_NODE_MENU:
+ /* Recurse - we recurse first and process the current node
+ * second, as the spec dictates.
+ */
+ matemenu_tree_execute_moves (tree, child, &need_remove_dups);
+ break;
+
+ case MENU_LAYOUT_NODE_MOVE:
+ move_nodes = g_slist_prepend (move_nodes, child);
+ break;
+
+ default:
+ break;
+ }
+
+ child = menu_layout_node_get_next (child);
+ }
+
+ /* We need to execute the move operations in the order that they appear */
+ move_nodes = g_slist_reverse (move_nodes);
+
+ tmp = move_nodes;
+ while (tmp != NULL)
+ {
+ MenuLayoutNode *move_node = tmp->data;
+ MenuLayoutNode *old_node;
+ GSList *next = tmp->next;
+ const char *old;
+ const char *new;
+
+ old = menu_layout_node_move_get_old (move_node);
+ new = menu_layout_node_move_get_new (move_node);
+ g_assert (old != NULL && new != NULL);
+
+ menu_verbose ("executing <Move> old = \"%s\" new = \"%s\"\n",
+ old, new);
+
+ old_node = find_submenu (layout, old, FALSE);
+ if (old_node != NULL)
+ {
+ MenuLayoutNode *new_node;
+
+ /* here we can create duplicates anywhere below the
+ * node
+ */
+ need_remove_dups = TRUE;
+
+ /* look up new node creating it and its parents if
+ * required
+ */
+ new_node = find_submenu (layout, new, TRUE);
+ g_assert (new_node != NULL);
+
+ move_children (old_node, new_node);
+
+ menu_layout_node_unlink (old_node);
+ }
+
+ menu_layout_node_unlink (move_node);
+
+ tmp = next;
+ }
+
+ g_slist_free (move_nodes);
+
+ /* This oddness is to ensure we only remove dups once,
+ * at the root, instead of recursing the tree over
+ * and over.
+ */
+ if (need_remove_dups_p)
+ *need_remove_dups_p = need_remove_dups;
+ else if (need_remove_dups)
+ matemenu_tree_strip_duplicate_children (tree, layout);
+}
+
+static void
+matemenu_tree_load_layout (MateMenuTree *tree)
+{
+ GHashTable *loaded_menu_files;
+ GError *error;
+
+ if (tree->layout)
+ return;
+
+ if (!matemenu_tree_canonicalize_path (tree))
+ return;
+
+ menu_verbose ("Loading menu layout from \"%s\"\n",
+ tree->canonical_path);
+
+ error = NULL;
+ tree->layout = menu_layout_load (tree->canonical_path,
+ tree->type == MATEMENU_TREE_BASENAME ?
+ tree->basename : NULL,
+ &error);
+ if (tree->layout == NULL)
+ {
+ g_warning ("Error loading menu layout from \"%s\": %s",
+ tree->canonical_path, error->message);
+ g_error_free (error);
+ return;
+ }
+
+ loaded_menu_files = g_hash_table_new (g_str_hash, g_str_equal);
+ g_hash_table_insert (loaded_menu_files, tree->canonical_path, GUINT_TO_POINTER (TRUE));
+ matemenu_tree_resolve_files (tree, loaded_menu_files, tree->layout);
+ g_hash_table_destroy (loaded_menu_files);
+
+ matemenu_tree_strip_duplicate_children (tree, tree->layout);
+ matemenu_tree_execute_moves (tree, tree->layout, NULL);
+}
+
+static void
+matemenu_tree_force_reload (MateMenuTree *tree)
+{
+ matemenu_tree_force_rebuild (tree);
+
+ if (tree->layout)
+ menu_layout_node_unref (tree->layout);
+ tree->layout = NULL;
+}
+
+typedef struct
+{
+ DesktopEntrySet *set;
+ const char *category;
+} GetByCategoryForeachData;
+
+static void
+get_by_category_foreach (const char *file_id,
+ DesktopEntry *entry,
+ GetByCategoryForeachData *data)
+{
+ if (desktop_entry_has_category (entry, data->category))
+ desktop_entry_set_add_entry (data->set, entry, file_id);
+}
+
+static void
+get_by_category (DesktopEntrySet *entry_pool,
+ DesktopEntrySet *set,
+ const char *category)
+{
+ GetByCategoryForeachData data;
+
+ data.set = set;
+ data.category = category;
+
+ desktop_entry_set_foreach (entry_pool,
+ (DesktopEntrySetForeachFunc) get_by_category_foreach,
+ &data);
+}
+
+static DesktopEntrySet *
+process_include_rules (MenuLayoutNode *layout,
+ DesktopEntrySet *entry_pool)
+{
+ DesktopEntrySet *set = NULL;
+
+ switch (menu_layout_node_get_type (layout))
+ {
+ case MENU_LAYOUT_NODE_AND:
+ {
+ MenuLayoutNode *child;
+
+ menu_verbose ("Processing <And>\n");
+
+ child = menu_layout_node_get_children (layout);
+ while (child != NULL)
+ {
+ DesktopEntrySet *child_set;
+
+ child_set = process_include_rules (child, entry_pool);
+
+ if (set == NULL)
+ {
+ set = child_set;
+ }
+ else
+ {
+ desktop_entry_set_intersection (set, child_set);
+ desktop_entry_set_unref (child_set);
+ }
+
+ /* as soon as we get empty results, we can bail,
+ * because it's an AND
+ */
+ if (desktop_entry_set_get_count (set) == 0)
+ break;
+
+ child = menu_layout_node_get_next (child);
+ }
+ menu_verbose ("Processed <And>\n");
+ }
+ break;
+
+ case MENU_LAYOUT_NODE_OR:
+ {
+ MenuLayoutNode *child;
+
+ menu_verbose ("Processing <Or>\n");
+
+ child = menu_layout_node_get_children (layout);
+ while (child != NULL)
+ {
+ DesktopEntrySet *child_set;
+
+ child_set = process_include_rules (child, entry_pool);
+
+ if (set == NULL)
+ {
+ set = child_set;
+ }
+ else
+ {
+ desktop_entry_set_union (set, child_set);
+ desktop_entry_set_unref (child_set);
+ }
+
+ child = menu_layout_node_get_next (child);
+ }
+ menu_verbose ("Processed <Or>\n");
+ }
+ break;
+
+ case MENU_LAYOUT_NODE_NOT:
+ {
+ /* First get the OR of all the rules */
+ MenuLayoutNode *child;
+
+ menu_verbose ("Processing <Not>\n");
+
+ child = menu_layout_node_get_children (layout);
+ while (child != NULL)
+ {
+ DesktopEntrySet *child_set;
+
+ child_set = process_include_rules (child, entry_pool);
+
+ if (set == NULL)
+ {
+ set = child_set;
+ }
+ else
+ {
+ desktop_entry_set_union (set, child_set);
+ desktop_entry_set_unref (child_set);
+ }
+
+ child = menu_layout_node_get_next (child);
+ }
+
+ if (set != NULL)
+ {
+ DesktopEntrySet *inverted;
+
+ /* Now invert the result */
+ inverted = desktop_entry_set_new ();
+ desktop_entry_set_union (inverted, entry_pool);
+ desktop_entry_set_subtract (inverted, set);
+ desktop_entry_set_unref (set);
+ set = inverted;
+ }
+ menu_verbose ("Processed <Not>\n");
+ }
+ break;
+
+ case MENU_LAYOUT_NODE_ALL:
+ menu_verbose ("Processing <All>\n");
+ set = desktop_entry_set_new ();
+ desktop_entry_set_union (set, entry_pool);
+ menu_verbose ("Processed <All>\n");
+ break;
+
+ case MENU_LAYOUT_NODE_FILENAME:
+ {
+ DesktopEntry *entry;
+
+ menu_verbose ("Processing <Filename>%s</Filename>\n",
+ menu_layout_node_get_content (layout));
+
+ entry = desktop_entry_set_lookup (entry_pool,
+ menu_layout_node_get_content (layout));
+ if (entry != NULL)
+ {
+ set = desktop_entry_set_new ();
+ desktop_entry_set_add_entry (set,
+ entry,
+ menu_layout_node_get_content (layout));
+ }
+ menu_verbose ("Processed <Filename>%s</Filename>\n",
+ menu_layout_node_get_content (layout));
+ }
+ break;
+
+ case MENU_LAYOUT_NODE_CATEGORY:
+ menu_verbose ("Processing <Category>%s</Category>\n",
+ menu_layout_node_get_content (layout));
+ set = desktop_entry_set_new ();
+ get_by_category (entry_pool, set, menu_layout_node_get_content (layout));
+ menu_verbose ("Processed <Category>%s</Category>\n",
+ menu_layout_node_get_content (layout));
+ break;
+
+ default:
+ break;
+ }
+
+ if (set == NULL)
+ set = desktop_entry_set_new (); /* create an empty set */
+
+ menu_verbose ("Matched %d entries\n", desktop_entry_set_get_count (set));
+
+ return set;
+}
+
+static void
+collect_layout_info (MenuLayoutNode *layout,
+ GSList **layout_info)
+{
+ MenuLayoutNode *iter;
+
+ g_slist_foreach (*layout_info,
+ (GFunc) menu_layout_node_unref,
+ NULL);
+ g_slist_free (*layout_info);
+ *layout_info = NULL;
+
+ iter = menu_layout_node_get_children (layout);
+ while (iter != NULL)
+ {
+ switch (menu_layout_node_get_type (iter))
+ {
+ case MENU_LAYOUT_NODE_MENUNAME:
+ case MENU_LAYOUT_NODE_FILENAME:
+ case MENU_LAYOUT_NODE_SEPARATOR:
+ case MENU_LAYOUT_NODE_MERGE:
+ *layout_info = g_slist_prepend (*layout_info,
+ menu_layout_node_ref (iter));
+ break;
+
+ default:
+ break;
+ }
+
+ iter = menu_layout_node_get_next (iter);
+ }
+
+ *layout_info = g_slist_reverse (*layout_info);
+}
+
+static void
+entries_listify_foreach (const char *desktop_file_id,
+ DesktopEntry *desktop_entry,
+ MateMenuTreeDirectory *directory)
+{
+ directory->entries =
+ g_slist_prepend (directory->entries,
+ matemenu_tree_entry_new (directory,
+ desktop_entry,
+ desktop_file_id,
+ FALSE,
+ desktop_entry_get_no_display (desktop_entry)));
+}
+
+static void
+excluded_entries_listify_foreach (const char *desktop_file_id,
+ DesktopEntry *desktop_entry,
+ MateMenuTreeDirectory *directory)
+{
+ directory->entries =
+ g_slist_prepend (directory->entries,
+ matemenu_tree_entry_new (directory,
+ desktop_entry,
+ desktop_file_id,
+ TRUE,
+ desktop_entry_get_no_display (desktop_entry)));
+}
+
+static void
+set_default_layout_values (MateMenuTreeDirectory *parent,
+ MateMenuTreeDirectory *child)
+{
+ GSList *tmp;
+
+ /* if the child has a defined default layout, we don't want to override its
+ * values. The parent might have a non-defined layout info (ie, no child of
+ * the DefaultLayout node) but it doesn't meant the default layout values
+ * (ie, DefaultLayout attributes) aren't different from the global defaults.
+ */
+ if (child->default_layout_info != NULL ||
+ child->default_layout_values.mask != MENU_LAYOUT_VALUES_NONE)
+ return;
+
+ child->default_layout_values = parent->default_layout_values;
+
+ tmp = child->subdirs;
+ while (tmp != NULL)
+ {
+ MateMenuTreeDirectory *subdir = tmp->data;
+
+ set_default_layout_values (child, subdir);
+
+ tmp = tmp->next;
+ }
+}
+
+static MateMenuTreeDirectory *
+process_layout (MateMenuTree *tree,
+ MateMenuTreeDirectory *parent,
+ MenuLayoutNode *layout,
+ DesktopEntrySet *allocated)
+{
+ MenuLayoutNode *layout_iter;
+ MateMenuTreeDirectory *directory;
+ DesktopEntrySet *entry_pool;
+ DesktopEntrySet *entries;
+ DesktopEntrySet *allocated_set;
+ DesktopEntrySet *excluded_set;
+ gboolean deleted;
+ gboolean only_unallocated;
+ GSList *tmp;
+
+ g_assert (menu_layout_node_get_type (layout) == MENU_LAYOUT_NODE_MENU);
+ g_assert (menu_layout_node_menu_get_name (layout) != NULL);
+
+ directory = matemenu_tree_directory_new (parent,
+ menu_layout_node_menu_get_name (layout),
+ parent == NULL);
+
+ menu_verbose ("=== Menu name = %s ===\n", directory->name);
+
+
+ deleted = FALSE;
+ only_unallocated = FALSE;
+
+ entries = desktop_entry_set_new ();
+ allocated_set = desktop_entry_set_new ();
+
+ if (tree->flags & MATEMENU_TREE_FLAGS_INCLUDE_EXCLUDED)
+ excluded_set = desktop_entry_set_new ();
+ else
+ excluded_set = NULL;
+
+ entry_pool = _entry_directory_list_get_all_desktops (menu_layout_node_menu_get_app_dirs (layout));
+
+ layout_iter = menu_layout_node_get_children (layout);
+ while (layout_iter != NULL)
+ {
+ switch (menu_layout_node_get_type (layout_iter))
+ {
+ case MENU_LAYOUT_NODE_MENU:
+ /* recurse */
+ {
+ MateMenuTreeDirectory *child_dir;
+
+ menu_verbose ("Processing <Menu>\n");
+
+ child_dir = process_layout (tree,
+ directory,
+ layout_iter,
+ allocated);
+ if (child_dir)
+ directory->subdirs = g_slist_prepend (directory->subdirs,
+ child_dir);
+
+ menu_verbose ("Processed <Menu>\n");
+ }
+ break;
+
+ case MENU_LAYOUT_NODE_INCLUDE:
+ {
+ /* The match rule children of the <Include> are
+ * independent (logical OR) so we can process each one by
+ * itself
+ */
+ MenuLayoutNode *rule;
+
+ menu_verbose ("Processing <Include> (%d entries)\n",
+ desktop_entry_set_get_count (entries));
+
+ rule = menu_layout_node_get_children (layout_iter);
+ while (rule != NULL)
+ {
+ DesktopEntrySet *rule_set;
+
+ rule_set = process_include_rules (rule, entry_pool);
+ if (rule_set != NULL)
+ {
+ desktop_entry_set_union (entries, rule_set);
+ desktop_entry_set_union (allocated_set, rule_set);
+ if (excluded_set != NULL)
+ desktop_entry_set_subtract (excluded_set, rule_set);
+ desktop_entry_set_unref (rule_set);
+ }
+
+ rule = menu_layout_node_get_next (rule);
+ }
+
+ menu_verbose ("Processed <Include> (%d entries)\n",
+ desktop_entry_set_get_count (entries));
+ }
+ break;
+
+ case MENU_LAYOUT_NODE_EXCLUDE:
+ {
+ /* The match rule children of the <Exclude> are
+ * independent (logical OR) so we can process each one by
+ * itself
+ */
+ MenuLayoutNode *rule;
+
+ menu_verbose ("Processing <Exclude> (%d entries)\n",
+ desktop_entry_set_get_count (entries));
+
+ rule = menu_layout_node_get_children (layout_iter);
+ while (rule != NULL)
+ {
+ DesktopEntrySet *rule_set;
+
+ rule_set = process_include_rules (rule, entry_pool);
+ if (rule_set != NULL)
+ {
+ if (excluded_set != NULL)
+ desktop_entry_set_union (excluded_set, rule_set);
+ desktop_entry_set_subtract (entries, rule_set);
+ desktop_entry_set_unref (rule_set);
+ }
+
+ rule = menu_layout_node_get_next (rule);
+ }
+
+ menu_verbose ("Processed <Exclude> (%d entries)\n",
+ desktop_entry_set_get_count (entries));
+ }
+ break;
+
+ case MENU_LAYOUT_NODE_DIRECTORY:
+ {
+ DesktopEntry *entry;
+
+ menu_verbose ("Processing <Directory>%s</Directory>\n",
+ menu_layout_node_get_content (layout_iter));
+
+ /*
+ * The last <Directory> to exist wins, so we always try overwriting
+ */
+ entry = entry_directory_list_get_directory (menu_layout_node_menu_get_directory_dirs (layout),
+ menu_layout_node_get_content (layout_iter));
+
+ if (entry != NULL)
+ {
+ if (!desktop_entry_get_hidden (entry))
+ {
+ if (directory->directory_entry)
+ desktop_entry_unref (directory->directory_entry);
+ directory->directory_entry = entry; /* pass ref ownership */
+ }
+ else
+ {
+ desktop_entry_unref (entry);
+ }
+ }
+
+ menu_verbose ("Processed <Directory> new directory entry = %p (%s)\n",
+ directory->directory_entry,
+ directory->directory_entry? desktop_entry_get_path (directory->directory_entry) : "null");
+ }
+ break;
+
+ case MENU_LAYOUT_NODE_DELETED:
+ menu_verbose ("Processed <Deleted/>\n");
+ deleted = TRUE;
+ break;
+
+ case MENU_LAYOUT_NODE_NOT_DELETED:
+ menu_verbose ("Processed <NotDeleted/>\n");
+ deleted = FALSE;
+ break;
+
+ case MENU_LAYOUT_NODE_ONLY_UNALLOCATED:
+ menu_verbose ("Processed <OnlyUnallocated/>\n");
+ only_unallocated = TRUE;
+ break;
+
+ case MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED:
+ menu_verbose ("Processed <NotOnlyUnallocated/>\n");
+ only_unallocated = FALSE;
+ break;
+
+ case MENU_LAYOUT_NODE_DEFAULT_LAYOUT:
+ menu_layout_node_default_layout_get_values (layout_iter,
+ &directory->default_layout_values);
+ collect_layout_info (layout_iter, &directory->default_layout_info);
+ menu_verbose ("Processed <DefaultLayout/>\n");
+ break;
+
+ case MENU_LAYOUT_NODE_LAYOUT:
+ collect_layout_info (layout_iter, &directory->layout_info);
+ menu_verbose ("Processed <Layout/>\n");
+ break;
+
+ default:
+ break;
+ }
+
+ layout_iter = menu_layout_node_get_next (layout_iter);
+ }
+
+ desktop_entry_set_unref (entry_pool);
+
+ directory->only_unallocated = only_unallocated;
+
+ if (!directory->only_unallocated)
+ desktop_entry_set_union (allocated, allocated_set);
+
+ desktop_entry_set_unref (allocated_set);
+
+ if (directory->directory_entry)
+ {
+ if (desktop_entry_get_no_display (directory->directory_entry))
+ {
+ directory->is_nodisplay = TRUE;
+
+ if (!(tree->flags & MATEMENU_TREE_FLAGS_INCLUDE_NODISPLAY))
+ {
+ menu_verbose ("Not showing menu %s because NoDisplay=true\n",
+ desktop_entry_get_name (directory->directory_entry));
+ deleted = TRUE;
+ }
+ }
+
+ if (!desktop_entry_get_show_in_mate (directory->directory_entry))
+ {
+ menu_verbose ("Not showing menu %s because OnlyShowIn!=MATE or NotShowIn=MATE\n",
+ desktop_entry_get_name (directory->directory_entry));
+ deleted = TRUE;
+ }
+ }
+
+ if (deleted)
+ {
+ if (excluded_set != NULL)
+ desktop_entry_set_unref (excluded_set);
+ desktop_entry_set_unref (entries);
+ matemenu_tree_item_unref (directory);
+ return NULL;
+ }
+
+ desktop_entry_set_foreach (entries,
+ (DesktopEntrySetForeachFunc) entries_listify_foreach,
+ directory);
+ desktop_entry_set_unref (entries);
+
+ if (excluded_set != NULL)
+ {
+ desktop_entry_set_foreach (excluded_set,
+ (DesktopEntrySetForeachFunc) excluded_entries_listify_foreach,
+ directory);
+ desktop_entry_set_unref (excluded_set);
+ }
+
+ tmp = directory->subdirs;
+ while (tmp != NULL)
+ {
+ MateMenuTreeDirectory *subdir = tmp->data;
+
+ set_default_layout_values (directory, subdir);
+
+ tmp = tmp->next;
+ }
+
+ tmp = directory->entries;
+ while (tmp != NULL)
+ {
+ MateMenuTreeEntry *entry = tmp->data;
+ GSList *next = tmp->next;
+ gboolean delete = FALSE;
+
+ if (desktop_entry_get_hidden (entry->desktop_entry))
+ {
+ menu_verbose ("Deleting %s because Hidden=true\n",
+ desktop_entry_get_name (entry->desktop_entry));
+ delete = TRUE;
+ }
+
+ if (!(tree->flags & MATEMENU_TREE_FLAGS_INCLUDE_NODISPLAY) &&
+ desktop_entry_get_no_display (entry->desktop_entry))
+ {
+ menu_verbose ("Deleting %s because NoDisplay=true\n",
+ desktop_entry_get_name (entry->desktop_entry));
+ delete = TRUE;
+ }
+
+ if (!desktop_entry_get_show_in_mate (entry->desktop_entry))
+ {
+ menu_verbose ("Deleting %s because OnlyShowIn!=MATE or NotShowIn=MATE\n",
+ desktop_entry_get_name (entry->desktop_entry));
+ delete = TRUE;
+ }
+
+ if (desktop_entry_get_tryexec_failed (entry->desktop_entry))
+ {
+ menu_verbose ("Deleting %s because TryExec failed\n",
+ desktop_entry_get_name (entry->desktop_entry));
+ delete = TRUE;
+ }
+
+ if (delete)
+ {
+ directory->entries = g_slist_delete_link (directory->entries,
+ tmp);
+ matemenu_tree_item_unref_and_unset_parent (entry);
+ }
+
+ tmp = next;
+ }
+
+ g_assert (directory->name != NULL);
+
+ return directory;
+}
+
+static void
+process_only_unallocated (MateMenuTree *tree,
+ MateMenuTreeDirectory *directory,
+ DesktopEntrySet *allocated)
+{
+ GSList *tmp;
+
+ /* For any directory marked only_unallocated, we have to remove any
+ * entries that were in fact allocated.
+ */
+
+ if (directory->only_unallocated)
+ {
+ tmp = directory->entries;
+ while (tmp != NULL)
+ {
+ MateMenuTreeEntry *entry = tmp->data;
+ GSList *next = tmp->next;
+
+ if (desktop_entry_set_lookup (allocated, entry->desktop_file_id))
+ {
+ directory->entries = g_slist_delete_link (directory->entries,
+ tmp);
+ matemenu_tree_item_unref_and_unset_parent (entry);
+ }
+
+ tmp = next;
+ }
+ }
+
+ tmp = directory->subdirs;
+ while (tmp != NULL)
+ {
+ MateMenuTreeDirectory *subdir = tmp->data;
+
+ process_only_unallocated (tree, subdir, allocated);
+
+ tmp = tmp->next;
+ }
+}
+
+static void preprocess_layout_info (MateMenuTree *tree,
+ MateMenuTreeDirectory *directory);
+
+static GSList *
+get_layout_info (MateMenuTreeDirectory *directory,
+ gboolean *is_default_layout)
+{
+ MateMenuTreeDirectory *iter;
+
+ if (directory->layout_info != NULL)
+ {
+ if (is_default_layout)
+ {
+ *is_default_layout = FALSE;
+ }
+ return directory->layout_info;
+ }
+
+ /* Even if there's no layout information at all, the result will be an
+ * implicit default layout */
+ if (is_default_layout)
+ {
+ *is_default_layout = TRUE;
+ }
+
+ iter = directory;
+ while (iter != NULL)
+ {
+ /* FIXME: this is broken: we might skip real parent in the
+ * XML structure, that are hidden because of inlining. */
+ if (iter->default_layout_info != NULL)
+ {
+ return iter->default_layout_info;
+ }
+
+ iter = MATEMENU_TREE_ITEM (iter)->parent;
+ }
+
+ return NULL;
+}
+
+static void
+get_values_with_defaults (MenuLayoutNode *node,
+ MenuLayoutValues *layout_values,
+ MenuLayoutValues *default_layout_values)
+{
+ menu_layout_node_menuname_get_values (node, layout_values);
+
+ if (!(layout_values->mask & MENU_LAYOUT_VALUES_SHOW_EMPTY))
+ layout_values->show_empty = default_layout_values->show_empty;
+
+ if (!(layout_values->mask & MENU_LAYOUT_VALUES_INLINE_MENUS))
+ layout_values->inline_menus = default_layout_values->inline_menus;
+
+ if (!(layout_values->mask & MENU_LAYOUT_VALUES_INLINE_LIMIT))
+ layout_values->inline_limit = default_layout_values->inline_limit;
+
+ if (!(layout_values->mask & MENU_LAYOUT_VALUES_INLINE_HEADER))
+ layout_values->inline_header = default_layout_values->inline_header;
+
+ if (!(layout_values->mask & MENU_LAYOUT_VALUES_INLINE_ALIAS))
+ layout_values->inline_alias = default_layout_values->inline_alias;
+}
+
+static guint
+get_real_subdirs_len (MateMenuTreeDirectory *directory)
+{
+ guint len;
+ GSList *tmp;
+
+ len = 0;
+
+ tmp = directory->subdirs;
+ while (tmp != NULL)
+ {
+ MateMenuTreeDirectory *subdir = tmp->data;
+
+ tmp = tmp->next;
+
+ if (subdir->will_inline_header != G_MAXUINT16)
+ {
+ len += get_real_subdirs_len (subdir) + g_slist_length (subdir->entries) + 1;
+ }
+ else
+ len += 1;
+ }
+
+ return len;
+}
+
+static void
+preprocess_layout_info_subdir_helper (MateMenuTree *tree,
+ MateMenuTreeDirectory *directory,
+ MateMenuTreeDirectory *subdir,
+ MenuLayoutValues *layout_values,
+ gboolean *contents_added,
+ gboolean *should_remove)
+{
+ preprocess_layout_info (tree, subdir);
+
+ *should_remove = FALSE;
+ *contents_added = FALSE;
+
+ if (subdir->subdirs == NULL && subdir->entries == NULL)
+ {
+ if (!(tree->flags & MATEMENU_TREE_FLAGS_SHOW_EMPTY) &&
+ !layout_values->show_empty)
+ {
+ menu_verbose ("Not showing empty menu '%s'\n", subdir->name);
+ *should_remove = TRUE;
+ }
+ }
+
+ else if (layout_values->inline_menus)
+ {
+ guint real_subdirs_len;
+
+ real_subdirs_len = get_real_subdirs_len (subdir);
+
+ if (layout_values->inline_alias &&
+ real_subdirs_len + g_slist_length (subdir->entries) == 1)
+ {
+ MateMenuTreeAlias *alias;
+ MateMenuTreeItem *item;
+ GSList *list;
+
+ if (subdir->subdirs != NULL)
+ list = subdir->subdirs;
+ else
+ list = subdir->entries;
+
+ item = MATEMENU_TREE_ITEM (list->data);
+
+ menu_verbose ("Inline aliasing '%s' to '%s'\n",
+ item->type == MATEMENU_TREE_ITEM_ENTRY ?
+ matemenu_tree_entry_get_name (MATEMENU_TREE_ENTRY (item)) :
+ (item->type == MATEMENU_TREE_ITEM_DIRECTORY ?
+ matemenu_tree_directory_get_name (MATEMENU_TREE_DIRECTORY (item)) :
+ matemenu_tree_directory_get_name (MATEMENU_TREE_ALIAS (item)->directory)),
+ subdir->name);
+
+ alias = matemenu_tree_alias_new (directory, subdir, item);
+
+ g_slist_foreach (list,
+ (GFunc) matemenu_tree_item_unref_and_unset_parent,
+ NULL);
+ g_slist_free (list);
+ subdir->subdirs = NULL;
+ subdir->entries = NULL;
+
+ if (item->type == MATEMENU_TREE_ITEM_DIRECTORY)
+ directory->subdirs = g_slist_append (directory->subdirs, alias);
+ else
+ directory->entries = g_slist_append (directory->entries, alias);
+
+ *contents_added = TRUE;
+ *should_remove = TRUE;
+ }
+
+ else if (layout_values->inline_limit == 0 ||
+ layout_values->inline_limit >= real_subdirs_len + g_slist_length (subdir->entries))
+ {
+ if (layout_values->inline_header)
+ {
+ menu_verbose ("Creating inline header with name '%s'\n", subdir->name);
+ /* we're limited to 16-bits to spare some memory; if the limit is
+ * higher than that (would be crazy), we just consider it's
+ * unlimited */
+ if (layout_values->inline_limit < G_MAXUINT16)
+ subdir->will_inline_header = layout_values->inline_limit;
+ else
+ subdir->will_inline_header = 0;
+ }
+ else
+ {
+ g_slist_foreach (subdir->subdirs,
+ (GFunc) matemenu_tree_item_set_parent,
+ directory);
+ directory->subdirs = g_slist_concat (directory->subdirs,
+ subdir->subdirs);
+ subdir->subdirs = NULL;
+
+ g_slist_foreach (subdir->entries,
+ (GFunc) matemenu_tree_item_set_parent,
+ directory);
+ directory->entries = g_slist_concat (directory->entries,
+ subdir->entries);
+ subdir->entries = NULL;
+
+ *contents_added = TRUE;
+ *should_remove = TRUE;
+ }
+
+ menu_verbose ("Inlining directory contents of '%s' to '%s'\n",
+ subdir->name, directory->name);
+ }
+ }
+}
+
+static void
+preprocess_layout_info (MateMenuTree *tree,
+ MateMenuTreeDirectory *directory)
+{
+ GSList *tmp;
+ GSList *layout_info;
+ gboolean using_default_layout;
+ GSList *last_subdir;
+ gboolean strip_duplicates;
+ gboolean contents_added;
+ gboolean should_remove;
+ GSList *subdirs_sentinel;
+
+ /* Note: we need to preprocess all menus, even if the layout mask for a menu
+ * is MENU_LAYOUT_VALUES_NONE: in this case, we need to remove empty menus;
+ * and the layout mask can be different for a submenu anyway */
+
+ menu_verbose ("Processing menu layout inline hints for %s\n", directory->name);
+ g_assert (!directory->preprocessed);
+
+ strip_duplicates = FALSE;
+ /* we use last_subdir to track the last non-inlined subdirectory */
+ last_subdir = g_slist_last (directory->subdirs);
+
+ /*
+ * First process subdirectories with explicit layout
+ */
+ layout_info = get_layout_info (directory, &using_default_layout);
+ tmp = layout_info;
+ /* see comment below about Menuname to understand why we leave the loop if
+ * last_subdir is NULL */
+ while (tmp != NULL && last_subdir != NULL)
+ {
+ MenuLayoutNode *node = tmp->data;
+ MenuLayoutValues layout_values;
+ const char *name;
+ MateMenuTreeDirectory *subdir;
+ GSList *subdir_l;
+
+ tmp = tmp->next;
+
+ /* only Menuname nodes are relevant here */
+ if (menu_layout_node_get_type (node) != MENU_LAYOUT_NODE_MENUNAME)
+ continue;
+
+ get_values_with_defaults (node,
+ &layout_values,
+ &directory->default_layout_values);
+
+ /* find the subdirectory that is affected by those attributes */
+ name = menu_layout_node_get_content (node);
+ subdir = NULL;
+ subdir_l = directory->subdirs;
+ while (subdir_l != NULL)
+ {
+ subdir = subdir_l->data;
+
+ if (!strcmp (subdir->name, name))
+ break;
+
+ subdir = NULL;
+ subdir_l = subdir_l->next;
+
+ /* We do not want to use Menuname on a menu that appeared via
+ * inlining: without inlining, the Menuname wouldn't have matched
+ * anything, and we want to keep the same behavior.
+ * Unless the layout is a default layout, in which case the Menuname
+ * does match the subdirectory. */
+ if (!using_default_layout && subdir_l == last_subdir)
+ {
+ subdir_l = NULL;
+ break;
+ }
+ }
+
+ if (subdir == NULL)
+ continue;
+
+ preprocess_layout_info_subdir_helper (tree, directory,
+ subdir, &layout_values,
+ &contents_added, &should_remove);
+ strip_duplicates = strip_duplicates || contents_added;
+ if (should_remove)
+ {
+ if (last_subdir == subdir_l)
+ {
+ /* we need to recompute last_subdir since we'll remove it from
+ * the list */
+ GSList *buf;
+
+ if (subdir_l == directory->subdirs)
+ last_subdir = NULL;
+ else
+ {
+ buf = directory->subdirs;
+ while (buf != NULL && buf->next != subdir_l)
+ buf = buf->next;
+ last_subdir = buf;
+ }
+ }
+
+ directory->subdirs = g_slist_remove (directory->subdirs, subdir);
+ matemenu_tree_item_unref_and_unset_parent (MATEMENU_TREE_ITEM (subdir));
+ }
+ }
+
+ /*
+ * Now process the subdirectories with no explicit layout
+ */
+ /* this is bogus data, but we just need the pointer anyway */
+ subdirs_sentinel = g_slist_prepend (directory->subdirs, PACKAGE);
+ directory->subdirs = subdirs_sentinel;
+
+ tmp = directory->subdirs;
+ while (tmp->next != NULL)
+ {
+ MateMenuTreeDirectory *subdir = tmp->next->data;
+
+ if (subdir->preprocessed)
+ {
+ tmp = tmp->next;
+ continue;
+ }
+
+ preprocess_layout_info_subdir_helper (tree, directory,
+ subdir, &directory->default_layout_values,
+ &contents_added, &should_remove);
+ strip_duplicates = strip_duplicates || contents_added;
+ if (should_remove)
+ {
+ tmp = g_slist_delete_link (tmp, tmp->next);
+ matemenu_tree_item_unref_and_unset_parent (MATEMENU_TREE_ITEM (subdir));
+ }
+ else
+ tmp = tmp->next;
+ }
+
+ /* remove the sentinel */
+ directory->subdirs = g_slist_delete_link (directory->subdirs,
+ directory->subdirs);
+
+ /*
+ * Finally, remove duplicates if needed
+ */
+ if (strip_duplicates)
+ {
+ /* strip duplicate entries; there should be no duplicate directories */
+ directory->entries = g_slist_sort (directory->entries,
+ (GCompareFunc) matemenu_tree_entry_compare_by_id);
+ tmp = directory->entries;
+ while (tmp != NULL && tmp->next != NULL)
+ {
+ MateMenuTreeItem *a = tmp->data;
+ MateMenuTreeItem *b = tmp->next->data;
+
+ if (a->type == MATEMENU_TREE_ITEM_ALIAS)
+ a = MATEMENU_TREE_ALIAS (a)->aliased_item;
+
+ if (b->type == MATEMENU_TREE_ITEM_ALIAS)
+ b = MATEMENU_TREE_ALIAS (b)->aliased_item;
+
+ if (strcmp (MATEMENU_TREE_ENTRY (a)->desktop_file_id,
+ MATEMENU_TREE_ENTRY (b)->desktop_file_id) == 0)
+ {
+ tmp = g_slist_delete_link (tmp, tmp->next);
+ matemenu_tree_item_unref (b);
+ }
+ else
+ tmp = tmp->next;
+ }
+ }
+
+ directory->preprocessed = TRUE;
+}
+
+static void process_layout_info (MateMenuTree *tree,
+ MateMenuTreeDirectory *directory);
+
+static void
+check_pending_separator (MateMenuTreeDirectory *directory)
+{
+ if (directory->layout_pending_separator)
+ {
+ menu_verbose ("Adding pending separator in '%s'\n", directory->name);
+
+ directory->contents = g_slist_append (directory->contents,
+ matemenu_tree_separator_new (directory));
+ directory->layout_pending_separator = FALSE;
+ }
+}
+
+static void
+merge_alias (MateMenuTree *tree,
+ MateMenuTreeDirectory *directory,
+ MateMenuTreeAlias *alias)
+{
+ menu_verbose ("Merging alias '%s' in directory '%s'\n",
+ alias->directory->name, directory->name);
+
+ if (alias->aliased_item->type == MATEMENU_TREE_ITEM_DIRECTORY)
+ {
+ process_layout_info (tree, MATEMENU_TREE_DIRECTORY (alias->aliased_item));
+ }
+
+ check_pending_separator (directory);
+
+ directory->contents = g_slist_append (directory->contents,
+ matemenu_tree_item_ref (alias));
+}
+
+static void
+merge_subdir (MateMenuTree *tree,
+ MateMenuTreeDirectory *directory,
+ MateMenuTreeDirectory *subdir)
+{
+ menu_verbose ("Merging subdir '%s' in directory '%s'\n",
+ subdir->name, directory->name);
+
+ process_layout_info (tree, subdir);
+
+ check_pending_separator (directory);
+
+ if (subdir->will_inline_header == 0 ||
+ (subdir->will_inline_header != G_MAXUINT16 &&
+ g_slist_length (subdir->contents) <= subdir->will_inline_header))
+ {
+ MateMenuTreeHeader *header;
+
+ header = matemenu_tree_header_new (directory, subdir);
+ directory->contents = g_slist_append (directory->contents, header);
+
+ g_slist_foreach (subdir->contents,
+ (GFunc) matemenu_tree_item_set_parent,
+ directory);
+ directory->contents = g_slist_concat (directory->contents,
+ subdir->contents);
+ subdir->contents = NULL;
+ subdir->will_inline_header = G_MAXUINT16;
+
+ matemenu_tree_item_set_parent (MATEMENU_TREE_ITEM (subdir), NULL);
+ }
+ else
+ {
+ directory->contents = g_slist_append (directory->contents,
+ matemenu_tree_item_ref (subdir));
+ }
+}
+
+static void
+merge_subdir_by_name (MateMenuTree *tree,
+ MateMenuTreeDirectory *directory,
+ const char *subdir_name)
+{
+ GSList *tmp;
+
+ menu_verbose ("Attempting to merge subdir '%s' in directory '%s'\n",
+ subdir_name, directory->name);
+
+ tmp = directory->subdirs;
+ while (tmp != NULL)
+ {
+ MateMenuTreeDirectory *subdir = tmp->data;
+ GSList *next = tmp->next;
+
+ /* if it's an alias, then it cannot be affected by
+ * the Merge nodes in the layout */
+ if (MATEMENU_TREE_ITEM (subdir)->type == MATEMENU_TREE_ITEM_ALIAS)
+ continue;
+
+ if (!strcmp (subdir->name, subdir_name))
+ {
+ directory->subdirs = g_slist_delete_link (directory->subdirs, tmp);
+ merge_subdir (tree, directory, subdir);
+ matemenu_tree_item_unref (subdir);
+ }
+
+ tmp = next;
+ }
+}
+
+static void
+merge_entry (MateMenuTree *tree,
+ MateMenuTreeDirectory *directory,
+ MateMenuTreeEntry *entry)
+{
+ menu_verbose ("Merging entry '%s' in directory '%s'\n",
+ entry->desktop_file_id, directory->name);
+
+ check_pending_separator (directory);
+ directory->contents = g_slist_append (directory->contents,
+ matemenu_tree_item_ref (entry));
+}
+
+static void
+merge_entry_by_id (MateMenuTree *tree,
+ MateMenuTreeDirectory *directory,
+ const char *file_id)
+{
+ GSList *tmp;
+
+ menu_verbose ("Attempting to merge entry '%s' in directory '%s'\n",
+ file_id, directory->name);
+
+ tmp = directory->entries;
+ while (tmp != NULL)
+ {
+ MateMenuTreeEntry *entry = tmp->data;
+ GSList *next = tmp->next;
+
+ /* if it's an alias, then it cannot be affected by
+ * the Merge nodes in the layout */
+ if (MATEMENU_TREE_ITEM (entry)->type == MATEMENU_TREE_ITEM_ALIAS)
+ continue;
+
+ if (!strcmp (entry->desktop_file_id, file_id))
+ {
+ directory->entries = g_slist_delete_link (directory->entries, tmp);
+ merge_entry (tree, directory, entry);
+ matemenu_tree_item_unref (entry);
+ }
+
+ tmp = next;
+ }
+}
+
+static inline gboolean
+find_name_in_list (const char *name,
+ GSList *list)
+{
+ while (list != NULL)
+ {
+ if (!strcmp (name, list->data))
+ return TRUE;
+
+ list = list->next;
+ }
+
+ return FALSE;
+}
+
+static void
+merge_subdirs (MateMenuTree *tree,
+ MateMenuTreeDirectory *directory,
+ GSList *except)
+{
+ GSList *subdirs;
+ GSList *tmp;
+
+ menu_verbose ("Merging subdirs in directory '%s'\n", directory->name);
+
+ subdirs = directory->subdirs;
+ directory->subdirs = NULL;
+
+ subdirs = g_slist_sort_with_data (subdirs,
+ (GCompareDataFunc) matemenu_tree_item_compare,
+ GINT_TO_POINTER (MATEMENU_TREE_SORT_NAME));
+
+ tmp = subdirs;
+ while (tmp != NULL)
+ {
+ MateMenuTreeDirectory *subdir = tmp->data;
+
+ if (MATEMENU_TREE_ITEM (subdir)->type == MATEMENU_TREE_ITEM_ALIAS)
+ {
+ merge_alias (tree, directory, MATEMENU_TREE_ALIAS (subdir));
+ matemenu_tree_item_unref (subdir);
+ }
+ else if (!find_name_in_list (subdir->name, except))
+ {
+ merge_subdir (tree, directory, subdir);
+ matemenu_tree_item_unref (subdir);
+ }
+ else
+ {
+ menu_verbose ("Not merging directory '%s' yet\n", subdir->name);
+ directory->subdirs = g_slist_append (directory->subdirs, subdir);
+ }
+
+ tmp = tmp->next;
+ }
+
+ g_slist_free (subdirs);
+ g_slist_free (except);
+}
+
+static void
+merge_entries (MateMenuTree *tree,
+ MateMenuTreeDirectory *directory,
+ GSList *except)
+{
+ GSList *entries;
+ GSList *tmp;
+
+ menu_verbose ("Merging entries in directory '%s'\n", directory->name);
+
+ entries = directory->entries;
+ directory->entries = NULL;
+
+ entries = g_slist_sort_with_data (entries,
+ (GCompareDataFunc) matemenu_tree_item_compare,
+ GINT_TO_POINTER (tree->sort_key));
+
+ tmp = entries;
+ while (tmp != NULL)
+ {
+ MateMenuTreeEntry *entry = tmp->data;
+
+ if (MATEMENU_TREE_ITEM (entry)->type == MATEMENU_TREE_ITEM_ALIAS)
+ {
+ merge_alias (tree, directory, MATEMENU_TREE_ALIAS (entry));
+ matemenu_tree_item_unref (entry);
+ }
+ else if (!find_name_in_list (entry->desktop_file_id, except))
+ {
+ merge_entry (tree, directory, entry);
+ matemenu_tree_item_unref (entry);
+ }
+ else
+ {
+ menu_verbose ("Not merging entry '%s' yet\n", entry->desktop_file_id);
+ directory->entries = g_slist_append (directory->entries, entry);
+ }
+
+ tmp = tmp->next;
+ }
+
+ g_slist_free (entries);
+ g_slist_free (except);
+}
+
+static void
+merge_subdirs_and_entries (MateMenuTree *tree,
+ MateMenuTreeDirectory *directory,
+ GSList *except_subdirs,
+ GSList *except_entries)
+{
+ GSList *items;
+ GSList *tmp;
+
+ menu_verbose ("Merging subdirs and entries together in directory %s\n",
+ directory->name);
+
+ items = g_slist_concat (directory->subdirs, directory->entries);
+
+ directory->subdirs = NULL;
+ directory->entries = NULL;
+
+ items = g_slist_sort_with_data (items,
+ (GCompareDataFunc) matemenu_tree_item_compare,
+ GINT_TO_POINTER (tree->sort_key));
+
+ tmp = items;
+ while (tmp != NULL)
+ {
+ MateMenuTreeItem *item = tmp->data;
+ MateMenuTreeItemType type;
+
+ type = matemenu_tree_item_get_type (item);
+
+ if (type == MATEMENU_TREE_ITEM_ALIAS)
+ {
+ merge_alias (tree, directory, MATEMENU_TREE_ALIAS (item));
+ matemenu_tree_item_unref (item);
+ }
+ else if (type == MATEMENU_TREE_ITEM_DIRECTORY)
+ {
+ if (!find_name_in_list (MATEMENU_TREE_DIRECTORY (item)->name, except_subdirs))
+ {
+ merge_subdir (tree,
+ directory,
+ MATEMENU_TREE_DIRECTORY (item));
+ matemenu_tree_item_unref (item);
+ }
+ else
+ {
+ menu_verbose ("Not merging directory '%s' yet\n",
+ MATEMENU_TREE_DIRECTORY (item)->name);
+ directory->subdirs = g_slist_append (directory->subdirs, item);
+ }
+ }
+ else if (type == MATEMENU_TREE_ITEM_ENTRY)
+ {
+ if (!find_name_in_list (MATEMENU_TREE_ENTRY (item)->desktop_file_id, except_entries))
+ {
+ merge_entry (tree, directory, MATEMENU_TREE_ENTRY (item));
+ matemenu_tree_item_unref (item);
+ }
+ else
+ {
+ menu_verbose ("Not merging entry '%s' yet\n",
+ MATEMENU_TREE_ENTRY (item)->desktop_file_id);
+ directory->entries = g_slist_append (directory->entries, item);
+ }
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+
+ tmp = tmp->next;
+ }
+
+ g_slist_free (items);
+ g_slist_free (except_subdirs);
+ g_slist_free (except_entries);
+}
+
+static GSList *
+get_subdirs_from_layout_info (GSList *layout_info)
+{
+ GSList *subdirs;
+ GSList *tmp;
+
+ subdirs = NULL;
+
+ tmp = layout_info;
+ while (tmp != NULL)
+ {
+ MenuLayoutNode *node = tmp->data;
+
+ if (menu_layout_node_get_type (node) == MENU_LAYOUT_NODE_MENUNAME)
+ {
+ subdirs = g_slist_append (subdirs,
+ (char *) menu_layout_node_get_content (node));
+ }
+
+ tmp = tmp->next;
+ }
+
+ return subdirs;
+}
+
+static GSList *
+get_entries_from_layout_info (GSList *layout_info)
+{
+ GSList *entries;
+ GSList *tmp;
+
+ entries = NULL;
+
+ tmp = layout_info;
+ while (tmp != NULL)
+ {
+ MenuLayoutNode *node = tmp->data;
+
+ if (menu_layout_node_get_type (node) == MENU_LAYOUT_NODE_FILENAME)
+ {
+ entries = g_slist_append (entries,
+ (char *) menu_layout_node_get_content (node));
+ }
+
+ tmp = tmp->next;
+ }
+
+ return entries;
+}
+
+static void
+process_layout_info (MateMenuTree *tree,
+ MateMenuTreeDirectory *directory)
+{
+ GSList *layout_info;
+
+ menu_verbose ("Processing menu layout hints for %s\n", directory->name);
+
+ g_slist_foreach (directory->contents,
+ (GFunc) matemenu_tree_item_unref_and_unset_parent,
+ NULL);
+ g_slist_free (directory->contents);
+ directory->contents = NULL;
+ directory->layout_pending_separator = FALSE;
+
+ layout_info = get_layout_info (directory, NULL);
+
+ if (layout_info == NULL)
+ {
+ merge_subdirs (tree, directory, NULL);
+ merge_entries (tree, directory, NULL);
+ }
+ else
+ {
+ GSList *tmp;
+
+ tmp = layout_info;
+ while (tmp != NULL)
+ {
+ MenuLayoutNode *node = tmp->data;
+
+ switch (menu_layout_node_get_type (node))
+ {
+ case MENU_LAYOUT_NODE_MENUNAME:
+ merge_subdir_by_name (tree,
+ directory,
+ menu_layout_node_get_content (node));
+ break;
+
+ case MENU_LAYOUT_NODE_FILENAME:
+ merge_entry_by_id (tree,
+ directory,
+ menu_layout_node_get_content (node));
+ break;
+
+ case MENU_LAYOUT_NODE_SEPARATOR:
+ /* Unless explicitly told to show all separators, do not show a
+ * separator at the beginning of a menu. Note that we don't add
+ * the separators now, and instead make it pending. This way, we
+ * won't show two consecutive separators nor will we show a
+ * separator at the end of a menu. */
+ if (tree->flags & MATEMENU_TREE_FLAGS_SHOW_ALL_SEPARATORS)
+ {
+ directory->layout_pending_separator = TRUE;
+ check_pending_separator (directory);
+ }
+ else if (directory->contents)
+ {
+ menu_verbose ("Adding a potential separator in '%s'\n",
+ directory->name);
+
+ directory->layout_pending_separator = TRUE;
+ }
+ else
+ {
+ menu_verbose ("Skipping separator at the beginning of '%s'\n",
+ directory->name);
+ }
+ break;
+
+ case MENU_LAYOUT_NODE_MERGE:
+ switch (menu_layout_node_merge_get_type (node))
+ {
+ case MENU_LAYOUT_MERGE_NONE:
+ break;
+
+ case MENU_LAYOUT_MERGE_MENUS:
+ merge_subdirs (tree,
+ directory,
+ get_subdirs_from_layout_info (tmp->next));
+ break;
+
+ case MENU_LAYOUT_MERGE_FILES:
+ merge_entries (tree,
+ directory,
+ get_entries_from_layout_info (tmp->next));
+ break;
+
+ case MENU_LAYOUT_MERGE_ALL:
+ merge_subdirs_and_entries (tree,
+ directory,
+ get_subdirs_from_layout_info (tmp->next),
+ get_entries_from_layout_info (tmp->next));
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ tmp = tmp->next;
+ }
+ }
+
+ g_slist_foreach (directory->subdirs,
+ (GFunc) matemenu_tree_item_unref,
+ NULL);
+ g_slist_free (directory->subdirs);
+ directory->subdirs = NULL;
+
+ g_slist_foreach (directory->entries,
+ (GFunc) matemenu_tree_item_unref,
+ NULL);
+ g_slist_free (directory->entries);
+ directory->entries = NULL;
+
+ g_slist_foreach (directory->default_layout_info,
+ (GFunc) menu_layout_node_unref,
+ NULL);
+ g_slist_free (directory->default_layout_info);
+ directory->default_layout_info = NULL;
+
+ g_slist_foreach (directory->layout_info,
+ (GFunc) menu_layout_node_unref,
+ NULL);
+ g_slist_free (directory->layout_info);
+ directory->layout_info = NULL;
+}
+
+static void
+handle_entries_changed (MenuLayoutNode *layout,
+ MateMenuTree *tree)
+{
+ if (tree->layout == layout)
+ {
+ matemenu_tree_force_rebuild (tree);
+ matemenu_tree_invoke_monitors (tree);
+ }
+}
+
+static void
+matemenu_tree_build_from_layout (MateMenuTree *tree)
+{
+ DesktopEntrySet *allocated;
+
+ if (tree->root)
+ return;
+
+ matemenu_tree_load_layout (tree);
+ if (!tree->layout)
+ return;
+
+ menu_verbose ("Building menu tree from layout\n");
+
+ allocated = desktop_entry_set_new ();
+
+ /* create the menu structure */
+ tree->root = process_layout (tree,
+ NULL,
+ find_menu_child (tree->layout),
+ allocated);
+ if (tree->root)
+ {
+ matemenu_tree_directory_set_tree (tree->root, tree);
+
+ process_only_unallocated (tree, tree->root, allocated);
+
+ /* process the layout info part that can move/remove items:
+ * inline, show_empty, etc. */
+ preprocess_layout_info (tree, tree->root);
+ /* populate the menu structure that we got with the items, and order it
+ * according to the layout info */
+ process_layout_info (tree, tree->root);
+
+ menu_layout_node_root_add_entries_monitor (tree->layout,
+ (MenuLayoutNodeEntriesChangedFunc) handle_entries_changed,
+ tree);
+ }
+
+ desktop_entry_set_unref (allocated);
+}
+
+static void
+matemenu_tree_force_rebuild (MateMenuTree *tree)
+{
+ if (tree->root)
+ {
+ matemenu_tree_directory_set_tree (tree->root, NULL);
+ matemenu_tree_item_unref (tree->root);
+ tree->root = NULL;
+
+ g_assert (tree->layout != NULL);
+
+ menu_layout_node_root_remove_entries_monitor (tree->layout,
+ (MenuLayoutNodeEntriesChangedFunc) handle_entries_changed,
+ tree);
+ }
+}
diff --git a/libmenu/matemenu-tree.h b/libmenu/matemenu-tree.h
new file mode 100644
index 0000000..d4916a9
--- /dev/null
+++ b/libmenu/matemenu-tree.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2004 Red Hat, 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 __MATEMENU_TREE_H__
+#define __MATEMENU_TREE_H__
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct MateMenuTree MateMenuTree;
+typedef struct MateMenuTreeItem MateMenuTreeItem;
+typedef struct MateMenuTreeDirectory MateMenuTreeDirectory;
+typedef struct MateMenuTreeEntry MateMenuTreeEntry;
+typedef struct MateMenuTreeSeparator MateMenuTreeSeparator;
+typedef struct MateMenuTreeHeader MateMenuTreeHeader;
+typedef struct MateMenuTreeAlias MateMenuTreeAlias;
+
+typedef void (*MateMenuTreeChangedFunc) (MateMenuTree* tree, gpointer user_data);
+
+typedef enum {
+ MATEMENU_TREE_ITEM_INVALID = 0,
+ MATEMENU_TREE_ITEM_DIRECTORY,
+ MATEMENU_TREE_ITEM_ENTRY,
+ MATEMENU_TREE_ITEM_SEPARATOR,
+ MATEMENU_TREE_ITEM_HEADER,
+ MATEMENU_TREE_ITEM_ALIAS
+} MateMenuTreeItemType;
+
+#define MATEMENU_TREE_ITEM(i) ((MateMenuTreeItem*)(i))
+#define MATEMENU_TREE_DIRECTORY(i) ((MateMenuTreeDirectory*)(i))
+#define MATEMENU_TREE_ENTRY(i) ((MateMenuTreeEntry*)(i))
+#define MATEMENU_TREE_SEPARATOR(i) ((MateMenuTreeSeparator*)(i))
+#define MATEMENU_TREE_HEADER(i) ((MateMenuTreeHeader*)(i))
+#define MATEMENU_TREE_ALIAS(i) ((MateMenuTreeAlias*)(i))
+
+typedef enum {
+ MATEMENU_TREE_FLAGS_NONE = 0,
+ MATEMENU_TREE_FLAGS_INCLUDE_EXCLUDED = 1 << 0,
+ MATEMENU_TREE_FLAGS_SHOW_EMPTY = 1 << 1,
+ MATEMENU_TREE_FLAGS_INCLUDE_NODISPLAY = 1 << 2,
+ MATEMENU_TREE_FLAGS_SHOW_ALL_SEPARATORS = 1 << 3,
+ MATEMENU_TREE_FLAGS_MASK = 0x0f
+} MateMenuTreeFlags;
+
+typedef enum {
+ #define MATEMENU_TREE_SORT_FIRST MATEMENU_TREE_SORT_NAME
+ MATEMENU_TREE_SORT_NAME = 0,
+ MATEMENU_TREE_SORT_DISPLAY_NAME
+ #define MATEMENU_TREE_SORT_LAST MATEMENU_TREE_SORT_DISPLAY_NAME
+} MateMenuTreeSortKey;
+
+MateMenuTree* matemenu_tree_lookup(const char* menu_file, MateMenuTreeFlags flags);
+
+MateMenuTree* matemenu_tree_ref(MateMenuTree* tree);
+void matemenu_tree_unref(MateMenuTree* tree);
+
+void matemenu_tree_set_user_data(MateMenuTree* tree, gpointer user_data, GDestroyNotify dnotify);
+gpointer matemenu_tree_get_user_data(MateMenuTree* tree);
+
+const char* matemenu_tree_get_menu_file(MateMenuTree* tree);
+MateMenuTreeDirectory* matemenu_tree_get_root_directory(MateMenuTree* tree);
+MateMenuTreeDirectory* matemenu_tree_get_directory_from_path(MateMenuTree* tree, const char* path);
+
+MateMenuTreeSortKey matemenu_tree_get_sort_key(MateMenuTree* tree);
+void matemenu_tree_set_sort_key(MateMenuTree* tree, MateMenuTreeSortKey sort_key);
+
+
+
+gpointer matemenu_tree_item_ref(gpointer item);
+void matemenu_tree_item_unref(gpointer item);
+
+void matemenu_tree_item_set_user_data(MateMenuTreeItem* item, gpointer user_data, GDestroyNotify dnotify);
+gpointer matemenu_tree_item_get_user_data(MateMenuTreeItem* item);
+
+MateMenuTreeItemType matemenu_tree_item_get_type(MateMenuTreeItem* item);
+MateMenuTreeDirectory* matemenu_tree_item_get_parent(MateMenuTreeItem* item);
+
+
+GSList* matemenu_tree_directory_get_contents(MateMenuTreeDirectory* directory);
+const char* matemenu_tree_directory_get_name(MateMenuTreeDirectory* directory);
+const char* matemenu_tree_directory_get_comment(MateMenuTreeDirectory* directory);
+const char* matemenu_tree_directory_get_icon(MateMenuTreeDirectory* directory);
+const char* matemenu_tree_directory_get_desktop_file_path(MateMenuTreeDirectory* directory);
+const char* matemenu_tree_directory_get_menu_id(MateMenuTreeDirectory* directory);
+MateMenuTree* matemenu_tree_directory_get_tree(MateMenuTreeDirectory* directory);
+
+gboolean matemenu_tree_directory_get_is_nodisplay(MateMenuTreeDirectory* directory);
+
+char* matemenu_tree_directory_make_path(MateMenuTreeDirectory* directory, MateMenuTreeEntry* entry);
+
+
+const char* matemenu_tree_entry_get_name(MateMenuTreeEntry* entry);
+const char* matemenu_tree_entry_get_generic_name(MateMenuTreeEntry* entry);
+const char* matemenu_tree_entry_get_display_name(MateMenuTreeEntry* entry);
+const char* matemenu_tree_entry_get_comment(MateMenuTreeEntry* entry);
+const char* matemenu_tree_entry_get_icon(MateMenuTreeEntry* entry);
+const char* matemenu_tree_entry_get_exec(MateMenuTreeEntry* entry);
+gboolean matemenu_tree_entry_get_launch_in_terminal(MateMenuTreeEntry* entry);
+const char* matemenu_tree_entry_get_desktop_file_path(MateMenuTreeEntry* entry);
+const char* matemenu_tree_entry_get_desktop_file_id(MateMenuTreeEntry* entry);
+gboolean matemenu_tree_entry_get_is_excluded(MateMenuTreeEntry* entry);
+gboolean matemenu_tree_entry_get_is_nodisplay(MateMenuTreeEntry* entry);
+
+MateMenuTreeDirectory* matemenu_tree_header_get_directory(MateMenuTreeHeader* header);
+
+MateMenuTreeDirectory* matemenu_tree_alias_get_directory(MateMenuTreeAlias* alias);
+MateMenuTreeItem* matemenu_tree_alias_get_item(MateMenuTreeAlias* alias);
+
+void matemenu_tree_add_monitor(MateMenuTree* tree, MateMenuTreeChangedFunc callback, gpointer user_data);
+void matemenu_tree_remove_monitor(MateMenuTree* tree, MateMenuTreeChangedFunc callback, gpointer user_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MATEMENU_TREE_H__ */
diff --git a/libmenu/menu-layout.c b/libmenu/menu-layout.c
new file mode 100644
index 0000000..d447d2d
--- /dev/null
+++ b/libmenu/menu-layout.c
@@ -0,0 +1,2359 @@
+/* Menu layout in-memory data structure (a custom "DOM tree") */
+
+/*
+ * Copyright (C) 2002 - 2004 Red Hat, 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.
+ */
+
+#include <config.h>
+
+#include "menu-layout.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "canonicalize.h"
+#include "entry-directories.h"
+#include "menu-util.h"
+
+typedef struct MenuLayoutNodeMenu MenuLayoutNodeMenu;
+typedef struct MenuLayoutNodeRoot MenuLayoutNodeRoot;
+typedef struct MenuLayoutNodeLegacyDir MenuLayoutNodeLegacyDir;
+typedef struct MenuLayoutNodeMergeFile MenuLayoutNodeMergeFile;
+typedef struct MenuLayoutNodeDefaultLayout MenuLayoutNodeDefaultLayout;
+typedef struct MenuLayoutNodeMenuname MenuLayoutNodeMenuname;
+typedef struct MenuLayoutNodeMerge MenuLayoutNodeMerge;
+
+struct MenuLayoutNode
+{
+ /* Node lists are circular, for length-one lists
+ * prev/next point back to the node itself.
+ */
+ MenuLayoutNode *prev;
+ MenuLayoutNode *next;
+ MenuLayoutNode *parent;
+ MenuLayoutNode *children;
+
+ char *content;
+
+ guint refcount : 20;
+ guint type : 7;
+};
+
+struct MenuLayoutNodeRoot
+{
+ MenuLayoutNode node;
+
+ char *basedir;
+ char *name;
+
+ GSList *monitors;
+};
+
+struct MenuLayoutNodeMenu
+{
+ MenuLayoutNode node;
+
+ MenuLayoutNode *name_node; /* cache of the <Name> node */
+
+ EntryDirectoryList *app_dirs;
+ EntryDirectoryList *dir_dirs;
+};
+
+struct MenuLayoutNodeLegacyDir
+{
+ MenuLayoutNode node;
+
+ char *prefix;
+};
+
+struct MenuLayoutNodeMergeFile
+{
+ MenuLayoutNode node;
+
+ MenuMergeFileType type;
+};
+
+struct MenuLayoutNodeDefaultLayout
+{
+ MenuLayoutNode node;
+
+ MenuLayoutValues layout_values;
+};
+
+struct MenuLayoutNodeMenuname
+{
+ MenuLayoutNode node;
+
+ MenuLayoutValues layout_values;
+};
+
+struct MenuLayoutNodeMerge
+{
+ MenuLayoutNode node;
+
+ MenuLayoutMergeType merge_type;
+};
+
+typedef struct
+{
+ MenuLayoutNodeEntriesChangedFunc callback;
+ gpointer user_data;
+} MenuLayoutNodeEntriesMonitor;
+
+
+static inline MenuLayoutNode *
+node_next (MenuLayoutNode *node)
+{
+ /* root nodes (no parent) never have siblings */
+ if (node->parent == NULL)
+ return NULL;
+
+ /* circular list */
+ if (node->next == node->parent->children)
+ return NULL;
+
+ return node->next;
+}
+
+static void
+handle_entry_directory_changed (EntryDirectory *dir,
+ MenuLayoutNode *node)
+{
+ MenuLayoutNodeRoot *nr;
+ GSList *tmp;
+
+ g_assert (node->type == MENU_LAYOUT_NODE_MENU);
+
+ nr = (MenuLayoutNodeRoot *) menu_layout_node_get_root (node);
+
+ tmp = nr->monitors;
+ while (tmp != NULL)
+ {
+ MenuLayoutNodeEntriesMonitor *monitor = tmp->data;
+ GSList *next = tmp->next;
+
+ monitor->callback ((MenuLayoutNode *) nr, monitor->user_data);
+
+ tmp = next;
+ }
+}
+
+static void
+remove_entry_directory_list (MenuLayoutNodeMenu *nm,
+ EntryDirectoryList **dirs)
+{
+ if (*dirs)
+ {
+ entry_directory_list_remove_monitors (*dirs,
+ (EntryDirectoryChangedFunc) handle_entry_directory_changed,
+ nm);
+ entry_directory_list_unref (*dirs);
+ *dirs = NULL;
+ }
+}
+
+MenuLayoutNode *
+menu_layout_node_ref (MenuLayoutNode *node)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+
+ node->refcount += 1;
+
+ return node;
+}
+
+void
+menu_layout_node_unref (MenuLayoutNode *node)
+{
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (node->refcount > 0);
+
+ node->refcount -= 1;
+ if (node->refcount == 0)
+ {
+ MenuLayoutNode *iter;
+
+ iter = node->children;
+ while (iter != NULL)
+ {
+ MenuLayoutNode *next = node_next (iter);
+
+ menu_layout_node_unref (iter);
+
+ iter = next;
+ }
+
+ if (node->type == MENU_LAYOUT_NODE_MENU)
+ {
+ MenuLayoutNodeMenu *nm = (MenuLayoutNodeMenu *) node;
+
+ if (nm->name_node)
+ menu_layout_node_unref (nm->name_node);
+
+ remove_entry_directory_list (nm, &nm->app_dirs);
+ remove_entry_directory_list (nm, &nm->dir_dirs);
+ }
+ else if (node->type == MENU_LAYOUT_NODE_LEGACY_DIR)
+ {
+ MenuLayoutNodeLegacyDir *legacy = (MenuLayoutNodeLegacyDir *) node;
+
+ g_free (legacy->prefix);
+ }
+ else if (node->type == MENU_LAYOUT_NODE_ROOT)
+ {
+ MenuLayoutNodeRoot *nr = (MenuLayoutNodeRoot*) node;
+
+ g_slist_foreach (nr->monitors, (GFunc) g_free, NULL);
+ g_slist_free (nr->monitors);
+
+ g_free (nr->basedir);
+ g_free (nr->name);
+ }
+
+ g_free (node->content);
+ g_free (node);
+ }
+}
+
+MenuLayoutNode *
+menu_layout_node_new (MenuLayoutNodeType type)
+{
+ MenuLayoutNode *node;
+
+ switch (type)
+ {
+ case MENU_LAYOUT_NODE_MENU:
+ node = (MenuLayoutNode *) g_new0 (MenuLayoutNodeMenu, 1);
+ break;
+
+ case MENU_LAYOUT_NODE_LEGACY_DIR:
+ node = (MenuLayoutNode *) g_new0 (MenuLayoutNodeLegacyDir, 1);
+ break;
+
+ case MENU_LAYOUT_NODE_ROOT:
+ node = (MenuLayoutNode*) g_new0 (MenuLayoutNodeRoot, 1);
+ break;
+
+ case MENU_LAYOUT_NODE_MERGE_FILE:
+ node = (MenuLayoutNode *) g_new0 (MenuLayoutNodeMergeFile, 1);
+ break;
+
+ case MENU_LAYOUT_NODE_DEFAULT_LAYOUT:
+ node = (MenuLayoutNode *) g_new0 (MenuLayoutNodeDefaultLayout, 1);
+ break;
+
+ case MENU_LAYOUT_NODE_MENUNAME:
+ node = (MenuLayoutNode *) g_new0 (MenuLayoutNodeMenuname, 1);
+ break;
+
+ case MENU_LAYOUT_NODE_MERGE:
+ node = (MenuLayoutNode *) g_new0 (MenuLayoutNodeMerge, 1);
+ break;
+
+ default:
+ node = g_new0 (MenuLayoutNode, 1);
+ break;
+ }
+
+ node->type = type;
+
+ node->refcount = 1;
+
+ /* we're in a list of one node */
+ node->next = node;
+ node->prev = node;
+
+ return node;
+}
+
+MenuLayoutNode *
+menu_layout_node_get_next (MenuLayoutNode *node)
+{
+ return node_next (node);
+}
+
+MenuLayoutNode *
+menu_layout_node_get_parent (MenuLayoutNode *node)
+{
+ return node->parent;
+}
+
+MenuLayoutNode *
+menu_layout_node_get_children (MenuLayoutNode *node)
+{
+ return node->children;
+}
+
+MenuLayoutNode *
+menu_layout_node_get_root (MenuLayoutNode *node)
+{
+ MenuLayoutNode *parent;
+
+ parent = node;
+ while (parent->parent != NULL)
+ parent = parent->parent;
+
+ g_assert (parent->type == MENU_LAYOUT_NODE_ROOT);
+
+ return parent;
+}
+
+char *
+menu_layout_node_get_content_as_path (MenuLayoutNode *node)
+{
+ if (node->content == NULL)
+ {
+ menu_verbose (" (node has no content to get as a path)\n");
+ return NULL;
+ }
+
+ if (g_path_is_absolute (node->content))
+ {
+ return g_strdup (node->content);
+ }
+ else
+ {
+ MenuLayoutNodeRoot *root;
+
+ root = (MenuLayoutNodeRoot *) menu_layout_node_get_root (node);
+
+ if (root->basedir == NULL)
+ {
+ menu_verbose ("No basedir available, using \"%s\" as-is\n",
+ node->content);
+ return g_strdup (node->content);
+ }
+ else
+ {
+ menu_verbose ("Using basedir \"%s\" filename \"%s\"\n",
+ root->basedir, node->content);
+ return g_build_filename (root->basedir, node->content, NULL);
+ }
+ }
+}
+
+#define RETURN_IF_NO_PARENT(node) G_STMT_START { \
+ if ((node)->parent == NULL) \
+ { \
+ g_warning ("To add siblings to a menu node, " \
+ "it must not be the root node, " \
+ "and must be linked in below some root node\n" \
+ "node parent = %p and type = %d", \
+ (node)->parent, (node)->type); \
+ return; \
+ } \
+ } G_STMT_END
+
+#define RETURN_IF_HAS_ENTRY_DIRS(node) G_STMT_START { \
+ if ((node)->type == MENU_LAYOUT_NODE_MENU && \
+ (((MenuLayoutNodeMenu*)(node))->app_dirs != NULL || \
+ ((MenuLayoutNodeMenu*)(node))->dir_dirs != NULL)) \
+ { \
+ g_warning ("node acquired ->app_dirs or ->dir_dirs " \
+ "while not rooted in a tree\n"); \
+ return; \
+ } \
+ } G_STMT_END \
+
+void
+menu_layout_node_insert_before (MenuLayoutNode *node,
+ MenuLayoutNode *new_sibling)
+{
+ g_return_if_fail (new_sibling != NULL);
+ g_return_if_fail (new_sibling->parent == NULL);
+
+ RETURN_IF_NO_PARENT (node);
+ RETURN_IF_HAS_ENTRY_DIRS (new_sibling);
+
+ new_sibling->next = node;
+ new_sibling->prev = node->prev;
+
+ node->prev = new_sibling;
+ new_sibling->prev->next = new_sibling;
+
+ new_sibling->parent = node->parent;
+
+ if (node == node->parent->children)
+ node->parent->children = new_sibling;
+
+ menu_layout_node_ref (new_sibling);
+}
+
+void
+menu_layout_node_insert_after (MenuLayoutNode *node,
+ MenuLayoutNode *new_sibling)
+{
+ g_return_if_fail (new_sibling != NULL);
+ g_return_if_fail (new_sibling->parent == NULL);
+
+ RETURN_IF_NO_PARENT (node);
+ RETURN_IF_HAS_ENTRY_DIRS (new_sibling);
+
+ new_sibling->prev = node;
+ new_sibling->next = node->next;
+
+ node->next = new_sibling;
+ new_sibling->next->prev = new_sibling;
+
+ new_sibling->parent = node->parent;
+
+ menu_layout_node_ref (new_sibling);
+}
+
+void
+menu_layout_node_prepend_child (MenuLayoutNode *parent,
+ MenuLayoutNode *new_child)
+{
+ RETURN_IF_HAS_ENTRY_DIRS (new_child);
+
+ if (parent->children)
+ {
+ menu_layout_node_insert_before (parent->children, new_child);
+ }
+ else
+ {
+ parent->children = menu_layout_node_ref (new_child);
+ new_child->parent = parent;
+ }
+}
+
+void
+menu_layout_node_append_child (MenuLayoutNode *parent,
+ MenuLayoutNode *new_child)
+{
+ RETURN_IF_HAS_ENTRY_DIRS (new_child);
+
+ if (parent->children)
+ {
+ menu_layout_node_insert_after (parent->children->prev, new_child);
+ }
+ else
+ {
+ parent->children = menu_layout_node_ref (new_child);
+ new_child->parent = parent;
+ }
+}
+
+void
+menu_layout_node_unlink (MenuLayoutNode *node)
+{
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (node->parent != NULL);
+
+ menu_layout_node_steal (node);
+ menu_layout_node_unref (node);
+}
+
+static void
+recursive_clean_entry_directory_lists (MenuLayoutNode *node,
+ gboolean apps)
+{
+ EntryDirectoryList **dirs;
+ MenuLayoutNodeMenu *nm;
+ MenuLayoutNode *iter;
+
+ if (node->type != MENU_LAYOUT_NODE_MENU)
+ return;
+
+ nm = (MenuLayoutNodeMenu *) node;
+
+ dirs = apps ? &nm->app_dirs : &nm->dir_dirs;
+
+ if (*dirs == NULL || entry_directory_list_get_length (*dirs) == 0)
+ return; /* child menus continue to have valid lists */
+
+ remove_entry_directory_list (nm, dirs);
+
+ iter = node->children;
+ while (iter != NULL)
+ {
+ if (iter->type == MENU_LAYOUT_NODE_MENU)
+ recursive_clean_entry_directory_lists (iter, apps);
+
+ iter = node_next (iter);
+ }
+}
+
+void
+menu_layout_node_steal (MenuLayoutNode *node)
+{
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (node->parent != NULL);
+
+ switch (node->type)
+ {
+ case MENU_LAYOUT_NODE_NAME:
+ {
+ MenuLayoutNodeMenu *nm = (MenuLayoutNodeMenu *) node->parent;
+
+ if (nm->name_node == node)
+ {
+ menu_layout_node_unref (nm->name_node);
+ nm->name_node = NULL;
+ }
+ }
+ break;
+
+ case MENU_LAYOUT_NODE_APP_DIR:
+ recursive_clean_entry_directory_lists (node->parent, TRUE);
+ break;
+
+ case MENU_LAYOUT_NODE_DIRECTORY_DIR:
+ recursive_clean_entry_directory_lists (node->parent, FALSE);
+ break;
+
+ default:
+ break;
+ }
+
+ if (node->parent && node->parent->children == node)
+ {
+ if (node->next != node)
+ node->parent->children = node->next;
+ else
+ node->parent->children = NULL;
+ }
+
+ /* these are no-ops for length-one node lists */
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+
+ node->parent = NULL;
+
+ /* point to ourselves, now we're length one */
+ node->next = node;
+ node->prev = node;
+}
+
+MenuLayoutNodeType
+menu_layout_node_get_type (MenuLayoutNode *node)
+{
+ return node->type;
+}
+
+const char *
+menu_layout_node_get_content (MenuLayoutNode *node)
+{
+ return node->content;
+}
+
+void
+menu_layout_node_set_content (MenuLayoutNode *node,
+ const char *content)
+{
+ if (node->content == content)
+ return;
+
+ g_free (node->content);
+ node->content = g_strdup (content);
+}
+
+const char *
+menu_layout_node_root_get_name (MenuLayoutNode *node)
+{
+ MenuLayoutNodeRoot *nr;
+
+ g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_ROOT, NULL);
+
+ nr = (MenuLayoutNodeRoot*) node;
+
+ return nr->name;
+}
+
+const char *
+menu_layout_node_root_get_basedir (MenuLayoutNode *node)
+{
+ MenuLayoutNodeRoot *nr;
+
+ g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_ROOT, NULL);
+
+ nr = (MenuLayoutNodeRoot*) node;
+
+ return nr->basedir;
+}
+
+const char *
+menu_layout_node_menu_get_name (MenuLayoutNode *node)
+{
+ MenuLayoutNodeMenu *nm;
+
+ g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_MENU, NULL);
+
+ nm = (MenuLayoutNodeMenu*) node;
+
+ if (nm->name_node == NULL)
+ {
+ MenuLayoutNode *iter;
+
+ iter = node->children;
+ while (iter != NULL)
+ {
+ if (iter->type == MENU_LAYOUT_NODE_NAME)
+ {
+ nm->name_node = menu_layout_node_ref (iter);
+ break;
+ }
+
+ iter = node_next (iter);
+ }
+ }
+
+ if (nm->name_node == NULL)
+ return NULL;
+
+ return menu_layout_node_get_content (nm->name_node);
+}
+
+static void
+ensure_dir_lists (MenuLayoutNodeMenu *nm)
+{
+ MenuLayoutNode *node;
+ MenuLayoutNode *iter;
+ EntryDirectoryList *app_dirs;
+ EntryDirectoryList *dir_dirs;
+
+ node = (MenuLayoutNode *) nm;
+
+ if (nm->app_dirs && nm->dir_dirs)
+ return;
+
+ app_dirs = NULL;
+ dir_dirs = NULL;
+
+ if (nm->app_dirs == NULL)
+ {
+ app_dirs = entry_directory_list_new ();
+
+ if (node->parent && node->parent->type == MENU_LAYOUT_NODE_MENU)
+ {
+ EntryDirectoryList *dirs;
+
+ if ((dirs = menu_layout_node_menu_get_app_dirs (node->parent)))
+ entry_directory_list_append_list (app_dirs, dirs);
+ }
+ }
+
+ if (nm->dir_dirs == NULL)
+ {
+ dir_dirs = entry_directory_list_new ();
+
+ if (node->parent && node->parent->type == MENU_LAYOUT_NODE_MENU)
+ {
+ EntryDirectoryList *dirs;
+
+ if ((dirs = menu_layout_node_menu_get_directory_dirs (node->parent)))
+ entry_directory_list_append_list (dir_dirs, dirs);
+ }
+ }
+
+ iter = node->children;
+ while (iter != NULL)
+ {
+ EntryDirectory *ed;
+
+ if (app_dirs != NULL && iter->type == MENU_LAYOUT_NODE_APP_DIR)
+ {
+ char *path;
+
+ path = menu_layout_node_get_content_as_path (iter);
+
+ ed = entry_directory_new (DESKTOP_ENTRY_DESKTOP, path);
+ if (ed != NULL)
+ {
+ entry_directory_list_prepend (app_dirs, ed);
+ entry_directory_unref (ed);
+ }
+
+ g_free (path);
+ }
+
+ if (dir_dirs != NULL && iter->type == MENU_LAYOUT_NODE_DIRECTORY_DIR)
+ {
+ char *path;
+
+ path = menu_layout_node_get_content_as_path (iter);
+
+ ed = entry_directory_new (DESKTOP_ENTRY_DIRECTORY, path);
+ if (ed != NULL)
+ {
+ entry_directory_list_prepend (dir_dirs, ed);
+ entry_directory_unref (ed);
+ }
+
+ g_free (path);
+ }
+
+ if (iter->type == MENU_LAYOUT_NODE_LEGACY_DIR)
+ {
+ MenuLayoutNodeLegacyDir *legacy = (MenuLayoutNodeLegacyDir *) iter;
+ char *path;
+
+ path = menu_layout_node_get_content_as_path (iter);
+
+ if (app_dirs != NULL) /* we're loading app dirs */
+ {
+ ed = entry_directory_new_legacy (DESKTOP_ENTRY_DESKTOP,
+ path,
+ legacy->prefix);
+ if (ed != NULL)
+ {
+ entry_directory_list_prepend (app_dirs, ed);
+ entry_directory_unref (ed);
+ }
+ }
+
+ if (dir_dirs != NULL) /* we're loading dir dirs */
+ {
+ ed = entry_directory_new_legacy (DESKTOP_ENTRY_DIRECTORY,
+ path,
+ legacy->prefix);
+ if (ed != NULL)
+ {
+ entry_directory_list_prepend (dir_dirs, ed);
+ entry_directory_unref (ed);
+ }
+ }
+
+ g_free (path);
+ }
+
+ iter = node_next (iter);
+ }
+
+ if (app_dirs)
+ {
+ g_assert (nm->app_dirs == NULL);
+
+ nm->app_dirs = app_dirs;
+ entry_directory_list_add_monitors (nm->app_dirs,
+ (EntryDirectoryChangedFunc) handle_entry_directory_changed,
+ nm);
+ }
+
+ if (dir_dirs)
+ {
+ g_assert (nm->dir_dirs == NULL);
+
+ nm->dir_dirs = dir_dirs;
+ entry_directory_list_add_monitors (nm->dir_dirs,
+ (EntryDirectoryChangedFunc) handle_entry_directory_changed,
+ nm);
+ }
+}
+
+EntryDirectoryList *
+menu_layout_node_menu_get_app_dirs (MenuLayoutNode *node)
+{
+ MenuLayoutNodeMenu *nm;
+
+ g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_MENU, NULL);
+
+ nm = (MenuLayoutNodeMenu *) node;
+
+ ensure_dir_lists (nm);
+
+ return nm->app_dirs;
+}
+
+EntryDirectoryList *
+menu_layout_node_menu_get_directory_dirs (MenuLayoutNode *node)
+{
+ MenuLayoutNodeMenu *nm;
+
+ g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_MENU, NULL);
+
+ nm = (MenuLayoutNodeMenu *) node;
+
+ ensure_dir_lists (nm);
+
+ return nm->dir_dirs;
+}
+
+const char *
+menu_layout_node_move_get_old (MenuLayoutNode *node)
+{
+ MenuLayoutNode *iter;
+
+ iter = node->children;
+ while (iter != NULL)
+ {
+ if (iter->type == MENU_LAYOUT_NODE_OLD)
+ return iter->content;
+
+ iter = node_next (iter);
+ }
+
+ return NULL;
+}
+
+const char *
+menu_layout_node_move_get_new (MenuLayoutNode *node)
+{
+ MenuLayoutNode *iter;
+
+ iter = node->children;
+ while (iter != NULL)
+ {
+ if (iter->type == MENU_LAYOUT_NODE_NEW)
+ return iter->content;
+
+ iter = node_next (iter);
+ }
+
+ return NULL;
+}
+
+const char *
+menu_layout_node_legacy_dir_get_prefix (MenuLayoutNode *node)
+{
+ MenuLayoutNodeLegacyDir *legacy;
+
+ g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_LEGACY_DIR, NULL);
+
+ legacy = (MenuLayoutNodeLegacyDir *) node;
+
+ return legacy->prefix;
+}
+
+void
+menu_layout_node_legacy_dir_set_prefix (MenuLayoutNode *node,
+ const char *prefix)
+{
+ MenuLayoutNodeLegacyDir *legacy;
+
+ g_return_if_fail (node->type == MENU_LAYOUT_NODE_LEGACY_DIR);
+
+ legacy = (MenuLayoutNodeLegacyDir *) node;
+
+ g_free (legacy->prefix);
+ legacy->prefix = g_strdup (prefix);
+}
+
+MenuMergeFileType
+menu_layout_node_merge_file_get_type (MenuLayoutNode *node)
+{
+ MenuLayoutNodeMergeFile *merge_file;
+
+ g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_MERGE_FILE, FALSE);
+
+ merge_file = (MenuLayoutNodeMergeFile *) node;
+
+ return merge_file->type;
+}
+
+void
+menu_layout_node_merge_file_set_type (MenuLayoutNode *node,
+ MenuMergeFileType type)
+{
+ MenuLayoutNodeMergeFile *merge_file;
+
+ g_return_if_fail (node->type == MENU_LAYOUT_NODE_MERGE_FILE);
+
+ merge_file = (MenuLayoutNodeMergeFile *) node;
+
+ merge_file->type = type;
+}
+
+MenuLayoutMergeType
+menu_layout_node_merge_get_type (MenuLayoutNode *node)
+{
+ MenuLayoutNodeMerge *merge;
+
+ g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_MERGE, 0);
+
+ merge = (MenuLayoutNodeMerge *) node;
+
+ return merge->merge_type;
+}
+
+static void
+menu_layout_node_merge_set_type (MenuLayoutNode *node,
+ const char *merge_type)
+{
+ MenuLayoutNodeMerge *merge;
+
+ g_return_if_fail (node->type == MENU_LAYOUT_NODE_MERGE);
+
+ merge = (MenuLayoutNodeMerge *) node;
+
+ merge->merge_type = MENU_LAYOUT_MERGE_NONE;
+
+ if (strcmp (merge_type, "menus") == 0)
+ {
+ merge->merge_type = MENU_LAYOUT_MERGE_MENUS;
+ }
+ else if (strcmp (merge_type, "files") == 0)
+ {
+ merge->merge_type = MENU_LAYOUT_MERGE_FILES;
+ }
+ else if (strcmp (merge_type, "all") == 0)
+ {
+ merge->merge_type = MENU_LAYOUT_MERGE_ALL;
+ }
+}
+
+void
+menu_layout_node_default_layout_get_values (MenuLayoutNode *node,
+ MenuLayoutValues *values)
+{
+ MenuLayoutNodeDefaultLayout *default_layout;
+
+ g_return_if_fail (node->type == MENU_LAYOUT_NODE_DEFAULT_LAYOUT);
+ g_return_if_fail (values != NULL);
+
+ default_layout = (MenuLayoutNodeDefaultLayout *) node;
+
+ *values = default_layout->layout_values;
+}
+
+void
+menu_layout_node_menuname_get_values (MenuLayoutNode *node,
+ MenuLayoutValues *values)
+{
+ MenuLayoutNodeMenuname *menuname;
+
+ g_return_if_fail (node->type == MENU_LAYOUT_NODE_MENUNAME);
+ g_return_if_fail (values != NULL);
+
+ menuname = (MenuLayoutNodeMenuname *) node;
+
+ *values = menuname->layout_values;
+}
+
+static void
+menu_layout_values_set (MenuLayoutValues *values,
+ const char *show_empty,
+ const char *inline_menus,
+ const char *inline_limit,
+ const char *inline_header,
+ const char *inline_alias)
+{
+ values->mask = MENU_LAYOUT_VALUES_NONE;
+ values->show_empty = FALSE;
+ values->inline_menus = FALSE;
+ values->inline_limit = 4;
+ values->inline_header = FALSE;
+ values->inline_alias = FALSE;
+
+ if (show_empty != NULL)
+ {
+ values->show_empty = strcmp (show_empty, "true") == 0;
+ values->mask |= MENU_LAYOUT_VALUES_SHOW_EMPTY;
+ }
+
+ if (inline_menus != NULL)
+ {
+ values->inline_menus = strcmp (inline_menus, "true") == 0;
+ values->mask |= MENU_LAYOUT_VALUES_INLINE_MENUS;
+ }
+
+ if (inline_limit != NULL)
+ {
+ char *end;
+ int limit;
+
+ limit = strtol (inline_limit, &end, 10);
+ if (*end == '\0')
+ {
+ values->inline_limit = limit;
+ values->mask |= MENU_LAYOUT_VALUES_INLINE_LIMIT;
+ }
+ }
+
+ if (inline_header != NULL)
+ {
+ values->inline_header = strcmp (inline_header, "true") == 0;
+ values->mask |= MENU_LAYOUT_VALUES_INLINE_HEADER;
+ }
+
+ if (inline_alias != NULL)
+ {
+ values->inline_alias = strcmp (inline_alias, "true") == 0;
+ values->mask |= MENU_LAYOUT_VALUES_INLINE_ALIAS;
+ }
+}
+
+static void
+menu_layout_node_default_layout_set_values (MenuLayoutNode *node,
+ const char *show_empty,
+ const char *inline_menus,
+ const char *inline_limit,
+ const char *inline_header,
+ const char *inline_alias)
+{
+ MenuLayoutNodeDefaultLayout *default_layout;
+
+ g_return_if_fail (node->type == MENU_LAYOUT_NODE_DEFAULT_LAYOUT);
+
+ default_layout = (MenuLayoutNodeDefaultLayout *) node;
+
+ menu_layout_values_set (&default_layout->layout_values,
+ show_empty,
+ inline_menus,
+ inline_limit,
+ inline_header,
+ inline_alias);
+}
+
+static void
+menu_layout_node_menuname_set_values (MenuLayoutNode *node,
+ const char *show_empty,
+ const char *inline_menus,
+ const char *inline_limit,
+ const char *inline_header,
+ const char *inline_alias)
+{
+ MenuLayoutNodeMenuname *menuname;
+
+ g_return_if_fail (node->type == MENU_LAYOUT_NODE_MENUNAME);
+
+ menuname = (MenuLayoutNodeMenuname *) node;
+
+ menu_layout_values_set (&menuname->layout_values,
+ show_empty,
+ inline_menus,
+ inline_limit,
+ inline_header,
+ inline_alias);
+}
+
+void
+menu_layout_node_root_add_entries_monitor (MenuLayoutNode *node,
+ MenuLayoutNodeEntriesChangedFunc callback,
+ gpointer user_data)
+{
+ MenuLayoutNodeEntriesMonitor *monitor;
+ MenuLayoutNodeRoot *nr;
+ GSList *tmp;
+
+ g_return_if_fail (node->type == MENU_LAYOUT_NODE_ROOT);
+
+ nr = (MenuLayoutNodeRoot *) node;
+
+ tmp = nr->monitors;
+ while (tmp != NULL)
+ {
+ monitor = tmp->data;
+
+ if (monitor->callback == callback &&
+ monitor->user_data == user_data)
+ break;
+
+ tmp = tmp->next;
+ }
+
+ if (tmp == NULL)
+ {
+ monitor = g_new0 (MenuLayoutNodeEntriesMonitor, 1);
+ monitor->callback = callback;
+ monitor->user_data = user_data;
+
+ nr->monitors = g_slist_append (nr->monitors, monitor);
+ }
+}
+
+void
+menu_layout_node_root_remove_entries_monitor (MenuLayoutNode *node,
+ MenuLayoutNodeEntriesChangedFunc callback,
+ gpointer user_data)
+{
+ MenuLayoutNodeRoot *nr;
+ GSList *tmp;
+
+ g_return_if_fail (node->type == MENU_LAYOUT_NODE_ROOT);
+
+ nr = (MenuLayoutNodeRoot *) node;
+
+ tmp = nr->monitors;
+ while (tmp != NULL)
+ {
+ MenuLayoutNodeEntriesMonitor *monitor = tmp->data;
+ GSList *next = tmp->next;
+
+ if (monitor->callback == callback &&
+ monitor->user_data == user_data)
+ {
+ nr->monitors = g_slist_delete_link (nr->monitors, tmp);
+ g_free (monitor);
+ }
+
+ tmp = next;
+ }
+}
+
+
+/*
+ * Menu file parsing
+ */
+
+typedef struct
+{
+ MenuLayoutNode *root;
+ MenuLayoutNode *stack_top;
+} MenuParser;
+
+static void set_error (GError **err,
+ GMarkupParseContext *context,
+ int error_domain,
+ int error_code,
+ const char *format,
+ ...) G_GNUC_PRINTF (5, 6);
+
+static void add_context_to_error (GError **err,
+ GMarkupParseContext *context);
+
+static void start_element_handler (GMarkupParseContext *context,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ gpointer user_data,
+ GError **error);
+static void end_element_handler (GMarkupParseContext *context,
+ const char *element_name,
+ gpointer user_data,
+ GError **error);
+static void text_handler (GMarkupParseContext *context,
+ const char *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error);
+static void passthrough_handler (GMarkupParseContext *context,
+ const char *passthrough_text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error);
+
+
+static GMarkupParser menu_funcs = {
+ start_element_handler,
+ end_element_handler,
+ text_handler,
+ passthrough_handler,
+ NULL
+};
+
+static void
+set_error (GError **err,
+ GMarkupParseContext *context,
+ int error_domain,
+ int error_code,
+ const char *format,
+ ...)
+{
+ int line, ch;
+ va_list args;
+ char *str;
+
+ g_markup_parse_context_get_position (context, &line, &ch);
+
+ va_start (args, format);
+ str = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ g_set_error (err, error_domain, error_code,
+ "Line %d character %d: %s",
+ line, ch, str);
+
+ g_free (str);
+}
+
+static void
+add_context_to_error (GError **err,
+ GMarkupParseContext *context)
+{
+ int line, ch;
+ char *str;
+
+ if (err == NULL || *err == NULL)
+ return;
+
+ g_markup_parse_context_get_position (context, &line, &ch);
+
+ str = g_strdup_printf ("Line %d character %d: %s",
+ line, ch, (*err)->message);
+ g_free ((*err)->message);
+ (*err)->message = str;
+}
+
+#define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0)
+
+typedef struct
+{
+ const char *name;
+ const char **retloc;
+} LocateAttr;
+
+static gboolean
+locate_attributes (GMarkupParseContext *context,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ GError **error,
+ const char *first_attribute_name,
+ const char **first_attribute_retloc,
+ ...)
+{
+#define MAX_ATTRS 24
+ LocateAttr attrs[MAX_ATTRS];
+ int n_attrs;
+ va_list args;
+ const char *name;
+ const char **retloc;
+ gboolean retval;
+ int i;
+
+ g_return_val_if_fail (first_attribute_name != NULL, FALSE);
+ g_return_val_if_fail (first_attribute_retloc != NULL, FALSE);
+
+ retval = TRUE;
+
+ n_attrs = 1;
+ attrs[0].name = first_attribute_name;
+ attrs[0].retloc = first_attribute_retloc;
+ *first_attribute_retloc = NULL;
+
+ va_start (args, first_attribute_retloc);
+
+ name = va_arg (args, const char *);
+ retloc = va_arg (args, const char **);
+
+ while (name != NULL)
+ {
+ g_return_val_if_fail (retloc != NULL, FALSE);
+
+ g_assert (n_attrs < MAX_ATTRS);
+
+ attrs[n_attrs].name = name;
+ attrs[n_attrs].retloc = retloc;
+ n_attrs += 1;
+ *retloc = NULL;
+
+ name = va_arg (args, const char *);
+ retloc = va_arg (args, const char **);
+ }
+
+ va_end (args);
+
+ i = 0;
+ while (attribute_names[i])
+ {
+ int j;
+
+ j = 0;
+ while (j < n_attrs)
+ {
+ if (strcmp (attrs[j].name, attribute_names[i]) == 0)
+ {
+ retloc = attrs[j].retloc;
+
+ if (*retloc != NULL)
+ {
+ set_error (error, context,
+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ "Attribute \"%s\" repeated twice on the same <%s> element",
+ attrs[j].name, element_name);
+ retval = FALSE;
+ goto out;
+ }
+
+ *retloc = attribute_values[i];
+ break;
+ }
+
+ ++j;
+ }
+
+ if (j == n_attrs)
+ {
+ set_error (error, context,
+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ "Attribute \"%s\" is invalid on <%s> element in this context",
+ attribute_names[i], element_name);
+ retval = FALSE;
+ goto out;
+ }
+
+ ++i;
+ }
+
+ out:
+ return retval;
+
+#undef MAX_ATTRS
+}
+
+static gboolean
+check_no_attributes (GMarkupParseContext *context,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ GError **error)
+{
+ if (attribute_names[0] != NULL)
+ {
+ set_error (error, context,
+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ "Attribute \"%s\" is invalid on <%s> element in this context",
+ attribute_names[0], element_name);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int
+has_child_of_type (MenuLayoutNode *node,
+ MenuLayoutNodeType type)
+{
+ MenuLayoutNode *iter;
+
+ iter = node->children;
+ while (iter)
+ {
+ if (iter->type == type)
+ return TRUE;
+
+ iter = node_next (iter);
+ }
+
+ return FALSE;
+}
+
+static void
+push_node (MenuParser *parser,
+ MenuLayoutNodeType type)
+{
+ MenuLayoutNode *node;
+
+ node = menu_layout_node_new (type);
+ menu_layout_node_append_child (parser->stack_top, node);
+ menu_layout_node_unref (node);
+
+ parser->stack_top = node;
+}
+
+static void
+start_menu_element (MenuParser *parser,
+ GMarkupParseContext *context,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ GError **error)
+{
+ if (!check_no_attributes (context, element_name,
+ attribute_names, attribute_values,
+ error))
+ return;
+
+ if (!(parser->stack_top->type == MENU_LAYOUT_NODE_ROOT ||
+ parser->stack_top->type == MENU_LAYOUT_NODE_MENU))
+ {
+ set_error (error, context,
+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ "<Menu> element can only appear below other <Menu> elements or at toplevel\n");
+ }
+ else
+ {
+ push_node (parser, MENU_LAYOUT_NODE_MENU);
+ }
+}
+
+static void
+start_menu_child_element (MenuParser *parser,
+ GMarkupParseContext *context,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ GError **error)
+{
+ if (ELEMENT_IS ("LegacyDir"))
+ {
+ const char *prefix;
+
+ push_node (parser, MENU_LAYOUT_NODE_LEGACY_DIR);
+
+ if (!locate_attributes (context, element_name,
+ attribute_names, attribute_values,
+ error,
+ "prefix", &prefix,
+ NULL))
+ return;
+
+ menu_layout_node_legacy_dir_set_prefix (parser->stack_top, prefix);
+ }
+ else if (ELEMENT_IS ("MergeFile"))
+ {
+ const char *type;
+
+ push_node (parser, MENU_LAYOUT_NODE_MERGE_FILE);
+
+ if (!locate_attributes (context, element_name,
+ attribute_names, attribute_values,
+ error,
+ "type", &type,
+ NULL))
+ return;
+
+ if (type != NULL && strcmp (type, "parent") == 0)
+ {
+ menu_layout_node_merge_file_set_type (parser->stack_top,
+ MENU_MERGE_FILE_TYPE_PARENT);
+ }
+ }
+ else if (ELEMENT_IS ("DefaultLayout"))
+ {
+ const char *show_empty;
+ const char *inline_menus;
+ const char *inline_limit;
+ const char *inline_header;
+ const char *inline_alias;
+
+ push_node (parser, MENU_LAYOUT_NODE_DEFAULT_LAYOUT);
+
+ locate_attributes (context, element_name,
+ attribute_names, attribute_values,
+ error,
+ "show_empty", &show_empty,
+ "inline", &inline_menus,
+ "inline_limit", &inline_limit,
+ "inline_header", &inline_header,
+ "inline_alias", &inline_alias,
+ NULL);
+
+ menu_layout_node_default_layout_set_values (parser->stack_top,
+ show_empty,
+ inline_menus,
+ inline_limit,
+ inline_header,
+ inline_alias);
+ }
+ else
+ {
+ if (!check_no_attributes (context, element_name,
+ attribute_names, attribute_values,
+ error))
+ return;
+
+ if (ELEMENT_IS ("AppDir"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_APP_DIR);
+ }
+ else if (ELEMENT_IS ("DefaultAppDirs"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_DEFAULT_APP_DIRS);
+ }
+ else if (ELEMENT_IS ("DirectoryDir"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_DIRECTORY_DIR);
+ }
+ else if (ELEMENT_IS ("DefaultDirectoryDirs"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_DEFAULT_DIRECTORY_DIRS);
+ }
+ else if (ELEMENT_IS ("DefaultMergeDirs"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_DEFAULT_MERGE_DIRS);
+ }
+ else if (ELEMENT_IS ("Name"))
+ {
+ if (has_child_of_type (parser->stack_top, MENU_LAYOUT_NODE_NAME))
+ {
+ set_error (error, context,
+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ "Multiple <Name> elements in a <Menu> element is not allowed\n");
+ return;
+ }
+
+ push_node (parser, MENU_LAYOUT_NODE_NAME);
+ }
+ else if (ELEMENT_IS ("Directory"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_DIRECTORY);
+ }
+ else if (ELEMENT_IS ("OnlyUnallocated"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_ONLY_UNALLOCATED);
+ }
+ else if (ELEMENT_IS ("NotOnlyUnallocated"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED);
+ }
+ else if (ELEMENT_IS ("Include"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_INCLUDE);
+ }
+ else if (ELEMENT_IS ("Exclude"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_EXCLUDE);
+ }
+ else if (ELEMENT_IS ("MergeDir"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_MERGE_DIR);
+ }
+ else if (ELEMENT_IS ("KDELegacyDirs"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_KDE_LEGACY_DIRS);
+ }
+ else if (ELEMENT_IS ("Move"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_MOVE);
+ }
+ else if (ELEMENT_IS ("Deleted"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_DELETED);
+
+ }
+ else if (ELEMENT_IS ("NotDeleted"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_NOT_DELETED);
+ }
+ else if (ELEMENT_IS ("Layout"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_LAYOUT);
+ }
+ else
+ {
+ set_error (error, context,
+ G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ "Element <%s> may not appear below <%s>\n",
+ element_name, "Menu");
+ }
+ }
+}
+
+static void
+start_matching_rule_element (MenuParser *parser,
+ GMarkupParseContext *context,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ GError **error)
+{
+ if (!check_no_attributes (context, element_name,
+ attribute_names, attribute_values,
+ error))
+ return;
+
+
+ if (ELEMENT_IS ("Filename"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_FILENAME);
+ }
+ else if (ELEMENT_IS ("Category"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_CATEGORY);
+ }
+ else if (ELEMENT_IS ("All"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_ALL);
+ }
+ else if (ELEMENT_IS ("And"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_AND);
+ }
+ else if (ELEMENT_IS ("Or"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_OR);
+ }
+ else if (ELEMENT_IS ("Not"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_NOT);
+ }
+ else
+ {
+ set_error (error, context,
+ G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ "Element <%s> may not appear in this context\n",
+ element_name);
+ }
+}
+
+static void
+start_move_child_element (MenuParser *parser,
+ GMarkupParseContext *context,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ GError **error)
+{
+ if (!check_no_attributes (context, element_name,
+ attribute_names, attribute_values,
+ error))
+ return;
+
+ if (ELEMENT_IS ("Old"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_OLD);
+ }
+ else if (ELEMENT_IS ("New"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_NEW);
+ }
+ else
+ {
+ set_error (error, context,
+ G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ "Element <%s> may not appear below <%s>\n",
+ element_name, "Move");
+ }
+}
+
+static void
+start_layout_child_element (MenuParser *parser,
+ GMarkupParseContext *context,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ GError **error)
+{
+ if (ELEMENT_IS ("Menuname"))
+ {
+ const char *show_empty;
+ const char *inline_menus;
+ const char *inline_limit;
+ const char *inline_header;
+ const char *inline_alias;
+
+ push_node (parser, MENU_LAYOUT_NODE_MENUNAME);
+
+ locate_attributes (context, element_name,
+ attribute_names, attribute_values,
+ error,
+ "show_empty", &show_empty,
+ "inline", &inline_menus,
+ "inline_limit", &inline_limit,
+ "inline_header", &inline_header,
+ "inline_alias", &inline_alias,
+ NULL);
+
+ menu_layout_node_menuname_set_values (parser->stack_top,
+ show_empty,
+ inline_menus,
+ inline_limit,
+ inline_header,
+ inline_alias);
+ }
+ else if (ELEMENT_IS ("Merge"))
+ {
+ const char *type;
+
+ push_node (parser, MENU_LAYOUT_NODE_MERGE);
+
+ locate_attributes (context, element_name,
+ attribute_names, attribute_values,
+ error,
+ "type", &type,
+ NULL);
+
+ menu_layout_node_merge_set_type (parser->stack_top, type);
+ }
+ else
+ {
+ if (!check_no_attributes (context, element_name,
+ attribute_names, attribute_values,
+ error))
+ return;
+
+ if (ELEMENT_IS ("Filename"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_FILENAME);
+ }
+ else if (ELEMENT_IS ("Separator"))
+ {
+ push_node (parser, MENU_LAYOUT_NODE_SEPARATOR);
+ }
+ else
+ {
+ set_error (error, context,
+ G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ "Element <%s> may not appear below <%s>\n",
+ element_name, "Move");
+ }
+ }
+}
+
+static void
+start_element_handler (GMarkupParseContext *context,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ gpointer user_data,
+ GError **error)
+{
+ MenuParser *parser = user_data;
+
+ if (ELEMENT_IS ("Menu"))
+ {
+ if (parser->stack_top == parser->root &&
+ has_child_of_type (parser->root, MENU_LAYOUT_NODE_MENU))
+ {
+ set_error (error, context,
+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ "Multiple root elements in menu file, only one toplevel <Menu> is allowed\n");
+ return;
+ }
+
+ start_menu_element (parser, context, element_name,
+ attribute_names, attribute_values,
+ error);
+ }
+ else if (parser->stack_top == parser->root)
+ {
+ set_error (error, context,
+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ "Root element in a menu file must be <Menu>, not <%s>\n",
+ element_name);
+ }
+ else if (parser->stack_top->type == MENU_LAYOUT_NODE_MENU)
+ {
+ start_menu_child_element (parser, context, element_name,
+ attribute_names, attribute_values,
+ error);
+ }
+ else if (parser->stack_top->type == MENU_LAYOUT_NODE_INCLUDE ||
+ parser->stack_top->type == MENU_LAYOUT_NODE_EXCLUDE ||
+ parser->stack_top->type == MENU_LAYOUT_NODE_AND ||
+ parser->stack_top->type == MENU_LAYOUT_NODE_OR ||
+ parser->stack_top->type == MENU_LAYOUT_NODE_NOT)
+ {
+ start_matching_rule_element (parser, context, element_name,
+ attribute_names, attribute_values,
+ error);
+ }
+ else if (parser->stack_top->type == MENU_LAYOUT_NODE_MOVE)
+ {
+ start_move_child_element (parser, context, element_name,
+ attribute_names, attribute_values,
+ error);
+ }
+ else if (parser->stack_top->type == MENU_LAYOUT_NODE_LAYOUT ||
+ parser->stack_top->type == MENU_LAYOUT_NODE_DEFAULT_LAYOUT)
+ {
+ start_layout_child_element (parser, context, element_name,
+ attribute_names, attribute_values,
+ error);
+ }
+ else
+ {
+ set_error (error, context,
+ G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ "Element <%s> may not appear in this context\n",
+ element_name);
+ }
+
+ add_context_to_error (error, context);
+}
+
+/* we want to make sure that the <Layout> or <DefaultLayout> is either empty,
+ * or contain one <Merge> of type "all", or contain one <Merge> of type "menus"
+ * and one <Merge> of type "files". If this is not the case, we try to clean up
+ * things:
+ * + if there is at least one <Merge> of type "all", then we only keep the
+ * last <Merge> of type "all" and remove all others <Merge>
+ * + if there is no <Merge> with type "all", we keep only the last <Merge> of
+ * type "menus" and the last <Merge> of type "files". If there's no <Merge>
+ * of type "menus" we append one, and then if there's no <Merge> of type
+ * "files", we append one. (So menus are before files)
+ */
+static gboolean
+fixup_layout_node (GMarkupParseContext *context,
+ MenuParser *parser,
+ MenuLayoutNode *node,
+ GError **error)
+{
+ MenuLayoutNode *child;
+ MenuLayoutNode *last_all;
+ MenuLayoutNode *last_menus;
+ MenuLayoutNode *last_files;
+ int n_all;
+ int n_menus;
+ int n_files;
+
+ if (!node->children)
+ {
+ return TRUE;
+ }
+
+ last_all = NULL;
+ last_menus = NULL;
+ last_files = NULL;
+ n_all = 0;
+ n_menus = 0;
+ n_files = 0;
+
+ child = node->children;
+ while (child != NULL)
+ {
+ switch (child->type)
+ {
+ case MENU_LAYOUT_NODE_MERGE:
+ switch (menu_layout_node_merge_get_type (child))
+ {
+ case MENU_LAYOUT_MERGE_NONE:
+ break;
+
+ case MENU_LAYOUT_MERGE_MENUS:
+ last_menus = child;
+ n_menus++;
+ break;
+
+ case MENU_LAYOUT_MERGE_FILES:
+ last_files = child;
+ n_files++;
+ break;
+
+ case MENU_LAYOUT_MERGE_ALL:
+ last_all = child;
+ n_all++;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ child = node_next (child);
+ }
+
+ if ((n_all == 1 && n_menus == 0 && n_files == 0) ||
+ (n_all == 0 && n_menus == 1 && n_files == 1))
+ {
+ return TRUE;
+ }
+ else if (n_all > 1 || n_menus > 1 || n_files > 1 ||
+ (n_all == 1 && (n_menus != 0 || n_files != 0)))
+ {
+ child = node->children;
+ while (child != NULL)
+ {
+ MenuLayoutNode *next;
+
+ next = node_next (child);
+
+ switch (child->type)
+ {
+ case MENU_LAYOUT_NODE_MERGE:
+ switch (menu_layout_node_merge_get_type (child))
+ {
+ case MENU_LAYOUT_MERGE_NONE:
+ break;
+
+ case MENU_LAYOUT_MERGE_MENUS:
+ if (n_all || last_menus != child)
+ {
+ menu_verbose ("removing duplicated merge menus element\n");
+ menu_layout_node_unlink (child);
+ }
+ break;
+
+ case MENU_LAYOUT_MERGE_FILES:
+ if (n_all || last_files != child)
+ {
+ menu_verbose ("removing duplicated merge files element\n");
+ menu_layout_node_unlink (child);
+ }
+ break;
+
+ case MENU_LAYOUT_MERGE_ALL:
+ if (last_all != child)
+ {
+ menu_verbose ("removing duplicated merge all element\n");
+ menu_layout_node_unlink (child);
+ }
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ child = next;
+ }
+ }
+
+ if (n_all == 0 && n_menus == 0)
+ {
+ last_menus = menu_layout_node_new (MENU_LAYOUT_NODE_MERGE);
+ menu_layout_node_merge_set_type (last_menus, "menus");
+ menu_verbose ("appending missing merge menus element\n");
+ menu_layout_node_append_child (node, last_menus);
+ }
+
+ if (n_all == 0 && n_files == 0)
+ {
+ last_files = menu_layout_node_new (MENU_LAYOUT_NODE_MERGE);
+ menu_layout_node_merge_set_type (last_files, "files");
+ menu_verbose ("appending missing merge files element\n");
+ menu_layout_node_append_child (node, last_files);
+ }
+
+ return TRUE;
+}
+
+/* we want to a) check that we have old-new pairs and b) canonicalize
+ * such that each <Move> has exactly one old-new pair
+ */
+static gboolean
+fixup_move_node (GMarkupParseContext *context,
+ MenuParser *parser,
+ MenuLayoutNode *node,
+ GError **error)
+{
+ MenuLayoutNode *child;
+ int n_old;
+ int n_new;
+
+ n_old = 0;
+ n_new = 0;
+
+ child = node->children;
+ while (child != NULL)
+ {
+ switch (child->type)
+ {
+ case MENU_LAYOUT_NODE_OLD:
+ if (n_new != n_old)
+ {
+ set_error (error, context,
+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ "<Old>/<New> elements not paired properly\n");
+ return FALSE;
+ }
+
+ n_old += 1;
+
+ break;
+
+ case MENU_LAYOUT_NODE_NEW:
+ n_new += 1;
+
+ if (n_new != n_old)
+ {
+ set_error (error, context,
+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ "<Old>/<New> elements not paired properly\n");
+ return FALSE;
+ }
+
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ child = node_next (child);
+ }
+
+ if (n_new == 0 || n_old == 0)
+ {
+ set_error (error, context,
+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ "<Old>/<New> elements missing under <Move>\n");
+ return FALSE;
+ }
+
+ g_assert (n_new == n_old);
+ g_assert ((n_new + n_old) % 2 == 0);
+
+ if (n_new > 1)
+ {
+ MenuLayoutNode *prev;
+ MenuLayoutNode *append_after;
+
+ /* Need to split the <Move> into multiple <Move> */
+
+ n_old = 0;
+ n_new = 0;
+ prev = NULL;
+ append_after = node;
+
+ child = node->children;
+ while (child != NULL)
+ {
+ MenuLayoutNode *next;
+
+ next = node_next (child);
+
+ switch (child->type)
+ {
+ case MENU_LAYOUT_NODE_OLD:
+ n_old += 1;
+ break;
+
+ case MENU_LAYOUT_NODE_NEW:
+ n_new += 1;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ if (n_old == n_new &&
+ n_old > 1)
+ {
+ /* Move the just-completed pair */
+ MenuLayoutNode *new_move;
+
+ g_assert (prev != NULL);
+
+ new_move = menu_layout_node_new (MENU_LAYOUT_NODE_MOVE);
+ menu_verbose ("inserting new_move after append_after\n");
+ menu_layout_node_insert_after (append_after, new_move);
+ append_after = new_move;
+
+ menu_layout_node_steal (prev);
+ menu_layout_node_steal (child);
+
+ menu_verbose ("appending prev to new_move\n");
+ menu_layout_node_append_child (new_move, prev);
+ menu_verbose ("appending child to new_move\n");
+ menu_layout_node_append_child (new_move, child);
+
+ menu_verbose ("Created new move element old = %s new = %s\n",
+ menu_layout_node_move_get_old (new_move),
+ menu_layout_node_move_get_new (new_move));
+
+ menu_layout_node_unref (new_move);
+ menu_layout_node_unref (prev);
+ menu_layout_node_unref (child);
+
+ prev = NULL;
+ }
+ else
+ {
+ prev = child;
+ }
+
+ prev = child;
+ child = next;
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+end_element_handler (GMarkupParseContext *context,
+ const char *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ MenuParser *parser = user_data;
+
+ g_assert (parser->stack_top != NULL);
+
+ switch (parser->stack_top->type)
+ {
+ case MENU_LAYOUT_NODE_APP_DIR:
+ case MENU_LAYOUT_NODE_DIRECTORY_DIR:
+ case MENU_LAYOUT_NODE_NAME:
+ case MENU_LAYOUT_NODE_DIRECTORY:
+ case MENU_LAYOUT_NODE_FILENAME:
+ case MENU_LAYOUT_NODE_CATEGORY:
+ case MENU_LAYOUT_NODE_MERGE_DIR:
+ case MENU_LAYOUT_NODE_LEGACY_DIR:
+ case MENU_LAYOUT_NODE_OLD:
+ case MENU_LAYOUT_NODE_NEW:
+ case MENU_LAYOUT_NODE_MENUNAME:
+ if (menu_layout_node_get_content (parser->stack_top) == NULL)
+ {
+ set_error (error, context,
+ G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+ "Element <%s> is required to contain text and was empty\n",
+ element_name);
+ goto out;
+ }
+ break;
+
+ case MENU_LAYOUT_NODE_MENU:
+ if (!has_child_of_type (parser->stack_top, MENU_LAYOUT_NODE_NAME))
+ {
+ set_error (error, context,
+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ "<Menu> elements are required to contain a <Name> element\n");
+ goto out;
+ }
+ break;
+
+ case MENU_LAYOUT_NODE_ROOT:
+ case MENU_LAYOUT_NODE_PASSTHROUGH:
+ case MENU_LAYOUT_NODE_DEFAULT_APP_DIRS:
+ case MENU_LAYOUT_NODE_DEFAULT_DIRECTORY_DIRS:
+ case MENU_LAYOUT_NODE_DEFAULT_MERGE_DIRS:
+ case MENU_LAYOUT_NODE_ONLY_UNALLOCATED:
+ case MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED:
+ case MENU_LAYOUT_NODE_INCLUDE:
+ case MENU_LAYOUT_NODE_EXCLUDE:
+ case MENU_LAYOUT_NODE_ALL:
+ case MENU_LAYOUT_NODE_AND:
+ case MENU_LAYOUT_NODE_OR:
+ case MENU_LAYOUT_NODE_NOT:
+ case MENU_LAYOUT_NODE_KDE_LEGACY_DIRS:
+ case MENU_LAYOUT_NODE_DELETED:
+ case MENU_LAYOUT_NODE_NOT_DELETED:
+ case MENU_LAYOUT_NODE_SEPARATOR:
+ case MENU_LAYOUT_NODE_MERGE:
+ case MENU_LAYOUT_NODE_MERGE_FILE:
+ break;
+
+ case MENU_LAYOUT_NODE_LAYOUT:
+ case MENU_LAYOUT_NODE_DEFAULT_LAYOUT:
+ if (!fixup_layout_node (context, parser, parser->stack_top, error))
+ goto out;
+ break;
+
+ case MENU_LAYOUT_NODE_MOVE:
+ if (!fixup_move_node (context, parser, parser->stack_top, error))
+ goto out;
+ break;
+ }
+
+ out:
+ parser->stack_top = parser->stack_top->parent;
+}
+
+static gboolean
+all_whitespace (const char *text,
+ int text_len)
+{
+ const char *p;
+ const char *end;
+
+ p = text;
+ end = text + text_len;
+
+ while (p != end)
+ {
+ if (!g_ascii_isspace (*p))
+ return FALSE;
+
+ p = g_utf8_next_char (p);
+ }
+
+ return TRUE;
+}
+
+static void
+text_handler (GMarkupParseContext *context,
+ const char *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ MenuParser *parser = user_data;
+
+ switch (parser->stack_top->type)
+ {
+ case MENU_LAYOUT_NODE_APP_DIR:
+ case MENU_LAYOUT_NODE_DIRECTORY_DIR:
+ case MENU_LAYOUT_NODE_NAME:
+ case MENU_LAYOUT_NODE_DIRECTORY:
+ case MENU_LAYOUT_NODE_FILENAME:
+ case MENU_LAYOUT_NODE_CATEGORY:
+ case MENU_LAYOUT_NODE_MERGE_FILE:
+ case MENU_LAYOUT_NODE_MERGE_DIR:
+ case MENU_LAYOUT_NODE_LEGACY_DIR:
+ case MENU_LAYOUT_NODE_OLD:
+ case MENU_LAYOUT_NODE_NEW:
+ case MENU_LAYOUT_NODE_MENUNAME:
+ g_assert (menu_layout_node_get_content (parser->stack_top) == NULL);
+
+ menu_layout_node_set_content (parser->stack_top, text);
+ break;
+
+ case MENU_LAYOUT_NODE_ROOT:
+ case MENU_LAYOUT_NODE_PASSTHROUGH:
+ case MENU_LAYOUT_NODE_MENU:
+ case MENU_LAYOUT_NODE_DEFAULT_APP_DIRS:
+ case MENU_LAYOUT_NODE_DEFAULT_DIRECTORY_DIRS:
+ case MENU_LAYOUT_NODE_DEFAULT_MERGE_DIRS:
+ case MENU_LAYOUT_NODE_ONLY_UNALLOCATED:
+ case MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED:
+ case MENU_LAYOUT_NODE_INCLUDE:
+ case MENU_LAYOUT_NODE_EXCLUDE:
+ case MENU_LAYOUT_NODE_ALL:
+ case MENU_LAYOUT_NODE_AND:
+ case MENU_LAYOUT_NODE_OR:
+ case MENU_LAYOUT_NODE_NOT:
+ case MENU_LAYOUT_NODE_KDE_LEGACY_DIRS:
+ case MENU_LAYOUT_NODE_MOVE:
+ case MENU_LAYOUT_NODE_DELETED:
+ case MENU_LAYOUT_NODE_NOT_DELETED:
+ case MENU_LAYOUT_NODE_LAYOUT:
+ case MENU_LAYOUT_NODE_DEFAULT_LAYOUT:
+ case MENU_LAYOUT_NODE_SEPARATOR:
+ case MENU_LAYOUT_NODE_MERGE:
+ if (!all_whitespace (text, text_len))
+ {
+ set_error (error, context,
+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ "No text is allowed inside element <%s>",
+ g_markup_parse_context_get_element (context));
+ }
+ break;
+ }
+
+ add_context_to_error (error, context);
+}
+
+static void
+passthrough_handler (GMarkupParseContext *context,
+ const char *passthrough_text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ MenuParser *parser = user_data;
+ MenuLayoutNode *node;
+
+ /* don't push passthrough on the stack, it's not an element */
+
+ node = menu_layout_node_new (MENU_LAYOUT_NODE_PASSTHROUGH);
+ menu_layout_node_set_content (node, passthrough_text);
+
+ menu_layout_node_append_child (parser->stack_top, node);
+ menu_layout_node_unref (node);
+
+ add_context_to_error (error, context);
+}
+
+static void
+menu_parser_init (MenuParser *parser)
+{
+ parser->root = menu_layout_node_new (MENU_LAYOUT_NODE_ROOT);
+ parser->stack_top = parser->root;
+}
+
+static void
+menu_parser_free (MenuParser *parser)
+{
+ if (parser->root)
+ menu_layout_node_unref (parser->root);
+}
+
+MenuLayoutNode *
+menu_layout_load (const char *filename,
+ const char *non_prefixed_basename,
+ GError **err)
+{
+ GMarkupParseContext *context;
+ MenuLayoutNodeRoot *root;
+ MenuLayoutNode *retval;
+ MenuParser parser;
+ GError *error;
+ GString *str;
+ char *text;
+ char *s;
+ gsize length;
+
+ text = NULL;
+ length = 0;
+ retval = NULL;
+ context = NULL;
+
+ menu_verbose ("Loading \"%s\" from disk\n", filename);
+
+ if (!g_file_get_contents (filename,
+ &text,
+ &length,
+ err))
+ {
+ menu_verbose ("Failed to load \"%s\"\n",
+ filename);
+ return NULL;
+ }
+
+ g_assert (text != NULL);
+
+ menu_parser_init (&parser);
+
+ root = (MenuLayoutNodeRoot *) parser.root;
+
+ root->basedir = g_path_get_dirname (filename);
+ menu_verbose ("Set basedir \"%s\"\n", root->basedir);
+
+ if (non_prefixed_basename)
+ s = g_strdup (non_prefixed_basename);
+ else
+ s = g_path_get_basename (filename);
+ str = g_string_new (s);
+ if (g_str_has_suffix (str->str, ".menu"))
+ g_string_truncate (str, str->len - strlen (".menu"));
+
+ root->name = str->str;
+ menu_verbose ("Set menu name \"%s\"\n", root->name);
+
+ g_string_free (str, FALSE);
+ g_free (s);
+
+ context = g_markup_parse_context_new (&menu_funcs, 0, &parser, NULL);
+
+ error = NULL;
+ if (!g_markup_parse_context_parse (context,
+ text,
+ length,
+ &error))
+ goto out;
+
+ error = NULL;
+ g_markup_parse_context_end_parse (context, &error);
+
+ out:
+ if (context)
+ g_markup_parse_context_free (context);
+ g_free (text);
+
+ if (error)
+ {
+ menu_verbose ("Error \"%s\" loading \"%s\"\n",
+ error->message, filename);
+ g_propagate_error (err, error);
+ }
+ else if (has_child_of_type (parser.root, MENU_LAYOUT_NODE_MENU))
+ {
+ menu_verbose ("File loaded OK\n");
+ retval = parser.root;
+ parser.root = NULL;
+ }
+ else
+ {
+ menu_verbose ("Did not have a root element in file\n");
+ g_set_error (err, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ "Menu file %s did not contain a root <Menu> element",
+ filename);
+ }
+
+ menu_parser_free (&parser);
+
+ return retval;
+}
diff --git a/libmenu/menu-layout.h b/libmenu/menu-layout.h
new file mode 100644
index 0000000..4b63014
--- /dev/null
+++ b/libmenu/menu-layout.h
@@ -0,0 +1,161 @@
+/* Menu layout in-memory data structure (a custom "DOM tree") */
+
+/*
+ * Copyright (C) 2002 - 2004 Red Hat, 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 __MENU_LAYOUT_H__
+#define __MENU_LAYOUT_H__
+
+#include <glib.h>
+
+#include "entry-directories.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct MenuLayoutNode MenuLayoutNode;
+
+typedef enum {
+ MENU_LAYOUT_NODE_ROOT,
+ MENU_LAYOUT_NODE_PASSTHROUGH,
+ MENU_LAYOUT_NODE_MENU,
+ MENU_LAYOUT_NODE_APP_DIR,
+ MENU_LAYOUT_NODE_DEFAULT_APP_DIRS,
+ MENU_LAYOUT_NODE_DIRECTORY_DIR,
+ MENU_LAYOUT_NODE_DEFAULT_DIRECTORY_DIRS,
+ MENU_LAYOUT_NODE_DEFAULT_MERGE_DIRS,
+ MENU_LAYOUT_NODE_NAME,
+ MENU_LAYOUT_NODE_DIRECTORY,
+ MENU_LAYOUT_NODE_ONLY_UNALLOCATED,
+ MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED,
+ MENU_LAYOUT_NODE_INCLUDE,
+ MENU_LAYOUT_NODE_EXCLUDE,
+ MENU_LAYOUT_NODE_FILENAME,
+ MENU_LAYOUT_NODE_CATEGORY,
+ MENU_LAYOUT_NODE_ALL,
+ MENU_LAYOUT_NODE_AND,
+ MENU_LAYOUT_NODE_OR,
+ MENU_LAYOUT_NODE_NOT,
+ MENU_LAYOUT_NODE_MERGE_FILE,
+ MENU_LAYOUT_NODE_MERGE_DIR,
+ MENU_LAYOUT_NODE_LEGACY_DIR,
+ MENU_LAYOUT_NODE_KDE_LEGACY_DIRS,
+ MENU_LAYOUT_NODE_MOVE,
+ MENU_LAYOUT_NODE_OLD,
+ MENU_LAYOUT_NODE_NEW,
+ MENU_LAYOUT_NODE_DELETED,
+ MENU_LAYOUT_NODE_NOT_DELETED,
+ MENU_LAYOUT_NODE_LAYOUT,
+ MENU_LAYOUT_NODE_DEFAULT_LAYOUT,
+ MENU_LAYOUT_NODE_MENUNAME,
+ MENU_LAYOUT_NODE_SEPARATOR,
+ MENU_LAYOUT_NODE_MERGE
+} MenuLayoutNodeType;
+
+typedef enum {
+ MENU_MERGE_FILE_TYPE_PATH = 0,
+ MENU_MERGE_FILE_TYPE_PARENT
+} MenuMergeFileType;
+
+typedef enum {
+ MENU_LAYOUT_MERGE_NONE,
+ MENU_LAYOUT_MERGE_MENUS,
+ MENU_LAYOUT_MERGE_FILES,
+ MENU_LAYOUT_MERGE_ALL
+} MenuLayoutMergeType;
+
+typedef enum {
+ MENU_LAYOUT_VALUES_NONE = 0,
+ MENU_LAYOUT_VALUES_SHOW_EMPTY = 1 << 0,
+ MENU_LAYOUT_VALUES_INLINE_MENUS = 1 << 1,
+ MENU_LAYOUT_VALUES_INLINE_LIMIT = 1 << 2,
+ MENU_LAYOUT_VALUES_INLINE_HEADER = 1 << 3,
+ MENU_LAYOUT_VALUES_INLINE_ALIAS = 1 << 4
+} MenuLayoutValuesMask;
+
+typedef struct {
+ MenuLayoutValuesMask mask;
+
+ guint show_empty: 1;
+ guint inline_menus: 1;
+ guint inline_header: 1;
+ guint inline_alias: 1;
+
+ guint inline_limit;
+} MenuLayoutValues;
+
+
+MenuLayoutNode *menu_layout_load (const char* filename, const char *non_prefixed_basename, GError** error);
+
+MenuLayoutNode *menu_layout_node_new (MenuLayoutNodeType type);
+MenuLayoutNode *menu_layout_node_ref (MenuLayoutNode *node);
+void menu_layout_node_unref (MenuLayoutNode *node);
+
+MenuLayoutNodeType menu_layout_node_get_type (MenuLayoutNode *node);
+
+MenuLayoutNode *menu_layout_node_get_root (MenuLayoutNode *node);
+MenuLayoutNode *menu_layout_node_get_parent (MenuLayoutNode *node);
+MenuLayoutNode *menu_layout_node_get_children (MenuLayoutNode *node);
+MenuLayoutNode *menu_layout_node_get_next (MenuLayoutNode *node);
+
+void menu_layout_node_insert_before (MenuLayoutNode *node, MenuLayoutNode *new_sibling);
+void menu_layout_node_insert_after (MenuLayoutNode *node, MenuLayoutNode *new_sibling);
+void menu_layout_node_prepend_child (MenuLayoutNode *parent, MenuLayoutNode *new_child);
+void menu_layout_node_append_child (MenuLayoutNode *parent, MenuLayoutNode *new_child);
+
+void menu_layout_node_unlink (MenuLayoutNode *node);
+void menu_layout_node_steal (MenuLayoutNode *node);
+
+const char *menu_layout_node_get_content (MenuLayoutNode *node);
+void menu_layout_node_set_content (MenuLayoutNode *node, const char *content);
+
+char *menu_layout_node_get_content_as_path (MenuLayoutNode *node);
+
+const char *menu_layout_node_root_get_name (MenuLayoutNode *node);
+const char *menu_layout_node_root_get_basedir (MenuLayoutNode *node);
+
+const char *menu_layout_node_menu_get_name (MenuLayoutNode *node);
+EntryDirectoryList *menu_layout_node_menu_get_app_dirs (MenuLayoutNode *node);
+EntryDirectoryList *menu_layout_node_menu_get_directory_dirs (MenuLayoutNode *node);
+
+const char *menu_layout_node_move_get_old (MenuLayoutNode *node);
+const char *menu_layout_node_move_get_new (MenuLayoutNode *node);
+
+const char *menu_layout_node_legacy_dir_get_prefix (MenuLayoutNode *node);
+void menu_layout_node_legacy_dir_set_prefix (MenuLayoutNode *node, const char *prefix);
+
+MenuMergeFileType menu_layout_node_merge_file_get_type (MenuLayoutNode *node);
+void menu_layout_node_merge_file_set_type (MenuLayoutNode *node, MenuMergeFileType type);
+
+MenuLayoutMergeType menu_layout_node_merge_get_type (MenuLayoutNode *node);
+
+void menu_layout_node_default_layout_get_values (MenuLayoutNode *node, MenuLayoutValues *values);
+void menu_layout_node_menuname_get_values (MenuLayoutNode *node, MenuLayoutValues *values);
+
+typedef void (*MenuLayoutNodeEntriesChangedFunc) (MenuLayoutNode* node, gpointer user_data);
+
+void menu_layout_node_root_add_entries_monitor (MenuLayoutNode* node, MenuLayoutNodeEntriesChangedFunc callback, gpointer user_data);
+void menu_layout_node_root_remove_entries_monitor (MenuLayoutNode* node, MenuLayoutNodeEntriesChangedFunc callback, gpointer user_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MENU_LAYOUT_H__ */
diff --git a/libmenu/menu-monitor.c b/libmenu/menu-monitor.c
new file mode 100644
index 0000000..ff36010
--- /dev/null
+++ b/libmenu/menu-monitor.c
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2006 Mark McLoughlin
+ * Copyright (C) 2007 Sebastian Dröge
+ * Copyright (C) 2008 Vincent Untz
+ *
+ * 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.
+ */
+
+#include <config.h>
+
+#include "menu-monitor.h"
+
+#include <gio/gio.h>
+
+#include "menu-util.h"
+
+struct MenuMonitor {
+ char* path;
+ guint refcount;
+
+ GSList* notifies;
+
+ GFileMonitor* monitor;
+
+ guint is_directory: 1;
+};
+
+typedef struct {
+ MenuMonitor* monitor;
+ MenuMonitorEvent event;
+ char* path;
+} MenuMonitorEventInfo;
+
+typedef struct {
+ MenuMonitorNotifyFunc notify_func;
+ gpointer user_data;
+ guint refcount;
+} MenuMonitorNotify;
+
+static MenuMonitorNotify* mate_menu_monitor_notify_ref(MenuMonitorNotify* notify);
+static void mate_menu_monitor_notify_unref(MenuMonitorNotify* notify);
+
+static GHashTable* monitors_registry = NULL;
+static guint events_idle_handler = 0;
+static GSList* pending_events = NULL;
+
+static void invoke_notifies(MenuMonitor* monitor, MenuMonitorEvent event, const char* path)
+{
+ GSList *copy;
+ GSList *tmp;
+
+ copy = g_slist_copy (monitor->notifies);
+ g_slist_foreach (copy,
+ (GFunc) mate_menu_monitor_notify_ref,
+ NULL);
+
+ tmp = copy;
+ while (tmp != NULL)
+ {
+ MenuMonitorNotify *notify = tmp->data;
+ GSList *next = tmp->next;
+
+ if (notify->notify_func)
+ {
+ notify->notify_func (monitor, event, path, notify->user_data);
+ }
+
+ mate_menu_monitor_notify_unref(notify);
+
+ tmp = next;
+ }
+
+ g_slist_free (copy);
+}
+
+static gboolean emit_events_in_idle(void)
+{
+ GSList *events_to_emit;
+ GSList *tmp;
+
+ events_to_emit = pending_events;
+
+ pending_events = NULL;
+ events_idle_handler = 0;
+
+ tmp = events_to_emit;
+ while (tmp != NULL)
+ {
+ MenuMonitorEventInfo *event_info = tmp->data;
+
+ mate_menu_monitor_ref(event_info->monitor);
+
+ tmp = tmp->next;
+ }
+
+ tmp = events_to_emit;
+ while (tmp != NULL)
+ {
+ MenuMonitorEventInfo *event_info = tmp->data;
+
+ invoke_notifies (event_info->monitor,
+ event_info->event,
+ event_info->path);
+
+ menu_monitor_unref (event_info->monitor);
+ event_info->monitor = NULL;
+
+ g_free (event_info->path);
+ event_info->path = NULL;
+
+ event_info->event = MENU_MONITOR_EVENT_INVALID;
+
+ g_free (event_info);
+
+ tmp = tmp->next;
+ }
+
+ g_slist_free (events_to_emit);
+
+ return FALSE;
+}
+
+static void menu_monitor_queue_event(MenuMonitorEventInfo* event_info)
+{
+ pending_events = g_slist_append (pending_events, event_info);
+
+ if (events_idle_handler == 0)
+ {
+ events_idle_handler = g_idle_add ((GSourceFunc) emit_events_in_idle, NULL);
+ }
+}
+
+static inline char* get_registry_key(const char* path, gboolean is_directory)
+{
+ return g_strdup_printf ("%s:%s",
+ path,
+ is_directory ? "<dir>" : "<file>");
+}
+
+static gboolean monitor_callback (GFileMonitor* monitor, GFile* child, GFile* other_file, GFileMonitorEvent eflags, gpointer user_data)
+{
+ MenuMonitorEventInfo *event_info;
+ MenuMonitorEvent event;
+ MenuMonitor *menu_monitor = (MenuMonitor *) user_data;
+
+ event = MENU_MONITOR_EVENT_INVALID;
+ switch (eflags)
+ {
+ case G_FILE_MONITOR_EVENT_CHANGED:
+ event = MENU_MONITOR_EVENT_CHANGED;
+ break;
+ case G_FILE_MONITOR_EVENT_CREATED:
+ event = MENU_MONITOR_EVENT_CREATED;
+ break;
+ case G_FILE_MONITOR_EVENT_DELETED:
+ event = MENU_MONITOR_EVENT_DELETED;
+ break;
+ default:
+ return TRUE;
+ }
+
+ event_info = g_new0 (MenuMonitorEventInfo, 1);
+
+ event_info->path = g_file_get_path (child);
+ event_info->event = event;
+ event_info->monitor = menu_monitor;
+
+ menu_monitor_queue_event (event_info);
+
+ return TRUE;
+}
+
+static MenuMonitor* register_monitor(const char* path, gboolean is_directory)
+{
+ static gboolean initted = FALSE;
+ MenuMonitor *retval;
+ GFile *file;
+
+ if (!initted)
+ {
+ /* This is the only place where we're using GObject and the app can't
+ * know we're using it, so we need to init the type system ourselves. */
+ g_type_init ();
+ initted = TRUE;
+ }
+
+ retval = g_new0 (MenuMonitor, 1);
+
+ retval->path = g_strdup (path);
+ retval->refcount = 1;
+ retval->is_directory = is_directory != FALSE;
+
+ file = g_file_new_for_path (retval->path);
+
+ if (file == NULL)
+ {
+ menu_verbose ("Not adding monitor on '%s', failed to create GFile\n",
+ retval->path);
+ return retval;
+ }
+
+ if (retval->is_directory)
+ retval->monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE,
+ NULL, NULL);
+ else
+ retval->monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE,
+ NULL, NULL);
+
+ g_object_unref (G_OBJECT (file));
+
+ if (retval->monitor == NULL)
+ {
+ menu_verbose ("Not adding monitor on '%s', failed to create monitor\n",
+ retval->path);
+ return retval;
+ }
+
+ g_signal_connect (retval->monitor, "changed",
+ G_CALLBACK (monitor_callback), retval);
+
+ return retval;
+}
+
+static MenuMonitor* lookup_monitor(const char* path, gboolean is_directory)
+{
+ MenuMonitor *retval;
+ char *registry_key;
+
+ retval = NULL;
+
+ registry_key = get_registry_key (path, is_directory);
+
+ if (monitors_registry == NULL)
+ {
+ monitors_registry = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ NULL);
+ }
+ else
+ {
+ retval = g_hash_table_lookup (monitors_registry, registry_key);
+ }
+
+ if (retval == NULL)
+ {
+ retval = register_monitor (path, is_directory);
+ g_hash_table_insert (monitors_registry, registry_key, retval);
+
+ return retval;
+ }
+ else
+ {
+ g_free (registry_key);
+
+ return mate_menu_monitor_ref(retval);
+ }
+}
+
+MenuMonitor* mate_menu_monitor_file_get(const char* path)
+{
+ g_return_val_if_fail(path != NULL, NULL);
+
+ return lookup_monitor(path, FALSE);
+}
+
+MenuMonitor* menu_get_directory_monitor(const char* path)
+{
+ g_return_val_if_fail (path != NULL, NULL);
+
+ return lookup_monitor (path, TRUE);
+}
+
+MenuMonitor* mate_menu_monitor_ref(MenuMonitor* monitor)
+{
+ g_return_val_if_fail(monitor != NULL, NULL);
+ g_return_val_if_fail(monitor->refcount > 0, NULL);
+
+ monitor->refcount++;
+
+ return monitor;
+}
+
+static void menu_monitor_clear_pending_events(MenuMonitor* monitor)
+{
+ GSList *tmp;
+
+ tmp = pending_events;
+ while (tmp != NULL)
+ {
+ MenuMonitorEventInfo *event_info = tmp->data;
+ GSList *next = tmp->next;
+
+ if (event_info->monitor == monitor)
+ {
+ pending_events = g_slist_delete_link (pending_events, tmp);
+
+ g_free (event_info->path);
+ event_info->path = NULL;
+
+ event_info->monitor = NULL;
+ event_info->event = MENU_MONITOR_EVENT_INVALID;
+
+ g_free (event_info);
+ }
+
+ tmp = next;
+ }
+}
+
+void menu_monitor_unref(MenuMonitor* monitor)
+{
+ char *registry_key;
+
+ g_return_if_fail (monitor != NULL);
+ g_return_if_fail (monitor->refcount > 0);
+
+ if (--monitor->refcount > 0)
+ return;
+
+ registry_key = get_registry_key (monitor->path, monitor->is_directory);
+ g_hash_table_remove (monitors_registry, registry_key);
+ g_free (registry_key);
+
+ if (g_hash_table_size (monitors_registry) == 0)
+ {
+ g_hash_table_destroy (monitors_registry);
+ monitors_registry = NULL;
+ }
+
+ if (monitor->monitor)
+ {
+ g_file_monitor_cancel (monitor->monitor);
+ g_object_unref (monitor->monitor);
+ monitor->monitor = NULL;
+ }
+
+ g_slist_foreach (monitor->notifies, (GFunc) mate_menu_monitor_notify_unref, NULL);
+ g_slist_free (monitor->notifies);
+ monitor->notifies = NULL;
+
+ menu_monitor_clear_pending_events (monitor);
+
+ g_free (monitor->path);
+ monitor->path = NULL;
+
+ g_free (monitor);
+}
+
+static MenuMonitorNotify* mate_menu_monitor_notify_ref(MenuMonitorNotify* notify)
+{
+ g_return_val_if_fail(notify != NULL, NULL);
+ g_return_val_if_fail(notify->refcount > 0, NULL);
+
+ notify->refcount++;
+
+ return notify;
+}
+
+static void mate_menu_monitor_notify_unref(MenuMonitorNotify* notify)
+{
+ g_return_if_fail(notify != NULL);
+ g_return_if_fail(notify->refcount > 0);
+
+ if (--notify->refcount > 0)
+ {
+ return;
+ }
+
+ g_free(notify);
+}
+
+void menu_monitor_add_notify(MenuMonitor* monitor, MenuMonitorNotifyFunc notify_func, gpointer user_data)
+{
+ MenuMonitorNotify* notify;
+
+ g_return_if_fail(monitor != NULL);
+ g_return_if_fail(notify_func != NULL);
+
+ GSList* tmp = monitor->notifies;
+
+ while (tmp != NULL)
+ {
+ notify = tmp->data;
+
+ if (notify->notify_func == notify_func && notify->user_data == user_data)
+ {
+ break;
+ }
+
+ tmp = tmp->next;
+ }
+
+ if (tmp == NULL)
+ {
+ notify = g_new0(MenuMonitorNotify, 1);
+ notify->notify_func = notify_func;
+ notify->user_data = user_data;
+ notify->refcount = 1;
+
+ monitor->notifies = g_slist_append(monitor->notifies, notify);
+ }
+}
+
+void mate_menu_monitor_notify_remove(MenuMonitor* monitor, MenuMonitorNotifyFunc notify_func, gpointer user_data)
+{
+ GSList* tmp = monitor->notifies;
+
+ while (tmp != NULL)
+ {
+ MenuMonitorNotify* notify = tmp->data;
+ GSList* next = tmp->next;
+
+ if (notify->notify_func == notify_func && notify->user_data == user_data)
+ {
+ notify->notify_func = NULL;
+ notify->user_data = NULL;
+
+ mate_menu_monitor_notify_unref(notify);
+
+ monitor->notifies = g_slist_delete_link(monitor->notifies, tmp);
+ }
+
+ tmp = next;
+ }
+}
diff --git a/libmenu/menu-monitor.h b/libmenu/menu-monitor.h
new file mode 100644
index 0000000..1dbf6ba
--- /dev/null
+++ b/libmenu/menu-monitor.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2011 Perberos
+ *
+ * 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 __MENU_MONITOR_H__
+#define __MENU_MONITOR_H__
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct MenuMonitor MenuMonitor;
+
+typedef enum {
+ MENU_MONITOR_EVENT_INVALID = 0,
+ MENU_MONITOR_EVENT_CREATED = 1,
+ MENU_MONITOR_EVENT_DELETED = 2,
+ MENU_MONITOR_EVENT_CHANGED = 3
+} MenuMonitorEvent;
+
+typedef void (*MenuMonitorNotifyFunc) (MenuMonitor* monitor, MenuMonitorEvent event, const char* path, gpointer user_data);
+
+
+MenuMonitor* menu_get_file_monitor(const char* path);
+MenuMonitor* menu_get_directory_monitor(const char* path);
+
+MenuMonitor* menu_monitor_ref(MenuMonitor* monitor);
+void menu_monitor_unref(MenuMonitor* monitor);
+
+void menu_monitor_add_notify(MenuMonitor* monitor, MenuMonitorNotifyFunc notify_func, gpointer user_data);
+void menu_monitor_remove_notify(MenuMonitor* monitor, MenuMonitorNotifyFunc notify_func, gpointer user_data);
+
+
+/* Izquierda a derecha
+ */
+
+#define mate_menu_monitor_file_get menu_get_file_monitor
+#define mate_menu_monitor_directory_get menu_get_directory_monitor
+
+#define mate_menu_monitor_ref menu_monitor_ref
+#define mate_menu_monitor_unref menu_monitor_unref
+
+#define mate_menu_monitor_notify_add menu_monitor_add_notify
+#define mate_menu_monitor_notify_remove menu_monitor_remove_notify
+#define mate_menu_monitor_notify_ref menu_monitor_notify_ref /* private */
+#define mate_menu_monitor_notify_unref menu_monitor_notify_unref /* private */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MENU_MONITOR_H__ */
diff --git a/libmenu/menu-util.c b/libmenu/menu-util.c
new file mode 100644
index 0000000..2f992b0
--- /dev/null
+++ b/libmenu/menu-util.c
@@ -0,0 +1,436 @@
+/* Random utility functions for menu code */
+
+/*
+ * Copyright (C) 2003 Red Hat, 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.
+ */
+
+#include <config.h>
+
+#include "menu-util.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+
+
+#ifdef G_ENABLE_DEBUG
+
+static gboolean verbose = FALSE;
+static gboolean initted = FALSE;
+
+static inline gboolean menu_verbose_enabled(void)
+{
+ if (!initted)
+ {
+ verbose = g_getenv("MENU_VERBOSE") != NULL;
+ initted = TRUE;
+ }
+
+ return verbose;
+}
+
+static int utf8_fputs(const char* str, FILE* f)
+{
+ char* l;
+ int ret;
+
+ l = g_locale_from_utf8(str, -1, NULL, NULL, NULL);
+
+ if (l == NULL)
+ {
+ ret = fputs(str, f); /* just print it anyway, better than nothing */
+ }
+ else
+ {
+ ret = fputs(l, f);
+ }
+
+ g_free(l);
+
+ return ret;
+}
+
+void menu_verbose(const char* format, ...)
+{
+ va_list args;
+ char* str;
+
+ if (!menu_verbose_enabled())
+ {
+ return;
+ }
+
+ va_start(args, format);
+ str = g_strdup_vprintf(format, args);
+ va_end(args);
+
+ utf8_fputs(str, stderr);
+ fflush(stderr);
+
+ g_free(str);
+}
+
+static void append_to_string(MenuLayoutNode* node, gboolean onelevel, int depth, GString* str);
+
+static void append_spaces(GString* str, int depth)
+{
+ while (depth > 0)
+ {
+ g_string_append_c(str, ' ');
+ --depth;
+ }
+}
+
+static void append_children(MenuLayoutNode* node, int depth, GString* str)
+{
+ MenuLayoutNode* iter;
+
+ iter = menu_layout_node_get_children(node);
+
+ while (iter != NULL)
+ {
+ append_to_string(iter, FALSE, depth, str);
+
+ iter = menu_layout_node_get_next(iter);
+ }
+}
+
+static void append_simple_with_attr(MenuLayoutNode* node, int depth, const char* node_name, const char* attr_name, const char* attr_value, GString* str)
+{
+ const char* content;
+
+ append_spaces(str, depth);
+
+ if ((content = menu_layout_node_get_content(node)))
+ {
+ char* escaped;
+
+ escaped = g_markup_escape_text(content, -1);
+
+ if (attr_name && attr_value)
+ {
+ char* attr_escaped;
+
+ attr_escaped = g_markup_escape_text(attr_value, -1);
+
+ g_string_append_printf(str, "<%s %s=\"%s\">%s</%s>\n", node_name, attr_name, attr_escaped, escaped, node_name);
+
+ g_free(attr_escaped);
+ }
+ else
+ {
+ g_string_append_printf(str, "<%s>%s</%s>\n", node_name, escaped, node_name);
+ }
+
+ g_free(escaped);
+ }
+ else
+ {
+ if (attr_name && attr_value)
+ {
+ char* attr_escaped;
+
+ attr_escaped = g_markup_escape_text(attr_value, -1);
+
+ g_string_append_printf(str, "<%s %s=\"%s\"/>\n", node_name, attr_name, attr_escaped);
+
+ g_free(attr_escaped);
+ }
+ else
+ {
+ g_string_append_printf(str, "<%s/>\n", node_name);
+ }
+ }
+}
+
+static void append_layout(MenuLayoutNode* node, int depth, const char* node_name, MenuLayoutValues* layout_values, GString* str)
+{
+ const char* content;
+
+ append_spaces(str, depth);
+
+ if ((content = menu_layout_node_get_content(node)))
+ {
+ char* escaped;
+
+ escaped = g_markup_escape_text(content, -1);
+
+ g_string_append_printf(str,
+ "<%s show_empty=\"%s\" inline=\"%s\" inline_header=\"%s\""
+ " inline_alias=\"%s\" inline_limit=\"%d\">%s</%s>\n",
+ node_name,
+ layout_values->show_empty ? "true" : "false",
+ layout_values->inline_menus ? "true" : "false",
+ layout_values->inline_header ? "true" : "false",
+ layout_values->inline_alias ? "true" : "false",
+ layout_values->inline_limit,
+ escaped,
+ node_name);
+
+ g_free(escaped);
+ }
+ else
+ {
+ g_string_append_printf(str,
+ "<%s show_empty=\"%s\" inline=\"%s\" inline_header=\"%s\""
+ " inline_alias=\"%s\" inline_limit=\"%d\"/>\n",
+ node_name,
+ layout_values->show_empty ? "true" : "false",
+ layout_values->inline_menus ? "true" : "false",
+ layout_values->inline_header ? "true" : "false",
+ layout_values->inline_alias ? "true" : "false",
+ layout_values->inline_limit);
+ }
+}
+
+static void append_merge(MenuLayoutNode* node, int depth, const char* node_name, MenuLayoutMergeType merge_type, GString* str)
+{
+ const char* merge_type_str;
+
+ merge_type_str = NULL;
+
+ switch (merge_type)
+ {
+ case MENU_LAYOUT_MERGE_NONE:
+ merge_type_str = "none";
+ break;
+
+ case MENU_LAYOUT_MERGE_MENUS:
+ merge_type_str = "menus";
+ break;
+
+ case MENU_LAYOUT_MERGE_FILES:
+ merge_type_str = "files";
+ break;
+
+ case MENU_LAYOUT_MERGE_ALL:
+ merge_type_str = "all";
+ break;
+
+ default:
+ g_assert_not_reached();
+ break;
+ }
+
+ append_simple_with_attr(node, depth, node_name, "type", merge_type_str, str);
+}
+
+static void append_simple(MenuLayoutNode* node, int depth, const char* node_name, GString* str)
+{
+ append_simple_with_attr(node, depth, node_name, NULL, NULL, str);
+}
+
+static void append_start(MenuLayoutNode* node, int depth, const char* node_name, GString* str)
+{
+ append_spaces(str, depth);
+
+ g_string_append_printf(str, "<%s>\n", node_name);
+}
+
+static void append_end(MenuLayoutNode* node, int depth, const char* node_name, GString* str)
+{
+ append_spaces(str, depth);
+
+ g_string_append_printf(str, "</%s>\n", node_name);
+}
+
+static void append_container(MenuLayoutNode* node, gboolean onelevel, int depth, const char* node_name, GString* str)
+{
+ append_start(node, depth, node_name, str);
+
+ if (!onelevel)
+ {
+ append_children(node, depth + 2, str);
+ append_end(node, depth, node_name, str);
+ }
+}
+
+static void append_to_string(MenuLayoutNode* node, gboolean onelevel, int depth, GString* str)
+{
+ MenuLayoutValues layout_values;
+
+ switch (menu_layout_node_get_type(node))
+ {
+ case MENU_LAYOUT_NODE_ROOT:
+ if (!onelevel)
+ append_children(node, depth - 1, str); /* -1 to ignore depth of root */
+ else
+ append_start(node, depth - 1, "Root", str);
+ break;
+
+ case MENU_LAYOUT_NODE_PASSTHROUGH:
+ g_string_append(str, menu_layout_node_get_content(node));
+ g_string_append_c(str, '\n');
+ break;
+
+ case MENU_LAYOUT_NODE_MENU:
+ append_container(node, onelevel, depth, "Menu", str);
+ break;
+
+ case MENU_LAYOUT_NODE_APP_DIR:
+ append_simple(node, depth, "AppDir", str);
+ break;
+
+ case MENU_LAYOUT_NODE_DEFAULT_APP_DIRS:
+ append_simple(node, depth, "DefaultAppDirs", str);
+ break;
+
+ case MENU_LAYOUT_NODE_DIRECTORY_DIR:
+ append_simple(node, depth, "DirectoryDir", str);
+ break;
+
+ case MENU_LAYOUT_NODE_DEFAULT_DIRECTORY_DIRS:
+ append_simple(node, depth, "DefaultDirectoryDirs", str);
+ break;
+
+ case MENU_LAYOUT_NODE_DEFAULT_MERGE_DIRS:
+ append_simple(node, depth, "DefaultMergeDirs", str);
+ break;
+
+ case MENU_LAYOUT_NODE_NAME:
+ append_simple(node, depth, "Name", str);
+ break;
+
+ case MENU_LAYOUT_NODE_DIRECTORY:
+ append_simple(node, depth, "Directory", str);
+ break;
+
+ case MENU_LAYOUT_NODE_ONLY_UNALLOCATED:
+ append_simple(node, depth, "OnlyUnallocated", str);
+ break;
+
+ case MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED:
+ append_simple(node, depth, "NotOnlyUnallocated", str);
+ break;
+
+ case MENU_LAYOUT_NODE_INCLUDE:
+ append_container(node, onelevel, depth, "Include", str);
+ break;
+
+ case MENU_LAYOUT_NODE_EXCLUDE:
+ append_container(node, onelevel, depth, "Exclude", str);
+ break;
+
+ case MENU_LAYOUT_NODE_FILENAME:
+ append_simple(node, depth, "Filename", str);
+ break;
+
+ case MENU_LAYOUT_NODE_CATEGORY:
+ append_simple(node, depth, "Category", str);
+ break;
+
+ case MENU_LAYOUT_NODE_ALL:
+ append_simple(node, depth, "All", str);
+ break;
+
+ case MENU_LAYOUT_NODE_AND:
+ append_container(node, onelevel, depth, "And", str);
+ break;
+
+ case MENU_LAYOUT_NODE_OR:
+ append_container(node, onelevel, depth, "Or", str);
+ break;
+
+ case MENU_LAYOUT_NODE_NOT:
+ append_container(node, onelevel, depth, "Not", str);
+ break;
+
+ case MENU_LAYOUT_NODE_MERGE_FILE:
+ {
+ MenuMergeFileType type;
+
+ type = menu_layout_node_merge_file_get_type(node);
+
+ append_simple_with_attr(node, depth, "MergeFile", "type", type == MENU_MERGE_FILE_TYPE_PARENT ? "parent" : "path", str);
+ break;
+ }
+
+ case MENU_LAYOUT_NODE_MERGE_DIR:
+ append_simple(node, depth, "MergeDir", str);
+ break;
+
+ case MENU_LAYOUT_NODE_LEGACY_DIR:
+ append_simple_with_attr(node, depth, "LegacyDir", "prefix", menu_layout_node_legacy_dir_get_prefix (node), str);
+ break;
+
+ case MENU_LAYOUT_NODE_KDE_LEGACY_DIRS:
+ append_simple(node, depth, "KDELegacyDirs", str);
+ break;
+
+ case MENU_LAYOUT_NODE_MOVE:
+ append_container(node, onelevel, depth, "Move", str);
+ break;
+
+ case MENU_LAYOUT_NODE_OLD:
+ append_simple(node, depth, "Old", str);
+ break;
+
+ case MENU_LAYOUT_NODE_NEW:
+ append_simple(node, depth, "New", str);
+ break;
+
+ case MENU_LAYOUT_NODE_DELETED:
+ append_simple(node, depth, "Deleted", str);
+ break;
+
+ case MENU_LAYOUT_NODE_NOT_DELETED:
+ append_simple(node, depth, "NotDeleted", str);
+ break;
+
+ case MENU_LAYOUT_NODE_LAYOUT:
+ append_container(node, onelevel, depth, "Layout", str);
+ break;
+
+ case MENU_LAYOUT_NODE_DEFAULT_LAYOUT:
+ menu_layout_node_default_layout_get_values(node, &layout_values);
+ append_layout(node, depth, "DefaultLayout", &layout_values, str);
+ break;
+
+ case MENU_LAYOUT_NODE_MENUNAME:
+ menu_layout_node_menuname_get_values(node, &layout_values);
+ append_layout(node, depth, "MenuName", &layout_values, str);
+ break;
+
+ case MENU_LAYOUT_NODE_SEPARATOR:
+ append_simple(node, depth, "Name", str);
+ break;
+
+ case MENU_LAYOUT_NODE_MERGE:
+ append_merge(node, depth, "Merge", menu_layout_node_merge_get_type(node), str);
+ break;
+
+ default:
+ g_assert_not_reached();
+ break;
+ }
+}
+
+void menu_debug_print_layout(MenuLayoutNode* node, gboolean onelevel)
+{
+ if (menu_verbose_enabled())
+ {
+ GString* str = g_string_new(NULL);
+ append_to_string(node, onelevel, 0, str);
+
+ utf8_fputs(str->str, stderr);
+ fflush(stderr);
+
+ g_string_free(str, TRUE);
+ }
+}
+
+#endif /* G_ENABLE_DEBUG */
diff --git a/libmenu/menu-util.h b/libmenu/menu-util.h
new file mode 100644
index 0000000..035f0e9
--- /dev/null
+++ b/libmenu/menu-util.h
@@ -0,0 +1,59 @@
+/* Random utility functions for menu code */
+
+/*
+ * Copyright (C) 2003 Red Hat, 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 __MENU_UTIL_H__
+#define __MENU_UTIL_H__
+
+#include <glib.h>
+
+#include "menu-layout.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+#ifdef G_ENABLE_DEBUG
+
+ void menu_verbose(const char* format, ...) G_GNUC_PRINTF(1, 2);
+
+ void menu_debug_print_layout(MenuLayoutNode* node, gboolean onelevel);
+
+#else /* !defined(G_ENABLE_DEBUG) */
+
+ #ifdef G_HAVE_ISO_VARARGS
+ #define menu_verbose(...)
+ #elif defined(G_HAVE_GNUC_VARARGS)
+ #define menu_verbose(format...)
+ #else
+ #error "Cannot disable verbose mode due to lack of varargs macros"
+ #endif
+
+ #define menu_debug_print_layout(n, o)
+
+#endif /* G_ENABLE_DEBUG */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MENU_UTIL_H__ */
diff --git a/m4/intltool.m4 b/m4/intltool.m4
new file mode 100644
index 0000000..839e855
--- /dev/null
+++ b/m4/intltool.m4
@@ -0,0 +1,216 @@
+## intltool.m4 - Configure intltool for the target system. -*-Shell-script-*-
+## Copyright (C) 2001 Eazel, Inc.
+## Author: Maciej Stachowiak <[email protected]>
+## Kenneth Christiansen <[email protected]>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+##
+## As a special exception to the GNU General Public License, if you
+## distribute this file as part of a program that contains a
+## configuration script generated by Autoconf, you may include it under
+## the same distribution terms that you use for the rest of that program.
+
+dnl IT_PROG_INTLTOOL([MINIMUM-VERSION], [no-xml])
+# serial 40 IT_PROG_INTLTOOL
+AC_DEFUN([IT_PROG_INTLTOOL], [
+AC_PREREQ([2.50])dnl
+AC_REQUIRE([AM_NLS])dnl
+
+case "$am__api_version" in
+ 1.[01234])
+ AC_MSG_ERROR([Automake 1.5 or newer is required to use intltool])
+ ;;
+ *)
+ ;;
+esac
+
+if test -n "$1"; then
+ AC_MSG_CHECKING([for intltool >= $1])
+
+ INTLTOOL_REQUIRED_VERSION_AS_INT=`echo $1 | awk -F. '{ print $ 1 * 1000 + $ 2 * 100 + $ 3; }'`
+ INTLTOOL_APPLIED_VERSION=`intltool-update --version | head -1 | cut -d" " -f3`
+ [INTLTOOL_APPLIED_VERSION_AS_INT=`echo $INTLTOOL_APPLIED_VERSION | awk -F. '{ print $ 1 * 1000 + $ 2 * 100 + $ 3; }'`
+ ]
+ AC_MSG_RESULT([$INTLTOOL_APPLIED_VERSION found])
+ test "$INTLTOOL_APPLIED_VERSION_AS_INT" -ge "$INTLTOOL_REQUIRED_VERSION_AS_INT" ||
+ AC_MSG_ERROR([Your intltool is too old. You need intltool $1 or later.])
+fi
+
+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.])
+fi
+
+ INTLTOOL_DESKTOP_RULE='%.desktop: %.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@'
+INTLTOOL_DIRECTORY_RULE='%.directory: %.directory.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@'
+ INTLTOOL_KEYS_RULE='%.keys: %.keys.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -k -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@'
+ INTLTOOL_PROP_RULE='%.prop: %.prop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@'
+ INTLTOOL_OAF_RULE='%.oaf: %.oaf.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -o -p $(top_srcdir)/po $< [$]@'
+ INTLTOOL_PONG_RULE='%.pong: %.pong.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@'
+ INTLTOOL_SERVER_RULE='%.server: %.server.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -o -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@'
+ INTLTOOL_SHEET_RULE='%.sheet: %.sheet.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@'
+INTLTOOL_SOUNDLIST_RULE='%.soundlist: %.soundlist.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@'
+ INTLTOOL_UI_RULE='%.ui: %.ui.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@'
+ INTLTOOL_XML_RULE='%.xml: %.xml.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@'
+ INTLTOOL_XML_NOMERGE_RULE='%.xml: %.xml.in $(INTLTOOL_MERGE) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u /tmp $< [$]@'
+ INTLTOOL_XAM_RULE='%.xam: %.xml.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@'
+ INTLTOOL_KBD_RULE='%.kbd: %.kbd.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -m -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@'
+ INTLTOOL_CAVES_RULE='%.caves: %.caves.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@'
+ INTLTOOL_SCHEMAS_RULE='%.schemas: %.schemas.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -s -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@'
+ INTLTOOL_THEME_RULE='%.theme: %.theme.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@'
+ INTLTOOL_SERVICE_RULE='%.service: %.service.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@'
+ INTLTOOL_POLICY_RULE='%.policy: %.policy.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@'
+
+_IT_SUBST(INTLTOOL_DESKTOP_RULE)
+_IT_SUBST(INTLTOOL_DIRECTORY_RULE)
+_IT_SUBST(INTLTOOL_KEYS_RULE)
+_IT_SUBST(INTLTOOL_PROP_RULE)
+_IT_SUBST(INTLTOOL_OAF_RULE)
+_IT_SUBST(INTLTOOL_PONG_RULE)
+_IT_SUBST(INTLTOOL_SERVER_RULE)
+_IT_SUBST(INTLTOOL_SHEET_RULE)
+_IT_SUBST(INTLTOOL_SOUNDLIST_RULE)
+_IT_SUBST(INTLTOOL_UI_RULE)
+_IT_SUBST(INTLTOOL_XAM_RULE)
+_IT_SUBST(INTLTOOL_KBD_RULE)
+_IT_SUBST(INTLTOOL_XML_RULE)
+_IT_SUBST(INTLTOOL_XML_NOMERGE_RULE)
+_IT_SUBST(INTLTOOL_CAVES_RULE)
+_IT_SUBST(INTLTOOL_SCHEMAS_RULE)
+_IT_SUBST(INTLTOOL_THEME_RULE)
+_IT_SUBST(INTLTOOL_SERVICE_RULE)
+_IT_SUBST(INTLTOOL_POLICY_RULE)
+
+# Check the gettext tools to make sure they are GNU
+AC_PATH_PROG(XGETTEXT, xgettext)
+AC_PATH_PROG(MSGMERGE, msgmerge)
+AC_PATH_PROG(MSGFMT, msgfmt)
+AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT)
+if test -z "$XGETTEXT" -o -z "$MSGMERGE" -o -z "$MSGFMT"; then
+ AC_MSG_ERROR([GNU gettext tools not found; required for intltool])
+fi
+xgversion="`$XGETTEXT --version|grep '(GNU ' 2> /dev/null`"
+mmversion="`$MSGMERGE --version|grep '(GNU ' 2> /dev/null`"
+mfversion="`$MSGFMT --version|grep '(GNU ' 2> /dev/null`"
+if test -z "$xgversion" -o -z "$mmversion" -o -z "$mfversion"; then
+ AC_MSG_ERROR([GNU gettext tools not found; required for intltool])
+fi
+
+AC_PATH_PROG(INTLTOOL_PERL, perl)
+if test -z "$INTLTOOL_PERL"; then
+ AC_MSG_ERROR([perl not found])
+fi
+AC_MSG_CHECKING([for perl >= 5.8.1])
+$INTLTOOL_PERL -e "use 5.8.1;" > /dev/null 2>&1
+if test $? -ne 0; then
+ AC_MSG_ERROR([perl 5.8.1 is required for intltool])
+else
+ IT_PERL_VERSION="`$INTLTOOL_PERL -e \"printf '%vd', $^V\"`"
+ AC_MSG_RESULT([$IT_PERL_VERSION])
+fi
+if test "x$2" != "xno-xml"; then
+ AC_MSG_CHECKING([for XML::Parser])
+ if `$INTLTOOL_PERL -e "require XML::Parser" 2>/dev/null`; then
+ AC_MSG_RESULT([ok])
+ else
+ AC_MSG_ERROR([XML::Parser perl module is required for intltool])
+ fi
+fi
+
+# Substitute ALL_LINGUAS so we can use it in po/Makefile
+AC_SUBST(ALL_LINGUAS)
+
+# Set DATADIRNAME correctly if it is not set yet
+# (copied from glib-gettext.m4)
+if test -z "$DATADIRNAME"; then
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([[]],
+ [[extern int _nl_msg_cat_cntr;
+ return _nl_msg_cat_cntr]])],
+ [DATADIRNAME=share],
+ [case $host in
+ *-*-solaris*)
+ dnl On Solaris, if bind_textdomain_codeset is in libc,
+ dnl GNU format message catalog is always supported,
+ dnl since both are added to the libc all together.
+ dnl Hence, we'd like to go with DATADIRNAME=share
+ dnl in this case.
+ AC_CHECK_FUNC(bind_textdomain_codeset,
+ [DATADIRNAME=share], [DATADIRNAME=lib])
+ ;;
+ *)
+ [DATADIRNAME=lib]
+ ;;
+ esac])
+fi
+AC_SUBST(DATADIRNAME)
+
+IT_PO_SUBDIR([po])
+
+])
+
+
+# IT_PO_SUBDIR(DIRNAME)
+# ---------------------
+# All po subdirs have to be declared with this macro; the subdir "po" is
+# declared by IT_PROG_INTLTOOL.
+#
+AC_DEFUN([IT_PO_SUBDIR],
+[AC_PREREQ([2.53])dnl We use ac_top_srcdir inside AC_CONFIG_COMMANDS.
+dnl
+dnl The following CONFIG_COMMANDS should be executed at the very end
+dnl of config.status.
+AC_CONFIG_COMMANDS_PRE([
+ AC_CONFIG_COMMANDS([$1/stamp-it], [
+ if [ ! grep "^# INTLTOOL_MAKEFILE$" "$1/Makefile.in" > /dev/null ]; then
+ AC_MSG_ERROR([$1/Makefile.in.in was not created by intltoolize.])
+ fi
+ rm -f "$1/stamp-it" "$1/stamp-it.tmp" "$1/POTFILES" "$1/Makefile.tmp"
+ >"$1/stamp-it.tmp"
+ [sed '/^#/d
+ s/^[[].*] *//
+ /^[ ]*$/d
+ '"s|^| $ac_top_srcdir/|" \
+ "$srcdir/$1/POTFILES.in" | sed '$!s/$/ \\/' >"$1/POTFILES"
+ ]
+ [sed '/^POTFILES =/,/[^\\]$/ {
+ /^POTFILES =/!d
+ r $1/POTFILES
+ }
+ ' "$1/Makefile.in" >"$1/Makefile"]
+ rm -f "$1/Makefile.tmp"
+ mv "$1/stamp-it.tmp" "$1/stamp-it"
+ ])
+])dnl
+])
+
+# _IT_SUBST(VARIABLE)
+# -------------------
+# Abstract macro to do either _AM_SUBST_NOTMAKE or AC_SUBST
+#
+AC_DEFUN([_IT_SUBST],
+[
+AC_SUBST([$1])
+m4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([$1])])
+]
+)
+
+# deprecated macros
+AU_ALIAS([AC_PROG_INTLTOOL], [IT_PROG_INTLTOOL])
+# A hint is needed for aclocal from Automake <= 1.9.4:
+# AC_DEFUN([AC_PROG_INTLTOOL], ...)
+
diff --git a/m4/ltsugar.m4 b/m4/ltsugar.m4
new file mode 100644
index 0000000..9000a05
--- /dev/null
+++ b/m4/ltsugar.m4
@@ -0,0 +1,123 @@
+# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+ [$#], [2], [[$2]],
+ [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift([email protected])))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+ [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift([email protected])))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59 which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+ [$#], 1, [],
+ [m4_dquote(m4_shift([email protected]))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+ m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+ [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+ [m4_foreach([_Lt_suffix],
+ ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift([email protected])))))[,
+ [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+ [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+ [lt_append([$1], [$2], [$3])$4],
+ [$5])],
+ [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+ m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+ m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+ [$5],
+ [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+ [lt_join(m4_quote(m4_default([$4], [[, ]])),
+ lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, [email protected])]),
+ [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
diff --git a/m4/python.m4 b/m4/python.m4
new file mode 100644
index 0000000..deb3269
--- /dev/null
+++ b/m4/python.m4
@@ -0,0 +1,86 @@
+dnl a macro to check for ability to create python extensions
+dnl AM_CHECK_PYTHON_HEADERS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE])
+dnl function also defines PYTHON_INCLUDES
+AC_DEFUN([AM_CHECK_PYTHON_HEADERS],
+[AC_REQUIRE([AM_PATH_PYTHON])
+
+AC_SUBST(PYTHON_INCLUDES)
+AC_SUBST(PYTHON_LIBS)
+AC_SUBST(PYTHON_EMBED_LIBS)
+AC_SUBST(PYTHON_LDFLAGS)
+AC_SUBST(PYTHON_CC)
+
+AC_MSG_CHECKING(for headers required to compile python extensions)
+dnl deduce PYTHON_INCLUDES
+py_prefix=`$PYTHON -c "import sys; print sys.prefix"`
+py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"`
+if test -x "$PYTHON-config"; then
+ PYTHON_INCLUDES=`$PYTHON-config --includes 2>/dev/null`
+else
+ PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}"
+ if test "$py_prefix" != "$py_exec_prefix"; then
+ PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}"
+ fi
+fi
+dnl check if the headers exist:
+save_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES"
+AC_TRY_CPP([#include <Python.h>],dnl
+[AC_MSG_RESULT(found)
+
+AC_MSG_CHECKING(for python libraries)
+
+
+dnl Check whether python was compiled as shared library
+link_pymodules_libpython=false;
+py_enable_shared=`$PYTHON -c "from distutils.sysconfig import get_config_var; print repr(get_config_var('Py_ENABLE_SHARED'))"`
+if test $py_enable_shared == 1 ; then
+ if test x`uname -s` != xDarwin; then
+ PYTHON_LDFLAGS="-no-undefined"
+ link_pymodules_libpython=true;
+ fi
+fi
+
+dnl use distutils to get some python configuration variables..
+PYTHON_CC=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_config_var('CC')"`
+PYTHON_LIB_DEPS=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_config_var('SYSLIBS'), sysconfig.get_config_var('SHLIBS')"`
+PYTHON_LIBDIR=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_config_var('LIBDIR')"`
+PYTHON_LIBPL=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_config_var('LIBPL')"`
+
+save_CC="$CC"
+save_LIBS="$LIBS"
+
+PYTHON_EMBED_LIBS="-L${PYTHON_LIBDIR} ${PYTHON_LIB_DEPS} -lpython${PYTHON_VERSION}"
+
+CC="$PYTHON_CC"
+LIBS="$LIBS $PYTHON_EMBED_LIBS"
+AC_TRY_LINK_FUNC(Py_Initialize, dnl
+ [
+ LIBS="$save_LIBS";
+ if $link_pymodules_libpython; then
+ PYTHON_LIBS="$PYTHON_EMBED_LIBS";
+ fi
+ AC_MSG_RESULT([$PYTHON_EMBED_LIBS]);
+ $1], dnl
+[
+
+ PYTHON_EMBED_LIBS="-L${PYTHON_LIBPL} ${PYTHON_LIB_DEPS} -lpython${PYTHON_VERSION}"
+
+ LIBS="$save_LIBS $PYTHON_EMBED_LIBS";
+ AC_TRY_LINK_FUNC(Py_Initialize, dnl
+ [
+ LIBS="$save_LIBS";
+ if $link_pymodules_libpython; then
+ PYTHON_LIBS="$PYTHON_EMBED_LIBS";
+ fi
+ AC_MSG_RESULT([$PYTHON_EMBED_LIBS]);
+ $1], dnl
+ AC_MSG_RESULT(not found); $2)
+])
+CC="$save_CC"
+
+$1],dnl
+[AC_MSG_RESULT(not found)
+$2])
+CPPFLAGS="$save_CPPFLAGS"
+])
diff --git a/missing b/missing
new file mode 100755
index 0000000..28055d2
--- /dev/null
+++ b/missing
@@ -0,0 +1,376 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+
+scriptversion=2009-04-28.21; # UTC
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
+# 2008, 2009 Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <[email protected]>, 1996.
+
+# 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, 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, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+run=:
+sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
+sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+ configure_ac=configure.ac
+else
+ configure_ac=configure.in
+fi
+
+msg="missing on your system"
+
+case $1 in
+--run)
+ # Try to run requested program, and just exit if it succeeds.
+ run=
+ shift
+ "[email protected]" && exit 0
+ # Exit code 63 means version mismatch. This often happens
+ # when the user try to use an ancient version of a tool on
+ # a file that requires a minimum version. In this case we
+ # we should proceed has if the program had been absent, or
+ # if --run hadn't been passed.
+ if test $? = 63; then
+ run=:
+ msg="probably too old"
+ fi
+ ;;
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+ --run try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ autom4te touch the output file, or create a stub one
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ help2man touch the output file
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ tar try tar, gnutar, gtar, then tar without non-portable flags
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]
+
+Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and
+\`g' are ignored when checking the name.
+
+Send bug reports to <[email protected]>."
+ exit $?
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ exit $?
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+esac
+
+# normalize program name to check for.
+program=`echo "$1" | sed '
+ s/^gnu-//; t
+ s/^gnu//; t
+ s/^g//; t'`
+
+# Now exit if we have it, but it failed. Also exit now if we
+# don't have it and --version was passed (most likely to detect
+# the program). This is about non-GNU programs, so use $1 not
+# $program.
+case $1 in
+ lex*|yacc*)
+ # Not GNU programs, they don't have --version.
+ ;;
+
+ tar*)
+ if test -n "$run"; then
+ echo 1>&2 "ERROR: \`tar' requires --run"
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ exit 1
+ fi
+ ;;
+
+ *)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ # Could not run --version or --help. This is probably someone
+ # running `$TOOL --version' or `$TOOL --help' to check whether
+ # $TOOL exists and not knowing $TOOL uses missing.
+ exit 1
+ fi
+ ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case $program in
+ aclocal*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acinclude.m4' or \`${configure_ac}'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`${configure_ac}'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acconfig.h' or \`${configure_ac}'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case $f in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ autom4te*)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, but is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them.
+ You can get \`$1' as part of \`Autoconf' from any GNU
+ archive site."
+
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo "#! /bin/sh"
+ echo "# Created by GNU Automake missing as a replacement of"
+ echo "# $ [email protected]"
+ echo "exit 0"
+ chmod +x $file
+ exit 1
+ fi
+ ;;
+
+ bison*|yacc*)
+ echo 1>&2 "\
+WARNING: \`$1' $msg. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if test $# -ne 1; then
+ eval LASTARG="\${$#}"
+ case $LASTARG in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if test ! -f y.tab.h; then
+ echo >y.tab.h
+ fi
+ if test ! -f y.tab.c; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex*|flex*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if test $# -ne 1; then
+ eval LASTARG="\${$#}"
+ case $LASTARG in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if test ! -f lex.yy.c; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ help2man*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a dependency of a manual page. You may need the
+ \`Help2man' package in order for those modifications to take
+ effect. You can get \`Help2man' from any GNU archive site."
+
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo ".ab help2man is required to generate this page"
+ exit $?
+ fi
+ ;;
+
+ makeinfo*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ # The file to touch is that specified with -o ...
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -z "$file"; then
+ # ... or it is the one specified with @setfilename ...
+ infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '
+ /^@setfilename/{
+ s/.* \([^ ]*\) *$/\1/
+ p
+ q
+ }' $infile`
+ # ... or it is derived from the source name (dir/f.texi becomes f.info)
+ test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
+ fi
+ # If the file does not exist, the user really needs makeinfo;
+ # let's fail without touching anything.
+ test -f $file || exit 1
+ touch $file
+ ;;
+
+ tar*)
+ shift
+
+ # We have already tried tar in the generic part.
+ # Look for gnutar/gtar before invocation to avoid ugly error
+ # messages.
+ if (gnutar --version > /dev/null 2>&1); then
+ gnutar "[email protected]" && exit 0
+ fi
+ if (gtar --version > /dev/null 2>&1); then
+ gtar "[email protected]" && exit 0
+ fi
+ firstarg="$1"
+ if shift; then
+ case $firstarg in
+ *o*)
+ firstarg=`echo "$firstarg" | sed s/o//`
+ tar "$firstarg" "[email protected]" && exit 0
+ ;;
+ esac
+ case $firstarg in
+ *h*)
+ firstarg=`echo "$firstarg" | sed s/h//`
+ tar "$firstarg" "[email protected]" && exit 0
+ ;;
+ esac
+ fi
+
+ echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+ You may want to install GNU tar or Free paxutils, or check the
+ command line arguments."
+ exit 1
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequisites for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/mkinstalldirs b/mkinstalldirs
new file mode 100755
index 0000000..4191a45
--- /dev/null
+++ b/mkinstalldirs
@@ -0,0 +1,162 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+
+scriptversion=2009-04-28.21; # UTC
+
+# Original author: Noah Friedman <[email protected]>
+# Created: 1993-05-16
+# Public domain.
+#
+# This file is maintained in Automake, please report
+# bugs to <[email protected]> or send patches to
+
+nl='
+'
+IFS=" "" $nl"
+errstatus=0
+dirmode=
+
+usage="\
+Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ...
+
+Create each directory DIR (with mode MODE, if specified), including all
+leading file name components.
+
+Report bugs to <[email protected]>."
+
+# process command line arguments
+while test $# -gt 0 ; do
+ case $1 in
+ -h | --help | --h*) # -h for help
+ echo "$usage"
+ exit $?
+ ;;
+ -m) # -m PERM arg
+ shift
+ test $# -eq 0 && { echo "$usage" 1>&2; exit 1; }
+ dirmode=$1
+ shift
+ ;;
+ --version)
+ echo "$0 $scriptversion"
+ exit $?
+ ;;
+ --) # stop option processing
+ shift
+ break
+ ;;
+ -*) # unknown option
+ echo "$usage" 1>&2
+ exit 1
+ ;;
+ *) # first non-opt arg
+ break
+ ;;
+ esac
+done
+
+for file
+do
+ if test -d "$file"; then
+ shift
+ else
+ break
+ fi
+done
+
+case $# in
+ 0) exit 0 ;;
+esac
+
+# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and
+# mkdir -p a/c at the same time, both will detect that a is missing,
+# one will create a, then the other will try to create a and die with
+# a "File exists" error. This is a problem when calling mkinstalldirs
+# from a parallel make. We use --version in the probe to restrict
+# ourselves to GNU mkdir, which is thread-safe.
+case $dirmode in
+ '')
+ if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
+ echo "mkdir -p -- $*"
+ exec mkdir -p -- "[email protected]"
+ else
+ # On NextStep and OpenStep, the `mkdir' command does not
+ # recognize any option. It will interpret all options as
+ # directories to create, and then abort because `.' already
+ # exists.
+ test -d ./-p && rmdir ./-p
+ test -d ./--version && rmdir ./--version
+ fi
+ ;;
+ *)
+ if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 &&
+ test ! -d ./--version; then
+ echo "mkdir -m $dirmode -p -- $*"
+ exec mkdir -m "$dirmode" -p -- "[email protected]"
+ else
+ # Clean up after NextStep and OpenStep mkdir.
+ for d in ./-m ./-p ./--version "./$dirmode";
+ do
+ test -d $d && rmdir $d
+ done
+ fi
+ ;;
+esac
+
+for file
+do
+ case $file in
+ /*) pathcomp=/ ;;
+ *) pathcomp= ;;
+ esac
+ oIFS=$IFS
+ IFS=/
+ set fnord $file
+ shift
+ IFS=$oIFS
+
+ for d
+ do
+ test "x$d" = x && continue
+
+ pathcomp=$pathcomp$d
+ case $pathcomp in
+ -*) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp"
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ else
+ if test ! -z "$dirmode"; then
+ echo "chmod $dirmode $pathcomp"
+ lasterr=
+ chmod "$dirmode" "$pathcomp" || lasterr=$?
+
+ if test ! -z "$lasterr"; then
+ errstatus=$lasterr
+ fi
+ fi
+ fi
+ fi
+
+ pathcomp=$pathcomp/
+ done
+done
+
+exit $errstatus
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/po/LINGUAS b/po/LINGUAS
new file mode 100644
index 0000000..8ffe8e6
--- /dev/null
+++ b/po/LINGUAS
@@ -0,0 +1,100 @@
+af
+an
+ar
+as
+ast
+be
+bg
+bn_IN
+bn
+br
+ca
+crh
+cs
+cy
+da
+de
+dv
+dz
+el
+en_CA
+en_GB
+eo
+es
+et
+eu
+fa
+fi
+fr
+fur
+fy
+ga
+gl
+gn
+gu
+gv
+ha
+he
+hi
+hr
+hu
+hy
+id
+ig
+io
+is
+it
+ja
+ka
+kk
+kn
+ko
+ku
+ky
+lt
+lv
+mai
+mg
+mk
+ml
+mn
+mr
+ms
+nb
+nds
+ne
+nl
+nn
+oc
+or
+pa
+pl
+ps
+pt_BR
+pt
+ro
+ru
+rw
+si
+sk
+sl
+sq
+sr
+sv
+ta
+te
+th
+tr
+ug
+uk
+vi
+xh
+yo
+zh_CN
+zh_HK
+zh_TW
diff --git a/po/POTFILES.in b/po/POTFILES.in
new file mode 100644
index 0000000..e989d1e
--- /dev/null
+++ b/po/POTFILES.in
@@ -0,0 +1,28 @@
+# List of source files containing translatable strings.
+# Please keep this file sorted alphabetically.
+desktop-directories/mate-audio-video.directory.in
+desktop-directories/mate-development.directory.in
+desktop-directories/mate-education.directory.in
+desktop-directories/mate-game.directory.in
+desktop-directories/mate-graphics.directory.in
+desktop-directories/mate-hardware.directory.in
+desktop-directories/mate-internet-and-network.directory.in
+desktop-directories/mate-look-and-feel.directory.in
+desktop-directories/mate-network.directory.in
+desktop-directories/mate-office.directory.in
+desktop-directories/mate-personal.directory.in
+desktop-directories/mate-settings-system.directory.in
+desktop-directories/mate-settings.directory.in
+desktop-directories/mate-system.directory.in
+desktop-directories/mate-system-tools.directory.in
+desktop-directories/mate-utility-accessibility.directory.in
+desktop-directories/mate-utility.directory.in
+desktop-directories/mate-menu-applications.directory.in
+desktop-directories/mate-menu-system.directory.in
+desktop-directories/mate-other.directory.in
+# simple menu was removed
+#simple-editor/matemenu-simple-editor.desktop.in
+#[type: gettext/glade]simple-editor/matemenu-simple-editor.ui
+#simple-editor/MateMenuSimpleEditor/main.py
+#simple-editor/MateMenuSimpleEditor/maindialog.py
+#simple-editor/MateMenuSimpleEditor/menufilewriter.py
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
new file mode 100644
index 0000000..0185faf
--- /dev/null
+++ b/po/POTFILES.skip
@@ -0,0 +1,3 @@
+# List of source files containing translatable strings that should be skipped.
+# Please keep this file sorted alphabetically.
+util/test-menu-spec.c
diff --git a/po/af.po b/po/af.po
new file mode 100644
index 0000000..d508efb
--- /dev/null
+++ b/po/af.po
@@ -0,0 +1,258 @@
+# Afrikaans translation of mate-menus
+# This file is distributed under the same license as the mate-menus package.
+# F Wolff <[email protected]>, 2008
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-09-22 00:23+0200\n"
+"PO-Revision-Date: 2008-09-15 20:46+0200\n"
+"Last-Translator: F Wolff <[email protected]>\n"
+"Language-Team: [email protected]\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: VirTaal 0.1\n"
+
+#: ../desktop-directories/AudioVideo.directory.in.h:1
+msgid "Multimedia menu"
+msgstr "Multimediakieslys"
+
+#: ../desktop-directories/AudioVideo.directory.in.h:2
+msgid "Sound & Video"
+msgstr "Klank & video"
+
+#: ../desktop-directories/Development.directory.in.h:1
+msgid "Programming"
+msgstr "Programmering"
+
+#: ../desktop-directories/Development.directory.in.h:2
+msgid "Tools for software development"
+msgstr "Gereedskap vir sagtewareontwikkeling"
+
+#: ../desktop-directories/Education.directory.in.h:1
+msgid "Education"
+msgstr "Opvoeding"
+
+#: ../desktop-directories/Game.directory.in.h:1
+msgid "Games"
+msgstr "Speletjies"
+
+#: ../desktop-directories/Game.directory.in.h:2
+msgid "Games and amusements"
+msgstr "Speletjies en vermaak"
+
+#: ../desktop-directories/Graphics.directory.in.h:1
+msgid "Graphics"
+msgstr "Grafika"
+
+#: ../desktop-directories/Graphics.directory.in.h:2
+msgid "Graphics applications"
+msgstr "Grafika-toepassings"
+
+#: ../desktop-directories/Hardware.directory.in.h:1
+msgid "Hardware"
+msgstr "Hardeware"
+
+#: ../desktop-directories/Hardware.directory.in.h:2
+msgid "Settings for several hardware devices"
+msgstr "Instellings vir verskeie hardewaretoestelle"
+
+#: ../desktop-directories/InternetAndNetwork.directory.in.h:1
+msgid "Internet and Network"
+msgstr "Internet en netwerk"
+
+#: ../desktop-directories/InternetAndNetwork.directory.in.h:2
+msgid "Network-related settings"
+msgstr "Netwerkverwante instellings"
+
+#: ../desktop-directories/LookAndFeel.directory.in.h:1
+msgid "Look and Feel"
+msgstr "Voorkoms en gedrag"
+
+#: ../desktop-directories/LookAndFeel.directory.in.h:2
+msgid "Settings controlling the desktop appearance and behavior"
+msgstr "Instellings wat die werkskerm se voorkoms en gedrag beheer"
+
+#: ../desktop-directories/Network.directory.in.h:1
+msgid "Internet"
+msgstr "Internet"
+
+#: ../desktop-directories/Network.directory.in.h:2
+msgid "Programs for Internet access such as web and email"
+msgstr "Programme vir Internettoegang soos web en e-pos"
+
+#: ../desktop-directories/Office.directory.in.h:1
+msgid "Office"
+msgstr "Kantoor"
+
+#: ../desktop-directories/Office.directory.in.h:2
+msgid "Office Applications"
+msgstr "Kantoortoepassings"
+
+#: ../desktop-directories/Personal.directory.in.h:1
+msgid "Personal"
+msgstr "Persoonlik"
+
+#: ../desktop-directories/Personal.directory.in.h:2
+msgid "Personal settings"
+msgstr "Persoonlike instellings"
+
+#: ../desktop-directories/Settings-System.directory.in.h:1
+msgid "Administration"
+msgstr "Administrasie"
+
+#: ../desktop-directories/Settings-System.directory.in.h:2
+msgid "Change system-wide settings (affects all users)"
+msgstr "Wysig instellings stelselwyd (affekteer alle gebruikers)"
+
+#: ../desktop-directories/Settings.directory.in.h:1
+msgid "Personal preferences"
+msgstr "Persoonlike voorkeure"
+
+#: ../desktop-directories/Settings.directory.in.h:2
+msgid "Preferences"
+msgstr "Voorkeure"
+
+#: ../desktop-directories/System.directory.in.h:1
+#: ../desktop-directories/X-MATE-Menu-System.directory.in.h:2
+msgid "System"
+msgstr "Stelsel"
+
+#: ../desktop-directories/System.directory.in.h:2
+msgid "System settings"
+msgstr "Stelselinstellings"
+
+#: ../desktop-directories/System-Tools.directory.in.h:1
+msgid "System Tools"
+msgstr "Stelselgereedskap"
+
+#: ../desktop-directories/System-Tools.directory.in.h:2
+msgid "System configuration and monitoring"
+msgstr "Stelselopstelling en monitering"
+
+#: ../desktop-directories/Utility-Accessibility.directory.in.h:1
+msgid "Universal Access"
+msgstr "Universele toegang"
+
+#: ../desktop-directories/Utility-Accessibility.directory.in.h:2
+msgid "Universal Access Settings"
+msgstr "Verstelling van universele toegang"
+
+#: ../desktop-directories/Utility.directory.in.h:1
+msgid "Accessories"
+msgstr "Toebehore"
+
+#: ../desktop-directories/Utility.directory.in.h:2
+msgid "Desktop accessories"
+msgstr "Werkskermtoebehore"
+
+#: ../desktop-directories/X-MATE-Menu-Applications.directory.in.h:1
+msgid "Applications"
+msgstr "Toepassings"
+
+#: ../desktop-directories/X-MATE-Menu-System.directory.in.h:1
+msgid "Personal preferences and administration settings"
+msgstr "Persoonlike voorkeure en administrasie-instellings"
+
+#: ../desktop-directories/X-MATE-Other.directory.in.h:1
+msgid "Applications that did not fit in other categories"
+msgstr "Toepassings wat nie in ander kategorieë pas nie"
+
+#: ../desktop-directories/X-MATE-Other.directory.in.h:2
+msgid "Other"
+msgstr "Ander"
+
+#: ../simple-editor/gmenu-simple-editor.desktop.in.h:1
+msgid "Menu Editor"
+msgstr "Kieslysredigeerder"
+
+#: ../simple-editor/gmenu-simple-editor.glade.h:1
+msgid "Edit Menus"
+msgstr "Redigeer kieslyste"
+
+#: ../simple-editor/gmenu-simple-editor.glade.h:2
+msgid "_Applications:"
+msgstr "_Toepassings:"
+
+#: ../simple-editor/gmenu-simple-editor.glade.h:3
+msgid "_Defaults"
+msgstr "_Verstekwaardes"
+
+#: ../simple-editor/gmenu-simple-editor.glade.h:4
+msgid "_Menus:"
+msgstr "_Kieslyste:"
+
+#: ../simple-editor/GMenuSimpleEditor/maindialog.py:94
+#: ../simple-editor/GMenuSimpleEditor/maindialog.py:121
+msgid "Name"
+msgstr "Naam"
+
+#: ../simple-editor/GMenuSimpleEditor/maindialog.py:113
+msgid "Show"
+msgstr "Wys"
+
+#: ../simple-editor/GMenuSimpleEditor/menufilewriter.py:42
+msgid ""
+"Cannot find home directory: not set in /etc/passwd and no value for $HOME in "
+"environment"
+msgstr ""
+"Kan nie tuisgids vind nie: nie aangedui in /etc/passwd nie een geen waarde "
+"vir $HOME in die omgewing nie"
+
+#: ../util/test-menu-spec.c:33
+msgid "Menu file"
+msgstr "Kieslyslêer"
+
+#: ../util/test-menu-spec.c:33
+msgid "MENU_FILE"
+msgstr ""
+
+#: ../util/test-menu-spec.c:34
+msgid "Monitor for menu changes"
+msgstr ""
+
+#: ../util/test-menu-spec.c:35
+msgid "Include <Exclude>d entries"
+msgstr ""
+
+#: ../util/test-menu-spec.c:36
+msgid "Include NoDisplay=true entries"
+msgstr ""
+
+#: ../util/test-menu-spec.c:91
+msgid "Invalid desktop file ID"
+msgstr ""
+
+#: ../util/test-menu-spec.c:92
+msgid "[Invalid Filename]"
+msgstr ""
+
+#: ../util/test-menu-spec.c:93
+msgid " <excluded>"
+msgstr ""
+
+#: ../util/test-menu-spec.c:164
+#, c-format
+msgid ""
+"\n"
+"\n"
+"\n"
+"==== Menu changed, reloading ====\n"
+"\n"
+"\n"
+msgstr ""
+
+#: ../util/test-menu-spec.c:169 ../util/test-menu-spec.c:211
+msgid "Menu tree is empty"
+msgstr ""
+
+#: ../util/test-menu-spec.c:189
+msgid "- test MATE's implementation of the Desktop Menu Specification"
+msgstr ""
+
+#~ msgid "Universal access related preferences"
+#~ msgstr "Voorkeure aangaande universele toegang"
+
+#~ msgid "Personal preferences and settings"
+#~ msgstr "Persoonlike voorkeure en instellings"
diff --git a/po/an.po b/po/an.po
new file mode 100644
index 0000000..ccdf461
--- /dev/null
+++ b/po/an.po
@@ -0,0 +1,211 @@
+# Aragonese translations mate-menus.
+# Copyright (C) 2010 Mate Foundation
+# This file is distributed under the same license as the PACKAGE package.
+# Daniel Martinez <[email protected]>, 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mate-menus.HEAD.an\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=mate-"
+"menus&component=general\n"
+"POT-Creation-Date: 2010-09-15 06:57+0000\n"
+"PO-Revision-Date: 2010-04-24 02:30+0200\n"
+"Last-Translator: Daniel Martinez <[email protected]>\n"
+"Language-Team: Aragonés <[email protected]>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../desktop-directories/AudioVideo.directory.in.h:1
+msgid "Multimedia menu"
+msgstr "Menú de programas multimedia"
+
+#: ../desktop-directories/AudioVideo.directory.in.h:2
+msgid "Sound & Video"
+msgstr "Vidio y soniu"
+
+#: ../desktop-directories/Development.directory.in.h:1
+msgid "Programming"
+msgstr "Programacion"
+
+#: ../desktop-directories/Development.directory.in.h:2
+msgid "Tools for software development"
+msgstr "Ainas ta lo desarrollo de software"
+
+#: ../desktop-directories/Education.directory.in.h:1
+msgid "Education"
+msgstr "Educacion"
+
+#: ../desktop-directories/Game.directory.in.h:1
+msgid "Games"
+msgstr "Chuegos"
+
+#: ../desktop-directories/Game.directory.in.h:2
+msgid "Games and amusements"
+msgstr "Chuegos y distraccions"
+
+#: ../desktop-directories/Graphics.directory.in.h:1
+msgid "Graphics"
+msgstr "Graficos"
+
+#: ../desktop-directories/Graphics.directory.in.h:2
+msgid "Graphics applications"
+msgstr "Aplicacions graficas"
+
+#: ../desktop-directories/Hardware.directory.in.h:1
+msgid "Hardware"
+msgstr "Hardware"
+
+#: ../desktop-directories/Hardware.directory.in.h:2
+msgid "Settings for several hardware devices"
+msgstr "Propiedaz ta varios dispositivos de hardware"
+
+#: ../desktop-directories/InternetAndNetwork.directory.in.h:1
+msgid "Internet and Network"
+msgstr "Internet y rete"
+
+#: ../desktop-directories/InternetAndNetwork.directory.in.h:2
+msgid "Network-related settings"
+msgstr "Propiedatz arredol d'o rete"
+
+#: ../desktop-directories/LookAndFeel.directory.in.h:1
+msgid "Look and Feel"
+msgstr "Visualizacion y comportamiento"
+
+#: ../desktop-directories/LookAndFeel.directory.in.h:2
+msgid "Settings controlling the desktop appearance and behavior"
+msgstr "Propiedaz que controlan l'apariencia y o comportamiento d'o escritorio"
+
+#: ../desktop-directories/Network.directory.in.h:1
+msgid "Internet"
+msgstr "Internet"
+
+#: ../desktop-directories/Network.directory.in.h:2
+msgid "Programs for Internet access such as web and email"
+msgstr "Programas ta l'acceso a internet, tals como web y e-mail"
+
+#: ../desktop-directories/Office.directory.in.h:1
+msgid "Office"
+msgstr "Oficina"
+
+#: ../desktop-directories/Office.directory.in.h:2
+msgid "Office Applications"
+msgstr "Aplicacions d'oficina"
+
+#. Translators: this is Personal as in "Personal settings"
+#: ../desktop-directories/Personal.directory.in.h:2
+msgid "Personal"
+msgstr "Presonal"
+
+#: ../desktop-directories/Personal.directory.in.h:3
+msgid "Personal settings"
+msgstr "Peferencias presonals"
+
+#: ../desktop-directories/Settings-System.directory.in.h:1
+msgid "Administration"
+msgstr "Almenistracion"
+
+#: ../desktop-directories/Settings-System.directory.in.h:2
+msgid "Change system-wide settings (affects all users)"
+msgstr "Cambear as preferencias globals d'o sistema (ta toz os usuarios)"
+
+#: ../desktop-directories/Settings.directory.in.h:1
+msgid "Personal preferences"
+msgstr "Preferencias presonals "
+
+#: ../desktop-directories/Settings.directory.in.h:2
+msgid "Preferences"
+msgstr "Preferencias"
+
+#: ../desktop-directories/System.directory.in.h:1
+#: ../desktop-directories/X-MATE-Menu-System.directory.in.h:2
+msgid "System"
+msgstr "Sistema"
+
+#: ../desktop-directories/System.directory.in.h:2
+msgid "System settings"
+msgstr "Preferencias d'o sistema"
+
+#: ../desktop-directories/System-Tools.directory.in.h:1
+msgid "System Tools"
+msgstr "Ainas d'o sistema"
+
+#: ../desktop-directories/System-Tools.directory.in.h:2
+msgid "System configuration and monitoring"
+msgstr "Configuracion y monitorizacion d'o sistema"
+
+#: ../desktop-directories/Utility-Accessibility.directory.in.h:1
+msgid "Universal Access"
+msgstr "Acceso universal"
+
+#: ../desktop-directories/Utility-Accessibility.directory.in.h:2
+msgid "Universal Access Settings"
+msgstr "Preferencias d'acceso universal"
+
+#: ../desktop-directories/Utility.directory.in.h:1
+msgid "Accessories"
+msgstr "Accesorios"
+
+#: ../desktop-directories/Utility.directory.in.h:2
+msgid "Desktop accessories"
+msgstr "Accesorios d'o escritorio"
+
+#: ../desktop-directories/X-MATE-Menu-Applications.directory.in.h:1
+msgid "Applications"
+msgstr "Aplicacions"
+
+#: ../desktop-directories/X-MATE-Menu-System.directory.in.h:1
+msgid "Personal preferences and administration settings"
+msgstr "Preferencias presonals y opcions d'almenistracion"
+
+#: ../desktop-directories/X-MATE-Other.directory.in.h:1
+msgid "Applications that did not fit in other categories"
+msgstr "Aplicacions que no dentran en denguna atra categoria"
+
+#: ../desktop-directories/X-MATE-Other.directory.in.h:2
+msgid "Other"
+msgstr "Atras"
+
+#: ../simple-editor/gmenu-simple-editor.desktop.in.h:1
+msgid "Menu Editor"
+msgstr "Editor d'o menu"
+
+#: ../simple-editor/gmenu-simple-editor.ui.h:1
+msgid "Edit Menus"
+msgstr "Editar menus"
+
+#: ../simple-editor/gmenu-simple-editor.ui.h:2
+msgid "_Applications:"
+msgstr "_Aplicacions:"
+
+#: ../simple-editor/gmenu-simple-editor.ui.h:3
+msgid "_Defaults"
+msgstr "_Predeterminaus"
+
+#: ../simple-editor/gmenu-simple-editor.ui.h:4
+msgid "_Menus:"
+msgstr "_Menus:"
+
+#. Translators: %s is the version number
+#: ../simple-editor/GMenuSimpleEditor/main.py:49
+#, python-format
+msgid "Simple Menu Editor %s"
+msgstr "Editor simple d'o menu %s"
+
+#: ../simple-editor/GMenuSimpleEditor/maindialog.py:94
+#: ../simple-editor/GMenuSimpleEditor/maindialog.py:121
+msgid "Name"
+msgstr "Nome"
+
+#: ../simple-editor/GMenuSimpleEditor/maindialog.py:113
+msgid "Show"
+msgstr "Amostrar"
+
+#: ../simple-editor/GMenuSimpleEditor/menufilewriter.py:42
+msgid ""
+"Cannot find home directory: not set in /etc/passwd and no value for $HOME in "
+"environment"
+msgstr ""
+"No s'ha puesto trobar lo direutorio presonal: no ye estableciu en o /etc/"
+"passwd y no bi ha dengun valor en a variable d'entorno $HOME"
+
diff --git a/po/ar.po b/po/ar.po
new file mode 100644
index 0000000..accbbec
--- /dev/null
+++ b/po/ar.po
@@ -0,0 +1,270 @@
+# translation of mate-menus.HEAD.po to Arabic
+# This file is distributed under the same license as the PACKAGE package.
+# Copyright (C) 2005 THE PACKAGE'S COPYRIGHT HOLDER, 2005.
+# Djihed Afifi <[email protected]>, 2006.
+# Khaled Hosny <[email protected]>, 2006, 2007, 2008, 2009.
+# Anas Husseini <[email protected]>, 2007.
+msgid ""
+msgstr ""
+"Project-Id-Version: mate-menus.HEAD\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-08-20 21:13+0300\n"
+"PO-Revision-Date: 2009-08-20 21:17+0300\n"
+"Last-Translator: Khaled Hosny <[email protected]>\n"
+"Language-Team: Arabic <[email protected]>\n"
+"Language: ar\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
+