diff options
author | Perberos <[email protected]> | 2011-12-01 22:29:22 -0300 |
---|---|---|
committer | Perberos <[email protected]> | 2011-12-01 22:29:22 -0300 |
commit | 17e291fd05d66fe232e2f409d54331c495b2fbd0 (patch) | |
tree | d3f9b3bc149dedc9d192317e930d438c5e9ba21a | |
download | mate-menus-17e291fd05d66fe232e2f409d54331c495b2fbd0.tar.bz2 mate-menus-17e291fd05d66fe232e2f409d54331c495b2fbd0.tar.xz |
moving from https://github.com/perberos/mate-desktop-environment
174 files changed, 49563 insertions, 0 deletions
@@ -0,0 +1,3 @@ +Mark McLoughlin <[email protected]> +Havoc Pennington <[email protected]> +Vincent Untz <[email protected]> @@ -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 @@ + @@ -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 +E-mail: [email protected] +Userid: vuntz + +Non-active maintainers, who have a good understanding of the code +----------------------------------------------------------------- + +#Mark McLoughlin +#E-mail: [email protected] 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 @@ -0,0 +1 @@ + @@ -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([--enable-cxx-warnings[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} + +" @@ -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 + "[email protected]" -Wc,-M + else + tmpdepfile1=$dir$base.u + tmpdepfile2=$dir$base.u + tmpdepfile3=$dir$base.u + "[email protected]" -M + 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 + "[email protected]" +Maked + 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 + "[email protected]" -MD + 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 + + "[email protected]" -E | + 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) + exec "[email protected]" + ;; + +*) + 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 +Version: @[email protected] +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 +Version: @[email protected] +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" +]) @@ -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 +# <[email protected]>. + +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:" + |